Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
6a488035 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 TO |
11 | |
12 | /** | |
13 | * | |
14 | * @package CRM | |
ca5cec67 | 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
16 | */ |
17 | ||
18 | /** | |
19 | * class to provide simple static functions for file objects | |
20 | */ | |
21 | class CRM_Utils_File { | |
22 | ||
23 | /** | |
24 | * Given a file name, determine if the file contents make it an ascii file | |
25 | * | |
77855840 TO |
26 | * @param string $name |
27 | * Name of file. | |
6a488035 | 28 | * |
ae5ffbb7 | 29 | * @return bool |
a6c01b45 | 30 | * true if file is ascii |
6a488035 | 31 | */ |
00be9182 | 32 | public static function isAscii($name) { |
6a488035 TO |
33 | $fd = fopen($name, "r"); |
34 | if (!$fd) { | |
35 | return FALSE; | |
36 | } | |
37 | ||
38 | $ascii = TRUE; | |
39 | while (!feof($fd)) { | |
40 | $line = fgets($fd, 8192); | |
41 | if (!CRM_Utils_String::isAscii($line)) { | |
42 | $ascii = FALSE; | |
43 | break; | |
44 | } | |
45 | } | |
46 | ||
47 | fclose($fd); | |
48 | return $ascii; | |
49 | } | |
50 | ||
51 | /** | |
52 | * Given a file name, determine if the file contents make it an html file | |
53 | * | |
77855840 TO |
54 | * @param string $name |
55 | * Name of file. | |
6a488035 | 56 | * |
ae5ffbb7 | 57 | * @return bool |
a6c01b45 | 58 | * true if file is html |
6a488035 | 59 | */ |
00be9182 | 60 | public static function isHtml($name) { |
6a488035 TO |
61 | $fd = fopen($name, "r"); |
62 | if (!$fd) { | |
63 | return FALSE; | |
64 | } | |
65 | ||
66 | $html = FALSE; | |
67 | $lineCount = 0; | |
68 | while (!feof($fd) & $lineCount <= 5) { | |
69 | $lineCount++; | |
70 | $line = fgets($fd, 8192); | |
71 | if (!CRM_Utils_String::isHtml($line)) { | |
72 | $html = TRUE; | |
73 | break; | |
74 | } | |
75 | } | |
76 | ||
77 | fclose($fd); | |
78 | return $html; | |
79 | } | |
80 | ||
81 | /** | |
100fef9d | 82 | * Create a directory given a path name, creates parent directories |
6a488035 TO |
83 | * if needed |
84 | * | |
77855840 TO |
85 | * @param string $path |
86 | * The path name. | |
87 | * @param bool $abort | |
88 | * Should we abort or just return an invalid code. | |
3daed292 TO |
89 | * @return bool|NULL |
90 | * NULL: Folder already exists or was not specified. | |
91 | * TRUE: Creation succeeded. | |
92 | * FALSE: Creation failed. | |
6a488035 | 93 | */ |
00be9182 | 94 | public static function createDir($path, $abort = TRUE) { |
6a488035 | 95 | if (is_dir($path) || empty($path)) { |
3daed292 | 96 | return NULL; |
6a488035 TO |
97 | } |
98 | ||
99 | CRM_Utils_File::createDir(dirname($path), $abort); | |
100 | if (@mkdir($path, 0777) == FALSE) { | |
101 | if ($abort) { | |
102 | $docLink = CRM_Utils_System::docURL2('Moving an Existing Installation to a New Server or Location', NULL, NULL, NULL, NULL, "wiki"); | |
103 | echo "Error: Could not create directory: $path.<p>If you have moved an existing CiviCRM installation from one location or server to another there are several steps you will need to follow. They are detailed on this CiviCRM wiki page - {$docLink}. A fix for the specific problem that caused this error message to be displayed is to set the value of the config_backend column in the civicrm_domain table to NULL. However we strongly recommend that you review and follow all the steps in that document.</p>"; | |
104 | ||
105 | CRM_Utils_System::civiExit(); | |
106 | } | |
107 | else { | |
108 | return FALSE; | |
109 | } | |
110 | } | |
111 | return TRUE; | |
112 | } | |
113 | ||
114 | /** | |
100fef9d | 115 | * Delete a directory given a path name, delete children directories |
6a488035 TO |
116 | * and files if needed |
117 | * | |
77855840 TO |
118 | * @param string $target |
119 | * The path name. | |
f4aaa82a EM |
120 | * @param bool $rmdir |
121 | * @param bool $verbose | |
122 | * | |
123 | * @throws Exception | |
6a488035 | 124 | */ |
00be9182 | 125 | public static function cleanDir($target, $rmdir = TRUE, $verbose = TRUE) { |
be2fb01f | 126 | static $exceptions = ['.', '..']; |
d269912e | 127 | if ($target == '' || $target == '/' || !$target) { |
6a488035 TO |
128 | throw new Exception("Overly broad deletion"); |
129 | } | |
130 | ||
5e7670b1 | 131 | if ($dh = @opendir($target)) { |
132 | while (FALSE !== ($sibling = readdir($dh))) { | |
6a488035 TO |
133 | if (!in_array($sibling, $exceptions)) { |
134 | $object = $target . DIRECTORY_SEPARATOR . $sibling; | |
135 | ||
136 | if (is_dir($object)) { | |
137 | CRM_Utils_File::cleanDir($object, $rmdir, $verbose); | |
138 | } | |
139 | elseif (is_file($object)) { | |
140 | if (!unlink($object)) { | |
be2fb01f | 141 | CRM_Core_Session::setStatus(ts('Unable to remove file %1', [1 => $object]), ts('Warning'), 'error'); |
e7292422 | 142 | } |
6a488035 TO |
143 | } |
144 | } | |
145 | } | |
5e7670b1 | 146 | closedir($dh); |
6a488035 TO |
147 | |
148 | if ($rmdir) { | |
149 | if (rmdir($target)) { | |
150 | if ($verbose) { | |
be2fb01f | 151 | CRM_Core_Session::setStatus(ts('Removed directory %1', [1 => $target]), '', 'success'); |
6a488035 TO |
152 | } |
153 | return TRUE; | |
e7292422 | 154 | } |
6a488035 | 155 | else { |
be2fb01f | 156 | CRM_Core_Session::setStatus(ts('Unable to remove directory %1', [1 => $target]), ts('Warning'), 'error'); |
e7292422 TO |
157 | } |
158 | } | |
6a488035 TO |
159 | } |
160 | } | |
161 | ||
7f616c07 TO |
162 | /** |
163 | * Concatenate several files. | |
164 | * | |
165 | * @param array $files | |
166 | * List of file names. | |
167 | * @param string $delim | |
168 | * An optional delimiter to put between files. | |
169 | * @return string | |
170 | */ | |
171 | public static function concat($files, $delim = '') { | |
172 | $buf = ''; | |
173 | $first = TRUE; | |
174 | foreach ($files as $file) { | |
175 | if (!$first) { | |
176 | $buf .= $delim; | |
177 | } | |
178 | $buf .= file_get_contents($file); | |
179 | $first = FALSE; | |
180 | } | |
181 | return $buf; | |
182 | } | |
183 | ||
5bc392e6 | 184 | /** |
ae5ffbb7 TO |
185 | * @param string $source |
186 | * @param string $destination | |
5bc392e6 | 187 | */ |
ae5ffbb7 | 188 | public static function copyDir($source, $destination) { |
5e7670b1 | 189 | if ($dh = opendir($source)) { |
948d11bf | 190 | @mkdir($destination); |
5e7670b1 | 191 | while (FALSE !== ($file = readdir($dh))) { |
948d11bf CB |
192 | if (($file != '.') && ($file != '..')) { |
193 | if (is_dir($source . DIRECTORY_SEPARATOR . $file)) { | |
194 | CRM_Utils_File::copyDir($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file); | |
195 | } | |
196 | else { | |
197 | copy($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file); | |
198 | } | |
6a488035 TO |
199 | } |
200 | } | |
5e7670b1 | 201 | closedir($dh); |
6a488035 | 202 | } |
6a488035 TO |
203 | } |
204 | ||
205 | /** | |
206 | * Given a file name, recode it (in place!) to UTF-8 | |
207 | * | |
77855840 TO |
208 | * @param string $name |
209 | * Name of file. | |
6a488035 | 210 | * |
ae5ffbb7 | 211 | * @return bool |
a6c01b45 | 212 | * whether the file was recoded properly |
6a488035 | 213 | */ |
00be9182 | 214 | public static function toUtf8($name) { |
6a488035 TO |
215 | static $config = NULL; |
216 | static $legacyEncoding = NULL; | |
217 | if ($config == NULL) { | |
218 | $config = CRM_Core_Config::singleton(); | |
219 | $legacyEncoding = $config->legacyEncoding; | |
220 | } | |
221 | ||
222 | if (!function_exists('iconv')) { | |
223 | ||
224 | return FALSE; | |
225 | ||
226 | } | |
227 | ||
228 | $contents = file_get_contents($name); | |
229 | if ($contents === FALSE) { | |
230 | return FALSE; | |
231 | } | |
232 | ||
233 | $contents = iconv($legacyEncoding, 'UTF-8', $contents); | |
234 | if ($contents === FALSE) { | |
235 | return FALSE; | |
236 | } | |
237 | ||
238 | $file = fopen($name, 'w'); | |
239 | if ($file === FALSE) { | |
240 | return FALSE; | |
241 | } | |
242 | ||
243 | $written = fwrite($file, $contents); | |
244 | $closed = fclose($file); | |
245 | if ($written === FALSE or !$closed) { | |
246 | return FALSE; | |
247 | } | |
248 | ||
249 | return TRUE; | |
250 | } | |
251 | ||
252 | /** | |
5c8cb77f | 253 | * Appends a slash to the end of a string if it doesn't already end with one |
6a488035 | 254 | * |
5c8cb77f CW |
255 | * @param string $path |
256 | * @param string $slash | |
f4aaa82a | 257 | * |
6a488035 | 258 | * @return string |
6a488035 | 259 | */ |
00be9182 | 260 | public static function addTrailingSlash($path, $slash = NULL) { |
5c8cb77f | 261 | if (!$slash) { |
ea3ddccf | 262 | // FIXME: Defaulting to backslash on windows systems can produce |
50bfb460 | 263 | // unexpected results, esp for URL strings which should always use forward-slashes. |
5c8cb77f CW |
264 | // I think this fn should default to forward-slash instead. |
265 | $slash = DIRECTORY_SEPARATOR; | |
6a488035 | 266 | } |
be2fb01f | 267 | if (!in_array(substr($path, -1, 1), ['/', '\\'])) { |
5c8cb77f | 268 | $path .= $slash; |
6a488035 | 269 | } |
5c8cb77f | 270 | return $path; |
6a488035 TO |
271 | } |
272 | ||
3f0e59f6 AH |
273 | /** |
274 | * Save a fake file somewhere | |
275 | * | |
276 | * @param string $dir | |
277 | * The directory where the file should be saved. | |
278 | * @param string $contents | |
279 | * Optional: the contents of the file. | |
33d245c8 | 280 | * @param string $fileName |
3f0e59f6 AH |
281 | * |
282 | * @return string | |
283 | * The filename saved, or FALSE on failure. | |
284 | */ | |
33d245c8 | 285 | public static function createFakeFile($dir, $contents = 'delete me', $fileName = NULL) { |
3f0e59f6 | 286 | $dir = self::addTrailingSlash($dir); |
33d245c8 CW |
287 | if (!$fileName) { |
288 | $fileName = 'delete-this-' . CRM_Utils_String::createRandom(10, CRM_Utils_String::ALPHANUMERIC); | |
289 | } | |
76ceb0c4 | 290 | $success = @file_put_contents($dir . $fileName, $contents); |
3f0e59f6 | 291 | |
33d245c8 | 292 | return ($success === FALSE) ? FALSE : $fileName; |
3f0e59f6 AH |
293 | } |
294 | ||
5bc392e6 | 295 | /** |
e95fbe72 TO |
296 | * @param string|NULL $dsn |
297 | * Use NULL to load the default/active connection from CRM_Core_DAO. | |
298 | * Otherwise, give a full DSN string. | |
100fef9d | 299 | * @param string $fileName |
c0e4c31d | 300 | * @param string $prefix |
5bc392e6 EM |
301 | * @param bool $dieOnErrors |
302 | */ | |
c0e4c31d JK |
303 | public static function sourceSQLFile($dsn, $fileName, $prefix = NULL, $dieOnErrors = TRUE) { |
304 | if (FALSE === file_get_contents($fileName)) { | |
305 | // Our file cannot be found. | |
306 | // Using 'die' here breaks this on extension upgrade. | |
ff48e573 | 307 | throw new CRM_Core_Exception('Could not find the SQL file.'); |
cf369463 JK |
308 | } |
309 | ||
c0e4c31d JK |
310 | self::runSqlQuery($dsn, file_get_contents($fileName), $prefix, $dieOnErrors); |
311 | } | |
312 | ||
313 | /** | |
314 | * | |
315 | * @param string|NULL $dsn | |
316 | * @param string $queryString | |
317 | * @param string $prefix | |
318 | * @param bool $dieOnErrors | |
319 | */ | |
320 | public static function runSqlQuery($dsn, $queryString, $prefix = NULL, $dieOnErrors = TRUE) { | |
321 | $string = $prefix . $queryString; | |
322 | ||
e95fbe72 TO |
323 | if ($dsn === NULL) { |
324 | $db = CRM_Core_DAO::getConnection(); | |
325 | } | |
326 | else { | |
327 | require_once 'DB.php'; | |
328 | $db = DB::connect($dsn); | |
329 | } | |
6a488035 | 330 | |
6a488035 TO |
331 | if (PEAR::isError($db)) { |
332 | die("Cannot open $dsn: " . $db->getMessage()); | |
333 | } | |
334 | if (CRM_Utils_Constant::value('CIVICRM_MYSQL_STRICT', CRM_Utils_System::isDevelopment())) { | |
335 | $db->query('SET SESSION sql_mode = STRICT_TRANS_TABLES'); | |
336 | } | |
abb74cc1 | 337 | $db->query('SET NAMES utf8'); |
b228b202 | 338 | $transactionId = CRM_Utils_Type::escape(CRM_Utils_Request::id(), 'String'); |
65a6387f | 339 | $db->query('SET @uniqueID = ' . "'$transactionId'"); |
6a488035 | 340 | |
50bfb460 | 341 | // get rid of comments starting with # and -- |
6a488035 | 342 | |
fc6159c2 | 343 | $string = self::stripComments($string); |
6a488035 TO |
344 | |
345 | $queries = preg_split('/;\s*$/m', $string); | |
346 | foreach ($queries as $query) { | |
347 | $query = trim($query); | |
348 | if (!empty($query)) { | |
349 | CRM_Core_Error::debug_query($query); | |
350 | $res = &$db->query($query); | |
351 | if (PEAR::isError($res)) { | |
352 | if ($dieOnErrors) { | |
353 | die("Cannot execute $query: " . $res->getMessage()); | |
354 | } | |
355 | else { | |
356 | echo "Cannot execute $query: " . $res->getMessage() . "<p>"; | |
357 | } | |
358 | } | |
359 | } | |
360 | } | |
361 | } | |
c0e4c31d | 362 | |
fc6159c2 | 363 | /** |
364 | * | |
365 | * Strips comment from a possibly multiline SQL string | |
366 | * | |
367 | * @param string $string | |
368 | * | |
369 | * @return string | |
bd6326bf | 370 | * stripped string |
fc6159c2 | 371 | */ |
372 | public static function stripComments($string) { | |
373 | return preg_replace("/^(#|--).*\R*/m", "", $string); | |
374 | } | |
6a488035 | 375 | |
5bc392e6 EM |
376 | /** |
377 | * @param $ext | |
378 | * | |
379 | * @return bool | |
380 | */ | |
00be9182 | 381 | public static function isExtensionSafe($ext) { |
6a488035 TO |
382 | static $extensions = NULL; |
383 | if (!$extensions) { | |
384 | $extensions = CRM_Core_OptionGroup::values('safe_file_extension', TRUE); | |
385 | ||
50bfb460 | 386 | // make extensions to lowercase |
6a488035 TO |
387 | $extensions = array_change_key_case($extensions, CASE_LOWER); |
388 | // allow html/htm extension ONLY if the user is admin | |
389 | // and/or has access CiviMail | |
390 | if (!(CRM_Core_Permission::check('access CiviMail') || | |
353ffa53 TO |
391 | CRM_Core_Permission::check('administer CiviCRM') || |
392 | (CRM_Mailing_Info::workflowEnabled() && | |
393 | CRM_Core_Permission::check('create mailings') | |
394 | ) | |
395 | ) | |
396 | ) { | |
6a488035 TO |
397 | unset($extensions['html']); |
398 | unset($extensions['htm']); | |
399 | } | |
400 | } | |
50bfb460 | 401 | // support lower and uppercase file extensions |
fe0dbeda | 402 | return (bool) isset($extensions[strtolower($ext)]); |
6a488035 TO |
403 | } |
404 | ||
405 | /** | |
fe482240 | 406 | * Determine whether a given file is listed in the PHP include path. |
6a488035 | 407 | * |
77855840 TO |
408 | * @param string $name |
409 | * Name of file. | |
6a488035 | 410 | * |
ae5ffbb7 | 411 | * @return bool |
a6c01b45 | 412 | * whether the file can be include()d or require()d |
6a488035 | 413 | */ |
00be9182 | 414 | public static function isIncludable($name) { |
6a488035 TO |
415 | $x = @fopen($name, 'r', TRUE); |
416 | if ($x) { | |
417 | fclose($x); | |
418 | return TRUE; | |
419 | } | |
420 | else { | |
421 | return FALSE; | |
422 | } | |
423 | } | |
424 | ||
425 | /** | |
ea3ddccf | 426 | * Remove the 32 bit md5 we add to the fileName also remove the unknown tag if we added it. |
427 | * | |
428 | * @param $name | |
429 | * | |
430 | * @return mixed | |
6a488035 | 431 | */ |
00be9182 | 432 | public static function cleanFileName($name) { |
6a488035 TO |
433 | // replace the last 33 character before the '.' with null |
434 | $name = preg_replace('/(_[\w]{32})\./', '.', $name); | |
435 | return $name; | |
436 | } | |
437 | ||
5bc392e6 | 438 | /** |
8246bca4 | 439 | * Make a valid file name. |
440 | * | |
100fef9d | 441 | * @param string $name |
5bc392e6 EM |
442 | * |
443 | * @return string | |
444 | */ | |
00be9182 | 445 | public static function makeFileName($name) { |
353ffa53 TO |
446 | $uniqID = md5(uniqid(rand(), TRUE)); |
447 | $info = pathinfo($name); | |
6a488035 TO |
448 | $basename = substr($info['basename'], |
449 | 0, -(strlen(CRM_Utils_Array::value('extension', $info)) + (CRM_Utils_Array::value('extension', $info) == '' ? 0 : 1)) | |
450 | ); | |
451 | if (!self::isExtensionSafe(CRM_Utils_Array::value('extension', $info))) { | |
452 | // munge extension so it cannot have an embbeded dot in it | |
453 | // The maximum length of a filename for most filesystems is 255 chars. | |
454 | // We'll truncate at 240 to give some room for the extension. | |
455 | return CRM_Utils_String::munge("{$basename}_" . CRM_Utils_Array::value('extension', $info) . "_{$uniqID}", '_', 240) . ".unknown"; | |
456 | } | |
457 | else { | |
458 | return CRM_Utils_String::munge("{$basename}_{$uniqID}", '_', 240) . "." . CRM_Utils_Array::value('extension', $info); | |
459 | } | |
460 | } | |
461 | ||
33d245c8 CW |
462 | /** |
463 | * Copies a file | |
464 | * | |
465 | * @param $filePath | |
466 | * @return mixed | |
467 | */ | |
468 | public static function duplicate($filePath) { | |
469 | $oldName = pathinfo($filePath, PATHINFO_FILENAME); | |
470 | $uniqID = md5(uniqid(rand(), TRUE)); | |
471 | $newName = preg_replace('/(_[\w]{32})$/', '', $oldName) . '_' . $uniqID; | |
472 | $newPath = str_replace($oldName, $newName, $filePath); | |
473 | copy($filePath, $newPath); | |
474 | return $newPath; | |
475 | } | |
476 | ||
5bc392e6 | 477 | /** |
8246bca4 | 478 | * Get files for the extension. |
479 | * | |
480 | * @param string $path | |
481 | * @param string $ext | |
5bc392e6 EM |
482 | * |
483 | * @return array | |
484 | */ | |
00be9182 | 485 | public static function getFilesByExtension($path, $ext) { |
353ffa53 | 486 | $path = self::addTrailingSlash($path); |
be2fb01f | 487 | $files = []; |
948d11bf | 488 | if ($dh = opendir($path)) { |
948d11bf CB |
489 | while (FALSE !== ($elem = readdir($dh))) { |
490 | if (substr($elem, -(strlen($ext) + 1)) == '.' . $ext) { | |
491 | $files[] .= $path . $elem; | |
492 | } | |
6a488035 | 493 | } |
948d11bf | 494 | closedir($dh); |
6a488035 | 495 | } |
6a488035 TO |
496 | return $files; |
497 | } | |
498 | ||
499 | /** | |
500 | * Restrict access to a given directory (by planting there a restrictive .htaccess file) | |
501 | * | |
77855840 TO |
502 | * @param string $dir |
503 | * The directory to be secured. | |
f4aaa82a | 504 | * @param bool $overwrite |
6a488035 | 505 | */ |
00be9182 | 506 | public static function restrictAccess($dir, $overwrite = FALSE) { |
6a488035 TO |
507 | // note: empty value for $dir can play havoc, since that might result in putting '.htaccess' to root dir |
508 | // of site, causing site to stop functioning. | |
509 | // FIXME: we should do more checks here - | |
ea3b22b5 | 510 | if (!empty($dir) && is_dir($dir)) { |
6a488035 TO |
511 | $htaccess = <<<HTACCESS |
512 | <Files "*"> | |
b1de9132 D |
513 | # Apache 2.2 |
514 | <IfModule !authz_core_module> | |
515 | Order allow,deny | |
516 | Deny from all | |
517 | </IfModule> | |
518 | ||
519 | # Apache 2.4+ | |
520 | <IfModule authz_core_module> | |
521 | Require all denied | |
522 | </IfModule> | |
6a488035 TO |
523 | </Files> |
524 | ||
525 | HTACCESS; | |
526 | $file = $dir . '.htaccess'; | |
ea3b22b5 TO |
527 | if ($overwrite || !file_exists($file)) { |
528 | if (file_put_contents($file, $htaccess) === FALSE) { | |
529 | CRM_Core_Error::movedSiteError($file); | |
530 | } | |
6a488035 TO |
531 | } |
532 | } | |
533 | } | |
534 | ||
af5201d4 TO |
535 | /** |
536 | * Restrict remote users from browsing the given directory. | |
537 | * | |
538 | * @param $publicDir | |
539 | */ | |
00be9182 | 540 | public static function restrictBrowsing($publicDir) { |
9404eeac TO |
541 | if (!is_dir($publicDir) || !is_writable($publicDir)) { |
542 | return; | |
543 | } | |
544 | ||
af5201d4 TO |
545 | // base dir |
546 | $nobrowse = realpath($publicDir) . '/index.html'; | |
547 | if (!file_exists($nobrowse)) { | |
548 | @file_put_contents($nobrowse, ''); | |
549 | } | |
550 | ||
551 | // child dirs | |
552 | $dir = new RecursiveDirectoryIterator($publicDir); | |
553 | foreach ($dir as $name => $object) { | |
554 | if (is_dir($name) && $name != '..') { | |
555 | $nobrowse = realpath($name) . '/index.html'; | |
556 | if (!file_exists($nobrowse)) { | |
557 | @file_put_contents($nobrowse, ''); | |
558 | } | |
559 | } | |
560 | } | |
561 | } | |
562 | ||
6a488035 | 563 | /** |
cc722349 TO |
564 | * (Deprecated) Create the file-path from which all other internal paths are |
565 | * computed. This implementation determines it as `dirname(CIVICRM_TEMPLATE_COMPILEDIR)`. | |
566 | * | |
567 | * This approach is problematic - e.g. it prevents one from authentically | |
568 | * splitting the CIVICRM_TEMPLATE_COMPILEDIR away from other dirs. The implementation | |
569 | * is preserved for backwards compatibility (and should only be called by | |
570 | * CMS-adapters and by Civi\Core\Paths). | |
571 | * | |
572 | * Do not use it for new path construction logic. Instead, use Civi::paths(). | |
573 | * | |
574 | * @deprecated | |
575 | * @see \Civi::paths() | |
576 | * @see \Civi\Core\Paths | |
6a488035 | 577 | */ |
635f0b86 | 578 | public static function baseFilePath() { |
6a488035 TO |
579 | static $_path = NULL; |
580 | if (!$_path) { | |
635f0b86 TO |
581 | // Note: Don't rely on $config; that creates a dependency loop. |
582 | if (!defined('CIVICRM_TEMPLATE_COMPILEDIR')) { | |
583 | throw new RuntimeException("Undefined constant: CIVICRM_TEMPLATE_COMPILEDIR"); | |
6a488035 | 584 | } |
635f0b86 | 585 | $templateCompileDir = CIVICRM_TEMPLATE_COMPILEDIR; |
6a488035 TO |
586 | |
587 | $path = dirname($templateCompileDir); | |
588 | ||
589 | //this fix is to avoid creation of upload dirs inside templates_c directory | |
590 | $checkPath = explode(DIRECTORY_SEPARATOR, $path); | |
591 | ||
592 | $cnt = count($checkPath) - 1; | |
593 | if ($checkPath[$cnt] == 'templates_c') { | |
594 | unset($checkPath[$cnt]); | |
595 | $path = implode(DIRECTORY_SEPARATOR, $checkPath); | |
596 | } | |
597 | ||
598 | $_path = CRM_Utils_File::addTrailingSlash($path); | |
599 | } | |
600 | return $_path; | |
601 | } | |
602 | ||
9f87b14b TO |
603 | /** |
604 | * Determine if a path is absolute. | |
605 | * | |
ea3ddccf | 606 | * @param string $path |
607 | * | |
9f87b14b TO |
608 | * @return bool |
609 | * TRUE if absolute. FALSE if relative. | |
610 | */ | |
611 | public static function isAbsolute($path) { | |
612 | if (substr($path, 0, 1) === DIRECTORY_SEPARATOR) { | |
613 | return TRUE; | |
614 | } | |
615 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { | |
616 | if (preg_match('!^[a-zA-Z]:[/\\\\]!', $path)) { | |
617 | return TRUE; | |
618 | } | |
619 | } | |
620 | return FALSE; | |
621 | } | |
622 | ||
5bc392e6 EM |
623 | /** |
624 | * @param $directory | |
625 | * | |
626 | * @return string | |
78b93b79 TO |
627 | * @deprecated |
628 | * Computation of a relative path requires some base. | |
629 | * This implementation is problematic because it relies on an | |
630 | * implicit base which was constructed problematically. | |
5bc392e6 | 631 | */ |
00be9182 | 632 | public static function relativeDirectory($directory) { |
6a488035 TO |
633 | // Do nothing on windows |
634 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { | |
635 | return $directory; | |
636 | } | |
637 | ||
638 | // check if directory is relative, if so return immediately | |
9f87b14b | 639 | if (!self::isAbsolute($directory)) { |
6a488035 TO |
640 | return $directory; |
641 | } | |
642 | ||
643 | // make everything relative from the baseFilePath | |
644 | $basePath = self::baseFilePath(); | |
645 | // check if basePath is a substr of $directory, if so | |
646 | // return rest of string | |
647 | if (substr($directory, 0, strlen($basePath)) == $basePath) { | |
648 | return substr($directory, strlen($basePath)); | |
649 | } | |
650 | ||
651 | // return the original value | |
652 | return $directory; | |
653 | } | |
654 | ||
5bc392e6 EM |
655 | /** |
656 | * @param $directory | |
47ec6547 | 657 | * @param string $basePath |
e3d28c74 | 658 | * The base path when evaluating relative paths. Should include trailing slash. |
5bc392e6 EM |
659 | * |
660 | * @return string | |
661 | */ | |
47ec6547 | 662 | public static function absoluteDirectory($directory, $basePath) { |
acc609a7 TO |
663 | // check if directory is already absolute, if so return immediately |
664 | // Note: Windows PHP accepts any mix of "/" or "\", so "C:\htdocs" or "C:/htdocs" would be a valid absolute path | |
665 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && preg_match(';^[a-zA-Z]:[/\\\\];', $directory)) { | |
6a488035 TO |
666 | return $directory; |
667 | } | |
668 | ||
669 | // check if directory is already absolute, if so return immediately | |
670 | if (substr($directory, 0, 1) == DIRECTORY_SEPARATOR) { | |
671 | return $directory; | |
672 | } | |
673 | ||
47ec6547 TO |
674 | if ($basePath === NULL) { |
675 | // Previous versions interpreted `NULL` to mean "default to `self::baseFilePath()`". | |
676 | // However, no code in the known `universe` relies on this interpretation, and | |
677 | // the `baseFilePath()` function is problematic/deprecated. | |
678 | throw new \RuntimeException("absoluteDirectory() requires specifying a basePath"); | |
679 | } | |
6a488035 | 680 | |
b89b9154 | 681 | // ensure that $basePath has a trailing slash |
54972caa | 682 | $basePath = self::addTrailingSlash($basePath); |
6a488035 TO |
683 | return $basePath . $directory; |
684 | } | |
685 | ||
686 | /** | |
fe482240 | 687 | * Make a file path relative to some base dir. |
6a488035 | 688 | * |
f4aaa82a EM |
689 | * @param $directory |
690 | * @param $basePath | |
691 | * | |
6a488035 TO |
692 | * @return string |
693 | */ | |
00be9182 | 694 | public static function relativize($directory, $basePath) { |
9f87b14b TO |
695 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { |
696 | $directory = strtr($directory, '\\', '/'); | |
697 | $basePath = strtr($basePath, '\\', '/'); | |
698 | } | |
6a488035 TO |
699 | if (substr($directory, 0, strlen($basePath)) == $basePath) { |
700 | return substr($directory, strlen($basePath)); | |
0db6c3e1 TO |
701 | } |
702 | else { | |
6a488035 TO |
703 | return $directory; |
704 | } | |
705 | } | |
706 | ||
707 | /** | |
fe482240 | 708 | * Create a path to a temporary file which can endure for multiple requests. |
6a488035 | 709 | * |
50bfb460 | 710 | * @todo Automatic file cleanup using, eg, TTL policy |
6a488035 | 711 | * |
5a4f6742 | 712 | * @param string $prefix |
6a488035 TO |
713 | * |
714 | * @return string, path to an openable/writable file | |
715 | * @see tempnam | |
716 | */ | |
00be9182 | 717 | public static function tempnam($prefix = 'tmp-') { |
50bfb460 SB |
718 | // $config = CRM_Core_Config::singleton(); |
719 | // $nonce = md5(uniqid() . $config->dsn . $config->userFrameworkResourceURL); | |
720 | // $fileName = "{$config->configAndLogDir}" . $prefix . $nonce . $suffix; | |
6a488035 TO |
721 | $fileName = tempnam(sys_get_temp_dir(), $prefix); |
722 | return $fileName; | |
723 | } | |
724 | ||
725 | /** | |
fe482240 | 726 | * Create a path to a temporary directory which can endure for multiple requests. |
6a488035 | 727 | * |
50bfb460 | 728 | * @todo Automatic file cleanup using, eg, TTL policy |
6a488035 | 729 | * |
5a4f6742 | 730 | * @param string $prefix |
6a488035 TO |
731 | * |
732 | * @return string, path to an openable/writable directory; ends with '/' | |
733 | * @see tempnam | |
734 | */ | |
00be9182 | 735 | public static function tempdir($prefix = 'tmp-') { |
6a488035 TO |
736 | $fileName = self::tempnam($prefix); |
737 | unlink($fileName); | |
738 | mkdir($fileName, 0700); | |
739 | return $fileName . '/'; | |
740 | } | |
741 | ||
742 | /** | |
d7166b43 TO |
743 | * Search directory tree for files which match a glob pattern. |
744 | * | |
745 | * Note: Dot-directories (like "..", ".git", or ".svn") will be ignored. | |
6a488035 | 746 | * |
5a4f6742 CW |
747 | * @param string $dir |
748 | * base dir. | |
749 | * @param string $pattern | |
750 | * glob pattern, eg "*.txt". | |
a2dc0f82 TO |
751 | * @param bool $relative |
752 | * TRUE if paths should be made relative to $dir | |
6a488035 TO |
753 | * @return array(string) |
754 | */ | |
a2dc0f82 | 755 | public static function findFiles($dir, $pattern, $relative = FALSE) { |
cae27189 | 756 | if (!is_dir($dir)) { |
be2fb01f | 757 | return []; |
cae27189 | 758 | } |
a2dc0f82 | 759 | $dir = rtrim($dir, '/'); |
be2fb01f CW |
760 | $todos = [$dir]; |
761 | $result = []; | |
6a488035 TO |
762 | while (!empty($todos)) { |
763 | $subdir = array_shift($todos); | |
0b72a00f TO |
764 | $matches = glob("$subdir/$pattern"); |
765 | if (is_array($matches)) { | |
766 | foreach ($matches as $match) { | |
002f1716 | 767 | if (!is_dir($match)) { |
a2dc0f82 | 768 | $result[] = $relative ? CRM_Utils_File::relativize($match, "$dir/") : $match; |
002f1716 | 769 | } |
6a488035 TO |
770 | } |
771 | } | |
948d11bf | 772 | if ($dh = opendir($subdir)) { |
6a488035 TO |
773 | while (FALSE !== ($entry = readdir($dh))) { |
774 | $path = $subdir . DIRECTORY_SEPARATOR . $entry; | |
d7166b43 TO |
775 | if ($entry{0} == '.') { |
776 | // ignore | |
0db6c3e1 TO |
777 | } |
778 | elseif (is_dir($path)) { | |
6a488035 TO |
779 | $todos[] = $path; |
780 | } | |
781 | } | |
782 | closedir($dh); | |
783 | } | |
784 | } | |
785 | return $result; | |
786 | } | |
787 | ||
788 | /** | |
789 | * Determine if $child is a sub-directory of $parent | |
790 | * | |
791 | * @param string $parent | |
792 | * @param string $child | |
f4aaa82a EM |
793 | * @param bool $checkRealPath |
794 | * | |
6a488035 TO |
795 | * @return bool |
796 | */ | |
00be9182 | 797 | public static function isChildPath($parent, $child, $checkRealPath = TRUE) { |
6a488035 TO |
798 | if ($checkRealPath) { |
799 | $parent = realpath($parent); | |
800 | $child = realpath($child); | |
801 | } | |
802 | $parentParts = explode('/', rtrim($parent, '/')); | |
803 | $childParts = explode('/', rtrim($child, '/')); | |
804 | while (($parentPart = array_shift($parentParts)) !== NULL) { | |
805 | $childPart = array_shift($childParts); | |
806 | if ($parentPart != $childPart) { | |
807 | return FALSE; | |
808 | } | |
809 | } | |
810 | if (empty($childParts)) { | |
6714d8d2 SL |
811 | // same directory |
812 | return FALSE; | |
0db6c3e1 TO |
813 | } |
814 | else { | |
6a488035 TO |
815 | return TRUE; |
816 | } | |
817 | } | |
818 | ||
819 | /** | |
820 | * Move $fromDir to $toDir, replacing/deleting any | |
821 | * pre-existing content. | |
822 | * | |
77855840 TO |
823 | * @param string $fromDir |
824 | * The directory which should be moved. | |
825 | * @param string $toDir | |
826 | * The new location of the directory. | |
f4aaa82a EM |
827 | * @param bool $verbose |
828 | * | |
a6c01b45 CW |
829 | * @return bool |
830 | * TRUE on success | |
6a488035 | 831 | */ |
00be9182 | 832 | public static function replaceDir($fromDir, $toDir, $verbose = FALSE) { |
6a488035 TO |
833 | if (is_dir($toDir)) { |
834 | if (!self::cleanDir($toDir, TRUE, $verbose)) { | |
835 | return FALSE; | |
836 | } | |
837 | } | |
838 | ||
50bfb460 | 839 | // return rename($fromDir, $toDir); CRM-11987, https://bugs.php.net/bug.php?id=54097 |
6a488035 TO |
840 | |
841 | CRM_Utils_File::copyDir($fromDir, $toDir); | |
842 | if (!CRM_Utils_File::cleanDir($fromDir, TRUE, FALSE)) { | |
be2fb01f | 843 | CRM_Core_Session::setStatus(ts('Failed to clean temp dir: %1', [1 => $fromDir]), '', 'alert'); |
6a488035 TO |
844 | return FALSE; |
845 | } | |
846 | return TRUE; | |
847 | } | |
96025800 | 848 | |
8246bca4 | 849 | /** |
850 | * Format file. | |
851 | * | |
852 | * @param array $param | |
853 | * @param string $fileName | |
854 | * @param array $extraParams | |
855 | */ | |
be2fb01f | 856 | public static function formatFile(&$param, $fileName, $extraParams = []) { |
90a73810 | 857 | if (empty($param[$fileName])) { |
858 | return; | |
859 | } | |
860 | ||
be2fb01f | 861 | $fileParams = [ |
90a73810 | 862 | 'uri' => $param[$fileName]['name'], |
863 | 'type' => $param[$fileName]['type'], | |
864 | 'location' => $param[$fileName]['name'], | |
865 | 'upload_date' => date('YmdHis'), | |
be2fb01f | 866 | ] + $extraParams; |
90a73810 | 867 | |
868 | $param[$fileName] = $fileParams; | |
869 | } | |
870 | ||
f3726153 | 871 | /** |
872 | * Return formatted file URL, like for image file return image url with image icon | |
873 | * | |
874 | * @param string $path | |
875 | * Absoulte file path | |
876 | * @param string $fileType | |
877 | * @param string $url | |
878 | * File preview link e.g. https://example.com/civicrm/file?reset=1&filename=image.png&mime-type=image/png | |
879 | * | |
880 | * @return string $url | |
881 | */ | |
882 | public static function getFileURL($path, $fileType, $url = NULL) { | |
883 | if (empty($path) || empty($fileType)) { | |
884 | return ''; | |
885 | } | |
886 | elseif (empty($url)) { | |
887 | $fileName = basename($path); | |
888 | $url = CRM_Utils_System::url('civicrm/file', "reset=1&filename={$fileName}&mime-type={$fileType}"); | |
889 | } | |
890 | switch ($fileType) { | |
891 | case 'image/jpeg': | |
892 | case 'image/pjpeg': | |
893 | case 'image/gif': | |
894 | case 'image/x-png': | |
895 | case 'image/png': | |
c3821398 | 896 | case 'image/jpg': |
f3726153 | 897 | list($imageWidth, $imageHeight) = getimagesize($path); |
898 | list($imageThumbWidth, $imageThumbHeight) = CRM_Contact_BAO_Contact::getThumbSize($imageWidth, $imageHeight); | |
899 | $url = "<a href=\"$url\" class='crm-image-popup'> | |
900 | <img src=\"$url\" width=$imageThumbWidth height=$imageThumbHeight/> | |
901 | </a>"; | |
902 | break; | |
903 | ||
904 | default: | |
17ae6ca4 | 905 | $url = sprintf('<a href="%s">%s</a>', $url, self::cleanFileName(basename($path))); |
f3726153 | 906 | break; |
907 | } | |
908 | ||
909 | return $url; | |
910 | } | |
911 | ||
c3821398 | 912 | /** |
913 | * Return formatted image icon | |
914 | * | |
915 | * @param string $imageURL | |
916 | * Contact's image url | |
917 | * | |
918 | * @return string $url | |
919 | */ | |
920 | public static function getImageURL($imageURL) { | |
921 | // retrieve image name from $imageURL | |
922 | $imageURL = CRM_Utils_String::unstupifyUrl($imageURL); | |
923 | parse_str(parse_url($imageURL, PHP_URL_QUERY), $query); | |
924 | ||
cb8fb3cf JP |
925 | $url = NULL; |
926 | if (!empty($query['photo'])) { | |
927 | $path = CRM_Core_Config::singleton()->customFileUploadDir . $query['photo']; | |
928 | } | |
929 | else { | |
930 | $path = $url = $imageURL; | |
931 | } | |
878a913b | 932 | $fileExtension = strtolower(pathinfo($path, PATHINFO_EXTENSION)); |
8ece24f4 PN |
933 | //According to (https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types), |
934 | // there are some extensions that would need translating.: | |
935 | $translateMimeTypes = [ | |
936 | 'tif' => 'tiff', | |
937 | 'jpg' => 'jpeg', | |
938 | 'svg' => 'svg+xml', | |
939 | ]; | |
940 | $mimeType = 'image/' . CRM_Utils_Array::value( | |
941 | $fileExtension, | |
942 | $translateMimeTypes, | |
943 | $fileExtension | |
944 | ); | |
c3821398 | 945 | |
cb8fb3cf | 946 | return self::getFileURL($path, $mimeType, $url); |
c3821398 | 947 | } |
948 | ||
3cd6a7b6 | 949 | /** |
62b3b6e7 SM |
950 | * Resize an image. |
951 | * | |
952 | * @param string $sourceFile | |
953 | * Filesystem path to existing image on server | |
954 | * @param int $targetWidth | |
955 | * New width desired, in pixels | |
956 | * @param int $targetHeight | |
957 | * New height desired, in pixels | |
958 | * @param string $suffix = "" | |
959 | * If supplied, the image will be renamed to include this suffix. For | |
960 | * example if the original file name is "foo.png" and $suffix = "_bar", | |
961 | * then the final file name will be "foo_bar.png". | |
ae969bc1 SM |
962 | * @param bool $preserveAspect = TRUE |
963 | * When TRUE $width and $height will be used as a bounding box, outside of | |
964 | * which the resized image will not extend. | |
965 | * When FALSE, the image will be resized exactly to $width and $height, even | |
966 | * if it means stretching it. | |
3cd6a7b6 SM |
967 | * |
968 | * @return string | |
969 | * Path to image | |
62b3b6e7 SM |
970 | * @throws \CRM_Core_Exception |
971 | * Under the following conditions | |
972 | * - When GD is not available. | |
973 | * - When the source file is not an image. | |
3cd6a7b6 | 974 | */ |
ae969bc1 | 975 | public static function resizeImage($sourceFile, $targetWidth, $targetHeight, $suffix = "", $preserveAspect = TRUE) { |
3cd6a7b6 | 976 | |
62b3b6e7 SM |
977 | // Check if GD is installed |
978 | $gdSupport = CRM_Utils_System::getModuleSetting('gd', 'GD Support'); | |
979 | if (!$gdSupport) { | |
980 | throw new CRM_Core_Exception(ts('Unable to resize image because the GD image library is not currently compiled in your PHP installation.')); | |
981 | } | |
982 | ||
983 | $sourceMime = mime_content_type($sourceFile); | |
984 | if ($sourceMime == 'image/gif') { | |
985 | $sourceData = imagecreatefromgif($sourceFile); | |
986 | } | |
987 | elseif ($sourceMime == 'image/png') { | |
988 | $sourceData = imagecreatefrompng($sourceFile); | |
3cd6a7b6 | 989 | } |
62b3b6e7 SM |
990 | elseif ($sourceMime == 'image/jpeg') { |
991 | $sourceData = imagecreatefromjpeg($sourceFile); | |
3cd6a7b6 SM |
992 | } |
993 | else { | |
62b3b6e7 | 994 | throw new CRM_Core_Exception(ts('Unable to resize image because the file supplied was not an image.')); |
3cd6a7b6 SM |
995 | } |
996 | ||
62b3b6e7 SM |
997 | // get image about original image |
998 | $sourceInfo = getimagesize($sourceFile); | |
999 | $sourceWidth = $sourceInfo[0]; | |
1000 | $sourceHeight = $sourceInfo[1]; | |
1001 | ||
ae969bc1 SM |
1002 | // Adjust target width/height if preserving aspect ratio |
1003 | if ($preserveAspect) { | |
1004 | $sourceAspect = $sourceWidth / $sourceHeight; | |
1005 | $targetAspect = $targetWidth / $targetHeight; | |
1006 | if ($sourceAspect > $targetAspect) { | |
1007 | $targetHeight = $targetWidth / $sourceAspect; | |
1008 | } | |
1009 | if ($sourceAspect < $targetAspect) { | |
1010 | $targetWidth = $targetHeight * $sourceAspect; | |
1011 | } | |
1012 | } | |
1013 | ||
62b3b6e7 SM |
1014 | // figure out the new filename |
1015 | $pathParts = pathinfo($sourceFile); | |
1016 | $targetFile = $pathParts['dirname'] . DIRECTORY_SEPARATOR | |
1017 | . $pathParts['filename'] . $suffix . "." . $pathParts['extension']; | |
1018 | ||
1019 | $targetData = imagecreatetruecolor($targetWidth, $targetHeight); | |
1020 | ||
3cd6a7b6 | 1021 | // resize |
62b3b6e7 SM |
1022 | imagecopyresized($targetData, $sourceData, |
1023 | 0, 0, 0, 0, | |
1024 | $targetWidth, $targetHeight, $sourceWidth, $sourceHeight); | |
3cd6a7b6 SM |
1025 | |
1026 | // save the resized image | |
62b3b6e7 | 1027 | $fp = fopen($targetFile, 'w+'); |
3cd6a7b6 | 1028 | ob_start(); |
62b3b6e7 | 1029 | imagejpeg($targetData); |
3cd6a7b6 SM |
1030 | $image_buffer = ob_get_contents(); |
1031 | ob_end_clean(); | |
62b3b6e7 | 1032 | imagedestroy($targetData); |
3cd6a7b6 SM |
1033 | fwrite($fp, $image_buffer); |
1034 | rewind($fp); | |
1035 | fclose($fp); | |
1036 | ||
1037 | // return the URL to link to | |
1038 | $config = CRM_Core_Config::singleton(); | |
62b3b6e7 | 1039 | return $config->imageUploadURL . basename($targetFile); |
3cd6a7b6 | 1040 | } |
4994819e CW |
1041 | |
1042 | /** | |
1043 | * Get file icon class for specific MIME Type | |
1044 | * | |
1045 | * @param string $mimeType | |
1046 | * @return string | |
1047 | */ | |
1048 | public static function getIconFromMimeType($mimeType) { | |
892be376 CW |
1049 | if (!isset(Civi::$statics[__CLASS__]['mimeIcons'])) { |
1050 | Civi::$statics[__CLASS__]['mimeIcons'] = json_decode(file_get_contents(__DIR__ . '/File/mimeIcons.json'), TRUE); | |
1051 | } | |
1052 | $iconClasses = Civi::$statics[__CLASS__]['mimeIcons']; | |
4994819e CW |
1053 | foreach ($iconClasses as $text => $icon) { |
1054 | if (strpos($mimeType, $text) === 0) { | |
1055 | return $icon; | |
1056 | } | |
1057 | } | |
892be376 | 1058 | return $iconClasses['*']; |
4994819e CW |
1059 | } |
1060 | ||
a7762e79 SL |
1061 | /** |
1062 | * Is the filename a safe and valid filename passed in from URL | |
1063 | * | |
1064 | * @param string $fileName | |
1065 | * @return bool | |
1066 | */ | |
1067 | public static function isValidFileName($fileName = NULL) { | |
1068 | if ($fileName) { | |
91768280 | 1069 | $check = ($fileName === basename($fileName)); |
a7762e79 SL |
1070 | if ($check) { |
1071 | if (substr($fileName, 0, 1) == '/' || substr($fileName, 0, 1) == '.' || substr($fileName, 0, 1) == DIRECTORY_SEPARATOR) { | |
1072 | $check = FALSE; | |
1073 | } | |
1074 | } | |
1075 | return $check; | |
1076 | } | |
1077 | return FALSE; | |
1078 | } | |
1079 | ||
2d20f3a9 | 1080 | /** |
6cb3fe2e SL |
1081 | * Get the extensions that this MimeTpe is for |
1082 | * @param string $mimeType the mime-type we want extensions for | |
1083 | * @return array | |
1084 | */ | |
1085 | public static function getAcceptableExtensionsForMimeType($mimeType = NULL) { | |
108332db SL |
1086 | $mimeRepostory = new \MimeTyper\Repository\ExtendedRepository(); |
1087 | return $mimeRepostory->findExtensions($mimeType); | |
6cb3fe2e SL |
1088 | } |
1089 | ||
1090 | /** | |
1091 | * Get the extension of a file based on its path | |
1092 | * @param string $path path of the file to query | |
1093 | * @return string | |
2d20f3a9 | 1094 | */ |
6cb3fe2e SL |
1095 | public static function getExtensionFromPath($path) { |
1096 | return pathinfo($path, PATHINFO_EXTENSION); | |
2d20f3a9 SL |
1097 | } |
1098 | ||
6a488035 | 1099 | } |