Ejemplo n.º 1
0
 /**
  * Normalize the given absolute path.
  *
  * This includes:
  *   - Uppercase the drive letter if there is one.
  *   - Remove redundant slashes after the drive spec.
  *   - resolve all ./, .\, ../ and ..\ sequences.
  *   - DOS style paths that start with a drive letter will have
  *     \ as the separator.
  * @param string $path Path to normalize.
  * @return string
  */
 function normalize($path)
 {
     $path = (string) $path;
     $orig = $path;
     $path = str_replace('/', DIRECTORY_SEPARATOR, str_replace('\\', DIRECTORY_SEPARATOR, $path));
     // make sure we are dealing with an absolute path
     if (!StringHelper::startsWith(DIRECTORY_SEPARATOR, $path) && !(strlen($path) >= 2 && Character::isLetter($path[0]) && $path[1] === ':')) {
         throw new IOException("{$path} is not an absolute path");
     }
     $dosWithDrive = false;
     $root = null;
     // Eliminate consecutive slashes after the drive spec
     if (strlen($path) >= 2 && Character::isLetter($path[0]) && $path[1] === ':') {
         $dosWithDrive = true;
         $ca = str_replace('/', '\\', $path);
         $ca = StringHelper::toCharArray($ca);
         $path = strtoupper($ca[0]) . ':';
         for ($i = 2, $_i = count($ca); $i < $_i; $i++) {
             if ($ca[$i] !== '\\' || $ca[$i] === '\\' && $ca[$i - 1] !== '\\') {
                 $path .= $ca[$i];
             }
         }
         $path = str_replace('\\', DIRECTORY_SEPARATOR, $path);
         if (strlen($path) == 2) {
             $root = $path;
             $path = "";
         } else {
             $root = substr($path, 0, 3);
             $path = substr($path, 3);
         }
     } else {
         if (strlen($path) == 1) {
             $root = DIRECTORY_SEPARATOR;
             $path = "";
         } else {
             if ($path[1] == DIRECTORY_SEPARATOR) {
                 // UNC drive
                 $root = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
                 $path = substr($path, 2);
             } else {
                 $root = DIRECTORY_SEPARATOR;
                 $path = substr($path, 1);
             }
         }
     }
     $s = array();
     array_push($s, $root);
     $tok = strtok($path, DIRECTORY_SEPARATOR);
     while ($tok !== false) {
         $thisToken = $tok;
         if ("." === $thisToken) {
             $tok = strtok(DIRECTORY_SEPARATOR);
             continue;
         } elseif (".." === $thisToken) {
             if (count($s) < 2) {
                 // using '..' in path that is too short
                 throw new IOException("Cannot resolve path: {$orig}");
             } else {
                 array_pop($s);
             }
         } else {
             // plain component
             array_push($s, $thisToken);
         }
         $tok = strtok(DIRECTORY_SEPARATOR);
     }
     $sb = "";
     for ($i = 0, $_i = count($s); $i < $_i; $i++) {
         if ($i > 1) {
             // not before the filesystem root and not after it, since root
             // already contains one
             $sb .= DIRECTORY_SEPARATOR;
         }
         $sb .= (string) $s[$i];
     }
     $path = (string) $sb;
     if ($dosWithDrive === true) {
         $path = str_replace('/', '\\', $path);
     }
     return $path;
 }
Ejemplo n.º 2
0
 /**
  * Returns the next path element from this tokenizer.
  * 
  * @return the next path element from this tokenizer.
  * 
  * @throws Exception if there are no more elements in this tokenizer's path.
  */
 public function nextToken()
 {
     if ($this->lookahead !== null) {
         $token = $this->lookahead;
         $this->lookahead = null;
     } else {
         $token = trim(array_shift($this->tokens));
     }
     if (strlen($token) === 1 && Character::isLetter($token[0]) && $this->dosStyleFilesystem && !empty($this->tokens)) {
         // we are on a dos style system so this path could be a drive
         // spec. We look at the next token
         $nextToken = trim(array_shift($this->tokens));
         if (StringHelper::startsWith('\\', $nextToken) || StringHelper::startsWith('/', $nextToken)) {
             // we know we are on a DOS style platform and the next path
             // starts with a slash or backslash, so we know this is a
             // drive spec
             $token .= ':' . $nextToken;
         } else {
             // store the token just read for next time
             $this->lookahead = $nextToken;
         }
     }
     return $token;
 }