root / trunk / plugins / ExtendedFileManager / Classes / ExtendedFileManager.php @ 579

Revision 579, 21.2 kB (checked in by ray, 7 years ago)

ExtendedFileManager updates:

*to complete cofigurability through js directories can now be set for images and files individually (optional & backwards compatible)

* linkfile button can be disabled (xinha_config.ExtendedFileManager.use_linker =false)

* relocated button from the end of toolbar next to createlink

* insert image/link with double click

* preview img didn't have src when no image selected, which showed a "image not found icon" in IE

* slight modifications and updates in Readme.txt (kicked out afru's website. The domain isn't even registered anymore)

Line 
1<?php
2/**
3 * ExtendedFileManager, list images, directories, and thumbnails.
4 * Authors: Wei Zhuo, Afru, Krzysztof Kotowicz
5 * Version: Updated on 08-01-2005 by Afru
6 * Version: Updated on 04-07-2006 by Krzysztof Kotowicz
7 * Package: ExtendedFileManager (EFM 1.1.2)
8 * http://www.afrusoft.com/htmlarea
9 */
10
11/**
12 * We use classes from ImageManager to avoid code duplication
13 */
14require_once '../ImageManager/Classes/Files.php';
15
16/**
17 * ExtendedFileManager Class.
18 * @author $Author: Wei Zhuo $
19 * @author $Author: Krzysztof Kotowicz $
20 * @version $Id: ExtendedFileManager.php 27 2004-04-01 08:31:57Z Wei Zhuo $
21 */
22class ExtendedFileManager
23{
24    /**
25     * Configuration array.
26     */
27    var $config;
28
29    /**
30     * Array of directory information.
31     */
32    var $dirs;
33   
34    /**
35     * Manager mode - image | link
36     */
37    var $mode;
38
39    /**
40     * Constructor. Create a new Image Manager instance.
41     * @param array $config configuration array, see config.inc.php
42     */
43    function ExtendedFileManager($config, $mode = null)
44    {
45        $this->config = $config;
46       
47        $this->mode = empty($mode) ? (empty($config['insert_mode']) ? 'image' : $config['insert_mode']): $mode;
48    }
49
50    /**
51     * Get the base directory.
52     * @return string base dir, see config.inc.php
53     */
54    function getImagesDir()
55    {
56        if ($this->mode == 'link' && isset($this->config['files_dir']))
57            Return $this->config['files_dir'];
58        else Return $this->config['images_dir'];
59    }
60
61    /**
62     * Get the base URL.
63     * @return string base url, see config.inc.php
64     */
65    function getImagesURL()
66    {
67        if ($this->mode == 'link' && isset($this->config['files_url']))
68                Return $this->config['files_url'];
69        else Return $this->config['images_url'];
70    }
71
72    function isValidBase()
73    {
74        return is_dir($this->getImagesDir());
75    }
76
77    /**
78     * Get the tmp file prefix.
79     * @return string tmp file prefix.
80     */
81    function getTmpPrefix()
82    {
83        Return $this->config['tmp_prefix'];
84    }
85
86    /**
87     * Get the sub directories in the base dir.
88     * Each array element contain
89     * the relative path (relative to the base dir) as key and the
90     * full path as value.
91     * @return array of sub directries
92     * <code>array('path name' => 'full directory path', ...)</code>
93     */
94    function getDirs()
95    {
96        if(is_null($this->dirs))
97        {
98            $dirs = $this->_dirs($this->getImagesDir(),'/');
99            ksort($dirs);
100            $this->dirs = $dirs;
101        }
102        return $this->dirs;
103    }
104
105    /**
106     * Recursively travese the directories to get a list
107     * of accessable directories.
108     * @param string $base the full path to the current directory
109     * @param string $path the relative path name
110     * @return array of accessiable sub-directories
111     * <code>array('path name' => 'full directory path', ...)</code>
112     */
113    function _dirs($base, $path)
114    {
115        $base = Files::fixPath($base);
116        $dirs = array();
117
118        if($this->isValidBase() == false)
119            return $dirs;
120
121        $d = @dir($base);
122       
123        while (false !== ($entry = $d->read()))
124        {
125            //If it is a directory, and it doesn't start with
126            // a dot, and if is it not the thumbnail directory
127            if(is_dir($base.$entry)
128                && substr($entry,0,1) != '.'
129                && $this->isThumbDir($entry) == false)
130            {
131                $relative = Files::fixPath($path.$entry);
132                $fullpath = Files::fixPath($base.$entry);
133                $dirs[$relative] = $fullpath;
134                $dirs = array_merge($dirs, $this->_dirs($fullpath, $relative));
135            }
136        }
137        $d->close();
138
139        Return $dirs;
140    }
141
142    /**
143     * Get all the files and directories of a relative path.
144     * @param string $path relative path to be base path.
145     * @return array of file and path information.
146     * <code>array(0=>array('relative'=>'fullpath',...), 1=>array('filename'=>fileinfo array(),...)</code>
147     * fileinfo array: <code>array('url'=>'full url',
148     *                       'relative'=>'relative to base',
149     *                        'fullpath'=>'full file path',
150     *                        'image'=>imageInfo array() false if not image,
151     *                        'stat' => filestat)</code>
152     */
153    function getFiles($path)
154    {
155        $files = array();
156        $dirs = array();
157
158        $valid_extensions = $this->mode == 'image' ? $this->config['allowed_image_extensions'] : $this->config['allowed_link_extensions'];
159
160        if($this->isValidBase() == false)
161            return array($files,$dirs);
162
163        $path = Files::fixPath($path);
164        $base = Files::fixPath($this->getImagesDir());
165        $fullpath = Files::makePath($base,$path);
166
167
168        $d = @dir($fullpath);
169       
170        while (false !== ($entry = $d->read()))
171        {
172            //not a dot file or directory
173            if(substr($entry,0,1) != '.')
174            {
175                if(is_dir($fullpath.$entry)
176                    && $this->isThumbDir($entry) == false)
177                {
178                    $relative = Files::fixPath($path.$entry);
179                    $full = Files::fixPath($fullpath.$entry);
180                    $count = $this->countFiles($full);
181                    $dirs[$relative] = array('fullpath'=>$full,'entry'=>$entry,'count'=>$count, 'stat'=>stat($fullpath.$entry));
182                }
183
184                else if(is_file($fullpath.$entry) && $this->isThumb($entry)==false && $this->isTmpFile($entry) == false)
185                {
186                    $afruext = strtolower(substr(strrchr($entry, "."), 1));
187
188                    if(in_array($afruext,$valid_extensions))
189                    {
190
191                        $file['url'] = Files::makePath($this->config['base_url'],$path).$entry;
192                        $file['relative'] = $path.$entry;
193                        $file['fullpath'] = $fullpath.$entry;
194                        $img = $this->getImageInfo($fullpath.$entry);
195                        if(!is_array($img)) $img[0]=$img[1]=0;
196                        $file['image'] = $img;
197                        $file['stat'] = stat($fullpath.$entry);
198                        $file['ext'] = $afruext;
199                        $files[$entry] = $file;
200                    }
201
202                }
203            }
204        }
205        $d->close();
206        ksort($dirs);
207        ksort($files);
208       
209        Return array($dirs, $files);
210    }   
211
212    /**
213     * Count the number of files and directories in a given folder
214     * minus the thumbnail folders and thumbnails.
215     */
216    function countFiles($path)
217    {
218        $total = 0;
219
220        if(is_dir($path))
221        {
222            $d = @dir($path);
223
224            while (false !== ($entry = $d->read()))
225            {
226                //echo $entry."<br>";
227                if(substr($entry,0,1) != '.'
228                    && $this->isThumbDir($entry) == false
229                    && $this->isTmpFile($entry) == false
230                    && $this->isThumb($entry) == false)
231                {
232                    $total++;
233                }
234            }
235            $d->close();
236        }
237        return $total;
238    }
239
240    /**
241     * Get image size information.
242     * @param string $file the image file
243     * @return array of getImageSize information,
244     *  false if the file is not an image.
245     */
246    function getImageInfo($file)
247    {
248        Return @getImageSize($file);
249    }
250
251    /**
252     * Check if the file contains the thumbnail prefix.
253     * @param string $file filename to be checked
254     * @return true if the file contains the thumbnail prefix, false otherwise.
255     */
256    function isThumb($file)
257    {
258        $len = strlen($this->config['thumbnail_prefix']);
259        if(substr($file,0,$len)==$this->config['thumbnail_prefix'])
260            Return true;
261        else
262            Return false;
263    }
264
265    /**
266     * Check if the given directory is a thumbnail directory.
267     * @param string $entry directory name
268     * @return true if it is a thumbnail directory, false otherwise
269     */
270    function isThumbDir($entry)
271    {
272        if($this->config['thumbnail_dir'] == false
273            || strlen(trim($this->config['thumbnail_dir'])) == 0)
274            Return false;       
275        else
276            Return ($entry == $this->config['thumbnail_dir']);
277    }
278
279    /**
280     * Check if the given file is a tmp file.
281     * @param string $file file name
282     * @return boolean true if it is a tmp file, false otherwise
283     */
284    function isTmpFile($file)
285    {
286        $len = strlen($this->config['tmp_prefix']);
287        if(substr($file,0,$len)==$this->config['tmp_prefix'])
288            Return true;
289        else
290            Return false;         
291    }
292
293    /**
294     * For a given image file, get the respective thumbnail filename
295     * no file existence check is done.
296     * @param string $fullpathfile the full path to the image file
297     * @return string of the thumbnail file
298     */
299    function getThumbName($fullpathfile)
300    {
301        $path_parts = pathinfo($fullpathfile);
302       
303        $thumbnail = $this->config['thumbnail_prefix'].$path_parts['basename'];
304
305        if($this->config['safe_mode'] == true
306            || strlen(trim($this->config['thumbnail_dir'])) == 0)
307        {
308            Return Files::makeFile($path_parts['dirname'],$thumbnail);
309        }
310        else
311        {
312            if(strlen(trim($this->config['thumbnail_dir'])) > 0)
313            {
314                $path = Files::makePath($path_parts['dirname'],$this->config['thumbnail_dir']);
315                if(!is_dir($path))
316                    Files::createFolder($path);
317                Return Files::makeFile($path,$thumbnail);
318            }
319            else //should this ever happen?
320            {
321                //error_log('ExtendedFileManager: Error in creating thumbnail name');
322            }
323        }
324    }
325   
326    /**
327     * Similar to getThumbName, but returns the URL, base on the
328     * given base_url in config.inc.php
329     * @param string $relative the relative image file name,
330     * relative to the base_dir path
331     * @return string the url of the thumbnail
332     */
333    function getThumbURL($relative)
334    {
335        $path_parts = pathinfo($relative);
336        $thumbnail = $this->config['thumbnail_prefix'].$path_parts['basename'];
337        if($path_parts['dirname']=='\\') $path_parts['dirname']='/';
338
339        if($this->config['safe_mode'] == true
340            || strlen(trim($this->config['thumbnail_dir'])) == 0)
341        {
342            Return Files::makeFile($this->getImagesURL(),$thumbnail);
343        }
344        else
345        {
346            if(strlen(trim($this->config['thumbnail_dir'])) > 0)
347            {
348                $path = Files::makePath($path_parts['dirname'],$this->config['thumbnail_dir']);
349                $url_path = Files::makePath($this->getImagesURL(), $path);
350                Return Files::makeFile($url_path,$thumbnail);
351            }
352            else //should this ever happen?
353            {
354                //error_log('ExtendedFileManager: Error in creating thumbnail url');
355            }
356
357        }
358    }
359
360   /**
361    * For a given image file, get the respective resized filename
362    * no file existence check is done.
363    * @param string $fullpathfile the full path to the image file
364    * @param integer $width the intended width
365    * @param integer $height the intended height
366    * @param boolean $mkDir whether to attempt to make the resized_dir if it doesn't exist
367    * @return string of the resized filename
368    */
369    function getResizedName($fullpathfile, $width, $height, $mkDir = TRUE)
370    {
371        $path_parts = pathinfo($fullpathfile);
372
373        $thumbnail = $this->config['resized_prefix']."_{$width}x{$height}_{$path_parts['basename']}";
374
375        if( strlen(trim($this->config['resized_dir'])) == 0 || $this->config['safe_mode'] == true )
376        {
377            Return Files::makeFile($path_parts['dirname'],$thumbnail);
378        }
379        else
380        {
381      $path = Files::makePath($path_parts['dirname'],$this->config['resized_dir']);
382      if($mkDir && !is_dir($path))
383        Files::createFolder($path);
384      Return Files::makeFile($path,$thumbnail);
385        }
386    }
387
388    /**
389     * Check if the given path is part of the subdirectories
390     * under the base_dir.
391     * @param string $path the relative path to be checked
392     * @return boolean true if the path exists, false otherwise
393     */
394    function validRelativePath($path)
395    {
396        $dirs = $this->getDirs();
397        if($path == '/')
398            Return true;
399        //check the path given in the url against the
400        //list of paths in the system.
401        for($i = 0; $i < count($dirs); $i++)
402        {
403            $key = key($dirs);
404            //we found the path
405            if($key == $path)
406                Return true;
407       
408            next($dirs);
409        }       
410        Return false;
411    }
412
413    /**
414     * Process uploaded files, assumes the file is in
415     * $_FILES['upload'] and $_POST['dir'] is set.
416     * The dir must be relative to the base_dir and exists.
417     * @return null
418     */
419    function processUploads()
420    {
421        if($this->isValidBase() == false)
422            return;
423
424        $relative = null;
425
426        if(isset($_POST['dir']))
427            $relative = rawurldecode($_POST['dir']);
428        else
429            return;
430
431        //check for the file, and must have valid relative path
432        if(isset($_FILES['upload']) && $this->validRelativePath($relative))
433        {
434            Return $this->_processFiles($relative, $_FILES['upload']);
435        }
436    }
437
438    /**
439     * Process upload files. The file must be an
440     * uploaded file. Any duplicate
441     * file will be renamed. See Files::copyFile for details
442     * on renaming.
443     * @param string $relative the relative path where the file
444     * should be copied to.
445     * @param array $file the uploaded file from $_FILES
446     * @return boolean true if the file was processed successfully,
447     * false otherwise
448     */
449    function _processFiles($relative, $file)
450    {
451       
452        if($file['error']!=0)
453        {
454            Return false;
455        }
456
457        if(!is_file($file['tmp_name']))
458        {
459            Return false;
460        }
461
462        if(!is_uploaded_file($file['tmp_name']))
463        {
464            Files::delFile($file['tmp_name']);
465            Return false;
466        }
467
468        $valid_extensions = $this->mode == 'image' ? $this->config['allowed_image_extensions'] : $this->config['allowed_link_extensions'];
469        $max_size = $this->mode == 'image' ? $this->config['max_filesize_kb_image'] : $this->config['max_filesize_kb_link'];
470        $afruext = strtolower(substr(strrchr($file['name'], "."), 1));
471
472        if(!in_array($afruext, $valid_extensions))
473        {
474            Files::delFile($file['tmp_name']);
475            Return "Cannot upload .".$afruext." Files. Permission denied.";
476        }
477
478        if($file['size']>($max_size*1024))
479        {
480            Files::delFile($file['tmp_name']);
481            Return "Unble to upload file. Maximum file size [".$max_size."Kb] exceeded.";
482        }
483
484        if(!empty($this->config['max_foldersize_mb']) &&  (Files::dirSize($this->getImagesDir()))+$file['size']> ($this->config['max_foldersize_mb']*1048576))
485        {
486            Files::delFile($file['tmp_name']);
487            Return ("Cannot upload. Maximum folder size reached. Delete unwanted files and try again.");
488        }
489
490        //now copy the file
491        $path = Files::makePath($this->getImagesDir(),$relative);
492        $result = Files::copyFile($file['tmp_name'], $path, $file['name']);
493
494        //no copy error
495        if(!is_int($result))
496        {
497            Files::delFile($file['tmp_name']);
498            Return $file['name']." successfully uploaded.";
499        }
500
501        //delete tmp files.
502        Files::delFile($file['tmp_name']);
503        Return false;
504
505    }
506
507
508    function getDiskInfo()
509    {
510        if (empty($this->config['max_foldersize_mb']))
511            return '';
512           
513        $tmpFreeSize=($this->config['max_foldersize_mb']*1048576)-Files::dirSize($this->getImagesDir());
514
515        if(!is_numeric($tmpFreeSize) || $tmpFreeSize<0)    $tmpFreeSize=0;
516       
517        Return 'Total Size : '.$this->config['max_foldersize_mb'].' Mb , Free Space: '.Files::formatSize($tmpFreeSize);
518    }
519
520
521
522    /**
523     * Get the URL of the relative file.
524     * basically appends the relative file to the
525     * base_url given in config.inc.php
526     * @param string $relative a file the relative to the base_dir
527     * @return string the URL of the relative file.
528     */
529    function getFileURL($relative)
530    {
531        Return Files::makeFile($this->getImagesURL(),$relative);
532    }
533
534    /**
535     * Get the fullpath to a relative file.
536     * @param string $relative the relative file.
537     * @return string the full path, .ie. the base_dir + relative.
538     */
539    function getFullPath($relative)
540    {
541        Return Files::makeFile($this->getImagesDir(),$relative);;
542    }
543
544    /**
545     * Get the default thumbnail.
546     * @return string default thumbnail, empty string if
547     * the thumbnail doesn't exist.
548     */
549    function getDefaultThumb()
550    {
551        if(is_file($this->config['default_thumbnail']))
552            Return $this->config['default_thumbnail'];
553        else
554            Return '';
555    }
556
557
558    /**
559     * Checks image size. If the image size is less than default size
560     * returns the original size else returns default size to display thumbnail
561    */
562    function checkImageSize($relative)
563    {
564        $fullpath = Files::makeFile($this->getImagesDir(),$relative);
565
566        $afruext = strtolower(substr(strrchr($relative, "."), 1));
567       
568        if(!in_array($afruext,$this->config['thumbnail_extensions']))
569        {
570            $imgInfo=array(0,0);
571            Return $imgInfo;
572        }
573        else
574        {
575            $imgInfo = @getImageSize($fullpath);
576            //not an image
577            if(!is_array($imgInfo))
578            {
579                $imgInfo=array(0,0);
580                Return $imgInfo;
581            }
582            else
583            {
584                if($imgInfo[0] > $this->config['thumbnail_width'])
585                $imgInfo[0] = $this->config['thumbnail_width'];
586
587                if($imgInfo[1] > $this->config['thumbnail_height'])
588                $imgInfo[1] = $this->config['thumbnail_height'];
589
590                Return $imgInfo;
591            }
592        }
593
594    }
595
596
597    /**
598     * Get the thumbnail url to be displayed.
599     * If the thumbnail exists, and it is up-to-date
600     * the thumbnail url will be returns. If the
601     * file is not an image, a default image will be returned.
602     * If it is an image file, and no thumbnail exists or
603     * the thumbnail is out-of-date (i.e. the thumbnail
604     * modified time is less than the original file)
605     * then a thumbs.php?img=filename.jpg is returned.
606     * The thumbs.php url will generate a new thumbnail
607     * on the fly. If the image is less than the dimensions
608     * of the thumbnails, the image will be display instead.
609     * @param string $relative the relative image file.
610     * @return string the url of the thumbnail, be it
611     * actually thumbnail or a script to generate the
612     * thumbnail on the fly.
613     */
614    function getThumbnail($relative)
615    {
616        global $IMConfig;
617       
618        $fullpath = Files::makeFile($this->getImagesDir(),$relative);
619
620        //not a file???
621        if(!is_file($fullpath))
622            Return $this->getDefaultThumb();
623
624        $afruext = strtolower(substr(strrchr($relative, "."), 1));
625       
626        if(!in_array($afruext,$this->config['thumbnail_extensions']))
627        {
628            if(is_file('icons/'.$afruext.'.gif'))
629                Return('icons/'.$afruext.'.gif');
630            else
631                Return $this->getDefaultThumb();
632        }
633
634        $imgInfo = @getImageSize($fullpath);
635
636        //not an image
637        if(!is_array($imgInfo))
638            Return $this->getDefaultThumb();
639
640
641        //Returning original image as thumbnail without Image Library by Afru
642        if(!$this->config['img_library']) Return $this->getFileURL($relative);
643
644
645        //the original image is smaller than thumbnails,
646        //so just return the url to the original image.
647        if ($imgInfo[0] <= $this->config['thumbnail_width']
648         && $imgInfo[1] <= $this->config['thumbnail_height'])
649            Return $this->getFileURL($relative);
650
651        $thumbnail = $this->getThumbName($fullpath);
652       
653        //check for thumbnails, if exists and
654        // it is up-to-date, return the thumbnail url
655        if(is_file($thumbnail))
656        {
657            if(filemtime($thumbnail) >= filemtime($fullpath))
658                Return $this->getThumbURL($relative);
659        }
660
661        //well, no thumbnail was found, so ask the thumbs.php
662        //to generate the thumbnail on the fly.
663        Return $IMConfig['backend_url'] . '__function=thumbs&img='.rawurlencode($relative)."&mode=$this->mode";
664    }
665
666    /**
667     * Delete and specified files.
668     * @return boolean true if delete, false otherwise
669     */
670    function deleteFiles()
671    {
672        if(isset($_GET['delf']))
673            return $this->_delFile(rawurldecode($_GET['delf']));
674        return false;
675    }
676
677    /**
678     * Delete and specified directories.
679     * @return boolean true if delete, false otherwise
680     */
681    function deleteDirs()
682    {
683         if(isset($_GET['deld']))
684            return $this->_delDir(rawurldecode($_GET['deld']));       
685         else
686             Return false;
687    }
688
689    /**
690     * Delete the relative file, and any thumbnails.
691     * @param string $relative the relative file.
692     * @return boolean true if deleted, false otherwise.
693     */
694    function _delFile($relative)
695    {
696        $fullpath = Files::makeFile($this->getImagesDir(),$relative);
697   
698        $afruext = strtolower(substr(strrchr($relative, "."), 1));
699
700        $valid_extensions = $this->mode == 'image' ? $this->config['allowed_image_extensions'] : $this->config['allowed_link_extensions'];
701
702        if(!in_array($afruext,$valid_extensions))
703        {
704            return false;
705        }
706
707        //check that the file is an image
708        if(is_array($this->getImageInfo($fullpath)))
709        {
710            $thumbnail = $this->getThumbName($fullpath);
711            Files::delFile($thumbnail);
712        }
713
714        Return Files::delFile($fullpath);
715    }
716
717    /**
718     * Delete directories recursively.
719     * @param string $relative the relative path to be deleted.
720     * @return boolean true if deleted, false otherwise.
721     */
722    function _delDir($relative)
723    {
724        $fullpath = Files::makePath($this->getImagesDir(),$relative);
725        if($this->countFiles($fullpath) <= 0)
726            return Files::delFolder($fullpath,true); //delete recursively.
727        else
728            Return false;
729    }
730
731    /**
732     * Create new directories.
733     * If in safe_mode, nothing happens.
734     * @return boolean true if created, false otherwise.
735     */
736    function processNewDir()
737    {
738        if($this->config['safe_mode'] == true)
739            Return false;
740
741        if(isset($_GET['newDir']) && isset($_GET['dir']))
742        {
743            $newDir = rawurldecode($_GET['newDir']);
744            $dir = rawurldecode($_GET['dir']);
745            $path = Files::makePath($this->getImagesDir(),$dir);
746            $fullpath = Files::makePath($path, Files::escape($newDir));
747            if(is_dir($fullpath))
748                Return false;
749
750            Return Files::createFolder($fullpath);
751        }
752    }
753
754    /**
755     * Renames files if certain GET variables are set
756     * @return bool
757     */
758    function processRenames()
759    {
760        if(!empty($_GET['rename']) && !empty($_GET['renameTo']))
761        {
762            // new file name (without path and extension)
763            $newName = Files::escape(rawurldecode($_GET['renameTo']));
764            $newName = str_replace('.', '', $newName);
765
766            // path to file (from base images directory)
767            $oldName = rawurldecode($_GET['rename']);
768
769            // strip parent dir ("..") to avoid escaping from base directiory
770            $oldName = preg_replace('#\.\.#', '', $oldName);
771
772            // path to old file
773            $oldPath = Files::makeFile($this->getImagesDir(), $oldName);
774
775            $ret = Files::renameFile($oldPath, $newName);
776            if ($ret === true) {
777                // delete old thumbnail
778                Files::delFile($this->getThumbname($oldPath));
779            }
780            return $ret;
781        }
782       
783        return null;
784    }
785
786}
787
788?>
Note: See TracBrowser for help on using the browser.