Move to sane directory structure. Don't make 'cms' the top level of the silverstripe...
[silverstripe-elijah.git] / silverstripe-gsoc / cms / code / ImageEditor.php
blobfbed747879c843da77b521c2a817994e802100ce
1 <?php
2 /**
3 * This Controller handles all operation needed for ImageEditor to work(expect for GD operations).
4 *
5 */
7 class ImageEditor extends Controller {
9 public $fileToEdit = "";
11 /**
12 * Includes all JS required for ImageEditor. This method requires setting
13 * a fileToEdit URL in POST.
15 * @return String
16 */
17 public function index() {
18 Requirements::clear();
19 Requirements::javascript('jsparty/prototype.js');
20 Requirements::javascript('jsparty/scriptaculous/scriptaculous.js');
21 Requirements::javascript('cms/javascript/ImageEditor/Utils.js');
22 Requirements::javascript('cms/javascript/ImageEditor/ImageHistory.js');
23 Requirements::javascript('cms/javascript/ImageEditor/Image.js');
24 Requirements::javascript('cms/javascript/ImageEditor/ImageTransformation.js');
25 Requirements::javascript('cms/javascript/ImageEditor/Resizeable.js');
26 Requirements::javascript('cms/javascript/ImageEditor/Effects.js');
27 Requirements::javascript('cms/javascript/ImageEditor/Environment.js');
28 Requirements::javascript('cms/javascript/ImageEditor/Crop.js');
29 Requirements::javascript('cms/javascript/ImageEditor/Resize.js');
30 Requirements::javascript('cms/javascript/ImageEditor/ImageBox.js');
31 Requirements::javascript('cms/javascript/ImageEditor/ImageEditor.js');
32 Requirements::javascript('cms/javascript/ImageEditor/DocumentBody.js');
34 Requirements::javascript('jsparty/loader.js');
35 Requirements::javascript('jsparty/behaviour.js');
36 Requirements::javascript('cms/javascript/LeftAndMain.js');
37 Requirements::css('cms/css/ImageEditor/ImageEditor.css');
39 if(!isset($this->requestParams['fileToEdit'])) $this->raiseError();
40 $fileWithPath = $this->requestParams['fileToEdit'];
41 $this->fileToEdit = $this->file2Origin($fileWithPath);
42 return $this->renderWith(__CLASS__);
45 /**
46 * Method is used for manipulating photos.
47 * Method requires two params set in POST
48 * file - file on which operation will be performed
49 * command - name of operation(crop|rotate|resize)
51 * Each operation requires additional parameters.
53 * @return String - JSON array with image properties (width,height,url).
54 */
55 public function manipulate() {
56 $fileName = $this->requestParams['file'];
57 if(strpos($fileName,'?') !== false) $fileName = substr($fileName,0,strpos($fileName,'?'));
58 $command = $this->requestParams['command'];
59 $this->checkFileExists($fileName);
60 $fileInfo = pathinfo($fileName);
61 $gd = new GD($fileName);
62 switch($command) {
63 case 'rotate':
64 $angle = $_POST['angle'];
65 $gd = $gd->rotate($angle);
66 break;
67 case 'resize':
68 $imageNewWidth = $_POST['newImageWidth'];
69 $imageNewHeight = $_POST['newImageHeight'];
70 $gd = $gd->resize($imageNewWidth,$imageNewHeight);
71 break;
72 case 'crop':
73 $top = $_POST['top'];
74 $left = $_POST['left'];
75 $width = $_POST['width'];
76 $height = $_POST['height'];
77 $gd = $gd->crop($top,$left,$width,$height);
78 break;
80 $rand = md5(rand(1,100000));
81 $gd->writeTo('../assets/_tmp/' . $rand . '.' . $fileInfo['extension']);
82 return $this->getImageInfoInJSON($gd,'assets/_tmp/' . $rand . '.' . $fileInfo['extension']);
85 /**
86 * Method is used for saving photos.
87 * Method requires two params set in POST
88 * originalFile - this file will be replaced by second file
89 * editedFile - this file will replace first file.
91 * After replacing original file all thumbnails created from it are removed.
93 * @return String - Message that everything went ok.
94 */
96 public function save() {
97 if(isset($this->requestParams['originalFile']) && isset($this->requestParams['editedFile'])) {
98 $originalFile = $this->requestParams['originalFile'];
99 $editedFile = $this->requestParams['editedFile'];
100 if(strpos($originalFile,'?') !== false) $originalFile = substr($originalFile,0,strpos($originalFile,'?'));
101 if($this->checkFileExists($originalFile) && $this->checkFileExists($editedFile)) {
102 if($editedFile != $originalFile && copy($this->url2File($editedFile),$this->url2File($originalFile))) {
103 $image = DataObject::get_one('File','Filename = \'' . substr($this->url2File($originalFile),3) . '\'');
104 $image->generateFormattedImage('AssetLibraryPreview');
105 } else {
106 $this->raiseError();
108 } else {
109 $this->raiseError();
111 } else {
112 $this->raiseError();
114 return 'parent.parent.parent.statusMessage(\'Image saved\',\'good\',false);';
118 * Method is invoked when ImageEditor is closed whether image is saved or not.
120 * /assets/tmp is folder where we store temporary images created during editing so
121 * after closing they are no necessity to keep them.
123 * @return null
126 public function close() {
127 $tmpDir = '../assets/_tmp';
128 if(file_exists($tmpDir)) {
129 Filesystem::removeFolder($tmpDir);
130 mkdir($tmpDir);
131 chmod($tmpDir, 02775);
136 * Method return JSON array containing info about image.
138 * @param gd - GD object used for retrieving info about image
139 * @param file
141 * @return string JSON array explained in manipulate method comment
144 private function getImageInfoInJSON(GD $gd,$file) {
145 return '{"fileName":"' . $file . '","width":' . $gd->getWidth() . ',"height":' . $gd->getHeight() . '}';
149 * Method converts thumbnail file name to file name of it's "parent"
151 * @param file - name of thumbnail file
153 * @return string name of parent file.
156 private function file2Origin($file) {
157 $file = str_replace('_resampled/','',$file);
158 $file = str_replace('_resampled/','',$file);
159 $file = str_replace('AssetLibraryPreview-','',$file);
160 $this->checkFileExists($file);
161 return $file;
164 * Method converts URL of file to file path in file system.
166 * @param url - url of file
168 * @return string path of file in file system
171 private function url2File($url) {
172 return '..' . substr($url,strpos($url,'/assets'));
176 * Method checks if file exists and have proper name and extension.
178 * If any of constraints aren't fulfilled method will generate error.
180 * @param url - url of file
182 * @return boolean
185 private function checkFileExists($url) {
186 if(strpos($url,'?') !== false) $url = substr($url,0,strpos($url,'?'));
187 $pathInfo = pathinfo($url);
188 if(count($pathInfo) < 3) $this->raiseError();
189 if(!in_array(strtolower($pathInfo['extension']),array('jpeg','jpg','jpe','png','gif'))) $this->raiseError();
190 $path = explode('/',$pathInfo['dirname']);
191 if(count($path) > 1) {
192 $assetId = array_search('assets',$path);
193 if($assetId > 0) {
194 $realPath = '../' . implode('/',array_slice($path,$assetId,count($path) - $assetId));
195 if(strpos($pathInfo['basename'],'AssetLibraryPreview') !== false) {
196 $realPath .= '/' . substr($pathInfo['basename'],strpos($pathInfo['basename'],'-'));
197 } else {
198 $realPath .= '/' . $pathInfo['basename'];
200 } else {
201 $this->raiseError();
203 if(file_exists($realPath)) {
204 return true;
205 } else {
206 $this->raiseError();
208 } else {
209 $this->raiseError();
214 * Method raiser error. Error is showed using statusMessage function.
216 * @param message - error message
220 private function raiseError($message = "") {
221 echo "parent.parent.parent.statusMessage('Error: " . $message . "','bad',false);";
222 exit();