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