Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
76.19% covered (warning)
76.19%
256 / 336
52.63% covered (warning)
52.63%
10 / 19
CRAP
0.00% covered (danger)
0.00%
0 / 1
SeedDMS_Core_File
76.19% covered (warning)
76.19%
256 / 336
52.63% covered (warning)
52.63%
10 / 19
182.52
0.00% covered (danger)
0.00%
0 / 1
 renameFile
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 removeFile
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 copyFile
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 linkFile
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 moveFile
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 fileSize
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 mimetype
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
702
 format_filesize
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 parse_filesize
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
8
 file_exists
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 checksum
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 fileExtension
100.00% covered (success)
100.00%
199 / 199
100.00% covered (success)
100.00%
1 / 1
7
 checkFilename
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 renameDir
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 makeDir
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 removeDir
84.62% covered (warning)
84.62%
11 / 13
0.00% covered (danger)
0.00%
0 / 1
8.23
 copyDir
69.23% covered (warning)
69.23%
9 / 13
0.00% covered (danger)
0.00%
0 / 1
9.86
 moveDir
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 gzcompressfile
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2declare(strict_types=1);
3
4/**
5 * Implementation of various file system operations
6 *
7 * @category   DMS
8 * @package    SeedDMS_Core
9 * @license    GPL 2
10 * @author     Uwe Steinmann <uwe@steinmann.cx>
11 * @copyright  Copyright (C) 2002-2005 Markus Westphal,
12 *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
13 *             2010-2024 Uwe Steinmann
14 */
15
16/**
17 * Class with file operations in the document management system
18 *
19 * Use the methods of this class only for files below the content
20 * directory but not for temporäry files, cache files or log files.
21 *
22 * @category   DMS
23 * @package    SeedDMS_Core
24 * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
25 * @copyright  Copyright (C) 2002-2005 Markus Westphal,
26 *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
27 *             2010-2024 Uwe Steinmann
28 */
29class SeedDMS_Core_File {
30    /**
31     * Rename a file
32     *
33     * @param $old old name of file
34     * @param $new new name of file
35     * @return bool
36     */
37    public static function renameFile($old, $new) { /* {{{ */
38        return @rename($old, $new);
39    } /* }}} */
40
41    /**
42     * Delete a file
43     *
44     * @param $file name of file
45     * @return bool
46     */
47    public static function removeFile($file) { /* {{{ */
48        return @unlink($file);
49    } /* }}} */
50
51    /**
52     * Make copy of file
53     *
54     * @param $source name of file to be copied
55     * @param $target name of target file
56     * @return bool
57     */
58    public static function copyFile($source, $target) { /* {{{ */
59        return @copy($source, $target);
60    } /* }}} */
61
62    /**
63     * Create symbolic link
64     *
65     * @param $source name of link
66     * @param $target name of file to link
67     * @return bool
68     */
69    public static function linkFile($source, $target) { /* {{{ */
70        return symlink($source, $target);
71    } /* }}} */
72
73    /**
74     * Move file
75     *
76     * @param $source name of file to be moved
77     * @param $target name of target file
78     * @return bool
79     */
80    public static function moveFile($source, $target) { /* {{{ */
81        if (!self::copyFile($source, $target))
82            return false;
83        return self::removeFile($source);
84    } /* }}} */
85
86    /**
87     * Return size of file
88     *
89     * @param $file name of file
90     * @return bool|int
91     */
92    public static function fileSize($file) { /* {{{ */
93        if (!$a = @fopen($file, 'r'))
94            return false;
95        fseek($a, 0, SEEK_END);
96        $filesize = ftell($a);
97        fclose($a);
98        return $filesize;
99    } /* }}} */
100
101    /**
102     * Return the mimetype of a given file
103     *
104     * This method uses finfo to determine the mimetype
105     * but will correct some mimetypes which are
106     * not propperly determined or could be more specific, e.g. text/plain
107     * when it is actually text/markdown. In thoses cases
108     * the file extension will be taken into account.
109     *
110     * @param string $filename name of file on disc
111     * @return string mimetype
112     */
113    public static function mimetype($filename) { /* {{{ */
114        $finfo = finfo_open(FILEINFO_MIME_TYPE);
115        $mimetype = finfo_file($finfo, $filename);
116
117        $lastDotIndex = strrpos($filename, ".");
118        if ($lastDotIndex === false) $fileType = ".";
119        else $fileType = substr($filename, $lastDotIndex);
120
121        switch ($mimetype) {
122            case 'application/octet-stream':
123            case 'text/plain':
124                if ($fileType == '.md')
125                    $mimetype = 'text/markdown';
126                if ($fileType == '.m3u')
127                    $mimetype = 'audio/x-mpegurl';
128                elseif ($fileType == '.tex')
129                    $mimetype = 'text/x-tex';
130                elseif ($fileType == '.docx')
131                    $mimetype = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
132                elseif ($fileType == '.pkpass')
133                    $mimetype = 'application/vnd.apple.pkpass';
134                elseif ($fileType == '.m3u')
135                    $mimetype = 'application/mpegurl';
136                elseif ($fileType == '.wpd' || $fileType == '.wpt')
137                    $mimetype = 'application/vnd.wordperfect';
138                elseif ($fileType == '.drawio')
139                    $mimetype = 'application/vnd.jgraph.mxfile';
140                elseif ($fileType == '.ris')
141                    $mimetype = 'application/x-research-info-systems';
142                elseif ($fileType == '.p12')
143                    $mimetype = 'application/x-pkcs12';
144                elseif ($fileType == '.dxf')
145                    $mimetype = 'application/dxf';
146                break;
147            case 'application/zip':
148                if ($fileType == '.pkpass')
149                    $mimetype = 'application/vnd.apple.pkpass';
150                elseif ($fileType == '.pkpasses')
151                    $mimetype = 'application/vnd.apple.pkpasses';
152                elseif ($fileType == '.numbers')
153                    $mimetype = 'application/vnd.apple.numbers';
154                elseif ($fileType == '.pages')
155                    $mimetype = 'application/vnd.apple.pages';
156                elseif ($fileType == '.key')
157                    $mimetype = 'application/vnd.apple.keynote';
158                break;
159            case 'application/gzip':
160                if ($fileType == '.xopp')
161                    $mimetype = 'application/x-xopp';
162                break;
163            case 'text/xml':
164                if ($fileType == '.html')
165                    $mimetype = 'text/html';
166                break;
167        }
168        return $mimetype;
169    } /* }}} */
170
171    /**
172     * Turn an integer into a string with units for bytes
173     *
174     * The default uses a base of 2 and a new unit for 1024^n
175     * If a base of 10 and a step of 1000 is passed, you will get metric
176     * units
177     *
178     * @param integer $size
179     * @param array $sizes list of units for $step^0, $step^3, $step^6, ..., $step^(n*3) bytes
180     * @param integer $base base
181     * @param integer $step factor between two unit steps
182     * @return string
183     */
184    public static function format_filesize($size, $sizes = array('Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'), $base=2, $step=1024) { /* {{{ */
185        if ($size == 0) return('0 Bytes');
186        if ($size == 1) return('1 Byte');
187        return (round($size/pow($step, ($i = floor(log($size, $step)))), $base) . ' ' . $sizes[$i]);
188    } /* }}} */
189
190    /**
191     * Parses a string like '[0-9]+ *[BKMGT]*' into an integer
192     *
193     * B,K,M,G,T stand for byte, kilo byte, mega byte, giga byte, tera byte
194     * If the last character is omitted, bytes are assumed. Arbitrary
195     * spaces between the number and the unit are allowed.
196     *
197     * @param string $str string to be parsed
198     * @return bool|int
199     */
200    public static function parse_filesize($str) { /* {{{ */
201        if (!preg_match('/^([0-9]+) *([BKMGT]*)$/', trim($str), $matches))
202            return false;
203        $value = $matches[1];
204        $unit = $matches[2] ? $matches[2] : 'B';
205        switch ($unit) {
206            case 'T':
207                return $value * 1024 * 1024 * 1024 *1024;
208                break;
209            case 'G':
210                return $value * 1024 * 1024 * 1024;
211                break;
212            case 'M':
213                return $value * 1024 * 1024;
214                break;
215            case 'K':
216                return $value * 1024;
217                break;
218            default:
219                return (int) $value;
220                break;
221        }
222        return false;
223    } /* }}} */
224
225    /**
226     * Check if file exists
227     *
228     * @param string $file name of file to be checked
229     * @return bool true if file exists
230     */
231    public static function file_exists($file) { /* {{{ */
232        return file_exists($file);
233    } /* }}} */
234
235    /**
236     * Calculate the checksum of a file
237     *
238     * This method calculates the md5 sum of the file's content.
239     *
240     * @param string $file name of file
241     * @return string md5 sum of file
242     */
243    public static function checksum($file) { /* {{{ */
244        if (file_exists($file))
245            return md5_file($file);
246        else
247            return '';
248    } /* }}} */
249
250    /**
251     * Return file extension by mimetype
252     *
253     * This methods returns the common file extension for a given mime type.
254     *
255     * @param string $mimetype
256     * @return string file extension with the dot or an empty string
257     */
258    public static function fileExtension($mimetype) { /* {{{ */
259        switch ($mimetype) {
260            case "application/pdf":
261            case "image/png":
262            case "image/gif":
263            case "image/jpg":
264                $expect = substr($mimetype, -3, 3);
265                break;
266            default:
267                $mime_map = [
268                    'video/3gpp2' => '3g2',
269                    'video/3gp' => '3gp',
270                    'video/3gpp' => '3gp',
271                    'application/x-compressed' => '7zip',
272                    'audio/x-acc'=> 'aac',
273                    'audio/ac3' => 'ac3',
274                    'audio/x-mpegurl' => 'm3u',
275                    'application/postscript' => 'ps',
276                    'audio/x-aiff' => 'aif',
277                    'audio/aiff' => 'aif',
278                    'audio/x-au' => 'au',
279                    'video/x-msvideo' => 'avi',
280                    'video/msvideo' => 'avi',
281                    'video/avi' => 'avi',
282                    'application/x-troff-msvideo' => 'avi',
283                    'application/macbinary' => 'bin',
284                    'application/mac-binary' => 'bin',
285                    'application/x-binary' => 'bin',
286                    'application/x-macbinary' => 'bin',
287                    'image/bmp' => 'bmp',
288                    'image/x-bmp' => 'bmp',
289                    'image/x-bitmap' => 'bmp',
290                    'image/x-xbitmap' => 'bmp',
291                    'image/x-win-bitmap' => 'bmp',
292                    'image/x-windows-bmp' => 'bmp',
293                    'image/ms-bmp' => 'bmp',
294                    'image/x-ms-bmp' => 'bmp',
295                    'application/bmp' => 'bmp',
296                    'application/x-bmp' => 'bmp',
297                    'application/x-win-bitmap' => 'bmp',
298                    'application/cdr' => 'cdr',
299                    'application/coreldraw' => 'cdr',
300                    'application/x-cdr' => 'cdr',
301                    'application/x-coreldraw' => 'cdr',
302                    'image/cdr' => 'cdr',
303                    'image/x-cdr' => 'cdr',
304                    'zz-application/zz-winassoc-cdr' => 'cdr',
305                    'application/mac-compactpro' => 'cpt',
306                    'application/pkix-crl' => 'crl',
307                    'application/pkcs-crl' => 'crl',
308                    'application/x-x509-ca-cert' => 'crt',
309                    'application/pkix-cert' => 'crt',
310                    'text/css' => 'css',
311                    'text/x-comma-separated-values' => 'csv',
312                    'text/comma-separated-values' => 'csv',
313                    'application/vnd.msexcel' => 'xls',
314                    'application/x-director' => 'dcr',
315                    'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
316                    'application/vnd.jgraph.mxfile' => 'drawio',
317                    'application/x-dvi' => 'dvi',
318                    'message/rfc822' => 'eml',
319                    'application/x-msdownload' => 'exe',
320                    'video/x-f4v' => 'f4v',
321                    'audio/x-flac' => 'flac',
322                    'video/x-flv' => 'flv',
323                    'image/gif' => 'gif',
324                    'image/heic' => 'heic',
325                    'application/gpg-keys' => 'gpg',
326                    'application/x-gtar' => 'tar.gz',
327                    'application/x-gzip' => 'gz',
328                    'application/mac-binhex40' => 'hqx',
329                    'application/mac-binhex' => 'hqx',
330                    'application/x-binhex40' => 'hqx',
331                    'application/x-mac-binhex40' => 'hqx',
332                    'text/html' => 'html',
333                    'image/x-icon' => 'ico',
334                    'image/x-ico' => 'ico',
335                    'image/vnd.microsoft.icon' => 'ico',
336                    'text/calendar' => 'ics',
337                    'application/java-archive' => 'jar',
338                    'application/x-java-application' => 'jar',
339                    'application/x-jar' => 'jar',
340                    'image/jp2' => 'jp2',
341                    'video/mj2'=> 'jp2',
342                    'image/jpx' => 'jp2',
343                    'image/jpm' => 'jp2',
344                    'image/jpeg' => 'jpg',
345                    'image/pjpeg' => 'jpg',
346                    'application/x-javascript' => 'js',
347                    'application/json' => 'json',
348                    'text/json' => 'json',
349                    'application/vnd.google-earth.kml+xml' => 'kml',
350                    'application/vnd.google-earth.kmz' => 'kmz',
351                    'text/x-log' => 'log',
352                    'audio/x-m4a' => 'm4a',
353                    'application/vnd.mpegurl' => 'm4u',
354                    'text/markdown' => 'md',
355                    'audio/midi' => 'mid',
356                    'application/vnd.mif' => 'mif',
357                    'video/quicktime' => 'mov',
358                    'video/x-sgi-movie' => 'movie',
359                    'audio/mpeg' => 'mp3',
360                    'audio/mpg' => 'mp3',
361                    'audio/mpeg3' => 'mp3',
362                    'audio/mp3' => 'mp3',
363                    'video/mp4' => 'mp4',
364                    'video/mpeg' => 'mpeg',
365                    'application/oda' => 'oda',
366                    'audio/ogg' => 'ogg',
367                    'video/ogg' => 'ogg',
368                    'application/ogg' => 'ogg',
369                    'application/x-pkcs10' => 'p10',
370                    'application/pkcs10' => 'p10',
371                    'application/x-pkcs12' => 'p12',
372                    'application/x-pkcs7-signature' => 'p7a',
373                    'application/pkcs7-mime' => 'p7c',
374                    'application/x-pkcs7-mime' => 'p7c',
375                    'application/x-pkcs7-certreqresp' => 'p7r',
376                    'application/pkcs7-signature' => 'p7s',
377                    'application/pdf' => 'pdf',
378                    'application/octet-stream' => 'pdf',
379                    'application/x-x509-user-cert' => 'pem',
380                    'application/x-pem-file' => 'pem',
381                    'application/pgp' => 'pgp',
382                    'application/x-httpd-php' => 'php',
383                    'application/php' => 'php',
384                    'application/x-php' => 'php',
385                    'text/php' => 'php',
386                    'text/x-php' => 'php',
387                    'application/x-httpd-php-source' => 'php',
388                    'image/png' => 'png',
389                    'image/x-png' => 'png',
390                    'application/powerpoint' => 'ppt',
391                    'application/vnd.ms-powerpoint' => 'ppt',
392                    'application/vnd.ms-office' => 'ppt',
393                    'application/msword' => 'doc',
394                    'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'pptx',
395                    'application/vnd.oasis.opendocument.presentation' => 'odp',
396                    'application/vnd.oasis.opendocument.text' => 'odt',
397                    'application/x-photoshop' => 'psd',
398                    'image/vnd.adobe.photoshop' => 'psd',
399                    'audio/x-realaudio' => 'ra',
400                    'audio/x-pn-realaudio' => 'ram',
401                    'application/x-rar' => 'rar',
402                    'application/rar' => 'rar',
403                    'application/x-rar-compressed' => 'rar',
404                    'audio/x-pn-realaudio-plugin' => 'rpm',
405                    'application/x-pkcs7' => 'rsa',
406                    'text/rtf' => 'rtf',
407                    'text/richtext' => 'rtx',
408                    'video/vnd.rn-realvideo' => 'rv',
409                    'application/x-stuffit' => 'sit',
410                    'application/smil' => 'smil',
411                    'text/srt' => 'srt',
412                    'image/svg+xml' => 'svg',
413                    'application/x-shockwave-flash' => 'swf',
414                    'application/x-tar' => 'tar',
415                    'application/x-gzip-compressed' => 'tgz',
416                    'image/tiff' => 'tiff',
417                    'text/plain' => 'txt',
418                    'text/x-vcard' => 'vcf',
419                    'application/videolan' => 'vlc',
420                    'text/vtt' => 'vtt',
421                    'audio/x-wav' => 'wav',
422                    'audio/wave' => 'wav',
423                    'audio/wav' => 'wav',
424                    'application/wbxml' => 'wbxml',
425                    'video/webm' => 'webm',
426                    'audio/x-ms-wma' => 'wma',
427                    'application/wmlc' => 'wmlc',
428                    'video/x-ms-wmv' => 'wmv',
429                    'video/x-ms-asf' => 'wmv',
430                    'application/xhtml+xml' => 'xhtml',
431                    'application/excel' => 'xl',
432                    'application/msexcel' => 'xls',
433                    'application/x-msexcel' => 'xls',
434                    'application/x-ms-excel' => 'xls',
435                    'application/x-excel' => 'xls',
436                    'application/x-dos_ms_excel' => 'xls',
437                    'application/xls' => 'xls',
438                    'application/x-xls' => 'xls',
439                    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx',
440                    'application/vnd.ms-excel' => 'xlsx',
441                    'application/xml' => 'xml',
442                    'text/xml' => 'xml',
443                    'text/xsl' => 'xsl',
444                    'application/xspf+xml' => 'xspf',
445                    'application/x-compress' => 'z',
446                    'application/x-zip' => 'zip',
447                    'application/zip' => 'zip',
448                    'application/x-zip-compressed' => 'zip',
449                    'application/s-compressed' => 'zip',
450                    'application/x-xz' => 'xz',
451                    'multipart/x-zip' => 'zip',
452                    'text/x-scriptzsh' => 'zsh',
453                    'application/vnd.apple.pkpass' => 'pkpass',
454                    'application/vnd.apple.pkpasses' => 'pkpasses',
455                    'application/x-research-info-systems' => 'ris',
456                    'application/dxf' => 'dxf',
457                ];
458                $expect = isset($mime_map[$mimetype]) === true ? $mime_map[$mimetype] : '';
459        }
460        return $expect;
461    } /* }}} */
462
463    /**
464     * Check if filename is valid and corresponds with mimetype
465     *
466     * @param string $filename
467     * @param string $mimetype
468     * @param integer $mode 1=very strict
469     * @return boolean false if filename is invalid
470     */
471    public static function checkFilename($filename, $mimetype, $mode=1) { /* {{{ */
472        if (!preg_match('/^[\w\-._ ]+$/', $filename))
473            return false;
474        $ext = pathinfo($filename, PATHINFO_EXTENSION);
475        if ($ext != self::fileExtension($mimetype))
476            return false;
477        return true;
478    } /* }}} */
479
480    /**
481     * Rename a directory
482     *
483     * @param string $old name of directory to be renamed
484     * @param string $new new name of directory
485     * @return bool
486     */
487    public static function renameDir($old, $new) { /* {{{ */
488        return @rename($old, $new);
489    } /* }}} */
490
491    /**
492     * Create a directory
493     *
494     * @param string $path path of new directory
495     * @return bool
496     */
497    public static function makeDir($path) { /* {{{ */
498        if (!is_dir($path)) {
499            $res = @mkdir($path, 0777, true);
500            if (!$res) return false;
501        }
502
503        return true;
504
505/* some old code
506        if (strncmp($path, DIRECTORY_SEPARATOR, 1) == 0) {
507            $mkfolder = DIRECTORY_SEPARATOR;
508        }
509        else {
510            $mkfolder = "";
511        }
512        $path = preg_split("/[\\\\\/]/", $path);
513        for($i = 0; isset( $path[$i]); $i++)
514        {
515            if (!strlen(trim($path[$i])))continue;
516            $mkfolder .= $path[$i];
517
518            if (!is_dir( $mkfolder)){
519                $res = @mkdir("$mkfolder", 0777);
520                if (!$res) return false;
521            }
522            $mkfolder .= DIRECTORY_SEPARATOR;
523        }
524
525        return true;
526
527        // patch from alekseynfor safe_mod or open_basedir
528
529        global $settings;
530        $path = substr_replace ($path, "/", 0, strlen($settings->_contentDir));
531        $mkfolder = $settings->_contentDir;
532
533        $path = preg_split( "/[\\\\\/]/", $path);
534
535        for($i = 0; isset($path[$i]); $i++)
536        {
537            if (!strlen(trim($path[$i])))continue;
538            $mkfolder .= $path[$i];
539
540            if (!is_dir( $mkfolder)){
541                $res = @mkdir("$mkfolder", 0777);
542                if (!$res) return false;
543            }
544            $mkfolder .= DIRECTORY_SEPARATOR;
545        }
546
547        return true;
548*/
549    } /* }}} */
550
551    /**
552     * Delete directory
553     *
554     * This method recursively deletes a directory including all its files.
555     *
556     * @param string $path path of directory to be deleted
557     * @return bool
558     */
559    public static function removeDir($path) { /* {{{ */
560        $handle = @opendir($path);
561        if (!$handle)
562            return false;
563        while ($entry = @readdir($handle)) {
564            if ($entry == ".." || $entry == ".")
565                continue;
566            elseif (is_dir($path . DIRECTORY_SEPARATOR . $entry)) {
567                if (!self::removeDir($path . DIRECTORY_SEPARATOR . $entry))
568                    return false;
569            } else {
570                if (!@unlink($path . DIRECTORY_SEPARATOR . $entry))
571                    return false;
572            }
573        }
574        @closedir($handle);
575        return @rmdir($path);
576    } /* }}} */
577
578    /**
579     * Copy a directory
580     *
581     * This method copies a directory recursively including all its files.
582     *
583     * @param string $sourcePath path of directory to copy
584     * @param string $targetPath path of target directory
585     * @return bool
586     */
587    public static function copyDir($sourcePath, $targetPath) { /* {{{ */
588        if (mkdir($targetPath, 0777)) {
589            $handle = @opendir($sourcePath);
590            while ($entry = @readdir($handle)) {
591                if ($entry == ".." || $entry == ".")
592                    continue;
593                elseif (is_dir($sourcePath . $entry)) {
594                    if (!self::copyDir($sourcePath . DIRECTORY_SEPARATOR . $entry, $targetPath . DIRECTORY_SEPARATOR . $entry))
595                        return false;
596                } else {
597                    if (!@copy($sourcePath . DIRECTORY_SEPARATOR . $entry, $targetPath . DIRECTORY_SEPARATOR . $entry))
598                        return false;
599                }
600            }
601            @closedir($handle);
602        } else {
603            return false;
604        }
605
606        return true;
607    } /* }}} */
608
609    /**
610     * Move a directory
611     *
612     * @param string $sourcePath path of directory to be moved
613     * @param string $targetPath new name of directory
614     * @return bool
615     */
616    public static function moveDir($sourcePath, $targetPath) { /* {{{ */
617        if (!self::copyDir($sourcePath, $targetPath))
618            return false;
619        return self::removeDir($sourcePath);
620    } /* }}} */
621
622    // code by Kioob (php.net manual)
623    /**
624     * Compress a file with gzip
625     *
626     * @param string $source path of file to be compressed
627     * @param bool $level level of compression
628     * @return bool|string file name of compressed file or false in case of an error
629     */
630    public static function gzcompressfile($source, $level = false) { /* {{{ */
631        $dest = $source.'.gz';
632        $mode = 'wb'.$level;
633        $error = false;
634        if ($fp_out = @gzopen($dest, $mode)) {
635            if ($fp_in = @fopen($source, 'rb')) {
636                while (!feof($fp_in))
637                    @gzwrite($fp_out, fread($fp_in, 1024*512));
638                @fclose($fp_in);
639            } else {
640                $error = true;
641            }
642            @gzclose($fp_out);
643        } else {
644            $error = true;
645        }
646
647        if ($error) return false;
648        else return $dest;
649    } /* }}} */
650}