pattern => compiled regex */ private static $compiled = array(); /** * Does any of `$patterns` match `$subject`? * * @param string[] $patterns */ public static function any_match( array $patterns, string $subject ): bool { foreach ( $patterns as $p ) { $p = (string) $p; if ( '' === $p ) { continue; } if ( self::matches( $p, $subject ) ) { return true; } } return false; } public static function matches( string $pattern, string $subject ): bool { $regex = self::compile( $pattern ); // Anchored glob (regex returned starts with '#^') vs substring // (regex returned starts with '#'). Both use preg_match the // same way; the anchoring is baked into the pattern. return 1 === preg_match( $regex, $subject ); } /** * Compile a user pattern to a PCRE delimited with `#`. Cached * for the request lifetime. */ public static function compile( string $pattern ): string { if ( isset( self::$compiled[ $pattern ] ) ) { return self::$compiled[ $pattern ]; } // Decide mode based on UNESCAPED glob metacharacters only. // `\*` alone keeps the pattern in substring mode (with escapes // resolved); `/cart/*` flips to anchored glob mode. $has_unescaped_glob = (bool) preg_match( '/(?