AutorÃa | Ultima modificación | Ver Log |
<?phpnamespace MatthiasMullie\PathConverter;/*** Convert paths relative from 1 file to another.** E.g.* ../../images/icon.jpg relative to /css/imports/icons.css* becomes* ../images/icon.jpg relative to /css/minified.css** Please report bugs on https://github.com/matthiasmullie/path-converter/issues** @author Matthias Mullie <pathconverter@mullie.eu>* @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved* @license MIT License*/class Converter implements ConverterInterface{/*** @var string*/protected $from;/*** @var string*/protected $to;/*** @param string $from The original base path (directory, not file!)* @param string $to The new base path (directory, not file!)* @param string $root Root directory (defaults to `getcwd`)*/public function __construct($from, $to, $root = ''){$shared = $this->shared($from, $to);if ($shared === '') {// when both paths have nothing in common, one of them is probably// absolute while the other is relative$root = $root ?: getcwd();$from = strpos($from, $root) === 0 ? $from : preg_replace('/\/+/', '/', $root.'/'.$from);$to = strpos($to, $root) === 0 ? $to : preg_replace('/\/+/', '/', $root.'/'.$to);// or traveling the tree via `..`// attempt to resolve path, or assume it's fine if it doesn't exist$from = @realpath($from) ?: $from;$to = @realpath($to) ?: $to;}$from = $this->dirname($from);$to = $this->dirname($to);$from = $this->normalize($from);$to = $this->normalize($to);$this->from = $from;$this->to = $to;}/*** Normalize path.** @param string $path** @return string*/protected function normalize($path){// deal with different operating systems' directory structure$path = rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $path), '/');// remove leading current directory.if (substr($path, 0, 2) === './') {$path = substr($path, 2);}// remove references to current directory in the path.$path = str_replace('/./', '/', $path);/** Example:* /home/forkcms/frontend/cache/compiled_templates/../../core/layout/css/../images/img.gif* to* /home/forkcms/frontend/core/layout/images/img.gif*/do {$path = preg_replace('/[^\/]+(?<!\.\.)\/\.\.\//', '', $path, -1, $count);} while ($count);return $path;}/*** Figure out the shared path of 2 locations.** Example:* /home/forkcms/frontend/core/layout/images/img.gif* and* /home/forkcms/frontend/cache/minified_css* share* /home/forkcms/frontend** @param string $path1* @param string $path2** @return string*/protected function shared($path1, $path2){// $path could theoretically be empty (e.g. no path is given), in which// case it shouldn't expand to array(''), which would compare to one's// root /$path1 = $path1 ? explode('/', $path1) : array();$path2 = $path2 ? explode('/', $path2) : array();$shared = array();// compare paths & strip identical ancestorsforeach ($path1 as $i => $chunk) {if (isset($path2[$i]) && $path1[$i] == $path2[$i]) {$shared[] = $chunk;} else {break;}}return implode('/', $shared);}/*** Convert paths relative from 1 file to another.** E.g.* ../images/img.gif relative to /home/forkcms/frontend/core/layout/css* should become:* ../../core/layout/images/img.gif relative to* /home/forkcms/frontend/cache/minified_css** @param string $path The relative path that needs to be converted** @return string The new relative path*/public function convert($path){// quit early if conversion makes no senseif ($this->from === $this->to) {return $path;}$path = $this->normalize($path);// if we're not dealing with a relative path, just return absoluteif (strpos($path, '/') === 0) {return $path;}// normalize paths$path = $this->normalize($this->from.'/'.$path);// strip shared ancestor paths$shared = $this->shared($path, $this->to);$path = mb_substr($path, mb_strlen($shared));$to = mb_substr($this->to, mb_strlen($shared));// add .. for every directory that needs to be traversed to new path$to = str_repeat('../', count(array_filter(explode('/', $to))));return $to.ltrim($path, '/');}/*** Attempt to get the directory name from a path.** @param string $path** @return string*/protected function dirname($path){if (@is_file($path)) {return dirname($path);}if (@is_dir($path)) {return rtrim($path, '/');}// no known file/dir, start making assumptions// ends in / = dirif (mb_substr($path, -1) === '/') {return rtrim($path, '/');}// has a dot in the name, likely a fileif (preg_match('/.*\..*$/', basename($path)) !== 0) {return dirname($path);}// you're on your own here!return $path;}}