Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
78.73% covered (warning)
78.73%
248 / 315
57.89% covered (warning)
57.89%
11 / 19
CRAP
0.00% covered (danger)
0.00%
0 / 1
SeedDMS_Core_File
78.73% covered (warning)
78.73%
248 / 315
57.89% covered (warning)
57.89%
11 / 19
134.05
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 / 39
0.00% covered (danger)
0.00%
0 / 1
380
 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
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fileExtension
100.00% covered (success)
100.00%
192 / 192
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                elseif ($fileType == '.tex')
127                    $mimetype = 'text/x-tex';
128                elseif ($fileType == '.docx')
129                    $mimetype = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
130                elseif ($fileType == '.pkpass')
131                    $mimetype = 'application/vnd.apple.pkpass';
132                elseif ($fileType == '.m3u')
133                    $mimetype = 'application/mpegurl';
134                break;
135            case 'application/zip':
136                if ($fileType == '.pkpass')
137                    $mimetype = 'application/vnd.apple.pkpass';
138                elseif ($fileType == '.pkpasses')
139                    $mimetype = 'application/vnd.apple.pkpasses';
140                elseif ($fileType == '.numbers')
141                    $mimetype = 'application/vnd.apple.numbers';
142                elseif ($fileType == '.pages')
143                    $mimetype = 'application/vnd.apple.pages';
144                elseif ($fileType == '.key')
145                    $mimetype = 'application/vnd.apple.keynote';
146                break;
147            case 'application/gzip':
148                if ($fileType == '.xopp')
149                    $mimetype = 'application/x-xopp';
150                break;
151            case 'text/xml':
152                if ($fileType == '.html')
153                    $mimetype = 'text/html';
154                break;
155        }
156        return $mimetype;
157    } /* }}} */
158
159    /**
160     * Turn an integer into a string with units for bytes
161     *
162     * @param integer $size
163     * @param array $sizes list of units for 10^0, 10^3, 10^6, ..., 10^(n*3) bytes
164     * @return string
165     */
166    public static function format_filesize($size, $sizes = array('Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB')) { /* {{{ */
167        if ($size == 0) return('0 Bytes');
168        if ($size == 1) return('1 Byte');
169        return (round($size/pow(1024, ($i = floor(log($size, 1024)))), 2) . ' ' . $sizes[$i]);
170    } /* }}} */
171
172    /**
173     * Parses a string like '[0-9]+ *[BKMGT]*' into an integer
174     *
175     * B,K,M,G,T stand for byte, kilo byte, mega byte, giga byte, tera byte
176     * If the last character is omitted, bytes are assumed. Arbitrary
177     * spaces between the number and the unit are allowed.
178     *
179     * @param string $str string to be parsed
180     * @return bool|int
181     */
182    public static function parse_filesize($str) { /* {{{ */
183        if (!preg_match('/^([0-9]+) *([BKMGT]*)$/', trim($str), $matches))
184            return false;
185        $value = $matches[1];
186        $unit = $matches[2] ? $matches[2] : 'B';
187        switch ($unit) {
188            case 'T':
189                return $value * 1024 * 1024 * 1024 *1024;
190                break;
191            case 'G':
192                return $value * 1024 * 1024 * 1024;
193                break;
194            case 'M':
195                return $value * 1024 * 1024;
196                break;
197            case 'K':
198                return $value * 1024;
199                break;
200            default:
201                return (int) $value;
202                break;
203        }
204        return false;
205    } /* }}} */
206
207    /**
208     * Check if file exists
209     *
210     * @param string $file name of file to be checked
211     * @return bool true if file exists
212     */
213    public static function file_exists($file) { /* {{{ */
214        return file_exists($file);
215    } /* }}} */
216
217    /**
218     * Calculate the checksum of a file
219     *
220     * This method calculates the md5 sum of the file's content.
221     *
222     * @param string $file name of file
223     * @return string md5 sum of file
224     */
225    public static function checksum($file) { /* {{{ */
226        return md5_file($file);
227    } /* }}} */
228
229    /**
230     * Return file extension by mimetype
231     *
232     * This methods returns the common file extension for a given mime type.
233     *
234     * @param string $mimetype
235     * @return string file extension with the dot or an empty string
236     */
237    public static function fileExtension($mimetype) { /* {{{ */
238        switch ($mimetype) {
239            case "application/pdf":
240            case "image/png":
241            case "image/gif":
242            case "image/jpg":
243                $expect = substr($mimetype, -3, 3);
244                break;
245            default:
246                $mime_map = [
247                    'video/3gpp2' => '3g2',
248                    'video/3gp' => '3gp',
249                    'video/3gpp' => '3gp',
250                    'application/x-compressed' => '7zip',
251                    'audio/x-acc'=> 'aac',
252                    'audio/ac3' => 'ac3',
253                    'application/postscript' => 'ps',
254                    'audio/x-aiff' => 'aif',
255                    'audio/aiff' => 'aif',
256                    'audio/x-au' => 'au',
257                    'video/x-msvideo' => 'avi',
258                    'video/msvideo' => 'avi',
259                    'video/avi' => 'avi',
260                    'application/x-troff-msvideo' => 'avi',
261                    'application/macbinary' => 'bin',
262                    'application/mac-binary' => 'bin',
263                    'application/x-binary' => 'bin',
264                    'application/x-macbinary' => 'bin',
265                    'image/bmp' => 'bmp',
266                    'image/x-bmp' => 'bmp',
267                    'image/x-bitmap' => 'bmp',
268                    'image/x-xbitmap' => 'bmp',
269                    'image/x-win-bitmap' => 'bmp',
270                    'image/x-windows-bmp' => 'bmp',
271                    'image/ms-bmp' => 'bmp',
272                    'image/x-ms-bmp' => 'bmp',
273                    'application/bmp' => 'bmp',
274                    'application/x-bmp' => 'bmp',
275                    'application/x-win-bitmap' => 'bmp',
276                    'application/cdr' => 'cdr',
277                    'application/coreldraw' => 'cdr',
278                    'application/x-cdr' => 'cdr',
279                    'application/x-coreldraw' => 'cdr',
280                    'image/cdr' => 'cdr',
281                    'image/x-cdr' => 'cdr',
282                    'zz-application/zz-winassoc-cdr' => 'cdr',
283                    'application/mac-compactpro' => 'cpt',
284                    'application/pkix-crl' => 'crl',
285                    'application/pkcs-crl' => 'crl',
286                    'application/x-x509-ca-cert' => 'crt',
287                    'application/pkix-cert' => 'crt',
288                    'text/css' => 'css',
289                    'text/x-comma-separated-values' => 'csv',
290                    'text/comma-separated-values' => 'csv',
291                    'application/vnd.msexcel' => 'xls',
292                    'application/x-director' => 'dcr',
293                    'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
294                    'application/x-dvi' => 'dvi',
295                    'message/rfc822' => 'eml',
296                    'application/x-msdownload' => 'exe',
297                    'video/x-f4v' => 'f4v',
298                    'audio/x-flac' => 'flac',
299                    'video/x-flv' => 'flv',
300                    'image/gif' => 'gif',
301                    'application/gpg-keys' => 'gpg',
302                    'application/x-gtar' => 'tar.gz',
303                    'application/x-gzip' => 'gzip',
304                    'application/mac-binhex40' => 'hqx',
305                    'application/mac-binhex' => 'hqx',
306                    'application/x-binhex40' => 'hqx',
307                    'application/x-mac-binhex40' => 'hqx',
308                    'text/html' => 'html',
309                    'image/x-icon' => 'ico',
310                    'image/x-ico' => 'ico',
311                    'image/vnd.microsoft.icon' => 'ico',
312                    'text/calendar' => 'ics',
313                    'application/java-archive' => 'jar',
314                    'application/x-java-application' => 'jar',
315                    'application/x-jar' => 'jar',
316                    'image/jp2' => 'jp2',
317                    'video/mj2'=> 'jp2',
318                    'image/jpx' => 'jp2',
319                    'image/jpm' => 'jp2',
320                    'image/jpeg' => 'jpg',
321                    'image/pjpeg' => 'jpg',
322                    'application/x-javascript' => 'js',
323                    'application/json' => 'json',
324                    'text/json' => 'json',
325                    'application/vnd.google-earth.kml+xml' => 'kml',
326                    'application/vnd.google-earth.kmz' => 'kmz',
327                    'text/x-log' => 'log',
328                    'audio/x-m4a' => 'm4a',
329                    'application/vnd.mpegurl' => 'm4u',
330                    'text/markdown' => 'md',
331                    'audio/midi' => 'mid',
332                    'application/vnd.mif' => 'mif',
333                    'video/quicktime' => 'mov',
334                    'video/x-sgi-movie' => 'movie',
335                    'audio/mpeg' => 'mp3',
336                    'audio/mpg' => 'mp3',
337                    'audio/mpeg3' => 'mp3',
338                    'audio/mp3' => 'mp3',
339                    'video/mp4' => 'mp4',
340                    'video/mpeg' => 'mpeg',
341                    'application/oda' => 'oda',
342                    'audio/ogg' => 'ogg',
343                    'video/ogg' => 'ogg',
344                    'application/ogg' => 'ogg',
345                    'application/x-pkcs10' => 'p10',
346                    'application/pkcs10' => 'p10',
347                    'application/x-pkcs12' => 'p12',
348                    'application/x-pkcs7-signature' => 'p7a',
349                    'application/pkcs7-mime' => 'p7c',
350                    'application/x-pkcs7-mime' => 'p7c',
351                    'application/x-pkcs7-certreqresp' => 'p7r',
352                    'application/pkcs7-signature' => 'p7s',
353                    'application/pdf' => 'pdf',
354                    'application/octet-stream' => 'pdf',
355                    'application/x-x509-user-cert' => 'pem',
356                    'application/x-pem-file' => 'pem',
357                    'application/pgp' => 'pgp',
358                    'application/x-httpd-php' => 'php',
359                    'application/php' => 'php',
360                    'application/x-php' => 'php',
361                    'text/php' => 'php',
362                    'text/x-php' => 'php',
363                    'application/x-httpd-php-source' => 'php',
364                    'image/png' => 'png',
365                    'image/x-png' => 'png',
366                    'application/powerpoint' => 'ppt',
367                    'application/vnd.ms-powerpoint' => 'ppt',
368                    'application/vnd.ms-office' => 'ppt',
369                    'application/msword' => 'doc',
370                    'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'pptx',
371                    'application/x-photoshop' => 'psd',
372                    'image/vnd.adobe.photoshop' => 'psd',
373                    'audio/x-realaudio' => 'ra',
374                    'audio/x-pn-realaudio' => 'ram',
375                    'application/x-rar' => 'rar',
376                    'application/rar' => 'rar',
377                    'application/x-rar-compressed' => 'rar',
378                    'audio/x-pn-realaudio-plugin' => 'rpm',
379                    'application/x-pkcs7' => 'rsa',
380                    'text/rtf' => 'rtf',
381                    'text/richtext' => 'rtx',
382                    'video/vnd.rn-realvideo' => 'rv',
383                    'application/x-stuffit' => 'sit',
384                    'application/smil' => 'smil',
385                    'text/srt' => 'srt',
386                    'image/svg+xml' => 'svg',
387                    'application/x-shockwave-flash' => 'swf',
388                    'application/x-tar' => 'tar',
389                    'application/x-gzip-compressed' => 'tgz',
390                    'image/tiff' => 'tiff',
391                    'text/plain' => 'txt',
392                    'text/x-vcard' => 'vcf',
393                    'application/videolan' => 'vlc',
394                    'text/vtt' => 'vtt',
395                    'audio/x-wav' => 'wav',
396                    'audio/wave' => 'wav',
397                    'audio/wav' => 'wav',
398                    'application/wbxml' => 'wbxml',
399                    'video/webm' => 'webm',
400                    'audio/x-ms-wma' => 'wma',
401                    'application/wmlc' => 'wmlc',
402                    'video/x-ms-wmv' => 'wmv',
403                    'video/x-ms-asf' => 'wmv',
404                    'application/xhtml+xml' => 'xhtml',
405                    'application/excel' => 'xl',
406                    'application/msexcel' => 'xls',
407                    'application/x-msexcel' => 'xls',
408                    'application/x-ms-excel' => 'xls',
409                    'application/x-excel' => 'xls',
410                    'application/x-dos_ms_excel' => 'xls',
411                    'application/xls' => 'xls',
412                    'application/x-xls' => 'xls',
413                    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx',
414                    'application/vnd.ms-excel' => 'xlsx',
415                    'application/xml' => 'xml',
416                    'text/xml' => 'xml',
417                    'text/xsl' => 'xsl',
418                    'application/xspf+xml' => 'xspf',
419                    'application/x-compress' => 'z',
420                    'application/x-zip' => 'zip',
421                    'application/zip' => 'zip',
422                    'application/x-zip-compressed' => 'zip',
423                    'application/s-compressed' => 'zip',
424                    'application/x-xz' => 'xz',
425                    'multipart/x-zip' => 'zip',
426                    'text/x-scriptzsh' => 'zsh',
427                    'application/vnd.apple.pkpass' => 'pkpass',
428                    'application/vnd.apple.pkpasses' => 'pkpasses',
429                ];
430                $expect = isset($mime_map[$mimetype]) === true ? $mime_map[$mimetype] : '';
431        }
432        return $expect;
433    } /* }}} */
434
435    /**
436     * Check if filename is valid and corresponds with mimetype
437     *
438     * @param string $filename
439     * @param string $mimetype
440     * @param integer $mode 1=very strict
441     * @return boolean false if filename is invalid
442     */
443    public static function checkFilename($filename, $mimetype, $mode=1) { /* {{{ */
444        if (!preg_match('/^[\w\-._ ]+$/', $filename))
445            return false;
446        $ext = pathinfo($filename, PATHINFO_EXTENSION);
447        if ($ext != self::fileExtension($mimetype))
448            return false;
449        return true;
450    } /* }}} */
451
452    /**
453     * Rename a directory
454     *
455     * @param string $old name of directory to be renamed
456     * @param string $new new name of directory
457     * @return bool
458     */
459    public static function renameDir($old, $new) { /* {{{ */
460        return @rename($old, $new);
461    } /* }}} */
462
463    /**
464     * Create a directory
465     *
466     * @param string $path path of new directory
467     * @return bool
468     */
469    public static function makeDir($path) { /* {{{ */
470        if (!is_dir($path)) {
471            $res = @mkdir($path, 0777, true);
472            if (!$res) return false;
473        }
474
475        return true;
476
477/* some old code
478        if (strncmp($path, DIRECTORY_SEPARATOR, 1) == 0) {
479            $mkfolder = DIRECTORY_SEPARATOR;
480        }
481        else {
482            $mkfolder = "";
483        }
484        $path = preg_split("/[\\\\\/]/", $path);
485        for($i = 0; isset( $path[$i]); $i++)
486        {
487            if (!strlen(trim($path[$i])))continue;
488            $mkfolder .= $path[$i];
489
490            if (!is_dir( $mkfolder)){
491                $res = @mkdir("$mkfolder", 0777);
492                if (!$res) return false;
493            }
494            $mkfolder .= DIRECTORY_SEPARATOR;
495        }
496
497        return true;
498
499        // patch from alekseynfor safe_mod or open_basedir
500
501        global $settings;
502        $path = substr_replace ($path, "/", 0, strlen($settings->_contentDir));
503        $mkfolder = $settings->_contentDir;
504
505        $path = preg_split( "/[\\\\\/]/", $path);
506
507        for($i = 0; isset($path[$i]); $i++)
508        {
509            if (!strlen(trim($path[$i])))continue;
510            $mkfolder .= $path[$i];
511
512            if (!is_dir( $mkfolder)){
513                $res = @mkdir("$mkfolder", 0777);
514                if (!$res) return false;
515            }
516            $mkfolder .= DIRECTORY_SEPARATOR;
517        }
518
519        return true;
520*/
521    } /* }}} */
522
523    /**
524     * Delete directory
525     *
526     * This method recursively deletes a directory including all its files.
527     *
528     * @param string $path path of directory to be deleted
529     * @return bool
530     */
531    public static function removeDir($path) { /* {{{ */
532        $handle = @opendir($path);
533        if (!$handle)
534            return false;
535        while ($entry = @readdir($handle)) {
536            if ($entry == ".." || $entry == ".")
537                continue;
538            elseif (is_dir($path . DIRECTORY_SEPARATOR . $entry)) {
539                if (!self::removeDir($path . DIRECTORY_SEPARATOR . $entry))
540                    return false;
541            } else {
542                if (!@unlink($path . DIRECTORY_SEPARATOR . $entry))
543                    return false;
544            }
545        }
546        @closedir($handle);
547        return @rmdir($path);
548    } /* }}} */
549
550    /**
551     * Copy a directory
552     *
553     * This method copies a directory recursively including all its files.
554     *
555     * @param string $sourcePath path of directory to copy
556     * @param string $targetPath path of target directory
557     * @return bool
558     */
559    public static function copyDir($sourcePath, $targetPath) { /* {{{ */
560        if (mkdir($targetPath, 0777)) {
561            $handle = @opendir($sourcePath);
562            while ($entry = @readdir($handle)) {
563                if ($entry == ".." || $entry == ".")
564                    continue;
565                elseif (is_dir($sourcePath . $entry)) {
566                    if (!self::copyDir($sourcePath . DIRECTORY_SEPARATOR . $entry, $targetPath . DIRECTORY_SEPARATOR . $entry))
567                        return false;
568                } else {
569                    if (!@copy($sourcePath . DIRECTORY_SEPARATOR . $entry, $targetPath . DIRECTORY_SEPARATOR . $entry))
570                        return false;
571                }
572            }
573            @closedir($handle);
574        } else {
575            return false;
576        }
577
578        return true;
579    } /* }}} */
580
581    /**
582     * Move a directory
583     *
584     * @param string $sourcePath path of directory to be moved
585     * @param string $targetPath new name of directory
586     * @return bool
587     */
588    public static function moveDir($sourcePath, $targetPath) { /* {{{ */
589        if (!self::copyDir($sourcePath, $targetPath))
590            return false;
591        return self::removeDir($sourcePath);
592    } /* }}} */
593
594    // code by Kioob (php.net manual)
595    /**
596     * Compress a file with gzip
597     *
598     * @param string $source path of file to be compressed
599     * @param bool $level level of compression
600     * @return bool|string file name of compressed file or false in case of an error
601     */
602    public static function gzcompressfile($source, $level = false) { /* {{{ */
603        $dest = $source.'.gz';
604        $mode = 'wb'.$level;
605        $error = false;
606        if ($fp_out = @gzopen($dest, $mode)) {
607            if ($fp_in = @fopen($source, 'rb')) {
608                while (!feof($fp_in))
609                    @gzwrite($fp_out, fread($fp_in, 1024*512));
610                @fclose($fp_in);
611            } else {
612                $error = true;
613            }
614            @gzclose($fp_out);
615        } else {
616            $error = true;
617        }
618
619        if ($error) return false;
620        else return $dest;
621    } /* }}} */
622}