Source for file ImageEditor.php

Documentation is available at ImageEditor.php

  1. <?php
  2. /**
  3.  * Image Editor. Editing tools, crop, rotate, scale and save.
  4.  * @author $Author$
  5.  * @version $Id$
  6.  * @package ImageManager
  7.  */
  8.  
  9. require_once('Transform.php');
  10.  
  11. /**
  12.  * Handles the basic image editing capbabilities.
  13.  * @author $Author$
  14.  * @version $Id$
  15.  * @package ImageManager
  16.  * @subpackage Editor
  17.  */
  18. class ImageEditor 
  19. {
  20.     /**
  21.      * ImageManager instance.
  22.      */
  23.     var $manager;
  24.  
  25.     /**
  26.      * user based on IP address
  27.      */
  28.     var $_uid;
  29.  
  30.     /**
  31.      * tmp file storage time.
  32.      */
  33.     var $lapse_time =900//15 mins
  34.  
  35.     var $filesaved = 0;
  36.  
  37.     /**
  38.      * Create a new ImageEditor instance. Editing requires a
  39.      * tmp file, which is saved in the current directory where the
  40.      * image is edited. The tmp file is assigned by md5 hash of the
  41.      * user IP address. This hashed is used as an ID for cleaning up
  42.      * the tmp files. In addition, any tmp files older than the
  43.      * the specified period will be deleted.
  44.      * @param ImageManager $manager the image manager, we need this
  45.      *  for some file and path handling functions.
  46.      */
  47.     function ImageEditor($manager
  48.     {
  49.         $this->manager = $manager;
  50.         $this->_uid = md5($_SERVER['REMOTE_ADDR']);
  51.     }
  52.     
  53.     /**
  54.      * Did we save a file?
  55.      * @return int 1 if the file was saved sucessfully,
  56.      *  0 no save operation, -1 file save error.
  57.      */
  58.     function isFileSaved(
  59.     {
  60.         Return $this->filesaved;
  61.     }
  62.  
  63.     /**
  64.      * Process the image, if not action, just display the image.
  65.      * @return array with image information, empty array if not an image.
  66.      *  <code>array('src'=>'url of the image', 'dimensions'=>'width="xx" height="yy"',
  67.      *  'file'=>'image file, relative', 'fullpath'=>'full path to the image');</code>
  68.      */
  69.     function processImage(
  70.     {
  71.         if(isset($_GET['img']))
  72.             $relative rawurldecode($_GET['img']);
  73.         else
  74.             Return array();
  75.         
  76.         //$relative = '/Series2004NoteFront.jpg';
  77.  
  78.         $imgURL $this->manager->getFileURL($relative);
  79.         $fullpath $this->manager->getFullPath($relative);
  80.         $imgInfo @getImageSize($fullpath);
  81.         if(!is_array($imgInfo))
  82.             Return array();
  83.  
  84.         $action $this->getAction();
  85.  
  86.         if(!is_null($action))
  87.         {
  88.             $image $this->processAction($action$relative$fullpath);
  89.         }
  90.         else
  91.         {
  92.             $image['src'$imgURL;
  93.             $image['dimensions'$imgInfo[3];
  94.             $image['file'$relative;
  95.             $image['fullpath'$fullpath;
  96.         }
  97.  
  98.         Return $image;
  99.     }
  100.  
  101.     /**
  102.      * Process the actions, crop, scale(resize), rotate, flip, and save.
  103.      * When ever an action is performed, the result is save into a
  104.      * temporary image file, see createUnique on the filename specs.
  105.      * It does not return the saved file, alway returning the tmp file.
  106.      * @param string $action, should be 'crop', 'scale', 'rotate','flip', or 'save'
  107.      * @param string $relative the relative image filename
  108.      * @param string $fullpath the fullpath to the image file
  109.      * @return array with image information
  110.      *  <code>array('src'=>'url of the image', 'dimensions'=>'width="xx" height="yy"',
  111.      *  'file'=>'image file, relative', 'fullpath'=>'full path to the image');</code>
  112.      */
  113.     function processAction($action$relative$fullpath
  114.     {
  115.         $params '';
  116.         
  117.         if(isset($_GET['params']))
  118.             $params $_GET['params'];
  119.  
  120.         $values =  explode(',',$params,4);
  121.         $saveFile $this->getSaveFileName($values[0]);
  122.  
  123.         $img Image_Transform::factory(IMAGE_CLASS);
  124.         $img->load($fullpath);
  125.  
  126.         switch ($action
  127.         {
  128.             case 'crop':
  129.                 $img->crop(intval($values[0]),intval($values[1]),
  130.                             intval($values[2]),intval($values[3]));
  131.             break;
  132.             case 'scale':
  133.                 $img->resize(intval($values[0]),intval($values[1]));
  134.                 break;
  135.             case 'rotate':
  136.                 $img->rotate(floatval($values[0]));
  137.                 break;
  138.             case 'flip':
  139.                 if ($values[0== 'hoz')
  140.                     $img->flip(true);
  141.                 else if($values[0== 'ver'
  142.                     $img->flip(false);
  143.                 break;
  144.             case 'save':
  145.                 if(!is_null($saveFile))
  146.                 {
  147.                     $quality intval($values[1]);
  148.                     if($quality <0$quality 85;
  149.                     $newSaveFile $this->makeRelative($relative$saveFile);
  150.                     $newSaveFile $this->getUniqueFilename($newSaveFile);
  151.                     
  152.                     //get unique filename just returns the filename, so
  153.                     //we need to make the relative path once more.
  154.                     $newSaveFile $this->makeRelative($relative$newSaveFile);
  155.                     $newSaveFullpath $this->manager->getFullPath($newSaveFile);
  156.                     $img->save($newSaveFullpath$values[0]$quality);
  157.                     if(is_file($newSaveFullpath))
  158.                         $this->filesaved = 1;
  159.                     else
  160.                         $this->filesaved = -1;
  161.                 }
  162.                 break;
  163.         }
  164.         
  165.         //create the tmp image file
  166.         $filename $this->createUnique($fullpath);
  167.         $newRelative $this->makeRelative($relative$filename);
  168.         $newFullpath $this->manager->getFullPath($newRelative);
  169.         $newURL $this->manager->getFileURL($newRelative);
  170.         
  171.         //save the file.
  172.         $img->save($newFullpath);
  173.         $img->free();
  174.  
  175.         //get the image information
  176.         $imgInfo @getimagesize($newFullpath);
  177.  
  178.         $image['src'$newURL;
  179.         $image['dimensions'$imgInfo[3];
  180.         $image['file'$newRelative;
  181.         $image['fullpath'$newFullpath;
  182.  
  183.         Return $image;
  184.     
  185.     }
  186.  
  187.     /**
  188.      * Get the file name base on the save name
  189.      * and the save type.
  190.      * @param string $type image type, 'jpeg', 'png', or 'gif'
  191.      * @return string the filename according to save type
  192.      */
  193.     function getSaveFileName($type
  194.     {
  195.         if(!isset($_GET['file']))
  196.             Return null;
  197.  
  198.         $filename Files::escape(rawurldecode($_GET['file']));
  199.         $index strrpos($filename,'.');
  200.         $base substr($filename,0,$index);
  201.         $ext strtolower(substr($filename,$index+1,strlen($filename)));
  202.  
  203.         if($type == 'jpeg' && !($ext=='jpeg' || $ext=='jpg'))
  204.         {
  205.             Return $base.'.jpeg';
  206.         }
  207.         if($type=='png' && $ext != 'png')
  208.             Return $base.'.png';
  209.         if($type=='gif' && $ext != 'gif')
  210.             Return $base.'.gif';
  211.  
  212.         Return $filename;
  213.     }
  214.  
  215.     /**
  216.      * Get the default save file name, used by editor.php.
  217.      * @return string a suggestive filename, this should be unique
  218.      */
  219.     function getDefaultSaveFile(
  220.     {
  221.         if(isset($_GET['img']))
  222.             $relative rawurldecode($_GET['img']);
  223.         else
  224.             Return null;
  225.  
  226.         Return $this->getUniqueFilename($relative);
  227.     }
  228.  
  229.     /**
  230.      * Get a unique filename. If the file exists, the filename
  231.      * base is appended with an increasing integer.
  232.      * @param string $relative the relative filename to the base_dir
  233.      * @return string a unique filename in the current path
  234.      */
  235.     function getUniqueFilename($relative
  236.     {
  237.         $fullpath $this->manager->getFullPath($relative);
  238.         
  239.         $pathinfo pathinfo($fullpath);
  240.  
  241.         $path Files::fixPath($pathinfo['dirname']);
  242.         $file Files::escape($pathinfo['basename']);
  243.         
  244.         $filename $file;
  245.  
  246.         $dotIndex strrpos($file'.');
  247.         $ext '';
  248.  
  249.         if(is_int($dotIndex)) 
  250.         {
  251.             $ext substr($file$dotIndex);
  252.             $base substr($file0$dotIndex);
  253.         }
  254.  
  255.         $counter 0;
  256.         while(is_file($path.$filename)) 
  257.         {
  258.             $counter++;
  259.             $filename $base.'_'.$counter.$ext;
  260.         }
  261.         
  262.         Return $filename;
  263.         
  264.     }
  265.  
  266.     /**
  267.      * Specifiy the original relative path, a new filename
  268.      * and return the new filename with relative path.
  269.      * i.e. $pathA (-filename) + $file
  270.      * @param string $pathA the relative file
  271.      * @param string $file the new filename
  272.      * @return string relative path with the new filename
  273.      */
  274.     function makeRelative($pathA$file
  275.     {
  276.         $index strrpos($pathA,'/');
  277.         if(!is_int($index))
  278.             Return $file;
  279.  
  280.         $path substr($pathA0$index);
  281.         Return Files::fixPath($path).$file;
  282.     }
  283.  
  284.     /**
  285.      * Get the action GET parameter
  286.      * @return string action parameter
  287.      */
  288.     function getAction(
  289.     {
  290.         $action null;
  291.         if(isset($_GET['action']))
  292.             $action $_GET['action'];
  293.         Return $action;
  294.     }
  295.  
  296.     /**
  297.      * Generate a unique string based on md5(microtime()).
  298.      * Well not so uniqe, as it is limited to 6 characters
  299.      * @return string unique string.
  300.      */
  301.     function uniqueStr()
  302.     {
  303.       return substr(md5(microtime()),0,6);
  304.     }
  305.  
  306.     /**
  307.      * Create unique tmp image file name.
  308.      * The filename is based on the tmp file prefix
  309.      * specified in config.inc.php plus
  310.      * the UID (basically a md5 of the remote IP)
  311.      * and some random 6 character string.
  312.      * This function also calls to clean up the tmp files.
  313.      * @param string $file the fullpath to a file
  314.      * @return string a unique filename for that path
  315.      *  NOTE: it only returns the filename, path no included.
  316.      */
  317.     function createUnique($file
  318.     {
  319.         $pathinfo pathinfo($file);
  320.         $path Files::fixPath($pathinfo['dirname']);
  321.         $imgType $this->getImageType($file);
  322.  
  323.         $unique_str $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
  324.  
  325.        //make sure the the unique temp file does not exists
  326.         while (file_exists($path.$unique_str))
  327.         {
  328.             $unique_str $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
  329.         }
  330.  
  331.         $this->cleanUp($path,$pathinfo['basename']);
  332.  
  333.         Return $unique_str;
  334.     }
  335.  
  336.     /**
  337.      * Delete any tmp image files.
  338.      * @param string $path the full path
  339.      *  where the clean should take place.
  340.      */
  341.     function cleanUp($path,$file
  342.     {
  343.         $path Files::fixPath($path);
  344.  
  345.         if(!is_dir($path))
  346.             Return false;
  347.  
  348.         $d @dir($path);
  349.         
  350.         $tmp $this->manager->getTmpPrefix();
  351.         $tmpLen strlen($tmp);
  352.  
  353.         $prefix $tmp.$this->_uid;
  354.         $len strlen($prefix);
  355.  
  356.         while (false !== ($entry $d->read())) 
  357.         {
  358.             //echo $entry."<br>";
  359.             if(is_file($path.$entry&& $this->manager->isTmpFile($entry))
  360.             {
  361.                 if(substr($entry,0,$len)==$prefix && $entry != $file)
  362.                     Files::delFile($path.$entry);
  363.                 else if(substr($entry,0,$tmpLen)==$tmp && $entry != $file)
  364.                 {
  365.                     if(filemtime($path.$entry)+$this->lapse_time < time())
  366.                         Files::delFile($path.$entry);
  367.                 }
  368.             }
  369.         }
  370.         $d->close();
  371.     }
  372.  
  373.     /**
  374.      * Get the image type base on an image file.
  375.      * @param string $file the full path to the image file.
  376.      * @return string of either 'gif', 'jpeg', 'png' or 'bmp'
  377.      *  otherwise it will return null.
  378.      */
  379.     function getImageType($file
  380.     {
  381.         $imageInfo @getImageSize($file);
  382.  
  383.         if(!is_array($imageInfo))
  384.             Return null;
  385.  
  386.         switch($imageInfo[2]
  387.         {
  388.             case 1:
  389.                 Return 'gif';
  390.             case 2:
  391.                 Return 'jpeg';
  392.             case 3:
  393.                 Return 'png';
  394.             case 6:
  395.                 Return 'bmp';
  396.         }
  397.  
  398.         Return null;
  399.     }
  400.  
  401.     /**
  402.      * Check if the specified image can be edit by GD
  403.      * mainly to check that GD can read and save GIFs
  404.      * @return int 0 if it is not a GIF file, 1 is GIF is editable, -1 if not editable.
  405.      */
  406.     function isGDEditable(
  407.     {
  408.         if(isset($_GET['img']))
  409.             $relative rawurldecode($_GET['img']);
  410.         else
  411.             Return 0;
  412.         if(IMAGE_CLASS != 'GD')
  413.             Return 0;
  414.  
  415.         $fullpath $this->manager->getFullPath($relative);
  416.  
  417.         $type $this->getImageType($fullpath);
  418.         if($type != 'gif')
  419.             Return 0;
  420.  
  421.         if(function_exists('ImageCreateFrom'+$type)
  422.             && function_exists('image'+$type))
  423.             Return 1;
  424.         else
  425.             Return -1;
  426.     }
  427.  
  428.     /**
  429.      * Check if GIF can be edit by GD.
  430.      * @return int 0 if it is not using the GD library, 1 is GIF is editable, -1 if not editable.
  431.      */
  432.     function isGDGIFAble(
  433.     {
  434.         if(IMAGE_CLASS != 'GD')
  435.             Return 0;
  436.  
  437.         if(function_exists('ImageCreateFromGif')
  438.             && function_exists('imagegif'))
  439.             Return 1;
  440.         else
  441.             Return -1;
  442.     }
  443. }
  444.  
  445. ?>

Documentation generated on Mon, 05 May 2008 16:20:19 +0400 by phpDocumentor 1.4.0