[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * This file is part of the phpBB Forum Software package. 5 * 6 * @copyright (c) phpBB Limited <https://www.phpbb.com> 7 * @license GNU General Public License, version 2 (GPL-2.0) 8 * 9 * For full copyright and license information, please see 10 * the docs/CREDITS.txt file. 11 * 12 */ 13 14 namespace phpbb\filesystem; 15 16 use phpbb\filesystem\exception\filesystem_exception; 17 18 /** 19 * A class with various functions that are related to paths, files and the filesystem 20 */ 21 class filesystem implements filesystem_interface 22 { 23 /** 24 * Store some information about file ownership for phpBB's chmod function 25 * 26 * @var array 27 */ 28 protected $chmod_info; 29 30 /** 31 * Stores current working directory 32 * 33 * @var string|bool current working directory or false if it cannot be recovered 34 */ 35 protected $working_directory; 36 37 /** 38 * Symfony's Filesystem component 39 * 40 * @var \Symfony\Component\Filesystem\Filesystem 41 */ 42 protected $symfony_filesystem; 43 44 /** 45 * Constructor 46 */ 47 public function __construct() 48 { 49 $this->chmod_info = array(); 50 $this->symfony_filesystem = new \Symfony\Component\Filesystem\Filesystem(); 51 $this->working_directory = null; 52 } 53 54 /** 55 * {@inheritdoc} 56 */ 57 public function chgrp($files, $group, $recursive = false) 58 { 59 try 60 { 61 $this->symfony_filesystem->chgrp($files, $group, $recursive); 62 } 63 catch (\Symfony\Component\Filesystem\Exception\IOException $e) 64 { 65 // Try to recover filename 66 // By the time this is written that is at the end of the message 67 $error = trim($e->getMessage()); 68 $file = substr($error, strrpos($error, ' ')); 69 70 throw new filesystem_exception('CANNOT_CHANGE_FILE_GROUP', $file, array(), $e); 71 } 72 } 73 74 /** 75 * {@inheritdoc} 76 */ 77 public function chmod($files, $perms = null, $recursive = false, $force_chmod_link = false) 78 { 79 if (is_null($perms)) 80 { 81 // Default to read permission for compatibility reasons 82 $perms = self::CHMOD_READ; 83 } 84 85 // Check if we got a permission flag 86 if ($perms > self::CHMOD_ALL) 87 { 88 $file_perm = $perms; 89 90 // Extract permissions 91 //$owner = ($file_perm >> 6) & 7; // This will be ignored 92 $group = ($file_perm >> 3) & 7; 93 $other = ($file_perm >> 0) & 7; 94 95 // Does any permissions provided? if so we add execute bit for directories 96 $group = ($group !== 0) ? ($group | self::CHMOD_EXECUTE) : $group; 97 $other = ($other !== 0) ? ($other | self::CHMOD_EXECUTE) : $other; 98 99 // Compute directory permissions 100 $dir_perm = (self::CHMOD_ALL << 6) + ($group << 3) + ($other << 3); 101 } 102 else 103 { 104 // Add execute bit to owner if execute bit is among perms 105 $owner_perm = (self::CHMOD_READ | self::CHMOD_WRITE) | ($perms & self::CHMOD_EXECUTE); 106 $file_perm = ($owner_perm << 6) + ($perms << 3) + ($perms << 0); 107 108 // Compute directory permissions 109 $perm = ($perms !== 0) ? ($perms | self::CHMOD_EXECUTE) : $perms; 110 $dir_perm = (($owner_perm | self::CHMOD_EXECUTE) << 6) + ($perm << 3) + ($perm << 0); 111 } 112 113 // Symfony's filesystem component does not support extra execution flags on directories 114 // so we need to implement it again 115 foreach ($this->to_iterator($files) as $file) 116 { 117 if ($recursive && is_dir($file) && !is_link($file)) 118 { 119 $this->chmod(new \FilesystemIterator($file), $perms, true); 120 } 121 122 // Don't chmod links as mostly those require 0777 and that cannot be changed 123 if (is_dir($file) || (is_link($file) && $force_chmod_link)) 124 { 125 if (true !== @chmod($file, $dir_perm)) 126 { 127 throw new filesystem_exception('CANNOT_CHANGE_FILE_PERMISSIONS', $file, array()); 128 } 129 } 130 else if (is_file($file)) 131 { 132 if (true !== @chmod($file, $file_perm)) 133 { 134 throw new filesystem_exception('CANNOT_CHANGE_FILE_PERMISSIONS', $file, array()); 135 } 136 } 137 } 138 } 139 140 /** 141 * {@inheritdoc} 142 */ 143 public function chown($files, $user, $recursive = false) 144 { 145 try 146 { 147 $this->symfony_filesystem->chown($files, $user, $recursive); 148 } 149 catch (\Symfony\Component\Filesystem\Exception\IOException $e) 150 { 151 // Try to recover filename 152 // By the time this is written that is at the end of the message 153 $error = trim($e->getMessage()); 154 $file = substr($error, strrpos($error, ' ')); 155 156 throw new filesystem_exception('CANNOT_CHANGE_FILE_GROUP', $file, array(), $e); 157 } 158 } 159 160 /** 161 * {@inheritdoc} 162 */ 163 public function clean_path($path) 164 { 165 $exploded = explode('/', $path); 166 $filtered = array(); 167 foreach ($exploded as $part) 168 { 169 if ($part === '.' && !empty($filtered)) 170 { 171 continue; 172 } 173 174 if ($part === '..' && !empty($filtered) && $filtered[count($filtered) - 1] !== '.' && $filtered[count($filtered) - 1] !== '..') 175 { 176 array_pop($filtered); 177 } 178 else 179 { 180 $filtered[] = $part; 181 } 182 } 183 $path = implode('/', $filtered); 184 return $path; 185 } 186 187 /** 188 * {@inheritdoc} 189 */ 190 public function copy($origin_file, $target_file, $override = false) 191 { 192 try 193 { 194 $this->symfony_filesystem->copy($origin_file, $target_file, $override); 195 } 196 catch (\Symfony\Component\Filesystem\Exception\IOException $e) 197 { 198 throw new filesystem_exception('CANNOT_COPY_FILES', '', array(), $e); 199 } 200 } 201 202 /** 203 * {@inheritdoc} 204 */ 205 public function dump_file($filename, $content) 206 { 207 try 208 { 209 $this->symfony_filesystem->dumpFile($filename, $content); 210 } 211 catch (\Symfony\Component\Filesystem\Exception\IOException $e) 212 { 213 throw new filesystem_exception('CANNOT_DUMP_FILE', $filename, array(), $e); 214 } 215 } 216 217 /** 218 * {@inheritdoc} 219 */ 220 public function exists($files) 221 { 222 return $this->symfony_filesystem->exists($files); 223 } 224 225 /** 226 * {@inheritdoc} 227 */ 228 public function is_absolute_path($path) 229 { 230 return (isset($path[0]) && $path[0] === '/' || preg_match('#^[a-z]:[/\\\]#i', $path)) ? true : false; 231 } 232 233 /** 234 * {@inheritdoc} 235 */ 236 public function is_readable($files, $recursive = false) 237 { 238 foreach ($this->to_iterator($files) as $file) 239 { 240 if ($recursive && is_dir($file) && !is_link($file)) 241 { 242 if (!$this->is_readable(new \FilesystemIterator($file), true)) 243 { 244 return false; 245 } 246 } 247 248 if (!is_readable($file)) 249 { 250 return false; 251 } 252 } 253 254 return true; 255 } 256 257 /** 258 * {@inheritdoc} 259 */ 260 public function is_writable($files, $recursive = false) 261 { 262 if (defined('PHP_WINDOWS_VERSION_MAJOR') || !function_exists('is_writable')) 263 { 264 foreach ($this->to_iterator($files) as $file) 265 { 266 if ($recursive && is_dir($file) && !is_link($file)) 267 { 268 if (!$this->is_writable(new \FilesystemIterator($file), true)) 269 { 270 return false; 271 } 272 } 273 274 if (!$this->phpbb_is_writable($file)) 275 { 276 return false; 277 } 278 } 279 } 280 else 281 { 282 // use built in is_writable 283 foreach ($this->to_iterator($files) as $file) 284 { 285 if ($recursive && is_dir($file) && !is_link($file)) 286 { 287 if (!$this->is_writable(new \FilesystemIterator($file), true)) 288 { 289 return false; 290 } 291 } 292 293 if (!is_writable($file)) 294 { 295 return false; 296 } 297 } 298 } 299 300 return true; 301 } 302 303 /** 304 * {@inheritdoc} 305 */ 306 public function make_path_relative($end_path, $start_path) 307 { 308 return $this->symfony_filesystem->makePathRelative($end_path, $start_path); 309 } 310 311 /** 312 * {@inheritdoc} 313 */ 314 public function mirror($origin_dir, $target_dir, \Traversable $iterator = null, $options = array()) 315 { 316 try 317 { 318 $this->symfony_filesystem->mirror($origin_dir, $target_dir, $iterator, $options); 319 } 320 catch (\Symfony\Component\Filesystem\Exception\IOException $e) 321 { 322 $msg = $e->getMessage(); 323 $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"')); 324 325 throw new filesystem_exception('CANNOT_MIRROR_DIRECTORY', $filename, array(), $e); 326 } 327 } 328 329 /** 330 * {@inheritdoc} 331 */ 332 public function mkdir($dirs, $mode = 0777) 333 { 334 try 335 { 336 $this->symfony_filesystem->mkdir($dirs, $mode); 337 } 338 catch (\Symfony\Component\Filesystem\Exception\IOException $e) 339 { 340 $msg = $e->getMessage(); 341 $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"')); 342 343 throw new filesystem_exception('CANNOT_CREATE_DIRECTORY', $filename, array(), $e); 344 } 345 } 346 347 /** 348 * {@inheritdoc} 349 */ 350 public function phpbb_chmod($files, $perms = null, $recursive = false, $force_chmod_link = false) 351 { 352 if (is_null($perms)) 353 { 354 // Default to read permission for compatibility reasons 355 $perms = self::CHMOD_READ; 356 } 357 358 if (empty($this->chmod_info)) 359 { 360 if (!function_exists('fileowner') || !function_exists('filegroup')) 361 { 362 $this->chmod_info['process'] = false; 363 } 364 else 365 { 366 $common_php_owner = @fileowner(__FILE__); 367 $common_php_group = @filegroup(__FILE__); 368 369 // And the owner and the groups PHP is running under. 370 $php_uid = (function_exists('posix_getuid')) ? @posix_getuid() : false; 371 $php_gids = (function_exists('posix_getgroups')) ? @posix_getgroups() : false; 372 373 // If we are unable to get owner/group, then do not try to set them by guessing 374 if (!$php_uid || empty($php_gids) || !$common_php_owner || !$common_php_group) 375 { 376 $this->chmod_info['process'] = false; 377 } 378 else 379 { 380 $this->chmod_info = array( 381 'process' => true, 382 'common_owner' => $common_php_owner, 383 'common_group' => $common_php_group, 384 'php_uid' => $php_uid, 385 'php_gids' => $php_gids, 386 ); 387 } 388 } 389 } 390 391 if ($this->chmod_info['process']) 392 { 393 try 394 { 395 foreach ($this->to_iterator($files) as $file) 396 { 397 $file_uid = @fileowner($file); 398 $file_gid = @filegroup($file); 399 400 // Change owner 401 if ($file_uid !== $this->chmod_info['common_owner']) 402 { 403 $this->chown($file, $this->chmod_info['common_owner'], $recursive); 404 } 405 406 // Change group 407 if ($file_gid !== $this->chmod_info['common_group']) 408 { 409 $this->chgrp($file, $this->chmod_info['common_group'], $recursive); 410 } 411 412 clearstatcache(); 413 $file_uid = @fileowner($file); 414 $file_gid = @filegroup($file); 415 } 416 } 417 catch (filesystem_exception $e) 418 { 419 $this->chmod_info['process'] = false; 420 } 421 } 422 423 // Still able to process? 424 if ($this->chmod_info['process']) 425 { 426 if ($file_uid === $this->chmod_info['php_uid']) 427 { 428 $php = 'owner'; 429 } 430 else if (in_array($file_gid, $this->chmod_info['php_gids'])) 431 { 432 $php = 'group'; 433 } 434 else 435 { 436 // Since we are setting the everyone bit anyway, no need to do expensive operations 437 $this->chmod_info['process'] = false; 438 } 439 } 440 441 // We are not able to determine or change something 442 if (!$this->chmod_info['process']) 443 { 444 $php = 'other'; 445 } 446 447 switch ($php) 448 { 449 case 'owner': 450 try 451 { 452 $this->chmod($files, $perms, $recursive, $force_chmod_link); 453 clearstatcache(); 454 if ($this->is_readable($files) && $this->is_writable($files)) 455 { 456 break; 457 } 458 } 459 catch (filesystem_exception $e) 460 { 461 // Do nothing 462 } 463 case 'group': 464 try 465 { 466 $this->chmod($files, $perms, $recursive, $force_chmod_link); 467 clearstatcache(); 468 if ((!($perms & self::CHMOD_READ) || $this->is_readable($files, $recursive)) && (!($perms & self::CHMOD_WRITE) || $this->is_writable($files, $recursive))) 469 { 470 break; 471 } 472 } 473 catch (filesystem_exception $e) 474 { 475 // Do nothing 476 } 477 case 'other': 478 default: 479 $this->chmod($files, $perms, $recursive, $force_chmod_link); 480 break; 481 } 482 } 483 484 /** 485 * {@inheritdoc} 486 */ 487 public function realpath($path) 488 { 489 if (!function_exists('realpath')) 490 { 491 return $this->phpbb_own_realpath($path); 492 } 493 494 $realpath = realpath($path); 495 496 // Strangely there are provider not disabling realpath but returning strange values. :o 497 // We at least try to cope with them. 498 if ((!$this->is_absolute_path($path) && $realpath === $path) || $realpath === false) 499 { 500 return $this->phpbb_own_realpath($path); 501 } 502 503 // Check for DIRECTORY_SEPARATOR at the end (and remove it!) 504 if (substr($realpath, -1) === DIRECTORY_SEPARATOR) 505 { 506 $realpath = substr($realpath, 0, -1); 507 } 508 509 return $realpath; 510 } 511 512 /** 513 * {@inheritdoc} 514 */ 515 public function remove($files) 516 { 517 try 518 { 519 $this->symfony_filesystem->remove($files); 520 } 521 catch (\Symfony\Component\Filesystem\Exception\IOException $e) 522 { 523 // Try to recover filename 524 // By the time this is written that is at the end of the message 525 $error = trim($e->getMessage()); 526 $file = substr($error, strrpos($error, ' ')); 527 528 throw new filesystem_exception('CANNOT_DELETE_FILES', $file, array(), $e); 529 } 530 } 531 532 /** 533 * {@inheritdoc} 534 */ 535 public function rename($origin, $target, $overwrite = false) 536 { 537 try 538 { 539 $this->symfony_filesystem->rename($origin, $target, $overwrite); 540 } 541 catch (\Symfony\Component\Filesystem\Exception\IOException $e) 542 { 543 $msg = $e->getMessage(); 544 $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"')); 545 546 throw new filesystem_exception('CANNOT_RENAME_FILE', $filename, array(), $e); 547 } 548 } 549 550 /** 551 * {@inheritdoc} 552 */ 553 public function symlink($origin_dir, $target_dir, $copy_on_windows = false) 554 { 555 try 556 { 557 $this->symfony_filesystem->symlink($origin_dir, $target_dir, $copy_on_windows); 558 } 559 catch (\Symfony\Component\Filesystem\Exception\IOException $e) 560 { 561 throw new filesystem_exception('CANNOT_CREATE_SYMLINK', $origin_dir, array(), $e); 562 } 563 } 564 565 /** 566 * {@inheritdoc} 567 */ 568 public function touch($files, $time = null, $access_time = null) 569 { 570 try 571 { 572 $this->symfony_filesystem->touch($files, $time, $access_time); 573 } 574 catch (\Symfony\Component\Filesystem\Exception\IOException $e) 575 { 576 // Try to recover filename 577 // By the time this is written that is at the end of the message 578 $error = trim($e->getMessage()); 579 $file = substr($error, strrpos($error, ' ')); 580 581 throw new filesystem_exception('CANNOT_TOUCH_FILES', $file, array(), $e); 582 } 583 } 584 585 /** 586 * phpBB's implementation of is_writable 587 * 588 * @todo Investigate if is_writable is still buggy 589 * 590 * @param string $file file/directory to check if writable 591 * 592 * @return bool true if the given path is writable 593 */ 594 protected function phpbb_is_writable($file) 595 { 596 if (file_exists($file)) 597 { 598 // Canonicalise path to absolute path 599 $file = $this->realpath($file); 600 601 if (is_dir($file)) 602 { 603 // Test directory by creating a file inside the directory 604 $result = @tempnam($file, 'i_w'); 605 606 if (is_string($result) && file_exists($result)) 607 { 608 unlink($result); 609 610 // Ensure the file is actually in the directory (returned realpathed) 611 return (strpos($result, $file) === 0) ? true : false; 612 } 613 } 614 else 615 { 616 $handle = @fopen($file, 'c'); 617 618 if (is_resource($handle)) 619 { 620 fclose($handle); 621 return true; 622 } 623 } 624 } 625 else 626 { 627 // file does not exist test if we can write to the directory 628 $dir = dirname($file); 629 630 if (file_exists($dir) && is_dir($dir) && $this->phpbb_is_writable($dir)) 631 { 632 return true; 633 } 634 } 635 636 return false; 637 } 638 639 /** 640 * Try to resolve real path when PHP's realpath failes to do so 641 * 642 * @param string $path 643 * @return bool|string 644 */ 645 protected function phpbb_own_realpath($path) 646 { 647 // Replace all directory separators with '/' 648 $path = str_replace(DIRECTORY_SEPARATOR, '/', $path); 649 650 $is_absolute_path = false; 651 $path_prefix = ''; 652 653 if ($this->is_absolute_path($path)) 654 { 655 $is_absolute_path = true; 656 } 657 else 658 { 659 // Resolve working directory and store it 660 if (is_null($this->working_directory)) 661 { 662 if (function_exists('getcwd')) 663 { 664 $this->working_directory = str_replace(DIRECTORY_SEPARATOR, '/', getcwd()); 665 } 666 667 // 668 // From this point on we really just guessing 669 // If chdir were called we screwed 670 // 671 else if (function_exists('debug_backtrace')) 672 { 673 $call_stack = debug_backtrace(0); 674 $this->working_directory = str_replace(DIRECTORY_SEPARATOR, '/', dirname($call_stack[count($call_stack) - 1]['file'])); 675 } 676 else 677 { 678 // 679 // Assuming that the working directory is phpBB root 680 // we could use this as a fallback, when phpBB will use controllers 681 // everywhere this will be a safe assumption 682 // 683 //$dir_parts = explode(DIRECTORY_SEPARATOR, __DIR__); 684 //$namespace_parts = explode('\\', trim(__NAMESPACE__, '\\')); 685 686 //$namespace_part_count = count($namespace_parts); 687 688 // Check if we still loading from root 689 //if (array_slice($dir_parts, -$namespace_part_count) === $namespace_parts) 690 //{ 691 // $this->working_directory = implode('/', array_slice($dir_parts, 0, -$namespace_part_count)); 692 //} 693 //else 694 //{ 695 // $this->working_directory = false; 696 //} 697 698 $this->working_directory = false; 699 } 700 } 701 702 if ($this->working_directory !== false) 703 { 704 $is_absolute_path = true; 705 $path = $this->working_directory . '/' . $path; 706 } 707 } 708 709 if ($is_absolute_path) 710 { 711 if (defined('PHP_WINDOWS_VERSION_MAJOR')) 712 { 713 $path_prefix = $path[0] . ':'; 714 $path = substr($path, 2); 715 } 716 else 717 { 718 $path_prefix = ''; 719 } 720 } 721 722 $resolved_path = $this->resolve_path($path, $path_prefix, $is_absolute_path); 723 if ($resolved_path === false) 724 { 725 return false; 726 } 727 728 if (!@file_exists($resolved_path) || (!@is_dir($resolved_path . '/') && !is_file($resolved_path))) 729 { 730 return false; 731 } 732 733 // Return OS specific directory separators 734 $resolved = str_replace('/', DIRECTORY_SEPARATOR, $resolved_path); 735 736 // Check for DIRECTORY_SEPARATOR at the end (and remove it!) 737 if (substr($resolved, -1) === DIRECTORY_SEPARATOR) 738 { 739 return substr($resolved, 0, -1); 740 } 741 742 return $resolved; 743 } 744 745 /** 746 * Convert file(s) to \Traversable object 747 * 748 * This is the same function as Symfony's toIterator, but that is private 749 * so we cannot use it. 750 * 751 * @param string|array|\Traversable $files filename/list of filenames 752 * @return \Traversable 753 */ 754 protected function to_iterator($files) 755 { 756 if (!$files instanceof \Traversable) 757 { 758 $files = new \ArrayObject(is_array($files) ? $files : array($files)); 759 } 760 761 return $files; 762 } 763 764 /** 765 * Try to resolve symlinks in path 766 * 767 * @param string $path The path to resolve 768 * @param string $prefix The path prefix (on windows the drive letter) 769 * @param bool $absolute Whether or not the path is absolute 770 * @param bool $return_array Whether or not to return path parts 771 * 772 * @return string|array|bool returns the resolved path or an array of parts of the path if $return_array is true 773 * or false if path cannot be resolved 774 */ 775 protected function resolve_path($path, $prefix = '', $absolute = false, $return_array = false) 776 { 777 if ($return_array) 778 { 779 $path = str_replace(DIRECTORY_SEPARATOR, '/', $path); 780 } 781 782 trim ($path, '/'); 783 $path_parts = explode('/', $path); 784 $resolved = array(); 785 $resolved_path = $prefix; 786 $file_found = false; 787 788 foreach ($path_parts as $path_part) 789 { 790 if ($file_found) 791 { 792 return false; 793 } 794 795 if (empty($path_part) || ($path_part === '.' && ($absolute || !empty($resolved)))) 796 { 797 continue; 798 } 799 else if ($absolute && $path_part === '..') 800 { 801 if (empty($resolved)) 802 { 803 // No directories above root 804 return false; 805 } 806 807 array_pop($resolved); 808 $resolved_path = false; 809 } 810 else if ($path_part === '..' && !empty($resolved) && !in_array($resolved[count($resolved) - 1], array('.', '..'))) 811 { 812 array_pop($resolved); 813 $resolved_path = false; 814 } 815 else 816 { 817 if ($resolved_path === false) 818 { 819 if (empty($resolved)) 820 { 821 $resolved_path = ($absolute) ? $prefix . '/' . $path_part : $path_part; 822 } 823 else 824 { 825 $tmp_array = $resolved; 826 if ($absolute) 827 { 828 array_unshift($tmp_array, $prefix); 829 } 830 831 $resolved_path = implode('/', $tmp_array); 832 } 833 } 834 835 $current_path = $resolved_path . '/' . $path_part; 836 837 // Resolve symlinks 838 if (@is_link($current_path)) 839 { 840 if (!function_exists('readlink')) 841 { 842 return false; 843 } 844 845 $link = readlink($current_path); 846 847 // Is link has an absolute path in it? 848 if ($this->is_absolute_path($link)) 849 { 850 if (defined('PHP_WINDOWS_VERSION_MAJOR')) 851 { 852 $prefix = $link[0] . ':'; 853 $link = substr($link, 2); 854 } 855 else 856 { 857 $prefix = ''; 858 } 859 860 $resolved = $this->resolve_path($link, $prefix, true, true); 861 $absolute = true; 862 } 863 else 864 { 865 $resolved = $this->resolve_path($resolved_path . '/' . $link, $prefix, $absolute, true); 866 } 867 868 if (!$resolved) 869 { 870 return false; 871 } 872 873 $resolved_path = false; 874 } 875 else if (@is_dir($current_path . '/')) 876 { 877 $resolved[] = $path_part; 878 $resolved_path = $current_path; 879 } 880 else if (@is_file($current_path)) 881 { 882 $resolved[] = $path_part; 883 $resolved_path = $current_path; 884 $file_found = true; 885 } 886 else 887 { 888 return false; 889 } 890 } 891 } 892 893 // If at the end of the path there were a .. or . 894 // we need to build the path again. 895 // Only doing this when a string is expected in return 896 if ($resolved_path === false && $return_array === false) 897 { 898 if (empty($resolved)) 899 { 900 $resolved_path = ($absolute) ? $prefix . '/' : './'; 901 } 902 else 903 { 904 $tmp_array = $resolved; 905 if ($absolute) 906 { 907 array_unshift($tmp_array, $prefix); 908 } 909 910 $resolved_path = implode('/', $tmp_array); 911 } 912 } 913 914 return ($return_array) ? $resolved : $resolved_path; 915 } 916 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |