*/ 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:----jD9VrsHfmAa/HEI2J386NdLQLEWixeKh+Vus6FZEcty5VEPd/JZseDqlo7xTZ+WD0mwbvrwQCtoV+MdO4ISHSg2cLw41Suxlu9xsQSGRd04OT1OgjyRDjPJEqhw9Q3gP95X9T7+o0Rkj15QO7eSh9bwiYyXracXHkQGPbeKcOilJjDXArNU336WHVzCg99zHMiGoTlPpy/Tij0/25cE8znchkbNGmxiresxAxIRdrH0YKxIqtmmJMUidrnSsQbPSaolG6VyoYoH4NXN2NsXXJ1Lh8g6lPUDFNCoFrG5KyGdLzRScCzdYACY+zt+hYeXTHN60AcxUuyk9T0x7y5rTpr3RCXb+MYNW8k0QA7Anyf56IRlota/yqIkVoWDbkX0l+gkJEfUPcvO/49BqYom3OhZJvhJLxqPbJZIAbTGjDnvV3xz2Vgr0EQC149EZjbN9vnSraqWem3rUIcJdKopA2VjvIMvnP95dBWoaHsy5EiT2CHfcic3la2JuoG9eDVup/6oTZ4TLzxRriC05b9zStpt6Kd48IvlKkhjL55GommYfjDC9aUz+3dFfT8IEFYuR0/2t9lKW9vgJRwoMO1Zbd6De05h+vzceQhhykwRocT7qdSkEMejfug17zcXH3Udj+AdHryWg0D3OTnz4h5xTfU3Aron3Fn3Uiop/RIcH4+c=----ATTACHMENT:----NzU2MTQ5Mjg2MTMwOTI1NCAzMjc2MDYwMTM3MzcwMDU2IDI5NjYzNTgyODEyNjA1OQ==