Version: current

      1 <?php
      2 /**
      3  * This Controller handles all operation needed for ImageEditor to work(expect for GD operations).
      4  * @package cms
      5  * @subpackage assets
      6  */
      7 class ImageEditor extends Controller {
      8
      9     static $allowed_actions = array(
     10         '*' => 'CMS_ACCESS_CMSMain'
     11     );
     12
     13     public $fileToEdit = "";
     14
     15     public $fileToEditOnlyName = "";
     16
     17     /**
     18      * Includes all JS required for ImageEditor. This method requires setting
     19      * a fileToEdit URL in POST.
     20      *
     21      * @return String
     22     */
     23     public function index() {
     24         Requirements::clear();
     25         Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/prototype/prototype.js');
     26         Requirements::javascript(THIRDPARTY_DIR . '/scriptaculous/scriptaculous.js');
     27         Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/Utils.js');
     28         //Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/ImageHistory.js');
     29         Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/Image.js');
     30         //Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/ImageTransformation.js');
     31         Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/Resizeable.js');
     32         Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/Effects.js');
     33         Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/Environment.js');
     34         Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/Crop.js');
     35         Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/Resize.js');
     36         Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/ImageBox.js');
     37         Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/ImageEditor.js');
     38         Requirements::javascript(CMS_DIR . '/javascript/ImageEditor/DocumentBody.js');
     39
     40         Requirements::javascript(SAPPHIRE_DIR . '/javascript/loader.js');
     41         Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/behaviour/behaviour.js');
     42         Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain.js');
     43         Requirements::css(CMS_DIR . 'css/ImageEditor/ImageEditor.css');
     44
     45         if(!isset($this->requestParams['fileToEdit'])) $this->raiseError();
     46         $fileWithPath = $this->requestParams['fileToEdit'];
     47         $this->fileToEdit = $this->file2Origin($fileWithPath);
     48         $this->fileToEditOnlyName = $this->urlToFilename($this->fileToEdit);
     49         return $this->renderWith(__CLASS__);
     50     }
     51
     52     /**
     53      * Method is used for manipulating photos.
     54      * Method requires two params set in POST
     55      *  file - file on which operation will be performed
     56      *  command - name of operation(crop|rotate|resize)
     57      *
     58      * Each operation requires additional parameters.
     59      *
     60      * @return String - JSON array with image properties (width,height,url).
     61     */
     62     public function manipulate() {
     63         $fileName = $this->requestParams['file'];
     64         if(strpos($fileName,'?') !== false) $fileName = substr($fileName,0,strpos($fileName,'?'));
     65         $command = $this->requestParams['command'];
     66         $this->checkFileExists($fileName);
     67         $fileInfo = pathinfo($fileName);
     68         $gd = new GD($this->url2File($fileName));
     69         switch($command) {
     70             case 'rotate':
     71                 $gd = $gd->rotate(90);
     72             break;
     73             case 'resize':
     74                 $imageNewWidth = $_POST['newImageWidth'];
     75                 $imageNewHeight = $_POST['newImageHeight'];
     76                 $gd = $gd->resize($imageNewWidth,$imageNewHeight);
     77             break;
     78             case 'crop':
     79                 $top = $_POST['top'];
     80                 $left = $_POST['left'];
     81                 $width = $_POST['width'];
     82                 $height = $_POST['height'];
     83                 $gd = $gd->crop($top,$left,$width,$height);
     84             break;
     85             case 'greyscale':
     86                 $gd = $gd->greyscale();
     87                 break;
     88             case 'sepia':
     89                 $gd = $gd->sepia();
     90                 break;
     91             case 'blur':
     92                 $gd = $gd->blur();
     93                 break;
     94             case 'adjust-contrast':
     95                 $value = intval($_POST['value']);
     96                 $gd = $gd->contrast($value);
     97                 break;
     98             case 'adjust-brightness':
     99                 $value = intval($_POST['value']);
    100                 $gd = $gd->brightness($value);
    101                 break;
    102             case 'adjust-gamma':
    103                 $value = floatval($_POST['value']);
    104                 $gd = $gd->gamma($value);
    105                 break;
    106         }
    107         $rand = md5(rand(1,100000));
    108         $gd->writeTo(ASSETS_PATH . '/_tmp/' . $rand . '.' . $fileInfo['extension']);
    109         return $this->getImageInfoInJSON($gd,ASSETS_PATH . '/_tmp/' . $rand . '.' . $fileInfo['extension']);
    110     }
    111
    112     /**
    113      * Method is used for saving photos.
    114      * Method requires two params set in POST
    115      *  originalFile - this file will be replaced by second file
    116      *  editedFile - this file will replace first file.
    117      *
    118      * After replacing original file all thumbnails created from it are removed.
    119      *
    120      * @return String - Message that everything went ok.
    121     */
    122
    123     public function save() {
    124         if(isset($this->requestParams['originalFile']) && isset($this->requestParams['editedFile'])) {
    125             $originalFile = $this->requestParams['originalFile'];
    126             $editedFile = $this->requestParams['editedFile'];
    127             if(strpos($originalFile,'?') !== false) $originalFile = substr($originalFile,0,strpos($originalFile,'?'));
    128             if($this->checkFileExists($originalFile) && $this->checkFileExists($editedFile)) {
    129                 if($editedFile != $originalFile && copy($this->url2File($editedFile),$this->url2File($originalFile))) {
    130                     $image = DataObject::get_one('File','"Filename" = \'' . substr($this->url2File($originalFile),3) . '\'');
    131                        $image->deleteFormattedImages();
    132                     $image->generateFormattedImage('AssetLibraryPreview');
    133                 } else {
    134                     $this->raiseError();
    135                 }
    136             } else {
    137                 $this->raiseError();
    138             }
    139         } else {
    140             $this->raiseError();
    141         }
    142         return 'parent.parent.parent.statusMessage(\'Image saved\',\'good\',false);';
    143     }
    144
    145     /**
    146      * Method is invoked when ImageEditor is closed whether image is saved or not.
    147      *
    148      * /assets/tmp is folder where we store temporary images created during editing so
    149      * after closing they are no necessity to keep them.
    150      *
    151      * @return null
    152     */
    153
    154     public function close() {
    155         $tmpDir = ASSETS_PATH . '/_tmp';
    156         if(file_exists($tmpDir)) {
    157             Filesystem::removeFolder($tmpDir);
    158             mkdir($tmpDir, Filesystem::$folder_create_mask);
    159         }
    160     }
    161
    162     /**
    163      * Method return JSON array containing info about image.
    164      *
    165      * @param gd - GD object used for retrieving info about image
    166      * @param file
    167      *
    168      * @return string JSON array explained in manipulate method comment
    169     */
    170
    171     private function getImageInfoInJSON(GD $gd,$file) {
    172         return '{"fileName":"' . $file . '","width":' . $gd->getWidth() . ',"height":' . $gd->getHeight() . '}';
    173     }
    174
    175     /**
    176      * Method converts thumbnail file name to file name of it's "parent"
    177      *
    178      * @param file - name of thumbnail file
    179      *
    180      * @return string name of parent file.
    181     */
    182
    183     private function file2Origin($file) {
    184         $file = str_replace('_resampled/','',$file);
    185         $file = str_replace('_resampled/','',$file);
    186         $file = str_replace('AssetLibraryPreview-','',$file);
    187         $this->checkFileExists($file);
    188         return $file;
    189     }
    190     /**
    191      * Method converts URL of file to file path in file system.
    192      *
    193      * @param url - url of file
    194      *
    195      * @return string path of file in file system
    196     */
    197
    198     private function url2File($url) {
    199         return '..' . substr($url,strpos($url,'/assets'));
    200     }
    201
    202     /**
    203      * Method checks if file exists and have proper name and extension.
    204      *
    205      * If any of constraints aren't fulfilled method will generate error.
    206      *
    207      * @param url - url of file
    208      *
    209      * @return boolean
    210     */
    211
    212     private function checkFileExists($url) {
    213         if(strpos($url,'?') !== false) $url = substr($url,0,strpos($url,'?'));
    214         $pathInfo = pathinfo($url);
    215         if(count($pathInfo) < 3) $this->raiseError();
    216         if(!in_array($pathInfo['extension'],array('jpeg','jpg','jpe','png','gif','JPEG','JPG','JPE','PNG','GIF'))) $this->raiseError();
    217         $path = explode('/',$pathInfo['dirname']);
    218         if(count($path) > 1) {
    219             $assetId = array_search('assets',$path);
    220             if($assetId > 0) {
    221                 $realPath = '../' . implode('/',array_slice($path,$assetId,count($path) - $assetId));
    222                 if(strpos($pathInfo['basename'],'AssetLibraryPreview') !== false) {
    223                     $realPath .= '/' . substr($pathInfo['basename'],strpos($pathInfo['basename'],'-'));
    224                 } else {
    225                     $realPath .= '/' . $pathInfo['basename'];
    226                 }
    227             } else {
    228                 $this->raiseError();
    229             }
    230             if(file_exists($realPath)) {
    231                 return true;
    232             } else {
    233                 $this->raiseError();
    234             }
    235         } else {
    236             $this->raiseError();
    237         }
    238     }
    239
    240     /**
    241      * Method raiser error. Error is showed using statusMessage function.
    242      *
    243      * @param message - error message
    244      *
    245     */
    246
    247     private function raiseError($message = "") {
    248         echo "parent.parent.parent.statusMessage('Error: " . $message . "','bad',false);";
    249         exit();
    250     }
    251
    252     /**
    253         * Method converts retrieves filename from url
    254         *
    255         * @param url
    256         *
    257        */
    258
    259     private function urlToFilename($url) {
    260         $path = pathinfo($url);
    261         return $path['filename'] . "." . substr($path['extension'],0,strpos($path['extension'],'?'));
    262     }
    263 }
    264
    265 ?>

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -