35 public static function isUtf8( $value ) {
36 return mb_check_encoding( (
string)$value,
'UTF-8' );
51 $subject, $nested =
false ) {
55 $encStart = preg_quote( $startDelim,
'!' );
56 $encEnd = preg_quote( $endDelim,
'!' );
57 $encSep = preg_quote( $separator,
'!' );
58 $len = strlen( $subject );
64 "!$encStart|$encEnd|$encSep!S", $subject, $m,
65 PREG_OFFSET_CAPTURE, $inputPos
70 $inputPos = $matchPos + strlen( $match );
71 if ( $match === $separator ) {
74 $subject, $lastPos, $matchPos - $lastPos
78 } elseif ( $match === $startDelim ) {
79 if ( $depth === 0 || $nested ) {
86 $exploded[] = substr( $subject, $lastPos );
89 return new ArrayIterator( $exploded );
110 $segments =
explode( $startDelim, $subject );
111 $output = array_shift( $segments );
112 foreach ( $segments as $s ) {
113 $endDelimPos = strpos( $s, $endDelim );
114 if ( $endDelimPos ===
false ) {
115 $output .= $startDelim . $s;
117 $output .= $replace . substr( $s, $endDelimPos + strlen( $endDelim ) );
147 private static function delimiterReplaceCallback( $startDelim, $endDelim, $callback,
148 $subject, $flags =
''
155 $encStart = preg_quote( $startDelim,
'!' );
156 $encEnd = preg_quote( $endDelim,
'!' );
157 $strcmp = !str_contains( $flags,
'i' ) ?
'strcmp' :
'strcasecmp';
158 $endLength = strlen( $endDelim );
161 while ( $inputPos < strlen( $subject ) &&
162 preg_match(
"!($encStart)|($encEnd)!S$flags", $subject, $m, PREG_OFFSET_CAPTURE, $inputPos )
164 $tokenOffset = $m[0][1];
165 if ( $m[1][0] !=
'' ) {
167 $strcmp( $endDelim, substr( $subject, $tokenOffset, $endLength ) ) == 0
169 # An end match is present at the same location
171 $tokenLength = $endLength;
173 $tokenType =
'start';
174 $tokenLength = strlen( $m[0][0] );
176 } elseif ( $m[2][0] !=
'' ) {
178 $tokenLength = strlen( $m[0][0] );
180 throw new InvalidArgumentException(
'Invalid delimiter given to ' . __METHOD__ );
183 if ( $tokenType ==
'start' ) {
184 # Only move the start position if we haven't already found a start
185 # This means that START START END matches outer pair
186 if ( !$foundStart ) {
188 $inputPos = $tokenOffset + $tokenLength;
189 # Write out the non-matching section
190 $output .= substr( $subject, $outputPos, $tokenOffset - $outputPos );
191 $outputPos = $tokenOffset;
192 $contentPos = $inputPos;
195 # Move the input position past the *first character* of START,
196 # to protect against missing END when it overlaps with START
197 $inputPos = $tokenOffset + 1;
199 } elseif ( $tokenType ==
'end' ) {
202 $output .= $callback( [
203 substr( $subject, $outputPos, $tokenOffset + $tokenLength - $outputPos ),
204 substr( $subject, $contentPos, $tokenOffset - $contentPos )
208 # Non-matching end, write it out
209 $output .= substr( $subject, $inputPos, $tokenOffset + $tokenLength - $outputPos );
211 $inputPos = $outputPos = $tokenOffset + $tokenLength;
213 throw new InvalidArgumentException(
'Invalid delimiter given to ' . __METHOD__ );
216 if ( $outputPos < strlen( $subject ) ) {
217 $output .= substr( $subject, $outputPos );
239 $startDelim, $endDelim, $replace, $subject, $flags =
''
241 return self::delimiterReplaceCallback(
242 $startDelim, $endDelim,
243 static function ( array
$matches ) use ( $replace ) {
259 $placeholder =
"\x00";
262 $text = str_replace( $placeholder,
'', $text );
265 $cleaned = self::delimiterReplaceCallback(
267 static function ( array
$matches ) use ( $search, $placeholder ) {
268 return str_replace( $search, $placeholder,
$matches[0] );
274 $cleaned = str_replace( $search, $replace, $cleaned );
275 $text = str_replace( $placeholder, $search, $cleaned );
291 return @preg_match( $string,
'' ) !==
false;
302 $string = str_replace(
'\\',
'\\\\', $string );
303 return str_replace(
'$',
'\\$', $string );
313 public static function explode( $separator, $subject ) {
314 if ( substr_count( $subject, $separator ) > 1000 ) {
317 return new ArrayIterator(
explode( $separator, $subject ) );
336 public static function unpack(
string $format,
string $data, $length =
false ): array {
337 Assert::parameterType( [
'integer',
'false' ], $length,
'$length' );
338 if ( $length !==
false ) {
339 $realLen = strlen( $data );
340 if ( $realLen < $length ) {
342 .
"string of length $realLen, but needed one "
343 .
"of at least length $length."
349 $result = @
unpack( $format, $data );
351 if ( $result ===
false ) {