/**
  * 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;
 }
Exemple #2
0
 /**
  * Tests whether or not a string matches against a pattern.
  * The pattern may contain two special characters:<br>
  * '*' means zero or more characters<br>
  * '?' means one and only one character
  *
  * @param pattern The pattern to match against.
  *                Must not be <code>null</code>.
  * @param str     The string which must be matched against the pattern.
  *                Must not be <code>null</code>.
  * @param isCaseSensitive Whether or not matching should be performed
  *                        case sensitively.
  *
  *
  * @return <code>true</code> if the string matches against the pattern,
  *         or <code>false</code> otherwise.
  */
 public static function match($pattern, $str, $isCaseSensitive = true)
 {
     $patArr = StringHelper::toCharArray($pattern);
     $strArr = StringHelper::toCharArray($str);
     $patIdxStart = 0;
     $patIdxEnd = count($patArr) - 1;
     $strIdxStart = 0;
     $strIdxEnd = count($strArr) - 1;
     $containsStar = false;
     for ($i = 0, $size = count($patArr); $i < $size; $i++) {
         if ($patArr[$i] == '*') {
             $containsStar = true;
             break;
         }
     }
     if (!$containsStar) {
         // No '*'s, so we make a shortcut
         if ($patIdxEnd != $strIdxEnd) {
             return false;
             // Pattern and string do not have the same size
         }
         for ($i = 0; $i <= $patIdxEnd; $i++) {
             $ch = $patArr[$i];
             if ($ch != '?') {
                 if ($isCaseSensitive && $ch !== $strArr[$i]) {
                     return false;
                     // Character mismatch
                 }
                 if (!$isCaseSensitive && strtoupper($ch) !== strtoupper($strArr[$i])) {
                     return false;
                     // Character mismatch
                 }
             }
         }
         return true;
         // String matches against pattern
     }
     if ($patIdxEnd == 0) {
         return true;
         // Pattern contains only '*', which matches anything
     }
     // Process characters before first star
     while (($ch = $patArr[$patIdxStart]) != '*' && $strIdxStart <= $strIdxEnd) {
         if ($ch != '?') {
             if ($isCaseSensitive && $ch !== $strArr[$strIdxStart]) {
                 return false;
                 // Character mismatch
             }
             if (!$isCaseSensitive && strtoupper($ch) !== strtoupper($strArr[$strIdxStart])) {
                 return false;
                 // Character mismatch
             }
         }
         $patIdxStart++;
         $strIdxStart++;
     }
     if ($strIdxStart > $strIdxEnd) {
         // All characters in the string are used. Check if only '*'s are
         // left in the pattern. If so, we succeeded. Otherwise failure.
         for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) {
             if ($patArr[$i] != '*') {
                 return false;
             }
         }
         return true;
     }
     // Process characters after last star
     while (($ch = $patArr[$patIdxEnd]) != '*' && $strIdxStart <= $strIdxEnd) {
         if ($ch != '?') {
             if ($isCaseSensitive && $ch !== $strArr[$strIdxEnd]) {
                 return false;
                 // Character mismatch
             }
             if (!$isCaseSensitive && strtoupper($ch) !== strtoupper($strArr[$strIdxEnd])) {
                 return false;
                 // Character mismatch
             }
         }
         $patIdxEnd--;
         $strIdxEnd--;
     }
     if ($strIdxStart > $strIdxEnd) {
         // All characters in the string are used. Check if only '*'s are
         // left in the pattern. If so, we succeeded. Otherwise failure.
         for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) {
             if ($patArr[$i] != '*') {
                 return false;
             }
         }
         return true;
     }
     // process pattern between stars. padIdxStart and patIdxEnd point
     // always to a '*'.
     while ($patIdxStart !== $patIdxEnd && $strIdxStart <= $strIdxEnd) {
         $patIdxTmp = -1;
         for ($i = $patIdxStart + 1; $i <= $patIdxEnd; $i++) {
             if ($patArr[$i] == '*') {
                 $patIdxTmp = $i;
                 break;
             }
         }
         if ($patIdxTmp === $patIdxStart + 1) {
             // Two stars next to each other, skip the first one.
             $patIdxStart++;
             continue;
         }
         // Find the pattern between padIdxStart & padIdxTmp in str between
         // strIdxStart & strIdxEnd
         $patLength = $patIdxTmp - $patIdxStart - 1;
         $strLength = $strIdxEnd - $strIdxStart + 1;
         $foundIdx = -1;
         //strLoop:
         for ($i = 0; $i <= $strLength - $patLength; $i++) {
             for ($j = 0; $j < $patLength; $j++) {
                 $ch = $patArr[$patIdxStart + $j + 1];
                 if ($ch != '?') {
                     if ($isCaseSensitive && $ch !== $strArr[$strIdxStart + $i + $j]) {
                         continue 2;
                         //continue to strLoop:
                     }
                     if (!$isCaseSensitive && strtoupper($ch) !== strtoupper($strArr[$strIdxStart + $i + $j])) {
                         continue 2;
                         //continue to strLoop:
                     }
                 }
             }
             // only reached if sub loop completed w/o invoking continue 2
             $foundIdx = $strIdxStart + $i;
             break;
         }
         if ($foundIdx == -1) {
             return false;
         }
         $patIdxStart = $patIdxTmp;
         $strIdxStart = $foundIdx + $patLength;
     }
     // All characters in the string are used. Check if only '*'s are left
     // in the pattern. If so, we succeeded. Otherwise failure.
     for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) {
         if ($patArr[$i] != '*') {
             return false;
         }
     }
     return true;
 }