Fixing text to make it more clear that the user has an account but is not registered...
[civicrm-core.git] / CRM / Utils / File.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
e7112fa7 6 | Copyright CiviCRM LLC (c) 2004-2015 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
e7112fa7 31 * @copyright CiviCRM LLC (c) 2004-2015
6a488035
TO
32 * $Id: $
33 *
34 */
35
36/**
37 * class to provide simple static functions for file objects
38 */
39class CRM_Utils_File {
40
41 /**
42 * Given a file name, determine if the file contents make it an ascii file
43 *
77855840
TO
44 * @param string $name
45 * Name of file.
6a488035 46 *
ae5ffbb7 47 * @return bool
a6c01b45 48 * true if file is ascii
6a488035 49 */
00be9182 50 public static function isAscii($name) {
6a488035
TO
51 $fd = fopen($name, "r");
52 if (!$fd) {
53 return FALSE;
54 }
55
56 $ascii = TRUE;
57 while (!feof($fd)) {
58 $line = fgets($fd, 8192);
59 if (!CRM_Utils_String::isAscii($line)) {
60 $ascii = FALSE;
61 break;
62 }
63 }
64
65 fclose($fd);
66 return $ascii;
67 }
68
69 /**
70 * Given a file name, determine if the file contents make it an html file
71 *
77855840
TO
72 * @param string $name
73 * Name of file.
6a488035 74 *
ae5ffbb7 75 * @return bool
a6c01b45 76 * true if file is html
6a488035 77 */
00be9182 78 public static function isHtml($name) {
6a488035
TO
79 $fd = fopen($name, "r");
80 if (!$fd) {
81 return FALSE;
82 }
83
84 $html = FALSE;
85 $lineCount = 0;
86 while (!feof($fd) & $lineCount <= 5) {
87 $lineCount++;
88 $line = fgets($fd, 8192);
89 if (!CRM_Utils_String::isHtml($line)) {
90 $html = TRUE;
91 break;
92 }
93 }
94
95 fclose($fd);
96 return $html;
97 }
98
99 /**
100fef9d 100 * Create a directory given a path name, creates parent directories
6a488035
TO
101 * if needed
102 *
77855840
TO
103 * @param string $path
104 * The path name.
105 * @param bool $abort
106 * Should we abort or just return an invalid code.
6a488035
TO
107 *
108 * @return void
6a488035 109 */
00be9182 110 public static function createDir($path, $abort = TRUE) {
6a488035
TO
111 if (is_dir($path) || empty($path)) {
112 return;
113 }
114
115 CRM_Utils_File::createDir(dirname($path), $abort);
116 if (@mkdir($path, 0777) == FALSE) {
117 if ($abort) {
118 $docLink = CRM_Utils_System::docURL2('Moving an Existing Installation to a New Server or Location', NULL, NULL, NULL, NULL, "wiki");
119 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>";
120
121 CRM_Utils_System::civiExit();
122 }
123 else {
124 return FALSE;
125 }
126 }
127 return TRUE;
128 }
129
130 /**
100fef9d 131 * Delete a directory given a path name, delete children directories
6a488035
TO
132 * and files if needed
133 *
77855840
TO
134 * @param string $target
135 * The path name.
f4aaa82a
EM
136 * @param bool $rmdir
137 * @param bool $verbose
138 *
139 * @throws Exception
6a488035 140 * @return void
6a488035 141 */
00be9182 142 public static function cleanDir($target, $rmdir = TRUE, $verbose = TRUE) {
6a488035
TO
143 static $exceptions = array('.', '..');
144 if ($target == '' || $target == '/') {
145 throw new Exception("Overly broad deletion");
146 }
147
5e7670b1 148 if ($dh = @opendir($target)) {
149 while (FALSE !== ($sibling = readdir($dh))) {
6a488035
TO
150 if (!in_array($sibling, $exceptions)) {
151 $object = $target . DIRECTORY_SEPARATOR . $sibling;
152
153 if (is_dir($object)) {
154 CRM_Utils_File::cleanDir($object, $rmdir, $verbose);
155 }
156 elseif (is_file($object)) {
157 if (!unlink($object)) {
158 CRM_Core_Session::setStatus(ts('Unable to remove file %1', array(1 => $object)), ts('Warning'), 'error');
e7292422 159 }
6a488035
TO
160 }
161 }
162 }
5e7670b1 163 closedir($dh);
6a488035
TO
164
165 if ($rmdir) {
166 if (rmdir($target)) {
167 if ($verbose) {
450f494d 168 CRM_Core_Session::setStatus(ts('Removed directory %1', array(1 => $target)), '', 'success');
6a488035
TO
169 }
170 return TRUE;
e7292422 171 }
6a488035
TO
172 else {
173 CRM_Core_Session::setStatus(ts('Unable to remove directory %1', array(1 => $target)), ts('Warning'), 'error');
e7292422
TO
174 }
175 }
6a488035
TO
176 }
177 }
178
7f616c07
TO
179 /**
180 * Concatenate several files.
181 *
182 * @param array $files
183 * List of file names.
184 * @param string $delim
185 * An optional delimiter to put between files.
186 * @return string
187 */
188 public static function concat($files, $delim = '') {
189 $buf = '';
190 $first = TRUE;
191 foreach ($files as $file) {
192 if (!$first) {
193 $buf .= $delim;
194 }
195 $buf .= file_get_contents($file);
196 $first = FALSE;
197 }
198 return $buf;
199 }
200
5bc392e6 201 /**
ae5ffbb7
TO
202 * @param string $source
203 * @param string $destination
5bc392e6 204 */
ae5ffbb7 205 public static function copyDir($source, $destination) {
5e7670b1 206 if ($dh = opendir($source)) {
948d11bf 207 @mkdir($destination);
5e7670b1 208 while (FALSE !== ($file = readdir($dh))) {
948d11bf
CB
209 if (($file != '.') && ($file != '..')) {
210 if (is_dir($source . DIRECTORY_SEPARATOR . $file)) {
211 CRM_Utils_File::copyDir($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file);
212 }
213 else {
214 copy($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file);
215 }
6a488035
TO
216 }
217 }
5e7670b1 218 closedir($dh);
6a488035 219 }
6a488035
TO
220 }
221
222 /**
223 * Given a file name, recode it (in place!) to UTF-8
224 *
77855840
TO
225 * @param string $name
226 * Name of file.
6a488035 227 *
ae5ffbb7 228 * @return bool
a6c01b45 229 * whether the file was recoded properly
6a488035 230 */
00be9182 231 public static function toUtf8($name) {
6a488035
TO
232 static $config = NULL;
233 static $legacyEncoding = NULL;
234 if ($config == NULL) {
235 $config = CRM_Core_Config::singleton();
236 $legacyEncoding = $config->legacyEncoding;
237 }
238
239 if (!function_exists('iconv')) {
240
241 return FALSE;
242
243 }
244
245 $contents = file_get_contents($name);
246 if ($contents === FALSE) {
247 return FALSE;
248 }
249
250 $contents = iconv($legacyEncoding, 'UTF-8', $contents);
251 if ($contents === FALSE) {
252 return FALSE;
253 }
254
255 $file = fopen($name, 'w');
256 if ($file === FALSE) {
257 return FALSE;
258 }
259
260 $written = fwrite($file, $contents);
261 $closed = fclose($file);
262 if ($written === FALSE or !$closed) {
263 return FALSE;
264 }
265
266 return TRUE;
267 }
268
269 /**
5c8cb77f 270 * Appends a slash to the end of a string if it doesn't already end with one
6a488035 271 *
5c8cb77f
CW
272 * @param string $path
273 * @param string $slash
f4aaa82a 274 *
6a488035 275 * @return string
6a488035 276 */
00be9182 277 public static function addTrailingSlash($path, $slash = NULL) {
5c8cb77f
CW
278 if (!$slash) {
279 // FIXME: Defaulting to backslash on windows systems can produce unexpected results, esp for URL strings which should always use forward-slashes.
280 // I think this fn should default to forward-slash instead.
281 $slash = DIRECTORY_SEPARATOR;
6a488035 282 }
5c8cb77f
CW
283 if (!in_array(substr($path, -1, 1), array('/', '\\'))) {
284 $path .= $slash;
6a488035 285 }
5c8cb77f 286 return $path;
6a488035
TO
287 }
288
5bc392e6
EM
289 /**
290 * @param $dsn
100fef9d 291 * @param string $fileName
5bc392e6
EM
292 * @param null $prefix
293 * @param bool $isQueryString
294 * @param bool $dieOnErrors
295 */
00be9182 296 public static function sourceSQLFile($dsn, $fileName, $prefix = NULL, $isQueryString = FALSE, $dieOnErrors = TRUE) {
6a488035
TO
297 require_once 'DB.php';
298
299 $db = DB::connect($dsn);
300 if (PEAR::isError($db)) {
301 die("Cannot open $dsn: " . $db->getMessage());
302 }
303 if (CRM_Utils_Constant::value('CIVICRM_MYSQL_STRICT', CRM_Utils_System::isDevelopment())) {
304 $db->query('SET SESSION sql_mode = STRICT_TRANS_TABLES');
305 }
306
307 if (!$isQueryString) {
308 $string = $prefix . file_get_contents($fileName);
309 }
310 else {
311 // use filename as query string
312 $string = $prefix . $fileName;
313 }
314
315 //get rid of comments starting with # and --
316
317 $string = preg_replace("/^#[^\n]*$/m", "\n", $string);
318 $string = preg_replace("/^(--[^-]).*/m", "\n", $string);
319
320 $queries = preg_split('/;\s*$/m', $string);
321 foreach ($queries as $query) {
322 $query = trim($query);
323 if (!empty($query)) {
324 CRM_Core_Error::debug_query($query);
325 $res = &$db->query($query);
326 if (PEAR::isError($res)) {
327 if ($dieOnErrors) {
328 die("Cannot execute $query: " . $res->getMessage());
329 }
330 else {
331 echo "Cannot execute $query: " . $res->getMessage() . "<p>";
332 }
333 }
334 }
335 }
336 }
337
5bc392e6
EM
338 /**
339 * @param $ext
340 *
341 * @return bool
342 */
00be9182 343 public static function isExtensionSafe($ext) {
6a488035
TO
344 static $extensions = NULL;
345 if (!$extensions) {
346 $extensions = CRM_Core_OptionGroup::values('safe_file_extension', TRUE);
347
348 //make extensions to lowercase
349 $extensions = array_change_key_case($extensions, CASE_LOWER);
350 // allow html/htm extension ONLY if the user is admin
351 // and/or has access CiviMail
352 if (!(CRM_Core_Permission::check('access CiviMail') ||
353ffa53
TO
353 CRM_Core_Permission::check('administer CiviCRM') ||
354 (CRM_Mailing_Info::workflowEnabled() &&
355 CRM_Core_Permission::check('create mailings')
356 )
357 )
358 ) {
6a488035
TO
359 unset($extensions['html']);
360 unset($extensions['htm']);
361 }
362 }
363 //support lower and uppercase file extensions
364 return isset($extensions[strtolower($ext)]) ? TRUE : FALSE;
365 }
366
367 /**
fe482240 368 * Determine whether a given file is listed in the PHP include path.
6a488035 369 *
77855840
TO
370 * @param string $name
371 * Name of file.
6a488035 372 *
ae5ffbb7 373 * @return bool
a6c01b45 374 * whether the file can be include()d or require()d
6a488035 375 */
00be9182 376 public static function isIncludable($name) {
6a488035
TO
377 $x = @fopen($name, 'r', TRUE);
378 if ($x) {
379 fclose($x);
380 return TRUE;
381 }
382 else {
383 return FALSE;
384 }
385 }
386
387 /**
100fef9d 388 * Remove the 32 bit md5 we add to the fileName
6a488035
TO
389 * also remove the unknown tag if we added it
390 */
00be9182 391 public static function cleanFileName($name) {
6a488035
TO
392 // replace the last 33 character before the '.' with null
393 $name = preg_replace('/(_[\w]{32})\./', '.', $name);
394 return $name;
395 }
396
5bc392e6 397 /**
100fef9d 398 * @param string $name
5bc392e6
EM
399 *
400 * @return string
401 */
00be9182 402 public static function makeFileName($name) {
353ffa53
TO
403 $uniqID = md5(uniqid(rand(), TRUE));
404 $info = pathinfo($name);
6a488035
TO
405 $basename = substr($info['basename'],
406 0, -(strlen(CRM_Utils_Array::value('extension', $info)) + (CRM_Utils_Array::value('extension', $info) == '' ? 0 : 1))
407 );
408 if (!self::isExtensionSafe(CRM_Utils_Array::value('extension', $info))) {
409 // munge extension so it cannot have an embbeded dot in it
410 // The maximum length of a filename for most filesystems is 255 chars.
411 // We'll truncate at 240 to give some room for the extension.
412 return CRM_Utils_String::munge("{$basename}_" . CRM_Utils_Array::value('extension', $info) . "_{$uniqID}", '_', 240) . ".unknown";
413 }
414 else {
415 return CRM_Utils_String::munge("{$basename}_{$uniqID}", '_', 240) . "." . CRM_Utils_Array::value('extension', $info);
416 }
417 }
418
5bc392e6
EM
419 /**
420 * @param $path
421 * @param $ext
422 *
423 * @return array
424 */
00be9182 425 public static function getFilesByExtension($path, $ext) {
353ffa53 426 $path = self::addTrailingSlash($path);
6a488035 427 $files = array();
948d11bf 428 if ($dh = opendir($path)) {
948d11bf
CB
429 while (FALSE !== ($elem = readdir($dh))) {
430 if (substr($elem, -(strlen($ext) + 1)) == '.' . $ext) {
431 $files[] .= $path . $elem;
432 }
6a488035 433 }
948d11bf 434 closedir($dh);
6a488035 435 }
6a488035
TO
436 return $files;
437 }
438
439 /**
440 * Restrict access to a given directory (by planting there a restrictive .htaccess file)
441 *
77855840
TO
442 * @param string $dir
443 * The directory to be secured.
f4aaa82a 444 * @param bool $overwrite
6a488035 445 */
00be9182 446 public static function restrictAccess($dir, $overwrite = FALSE) {
6a488035
TO
447 // note: empty value for $dir can play havoc, since that might result in putting '.htaccess' to root dir
448 // of site, causing site to stop functioning.
449 // FIXME: we should do more checks here -
ea3b22b5 450 if (!empty($dir) && is_dir($dir)) {
6a488035
TO
451 $htaccess = <<<HTACCESS
452<Files "*">
453 Order allow,deny
454 Deny from all
455</Files>
456
457HTACCESS;
458 $file = $dir . '.htaccess';
ea3b22b5
TO
459 if ($overwrite || !file_exists($file)) {
460 if (file_put_contents($file, $htaccess) === FALSE) {
461 CRM_Core_Error::movedSiteError($file);
462 }
6a488035
TO
463 }
464 }
465 }
466
af5201d4
TO
467 /**
468 * Restrict remote users from browsing the given directory.
469 *
470 * @param $publicDir
471 */
00be9182 472 public static function restrictBrowsing($publicDir) {
9404eeac
TO
473 if (!is_dir($publicDir) || !is_writable($publicDir)) {
474 return;
475 }
476
af5201d4
TO
477 // base dir
478 $nobrowse = realpath($publicDir) . '/index.html';
479 if (!file_exists($nobrowse)) {
480 @file_put_contents($nobrowse, '');
481 }
482
483 // child dirs
484 $dir = new RecursiveDirectoryIterator($publicDir);
485 foreach ($dir as $name => $object) {
486 if (is_dir($name) && $name != '..') {
487 $nobrowse = realpath($name) . '/index.html';
488 if (!file_exists($nobrowse)) {
489 @file_put_contents($nobrowse, '');
490 }
491 }
492 }
493 }
494
6a488035
TO
495 /**
496 * Create the base file path from which all our internal directories are
497 * offset. This is derived from the template compile directory set
498 */
635f0b86 499 public static function baseFilePath() {
6a488035
TO
500 static $_path = NULL;
501 if (!$_path) {
635f0b86
TO
502 // Note: Don't rely on $config; that creates a dependency loop.
503 if (!defined('CIVICRM_TEMPLATE_COMPILEDIR')) {
504 throw new RuntimeException("Undefined constant: CIVICRM_TEMPLATE_COMPILEDIR");
6a488035 505 }
635f0b86 506 $templateCompileDir = CIVICRM_TEMPLATE_COMPILEDIR;
6a488035
TO
507
508 $path = dirname($templateCompileDir);
509
510 //this fix is to avoid creation of upload dirs inside templates_c directory
511 $checkPath = explode(DIRECTORY_SEPARATOR, $path);
512
513 $cnt = count($checkPath) - 1;
514 if ($checkPath[$cnt] == 'templates_c') {
515 unset($checkPath[$cnt]);
516 $path = implode(DIRECTORY_SEPARATOR, $checkPath);
517 }
518
519 $_path = CRM_Utils_File::addTrailingSlash($path);
520 }
521 return $_path;
522 }
523
9f87b14b
TO
524 /**
525 * Determine if a path is absolute.
526 *
527 * @return bool
528 * TRUE if absolute. FALSE if relative.
529 */
530 public static function isAbsolute($path) {
531 if (substr($path, 0, 1) === DIRECTORY_SEPARATOR) {
532 return TRUE;
533 }
534 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
535 if (preg_match('!^[a-zA-Z]:[/\\\\]!', $path)) {
536 return TRUE;
537 }
538 }
539 return FALSE;
540 }
541
5bc392e6
EM
542 /**
543 * @param $directory
544 *
545 * @return string
546 */
00be9182 547 public static function relativeDirectory($directory) {
6a488035
TO
548 // Do nothing on windows
549 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
550 return $directory;
551 }
552
553 // check if directory is relative, if so return immediately
9f87b14b 554 if (!self::isAbsolute($directory)) {
6a488035
TO
555 return $directory;
556 }
557
558 // make everything relative from the baseFilePath
559 $basePath = self::baseFilePath();
560 // check if basePath is a substr of $directory, if so
561 // return rest of string
562 if (substr($directory, 0, strlen($basePath)) == $basePath) {
563 return substr($directory, strlen($basePath));
564 }
565
566 // return the original value
567 return $directory;
568 }
569
5bc392e6
EM
570 /**
571 * @param $directory
e3d28c74
TO
572 * @param string|NULL $basePath
573 * The base path when evaluating relative paths. Should include trailing slash.
5bc392e6
EM
574 *
575 * @return string
576 */
e3d28c74 577 public static function absoluteDirectory($directory, $basePath = NULL) {
acc609a7
TO
578 // check if directory is already absolute, if so return immediately
579 // Note: Windows PHP accepts any mix of "/" or "\", so "C:\htdocs" or "C:/htdocs" would be a valid absolute path
580 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && preg_match(';^[a-zA-Z]:[/\\\\];', $directory)) {
6a488035
TO
581 return $directory;
582 }
583
584 // check if directory is already absolute, if so return immediately
585 if (substr($directory, 0, 1) == DIRECTORY_SEPARATOR) {
586 return $directory;
587 }
588
589 // make everything absolute from the baseFilePath
e3d28c74 590 $basePath = ($basePath === NULL) ? self::baseFilePath() : $basePath;
6a488035
TO
591
592 return $basePath . $directory;
593 }
594
595 /**
fe482240 596 * Make a file path relative to some base dir.
6a488035 597 *
f4aaa82a
EM
598 * @param $directory
599 * @param $basePath
600 *
6a488035
TO
601 * @return string
602 */
00be9182 603 public static function relativize($directory, $basePath) {
9f87b14b
TO
604 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
605 $directory = strtr($directory, '\\', '/');
606 $basePath = strtr($basePath, '\\', '/');
607 }
6a488035
TO
608 if (substr($directory, 0, strlen($basePath)) == $basePath) {
609 return substr($directory, strlen($basePath));
0db6c3e1
TO
610 }
611 else {
6a488035
TO
612 return $directory;
613 }
614 }
615
616 /**
fe482240 617 * Create a path to a temporary file which can endure for multiple requests.
6a488035
TO
618 *
619 * TODO: Automatic file cleanup using, eg, TTL policy
620 *
5a4f6742 621 * @param string $prefix
6a488035
TO
622 *
623 * @return string, path to an openable/writable file
624 * @see tempnam
625 */
00be9182 626 public static function tempnam($prefix = 'tmp-') {
6a488035
TO
627 //$config = CRM_Core_Config::singleton();
628 //$nonce = md5(uniqid() . $config->dsn . $config->userFrameworkResourceURL);
629 //$fileName = "{$config->configAndLogDir}" . $prefix . $nonce . $suffix;
630 $fileName = tempnam(sys_get_temp_dir(), $prefix);
631 return $fileName;
632 }
633
634 /**
fe482240 635 * Create a path to a temporary directory which can endure for multiple requests.
6a488035
TO
636 *
637 * TODO: Automatic file cleanup using, eg, TTL policy
638 *
5a4f6742 639 * @param string $prefix
6a488035
TO
640 *
641 * @return string, path to an openable/writable directory; ends with '/'
642 * @see tempnam
643 */
00be9182 644 public static function tempdir($prefix = 'tmp-') {
6a488035
TO
645 $fileName = self::tempnam($prefix);
646 unlink($fileName);
647 mkdir($fileName, 0700);
648 return $fileName . '/';
649 }
650
651 /**
d7166b43
TO
652 * Search directory tree for files which match a glob pattern.
653 *
654 * Note: Dot-directories (like "..", ".git", or ".svn") will be ignored.
6a488035 655 *
5a4f6742
CW
656 * @param string $dir
657 * base dir.
658 * @param string $pattern
659 * glob pattern, eg "*.txt".
a2dc0f82
TO
660 * @param bool $relative
661 * TRUE if paths should be made relative to $dir
6a488035
TO
662 * @return array(string)
663 */
a2dc0f82
TO
664 public static function findFiles($dir, $pattern, $relative = FALSE) {
665 $dir = rtrim($dir, '/');
6a488035
TO
666 $todos = array($dir);
667 $result = array();
668 while (!empty($todos)) {
669 $subdir = array_shift($todos);
0b72a00f
TO
670 $matches = glob("$subdir/$pattern");
671 if (is_array($matches)) {
672 foreach ($matches as $match) {
002f1716 673 if (!is_dir($match)) {
a2dc0f82 674 $result[] = $relative ? CRM_Utils_File::relativize($match, "$dir/") : $match;
002f1716 675 }
6a488035
TO
676 }
677 }
948d11bf 678 if ($dh = opendir($subdir)) {
6a488035
TO
679 while (FALSE !== ($entry = readdir($dh))) {
680 $path = $subdir . DIRECTORY_SEPARATOR . $entry;
d7166b43
TO
681 if ($entry{0} == '.') {
682 // ignore
0db6c3e1
TO
683 }
684 elseif (is_dir($path)) {
6a488035
TO
685 $todos[] = $path;
686 }
687 }
688 closedir($dh);
689 }
690 }
691 return $result;
692 }
693
694 /**
695 * Determine if $child is a sub-directory of $parent
696 *
697 * @param string $parent
698 * @param string $child
f4aaa82a
EM
699 * @param bool $checkRealPath
700 *
6a488035
TO
701 * @return bool
702 */
00be9182 703 public static function isChildPath($parent, $child, $checkRealPath = TRUE) {
6a488035
TO
704 if ($checkRealPath) {
705 $parent = realpath($parent);
706 $child = realpath($child);
707 }
708 $parentParts = explode('/', rtrim($parent, '/'));
709 $childParts = explode('/', rtrim($child, '/'));
710 while (($parentPart = array_shift($parentParts)) !== NULL) {
711 $childPart = array_shift($childParts);
712 if ($parentPart != $childPart) {
713 return FALSE;
714 }
715 }
716 if (empty($childParts)) {
717 return FALSE; // same directory
0db6c3e1
TO
718 }
719 else {
6a488035
TO
720 return TRUE;
721 }
722 }
723
724 /**
725 * Move $fromDir to $toDir, replacing/deleting any
726 * pre-existing content.
727 *
77855840
TO
728 * @param string $fromDir
729 * The directory which should be moved.
730 * @param string $toDir
731 * The new location of the directory.
f4aaa82a
EM
732 * @param bool $verbose
733 *
a6c01b45
CW
734 * @return bool
735 * TRUE on success
6a488035 736 */
00be9182 737 public static function replaceDir($fromDir, $toDir, $verbose = FALSE) {
6a488035
TO
738 if (is_dir($toDir)) {
739 if (!self::cleanDir($toDir, TRUE, $verbose)) {
740 return FALSE;
741 }
742 }
743
744 // return rename($fromDir, $toDir); // CRM-11987, https://bugs.php.net/bug.php?id=54097
745
746 CRM_Utils_File::copyDir($fromDir, $toDir);
747 if (!CRM_Utils_File::cleanDir($fromDir, TRUE, FALSE)) {
e7292422 748 CRM_Core_Session::setStatus(ts('Failed to clean temp dir: %1', array(1 => $fromDir)), '', 'alert');
6a488035
TO
749 return FALSE;
750 }
751 return TRUE;
752 }
96025800 753
6a488035 754}