$matches[0], '$1' => $matches[1] ] ); }, $subject, $flags ); } /** * More or less "markup-safe" str_replace() * Ignores any instances of the separator inside `<...>` * @param string $search * @param string $replace * @param string $text * @return string */ public static function replaceMarkup( $search, $replace, $text ) { $placeholder = "\x00"; // Remove placeholder instances $text = str_replace( $placeholder, '', $text ); // Replace instances of the separator inside HTML-like tags with the placeholder $cleaned = self::delimiterReplaceCallback( '<', '>', static function ( array $matches ) use ( $search, $placeholder ) { return str_replace( $search, $placeholder, $matches[0] ); }, $text ); // Explode, then put the replaced separators back in $cleaned = str_replace( $search, $replace, $cleaned ); $text = str_replace( $placeholder, $search, $cleaned ); return $text; } /** * Utility function to check if the given string is a valid PCRE regex. Avoids * manually calling suppressWarnings and restoreWarnings, and provides a * one-line solution without the need to use @. * * @since 1.34 * @param string $string The string you want to check being a valid regex * @return bool */ public static function isValidPCRERegex( $string ) { AtEase::suppressWarnings(); // @phan-suppress-next-line PhanParamSuspiciousOrder False positive $isValid = preg_match( $string, '' ); AtEase::restoreWarnings(); return $isValid !== false; } /** * Escape a string to make it suitable for inclusion in a preg_replace() * replacement parameter. * * @param string $string * @return string */ public static function escapeRegexReplacement( $string ) { $string = str_replace( '\\', '\\\\', $string ); return str_replace( '$', '\\$', $string ); } /** * Workalike for explode() with limited memory usage. * * @param string $separator * @param string $subject * @return ArrayIterator|ExplodeIterator */ public static function explode( $separator, $subject ) { if ( substr_count( $subject, $separator ) > 1000 ) { return new ExplodeIterator( $separator, $subject ); } else { return new ArrayIterator( explode( $separator, $subject ) ); } } /** * Wrapper around php's unpack. * * @param string $format The format string (See php's docs) * @param string $data A binary string of binary data * @param int|false $length The minimum length of $data or false. This is to * prevent reading beyond the end of $data. false to disable the check. * * Also be careful when using this function to read unsigned 32 bit integer * because php might make it negative. * * @throws UnpackFailedException If $data not long enough, or if unpack fails * @return array Associative array of the extracted data * @since 1.42 */ public static function unpack( string $format, string $data, $length = false ): array { Assert::parameterType( [ 'integer', 'false' ], $length, '$length' ); if ( $length !== false ) { $realLen = strlen( $data ); if ( $realLen < $length ) { throw new UnpackFailedException( "Tried to unpack a " . "string of length $realLen, but needed one " . "of at least length $length." ); } } AtEase::suppressWarnings(); $result = unpack( $format, $data ); AtEase::restoreWarnings(); if ( $result === false ) { // If it cannot extract the packed data. throw new UnpackFailedException( "unpack could not unpack binary data" ); } return $result; } }