{"record":{"id":"50048422e3e6b453","repo":"rectorphp/rector","slug":"unescaped-metacharacter-s","errorCode":null,"errorMessage":"unescaped metacharacter \"%s\"","messagePattern":"unescaped metacharacter \"(.+?)\"","errorType":"validation","errorClass":"InvalidEregException","httpStatus":null,"severity":"error","filePath":"rules/Php70/EregToPcreTransformer.php","lineNumber":125,"sourceCode":"                $cls = '';\n                if ($i < $l && $content[$i] === '^') {\n                    $cls .= '^';\n                    ++$i;\n                }\n                if ($i >= $l) {\n                    throw new InvalidEregException('\"[\" does not have a matching \"]\"');\n                }\n                $start = \\true;\n                $i = (int) $i;\n                [$cls, $i] = $this->processSquareBracket($content, $i, $l, $cls, $start);\n                if ($i >= $l) {\n                    throw new InvalidEregException('\"[\" does not have a matching \"]\"');\n                }\n                $r[$rr] .= '[' . $cls . ']';\n            } elseif ($char === ')') {\n                break;\n            } elseif (in_array($char, ['*', '+', '?'], \\true)) {\n                throw new InvalidEregException('unescaped metacharacter \"' . $char . '\"');\n            } elseif ($char === '{') {\n                if ($i + 1 < $l && strpos('0123456789', $content[$i + 1]) !== \\false) {\n                    $r[$rr] .= '\\{';\n                } else {\n                    throw new InvalidEregException('unescaped metacharacter \"' . $char . '\"');\n                }\n            } elseif ($char === '.') {\n                $r[$rr] .= $char;\n            } elseif ($char === '^' || $char === '$') {\n                $r[$rr] .= $char;\n                ++$i;\n                continue;\n            } elseif ($char === '|') {\n                if ($r[$rr] === '') {\n                    $normalizeUnprintableChar = \\true;\n                }\n                $r[] = '';\n                ++$rr;","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/rectorphp/rector/blob/408fcb0ff1833e3d26cbc9b04c23a77565814a16/rules/Php70/EregToPcreTransformer.php#L107-L143","documentation":"This InvalidEregException is thrown when the ERE-to-PCRE converter meets a quantifier character '*', '+' or '?' at a position where there is no preceding atom to quantify — the start of the pattern or the start of a branch after '|', or two quantifiers in a row. In POSIX ERE such input is invalid, so EregToPcreTransformer refuses it (EregToPcreTransformer.php:125) and the ereg-to-preg conversion stops.","triggerScenarios":"Rector (Php70 set / EregToPregMatchRector, target PHP >= 7.0) encounters an ereg-family call whose literal pattern begins with or contains a bare quantifier, e.g. `ereg('*abc', $s)`, `split('a|+b', $s)`, or `ereg('a**', $s)` where the second '*' is parsed as a new atom. The atom loop sees '*', '+' or '?' where an atom is required and throws with the offending character in the message.","commonSituations":"Legacy grep/sed-style patterns pasted into ereg calls where a leading '*' was 'grep-ish' habit; broken edits that deleted the atom but kept the quantifier; glob-like patterns ('*.txt') mistakenly used as regexes in split()/ereg().","solutions":["Fix the pattern in the source file Rector reported: remove the orphan quantifier ('*abc' -> 'abc') or escape it ('\\*\\.txt') if it is meant literally.","If the string was a glob, not a regex, switch the legacy call to fnmatch()-style logic instead of letting rector convert it to preg_match.","Re-run rector; preflight-scan literal ereg/split patterns for leading or doubled quantifiers in big migrations."],"exampleFix":"// before - quantifier with no atom (glob habit)\nereg('*.txt', $filename);\n\n// after - escaped literal\nereg('\\*\\.txt', $filename); // rector: preg_match('#\\*\\.txt#m', $filename)","handlingStrategy":"try-catch","validationCode":"// quick lint: quantifier at pattern start or after '|' / another quantifier\nfunction hasOrphanQuantifier(string $p): bool {\n    return (bool) preg_match('~(^|\\||[+*?])[+*?]~', $p);\n}","typeGuard":null,"tryCatchPattern":"try {\n    $pcre = $eregToPcreTransformer->transform($pattern, $ignoreCase);\n} catch (InvalidEregException $e) {\n    // '*'/'+'/'?' with no atom to quantify — remove or escape it, then re-run\n    continue;\n}","preventionTips":["Remember ereg()/split() take POSIX ERE, not globs: '*.txt' is invalid, '\\*\\.txt' is correct.","Escape literal *, +, ? characters in legacy patterns.","Lint literal patterns for quantifiers at start-of-pattern or start-of-branch before migrations."],"tags":["rector","php","regex","posix-ere","quantifier","migration"],"backgroundTag":"invalid-regex-syntax","analyzedSha":"408fcb0ff1833e3d26cbc9b04c23a77565814a16","analyzedAt":"2026-08-21T05:11:02.643Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}