diff options
Diffstat (limited to 'plugins/Customizer/vendor/matthiasmullie/path-converter/src/Converter.php')
-rw-r--r-- | plugins/Customizer/vendor/matthiasmullie/path-converter/src/Converter.php | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/plugins/Customizer/vendor/matthiasmullie/path-converter/src/Converter.php b/plugins/Customizer/vendor/matthiasmullie/path-converter/src/Converter.php new file mode 100644 index 00000000..519d3c84 --- /dev/null +++ b/plugins/Customizer/vendor/matthiasmullie/path-converter/src/Converter.php @@ -0,0 +1,196 @@ +<?php + +namespace 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), '/'); + + /* + * 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 ancestors + foreach ($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 sense + if ($this->from === $this->to) { + return $path; + } + + $path = $this->normalize($path); + // if we're not dealing with a relative path, just return absolute + if (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 / = dir + if (mb_substr($path, -1) === '/') { + return rtrim($path, '/'); + } + + // has a dot in the name, likely a file + if (preg_match('/.*\..*$/', basename($path)) !== 0) { + return dirname($path); + } + + // you're on your own here! + return $path; + } +} |