user4492612
user4492612

Reputation:

Error: Nothing to repeat at offset error during a preg_match_all in PHP

I need to find if a file name contains some special characters I don't want.

I'm using this code actually:

$files = array("logo.png", "légo.png");
$badChars = array(" ", "é", "É", "è", "È", "à", "À", "ç", "Ç", "¨", "^", "=", "/", "*", "-", "+", "'", "<", ">", ":", ";", ",", "`", "~", "/", "", "|", "!", "@", "#", "$", "%", "?", "&", "(", ")", "¬", "{", "}", "[", "]", "ù", "Ù", '"', "«", "»");
$matches = array();

foreach($files as $file) {
    $matchFound = preg_match_all("#\b(" . implode("|", $badChars) . ")\b#i", $file, $matches);
}
if ($matchFound) {
    $words = array_unique($matches[0]);
    foreach($words as $word) {
        $results[] = array('Error' => "Forbided chars found : ". $word);
    }
}
else {
    $results[] = array('Success' => "OK.");
}

But I have an error saying:

Warning: preg_match_all(): Compilation failed: nothing to repeat at offset 38 in /home/public_html/upload.php on line 138

Which is:

$matchFound = preg_match_all("#\b(" . implode("|", $badChars) . ")\b#i", $file, $matches);

Any help or clue?

Upvotes: 0

Views: 2733

Answers (2)

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89574

it is because ? * + are quantifiers. Since they are not escaped you obtain this error: |? there is obviously nothing to repeat.

For your task you don't need to use an alternation, a character class should suffice:

if (preg_match_all('~[] éèàç¨^=/*-+\'<>:;,`\~/|!@#$%?&()¬{}[ù"«»]~ui', $file, $m)) {
    $m = array_unique($m[0]);
    $m = array_map(function ($i) use ($file) { return array('Error' => 'Forbidden character found : ' . $i . ' in ' . $file); }, $m);
    $results = array_merge($results, $m);
}

or perhaps this pattern: ~[^[:alnum:]]~

Upvotes: 1

nickb
nickb

Reputation: 59709

It's because your characters have * in it, which tries to repeat the previous character, which in your case ends up being |, which is invalid. Your regex turns into:

..... |/|*|-| .....

Map preg_quote() to your character array before your loop and you'll be fine:

$badChars = array_map( 'preg_quote', $badChars);

Just make sure that since you're not specifying your delimiter # in the call to preg_quote(), you'll have to manually escape it in your $badChars array.

Upvotes: 1

Related Questions