| 131 | | // When str starts with a DIRECTORY_SEPARATOR, pattern has to start with a |
| 132 | | // DIRECTORY_SEPARATOR. |
| 133 | | // When pattern starts with a DIRECTORY_SEPARATOR, str has to start with a |
| 134 | | // DIRECTORY_SEPARATOR. |
| 135 | | if (StringHelper::startsWith(DIRECTORY_SEPARATOR, $str) !== |
| 136 | | StringHelper::startsWith(DIRECTORY_SEPARATOR, $pattern)) { |
| 137 | | return false; |
| 138 | | } |
| 139 | | |
| 140 | | $patDirs = explode(DIRECTORY_SEPARATOR, $pattern); |
| 141 | | $strDirs = explode(DIRECTORY_SEPARATOR, $str); |
| 142 | | |
| 143 | | $patIdxStart = 0; |
| 144 | | $patIdxEnd = count($patDirs)-1; |
| 145 | | $strIdxStart = 0; |
| 146 | | $strIdxEnd = count($strDirs)-1; |
| 147 | | |
| 148 | | // up to first '**' |
| 149 | | while ($patIdxStart <= $patIdxEnd && $strIdxStart <= $strIdxEnd) { |
| 150 | | $patDir = $patDirs[$patIdxStart]; |
| 151 | | if ($patDir == "**") { |
| 152 | | break; |
| 153 | | } |
| 154 | | if (!self::match($patDir, $strDirs[$strIdxStart], $isCaseSensitive)) { |
| 155 | | return false; |
| 156 | | } |
| 157 | | $patIdxStart++; |
| 158 | | $strIdxStart++; |
| 159 | | } |
| 160 | | if ($strIdxStart > $strIdxEnd) { |
| 161 | | // String is exhausted |
| 162 | | for ($i=$patIdxStart; $i <= $patIdxEnd; $i++) { |
| 163 | | if ($patDirs[$i] != "**") { |
| 164 | | return false; |
| 165 | | } |
| 166 | | } |
| 167 | | return true; |
| 168 | | } elseif ($patIdxStart > $patIdxEnd) { |
| 169 | | // String not exhausted, but pattern is. Failure. |
| 170 | | return false; |
| 171 | | } |
| 172 | | |
| 173 | | // up to last '**' |
| 174 | | while ($patIdxStart <= $patIdxEnd && $strIdxStart <= $strIdxEnd) { |
| 175 | | $patDir = $patDirs[$patIdxEnd]; |
| 176 | | if ($patDir == "**") { |
| 177 | | break; |
| 178 | | } |
| 179 | | if (!self::match($patDir, $strDirs[$strIdxEnd], $isCaseSensitive)) { |
| 180 | | return false; |
| 181 | | } |
| 182 | | $patIdxEnd--; |
| 183 | | $strIdxEnd--; |
| 184 | | } |
| 185 | | |
| 186 | | if ($strIdxStart > $strIdxEnd) { |
| 187 | | // String is exhausted |
| 188 | | for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { |
| 189 | | if ($patDirs[$i] != "**") { |
| 190 | | return false; |
| 191 | | } |
| 192 | | } |
| 193 | | return true; |
| 194 | | } |
| 195 | | |
| 196 | | while ($patIdxStart != $patIdxEnd && $strIdxStart <= $strIdxEnd) { |
| 197 | | $patIdxTmp = -1; |
| 198 | | for ($i = $patIdxStart+1; $i <= $patIdxEnd; $i++) { |
| 199 | | if ($patDirs[$i] == "**") { |
| 200 | | $patIdxTmp = $i; |
| 201 | | break; |
| 202 | | } |
| 203 | | } |
| 204 | | if ($patIdxTmp == $patIdxStart+1) { |
| 205 | | // '**/**' situation, so skip one |
| 206 | | $patIdxStart++; |
| 207 | | continue; |
| 208 | | } |
| 209 | | // Find the pattern between padIdxStart & padIdxTmp in str between |
| 210 | | // strIdxStart & strIdxEnd |
| 211 | | $patLength = ($patIdxTmp-$patIdxStart-1); |
| 212 | | $strLength = ($strIdxEnd-$strIdxStart+1); |
| 213 | | $foundIdx = -1; |
| 214 | | |
| 215 | | //strLoop: (start of outer loop) |
| 216 | | for ($i=0; $i <= $strLength - $patLength; $i++) { |
| 217 | | for ($j = 0; $j < $patLength; $j++) { |
| 218 | | $subPat = $patDirs[$patIdxStart+$j+1]; |
| 219 | | $subStr = $strDirs[$strIdxStart+$i+$j]; |
| 220 | | if (!self::match($subPat, $subStr, $isCaseSensitive)) { |
| 221 | | continue 2; // continue up two levels (to strLoop:) |
| 222 | | } |
| 223 | | } |
| 224 | | $foundIdx = $strIdxStart+$i; // only reached if all sub patterns matched |
| 225 | | break; |
| 226 | | } |
| 227 | | |
| 228 | | if ($foundIdx == -1) { |
| 229 | | return false; |
| 230 | | } |
| 231 | | |
| 232 | | $patIdxStart = $patIdxTmp; |
| 233 | | $strIdxStart = $foundIdx + $patLength; |
| 234 | | } |
| 235 | | |
| 236 | | for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { |
| 237 | | if ($patDirs[$i] != "**") { |
| 238 | | return false; |
| 239 | | } |
| 240 | | } |
| 241 | | |
| 242 | | return true; |
| | 131 | $rePattern = preg_quote($pattern, '/'); |
| | 132 | $dirSep = preg_quote(DIRECTORY_SEPARATOR, '/'); |
| | 133 | $rePattern = str_replace(array("\*\*", "\*", "\?"), array('.*', '[^'.$dirSep.']*', '[^'.$dirSep.']'), $rePattern); |
| | 134 | $rePattern = '/^'.$rePattern.'$/'.($isCaseSensitive ? '' : 'i'); |
| | 135 | return preg_match($rePattern, $str); |
| 264 | | $patArr = StringHelper::toCharArray($pattern); |
| 265 | | $strArr = StringHelper::toCharArray($str); |
| 266 | | $patIdxStart = 0; |
| 267 | | $patIdxEnd = count($patArr)-1; |
| 268 | | $strIdxStart = 0; |
| 269 | | $strIdxEnd = count($strArr)-1; |
| 270 | | |
| 271 | | $containsStar = false; |
| 272 | | for ($i = 0, $size=count($patArr); $i < $size; $i++) { |
| 273 | | if ($patArr[$i] == '*') { |
| 274 | | $containsStar = true; |
| 275 | | break; |
| 276 | | } |
| 277 | | } |
| 278 | | |
| 279 | | if (!$containsStar) { |
| 280 | | // No '*'s, so we make a shortcut |
| 281 | | if ($patIdxEnd != $strIdxEnd) { |
| 282 | | return false; // Pattern and string do not have the same size |
| 283 | | } |
| 284 | | for ($i = 0; $i <= $patIdxEnd; $i++) { |
| 285 | | $ch = $patArr[$i]; |
| 286 | | if ($ch != '?') { |
| 287 | | if ($isCaseSensitive && $ch !== $strArr[$i]) { |
| 288 | | return false;// Character mismatch |
| 289 | | } |
| 290 | | if (!$isCaseSensitive && strtoupper($ch) !== |
| 291 | | strtoupper($strArr[$i])) { |
| 292 | | return false; // Character mismatch |
| 293 | | } |
| 294 | | } |
| 295 | | } |
| 296 | | return true; // String matches against pattern |
| 297 | | } |
| 298 | | |
| 299 | | if ($patIdxEnd == 0) { |
| 300 | | return true; // Pattern contains only '*', which matches anything |
| 301 | | } |
| 302 | | |
| 303 | | // Process characters before first star |
| 304 | | while(($ch = $patArr[$patIdxStart]) != '*' && $strIdxStart <= $strIdxEnd) { |
| 305 | | if ($ch != '?') { |
| 306 | | if ($isCaseSensitive && $ch !== $strArr[$strIdxStart]) { |
| 307 | | return false;// Character mismatch |
| 308 | | } |
| 309 | | if (!$isCaseSensitive && strtoupper($ch) !== |
| 310 | | strtoupper($strArr[$strIdxStart])) { |
| 311 | | return false;// Character mismatch |
| 312 | | } |
| 313 | | } |
| 314 | | $patIdxStart++; |
| 315 | | $strIdxStart++; |
| 316 | | } |
| 317 | | |
| 318 | | if ($strIdxStart > $strIdxEnd) { |
| 319 | | // All characters in the string are used. Check if only '*'s are |
| 320 | | // left in the pattern. If so, we succeeded. Otherwise failure. |
| 321 | | for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { |
| 322 | | if ($patArr[$i] != '*') { |
| 323 | | return false; |
| 324 | | } |
| 325 | | } |
| 326 | | return true; |
| 327 | | } |
| 328 | | |
| 329 | | // Process characters after last star |
| 330 | | while(($ch = $patArr[$patIdxEnd]) != '*' && $strIdxStart <= $strIdxEnd) { |
| 331 | | if ($ch != '?') { |
| 332 | | if ($isCaseSensitive && $ch !== $strArr[$strIdxEnd]) { |
| 333 | | return false;// Character mismatch |
| 334 | | } |
| 335 | | if (!$isCaseSensitive && strtoupper($ch) !== |
| 336 | | strtoupper($strArr[$strIdxEnd])) { |
| 337 | | return false;// Character mismatch |
| 338 | | } |
| 339 | | } |
| 340 | | $patIdxEnd--; |
| 341 | | $strIdxEnd--; |
| 342 | | } |
| 343 | | if ($strIdxStart > $strIdxEnd) { |
| 344 | | // All characters in the string are used. Check if only '*'s are |
| 345 | | // left in the pattern. If so, we succeeded. Otherwise failure. |
| 346 | | for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { |
| 347 | | if ($patArr[$i] != '*') { |
| 348 | | return false; |
| 349 | | } |
| 350 | | } |
| 351 | | return true; |
| 352 | | } |
| 353 | | |
| 354 | | // process pattern between stars. padIdxStart and patIdxEnd point |
| 355 | | // always to a '*'. |
| 356 | | while ($patIdxStart !== $patIdxEnd && $strIdxStart <= $strIdxEnd) { |
| 357 | | $patIdxTmp = -1; |
| 358 | | for ($i = $patIdxStart+1; $i <= $patIdxEnd; $i++) { |
| 359 | | if ($patArr[$i] == '*') { |
| 360 | | $patIdxTmp = $i; |
| 361 | | break; |
| 362 | | } |
| 363 | | } |
| 364 | | if ($patIdxTmp === $patIdxStart + 1) { |
| 365 | | // Two stars next to each other, skip the first one. |
| 366 | | $patIdxStart++; |
| 367 | | continue; |
| 368 | | } |
| 369 | | // Find the pattern between padIdxStart & padIdxTmp in str between |
| 370 | | // strIdxStart & strIdxEnd |
| 371 | | $patLength = ($patIdxTmp - $patIdxStart - 1); |
| 372 | | $strLength = ($strIdxEnd - $strIdxStart + 1); |
| 373 | | $foundIdx = -1; |
| 374 | | |
| 375 | | //strLoop: |
| 376 | | for ($i = 0; $i <= $strLength - $patLength; $i++) { |
| 377 | | for ($j = 0; $j < $patLength; $j++) { |
| 378 | | $ch = $patArr[$patIdxStart+$j+1]; |
| 379 | | if ($ch != '?') { |
| 380 | | if ($isCaseSensitive && $ch !== $strArr[$strIdxStart+$i+$j]) { |
| 381 | | continue 2; //continue to strLoop: |
| 382 | | } |
| 383 | | if (!$isCaseSensitive && strtoupper($ch) !== |
| 384 | | strtoupper($strArr[$strIdxStart+$i+$j])) { |
| 385 | | continue 2; //continue to strLoop: |
| 386 | | } |
| 387 | | } |
| 388 | | } |
| 389 | | // only reached if sub loop completed w/o invoking continue 2 |
| 390 | | $foundIdx = $strIdxStart + $i; |
| 391 | | break; |
| 392 | | } |
| 393 | | |
| 394 | | if ($foundIdx == -1) { |
| 395 | | return false; |
| 396 | | } |
| 397 | | |
| 398 | | $patIdxStart = $patIdxTmp; |
| 399 | | $strIdxStart = $foundIdx + $patLength; |
| 400 | | } |
| 401 | | |
| 402 | | // All characters in the string are used. Check if only '*'s are left |
| 403 | | // in the pattern. If so, we succeeded. Otherwise failure. |
| 404 | | for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { |
| 405 | | if ($patArr[$i] != '*') { |
| 406 | | return false; |
| 407 | | } |
| 408 | | } |
| 409 | | return true; |
| | 157 | $rePattern = preg_quote($pattern, '/'); |
| | 158 | $rePattern = str_replace(array("\*", "\?"), array('.*', '.'), $rePattern); |
| | 159 | $rePattern = '/^'.$rePattern.'$/'.($isCaseSensitive ? '' : 'i'); |
| | 160 | return preg_match($rePattern, $str); |