source: trunk/plugins/MootoolsFileManager/mootools-filemanager/Backend/FileManager.php @ 1245

Last change on this file since 1245 was 1245, checked in by gogo, 9 years ago

ticket:1502

Add support for attributes being set in MootoolsFileManager? for images.
Split out the "modes" of MootoolsFileManager? into different javascript files.

File size: 16.2 KB
Line 
1<?php
2/*
3Script: FileManager.php
4        MooTools FileManager - Backend for the FileManager Script
5
6License:
7        MIT-style license.
8
9Copyright:
10        Copyright (c) 2009 [Christoph Pojer](http://cpojer.net).
11
12Dependencies:
13        - Upload.php
14        - Image.php
15        - getId3 Library
16
17Options:
18        - directory: (string) The base directory to be used for the FileManger
19        - baseURL: (string) Absolute URL to the FileManager files
20        - assetBasePath: (string) The path to all images and swf files
21        - id3Path: (string, optional) The path to the getid3.php file
22        - mimeTypesPath: (string, optional) The path to the MimTypes.ini file.
23        - dateFormat: (string, defaults to *j M Y - H:i*) The format in which dates should be displayed
24        - upload: (boolean, defaults to *false*) Whether to allow uploads or not
25        - destroy: (boolean, defaults to *false*) Whether to allow deletion of files or not
26        - maxUploadSize: (integeter, defaults to *3145728* bytes) The maximum file size for upload in bytes
27        - safe: (string, defaults to *true*) If true, disallows
28        - filter: (string) If specified, the mimetypes to be allowed (for display and upload).
29                Example: image/ allows all Image Mimetypes
30*/
31
32require_once(FileManagerUtility::getPath() . '/Upload.php');
33require_once(FileManagerUtility::getPath() . '/Image.php');
34
35class FileManager {
36       
37        protected $path = null;
38        protected $length = null;
39        protected $basedir = null;
40        protected $basename = null;
41        protected $options;
42        protected $post;
43        protected $get;
44       
45        public function __construct($options){
46                $path = FileManagerUtility::getPath();
47               
48                $this->options = array_merge(array(
49                        'directory' => '../Demos/Files',
50                        'baseURL' => '',
51                        'assetBasePath' => '../Assets',
52                        'id3Path' => $path . '/Assets/getid3/getid3.php',
53                        'mimeTypesPath' => $path . '/MimeTypes.ini',
54                        'dateFormat' => 'j M Y - H:i',
55                        'maxUploadSize' => 1024 * 1024 * 3,
56                        'upload' => false,
57                        'destroy' => false,
58                        'safe' => true,
59                        'filter' => null,
60                       
61                        // Xinha: Allow to specify the "Resize Large Images" tolerance level.
62                        'suggestedMaxImageDimension' => array('width' => 800, 'height' => 600),
63                ), $options);
64               
65                $this->basedir = realpath($this->options['directory']);
66                $this->basename = pathinfo($this->basedir, PATHINFO_BASENAME) . '/';
67                $this->path = realpath($this->options['directory'] . '/../');
68                $this->length = strlen($this->path);
69               
70                header('Expires: Fri, 01 Jan 1990 00:00:00 GMT');
71                header('Cache-Control: no-cache, no-store, max-age=0, must-revalidate');
72               
73                $this->get = $_GET;
74                $this->post = $_POST;
75        }
76       
77        public function fireEvent($event){
78                $event = $event ? 'on' . ucfirst($event) : null;
79                if (!$event || !method_exists($this, $event)) $event = 'onView';
80               
81                $this->{$event}();
82        }
83       
84        protected function onView(){
85                $dir = $this->getDir(!empty($this->post['directory']) ? $this->post['directory'] : null);
86                $files = ($files = glob($dir . '/*')) ? $files : array();
87               
88                if ($dir != $this->basedir) array_unshift($files, $dir . '/..');
89                natcasesort($files);
90                foreach ($files as $file){
91                        $mime = $this->getMimeType($file);
92                        if ($this->options['filter'] && $mime != 'text/directory' && !FileManagerUtility::startsWith($mime, $this->options['filter']))
93                                continue;
94                       
95                        $out[is_dir($file) ? 0 : 1][] = array(
96                                'name' => pathinfo($file, PATHINFO_BASENAME),
97                                'date' => date($this->options['dateFormat'], filemtime($file)),
98                                'mime' => $this->getMimeType($file),
99                                'icon' => $this->getIcon($this->normalize($file)),
100                                'size' => filesize($file)
101                        );
102                }
103               
104                echo json_encode(array(
105                        'path' => $this->getPath($dir),
106                        'dir' => array(
107                                'name' => pathinfo($dir, PATHINFO_BASENAME),
108                                'date' => date($this->options['dateFormat'], filemtime($dir)),
109                                'mime' => 'text/directory',
110                                'icon' => 'dir'
111                        ),
112                        'files' => array_merge(!empty($out[0]) ? $out[0] : array(), !empty($out[1]) ? $out[1] : array())
113                ));
114        }
115       
116        protected function onDetail(){
117                if (empty($this->post['directory']) || empty($this->post['file'])) return;
118               
119                $file = realpath($this->path . '/' . $this->post['directory'] . '/' . $this->post['file']);
120                if (!$this->checkFile($file)) return;
121               
122                require_once($this->options['id3Path']);
123               
124                // Xinha: The URL is weird in the standard distribution of filemanager, it seems to expect
125                // that the files directory (where you are selecting/uploading) is always within the filemanager
126                // directory itself somewhere.
127                //
128                // Also the 'baseURL' seems to be wanted as the parent of the 'basedir' ("directory" option)
129                // Xinha is supplying both the same (eg url = /foo/test and dir = /home/bar/public_html/foo/test )
130                // so we will rip off the first part of directory, below.
131                $url = $this->options['baseURL'] . '/' . preg_replace('/^[^\/]*\//', '', $this->post['directory'] . '/' . $this->post['file']);
132               
133                $mime = $this->getMimeType($file);
134                $content = null;
135               
136    // Xinha: We want to get some more information about what has been selected in a way
137    // we can use it.  Effectively what gets put in here will be passed into the
138    // 'onDetails' event handler of your FileManager object (if any).
139    $extra_return_detail = array
140      (
141        'url'  => $url,
142        'mime' => $mime
143      );
144               
145                if (FileManagerUtility::startsWith($mime, 'image/')){
146                        $size = getimagesize($file);
147                        $content = '<img src="' . $url . '" class="preview" alt="" />
148                                <h2>${more}</h2>
149                                <dl>
150                                        <dt>${width}</dt><dd>' . $size[0] . 'px</dd>
151                                        <dt>${height}</dt><dd>' . $size[1] . 'px</dd>
152                                </dl>';
153               
154        // Xinha: Return some information about the image which can be access
155        // from the onDetails event handler in FileManager
156                                $extra_return_detail['width']  = $size[0];
157                                $extra_return_detail['height'] = $size[1];
158                               
159                }elseif (FileManagerUtility::startsWith($mime, 'text/') || $mime == 'application/x-javascript'){
160                        $filecontent = file_get_contents($file, null, null, 0, 300);
161                        if (!FileManagerUtility::isBinary($filecontent)) $content = '<div class="textpreview">' . nl2br(str_replace(array('$', "\t"), array('&#36;', '&nbsp;&nbsp;'), htmlentities($filecontent))) . '</div>';
162                }elseif ($mime == 'application/zip'){
163                        $out = array(array(), array());
164                        $getid3 = new getID3();
165                        $getid3->Analyze($file);
166                        foreach ($getid3->info['zip']['files'] as $name => $size){
167                                $icon = is_array($size) ? 'dir' : $this->getIcon($name);
168                                $out[($icon == 'dir') ? 0 : 1][$name] = '<li><a><img src="' . $this->options['assetBasePath'] . '/Icons/' . $icon . '.png" alt="" /> ' . $name . '</a></li>';
169                        }
170                        natcasesort($out[0]);
171                        natcasesort($out[1]);
172                        $content = '<ul>' . implode(array_merge($out[0], $out[1])) . '</ul>';
173                }elseif (FileManagerUtility::startsWith($mime, 'audio/')){
174                        $getid3 = new getID3();
175                        $getid3->Analyze($file);
176                       
177                        $content = '<div class="object">
178                                        <object type="application/x-shockwave-flash" data="' . $this->options['assetBasePath'] . '/dewplayer.swf?mp3=' . rawurlencode($url) . '&volume=30" width="200" height="20">
179                                                <param name="movie" value="' . $this->options['assetBasePath'] . '/dewplayer.swf?mp3=' . rawurlencode($url) . '&volume=30" />
180                                        </object>
181                                </div>
182                                <h2>${more}</h2>
183                                <dl>
184                                        <dt>${title}</dt><dd>' . $getid3->info['comments']['title'][0] . '</dd>
185                                        <dt>${artist}</dt><dd>' . $getid3->info['comments']['artist'][0] . '</dd>
186                                        <dt>${album}</dt><dd>' . $getid3->info['comments']['album'][0] . '</dd>
187                                        <dt>${length}</dt><dd>' . $getid3->info['playtime_string'] . '</dd>
188                                        <dt>${bitrate}</dt><dd>' . round($getid3->info['bitrate']/1000) . 'kbps</dd>
189                                </dl>';
190                }
191               
192                echo json_encode(array_merge(array(
193                        'content' => $content ? $content : '<div class="margin">
194                                ${nopreview}<br/><button value="' . $url . '">${download}</button>
195                        </div>'
196                ), $extra_return_detail));
197        }
198       
199        protected function onDestroy(){
200                if (!$this->options['destroy'] || empty($this->post['directory']) || empty($this->post['file'])) return;
201               
202                $file = realpath($this->path . '/' . $this->post['directory'] . '/' . $this->post['file']);
203                if (!$this->checkFile($file)) return;
204               
205                $this->unlink($file);
206               
207                echo json_encode(array(
208                        'content' => 'destroyed'
209                ));
210        }
211       
212        protected function onCreate(){
213    if ($this->options['upload'])
214    {
215                if (empty($this->post['directory']) || empty($this->post['file'])) return;
216               
217                $file = $this->getName($this->post['file'], $this->getDir($this->post['directory']));
218                if (!$file) return;
219               
220                mkdir($file);
221                }
222               
223                $this->onView();
224        }
225       
226        protected function onUpload(){
227                try{
228                        if (!$this->options['upload'])
229                                throw new FileManagerException('disabled');
230                        if (empty($this->get['directory']) || (function_exists('UploadIsAuthenticated') && !UploadIsAuthenticated($this->get)))
231                                throw new FileManagerException('authenticated');
232                       
233                        $dir = $this->getDir($this->get['directory']);
234                        $name = pathinfo((Upload::exists('Filedata')) ? $this->getName($_FILES['Filedata']['name'], $dir) : null, PATHINFO_FILENAME);
235                        $file = Upload::move('Filedata', $dir . '/', array(
236                                'name' => $name,
237                                'extension' => $this->options['safe'] && $name && in_array(strtolower(pathinfo($_FILES['Filedata']['name'], PATHINFO_EXTENSION)), array('exe', 'dll', 'php', 'php3', 'php4', 'php5', 'phps')) ? 'txt' : null,
238                                'size' => $this->options['maxUploadSize'],
239                                'mimes' => $this->getAllowedMimeTypes()
240                        ));
241                       
242                        if (FileManagerUtility::startsWith(Upload::mime($file), 'image/') && !empty($this->get['resize'])){
243                                $img = new Image($file);
244                                $size = $img->getSize();
245                                if ($size['width'] > $this->options['suggestedMaxImageDimension']['width']) $img->resize( $this->options['suggestedMaxImageDimension']['width'])->save();
246                                elseif ($size['height'] > $this->options['suggestedMaxImageDimension']['height']) $img->resize(null, $this->options['suggestedMaxImageDimension']['height'])->save();
247                        }
248                       
249                        echo json_encode(array(
250                                'status' => 1,
251                                'name' => pathinfo($file, PATHINFO_BASENAME)
252                        ));
253                }catch(UploadException $e){
254                        echo json_encode(array(
255                                'status' => 0,
256                                'error' => class_exists('ValidatorException') ? strip_tags($e->getMessage()) : '${upload.' . $e->getMessage() . '}' // This is for Styx :)
257                        ));
258                }catch(FileManagerException $e){
259                        echo json_encode(array(
260                                'status' => 0,
261                                'error' => '${upload.' . $e->getMessage() . '}'
262                        ));
263                }
264        }
265       
266        /* This method is used by both move and rename */
267        protected function onMove(){
268                if (empty($this->post['directory']) || empty($this->post['file'])) return;
269               
270                $rename = empty($this->post['newDirectory']) && !empty($this->post['name']);
271                $dir = $this->getDir($this->post['directory']);
272                $file = realpath($dir . '/' . $this->post['file']);
273               
274                $is_dir = is_dir($file);
275                if (!$this->checkFile($file) || (!$rename && $is_dir))
276                        return;
277               
278                if ($rename || $is_dir){
279                        if (empty($this->post['name'])) return;
280                        $newname = $this->getName($this->post['name'], $dir);
281                        $fn = 'rename';
282                }else{
283                        $newname = $this->getName(pathinfo($file, PATHINFO_FILENAME), $this->getDir($this->post['newDirectory']));
284                        $fn = !empty($this->post['copy']) ? 'copy' : 'rename';
285                }
286               
287                if (!$newname) return;
288               
289                $ext = pathinfo($file, PATHINFO_EXTENSION);
290                if ($ext) $newname .= '.' . $ext;
291                $fn($file, $newname);
292               
293                echo json_encode(array(
294                        'name' => pathinfo($this->normalize($newname), PATHINFO_BASENAME),
295                ));
296        }
297       
298        protected function unlink($file){
299                $file = realpath($file);
300                if ($this->basedir==$file || strlen($this->basedir)>=strlen($file))
301                        return;
302               
303                if (is_dir($file)){
304                        $files = glob($file . '/*');
305                        if (is_array($files))
306                                foreach ($files as $f)
307                                        $this->unlink($f);
308                               
309                        rmdir($file);
310                }else{
311                        try{ if ($this->checkFile($file)) unlink($file); }catch(Exception $e){}
312                }
313        }
314       
315        protected function getName($file, $dir){
316                $files = array();
317                foreach ((array)glob($dir . '/*') as $f)
318                        $files[] = pathinfo($f, PATHINFO_FILENAME);
319               
320                $pathinfo = pathinfo($file);
321                $file = $dir . '/' . FileManagerUtility::pagetitle($pathinfo['filename'], $files).(!empty($pathinfo['extension']) ? '.' . $pathinfo['extension'] : null);
322               
323                return !$file || !FileManagerUtility::startsWith($file, $this->basedir) || file_exists($file) ? null : $file;
324        }
325       
326        protected function getIcon($file){
327                if (FileManagerUtility::endsWith($file, '/..')) return 'dir_up';
328                else if (is_dir($file)) return 'dir';
329               
330                $ext = pathinfo($file, PATHINFO_EXTENSION);
331                return ($ext && file_exists(realpath($this->options['assetBasePath'] . '/Icons/' . $ext . '.png'))) ? $ext : 'default';
332        }
333
334        protected function getMimeType($file){
335                return is_dir($file) ? 'text/directory' : Upload::mime($file);
336        }
337       
338        protected function getDir($dir){
339                $dir = realpath($this->path . '/' . (FileManagerUtility::startsWith($dir, $this->basename) ? $dir : $this->basename));
340                return $this->checkFile($dir) ? $dir : $this->basedir;
341        }
342       
343        protected function getPath($file){
344                $file = $this->normalize(substr($file, $this->length));
345                return substr($file, FileManagerUtility::startsWith($file, '/') ? 1 : 0);
346        }
347       
348        protected function checkFile($file){
349                $mimes = $this->getAllowedMimeTypes();
350                $hasFilter = $this->options['filter'] && count($mimes);
351                if ($hasFilter) array_push($mimes, 'text/directory');
352                return !(!$file || !FileManagerUtility::startsWith($file, $this->basedir) || !file_exists($file) || ($hasFilter && !in_array($this->getMimeType($file), $mimes)));
353        }
354       
355        protected function normalize($file){
356                return preg_replace('/\\\|\/{2,}/', '/', $file);
357        }
358       
359        protected function getAllowedMimeTypes(){
360                $filter = $this->options['filter'];
361               
362                if (!$filter) return null;
363                if (!FileManagerUtility::endsWith($filter, '/')) return array($filter);
364               
365                static $mimes;
366                if (!$mimes) $mimes = parse_ini_file($this->options['mimeTypesPath']);
367               
368                foreach ($mimes as $mime)
369                        if (FileManagerUtility::startsWith($mime, $filter))
370                                $mimeTypes[] = strtolower($mime);
371               
372                return $mimeTypes;
373        }
374
375}
376
377class FileManagerException extends Exception {}
378
379/* Stripped-down version of some Styx PHP Framework-Functionality bundled with this FileBrowser. Styx is located at: http://styx.og5.net */
380class FileManagerUtility {
381       
382        public static function endsWith($string, $look){
383                return strrpos($string, $look)===strlen($string)-strlen($look);
384        }
385       
386        public static function startsWith($string, $look){
387                return strpos($string, $look)===0;
388        }
389       
390        public static function pagetitle($data, $options = array()){
391                static $regex;
392                if (!$regex){
393                        $regex = array(
394                                explode(' ', 'Æ Ê Œ œ ß Ü ÃŒ Ö ö Ä À À Á Â Ã Ä Å &#260; &#258; Ç &#262; &#268; &#270; &#272; Ð È É Ê Ë &#280; &#282; &#286; Ì Í Î Ï &#304; &#321; &#317; &#313; Ñ &#323; &#327; Ò Ó Ô Õ Ö Ø &#336; &#340; &#344; Å  &#346; &#350; &#356; &#354; Ù Ú Û Ü &#366; &#368; Ý Åœ &#377; &#379; à á â ã À Ã¥ &#261; &#259; ç &#263; &#269; &#271; &#273; Ú é ê ë &#281; &#283; &#287; ì í î ï &#305; &#322; &#318; &#314; ñ &#324; &#328; ð ò ó ÃŽ õ ö Þ &#337; &#341; &#345; &#347; Å¡ &#351; &#357; &#355; ù ú û ÃŒ &#367; &#369; Ãœ ÿ ÅŸ &#378; &#380;'),
395                                explode(' ', 'Ae ae Oe oe ss Ue ue Oe oe Ae ae A A A A A A A A C C C D D D E E E E E E G I I I I I L L L N N N O O O O O O O R R S S S T T U U U U U U Y Z Z Z a a a a a a a a c c c d d e e e e e e g i i i i i l l l n n n o o o o o o o o r r s s s t t u u u u u u y y z z z'),
396                        );
397                       
398                        $regex[0][] = '"';
399                        $regex[0][] = "'";
400                }
401               
402                $data = trim(substr(preg_replace('/(?:[^A-z0-9]|_|\^)+/i', '_', str_replace($regex[0], $regex[1], $data)), 0, 64), '_');
403                return !empty($options) ? self::checkTitle($data, $options) : $data;
404        }
405       
406        protected static function checkTitle($data, $options = array(), $i = 0){
407                if (!is_array($options)) return $data;
408               
409                foreach ($options as $content)
410                        if ($content && strtolower($content) == strtolower($data.($i ? '_' . $i : '')))
411                                return self::checkTitle($data, $options, ++$i);
412               
413                return $data.($i ? '_' . $i : '');
414        }
415       
416        public static function isBinary($str){
417                $array = array(0, 255);
418                for($i = 0; $i < strlen($str); $i++)
419                        if (in_array(ord($str[$i]), $array)) return true;
420               
421                return false;
422        }
423       
424        public static function getPath(){
425                static $path;
426                return $path ? $path : $path = pathinfo(__FILE__, PATHINFO_DIRNAME);
427        }
428       
429}
Note: See TracBrowser for help on using the repository browser.