Overview

Namespaces

  • Alpha
    • Controller
      • Front
    • Exception
    • Model
      • Type
    • Task
    • Util
      • Backup
      • Cache
      • Code
        • Highlight
        • Metric
      • Config
      • Convertor
      • Email
      • Extension
      • Feed
      • File
      • Graph
      • Helper
      • Http
        • Filter
        • Session
      • Image
      • Logging
      • Search
      • Security
    • View
      • Renderer
        • Html
        • Json
      • Widget

Classes

  • Button
  • DateBox
  • Image
  • RecordSelector
  • StringBox
  • TagCloud
  • TextBox
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: namespace Alpha\View\Widget;
  4: 
  5: use Alpha\Util\Logging\Logger;
  6: use Alpha\Util\Config\ConfigProvider;
  7: use Alpha\Model\Type\Integer;
  8: use Alpha\Model\Type\Enum;
  9: use Alpha\Model\Type\Boolean;
 10: use Alpha\Model\Type\Double;
 11: use Alpha\Exception\IllegalArguementException;
 12: use Alpha\Controller\Controller;
 13: use Alpha\Controller\Front\FrontController;
 14: 
 15: /**
 16:  * A widget that can generate an image which is scaled to the screen resolution of the
 17:  * user, and can be made secured to prevent hot-linking from remote sites.  Note that by
 18:  * default, a jpg file will be returned (the source file can be jpg, png, or gif).
 19:  *
 20:  * @since 1.0
 21:  *
 22:  * @author John Collins <dev@alphaframework.org>
 23:  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
 24:  * @copyright Copyright (c) 2015, John Collins (founder of Alpha Framework).
 25:  * All rights reserved.
 26:  *
 27:  * <pre>
 28:  * Redistribution and use in source and binary forms, with or
 29:  * without modification, are permitted provided that the
 30:  * following conditions are met:
 31:  *
 32:  * * Redistributions of source code must retain the above
 33:  *   copyright notice, this list of conditions and the
 34:  *   following disclaimer.
 35:  * * Redistributions in binary form must reproduce the above
 36:  *   copyright notice, this list of conditions and the
 37:  *   following disclaimer in the documentation and/or other
 38:  *   materials provided with the distribution.
 39:  * * Neither the name of the Alpha Framework nor the names
 40:  *   of its contributors may be used to endorse or promote
 41:  *   products derived from this software without specific
 42:  *   prior written permission.
 43:  *
 44:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 45:  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 46:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 47:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 48:  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 49:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 50:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 51:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 52:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 53:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 54:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 55:  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 56:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 57:  * </pre>
 58:  */
 59: class Image
 60: {
 61:     /**
 62:      * The title of the image for alt text (optional).
 63:      *
 64:      * @var string
 65:      *
 66:      * @since 1.0
 67:      */
 68:     private $title;
 69: 
 70:     /**
 71:      * The absolute path to the source image.
 72:      *
 73:      * @var string
 74:      *
 75:      * @since 1.0
 76:      */
 77:     private $source;
 78: 
 79:     /**
 80:      * The width of the image (can differ from the source file when scale=true).
 81:      *
 82:      * @var Alpha\Model\Type\Integer
 83:      *
 84:      * @since 1.0
 85:      */
 86:     private $width;
 87: 
 88:     /**
 89:      * The height of the image (can differ from the source file when scale=true).
 90:      *
 91:      * @var Alpha\Model\Type\Integer
 92:      *
 93:      * @since 1.0
 94:      */
 95:     private $height;
 96: 
 97:     /**
 98:      * The file type of the source image (gif, jpg, or png supported).
 99:      *
100:      * @var Alpha\Model\Type\Enum
101:      *
102:      * @since 1.0
103:      */
104:     private $sourceType;
105: 
106:     /**
107:      * The quality of the jpg image generated (0.00 to 1.00, 0.75 by default).
108:      *
109:      * @var Alpha\Model\Type\Double
110:      *
111:      * @since 1.0
112:      */
113:     private $quality;
114: 
115:     /**
116:      * Flag to determine if the image will scale to match the target resolution (false
117:      * by default).
118:      *
119:      * @var Alpha\Model\Type\Boolean
120:      *
121:      * @since 1.0
122:      */
123:     private $scale;
124: 
125:     /**
126:      * Flag to determine if the link to the image will change every 24hrs, making hot-linking
127:      * to the image difficult (false by default).
128:      *
129:      * @var Alpha\Model\Type\Boolean
130:      *
131:      * @since 1.0
132:      */
133:     private $secure;
134: 
135:     /**
136:      * The auto-generated name of the cache file for the image.
137:      *
138:      * @var string
139:      *
140:      * @since 1.0
141:      */
142:     private $filename;
143: 
144:     /**
145:      * Trace logger.
146:      *
147:      * @var Alpha\Util\Logging\Logger
148:      *
149:      * @since 1.0
150:      */
151:     private static $logger = null;
152: 
153:     /**
154:      * The constructor.
155:      *
156:      * @param $source
157:      * @param $width
158:      * @param $height
159:      * @param $sourceType
160:      * @param $quality
161:      * @param $scale
162:      *
163:      * @throws Alpha\Exception\IllegalArguementException
164:      *
165:      * @since 1.0
166:      */
167:     public function __construct($source, $width, $height, $sourceType, $quality = 0.75, $scale = false, $secure = false)
168:     {
169:         self::$logger = new Logger('Image');
170:         self::$logger->debug('>>__construct(source=['.$source.'], width=['.$width.'], height=['.$height.'], sourceType=['.$sourceType.'], quality=['.$quality.'], scale=['.$scale.'], secure=['.$secure.'])');
171: 
172:         $config = ConfigProvider::getInstance();
173: 
174:         if (file_exists($source)) {
175:             $this->source = $source;
176:         } else {
177:             throw new IllegalArguementException('The source file for the Image widget ['.$source.'] cannot be found!');
178:         }
179: 
180:         $this->sourceType = new Enum();
181:         $this->sourceType->setOptions(array('jpg', 'png', 'gif'));
182:         $this->sourceType->setValue($sourceType);
183: 
184:         if ($quality < 0.0 || $quality > 1.0) {
185:             throw new IllegalArguementException('The quality setting of ['.$quality.'] is outside of the allowable range of 0.0 to 1.0');
186:         }
187: 
188:         $this->quality = new Double($quality);
189:         $this->scale = new Boolean($scale);
190:         $this->secure = new Boolean($secure);
191: 
192:         $this->width = new Integer($width);
193:         $this->height = new Integer($height);
194: 
195:         $this->setFilename();
196: 
197:         self::$logger->debug('<<__construct');
198:     }
199: 
200:     /**
201:      * Renders the HTML <img> tag to the ViewImage controller, with all of the correct params to render the source
202:      * image in the desired resolution.
203:      *
204:      * @param $altText Set this value to render alternate text as part of the HTML link (defaults to no alternate text)
205:      *
206:      * @return string
207:      *
208:      * @since 1.0
209:      */
210:     public function renderHTMLLink($altText = '')
211:     {
212:         $config = ConfigProvider::getInstance();
213: 
214:         if ($this->secure->getBooleanValue()) {
215:             $params = Controller::generateSecurityFields();
216: 
217:             return '<img src="'.FrontController::generateSecureURL('act=Alpha\Controller\ImageController&source='.$this->source.'&width='.$this->width->getValue().'&height='.$this->height->getValue().'&type='.$this->sourceType->getValue().'&quality='.$this->quality->getValue().'&scale='.$this->scale->getValue().'&secure='.$this->secure->getValue().'&var1='.$params[0].'&var2='.$params[1]).'"'.(empty($altText) ? '' : ' alt="'.$altText.'"').($config->get('cms.images.widget.bootstrap.responsive') ? ' class="img-responsive"' : '').'/>';
218:         } else {
219:             return '<img src="'.FrontController::generateSecureURL('act=Alpha\Controller\ImageController&source='.$this->source.'&width='.$this->width->getValue().'&height='.$this->height->getValue().'&type='.$this->sourceType->getValue().'&quality='.$this->quality->getValue().'&scale='.$this->scale->getValue().'&secure='.$this->secure->getValue()).'"'.(empty($altText) ? '' : ' alt="'.$altText.'"').($config->get('cms.images.widget.bootstrap.responsive') ? ' class="img-responsive"' : '').'/>';
220:         }
221:     }
222: 
223:     /**
224:      * Setter for the filename, which also creates a sub-directory under /cache for images when required.
225:      *
226:      * @since 1.0
227:      *
228:      * @throws Alpha\Exception\AlphaException
229:      */
230:     private function setFilename()
231:     {
232:         $config = ConfigProvider::getInstance();
233: 
234:         if (!strpos($this->source, 'attachments/article_')) {
235:             // checking to see if we will write a jpg or png to the cache
236:             if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
237:                 $this->filename = $config->get('app.file.store.dir').'cache/images/'.basename($this->source, '.'.$this->sourceType->getValue()).'_'.$this->width->getValue().'x'.$this->height->getValue().'.png';
238:             } else {
239:                 $this->filename = $config->get('app.file.store.dir').'cache/images/'.basename($this->source, '.'.$this->sourceType->getValue()).'_'.$this->width->getValue().'x'.$this->height->getValue().'.jpg';
240:             }
241:         } else {
242:             // make a cache dir for the article
243:             $cacheDir = $config->get('app.file.store.dir').'cache/images/article_'.mb_substr($this->source, mb_strpos($this->source, 'attachments/article_') + 20, 11);
244:             if (!file_exists($cacheDir)) {
245:                 $success = mkdir($cacheDir);
246: 
247:                 if (!$success) {
248:                     throw new AlphaException('Unable to create the folder '.$cacheDir.' for the cache image, source file is '.$this->source);
249:                 }
250: 
251:                 // ...and set write permissions on the folder
252:                 $success = chmod($cacheDir, 0777);
253: 
254:                 if (!$success) {
255:                     throw new AlphaException('Unable to set write permissions on the folder ['.$cacheDir.'].');
256:                 }
257:             }
258: 
259:             // now set the filename to include the new cache directory
260:             if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
261:                 $this->filename = $cacheDir.'/'.basename($this->source, '.'.$this->sourceType->getValue()).'_'.$this->width->getValue().'x'.$this->height->getValue().'.png';
262:             } else {
263:                 $this->filename = $cacheDir.'/'.basename($this->source, '.'.$this->sourceType->getValue()).'_'.$this->width->getValue().'x'.$this->height->getValue().'.jpg';
264:             }
265:         }
266: 
267:         self::$logger->debug('Image filename is ['.$this->filename.']');
268:     }
269: 
270:     /**
271:      * Gets the auto-generated filename for the image in the /cache directory.
272:      *
273:      * @since 1.0
274:      */
275:     public function getFilename()
276:     {
277:         return $this->filename;
278:     }
279: 
280:     /**
281:      * Renders the actual binary image using GD library calls.
282:      *
283:      *  @since 1.0
284:      */
285:     public function renderImage()
286:     {
287:         $config = ConfigProvider::getInstance();
288: 
289:         // if scaled, we need to compute the target image size
290:         if ($this->scale->getBooleanValue() && isset($_COOKIE['screenSize'])) {
291:             $originalScreenResolution = explode('x', $config->get('sysCMSImagesWidgetScreenResolution'));
292:             $originalScreenX = $originalScreenResolution[0];
293:             $originalScreenY = $originalScreenResolution[1];
294: 
295:             $targetScreenResolution = explode('x', $_COOKIE['screenSize']);
296:             $targetScreenX = $targetScreenResolution[0];
297:             $targetScreenY = $targetScreenResolution[1];
298: 
299:             // calculate the new units we will scale by
300:             $xu = $targetScreenX / $originalScreenX;
301:             $yu = $targetScreenY / $originalScreenY;
302: 
303:             $this->width = new Integer(intval($this->width->getValue() * $xu));
304:             $this->height = new Integer(intval($this->height->getValue() * $yu));
305: 
306:             // need to update the cache filename as the dimensions have changed
307:             $this->setFilename();
308:         }
309: 
310:         // check the image cache first before we proceed
311:         if ($this->checkCache()) {
312:             $this->loadCache();
313:         } else {
314:             // now get the old image
315:             switch ($this->sourceType->getValue()) {
316:                 case 'gif':
317:                     $old_image = imagecreatefromgif($this->source);
318:                 break;
319:                 case 'jpg':
320:                     $old_image = imagecreatefromjpeg($this->source);
321:                 break;
322:                 case 'png':
323:                     $old_image = imagecreatefrompng($this->source);
324:                 break;
325:             }
326: 
327:             if (!$old_image) {
328:                 $im = imagecreatetruecolor($this->width->getValue(), $this->height->getValue());
329:                 $bgc = imagecolorallocate($im, 255, 255, 255);
330:                 $tc = imagecolorallocate($im, 0, 0, 0);
331:                 imagefilledrectangle($im, 0, 0, $this->width->getValue(), $this->height->getValue(), $bgc);
332: 
333:                 imagestring($im, 1, 5, 5, "Error loading $this->source", $tc);
334:                 if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
335:                     imagepng($im);
336:                 } else {
337:                     imagejpeg($im);
338:                 }
339:                 imagedestroy($im);
340:             } else {
341:                 // the dimensions of the source image
342:                 $oldWidth = imagesx($old_image);
343:                 $oldHeight = imagesy($old_image);
344: 
345:                 // now create the new image
346:                 $new_image = imagecreatetruecolor($this->width->getValue(), $this->height->getValue());
347: 
348:                 // set a transparent background for PNGs
349:                 if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
350:                     // Turn off transparency blending (temporarily)
351:                     imagealphablending($new_image, false);
352: 
353:                     // Create a new transparent color for image
354:                     $color = imagecolorallocatealpha($new_image, 255, 0, 0, 0);
355: 
356:                     // Completely fill the background of the new image with allocated color.
357:                     imagefill($new_image, 0, 0, $color);
358: 
359:                     // Restore transparency blending
360:                     imagesavealpha($new_image, true);
361:                 }
362:                 // copy the old image to the new image (in memory, not the file!)
363:                 imagecopyresampled($new_image, $old_image, 0, 0, 0, 0, $this->width->getValue(), $this->height->getValue(), $oldWidth, $oldHeight);
364: 
365:                 if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
366:                     imagepng($new_image);
367:                 } else {
368:                     imagejpeg($new_image, null, 100 * $this->quality->getValue());
369:                 }
370: 
371:                 $this->cache($new_image);
372:                 imagedestroy($old_image);
373:                 imagedestroy($new_image);
374:             }
375:         }
376:     }
377: 
378:     /**
379:      * Caches the image to the cache directory.
380:      *
381:      * @param image $image the binary GD image stream to save
382:      *
383:      * @since 1.0
384:      */
385:     private function cache($image)
386:     {
387:         $config = ConfigProvider::getInstance();
388: 
389:         if ($this->sourceType->getValue() == 'png' && $config->get('cms.images.perserve.png')) {
390:             imagepng($image, $this->filename);
391:         } else {
392:             imagejpeg($image, $this->filename, 100 * $this->quality->getValue());
393:         }
394:     }
395: 
396:     /**
397:      * Used to check the image cache for the image jpeg cache file.
398:      *
399:      * @return bool
400:      *
401:      * @since 1.0
402:      */
403:     private function checkCache()
404:     {
405:         return file_exists($this->filename);
406:     }
407: 
408:     /**
409:      * Method to load the content of the image cache file to the standard output stream (the browser).
410:      *
411:      * @since 1.0
412:      */
413:     private function loadCache()
414:     {
415:         readfile($this->filename);
416:     }
417: 
418:     /**
419:      * Converts a URL for an image to a relative file system path for the image, assuming it is
420:      * hosted on the same server as the application.
421:      *
422:      * @param string $imgURL
423:      *
424:      * @return string the path of the image
425:      *
426:      * @since 1.0
427:      */
428:     public static function convertImageURLToPath($imgURL)
429:     {
430:         $config = ConfigProvider::getInstance();
431: 
432:         $imgPath = str_replace($config->get('app.url').'/', '', $imgURL);
433: 
434:         return $imgPath;
435:     }
436: }
437: 
Alpha Framework 2.0.4 API Documentation API documentation generated by ApiGen 2.8.0