PluginProbe ʕ •ᴥ•ʔ
Kubio AI Page Builder / 2.8.4
Kubio AI Page Builder v2.8.4
2.8.4 2.8.3 2.8.2 2.8.1 trunk 1.0.0 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.9.0 2.0.0 2.1.1 2.1.2 2.1.3 2.2.0 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.5 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.6.1 2.6.2 2.6.3 2.6.5 2.6.6 2.6.7 2.7.0 2.7.1 2.7.2 2.7.3 2.8.0
kubio / vendor / symfony / string / ByteString.php
kubio / vendor / symfony / string Last commit date
Exception 1 year ago Inflector 1 year ago Resources 1 year ago Slugger 1 year ago AbstractString.php 1 year ago AbstractUnicodeString.php 1 year ago ByteString.php 1 year ago CHANGELOG.md 1 year ago CodePointString.php 1 year ago LICENSE 1 year ago LazyString.php 1 year ago README.md 1 year ago UnicodeString.php 1 year ago composer.json 1 year ago
ByteString.php
510 lines
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Symfony\Component\String;
13
14 use Symfony\Component\String\Exception\ExceptionInterface;
15 use Symfony\Component\String\Exception\InvalidArgumentException;
16 use Symfony\Component\String\Exception\RuntimeException;
17
18 /**
19 * Represents a binary-safe string of bytes.
20 *
21 * @author Nicolas Grekas <p@tchwork.com>
22 * @author Hugo Hamon <hugohamon@neuf.fr>
23 *
24 * @throws ExceptionInterface
25 */
26 class ByteString extends AbstractString
27 {
28 private const ALPHABET_ALPHANUMERIC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
29
30 public function __construct(string $string = '')
31 {
32 $this->string = $string;
33 }
34
35 /*
36 * The following method was derived from code of the Hack Standard Library (v4.40 - 2020-05-03)
37 *
38 * https://github.com/hhvm/hsl/blob/80a42c02f036f72a42f0415e80d6b847f4bf62d5/src/random/private.php#L16
39 *
40 * Code subject to the MIT license (https://github.com/hhvm/hsl/blob/master/LICENSE).
41 *
42 * Copyright (c) 2004-2020, Facebook, Inc. (https://www.facebook.com/)
43 */
44
45 public static function fromRandom(int $length = 16, ?string $alphabet = null): self
46 {
47 if ($length <= 0) {
48 throw new InvalidArgumentException(sprintf('A strictly positive length is expected, "%d" given.', $length));
49 }
50
51 $alphabet = $alphabet ?? self::ALPHABET_ALPHANUMERIC;
52 $alphabetSize = \strlen($alphabet);
53 $bits = (int) ceil(log($alphabetSize, 2.0));
54 if ($bits <= 0 || $bits > 56) {
55 throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.');
56 }
57
58 $ret = '';
59 while ($length > 0) {
60 $urandomLength = (int) ceil(2 * $length * $bits / 8.0);
61 $data = random_bytes($urandomLength);
62 $unpackedData = 0;
63 $unpackedBits = 0;
64 for ($i = 0; $i < $urandomLength && $length > 0; ++$i) {
65 // Unpack 8 bits
66 $unpackedData = ($unpackedData << 8) | \ord($data[$i]);
67 $unpackedBits += 8;
68
69 // While we have enough bits to select a character from the alphabet, keep
70 // consuming the random data
71 for (; $unpackedBits >= $bits && $length > 0; $unpackedBits -= $bits) {
72 $index = ($unpackedData & ((1 << $bits) - 1));
73 $unpackedData >>= $bits;
74 // Unfortunately, the alphabet size is not necessarily a power of two.
75 // Worst case, it is 2^k + 1, which means we need (k+1) bits and we
76 // have around a 50% chance of missing as k gets larger
77 if ($index < $alphabetSize) {
78 $ret .= $alphabet[$index];
79 --$length;
80 }
81 }
82 }
83 }
84
85 return new static($ret);
86 }
87
88 public function bytesAt(int $offset): array
89 {
90 $str = $this->string[$offset] ?? '';
91
92 return '' === $str ? [] : [\ord($str)];
93 }
94
95 public function append(string ...$suffix): parent
96 {
97 $str = clone $this;
98 $str->string .= 1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix);
99
100 return $str;
101 }
102
103 public function camel(): parent
104 {
105 $str = clone $this;
106
107 $parts = explode(' ', trim(ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->string))));
108 $parts[0] = 1 !== \strlen($parts[0]) && ctype_upper($parts[0]) ? $parts[0] : lcfirst($parts[0]);
109 $str->string = implode('', $parts);
110
111 return $str;
112 }
113
114 public function chunk(int $length = 1): array
115 {
116 if (1 > $length) {
117 throw new InvalidArgumentException('The chunk length must be greater than zero.');
118 }
119
120 if ('' === $this->string) {
121 return [];
122 }
123
124 $str = clone $this;
125 $chunks = [];
126
127 foreach (str_split($this->string, $length) as $chunk) {
128 $str->string = $chunk;
129 $chunks[] = clone $str;
130 }
131
132 return $chunks;
133 }
134
135 public function endsWith($suffix): bool
136 {
137 if ($suffix instanceof parent) {
138 $suffix = $suffix->string;
139 } elseif (\is_array($suffix) || $suffix instanceof \Traversable) {
140 return parent::endsWith($suffix);
141 } else {
142 $suffix = (string) $suffix;
143 }
144
145 return '' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase);
146 }
147
148 public function equalsTo($string): bool
149 {
150 if ($string instanceof parent) {
151 $string = $string->string;
152 } elseif (\is_array($string) || $string instanceof \Traversable) {
153 return parent::equalsTo($string);
154 } else {
155 $string = (string) $string;
156 }
157
158 if ('' !== $string && $this->ignoreCase) {
159 return 0 === strcasecmp($string, $this->string);
160 }
161
162 return $string === $this->string;
163 }
164
165 public function folded(): parent
166 {
167 $str = clone $this;
168 $str->string = strtolower($str->string);
169
170 return $str;
171 }
172
173 public function indexOf($needle, int $offset = 0): ?int
174 {
175 if ($needle instanceof parent) {
176 $needle = $needle->string;
177 } elseif (\is_array($needle) || $needle instanceof \Traversable) {
178 return parent::indexOf($needle, $offset);
179 } else {
180 $needle = (string) $needle;
181 }
182
183 if ('' === $needle) {
184 return null;
185 }
186
187 $i = $this->ignoreCase ? stripos($this->string, $needle, $offset) : strpos($this->string, $needle, $offset);
188
189 return false === $i ? null : $i;
190 }
191
192 public function indexOfLast($needle, int $offset = 0): ?int
193 {
194 if ($needle instanceof parent) {
195 $needle = $needle->string;
196 } elseif (\is_array($needle) || $needle instanceof \Traversable) {
197 return parent::indexOfLast($needle, $offset);
198 } else {
199 $needle = (string) $needle;
200 }
201
202 if ('' === $needle) {
203 return null;
204 }
205
206 $i = $this->ignoreCase ? strripos($this->string, $needle, $offset) : strrpos($this->string, $needle, $offset);
207
208 return false === $i ? null : $i;
209 }
210
211 public function isUtf8(): bool
212 {
213 return '' === $this->string || preg_match('//u', $this->string);
214 }
215
216 public function join(array $strings, ?string $lastGlue = null): parent
217 {
218 $str = clone $this;
219
220 $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue.array_pop($strings) : '';
221 $str->string = implode($this->string, $strings).$tail;
222
223 return $str;
224 }
225
226 public function length(): int
227 {
228 return \strlen($this->string);
229 }
230
231 public function lower(): parent
232 {
233 $str = clone $this;
234 $str->string = strtolower($str->string);
235
236 return $str;
237 }
238
239 public function match(string $regexp, int $flags = 0, int $offset = 0): array
240 {
241 $match = ((\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match';
242
243 if ($this->ignoreCase) {
244 $regexp .= 'i';
245 }
246
247 set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
248
249 try {
250 if (false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) {
251 $lastError = preg_last_error();
252
253 foreach (get_defined_constants(true)['pcre'] as $k => $v) {
254 if ($lastError === $v && '_ERROR' === substr($k, -6)) {
255 throw new RuntimeException('Matching failed with '.$k.'.');
256 }
257 }
258
259 throw new RuntimeException('Matching failed with unknown error code.');
260 }
261 } finally {
262 restore_error_handler();
263 }
264
265 return $matches;
266 }
267
268 public function padBoth(int $length, string $padStr = ' '): parent
269 {
270 $str = clone $this;
271 $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_BOTH);
272
273 return $str;
274 }
275
276 public function padEnd(int $length, string $padStr = ' '): parent
277 {
278 $str = clone $this;
279 $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_RIGHT);
280
281 return $str;
282 }
283
284 public function padStart(int $length, string $padStr = ' '): parent
285 {
286 $str = clone $this;
287 $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_LEFT);
288
289 return $str;
290 }
291
292 public function prepend(string ...$prefix): parent
293 {
294 $str = clone $this;
295 $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$str->string;
296
297 return $str;
298 }
299
300 public function replace(string $from, string $to): parent
301 {
302 $str = clone $this;
303
304 if ('' !== $from) {
305 $str->string = $this->ignoreCase ? str_ireplace($from, $to, $this->string) : str_replace($from, $to, $this->string);
306 }
307
308 return $str;
309 }
310
311 public function replaceMatches(string $fromRegexp, $to): parent
312 {
313 if ($this->ignoreCase) {
314 $fromRegexp .= 'i';
315 }
316
317 if (\is_array($to)) {
318 if (!\is_callable($to)) {
319 throw new \TypeError(sprintf('Argument 2 passed to "%s::replaceMatches()" must be callable, array given.', static::class));
320 }
321
322 $replace = 'preg_replace_callback';
323 } else {
324 $replace = $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace';
325 }
326
327 set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
328
329 try {
330 if (null === $string = $replace($fromRegexp, $to, $this->string)) {
331 $lastError = preg_last_error();
332
333 foreach (get_defined_constants(true)['pcre'] as $k => $v) {
334 if ($lastError === $v && '_ERROR' === substr($k, -6)) {
335 throw new RuntimeException('Matching failed with '.$k.'.');
336 }
337 }
338
339 throw new RuntimeException('Matching failed with unknown error code.');
340 }
341 } finally {
342 restore_error_handler();
343 }
344
345 $str = clone $this;
346 $str->string = $string;
347
348 return $str;
349 }
350
351 public function reverse(): parent
352 {
353 $str = clone $this;
354 $str->string = strrev($str->string);
355
356 return $str;
357 }
358
359 public function slice(int $start = 0, ?int $length = null): parent
360 {
361 $str = clone $this;
362 $str->string = (string) substr($this->string, $start, $length ?? \PHP_INT_MAX);
363
364 return $str;
365 }
366
367 public function snake(): parent
368 {
369 $str = $this->camel();
370 $str->string = strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], '\1_\2', $str->string));
371
372 return $str;
373 }
374
375 public function splice(string $replacement, int $start = 0, ?int $length = null): parent
376 {
377 $str = clone $this;
378 $str->string = substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX);
379
380 return $str;
381 }
382
383 public function split(string $delimiter, ?int $limit = null, ?int $flags = null): array
384 {
385 if (1 > $limit = $limit ?? \PHP_INT_MAX) {
386 throw new InvalidArgumentException('Split limit must be a positive integer.');
387 }
388
389 if ('' === $delimiter) {
390 throw new InvalidArgumentException('Split delimiter is empty.');
391 }
392
393 if (null !== $flags) {
394 return parent::split($delimiter, $limit, $flags);
395 }
396
397 $str = clone $this;
398 $chunks = $this->ignoreCase
399 ? preg_split('{'.preg_quote($delimiter).'}iD', $this->string, $limit)
400 : explode($delimiter, $this->string, $limit);
401
402 foreach ($chunks as &$chunk) {
403 $str->string = $chunk;
404 $chunk = clone $str;
405 }
406
407 return $chunks;
408 }
409
410 public function startsWith($prefix): bool
411 {
412 if ($prefix instanceof parent) {
413 $prefix = $prefix->string;
414 } elseif (!\is_string($prefix)) {
415 return parent::startsWith($prefix);
416 }
417
418 return '' !== $prefix && 0 === ($this->ignoreCase ? strncasecmp($this->string, $prefix, \strlen($prefix)) : strncmp($this->string, $prefix, \strlen($prefix)));
419 }
420
421 public function title(bool $allWords = false): parent
422 {
423 $str = clone $this;
424 $str->string = $allWords ? ucwords($str->string) : ucfirst($str->string);
425
426 return $str;
427 }
428
429 public function toUnicodeString(?string $fromEncoding = null): UnicodeString
430 {
431 return new UnicodeString($this->toCodePointString($fromEncoding)->string);
432 }
433
434 public function toCodePointString(?string $fromEncoding = null): CodePointString
435 {
436 $u = new CodePointString();
437
438 if (\in_array($fromEncoding, [null, 'utf8', 'utf-8', 'UTF8', 'UTF-8'], true) && preg_match('//u', $this->string)) {
439 $u->string = $this->string;
440
441 return $u;
442 }
443
444 set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
445
446 try {
447 try {
448 $validEncoding = false !== mb_detect_encoding($this->string, $fromEncoding ?? 'Windows-1252', true);
449 } catch (InvalidArgumentException $e) {
450 if (!\function_exists('iconv')) {
451 throw $e;
452 }
453
454 $u->string = iconv($fromEncoding ?? 'Windows-1252', 'UTF-8', $this->string);
455
456 return $u;
457 }
458 } finally {
459 restore_error_handler();
460 }
461
462 if (!$validEncoding) {
463 throw new InvalidArgumentException(sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252'));
464 }
465
466 $u->string = mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252');
467
468 return $u;
469 }
470
471 public function trim(string $chars = " \t\n\r\0\x0B\x0C"): parent
472 {
473 $str = clone $this;
474 $str->string = trim($str->string, $chars);
475
476 return $str;
477 }
478
479 public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C"): parent
480 {
481 $str = clone $this;
482 $str->string = rtrim($str->string, $chars);
483
484 return $str;
485 }
486
487 public function trimStart(string $chars = " \t\n\r\0\x0B\x0C"): parent
488 {
489 $str = clone $this;
490 $str->string = ltrim($str->string, $chars);
491
492 return $str;
493 }
494
495 public function upper(): parent
496 {
497 $str = clone $this;
498 $str->string = strtoupper($str->string);
499
500 return $str;
501 }
502
503 public function width(bool $ignoreAnsiDecoration = true): int
504 {
505 $string = preg_match('//u', $this->string) ? $this->string : preg_replace('/[\x80-\xFF]/', '?', $this->string);
506
507 return (new CodePointString($string))->width($ignoreAnsiDecoration);
508 }
509 }
510