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