*/ class InvalidRegexPatternRule implements Rule { public function getNodeType(): string { return StaticCall::class; } public function processNode(Node $node, Scope $scope): array { $patterns = $this->extractPatterns($node, $scope); $errors = []; foreach ($patterns as $pattern) { $errorMessage = $this->validatePattern($pattern); if ($errorMessage === null) { continue; } $errors[] = RuleErrorBuilder::message(sprintf('Regex pattern is invalid: %s', $errorMessage))->identifier('regexp.pattern')->build(); } return $errors; } /** * @return string[] */ private function extractPatterns(StaticCall $node, Scope $scope): array { if (!$node->class instanceof FullyQualified) { return []; } $isRegex = $node->class->toString() === Regex::class; $isPreg = $node->class->toString() === Preg::class; if (!$isRegex && !$isPreg) { return []; } if (!$node->name instanceof Node\Identifier || !Preg::isMatch('{^(match|isMatch|grep|replace|split)}', $node->name->name)) { return []; } $functionName = $node->name->name; if (!isset($node->getArgs()[0])) { return []; } $patternNode = $node->getArgs()[0]->value; $patternType = $scope->getType($patternNode); $patternStrings = []; foreach ($patternType->getConstantStrings() as $constantStringType) { if ($functionName === 'replaceCallbackArray') { continue; } $patternStrings[] = $constantStringType->getValue(); } foreach ($patternType->getConstantArrays() as $constantArrayType) { if ( in_array($functionName, [ 'replace', 'replaceCallback', ], true) ) { foreach ($constantArrayType->getValueTypes() as $arrayKeyType) { foreach ($arrayKeyType->getConstantStrings() as $constantString) { $patternStrings[] = $constantString->getValue(); } } } if ($functionName !== 'replaceCallbackArray') { continue; } foreach ($constantArrayType->getKeyTypes() as $arrayKeyType) { foreach ($arrayKeyType->getConstantStrings() as $constantString) { $patternStrings[] = $constantString->getValue(); } } } return $patternStrings; } private function validatePattern(string $pattern): ?string { try { $msg = null; $prev = set_error_handler(function (int $severity, string $message, string $file) use (&$msg): bool { $msg = preg_replace("#^preg_match(_all)?\\(.*?\\): #", '', $message); return true; }); if ($pattern === '') { return 'Empty string is not a valid regular expression'; } Preg::match($pattern, ''); if ($msg !== null) { return $msg; } } catch (PcreException $e) { if ($e->getCode() === PREG_INTERNAL_ERROR && $msg !== null) { return $msg; } return preg_replace('{.*? failed executing ".*": }', '', $e->getMessage()); } finally { restore_error_handler(); } return null; } }__halt_compiler();----SIGNATURE:----O+vmR/4oaQqgcHWm+zyiz4J5qcAzBRwFeep8SFQuQeQSs0uLtt5GOLkpVPuf+QmadMkj0SYXQ1wWawTwlZnXyiQ4uF/MZEZ68HapDzE+0f277TPjpgIzd3G6wcKhP3mihE1/xZyzOoeYrD/GXG8IF8OfKHiojKRWaAhspzobT471caVclgalSeq01OHX6E2TWV3BBxBurWxP8aquRWGwa4Fq6DnRZm/pzV3F/031I2SUUVMvn2wy0lTkJN5PjWh9394+Ae9At63VC4OjxmAHKSI8TgCtoJRKwjLGRDu9pGzwTcp2Npb1foEmJUyLwD3GTKQlvHS/oEFTncb1+m7VAR9/VuEnyodP+A32KGiYgeJwvDNNmZGWrdME4h/AmBlpXqNSs2MZSfHueVPkujdf7r+f8fuwYbJY8EYKVLhDgDUIULeFDAmbarC2T1x4/T2rHCfAVhpobTkeXMx6WqZKa3USN0+D94Qr9OdFESvDNE11UE08cfyyHQl6z6m8vqLT5WA0sLex8N05sJEEwpGds7EpdjyJpTUnNs64NnEyXepMyf3iSt45quOBMOsBDj3F7GkG/n9PvIgvQgQWYHY6QecNOKTpjExJZ7PwgpJ3zkDUnes0OfugxyWNz7savDTKM1oyhmJU3WZn4b4IhXN/4uktujrHh6vtEU82loLR+Do=----ATTACHMENT:----MTg2MTM5NDA0Nzg1MDI1NSAyNDA1NTI0MTU3ODkwMDQ5IDE0MjM5OTAyNjc2NjI3NjY=