CRM-17253 omit expensive unused information from token query
[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 */
00be9182 499 public static function baseFilePath($templateCompileDir = NULL) {
6a488035
TO
500 static $_path = NULL;
501 if (!$_path) {
502 if ($templateCompileDir == NULL) {
503 $config = CRM_Core_Config::singleton();
504 $templateCompileDir = $config->templateCompileDir;
505 }
506
507 $path = dirname($templateCompileDir);
508
509 //this fix is to avoid creation of upload dirs inside templates_c directory
510 $checkPath = explode(DIRECTORY_SEPARATOR, $path);
511
512 $cnt = count($checkPath) - 1;
513 if ($checkPath[$cnt] == 'templates_c') {
514 unset($checkPath[$cnt]);
515 $path = implode(DIRECTORY_SEPARATOR, $checkPath);
516 }
517
518 $_path = CRM_Utils_File::addTrailingSlash($path);
519 }
520 return $_path;
521 }
522
9f87b14b
TO
523 /**
524 * Determine if a path is absolute.
525 *
526 * @return bool
527 * TRUE if absolute. FALSE if relative.
528 */
529 public static function isAbsolute($path) {
530 if (substr($path, 0, 1) === DIRECTORY_SEPARATOR) {
531 return TRUE;
532 }
533 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
534 if (preg_match('!^[a-zA-Z]:[/\\\\]!', $path)) {
535 return TRUE;
536 }
537 }
538 return FALSE;
539 }
540
5bc392e6
EM
541 /**
542 * @param $directory
543 *
544 * @return string
545 */
00be9182 546 public static function relativeDirectory($directory) {
6a488035
TO
547 // Do nothing on windows
548 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
549 return $directory;
550 }
551
552 // check if directory is relative, if so return immediately
9f87b14b 553 if (!self::isAbsolute($directory)) {
6a488035
TO
554 return $directory;
555 }
556
557 // make everything relative from the baseFilePath
558 $basePath = self::baseFilePath();
559 // check if basePath is a substr of $directory, if so
560 // return rest of string
561 if (substr($directory, 0, strlen($basePath)) == $basePath) {
562 return substr($directory, strlen($basePath));
563 }
564
565 // return the original value
566 return $directory;
567 }
568
5bc392e6
EM
569 /**
570 * @param $directory
571 *
572 * @return string
573 */
00be9182 574 public static function absoluteDirectory($directory) {
acc609a7
TO
575 // check if directory is already absolute, if so return immediately
576 // Note: Windows PHP accepts any mix of "/" or "\", so "C:\htdocs" or "C:/htdocs" would be a valid absolute path
577 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && preg_match(';^[a-zA-Z]:[/\\\\];', $directory)) {
6a488035
TO
578 return $directory;
579 }
580
581 // check if directory is already absolute, if so return immediately
582 if (substr($directory, 0, 1) == DIRECTORY_SEPARATOR) {
583 return $directory;
584 }
585
586 // make everything absolute from the baseFilePath
587 $basePath = self::baseFilePath();
588
589 return $basePath . $directory;
590 }
591
592 /**
fe482240 593 * Make a file path relative to some base dir.
6a488035 594 *
f4aaa82a
EM
595 * @param $directory
596 * @param $basePath
597 *
6a488035
TO
598 * @return string
599 */
00be9182 600 public static function relativize($directory, $basePath) {
9f87b14b
TO
601 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
602 $directory = strtr($directory, '\\', '/');
603 $basePath = strtr($basePath, '\\', '/');
604 }
6a488035
TO
605 if (substr($directory, 0, strlen($basePath)) == $basePath) {
606 return substr($directory, strlen($basePath));
0db6c3e1
TO
607 }
608 else {
6a488035
TO
609 return $directory;
610 }
611 }
612
613 /**
fe482240 614 * Create a path to a temporary file which can endure for multiple requests.
6a488035
TO
615 *
616 * TODO: Automatic file cleanup using, eg, TTL policy
617 *
5a4f6742 618 * @param string $prefix
6a488035
TO
619 *
620 * @return string, path to an openable/writable file
621 * @see tempnam
622 */
00be9182 623 public static function tempnam($prefix = 'tmp-') {
6a488035
TO
624 //$config = CRM_Core_Config::singleton();
625 //$nonce = md5(uniqid() . $config->dsn . $config->userFrameworkResourceURL);
626 //$fileName = "{$config->configAndLogDir}" . $prefix . $nonce . $suffix;
627 $fileName = tempnam(sys_get_temp_dir(), $prefix);
628 return $fileName;
629 }
630
631 /**
fe482240 632 * Create a path to a temporary directory which can endure for multiple requests.
6a488035
TO
633 *
634 * TODO: Automatic file cleanup using, eg, TTL policy
635 *
5a4f6742 636 * @param string $prefix
6a488035
TO
637 *
638 * @return string, path to an openable/writable directory; ends with '/'
639 * @see tempnam
640 */
00be9182 641 public static function tempdir($prefix = 'tmp-') {
6a488035
TO
642 $fileName = self::tempnam($prefix);
643 unlink($fileName);
644 mkdir($fileName, 0700);
645 return $fileName . '/';
646 }
647
648 /**
d7166b43
TO
649 * Search directory tree for files which match a glob pattern.
650 *
651 * Note: Dot-directories (like "..", ".git", or ".svn") will be ignored.
6a488035 652 *
5a4f6742
CW
653 * @param string $dir
654 * base dir.
655 * @param string $pattern
656 * glob pattern, eg "*.txt".
a2dc0f82
TO
657 * @param bool $relative
658 * TRUE if paths should be made relative to $dir
6a488035
TO
659 * @return array(string)
660 */
a2dc0f82
TO
661 public static function findFiles($dir, $pattern, $relative = FALSE) {
662 $dir = rtrim($dir, '/');
6a488035
TO
663 $todos = array($dir);
664 $result = array();
665 while (!empty($todos)) {
666 $subdir = array_shift($todos);
0b72a00f
TO
667 $matches = glob("$subdir/$pattern");
668 if (is_array($matches)) {
669 foreach ($matches as $match) {
002f1716 670 if (!is_dir($match)) {
a2dc0f82 671 $result[] = $relative ? CRM_Utils_File::relativize($match, "$dir/") : $match;
002f1716 672 }
6a488035
TO
673 }
674 }
948d11bf 675 if ($dh = opendir($subdir)) {
6a488035
TO
676 while (FALSE !== ($entry = readdir($dh))) {
677 $path = $subdir . DIRECTORY_SEPARATOR . $entry;
d7166b43
TO
678 if ($entry{0} == '.') {
679 // ignore
0db6c3e1
TO
680 }
681 elseif (is_dir($path)) {
6a488035
TO
682 $todos[] = $path;
683 }
684 }
685 closedir($dh);
686 }
687 }
688 return $result;
689 }
690
691 /**
692 * Determine if $child is a sub-directory of $parent
693 *
694 * @param string $parent
695 * @param string $child
f4aaa82a
EM
696 * @param bool $checkRealPath
697 *
6a488035
TO
698 * @return bool
699 */
00be9182 700 public static function isChildPath($parent, $child, $checkRealPath = TRUE) {
6a488035
TO
701 if ($checkRealPath) {
702 $parent = realpath($parent);
703 $child = realpath($child);
704 }
705 $parentParts = explode('/', rtrim($parent, '/'));
706 $childParts = explode('/', rtrim($child, '/'));
707 while (($parentPart = array_shift($parentParts)) !== NULL) {
708 $childPart = array_shift($childParts);
709 if ($parentPart != $childPart) {
710 return FALSE;
711 }
712 }
713 if (empty($childParts)) {
714 return FALSE; // same directory
0db6c3e1
TO
715 }
716 else {
6a488035
TO
717 return TRUE;
718 }
719 }
720
721 /**
722 * Move $fromDir to $toDir, replacing/deleting any
723 * pre-existing content.
724 *
77855840
TO
725 * @param string $fromDir
726 * The directory which should be moved.
727 * @param string $toDir
728 * The new location of the directory.
f4aaa82a
EM
729 * @param bool $verbose
730 *
a6c01b45
CW
731 * @return bool
732 * TRUE on success
6a488035 733 */
00be9182 734 public static function replaceDir($fromDir, $toDir, $verbose = FALSE) {
6a488035
TO
735 if (is_dir($toDir)) {
736 if (!self::cleanDir($toDir, TRUE, $verbose)) {
737 return FALSE;
738 }
739 }
740
741 // return rename($fromDir, $toDir); // CRM-11987, https://bugs.php.net/bug.php?id=54097
742
743 CRM_Utils_File::copyDir($fromDir, $toDir);
744 if (!CRM_Utils_File::cleanDir($fromDir, TRUE, FALSE)) {
e7292422 745 CRM_Core_Session::setStatus(ts('Failed to clean temp dir: %1', array(1 => $fromDir)), '', 'alert');
6a488035
TO
746 return FALSE;
747 }
748 return TRUE;
749 }
96025800 750
6a488035 751}