Commit | Line | Data |
---|---|---|
281374c9 AE |
1 | <?php |
2 | namespace wcf\util; | |
ec1b1daf | 3 | use wcf\system\exception\SystemException; |
281374c9 | 4 | use wcf\system\io\File; |
a628af06 | 5 | use wcf\system\io\GZipFile; |
281374c9 AE |
6 | |
7 | /** | |
8 | * Contains file-related functions. | |
9f959ced MS |
9 | * |
10 | * @author Marcel Werk | |
c839bd49 | 11 | * @copyright 2001-2018 WoltLab GmbH |
281374c9 | 12 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
e71525e4 | 13 | * @package WoltLabSuite\Core\Util |
281374c9 | 14 | */ |
18284789 | 15 | final class FileUtil { |
35e07ccc MW |
16 | /** |
17 | * finfo instance | |
9f959ced | 18 | * @var \finfo |
35e07ccc MW |
19 | */ |
20 | protected static $finfo = null; | |
21 | ||
89c020cc AE |
22 | /** |
23 | * memory limit in bytes | |
24 | * @var integer | |
25 | */ | |
26 | protected static $memoryLimit = null; | |
27 | ||
d8fa09e0 AE |
28 | /** |
29 | * chmod mode | |
30 | * @var string | |
31 | */ | |
32 | protected static $mode = null; | |
33 | ||
59e352e7 TD |
34 | /** |
35 | * Tries to find the temp folder. | |
36 | * | |
37 | * @return string | |
2b770bdd | 38 | * @throws SystemException |
59e352e7 TD |
39 | */ |
40 | public static function getTempFolder() { | |
40c9a81c TD |
41 | try { |
42 | // This method does not contain any shut up operator by intent. | |
43 | // Any operation that fails here is fatal. | |
44 | $path = WCF_DIR.'tmp/'; | |
45 | ||
46 | if (is_file($path)) { | |
47 | // wat | |
48 | unlink($path); | |
49 | } | |
50 | ||
51 | if (!file_exists($path)) { | |
52 | mkdir($path, 0777); | |
53 | } | |
54 | ||
55 | if (!is_dir($path)) { | |
56 | throw new SystemException("Temporary folder '".$path."' does not exist and could not be created. Please check the permissions of the '".WCF_DIR."' folder using your favorite ftp program."); | |
57 | } | |
58 | ||
59 | if (!is_writable($path)) { | |
60 | self::makeWritable($path); | |
61 | } | |
62 | ||
63 | if (!is_writable($path)) { | |
64 | throw new SystemException("Temporary folder '".$path."' is not writable. Please check the permissions using your favorite ftp program."); | |
65 | } | |
66 | ||
67 | file_put_contents($path.'/.htaccess', 'deny from all'); | |
68 | ||
69 | return $path; | |
59e352e7 | 70 | } |
40c9a81c TD |
71 | catch (SystemException $e) { |
72 | // use tmp folder in document root by default | |
73 | if (!empty($_SERVER['DOCUMENT_ROOT'])) { | |
74 | if (strpos($_SERVER['DOCUMENT_ROOT'], 'strato') !== false) { | |
75 | // strato bugfix | |
76 | // create tmp folder in document root automatically | |
77 | if (!@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp')) { | |
78 | @mkdir($_SERVER['DOCUMENT_ROOT'].'/tmp/', 0777); | |
79 | self::makeWritable($_SERVER['DOCUMENT_ROOT'].'/tmp/'); | |
80 | } | |
81 | } | |
82 | if (@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp') && @is_writable($_SERVER['DOCUMENT_ROOT'].'/tmp')) { | |
83 | return $_SERVER['DOCUMENT_ROOT'].'/tmp/'; | |
84 | } | |
85 | } | |
86 | ||
87 | if (isset($_ENV['TMP']) && @is_writable($_ENV['TMP'])) { | |
88 | return $_ENV['TMP'] . '/'; | |
89 | } | |
90 | if (isset($_ENV['TEMP']) && @is_writable($_ENV['TEMP'])) { | |
91 | return $_ENV['TEMP'] . '/'; | |
92 | } | |
93 | if (isset($_ENV['TMPDIR']) && @is_writable($_ENV['TMPDIR'])) { | |
94 | return $_ENV['TMPDIR'] . '/'; | |
95 | } | |
96 | ||
97 | if (($path = ini_get('upload_tmp_dir')) && @is_writable($path)) { | |
98 | return $path . '/'; | |
99 | } | |
100 | if (@file_exists('/tmp/') && @is_writable('/tmp/')) { | |
101 | return '/tmp/'; | |
102 | } | |
103 | if (function_exists('session_save_path') && ($path = session_save_path()) && @is_writable($path)) { | |
104 | return $path . '/'; | |
105 | } | |
106 | ||
107 | throw new SystemException('There is no access to the system temporary folder due to an unknown reason and no user specific temporary folder exists in '.WCF_DIR.'! This is a misconfiguration of your webserver software! Please create a folder called '.$path.' using your favorite ftp program, make it writable and then retry this installation.'); | |
59e352e7 TD |
108 | } |
109 | } | |
110 | ||
281374c9 AE |
111 | /** |
112 | * Generates a new temporary filename in TMP_DIR. | |
9f959ced MS |
113 | * |
114 | * @param string $prefix | |
115 | * @param string $extension | |
116 | * @param string $dir | |
117 | * @return string | |
281374c9 AE |
118 | */ |
119 | public static function getTemporaryFilename($prefix = 'tmpFile_', $extension = '', $dir = TMP_DIR) { | |
120 | $dir = self::addTrailingSlash($dir); | |
121 | do { | |
122 | $tmpFile = $dir.$prefix.StringUtil::getRandomID().$extension; | |
123 | } | |
59e352e7 | 124 | while (file_exists($tmpFile)); |
281374c9 AE |
125 | |
126 | return $tmpFile; | |
127 | } | |
128 | ||
129 | /** | |
9f959ced | 130 | * Removes a leading slash from the given path. |
59dc0db6 | 131 | * |
9f959ced MS |
132 | * @param string $path |
133 | * @return string | |
281374c9 AE |
134 | */ |
135 | public static function removeLeadingSlash($path) { | |
4c53e034 | 136 | return ltrim($path, '/'); |
281374c9 | 137 | } |
9f959ced | 138 | |
281374c9 | 139 | /** |
9f959ced MS |
140 | * Removes a trailing slash from the given path. |
141 | * | |
142 | * @param string $path | |
143 | * @return string | |
281374c9 AE |
144 | */ |
145 | public static function removeTrailingSlash($path) { | |
4c53e034 | 146 | return rtrim($path, '/'); |
281374c9 AE |
147 | } |
148 | ||
149 | /** | |
9f959ced MS |
150 | * Adds a trailing slash to the given path. |
151 | * | |
152 | * @param string $path | |
153 | * @return string | |
281374c9 AE |
154 | */ |
155 | public static function addTrailingSlash($path) { | |
4c53e034 | 156 | return rtrim($path, '/').'/'; |
c244fcc6 AE |
157 | } |
158 | ||
159 | /** | |
9f959ced | 160 | * Adds a leading slash to the given path. |
c244fcc6 AE |
161 | * |
162 | * @param string $path | |
9f959ced | 163 | * @return string |
c244fcc6 AE |
164 | */ |
165 | public static function addLeadingSlash($path) { | |
4c53e034 | 166 | return '/'.ltrim($path, '/'); |
281374c9 | 167 | } |
9f959ced | 168 | |
281374c9 | 169 | /** |
9f959ced MS |
170 | * Returns the relative path from the given absolute paths. |
171 | * | |
172 | * @param string $currentDir | |
173 | * @param string $targetDir | |
174 | * @return string | |
281374c9 AE |
175 | */ |
176 | public static function getRelativePath($currentDir, $targetDir) { | |
177 | // remove trailing slashes | |
f2024036 AE |
178 | $currentDir = self::removeTrailingSlash(self::unifyDirSeparator($currentDir)); |
179 | $targetDir = self::removeTrailingSlash(self::unifyDirSeparator($targetDir)); | |
281374c9 AE |
180 | |
181 | if ($currentDir == $targetDir) { | |
59e352e7 | 182 | return './'; |
281374c9 AE |
183 | } |
184 | ||
185 | $current = explode('/', $currentDir); | |
186 | $target = explode('/', $targetDir); | |
187 | ||
188 | $relPath = ''; | |
189 | //for ($i = max(count($current), count($target)) - 1; $i >= 0; $i--) { | |
190 | for ($i = 0, $max = max(count($current), count($target)); $i < $max; $i++) { | |
191 | if (isset($current[$i]) && isset($target[$i])) { | |
192 | if ($current[$i] != $target[$i]) { | |
193 | for ($j = 0; $j < $i; $j++) { | |
59e352e7 | 194 | unset($target[$j]); |
281374c9 | 195 | } |
f4683ba3 | 196 | $relPath .= str_repeat('../', count($current) - $i).implode('/', $target).'/'; |
29ddf8ad | 197 | |
281374c9 AE |
198 | break; |
199 | } | |
97e52431 | 200 | } |
281374c9 AE |
201 | // go up one level |
202 | else if (isset($current[$i]) && !isset($target[$i])) { | |
203 | $relPath .= '../'; | |
204 | } | |
205 | else if (!isset($current[$i]) && isset($target[$i])) { | |
206 | $relPath .= $target[$i].'/'; | |
207 | } | |
208 | } | |
209 | ||
210 | return $relPath; | |
211 | } | |
212 | ||
213 | /** | |
9f959ced MS |
214 | * Creates a path on the local filesystem and returns true on success. |
215 | * Parent directories do not need to exists as they will be created if | |
216 | * necessary. | |
281374c9 | 217 | * |
9f959ced | 218 | * @param string $path |
9f959ced | 219 | * @return boolean |
281374c9 | 220 | */ |
1232bce2 | 221 | public static function makePath($path) { |
281374c9 AE |
222 | // directory already exists, abort |
223 | if (file_exists($path)) { | |
224 | return false; | |
225 | } | |
226 | ||
227 | // check if parent directory exists | |
228 | $parent = dirname($path); | |
229 | if ($parent != $path) { | |
230 | // parent directory does not exist either | |
231 | // we have to create the parent directory first | |
232 | $parent = self::addTrailingSlash($parent); | |
233 | if (!@file_exists($parent)) { | |
234 | // could not create parent directory either => abort | |
1232bce2 | 235 | if (!self::makePath($parent)) { |
59e352e7 | 236 | return false; |
281374c9 AE |
237 | } |
238 | } | |
239 | ||
240 | // well, the parent directory exists or has been created | |
241 | // lets create this path | |
1232bce2 | 242 | if (!@mkdir($path)) { |
281374c9 AE |
243 | return false; |
244 | } | |
1232bce2 AE |
245 | |
246 | self::makeWritable($path); | |
281374c9 AE |
247 | |
248 | return true; | |
249 | } | |
250 | ||
251 | return false; | |
252 | } | |
253 | ||
254 | /** | |
f2024036 | 255 | * Unifies windows and unix directory separators. |
9f959ced MS |
256 | * |
257 | * @param string $path | |
258 | * @return string | |
281374c9 | 259 | */ |
f2024036 | 260 | public static function unifyDirSeparator($path) { |
281374c9 AE |
261 | $path = str_replace('\\\\', '/', $path); |
262 | $path = str_replace('\\', '/', $path); | |
263 | return $path; | |
264 | } | |
265 | ||
266 | /** | |
267 | * Scans a folder (and subfolder) for a specific file. | |
268 | * Returns the filename if found, otherwise false. | |
9f959ced MS |
269 | * |
270 | * @param string $folder | |
271 | * @param string $searchfile | |
272 | * @param boolean $recursive | |
273 | * @return mixed | |
281374c9 AE |
274 | */ |
275 | public static function scanFolder($folder, $searchfile, $recursive = true) { | |
276 | if (!@is_dir($folder)) { | |
277 | return false; | |
278 | } | |
279 | if (!$searchfile) { | |
280 | return false; | |
281 | } | |
9f959ced | 282 | |
281374c9 AE |
283 | $folder = self::addTrailingSlash($folder); |
284 | $dirh = @opendir($folder); | |
285 | while ($filename = @readdir($dirh)) { | |
286 | if ($filename == '.' || $filename == '..') { | |
287 | continue; | |
288 | } | |
289 | if ($filename == $searchfile) { | |
290 | @closedir($dirh); | |
291 | return $folder.$filename; | |
292 | } | |
9f959ced | 293 | |
281374c9 AE |
294 | if ($recursive == true && @is_dir($folder.$filename)) { |
295 | if ($found = self::scanFolder($folder.$filename, $searchfile, $recursive)) { | |
296 | @closedir($dirh); | |
297 | return $found; | |
298 | } | |
299 | } | |
300 | } | |
301 | @closedir($dirh); | |
302 | } | |
303 | ||
304 | /** | |
28410a97 | 305 | * Returns true if the given filename is an url (http or ftp). |
281374c9 | 306 | * |
9f959ced | 307 | * @param string $filename |
281374c9 AE |
308 | * @return boolean |
309 | */ | |
310 | public static function isURL($filename) { | |
311 | return preg_match('!^(https?|ftp)://!', $filename); | |
312 | } | |
313 | ||
314 | /** | |
315 | * Returns canonicalized absolute pathname. | |
316 | * | |
317 | * @param string $path | |
318 | * @return string path | |
319 | */ | |
320 | public static function getRealPath($path) { | |
f2024036 | 321 | $path = self::unifyDirSeparator($path); |
281374c9 | 322 | |
59ab4d0f | 323 | $result = []; |
281374c9 AE |
324 | $pathA = explode('/', $path); |
325 | if ($pathA[0] === '') { | |
326 | $result[] = ''; | |
327 | } | |
9f959ced | 328 | |
281374c9 AE |
329 | foreach ($pathA as $key => $dir) { |
330 | if ($dir == '..') { | |
331 | if (end($result) == '..') { | |
332 | $result[] = '..'; | |
0f0590c2 MS |
333 | } |
334 | else { | |
281374c9 AE |
335 | $lastValue = array_pop($result); |
336 | if ($lastValue === '' || $lastValue === null) { | |
337 | $result[] = '..'; | |
338 | } | |
339 | } | |
0f0590c2 | 340 | } |
281374c9 AE |
341 | else if ($dir !== '' && $dir != '.') { |
342 | $result[] = $dir; | |
343 | } | |
344 | } | |
345 | ||
346 | $lastValue = end($pathA); | |
347 | if ($lastValue === '' || $lastValue === false) { | |
348 | $result[] = ''; | |
349 | } | |
350 | ||
351 | return implode('/', $result); | |
352 | } | |
353 | ||
354 | /** | |
9f959ced MS |
355 | * Formats the given filesize. |
356 | * | |
357 | * @param integer $byte | |
358 | * @param integer $precision | |
359 | * @return string | |
281374c9 AE |
360 | */ |
361 | public static function formatFilesize($byte, $precision = 2) { | |
362 | $symbol = 'Byte'; | |
363 | if ($byte >= 1000) { | |
364 | $byte /= 1000; | |
365 | $symbol = 'kB'; | |
366 | } | |
367 | if ($byte >= 1000) { | |
368 | $byte /= 1000; | |
369 | $symbol = 'MB'; | |
370 | } | |
371 | if ($byte >= 1000) { | |
372 | $byte /= 1000; | |
373 | $symbol = 'GB'; | |
374 | } | |
375 | if ($byte >= 1000) { | |
376 | $byte /= 1000; | |
377 | $symbol = 'TB'; | |
378 | } | |
379 | ||
380 | return StringUtil::formatNumeric(round($byte, $precision)).' '.$symbol; | |
381 | } | |
382 | ||
383 | /** | |
9f959ced | 384 | * Formats a filesize with binary prefix. |
281374c9 | 385 | * |
1615fc2e | 386 | * For more information: <http://en.wikipedia.org/wiki/Binary_prefix> |
9f959ced MS |
387 | * |
388 | * @param integer $byte | |
389 | * @param integer $precision | |
390 | * @return string | |
281374c9 AE |
391 | */ |
392 | public static function formatFilesizeBinary($byte, $precision = 2) { | |
393 | $symbol = 'Byte'; | |
394 | if ($byte >= 1024) { | |
395 | $byte /= 1024; | |
396 | $symbol = 'KiB'; | |
397 | } | |
398 | if ($byte >= 1024) { | |
399 | $byte /= 1024; | |
400 | $symbol = 'MiB'; | |
401 | } | |
402 | if ($byte >= 1024) { | |
403 | $byte /= 1024; | |
404 | $symbol = 'GiB'; | |
405 | } | |
406 | if ($byte >= 1024) { | |
407 | $byte /= 1024; | |
408 | $symbol = 'TiB'; | |
409 | } | |
410 | ||
411 | return StringUtil::formatNumeric(round($byte, $precision)).' '.$symbol; | |
412 | } | |
413 | ||
414 | /** | |
9f959ced MS |
415 | * Downloads a package archive from an http URL and returns the path to |
416 | * the downloaded file. | |
281374c9 AE |
417 | * |
418 | * @param string $httpUrl | |
419 | * @param string $prefix | |
a0ac592e TD |
420 | * @param array $options |
421 | * @param array $postParameters | |
9f959ced MS |
422 | * @param array $headers empty array or a not initialized variable |
423 | * @return string | |
e3369fd2 | 424 | * @deprecated This method currently only is a wrapper around \wcf\util\HTTPRequest. Please use |
f9d24625 | 425 | * HTTPRequest from now on, as this method may be removed in the future. |
281374c9 | 426 | */ |
59ab4d0f | 427 | public static function downloadFileFromHttp($httpUrl, $prefix = 'package', array $options = [], array $postParameters = [], &$headers = []) { |
a195ffa6 | 428 | $request = new HTTPRequest($httpUrl, $options, $postParameters); |
86fc0430 TD |
429 | $request->execute(); |
430 | $reply = $request->getReply(); | |
09727da6 | 431 | |
86fc0430 TD |
432 | $newFileName = self::getTemporaryFilename($prefix.'_'); |
433 | file_put_contents($newFileName, $reply['body']); // the file to write. | |
09727da6 | 434 | |
86fc0430 TD |
435 | $tmp = $reply['headers']; // copy variable, to avoid problems with the reference |
436 | $headers = $tmp; | |
281374c9 | 437 | |
59e352e7 | 438 | return $newFileName; |
281374c9 AE |
439 | } |
440 | ||
281374c9 AE |
441 | /** |
442 | * Determines whether a file is text or binary by checking the first few bytes in the file. | |
443 | * The exact number of bytes is system dependent, but it is typically several thousand. | |
444 | * If every byte in that part of the file is non-null, considers the file to be text; | |
445 | * otherwise it considers the file to be binary. | |
446 | * | |
447 | * @param string $file | |
9f959ced | 448 | * @return boolean |
281374c9 AE |
449 | */ |
450 | public static function isBinary($file) { | |
451 | // open file | |
452 | $file = new File($file, 'rb'); | |
453 | ||
454 | // get block size | |
455 | $stat = $file->stat(); | |
456 | $blockSize = $stat['blksize']; | |
457 | if ($blockSize < 0) $blockSize = 1024; | |
458 | if ($blockSize > $file->filesize()) $blockSize = $file->filesize(); | |
459 | if ($blockSize <= 0) return false; | |
460 | ||
461 | // get bytes | |
462 | $block = $file->read($blockSize); | |
56624595 | 463 | return (strlen($block) == 0 || strpos($block, "\0") !== false); |
281374c9 AE |
464 | } |
465 | ||
466 | /** | |
9f959ced MS |
467 | * Uncompresses a gzipped file and returns true if successful. |
468 | * | |
469 | * @param string $gzipped | |
470 | * @param string $destination | |
e3369fd2 | 471 | * @return boolean |
281374c9 AE |
472 | */ |
473 | public static function uncompressFile($gzipped, $destination) { | |
474 | if (!@is_file($gzipped)) { | |
59e352e7 | 475 | return false; |
281374c9 AE |
476 | } |
477 | ||
a628af06 | 478 | $sourceFile = new GZipFile($gzipped, 'rb'); |
281374c9 AE |
479 | //$filesize = $sourceFile->getFileSize(); |
480 | $targetFile = new File($destination); | |
481 | while (!$sourceFile->eof()) { | |
59e352e7 | 482 | $targetFile->write($sourceFile->read(512), 512); |
281374c9 AE |
483 | } |
484 | $targetFile->close(); | |
485 | $sourceFile->close(); | |
281374c9 | 486 | |
1232bce2 | 487 | self::makeWritable($destination); |
281374c9 | 488 | |
59e352e7 | 489 | return true; |
281374c9 AE |
490 | } |
491 | ||
492 | /** | |
28410a97 | 493 | * Returns true if php is running as apache module. |
281374c9 | 494 | * |
9f959ced | 495 | * @return boolean |
281374c9 AE |
496 | */ |
497 | public static function isApacheModule() { | |
498 | return function_exists('apache_get_version'); | |
499 | } | |
35e07ccc MW |
500 | |
501 | /** | |
502 | * Returns the mime type of a file. | |
503 | * | |
504 | * @param string $filename | |
505 | * @return string | |
506 | */ | |
507 | public static function getMimeType($filename) { | |
508 | if (self::$finfo === null) { | |
0e8c6d5e | 509 | if (!class_exists('\finfo', false)) return 'application/octet-stream'; |
35e07ccc MW |
510 | self::$finfo = new \finfo(FILEINFO_MIME_TYPE); |
511 | } | |
512 | ||
07673afa AE |
513 | // \finfo->file() can fail for files that contain only 1 byte, because libmagic expects at least |
514 | // a few bytes in order to determine the type. See https://bugs.php.net/bug.php?id=64684 | |
515 | $mimeType = @self::$finfo->file($filename); | |
516 | return $mimeType ?: 'application/octet-stream'; | |
35e07ccc | 517 | } |
18284789 | 518 | |
1232bce2 AE |
519 | /** |
520 | * Tries to make a file or directory writable. It starts of with the least | |
d8fa09e0 | 521 | * permissions and goes up until 0666 for files and 0777 for directories. |
1232bce2 AE |
522 | * |
523 | * @param string $filename | |
2b770bdd | 524 | * @throws SystemException |
1232bce2 AE |
525 | */ |
526 | public static function makeWritable($filename) { | |
043b049d | 527 | if (!file_exists($filename)) { |
1232bce2 AE |
528 | return; |
529 | } | |
530 | ||
d8fa09e0 | 531 | if (self::$mode === null) { |
850e5402 | 532 | // WCFSetup |
97e52431 | 533 | if (defined('INSTALL_SCRIPT') && file_exists(INSTALL_SCRIPT)) { |
850e5402 | 534 | // do not use PHP_OS here, as this represents the system it was built on != running on |
0436b618 AE |
535 | // php_uname() is forbidden on some strange hosts; PHP_EOL is reliable |
536 | if (PHP_EOL == "\r\n") { | |
537 | // Windows | |
53e6fba3 | 538 | self::$mode = '0777'; |
850e5402 AE |
539 | } |
540 | else { | |
0436b618 | 541 | // anything but Windows |
adbd8054 AE |
542 | clearstatcache(); |
543 | ||
884dc05a | 544 | self::$mode = '0666'; |
7fe5312d | 545 | |
850e5402 AE |
546 | $tmpFilename = '__permissions_'.sha1(time()).'.txt'; |
547 | @touch($tmpFilename); | |
7fe5312d | 548 | |
850e5402 AE |
549 | // create a new file and check the file owner, if it is the same |
550 | // as this file (uploaded through FTP), we can safely grant write | |
551 | // permissions exclusively to the owner rather than everyone | |
552 | if (file_exists($tmpFilename)) { | |
728b9dd6 | 553 | $scriptOwner = fileowner(INSTALL_SCRIPT); |
850e5402 | 554 | $fileOwner = fileowner($tmpFilename); |
7fe5312d | 555 | |
850e5402 | 556 | if ($scriptOwner === $fileOwner) { |
884dc05a | 557 | self::$mode = '0644'; |
850e5402 | 558 | } |
7fe5312d | 559 | |
850e5402 AE |
560 | @unlink($tmpFilename); |
561 | } | |
562 | } | |
563 | } | |
564 | else { | |
565 | // mirror permissions of WCF.class.php | |
49fd1c14 | 566 | if (!file_exists(WCF_DIR . 'lib/system/WCF.class.php')) { |
850e5402 AE |
567 | throw new SystemException("Unable to find 'wcf/lib/system/WCF.class.php'."); |
568 | } | |
569 | ||
570 | self::$mode = '0' . substr(sprintf('%o', fileperms(WCF_DIR . 'lib/system/WCF.class.php')), -3); | |
d8fa09e0 | 571 | } |
1232bce2 AE |
572 | } |
573 | ||
d8fa09e0 AE |
574 | if (is_dir($filename)) { |
575 | if (self::$mode == '0644') { | |
7fe5312d | 576 | @chmod($filename, 0755); |
1232bce2 | 577 | } |
d8fa09e0 | 578 | else { |
7fe5312d | 579 | @chmod($filename, 0777); |
1232bce2 AE |
580 | } |
581 | } | |
d8fa09e0 | 582 | else { |
7fe5312d | 583 | @chmod($filename, octdec(self::$mode)); |
d8fa09e0 AE |
584 | } |
585 | ||
586 | if (!is_writable($filename)) { | |
587 | // does not work with 0777 | |
588 | throw new SystemException("Unable to make '".$filename."' writable. This is a misconfiguration of your server, please contact your system administrator or hosting provider."); | |
589 | } | |
1232bce2 AE |
590 | } |
591 | ||
89c020cc AE |
592 | /** |
593 | * Returns memory limit in bytes. | |
594 | * | |
595 | * @return integer | |
596 | */ | |
597 | public static function getMemoryLimit() { | |
598 | if (self::$memoryLimit === null) { | |
599 | self::$memoryLimit = 0; | |
600 | ||
601 | $memoryLimit = ini_get('memory_limit'); | |
602 | ||
603 | // no limit | |
604 | if ($memoryLimit == -1) { | |
605 | self::$memoryLimit = -1; | |
606 | } | |
607 | ||
608 | // completely numeric, PHP assumes byte | |
609 | if (is_numeric($memoryLimit)) { | |
610 | self::$memoryLimit = $memoryLimit; | |
611 | } | |
612 | ||
613 | // PHP supports 'K', 'M' and 'G' shorthand notation | |
f000565d MW |
614 | if (preg_match('~^(\d+)\s*([KMG])$~i', $memoryLimit, $matches)) { |
615 | switch (strtoupper($matches[2])) { | |
89c020cc AE |
616 | case 'K': |
617 | self::$memoryLimit = $matches[1] * 1024; | |
618 | break; | |
619 | ||
620 | case 'M': | |
621 | self::$memoryLimit = $matches[1] * 1024 * 1024; | |
622 | break; | |
623 | ||
624 | case 'G': | |
625 | self::$memoryLimit = $matches[1] * 1024 * 1024 * 1024; | |
626 | break; | |
627 | } | |
628 | } | |
629 | } | |
630 | ||
631 | return self::$memoryLimit; | |
632 | } | |
633 | ||
4a99533b MS |
634 | /** |
635 | * Returns true if the given amount of memory is available. | |
636 | * | |
637 | * @param integer $neededMemory | |
638 | * @return boolean | |
639 | */ | |
640 | public static function checkMemoryLimit($neededMemory) { | |
641 | return self::getMemoryLimit() == -1 || self::getMemoryLimit() > (memory_get_usage() + $neededMemory); | |
642 | } | |
643 | ||
5552d2cc MW |
644 | /** |
645 | * Returns icon name for given filename. | |
646 | * | |
647 | * @param string $filename | |
648 | * @return string | |
649 | */ | |
650 | public static function getIconNameByFilename($filename) { | |
651 | static $mapping = [ | |
652 | // archive | |
653 | 'zip' => 'archive', 'rar' => 'archive', 'tar' => 'archive', 'gz' => 'archive', | |
654 | // audio | |
655 | 'mp3' => 'audio', 'ogg' => 'audio', 'wav' => 'audio', | |
656 | // code | |
657 | 'php' => 'code', 'html' => 'code', 'htm' => 'code', 'tpl' => 'code', 'js' => 'code', | |
658 | // excel | |
659 | 'xls' => 'excel', 'ods' => 'excel', 'xlsx' => 'excel', | |
660 | // image | |
661 | 'gif' => 'image', 'jpg' => 'image', 'jpeg' => 'image', 'png' => 'image', 'bmp' => 'image', | |
662 | // video | |
663 | 'avi' => 'video', 'wmv' => 'video', 'mov' => 'video', 'mp4' => 'video', 'mpg' => 'video', 'mpeg' => 'video', 'flv' => 'video', | |
664 | ||
665 | 'pdf' => 'pdf', | |
666 | // powerpoint | |
667 | 'ppt' => 'powerpoint', 'pptx' => 'powerpoint', | |
668 | // text | |
669 | 'txt' => 'text', | |
670 | // word | |
671 | 'doc' => 'word', 'docx' => 'word', 'odt' => 'word' | |
672 | ]; | |
673 | ||
674 | $lastDotPosition = strrpos($filename, '.'); | |
675 | if ($lastDotPosition !== false) { | |
676 | $extension = substr($filename, $lastDotPosition + 1); | |
677 | if (isset($mapping[$extension])) { | |
678 | return $mapping[$extension]; | |
679 | } | |
680 | } | |
681 | ||
682 | return ''; | |
683 | } | |
684 | ||
1d5f9363 MS |
685 | /** |
686 | * Forbid creation of FileUtil objects. | |
687 | */ | |
688 | private function __construct() { | |
689 | // does nothing | |
690 | } | |
dcb3a44c | 691 | } |