@@ -26,103 +26,103 @@ |
||
26 | 26 | */ |
27 | 27 | trait ServiceLocatorTrait |
28 | 28 | { |
29 | - private $factories; |
|
30 | - private $loading = []; |
|
31 | - private $providedTypes; |
|
32 | - |
|
33 | - /** |
|
34 | - * @param callable[] $factories |
|
35 | - */ |
|
36 | - public function __construct(array $factories) |
|
37 | - { |
|
38 | - $this->factories = $factories; |
|
39 | - } |
|
40 | - |
|
41 | - /** |
|
42 | - * {@inheritdoc} |
|
43 | - * |
|
44 | - * @return bool |
|
45 | - */ |
|
46 | - public function has(string $id) |
|
47 | - { |
|
48 | - return isset($this->factories[$id]); |
|
49 | - } |
|
50 | - |
|
51 | - /** |
|
52 | - * {@inheritdoc} |
|
53 | - * |
|
54 | - * @return mixed |
|
55 | - */ |
|
56 | - public function get(string $id) |
|
57 | - { |
|
58 | - if (!isset($this->factories[$id])) { |
|
59 | - throw $this->createNotFoundException($id); |
|
60 | - } |
|
61 | - |
|
62 | - if (isset($this->loading[$id])) { |
|
63 | - $ids = array_values($this->loading); |
|
64 | - $ids = \array_slice($this->loading, array_search($id, $ids)); |
|
65 | - $ids[] = $id; |
|
66 | - |
|
67 | - throw $this->createCircularReferenceException($id, $ids); |
|
68 | - } |
|
69 | - |
|
70 | - $this->loading[$id] = $id; |
|
71 | - try { |
|
72 | - return $this->factories[$id]($this); |
|
73 | - } finally { |
|
74 | - unset($this->loading[$id]); |
|
75 | - } |
|
76 | - } |
|
77 | - |
|
78 | - /** |
|
79 | - * {@inheritdoc} |
|
80 | - */ |
|
81 | - public function getProvidedServices(): array |
|
82 | - { |
|
83 | - if (null === $this->providedTypes) { |
|
84 | - $this->providedTypes = []; |
|
85 | - |
|
86 | - foreach ($this->factories as $name => $factory) { |
|
87 | - if (!\is_callable($factory)) { |
|
88 | - $this->providedTypes[$name] = '?'; |
|
89 | - } else { |
|
90 | - $type = (new \ReflectionFunction($factory))->getReturnType(); |
|
91 | - |
|
92 | - $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; |
|
93 | - } |
|
94 | - } |
|
95 | - } |
|
96 | - |
|
97 | - return $this->providedTypes; |
|
98 | - } |
|
99 | - |
|
100 | - private function createNotFoundException(string $id): NotFoundExceptionInterface |
|
101 | - { |
|
102 | - if (!$alternatives = array_keys($this->factories)) { |
|
103 | - $message = 'is empty...'; |
|
104 | - } else { |
|
105 | - $last = array_pop($alternatives); |
|
106 | - if ($alternatives) { |
|
107 | - $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); |
|
108 | - } else { |
|
109 | - $message = sprintf('only knows about the "%s" service.', $last); |
|
110 | - } |
|
111 | - } |
|
112 | - |
|
113 | - if ($this->loading) { |
|
114 | - $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); |
|
115 | - } else { |
|
116 | - $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); |
|
117 | - } |
|
118 | - |
|
119 | - return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { |
|
120 | - }; |
|
121 | - } |
|
122 | - |
|
123 | - private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface |
|
124 | - { |
|
125 | - return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { |
|
126 | - }; |
|
127 | - } |
|
29 | + private $factories; |
|
30 | + private $loading = []; |
|
31 | + private $providedTypes; |
|
32 | + |
|
33 | + /** |
|
34 | + * @param callable[] $factories |
|
35 | + */ |
|
36 | + public function __construct(array $factories) |
|
37 | + { |
|
38 | + $this->factories = $factories; |
|
39 | + } |
|
40 | + |
|
41 | + /** |
|
42 | + * {@inheritdoc} |
|
43 | + * |
|
44 | + * @return bool |
|
45 | + */ |
|
46 | + public function has(string $id) |
|
47 | + { |
|
48 | + return isset($this->factories[$id]); |
|
49 | + } |
|
50 | + |
|
51 | + /** |
|
52 | + * {@inheritdoc} |
|
53 | + * |
|
54 | + * @return mixed |
|
55 | + */ |
|
56 | + public function get(string $id) |
|
57 | + { |
|
58 | + if (!isset($this->factories[$id])) { |
|
59 | + throw $this->createNotFoundException($id); |
|
60 | + } |
|
61 | + |
|
62 | + if (isset($this->loading[$id])) { |
|
63 | + $ids = array_values($this->loading); |
|
64 | + $ids = \array_slice($this->loading, array_search($id, $ids)); |
|
65 | + $ids[] = $id; |
|
66 | + |
|
67 | + throw $this->createCircularReferenceException($id, $ids); |
|
68 | + } |
|
69 | + |
|
70 | + $this->loading[$id] = $id; |
|
71 | + try { |
|
72 | + return $this->factories[$id]($this); |
|
73 | + } finally { |
|
74 | + unset($this->loading[$id]); |
|
75 | + } |
|
76 | + } |
|
77 | + |
|
78 | + /** |
|
79 | + * {@inheritdoc} |
|
80 | + */ |
|
81 | + public function getProvidedServices(): array |
|
82 | + { |
|
83 | + if (null === $this->providedTypes) { |
|
84 | + $this->providedTypes = []; |
|
85 | + |
|
86 | + foreach ($this->factories as $name => $factory) { |
|
87 | + if (!\is_callable($factory)) { |
|
88 | + $this->providedTypes[$name] = '?'; |
|
89 | + } else { |
|
90 | + $type = (new \ReflectionFunction($factory))->getReturnType(); |
|
91 | + |
|
92 | + $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; |
|
93 | + } |
|
94 | + } |
|
95 | + } |
|
96 | + |
|
97 | + return $this->providedTypes; |
|
98 | + } |
|
99 | + |
|
100 | + private function createNotFoundException(string $id): NotFoundExceptionInterface |
|
101 | + { |
|
102 | + if (!$alternatives = array_keys($this->factories)) { |
|
103 | + $message = 'is empty...'; |
|
104 | + } else { |
|
105 | + $last = array_pop($alternatives); |
|
106 | + if ($alternatives) { |
|
107 | + $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); |
|
108 | + } else { |
|
109 | + $message = sprintf('only knows about the "%s" service.', $last); |
|
110 | + } |
|
111 | + } |
|
112 | + |
|
113 | + if ($this->loading) { |
|
114 | + $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); |
|
115 | + } else { |
|
116 | + $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); |
|
117 | + } |
|
118 | + |
|
119 | + return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { |
|
120 | + }; |
|
121 | + } |
|
122 | + |
|
123 | + private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface |
|
124 | + { |
|
125 | + return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { |
|
126 | + }; |
|
127 | + } |
|
128 | 128 | } |
@@ -21,46 +21,46 @@ |
||
21 | 21 | */ |
22 | 22 | trait ServiceSubscriberTrait |
23 | 23 | { |
24 | - /** @var ContainerInterface */ |
|
25 | - protected $container; |
|
24 | + /** @var ContainerInterface */ |
|
25 | + protected $container; |
|
26 | 26 | |
27 | - /** |
|
28 | - * {@inheritdoc} |
|
29 | - */ |
|
30 | - public static function getSubscribedServices(): array |
|
31 | - { |
|
32 | - static $services; |
|
27 | + /** |
|
28 | + * {@inheritdoc} |
|
29 | + */ |
|
30 | + public static function getSubscribedServices(): array |
|
31 | + { |
|
32 | + static $services; |
|
33 | 33 | |
34 | - if (null !== $services) { |
|
35 | - return $services; |
|
36 | - } |
|
34 | + if (null !== $services) { |
|
35 | + return $services; |
|
36 | + } |
|
37 | 37 | |
38 | - $services = \is_callable(['parent', __FUNCTION__]) ? parent::getSubscribedServices() : []; |
|
38 | + $services = \is_callable(['parent', __FUNCTION__]) ? parent::getSubscribedServices() : []; |
|
39 | 39 | |
40 | - foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { |
|
41 | - if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { |
|
42 | - continue; |
|
43 | - } |
|
40 | + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { |
|
41 | + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { |
|
42 | + continue; |
|
43 | + } |
|
44 | 44 | |
45 | - if (self::class === $method->getDeclaringClass()->name && ($returnType = $method->getReturnType()) && !$returnType->isBuiltin()) { |
|
46 | - $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType); |
|
47 | - } |
|
48 | - } |
|
45 | + if (self::class === $method->getDeclaringClass()->name && ($returnType = $method->getReturnType()) && !$returnType->isBuiltin()) { |
|
46 | + $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType); |
|
47 | + } |
|
48 | + } |
|
49 | 49 | |
50 | - return $services; |
|
51 | - } |
|
50 | + return $services; |
|
51 | + } |
|
52 | 52 | |
53 | - /** |
|
54 | - * @required |
|
55 | - */ |
|
56 | - public function setContainer(ContainerInterface $container) |
|
57 | - { |
|
58 | - $this->container = $container; |
|
53 | + /** |
|
54 | + * @required |
|
55 | + */ |
|
56 | + public function setContainer(ContainerInterface $container) |
|
57 | + { |
|
58 | + $this->container = $container; |
|
59 | 59 | |
60 | - if (\is_callable(['parent', __FUNCTION__])) { |
|
61 | - return parent::setContainer($container); |
|
62 | - } |
|
60 | + if (\is_callable(['parent', __FUNCTION__])) { |
|
61 | + return parent::setContainer($container); |
|
62 | + } |
|
63 | 63 | |
64 | - return null; |
|
65 | - } |
|
64 | + return null; |
|
65 | + } |
|
66 | 66 | } |
@@ -26,5 +26,5 @@ |
||
26 | 26 | */ |
27 | 27 | interface ResetInterface |
28 | 28 | { |
29 | - public function reset(); |
|
29 | + public function reset(); |
|
30 | 30 | } |
@@ -17,76 +17,76 @@ |
||
17 | 17 | |
18 | 18 | abstract class ServiceLocatorTest extends TestCase |
19 | 19 | { |
20 | - protected function getServiceLocator(array $factories) |
|
21 | - { |
|
22 | - return new class($factories) implements ContainerInterface { |
|
23 | - use ServiceLocatorTrait; |
|
24 | - }; |
|
25 | - } |
|
20 | + protected function getServiceLocator(array $factories) |
|
21 | + { |
|
22 | + return new class($factories) implements ContainerInterface { |
|
23 | + use ServiceLocatorTrait; |
|
24 | + }; |
|
25 | + } |
|
26 | 26 | |
27 | - public function testHas() |
|
28 | - { |
|
29 | - $locator = $this->getServiceLocator([ |
|
30 | - 'foo' => function () { return 'bar'; }, |
|
31 | - 'bar' => function () { return 'baz'; }, |
|
32 | - function () { return 'dummy'; }, |
|
33 | - ]); |
|
27 | + public function testHas() |
|
28 | + { |
|
29 | + $locator = $this->getServiceLocator([ |
|
30 | + 'foo' => function () { return 'bar'; }, |
|
31 | + 'bar' => function () { return 'baz'; }, |
|
32 | + function () { return 'dummy'; }, |
|
33 | + ]); |
|
34 | 34 | |
35 | - $this->assertTrue($locator->has('foo')); |
|
36 | - $this->assertTrue($locator->has('bar')); |
|
37 | - $this->assertFalse($locator->has('dummy')); |
|
38 | - } |
|
35 | + $this->assertTrue($locator->has('foo')); |
|
36 | + $this->assertTrue($locator->has('bar')); |
|
37 | + $this->assertFalse($locator->has('dummy')); |
|
38 | + } |
|
39 | 39 | |
40 | - public function testGet() |
|
41 | - { |
|
42 | - $locator = $this->getServiceLocator([ |
|
43 | - 'foo' => function () { return 'bar'; }, |
|
44 | - 'bar' => function () { return 'baz'; }, |
|
45 | - ]); |
|
40 | + public function testGet() |
|
41 | + { |
|
42 | + $locator = $this->getServiceLocator([ |
|
43 | + 'foo' => function () { return 'bar'; }, |
|
44 | + 'bar' => function () { return 'baz'; }, |
|
45 | + ]); |
|
46 | 46 | |
47 | - $this->assertSame('bar', $locator->get('foo')); |
|
48 | - $this->assertSame('baz', $locator->get('bar')); |
|
49 | - } |
|
47 | + $this->assertSame('bar', $locator->get('foo')); |
|
48 | + $this->assertSame('baz', $locator->get('bar')); |
|
49 | + } |
|
50 | 50 | |
51 | - public function testGetDoesNotMemoize() |
|
52 | - { |
|
53 | - $i = 0; |
|
54 | - $locator = $this->getServiceLocator([ |
|
55 | - 'foo' => function () use (&$i) { |
|
56 | - ++$i; |
|
51 | + public function testGetDoesNotMemoize() |
|
52 | + { |
|
53 | + $i = 0; |
|
54 | + $locator = $this->getServiceLocator([ |
|
55 | + 'foo' => function () use (&$i) { |
|
56 | + ++$i; |
|
57 | 57 | |
58 | - return 'bar'; |
|
59 | - }, |
|
60 | - ]); |
|
58 | + return 'bar'; |
|
59 | + }, |
|
60 | + ]); |
|
61 | 61 | |
62 | - $this->assertSame('bar', $locator->get('foo')); |
|
63 | - $this->assertSame('bar', $locator->get('foo')); |
|
64 | - $this->assertSame(2, $i); |
|
65 | - } |
|
62 | + $this->assertSame('bar', $locator->get('foo')); |
|
63 | + $this->assertSame('bar', $locator->get('foo')); |
|
64 | + $this->assertSame(2, $i); |
|
65 | + } |
|
66 | 66 | |
67 | - public function testThrowsOnUndefinedInternalService() |
|
68 | - { |
|
69 | - if (!$this->getExpectedException()) { |
|
70 | - $this->expectException(\Psr\Container\NotFoundExceptionInterface::class); |
|
71 | - $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); |
|
72 | - } |
|
73 | - $locator = $this->getServiceLocator([ |
|
74 | - 'foo' => function () use (&$locator) { return $locator->get('bar'); }, |
|
75 | - ]); |
|
67 | + public function testThrowsOnUndefinedInternalService() |
|
68 | + { |
|
69 | + if (!$this->getExpectedException()) { |
|
70 | + $this->expectException(\Psr\Container\NotFoundExceptionInterface::class); |
|
71 | + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); |
|
72 | + } |
|
73 | + $locator = $this->getServiceLocator([ |
|
74 | + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, |
|
75 | + ]); |
|
76 | 76 | |
77 | - $locator->get('foo'); |
|
78 | - } |
|
77 | + $locator->get('foo'); |
|
78 | + } |
|
79 | 79 | |
80 | - public function testThrowsOnCircularReference() |
|
81 | - { |
|
82 | - $this->expectException(\Psr\Container\ContainerExceptionInterface::class); |
|
83 | - $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); |
|
84 | - $locator = $this->getServiceLocator([ |
|
85 | - 'foo' => function () use (&$locator) { return $locator->get('bar'); }, |
|
86 | - 'bar' => function () use (&$locator) { return $locator->get('baz'); }, |
|
87 | - 'baz' => function () use (&$locator) { return $locator->get('bar'); }, |
|
88 | - ]); |
|
80 | + public function testThrowsOnCircularReference() |
|
81 | + { |
|
82 | + $this->expectException(\Psr\Container\ContainerExceptionInterface::class); |
|
83 | + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); |
|
84 | + $locator = $this->getServiceLocator([ |
|
85 | + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, |
|
86 | + 'bar' => function () use (&$locator) { return $locator->get('baz'); }, |
|
87 | + 'baz' => function () use (&$locator) { return $locator->get('bar'); }, |
|
88 | + ]); |
|
89 | 89 | |
90 | - $locator->get('foo'); |
|
91 | - } |
|
90 | + $locator->get('foo'); |
|
91 | + } |
|
92 | 92 | } |
@@ -12,136 +12,136 @@ |
||
12 | 12 | use Symfony\Polyfill\Mbstring as p; |
13 | 13 | |
14 | 14 | if (\PHP_VERSION_ID >= 80000) { |
15 | - return require __DIR__.'/bootstrap80.php'; |
|
15 | + return require __DIR__.'/bootstrap80.php'; |
|
16 | 16 | } |
17 | 17 | |
18 | 18 | if (!function_exists('mb_convert_encoding')) { |
19 | - function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); } |
|
19 | + function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); } |
|
20 | 20 | } |
21 | 21 | if (!function_exists('mb_decode_mimeheader')) { |
22 | - function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); } |
|
22 | + function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); } |
|
23 | 23 | } |
24 | 24 | if (!function_exists('mb_encode_mimeheader')) { |
25 | - function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); } |
|
25 | + function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); } |
|
26 | 26 | } |
27 | 27 | if (!function_exists('mb_decode_numericentity')) { |
28 | - function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); } |
|
28 | + function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); } |
|
29 | 29 | } |
30 | 30 | if (!function_exists('mb_encode_numericentity')) { |
31 | - function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); } |
|
31 | + function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); } |
|
32 | 32 | } |
33 | 33 | if (!function_exists('mb_convert_case')) { |
34 | - function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); } |
|
34 | + function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); } |
|
35 | 35 | } |
36 | 36 | if (!function_exists('mb_internal_encoding')) { |
37 | - function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); } |
|
37 | + function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); } |
|
38 | 38 | } |
39 | 39 | if (!function_exists('mb_language')) { |
40 | - function mb_language($language = null) { return p\Mbstring::mb_language($language); } |
|
40 | + function mb_language($language = null) { return p\Mbstring::mb_language($language); } |
|
41 | 41 | } |
42 | 42 | if (!function_exists('mb_list_encodings')) { |
43 | - function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); } |
|
43 | + function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); } |
|
44 | 44 | } |
45 | 45 | if (!function_exists('mb_encoding_aliases')) { |
46 | - function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); } |
|
46 | + function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); } |
|
47 | 47 | } |
48 | 48 | if (!function_exists('mb_check_encoding')) { |
49 | - function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); } |
|
49 | + function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); } |
|
50 | 50 | } |
51 | 51 | if (!function_exists('mb_detect_encoding')) { |
52 | - function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); } |
|
52 | + function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); } |
|
53 | 53 | } |
54 | 54 | if (!function_exists('mb_detect_order')) { |
55 | - function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); } |
|
55 | + function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); } |
|
56 | 56 | } |
57 | 57 | if (!function_exists('mb_parse_str')) { |
58 | - function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; } |
|
58 | + function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; } |
|
59 | 59 | } |
60 | 60 | if (!function_exists('mb_strlen')) { |
61 | - function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); } |
|
61 | + function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); } |
|
62 | 62 | } |
63 | 63 | if (!function_exists('mb_strpos')) { |
64 | - function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); } |
|
64 | + function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); } |
|
65 | 65 | } |
66 | 66 | if (!function_exists('mb_strtolower')) { |
67 | - function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); } |
|
67 | + function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); } |
|
68 | 68 | } |
69 | 69 | if (!function_exists('mb_strtoupper')) { |
70 | - function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); } |
|
70 | + function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); } |
|
71 | 71 | } |
72 | 72 | if (!function_exists('mb_substitute_character')) { |
73 | - function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); } |
|
73 | + function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); } |
|
74 | 74 | } |
75 | 75 | if (!function_exists('mb_substr')) { |
76 | - function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); } |
|
76 | + function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); } |
|
77 | 77 | } |
78 | 78 | if (!function_exists('mb_stripos')) { |
79 | - function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); } |
|
79 | + function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); } |
|
80 | 80 | } |
81 | 81 | if (!function_exists('mb_stristr')) { |
82 | - function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); } |
|
82 | + function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); } |
|
83 | 83 | } |
84 | 84 | if (!function_exists('mb_strrchr')) { |
85 | - function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); } |
|
85 | + function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); } |
|
86 | 86 | } |
87 | 87 | if (!function_exists('mb_strrichr')) { |
88 | - function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); } |
|
88 | + function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); } |
|
89 | 89 | } |
90 | 90 | if (!function_exists('mb_strripos')) { |
91 | - function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); } |
|
91 | + function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); } |
|
92 | 92 | } |
93 | 93 | if (!function_exists('mb_strrpos')) { |
94 | - function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); } |
|
94 | + function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); } |
|
95 | 95 | } |
96 | 96 | if (!function_exists('mb_strstr')) { |
97 | - function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); } |
|
97 | + function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); } |
|
98 | 98 | } |
99 | 99 | if (!function_exists('mb_get_info')) { |
100 | - function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); } |
|
100 | + function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); } |
|
101 | 101 | } |
102 | 102 | if (!function_exists('mb_http_output')) { |
103 | - function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); } |
|
103 | + function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); } |
|
104 | 104 | } |
105 | 105 | if (!function_exists('mb_strwidth')) { |
106 | - function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); } |
|
106 | + function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); } |
|
107 | 107 | } |
108 | 108 | if (!function_exists('mb_substr_count')) { |
109 | - function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); } |
|
109 | + function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); } |
|
110 | 110 | } |
111 | 111 | if (!function_exists('mb_output_handler')) { |
112 | - function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); } |
|
112 | + function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); } |
|
113 | 113 | } |
114 | 114 | if (!function_exists('mb_http_input')) { |
115 | - function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); } |
|
115 | + function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); } |
|
116 | 116 | } |
117 | 117 | |
118 | 118 | if (!function_exists('mb_convert_variables')) { |
119 | - function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); } |
|
119 | + function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); } |
|
120 | 120 | } |
121 | 121 | |
122 | 122 | if (!function_exists('mb_ord')) { |
123 | - function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); } |
|
123 | + function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); } |
|
124 | 124 | } |
125 | 125 | if (!function_exists('mb_chr')) { |
126 | - function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); } |
|
126 | + function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); } |
|
127 | 127 | } |
128 | 128 | if (!function_exists('mb_scrub')) { |
129 | - function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); } |
|
129 | + function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); } |
|
130 | 130 | } |
131 | 131 | if (!function_exists('mb_str_split')) { |
132 | - function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); } |
|
132 | + function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); } |
|
133 | 133 | } |
134 | 134 | |
135 | 135 | if (extension_loaded('mbstring')) { |
136 | - return; |
|
136 | + return; |
|
137 | 137 | } |
138 | 138 | |
139 | 139 | if (!defined('MB_CASE_UPPER')) { |
140 | - define('MB_CASE_UPPER', 0); |
|
140 | + define('MB_CASE_UPPER', 0); |
|
141 | 141 | } |
142 | 142 | if (!defined('MB_CASE_LOWER')) { |
143 | - define('MB_CASE_LOWER', 1); |
|
143 | + define('MB_CASE_LOWER', 1); |
|
144 | 144 | } |
145 | 145 | if (!defined('MB_CASE_TITLE')) { |
146 | - define('MB_CASE_TITLE', 2); |
|
146 | + define('MB_CASE_TITLE', 2); |
|
147 | 147 | } |
@@ -67,804 +67,804 @@ |
||
67 | 67 | */ |
68 | 68 | final class Mbstring |
69 | 69 | { |
70 | - public const MB_CASE_FOLD = \PHP_INT_MAX; |
|
71 | - |
|
72 | - private const CASE_FOLD = [ |
|
73 | - ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], |
|
74 | - ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], |
|
75 | - ]; |
|
76 | - |
|
77 | - private static $encodingList = ['ASCII', 'UTF-8']; |
|
78 | - private static $language = 'neutral'; |
|
79 | - private static $internalEncoding = 'UTF-8'; |
|
80 | - |
|
81 | - public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) |
|
82 | - { |
|
83 | - if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) { |
|
84 | - $fromEncoding = self::mb_detect_encoding($s, $fromEncoding); |
|
85 | - } else { |
|
86 | - $fromEncoding = self::getEncoding($fromEncoding); |
|
87 | - } |
|
88 | - |
|
89 | - $toEncoding = self::getEncoding($toEncoding); |
|
90 | - |
|
91 | - if ('BASE64' === $fromEncoding) { |
|
92 | - $s = base64_decode($s); |
|
93 | - $fromEncoding = $toEncoding; |
|
94 | - } |
|
95 | - |
|
96 | - if ('BASE64' === $toEncoding) { |
|
97 | - return base64_encode($s); |
|
98 | - } |
|
99 | - |
|
100 | - if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) { |
|
101 | - if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) { |
|
102 | - $fromEncoding = 'Windows-1252'; |
|
103 | - } |
|
104 | - if ('UTF-8' !== $fromEncoding) { |
|
105 | - $s = \iconv($fromEncoding, 'UTF-8//IGNORE', $s); |
|
106 | - } |
|
107 | - |
|
108 | - return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s); |
|
109 | - } |
|
110 | - |
|
111 | - if ('HTML-ENTITIES' === $fromEncoding) { |
|
112 | - $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8'); |
|
113 | - $fromEncoding = 'UTF-8'; |
|
114 | - } |
|
115 | - |
|
116 | - return \iconv($fromEncoding, $toEncoding.'//IGNORE', $s); |
|
117 | - } |
|
118 | - |
|
119 | - public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars) |
|
120 | - { |
|
121 | - $ok = true; |
|
122 | - array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) { |
|
123 | - if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) { |
|
124 | - $ok = false; |
|
125 | - } |
|
126 | - }); |
|
127 | - |
|
128 | - return $ok ? $fromEncoding : false; |
|
129 | - } |
|
130 | - |
|
131 | - public static function mb_decode_mimeheader($s) |
|
132 | - { |
|
133 | - return \iconv_mime_decode($s, 2, self::$internalEncoding); |
|
134 | - } |
|
135 | - |
|
136 | - public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null) |
|
137 | - { |
|
138 | - trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING); |
|
139 | - } |
|
140 | - |
|
141 | - public static function mb_decode_numericentity($s, $convmap, $encoding = null) |
|
142 | - { |
|
143 | - if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { |
|
144 | - trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); |
|
145 | - |
|
146 | - return null; |
|
147 | - } |
|
148 | - |
|
149 | - if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { |
|
150 | - return false; |
|
151 | - } |
|
152 | - |
|
153 | - if (null !== $encoding && !is_scalar($encoding)) { |
|
154 | - trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); |
|
155 | - |
|
156 | - return ''; // Instead of null (cf. mb_encode_numericentity). |
|
157 | - } |
|
158 | - |
|
159 | - $s = (string) $s; |
|
160 | - if ('' === $s) { |
|
161 | - return ''; |
|
162 | - } |
|
163 | - |
|
164 | - $encoding = self::getEncoding($encoding); |
|
165 | - |
|
166 | - if ('UTF-8' === $encoding) { |
|
167 | - $encoding = null; |
|
168 | - if (!preg_match('//u', $s)) { |
|
169 | - $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); |
|
170 | - } |
|
171 | - } else { |
|
172 | - $s = \iconv($encoding, 'UTF-8//IGNORE', $s); |
|
173 | - } |
|
174 | - |
|
175 | - $cnt = floor(\count($convmap) / 4) * 4; |
|
176 | - |
|
177 | - for ($i = 0; $i < $cnt; $i += 4) { |
|
178 | - // collector_decode_htmlnumericentity ignores $convmap[$i + 3] |
|
179 | - $convmap[$i] += $convmap[$i + 2]; |
|
180 | - $convmap[$i + 1] += $convmap[$i + 2]; |
|
181 | - } |
|
182 | - |
|
183 | - $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) { |
|
184 | - $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1]; |
|
185 | - for ($i = 0; $i < $cnt; $i += 4) { |
|
186 | - if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) { |
|
187 | - return self::mb_chr($c - $convmap[$i + 2]); |
|
188 | - } |
|
189 | - } |
|
190 | - |
|
191 | - return $m[0]; |
|
192 | - }, $s); |
|
193 | - |
|
194 | - if (null === $encoding) { |
|
195 | - return $s; |
|
196 | - } |
|
197 | - |
|
198 | - return \iconv('UTF-8', $encoding.'//IGNORE', $s); |
|
199 | - } |
|
200 | - |
|
201 | - public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false) |
|
202 | - { |
|
203 | - if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { |
|
204 | - trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); |
|
205 | - |
|
206 | - return null; |
|
207 | - } |
|
208 | - |
|
209 | - if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { |
|
210 | - return false; |
|
211 | - } |
|
212 | - |
|
213 | - if (null !== $encoding && !is_scalar($encoding)) { |
|
214 | - trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); |
|
215 | - |
|
216 | - return null; // Instead of '' (cf. mb_decode_numericentity). |
|
217 | - } |
|
218 | - |
|
219 | - if (null !== $is_hex && !is_scalar($is_hex)) { |
|
220 | - trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING); |
|
221 | - |
|
222 | - return null; |
|
223 | - } |
|
224 | - |
|
225 | - $s = (string) $s; |
|
226 | - if ('' === $s) { |
|
227 | - return ''; |
|
228 | - } |
|
229 | - |
|
230 | - $encoding = self::getEncoding($encoding); |
|
231 | - |
|
232 | - if ('UTF-8' === $encoding) { |
|
233 | - $encoding = null; |
|
234 | - if (!preg_match('//u', $s)) { |
|
235 | - $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); |
|
236 | - } |
|
237 | - } else { |
|
238 | - $s = \iconv($encoding, 'UTF-8//IGNORE', $s); |
|
239 | - } |
|
240 | - |
|
241 | - static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; |
|
242 | - |
|
243 | - $cnt = floor(\count($convmap) / 4) * 4; |
|
244 | - $i = 0; |
|
245 | - $len = \strlen($s); |
|
246 | - $result = ''; |
|
247 | - |
|
248 | - while ($i < $len) { |
|
249 | - $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; |
|
250 | - $uchr = substr($s, $i, $ulen); |
|
251 | - $i += $ulen; |
|
252 | - $c = self::mb_ord($uchr); |
|
253 | - |
|
254 | - for ($j = 0; $j < $cnt; $j += 4) { |
|
255 | - if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) { |
|
256 | - $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3]; |
|
257 | - $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';'; |
|
258 | - continue 2; |
|
259 | - } |
|
260 | - } |
|
261 | - $result .= $uchr; |
|
262 | - } |
|
263 | - |
|
264 | - if (null === $encoding) { |
|
265 | - return $result; |
|
266 | - } |
|
267 | - |
|
268 | - return \iconv('UTF-8', $encoding.'//IGNORE', $result); |
|
269 | - } |
|
270 | - |
|
271 | - public static function mb_convert_case($s, $mode, $encoding = null) |
|
272 | - { |
|
273 | - $s = (string) $s; |
|
274 | - if ('' === $s) { |
|
275 | - return ''; |
|
276 | - } |
|
277 | - |
|
278 | - $encoding = self::getEncoding($encoding); |
|
279 | - |
|
280 | - if ('UTF-8' === $encoding) { |
|
281 | - $encoding = null; |
|
282 | - if (!preg_match('//u', $s)) { |
|
283 | - $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); |
|
284 | - } |
|
285 | - } else { |
|
286 | - $s = \iconv($encoding, 'UTF-8//IGNORE', $s); |
|
287 | - } |
|
288 | - |
|
289 | - if (\MB_CASE_TITLE == $mode) { |
|
290 | - static $titleRegexp = null; |
|
291 | - if (null === $titleRegexp) { |
|
292 | - $titleRegexp = self::getData('titleCaseRegexp'); |
|
293 | - } |
|
294 | - $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s); |
|
295 | - } else { |
|
296 | - if (\MB_CASE_UPPER == $mode) { |
|
297 | - static $upper = null; |
|
298 | - if (null === $upper) { |
|
299 | - $upper = self::getData('upperCase'); |
|
300 | - } |
|
301 | - $map = $upper; |
|
302 | - } else { |
|
303 | - if (self::MB_CASE_FOLD === $mode) { |
|
304 | - $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); |
|
305 | - } |
|
306 | - |
|
307 | - static $lower = null; |
|
308 | - if (null === $lower) { |
|
309 | - $lower = self::getData('lowerCase'); |
|
310 | - } |
|
311 | - $map = $lower; |
|
312 | - } |
|
313 | - |
|
314 | - static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; |
|
315 | - |
|
316 | - $i = 0; |
|
317 | - $len = \strlen($s); |
|
318 | - |
|
319 | - while ($i < $len) { |
|
320 | - $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; |
|
321 | - $uchr = substr($s, $i, $ulen); |
|
322 | - $i += $ulen; |
|
323 | - |
|
324 | - if (isset($map[$uchr])) { |
|
325 | - $uchr = $map[$uchr]; |
|
326 | - $nlen = \strlen($uchr); |
|
327 | - |
|
328 | - if ($nlen == $ulen) { |
|
329 | - $nlen = $i; |
|
330 | - do { |
|
331 | - $s[--$nlen] = $uchr[--$ulen]; |
|
332 | - } while ($ulen); |
|
333 | - } else { |
|
334 | - $s = substr_replace($s, $uchr, $i - $ulen, $ulen); |
|
335 | - $len += $nlen - $ulen; |
|
336 | - $i += $nlen - $ulen; |
|
337 | - } |
|
338 | - } |
|
339 | - } |
|
340 | - } |
|
341 | - |
|
342 | - if (null === $encoding) { |
|
343 | - return $s; |
|
344 | - } |
|
345 | - |
|
346 | - return \iconv('UTF-8', $encoding.'//IGNORE', $s); |
|
347 | - } |
|
348 | - |
|
349 | - public static function mb_internal_encoding($encoding = null) |
|
350 | - { |
|
351 | - if (null === $encoding) { |
|
352 | - return self::$internalEncoding; |
|
353 | - } |
|
354 | - |
|
355 | - $normalizedEncoding = self::getEncoding($encoding); |
|
356 | - |
|
357 | - if ('UTF-8' === $normalizedEncoding || false !== @\iconv($normalizedEncoding, $normalizedEncoding, ' ')) { |
|
358 | - self::$internalEncoding = $normalizedEncoding; |
|
359 | - |
|
360 | - return true; |
|
361 | - } |
|
362 | - |
|
363 | - if (80000 > \PHP_VERSION_ID) { |
|
364 | - return false; |
|
365 | - } |
|
366 | - |
|
367 | - throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding)); |
|
368 | - } |
|
369 | - |
|
370 | - public static function mb_language($lang = null) |
|
371 | - { |
|
372 | - if (null === $lang) { |
|
373 | - return self::$language; |
|
374 | - } |
|
375 | - |
|
376 | - switch ($normalizedLang = strtolower($lang)) { |
|
377 | - case 'uni': |
|
378 | - case 'neutral': |
|
379 | - self::$language = $normalizedLang; |
|
380 | - |
|
381 | - return true; |
|
382 | - } |
|
383 | - |
|
384 | - if (80000 > \PHP_VERSION_ID) { |
|
385 | - return false; |
|
386 | - } |
|
387 | - |
|
388 | - throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang)); |
|
389 | - } |
|
390 | - |
|
391 | - public static function mb_list_encodings() |
|
392 | - { |
|
393 | - return ['UTF-8']; |
|
394 | - } |
|
395 | - |
|
396 | - public static function mb_encoding_aliases($encoding) |
|
397 | - { |
|
398 | - switch (strtoupper($encoding)) { |
|
399 | - case 'UTF8': |
|
400 | - case 'UTF-8': |
|
401 | - return ['utf8']; |
|
402 | - } |
|
403 | - |
|
404 | - return false; |
|
405 | - } |
|
406 | - |
|
407 | - public static function mb_check_encoding($var = null, $encoding = null) |
|
408 | - { |
|
409 | - if (null === $encoding) { |
|
410 | - if (null === $var) { |
|
411 | - return false; |
|
412 | - } |
|
413 | - $encoding = self::$internalEncoding; |
|
414 | - } |
|
415 | - |
|
416 | - return self::mb_detect_encoding($var, [$encoding]) || false !== @\iconv($encoding, $encoding, $var); |
|
417 | - } |
|
418 | - |
|
419 | - public static function mb_detect_encoding($str, $encodingList = null, $strict = false) |
|
420 | - { |
|
421 | - if (null === $encodingList) { |
|
422 | - $encodingList = self::$encodingList; |
|
423 | - } else { |
|
424 | - if (!\is_array($encodingList)) { |
|
425 | - $encodingList = array_map('trim', explode(',', $encodingList)); |
|
426 | - } |
|
427 | - $encodingList = array_map('strtoupper', $encodingList); |
|
428 | - } |
|
429 | - |
|
430 | - foreach ($encodingList as $enc) { |
|
431 | - switch ($enc) { |
|
432 | - case 'ASCII': |
|
433 | - if (!preg_match('/[\x80-\xFF]/', $str)) { |
|
434 | - return $enc; |
|
435 | - } |
|
436 | - break; |
|
437 | - |
|
438 | - case 'UTF8': |
|
439 | - case 'UTF-8': |
|
440 | - if (preg_match('//u', $str)) { |
|
441 | - return 'UTF-8'; |
|
442 | - } |
|
443 | - break; |
|
444 | - |
|
445 | - default: |
|
446 | - if (0 === strncmp($enc, 'ISO-8859-', 9)) { |
|
447 | - return $enc; |
|
448 | - } |
|
449 | - } |
|
450 | - } |
|
451 | - |
|
452 | - return false; |
|
453 | - } |
|
454 | - |
|
455 | - public static function mb_detect_order($encodingList = null) |
|
456 | - { |
|
457 | - if (null === $encodingList) { |
|
458 | - return self::$encodingList; |
|
459 | - } |
|
460 | - |
|
461 | - if (!\is_array($encodingList)) { |
|
462 | - $encodingList = array_map('trim', explode(',', $encodingList)); |
|
463 | - } |
|
464 | - $encodingList = array_map('strtoupper', $encodingList); |
|
465 | - |
|
466 | - foreach ($encodingList as $enc) { |
|
467 | - switch ($enc) { |
|
468 | - default: |
|
469 | - if (strncmp($enc, 'ISO-8859-', 9)) { |
|
470 | - return false; |
|
471 | - } |
|
472 | - // no break |
|
473 | - case 'ASCII': |
|
474 | - case 'UTF8': |
|
475 | - case 'UTF-8': |
|
476 | - } |
|
477 | - } |
|
478 | - |
|
479 | - self::$encodingList = $encodingList; |
|
480 | - |
|
481 | - return true; |
|
482 | - } |
|
483 | - |
|
484 | - public static function mb_strlen($s, $encoding = null) |
|
485 | - { |
|
486 | - $encoding = self::getEncoding($encoding); |
|
487 | - if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|
488 | - return \strlen($s); |
|
489 | - } |
|
490 | - |
|
491 | - return @\iconv_strlen($s, $encoding); |
|
492 | - } |
|
493 | - |
|
494 | - public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) |
|
495 | - { |
|
496 | - $encoding = self::getEncoding($encoding); |
|
497 | - if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|
498 | - return strpos($haystack, $needle, $offset); |
|
499 | - } |
|
500 | - |
|
501 | - $needle = (string) $needle; |
|
502 | - if ('' === $needle) { |
|
503 | - if (80000 > \PHP_VERSION_ID) { |
|
504 | - trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING); |
|
505 | - |
|
506 | - return false; |
|
507 | - } |
|
508 | - |
|
509 | - return 0; |
|
510 | - } |
|
511 | - |
|
512 | - return \iconv_strpos($haystack, $needle, $offset, $encoding); |
|
513 | - } |
|
514 | - |
|
515 | - public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) |
|
516 | - { |
|
517 | - $encoding = self::getEncoding($encoding); |
|
518 | - if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|
519 | - return strrpos($haystack, $needle, $offset); |
|
520 | - } |
|
521 | - |
|
522 | - if ($offset != (int) $offset) { |
|
523 | - $offset = 0; |
|
524 | - } elseif ($offset = (int) $offset) { |
|
525 | - if ($offset < 0) { |
|
526 | - if (0 > $offset += self::mb_strlen($needle)) { |
|
527 | - $haystack = self::mb_substr($haystack, 0, $offset, $encoding); |
|
528 | - } |
|
529 | - $offset = 0; |
|
530 | - } else { |
|
531 | - $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding); |
|
532 | - } |
|
533 | - } |
|
534 | - |
|
535 | - $pos = '' !== $needle || 80000 > \PHP_VERSION_ID |
|
536 | - ? \iconv_strrpos($haystack, $needle, $encoding) |
|
537 | - : self::mb_strlen($haystack, $encoding); |
|
538 | - |
|
539 | - return false !== $pos ? $offset + $pos : false; |
|
540 | - } |
|
541 | - |
|
542 | - public static function mb_str_split($string, $split_length = 1, $encoding = null) |
|
543 | - { |
|
544 | - if (null !== $string && !is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) { |
|
545 | - trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING); |
|
546 | - |
|
547 | - return null; |
|
548 | - } |
|
549 | - |
|
550 | - if (1 > $split_length = (int) $split_length) { |
|
551 | - if (80000 > \PHP_VERSION_ID) { |
|
552 | - trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING); |
|
553 | - return false; |
|
554 | - } |
|
555 | - |
|
556 | - throw new \ValueError('Argument #2 ($length) must be greater than 0'); |
|
557 | - } |
|
558 | - |
|
559 | - if (null === $encoding) { |
|
560 | - $encoding = mb_internal_encoding(); |
|
561 | - } |
|
562 | - |
|
563 | - if ('UTF-8' === $encoding = self::getEncoding($encoding)) { |
|
564 | - $rx = '/('; |
|
565 | - while (65535 < $split_length) { |
|
566 | - $rx .= '.{65535}'; |
|
567 | - $split_length -= 65535; |
|
568 | - } |
|
569 | - $rx .= '.{'.$split_length.'})/us'; |
|
570 | - |
|
571 | - return preg_split($rx, $string, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); |
|
572 | - } |
|
573 | - |
|
574 | - $result = []; |
|
575 | - $length = mb_strlen($string, $encoding); |
|
576 | - |
|
577 | - for ($i = 0; $i < $length; $i += $split_length) { |
|
578 | - $result[] = mb_substr($string, $i, $split_length, $encoding); |
|
579 | - } |
|
580 | - |
|
581 | - return $result; |
|
582 | - } |
|
583 | - |
|
584 | - public static function mb_strtolower($s, $encoding = null) |
|
585 | - { |
|
586 | - return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding); |
|
587 | - } |
|
588 | - |
|
589 | - public static function mb_strtoupper($s, $encoding = null) |
|
590 | - { |
|
591 | - return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding); |
|
592 | - } |
|
593 | - |
|
594 | - public static function mb_substitute_character($c = null) |
|
595 | - { |
|
596 | - if (null === $c) { |
|
597 | - return 'none'; |
|
598 | - } |
|
599 | - if (0 === strcasecmp($c, 'none')) { |
|
600 | - return true; |
|
601 | - } |
|
602 | - if (80000 > \PHP_VERSION_ID) { |
|
603 | - return false; |
|
604 | - } |
|
605 | - |
|
606 | - throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint'); |
|
607 | - } |
|
608 | - |
|
609 | - public static function mb_substr($s, $start, $length = null, $encoding = null) |
|
610 | - { |
|
611 | - $encoding = self::getEncoding($encoding); |
|
612 | - if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|
613 | - return (string) substr($s, $start, null === $length ? 2147483647 : $length); |
|
614 | - } |
|
615 | - |
|
616 | - if ($start < 0) { |
|
617 | - $start = \iconv_strlen($s, $encoding) + $start; |
|
618 | - if ($start < 0) { |
|
619 | - $start = 0; |
|
620 | - } |
|
621 | - } |
|
622 | - |
|
623 | - if (null === $length) { |
|
624 | - $length = 2147483647; |
|
625 | - } elseif ($length < 0) { |
|
626 | - $length = \iconv_strlen($s, $encoding) + $length - $start; |
|
627 | - if ($length < 0) { |
|
628 | - return ''; |
|
629 | - } |
|
630 | - } |
|
631 | - |
|
632 | - return (string) \iconv_substr($s, $start, $length, $encoding); |
|
633 | - } |
|
634 | - |
|
635 | - public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) |
|
636 | - { |
|
637 | - $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); |
|
638 | - $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); |
|
639 | - |
|
640 | - return self::mb_strpos($haystack, $needle, $offset, $encoding); |
|
641 | - } |
|
642 | - |
|
643 | - public static function mb_stristr($haystack, $needle, $part = false, $encoding = null) |
|
644 | - { |
|
645 | - $pos = self::mb_stripos($haystack, $needle, 0, $encoding); |
|
646 | - |
|
647 | - return self::getSubpart($pos, $part, $haystack, $encoding); |
|
648 | - } |
|
649 | - |
|
650 | - public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null) |
|
651 | - { |
|
652 | - $encoding = self::getEncoding($encoding); |
|
653 | - if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|
654 | - $pos = strrpos($haystack, $needle); |
|
655 | - } else { |
|
656 | - $needle = self::mb_substr($needle, 0, 1, $encoding); |
|
657 | - $pos = \iconv_strrpos($haystack, $needle, $encoding); |
|
658 | - } |
|
659 | - |
|
660 | - return self::getSubpart($pos, $part, $haystack, $encoding); |
|
661 | - } |
|
662 | - |
|
663 | - public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null) |
|
664 | - { |
|
665 | - $needle = self::mb_substr($needle, 0, 1, $encoding); |
|
666 | - $pos = self::mb_strripos($haystack, $needle, $encoding); |
|
667 | - |
|
668 | - return self::getSubpart($pos, $part, $haystack, $encoding); |
|
669 | - } |
|
670 | - |
|
671 | - public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) |
|
672 | - { |
|
673 | - $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); |
|
674 | - $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); |
|
675 | - |
|
676 | - return self::mb_strrpos($haystack, $needle, $offset, $encoding); |
|
677 | - } |
|
678 | - |
|
679 | - public static function mb_strstr($haystack, $needle, $part = false, $encoding = null) |
|
680 | - { |
|
681 | - $pos = strpos($haystack, $needle); |
|
682 | - if (false === $pos) { |
|
683 | - return false; |
|
684 | - } |
|
685 | - if ($part) { |
|
686 | - return substr($haystack, 0, $pos); |
|
687 | - } |
|
688 | - |
|
689 | - return substr($haystack, $pos); |
|
690 | - } |
|
691 | - |
|
692 | - public static function mb_get_info($type = 'all') |
|
693 | - { |
|
694 | - $info = [ |
|
695 | - 'internal_encoding' => self::$internalEncoding, |
|
696 | - 'http_output' => 'pass', |
|
697 | - 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)', |
|
698 | - 'func_overload' => 0, |
|
699 | - 'func_overload_list' => 'no overload', |
|
700 | - 'mail_charset' => 'UTF-8', |
|
701 | - 'mail_header_encoding' => 'BASE64', |
|
702 | - 'mail_body_encoding' => 'BASE64', |
|
703 | - 'illegal_chars' => 0, |
|
704 | - 'encoding_translation' => 'Off', |
|
705 | - 'language' => self::$language, |
|
706 | - 'detect_order' => self::$encodingList, |
|
707 | - 'substitute_character' => 'none', |
|
708 | - 'strict_detection' => 'Off', |
|
709 | - ]; |
|
710 | - |
|
711 | - if ('all' === $type) { |
|
712 | - return $info; |
|
713 | - } |
|
714 | - if (isset($info[$type])) { |
|
715 | - return $info[$type]; |
|
716 | - } |
|
717 | - |
|
718 | - return false; |
|
719 | - } |
|
720 | - |
|
721 | - public static function mb_http_input($type = '') |
|
722 | - { |
|
723 | - return false; |
|
724 | - } |
|
725 | - |
|
726 | - public static function mb_http_output($encoding = null) |
|
727 | - { |
|
728 | - return null !== $encoding ? 'pass' === $encoding : 'pass'; |
|
729 | - } |
|
730 | - |
|
731 | - public static function mb_strwidth($s, $encoding = null) |
|
732 | - { |
|
733 | - $encoding = self::getEncoding($encoding); |
|
734 | - |
|
735 | - if ('UTF-8' !== $encoding) { |
|
736 | - $s = \iconv($encoding, 'UTF-8//IGNORE', $s); |
|
737 | - } |
|
738 | - |
|
739 | - $s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide); |
|
740 | - |
|
741 | - return ($wide << 1) + \iconv_strlen($s, 'UTF-8'); |
|
742 | - } |
|
743 | - |
|
744 | - public static function mb_substr_count($haystack, $needle, $encoding = null) |
|
745 | - { |
|
746 | - return substr_count($haystack, $needle); |
|
747 | - } |
|
748 | - |
|
749 | - public static function mb_output_handler($contents, $status) |
|
750 | - { |
|
751 | - return $contents; |
|
752 | - } |
|
753 | - |
|
754 | - public static function mb_chr($code, $encoding = null) |
|
755 | - { |
|
756 | - if (0x80 > $code %= 0x200000) { |
|
757 | - $s = \chr($code); |
|
758 | - } elseif (0x800 > $code) { |
|
759 | - $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); |
|
760 | - } elseif (0x10000 > $code) { |
|
761 | - $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); |
|
762 | - } else { |
|
763 | - $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); |
|
764 | - } |
|
765 | - |
|
766 | - if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { |
|
767 | - $s = mb_convert_encoding($s, $encoding, 'UTF-8'); |
|
768 | - } |
|
769 | - |
|
770 | - return $s; |
|
771 | - } |
|
772 | - |
|
773 | - public static function mb_ord($s, $encoding = null) |
|
774 | - { |
|
775 | - if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { |
|
776 | - $s = mb_convert_encoding($s, 'UTF-8', $encoding); |
|
777 | - } |
|
778 | - |
|
779 | - if (1 === \strlen($s)) { |
|
780 | - return \ord($s); |
|
781 | - } |
|
782 | - |
|
783 | - $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; |
|
784 | - if (0xF0 <= $code) { |
|
785 | - return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; |
|
786 | - } |
|
787 | - if (0xE0 <= $code) { |
|
788 | - return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; |
|
789 | - } |
|
790 | - if (0xC0 <= $code) { |
|
791 | - return (($code - 0xC0) << 6) + $s[2] - 0x80; |
|
792 | - } |
|
793 | - |
|
794 | - return $code; |
|
795 | - } |
|
796 | - |
|
797 | - private static function getSubpart($pos, $part, $haystack, $encoding) |
|
798 | - { |
|
799 | - if (false === $pos) { |
|
800 | - return false; |
|
801 | - } |
|
802 | - if ($part) { |
|
803 | - return self::mb_substr($haystack, 0, $pos, $encoding); |
|
804 | - } |
|
805 | - |
|
806 | - return self::mb_substr($haystack, $pos, null, $encoding); |
|
807 | - } |
|
808 | - |
|
809 | - private static function html_encoding_callback(array $m) |
|
810 | - { |
|
811 | - $i = 1; |
|
812 | - $entities = ''; |
|
813 | - $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8')); |
|
814 | - |
|
815 | - while (isset($m[$i])) { |
|
816 | - if (0x80 > $m[$i]) { |
|
817 | - $entities .= \chr($m[$i++]); |
|
818 | - continue; |
|
819 | - } |
|
820 | - if (0xF0 <= $m[$i]) { |
|
821 | - $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; |
|
822 | - } elseif (0xE0 <= $m[$i]) { |
|
823 | - $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; |
|
824 | - } else { |
|
825 | - $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80; |
|
826 | - } |
|
827 | - |
|
828 | - $entities .= '&#'.$c.';'; |
|
829 | - } |
|
830 | - |
|
831 | - return $entities; |
|
832 | - } |
|
833 | - |
|
834 | - private static function title_case(array $s) |
|
835 | - { |
|
836 | - return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8'); |
|
837 | - } |
|
838 | - |
|
839 | - private static function getData($file) |
|
840 | - { |
|
841 | - if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { |
|
842 | - return require $file; |
|
843 | - } |
|
844 | - |
|
845 | - return false; |
|
846 | - } |
|
847 | - |
|
848 | - private static function getEncoding($encoding) |
|
849 | - { |
|
850 | - if (null === $encoding) { |
|
851 | - return self::$internalEncoding; |
|
852 | - } |
|
853 | - |
|
854 | - if ('UTF-8' === $encoding) { |
|
855 | - return 'UTF-8'; |
|
856 | - } |
|
857 | - |
|
858 | - $encoding = strtoupper($encoding); |
|
859 | - |
|
860 | - if ('8BIT' === $encoding || 'BINARY' === $encoding) { |
|
861 | - return 'CP850'; |
|
862 | - } |
|
863 | - |
|
864 | - if ('UTF8' === $encoding) { |
|
865 | - return 'UTF-8'; |
|
866 | - } |
|
867 | - |
|
868 | - return $encoding; |
|
869 | - } |
|
70 | + public const MB_CASE_FOLD = \PHP_INT_MAX; |
|
71 | + |
|
72 | + private const CASE_FOLD = [ |
|
73 | + ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], |
|
74 | + ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], |
|
75 | + ]; |
|
76 | + |
|
77 | + private static $encodingList = ['ASCII', 'UTF-8']; |
|
78 | + private static $language = 'neutral'; |
|
79 | + private static $internalEncoding = 'UTF-8'; |
|
80 | + |
|
81 | + public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) |
|
82 | + { |
|
83 | + if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) { |
|
84 | + $fromEncoding = self::mb_detect_encoding($s, $fromEncoding); |
|
85 | + } else { |
|
86 | + $fromEncoding = self::getEncoding($fromEncoding); |
|
87 | + } |
|
88 | + |
|
89 | + $toEncoding = self::getEncoding($toEncoding); |
|
90 | + |
|
91 | + if ('BASE64' === $fromEncoding) { |
|
92 | + $s = base64_decode($s); |
|
93 | + $fromEncoding = $toEncoding; |
|
94 | + } |
|
95 | + |
|
96 | + if ('BASE64' === $toEncoding) { |
|
97 | + return base64_encode($s); |
|
98 | + } |
|
99 | + |
|
100 | + if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) { |
|
101 | + if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) { |
|
102 | + $fromEncoding = 'Windows-1252'; |
|
103 | + } |
|
104 | + if ('UTF-8' !== $fromEncoding) { |
|
105 | + $s = \iconv($fromEncoding, 'UTF-8//IGNORE', $s); |
|
106 | + } |
|
107 | + |
|
108 | + return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s); |
|
109 | + } |
|
110 | + |
|
111 | + if ('HTML-ENTITIES' === $fromEncoding) { |
|
112 | + $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8'); |
|
113 | + $fromEncoding = 'UTF-8'; |
|
114 | + } |
|
115 | + |
|
116 | + return \iconv($fromEncoding, $toEncoding.'//IGNORE', $s); |
|
117 | + } |
|
118 | + |
|
119 | + public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars) |
|
120 | + { |
|
121 | + $ok = true; |
|
122 | + array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) { |
|
123 | + if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) { |
|
124 | + $ok = false; |
|
125 | + } |
|
126 | + }); |
|
127 | + |
|
128 | + return $ok ? $fromEncoding : false; |
|
129 | + } |
|
130 | + |
|
131 | + public static function mb_decode_mimeheader($s) |
|
132 | + { |
|
133 | + return \iconv_mime_decode($s, 2, self::$internalEncoding); |
|
134 | + } |
|
135 | + |
|
136 | + public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null) |
|
137 | + { |
|
138 | + trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING); |
|
139 | + } |
|
140 | + |
|
141 | + public static function mb_decode_numericentity($s, $convmap, $encoding = null) |
|
142 | + { |
|
143 | + if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { |
|
144 | + trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); |
|
145 | + |
|
146 | + return null; |
|
147 | + } |
|
148 | + |
|
149 | + if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { |
|
150 | + return false; |
|
151 | + } |
|
152 | + |
|
153 | + if (null !== $encoding && !is_scalar($encoding)) { |
|
154 | + trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); |
|
155 | + |
|
156 | + return ''; // Instead of null (cf. mb_encode_numericentity). |
|
157 | + } |
|
158 | + |
|
159 | + $s = (string) $s; |
|
160 | + if ('' === $s) { |
|
161 | + return ''; |
|
162 | + } |
|
163 | + |
|
164 | + $encoding = self::getEncoding($encoding); |
|
165 | + |
|
166 | + if ('UTF-8' === $encoding) { |
|
167 | + $encoding = null; |
|
168 | + if (!preg_match('//u', $s)) { |
|
169 | + $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); |
|
170 | + } |
|
171 | + } else { |
|
172 | + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); |
|
173 | + } |
|
174 | + |
|
175 | + $cnt = floor(\count($convmap) / 4) * 4; |
|
176 | + |
|
177 | + for ($i = 0; $i < $cnt; $i += 4) { |
|
178 | + // collector_decode_htmlnumericentity ignores $convmap[$i + 3] |
|
179 | + $convmap[$i] += $convmap[$i + 2]; |
|
180 | + $convmap[$i + 1] += $convmap[$i + 2]; |
|
181 | + } |
|
182 | + |
|
183 | + $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) { |
|
184 | + $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1]; |
|
185 | + for ($i = 0; $i < $cnt; $i += 4) { |
|
186 | + if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) { |
|
187 | + return self::mb_chr($c - $convmap[$i + 2]); |
|
188 | + } |
|
189 | + } |
|
190 | + |
|
191 | + return $m[0]; |
|
192 | + }, $s); |
|
193 | + |
|
194 | + if (null === $encoding) { |
|
195 | + return $s; |
|
196 | + } |
|
197 | + |
|
198 | + return \iconv('UTF-8', $encoding.'//IGNORE', $s); |
|
199 | + } |
|
200 | + |
|
201 | + public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false) |
|
202 | + { |
|
203 | + if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { |
|
204 | + trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); |
|
205 | + |
|
206 | + return null; |
|
207 | + } |
|
208 | + |
|
209 | + if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { |
|
210 | + return false; |
|
211 | + } |
|
212 | + |
|
213 | + if (null !== $encoding && !is_scalar($encoding)) { |
|
214 | + trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); |
|
215 | + |
|
216 | + return null; // Instead of '' (cf. mb_decode_numericentity). |
|
217 | + } |
|
218 | + |
|
219 | + if (null !== $is_hex && !is_scalar($is_hex)) { |
|
220 | + trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING); |
|
221 | + |
|
222 | + return null; |
|
223 | + } |
|
224 | + |
|
225 | + $s = (string) $s; |
|
226 | + if ('' === $s) { |
|
227 | + return ''; |
|
228 | + } |
|
229 | + |
|
230 | + $encoding = self::getEncoding($encoding); |
|
231 | + |
|
232 | + if ('UTF-8' === $encoding) { |
|
233 | + $encoding = null; |
|
234 | + if (!preg_match('//u', $s)) { |
|
235 | + $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); |
|
236 | + } |
|
237 | + } else { |
|
238 | + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); |
|
239 | + } |
|
240 | + |
|
241 | + static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; |
|
242 | + |
|
243 | + $cnt = floor(\count($convmap) / 4) * 4; |
|
244 | + $i = 0; |
|
245 | + $len = \strlen($s); |
|
246 | + $result = ''; |
|
247 | + |
|
248 | + while ($i < $len) { |
|
249 | + $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; |
|
250 | + $uchr = substr($s, $i, $ulen); |
|
251 | + $i += $ulen; |
|
252 | + $c = self::mb_ord($uchr); |
|
253 | + |
|
254 | + for ($j = 0; $j < $cnt; $j += 4) { |
|
255 | + if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) { |
|
256 | + $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3]; |
|
257 | + $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';'; |
|
258 | + continue 2; |
|
259 | + } |
|
260 | + } |
|
261 | + $result .= $uchr; |
|
262 | + } |
|
263 | + |
|
264 | + if (null === $encoding) { |
|
265 | + return $result; |
|
266 | + } |
|
267 | + |
|
268 | + return \iconv('UTF-8', $encoding.'//IGNORE', $result); |
|
269 | + } |
|
270 | + |
|
271 | + public static function mb_convert_case($s, $mode, $encoding = null) |
|
272 | + { |
|
273 | + $s = (string) $s; |
|
274 | + if ('' === $s) { |
|
275 | + return ''; |
|
276 | + } |
|
277 | + |
|
278 | + $encoding = self::getEncoding($encoding); |
|
279 | + |
|
280 | + if ('UTF-8' === $encoding) { |
|
281 | + $encoding = null; |
|
282 | + if (!preg_match('//u', $s)) { |
|
283 | + $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); |
|
284 | + } |
|
285 | + } else { |
|
286 | + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); |
|
287 | + } |
|
288 | + |
|
289 | + if (\MB_CASE_TITLE == $mode) { |
|
290 | + static $titleRegexp = null; |
|
291 | + if (null === $titleRegexp) { |
|
292 | + $titleRegexp = self::getData('titleCaseRegexp'); |
|
293 | + } |
|
294 | + $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s); |
|
295 | + } else { |
|
296 | + if (\MB_CASE_UPPER == $mode) { |
|
297 | + static $upper = null; |
|
298 | + if (null === $upper) { |
|
299 | + $upper = self::getData('upperCase'); |
|
300 | + } |
|
301 | + $map = $upper; |
|
302 | + } else { |
|
303 | + if (self::MB_CASE_FOLD === $mode) { |
|
304 | + $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); |
|
305 | + } |
|
306 | + |
|
307 | + static $lower = null; |
|
308 | + if (null === $lower) { |
|
309 | + $lower = self::getData('lowerCase'); |
|
310 | + } |
|
311 | + $map = $lower; |
|
312 | + } |
|
313 | + |
|
314 | + static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; |
|
315 | + |
|
316 | + $i = 0; |
|
317 | + $len = \strlen($s); |
|
318 | + |
|
319 | + while ($i < $len) { |
|
320 | + $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; |
|
321 | + $uchr = substr($s, $i, $ulen); |
|
322 | + $i += $ulen; |
|
323 | + |
|
324 | + if (isset($map[$uchr])) { |
|
325 | + $uchr = $map[$uchr]; |
|
326 | + $nlen = \strlen($uchr); |
|
327 | + |
|
328 | + if ($nlen == $ulen) { |
|
329 | + $nlen = $i; |
|
330 | + do { |
|
331 | + $s[--$nlen] = $uchr[--$ulen]; |
|
332 | + } while ($ulen); |
|
333 | + } else { |
|
334 | + $s = substr_replace($s, $uchr, $i - $ulen, $ulen); |
|
335 | + $len += $nlen - $ulen; |
|
336 | + $i += $nlen - $ulen; |
|
337 | + } |
|
338 | + } |
|
339 | + } |
|
340 | + } |
|
341 | + |
|
342 | + if (null === $encoding) { |
|
343 | + return $s; |
|
344 | + } |
|
345 | + |
|
346 | + return \iconv('UTF-8', $encoding.'//IGNORE', $s); |
|
347 | + } |
|
348 | + |
|
349 | + public static function mb_internal_encoding($encoding = null) |
|
350 | + { |
|
351 | + if (null === $encoding) { |
|
352 | + return self::$internalEncoding; |
|
353 | + } |
|
354 | + |
|
355 | + $normalizedEncoding = self::getEncoding($encoding); |
|
356 | + |
|
357 | + if ('UTF-8' === $normalizedEncoding || false !== @\iconv($normalizedEncoding, $normalizedEncoding, ' ')) { |
|
358 | + self::$internalEncoding = $normalizedEncoding; |
|
359 | + |
|
360 | + return true; |
|
361 | + } |
|
362 | + |
|
363 | + if (80000 > \PHP_VERSION_ID) { |
|
364 | + return false; |
|
365 | + } |
|
366 | + |
|
367 | + throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding)); |
|
368 | + } |
|
369 | + |
|
370 | + public static function mb_language($lang = null) |
|
371 | + { |
|
372 | + if (null === $lang) { |
|
373 | + return self::$language; |
|
374 | + } |
|
375 | + |
|
376 | + switch ($normalizedLang = strtolower($lang)) { |
|
377 | + case 'uni': |
|
378 | + case 'neutral': |
|
379 | + self::$language = $normalizedLang; |
|
380 | + |
|
381 | + return true; |
|
382 | + } |
|
383 | + |
|
384 | + if (80000 > \PHP_VERSION_ID) { |
|
385 | + return false; |
|
386 | + } |
|
387 | + |
|
388 | + throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang)); |
|
389 | + } |
|
390 | + |
|
391 | + public static function mb_list_encodings() |
|
392 | + { |
|
393 | + return ['UTF-8']; |
|
394 | + } |
|
395 | + |
|
396 | + public static function mb_encoding_aliases($encoding) |
|
397 | + { |
|
398 | + switch (strtoupper($encoding)) { |
|
399 | + case 'UTF8': |
|
400 | + case 'UTF-8': |
|
401 | + return ['utf8']; |
|
402 | + } |
|
403 | + |
|
404 | + return false; |
|
405 | + } |
|
406 | + |
|
407 | + public static function mb_check_encoding($var = null, $encoding = null) |
|
408 | + { |
|
409 | + if (null === $encoding) { |
|
410 | + if (null === $var) { |
|
411 | + return false; |
|
412 | + } |
|
413 | + $encoding = self::$internalEncoding; |
|
414 | + } |
|
415 | + |
|
416 | + return self::mb_detect_encoding($var, [$encoding]) || false !== @\iconv($encoding, $encoding, $var); |
|
417 | + } |
|
418 | + |
|
419 | + public static function mb_detect_encoding($str, $encodingList = null, $strict = false) |
|
420 | + { |
|
421 | + if (null === $encodingList) { |
|
422 | + $encodingList = self::$encodingList; |
|
423 | + } else { |
|
424 | + if (!\is_array($encodingList)) { |
|
425 | + $encodingList = array_map('trim', explode(',', $encodingList)); |
|
426 | + } |
|
427 | + $encodingList = array_map('strtoupper', $encodingList); |
|
428 | + } |
|
429 | + |
|
430 | + foreach ($encodingList as $enc) { |
|
431 | + switch ($enc) { |
|
432 | + case 'ASCII': |
|
433 | + if (!preg_match('/[\x80-\xFF]/', $str)) { |
|
434 | + return $enc; |
|
435 | + } |
|
436 | + break; |
|
437 | + |
|
438 | + case 'UTF8': |
|
439 | + case 'UTF-8': |
|
440 | + if (preg_match('//u', $str)) { |
|
441 | + return 'UTF-8'; |
|
442 | + } |
|
443 | + break; |
|
444 | + |
|
445 | + default: |
|
446 | + if (0 === strncmp($enc, 'ISO-8859-', 9)) { |
|
447 | + return $enc; |
|
448 | + } |
|
449 | + } |
|
450 | + } |
|
451 | + |
|
452 | + return false; |
|
453 | + } |
|
454 | + |
|
455 | + public static function mb_detect_order($encodingList = null) |
|
456 | + { |
|
457 | + if (null === $encodingList) { |
|
458 | + return self::$encodingList; |
|
459 | + } |
|
460 | + |
|
461 | + if (!\is_array($encodingList)) { |
|
462 | + $encodingList = array_map('trim', explode(',', $encodingList)); |
|
463 | + } |
|
464 | + $encodingList = array_map('strtoupper', $encodingList); |
|
465 | + |
|
466 | + foreach ($encodingList as $enc) { |
|
467 | + switch ($enc) { |
|
468 | + default: |
|
469 | + if (strncmp($enc, 'ISO-8859-', 9)) { |
|
470 | + return false; |
|
471 | + } |
|
472 | + // no break |
|
473 | + case 'ASCII': |
|
474 | + case 'UTF8': |
|
475 | + case 'UTF-8': |
|
476 | + } |
|
477 | + } |
|
478 | + |
|
479 | + self::$encodingList = $encodingList; |
|
480 | + |
|
481 | + return true; |
|
482 | + } |
|
483 | + |
|
484 | + public static function mb_strlen($s, $encoding = null) |
|
485 | + { |
|
486 | + $encoding = self::getEncoding($encoding); |
|
487 | + if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|
488 | + return \strlen($s); |
|
489 | + } |
|
490 | + |
|
491 | + return @\iconv_strlen($s, $encoding); |
|
492 | + } |
|
493 | + |
|
494 | + public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) |
|
495 | + { |
|
496 | + $encoding = self::getEncoding($encoding); |
|
497 | + if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|
498 | + return strpos($haystack, $needle, $offset); |
|
499 | + } |
|
500 | + |
|
501 | + $needle = (string) $needle; |
|
502 | + if ('' === $needle) { |
|
503 | + if (80000 > \PHP_VERSION_ID) { |
|
504 | + trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING); |
|
505 | + |
|
506 | + return false; |
|
507 | + } |
|
508 | + |
|
509 | + return 0; |
|
510 | + } |
|
511 | + |
|
512 | + return \iconv_strpos($haystack, $needle, $offset, $encoding); |
|
513 | + } |
|
514 | + |
|
515 | + public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) |
|
516 | + { |
|
517 | + $encoding = self::getEncoding($encoding); |
|
518 | + if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|
519 | + return strrpos($haystack, $needle, $offset); |
|
520 | + } |
|
521 | + |
|
522 | + if ($offset != (int) $offset) { |
|
523 | + $offset = 0; |
|
524 | + } elseif ($offset = (int) $offset) { |
|
525 | + if ($offset < 0) { |
|
526 | + if (0 > $offset += self::mb_strlen($needle)) { |
|
527 | + $haystack = self::mb_substr($haystack, 0, $offset, $encoding); |
|
528 | + } |
|
529 | + $offset = 0; |
|
530 | + } else { |
|
531 | + $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding); |
|
532 | + } |
|
533 | + } |
|
534 | + |
|
535 | + $pos = '' !== $needle || 80000 > \PHP_VERSION_ID |
|
536 | + ? \iconv_strrpos($haystack, $needle, $encoding) |
|
537 | + : self::mb_strlen($haystack, $encoding); |
|
538 | + |
|
539 | + return false !== $pos ? $offset + $pos : false; |
|
540 | + } |
|
541 | + |
|
542 | + public static function mb_str_split($string, $split_length = 1, $encoding = null) |
|
543 | + { |
|
544 | + if (null !== $string && !is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) { |
|
545 | + trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING); |
|
546 | + |
|
547 | + return null; |
|
548 | + } |
|
549 | + |
|
550 | + if (1 > $split_length = (int) $split_length) { |
|
551 | + if (80000 > \PHP_VERSION_ID) { |
|
552 | + trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING); |
|
553 | + return false; |
|
554 | + } |
|
555 | + |
|
556 | + throw new \ValueError('Argument #2 ($length) must be greater than 0'); |
|
557 | + } |
|
558 | + |
|
559 | + if (null === $encoding) { |
|
560 | + $encoding = mb_internal_encoding(); |
|
561 | + } |
|
562 | + |
|
563 | + if ('UTF-8' === $encoding = self::getEncoding($encoding)) { |
|
564 | + $rx = '/('; |
|
565 | + while (65535 < $split_length) { |
|
566 | + $rx .= '.{65535}'; |
|
567 | + $split_length -= 65535; |
|
568 | + } |
|
569 | + $rx .= '.{'.$split_length.'})/us'; |
|
570 | + |
|
571 | + return preg_split($rx, $string, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); |
|
572 | + } |
|
573 | + |
|
574 | + $result = []; |
|
575 | + $length = mb_strlen($string, $encoding); |
|
576 | + |
|
577 | + for ($i = 0; $i < $length; $i += $split_length) { |
|
578 | + $result[] = mb_substr($string, $i, $split_length, $encoding); |
|
579 | + } |
|
580 | + |
|
581 | + return $result; |
|
582 | + } |
|
583 | + |
|
584 | + public static function mb_strtolower($s, $encoding = null) |
|
585 | + { |
|
586 | + return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding); |
|
587 | + } |
|
588 | + |
|
589 | + public static function mb_strtoupper($s, $encoding = null) |
|
590 | + { |
|
591 | + return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding); |
|
592 | + } |
|
593 | + |
|
594 | + public static function mb_substitute_character($c = null) |
|
595 | + { |
|
596 | + if (null === $c) { |
|
597 | + return 'none'; |
|
598 | + } |
|
599 | + if (0 === strcasecmp($c, 'none')) { |
|
600 | + return true; |
|
601 | + } |
|
602 | + if (80000 > \PHP_VERSION_ID) { |
|
603 | + return false; |
|
604 | + } |
|
605 | + |
|
606 | + throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint'); |
|
607 | + } |
|
608 | + |
|
609 | + public static function mb_substr($s, $start, $length = null, $encoding = null) |
|
610 | + { |
|
611 | + $encoding = self::getEncoding($encoding); |
|
612 | + if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|
613 | + return (string) substr($s, $start, null === $length ? 2147483647 : $length); |
|
614 | + } |
|
615 | + |
|
616 | + if ($start < 0) { |
|
617 | + $start = \iconv_strlen($s, $encoding) + $start; |
|
618 | + if ($start < 0) { |
|
619 | + $start = 0; |
|
620 | + } |
|
621 | + } |
|
622 | + |
|
623 | + if (null === $length) { |
|
624 | + $length = 2147483647; |
|
625 | + } elseif ($length < 0) { |
|
626 | + $length = \iconv_strlen($s, $encoding) + $length - $start; |
|
627 | + if ($length < 0) { |
|
628 | + return ''; |
|
629 | + } |
|
630 | + } |
|
631 | + |
|
632 | + return (string) \iconv_substr($s, $start, $length, $encoding); |
|
633 | + } |
|
634 | + |
|
635 | + public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) |
|
636 | + { |
|
637 | + $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); |
|
638 | + $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); |
|
639 | + |
|
640 | + return self::mb_strpos($haystack, $needle, $offset, $encoding); |
|
641 | + } |
|
642 | + |
|
643 | + public static function mb_stristr($haystack, $needle, $part = false, $encoding = null) |
|
644 | + { |
|
645 | + $pos = self::mb_stripos($haystack, $needle, 0, $encoding); |
|
646 | + |
|
647 | + return self::getSubpart($pos, $part, $haystack, $encoding); |
|
648 | + } |
|
649 | + |
|
650 | + public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null) |
|
651 | + { |
|
652 | + $encoding = self::getEncoding($encoding); |
|
653 | + if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|
654 | + $pos = strrpos($haystack, $needle); |
|
655 | + } else { |
|
656 | + $needle = self::mb_substr($needle, 0, 1, $encoding); |
|
657 | + $pos = \iconv_strrpos($haystack, $needle, $encoding); |
|
658 | + } |
|
659 | + |
|
660 | + return self::getSubpart($pos, $part, $haystack, $encoding); |
|
661 | + } |
|
662 | + |
|
663 | + public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null) |
|
664 | + { |
|
665 | + $needle = self::mb_substr($needle, 0, 1, $encoding); |
|
666 | + $pos = self::mb_strripos($haystack, $needle, $encoding); |
|
667 | + |
|
668 | + return self::getSubpart($pos, $part, $haystack, $encoding); |
|
669 | + } |
|
670 | + |
|
671 | + public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) |
|
672 | + { |
|
673 | + $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); |
|
674 | + $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); |
|
675 | + |
|
676 | + return self::mb_strrpos($haystack, $needle, $offset, $encoding); |
|
677 | + } |
|
678 | + |
|
679 | + public static function mb_strstr($haystack, $needle, $part = false, $encoding = null) |
|
680 | + { |
|
681 | + $pos = strpos($haystack, $needle); |
|
682 | + if (false === $pos) { |
|
683 | + return false; |
|
684 | + } |
|
685 | + if ($part) { |
|
686 | + return substr($haystack, 0, $pos); |
|
687 | + } |
|
688 | + |
|
689 | + return substr($haystack, $pos); |
|
690 | + } |
|
691 | + |
|
692 | + public static function mb_get_info($type = 'all') |
|
693 | + { |
|
694 | + $info = [ |
|
695 | + 'internal_encoding' => self::$internalEncoding, |
|
696 | + 'http_output' => 'pass', |
|
697 | + 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)', |
|
698 | + 'func_overload' => 0, |
|
699 | + 'func_overload_list' => 'no overload', |
|
700 | + 'mail_charset' => 'UTF-8', |
|
701 | + 'mail_header_encoding' => 'BASE64', |
|
702 | + 'mail_body_encoding' => 'BASE64', |
|
703 | + 'illegal_chars' => 0, |
|
704 | + 'encoding_translation' => 'Off', |
|
705 | + 'language' => self::$language, |
|
706 | + 'detect_order' => self::$encodingList, |
|
707 | + 'substitute_character' => 'none', |
|
708 | + 'strict_detection' => 'Off', |
|
709 | + ]; |
|
710 | + |
|
711 | + if ('all' === $type) { |
|
712 | + return $info; |
|
713 | + } |
|
714 | + if (isset($info[$type])) { |
|
715 | + return $info[$type]; |
|
716 | + } |
|
717 | + |
|
718 | + return false; |
|
719 | + } |
|
720 | + |
|
721 | + public static function mb_http_input($type = '') |
|
722 | + { |
|
723 | + return false; |
|
724 | + } |
|
725 | + |
|
726 | + public static function mb_http_output($encoding = null) |
|
727 | + { |
|
728 | + return null !== $encoding ? 'pass' === $encoding : 'pass'; |
|
729 | + } |
|
730 | + |
|
731 | + public static function mb_strwidth($s, $encoding = null) |
|
732 | + { |
|
733 | + $encoding = self::getEncoding($encoding); |
|
734 | + |
|
735 | + if ('UTF-8' !== $encoding) { |
|
736 | + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); |
|
737 | + } |
|
738 | + |
|
739 | + $s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide); |
|
740 | + |
|
741 | + return ($wide << 1) + \iconv_strlen($s, 'UTF-8'); |
|
742 | + } |
|
743 | + |
|
744 | + public static function mb_substr_count($haystack, $needle, $encoding = null) |
|
745 | + { |
|
746 | + return substr_count($haystack, $needle); |
|
747 | + } |
|
748 | + |
|
749 | + public static function mb_output_handler($contents, $status) |
|
750 | + { |
|
751 | + return $contents; |
|
752 | + } |
|
753 | + |
|
754 | + public static function mb_chr($code, $encoding = null) |
|
755 | + { |
|
756 | + if (0x80 > $code %= 0x200000) { |
|
757 | + $s = \chr($code); |
|
758 | + } elseif (0x800 > $code) { |
|
759 | + $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); |
|
760 | + } elseif (0x10000 > $code) { |
|
761 | + $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); |
|
762 | + } else { |
|
763 | + $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); |
|
764 | + } |
|
765 | + |
|
766 | + if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { |
|
767 | + $s = mb_convert_encoding($s, $encoding, 'UTF-8'); |
|
768 | + } |
|
769 | + |
|
770 | + return $s; |
|
771 | + } |
|
772 | + |
|
773 | + public static function mb_ord($s, $encoding = null) |
|
774 | + { |
|
775 | + if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { |
|
776 | + $s = mb_convert_encoding($s, 'UTF-8', $encoding); |
|
777 | + } |
|
778 | + |
|
779 | + if (1 === \strlen($s)) { |
|
780 | + return \ord($s); |
|
781 | + } |
|
782 | + |
|
783 | + $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; |
|
784 | + if (0xF0 <= $code) { |
|
785 | + return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; |
|
786 | + } |
|
787 | + if (0xE0 <= $code) { |
|
788 | + return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; |
|
789 | + } |
|
790 | + if (0xC0 <= $code) { |
|
791 | + return (($code - 0xC0) << 6) + $s[2] - 0x80; |
|
792 | + } |
|
793 | + |
|
794 | + return $code; |
|
795 | + } |
|
796 | + |
|
797 | + private static function getSubpart($pos, $part, $haystack, $encoding) |
|
798 | + { |
|
799 | + if (false === $pos) { |
|
800 | + return false; |
|
801 | + } |
|
802 | + if ($part) { |
|
803 | + return self::mb_substr($haystack, 0, $pos, $encoding); |
|
804 | + } |
|
805 | + |
|
806 | + return self::mb_substr($haystack, $pos, null, $encoding); |
|
807 | + } |
|
808 | + |
|
809 | + private static function html_encoding_callback(array $m) |
|
810 | + { |
|
811 | + $i = 1; |
|
812 | + $entities = ''; |
|
813 | + $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8')); |
|
814 | + |
|
815 | + while (isset($m[$i])) { |
|
816 | + if (0x80 > $m[$i]) { |
|
817 | + $entities .= \chr($m[$i++]); |
|
818 | + continue; |
|
819 | + } |
|
820 | + if (0xF0 <= $m[$i]) { |
|
821 | + $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; |
|
822 | + } elseif (0xE0 <= $m[$i]) { |
|
823 | + $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; |
|
824 | + } else { |
|
825 | + $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80; |
|
826 | + } |
|
827 | + |
|
828 | + $entities .= '&#'.$c.';'; |
|
829 | + } |
|
830 | + |
|
831 | + return $entities; |
|
832 | + } |
|
833 | + |
|
834 | + private static function title_case(array $s) |
|
835 | + { |
|
836 | + return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8'); |
|
837 | + } |
|
838 | + |
|
839 | + private static function getData($file) |
|
840 | + { |
|
841 | + if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { |
|
842 | + return require $file; |
|
843 | + } |
|
844 | + |
|
845 | + return false; |
|
846 | + } |
|
847 | + |
|
848 | + private static function getEncoding($encoding) |
|
849 | + { |
|
850 | + if (null === $encoding) { |
|
851 | + return self::$internalEncoding; |
|
852 | + } |
|
853 | + |
|
854 | + if ('UTF-8' === $encoding) { |
|
855 | + return 'UTF-8'; |
|
856 | + } |
|
857 | + |
|
858 | + $encoding = strtoupper($encoding); |
|
859 | + |
|
860 | + if ('8BIT' === $encoding || 'BINARY' === $encoding) { |
|
861 | + return 'CP850'; |
|
862 | + } |
|
863 | + |
|
864 | + if ('UTF8' === $encoding) { |
|
865 | + return 'UTF-8'; |
|
866 | + } |
|
867 | + |
|
868 | + return $encoding; |
|
869 | + } |
|
870 | 870 | } |
@@ -12,132 +12,132 @@ |
||
12 | 12 | use Symfony\Polyfill\Mbstring as p; |
13 | 13 | |
14 | 14 | if (!function_exists('mb_convert_encoding')) { |
15 | - function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); } |
|
15 | + function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); } |
|
16 | 16 | } |
17 | 17 | if (!function_exists('mb_decode_mimeheader')) { |
18 | - function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); } |
|
18 | + function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); } |
|
19 | 19 | } |
20 | 20 | if (!function_exists('mb_encode_mimeheader')) { |
21 | - function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); } |
|
21 | + function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); } |
|
22 | 22 | } |
23 | 23 | if (!function_exists('mb_decode_numericentity')) { |
24 | - function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); } |
|
24 | + function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); } |
|
25 | 25 | } |
26 | 26 | if (!function_exists('mb_encode_numericentity')) { |
27 | - function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); } |
|
27 | + function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); } |
|
28 | 28 | } |
29 | 29 | if (!function_exists('mb_convert_case')) { |
30 | - function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); } |
|
30 | + function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); } |
|
31 | 31 | } |
32 | 32 | if (!function_exists('mb_internal_encoding')) { |
33 | - function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); } |
|
33 | + function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); } |
|
34 | 34 | } |
35 | 35 | if (!function_exists('mb_language')) { |
36 | - function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); } |
|
36 | + function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); } |
|
37 | 37 | } |
38 | 38 | if (!function_exists('mb_list_encodings')) { |
39 | - function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); } |
|
39 | + function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); } |
|
40 | 40 | } |
41 | 41 | if (!function_exists('mb_encoding_aliases')) { |
42 | - function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); } |
|
42 | + function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); } |
|
43 | 43 | } |
44 | 44 | if (!function_exists('mb_check_encoding')) { |
45 | - function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); } |
|
45 | + function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); } |
|
46 | 46 | } |
47 | 47 | if (!function_exists('mb_detect_encoding')) { |
48 | - function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); } |
|
48 | + function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); } |
|
49 | 49 | } |
50 | 50 | if (!function_exists('mb_detect_order')) { |
51 | - function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); } |
|
51 | + function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); } |
|
52 | 52 | } |
53 | 53 | if (!function_exists('mb_parse_str')) { |
54 | - function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; } |
|
54 | + function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; } |
|
55 | 55 | } |
56 | 56 | if (!function_exists('mb_strlen')) { |
57 | - function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); } |
|
57 | + function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); } |
|
58 | 58 | } |
59 | 59 | if (!function_exists('mb_strpos')) { |
60 | - function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } |
|
60 | + function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } |
|
61 | 61 | } |
62 | 62 | if (!function_exists('mb_strtolower')) { |
63 | - function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); } |
|
63 | + function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); } |
|
64 | 64 | } |
65 | 65 | if (!function_exists('mb_strtoupper')) { |
66 | - function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); } |
|
66 | + function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); } |
|
67 | 67 | } |
68 | 68 | if (!function_exists('mb_substitute_character')) { |
69 | - function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); } |
|
69 | + function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); } |
|
70 | 70 | } |
71 | 71 | if (!function_exists('mb_substr')) { |
72 | - function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); } |
|
72 | + function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); } |
|
73 | 73 | } |
74 | 74 | if (!function_exists('mb_stripos')) { |
75 | - function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } |
|
75 | + function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } |
|
76 | 76 | } |
77 | 77 | if (!function_exists('mb_stristr')) { |
78 | - function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } |
|
78 | + function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } |
|
79 | 79 | } |
80 | 80 | if (!function_exists('mb_strrchr')) { |
81 | - function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } |
|
81 | + function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } |
|
82 | 82 | } |
83 | 83 | if (!function_exists('mb_strrichr')) { |
84 | - function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } |
|
84 | + function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } |
|
85 | 85 | } |
86 | 86 | if (!function_exists('mb_strripos')) { |
87 | - function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } |
|
87 | + function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } |
|
88 | 88 | } |
89 | 89 | if (!function_exists('mb_strrpos')) { |
90 | - function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } |
|
90 | + function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } |
|
91 | 91 | } |
92 | 92 | if (!function_exists('mb_strstr')) { |
93 | - function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } |
|
93 | + function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } |
|
94 | 94 | } |
95 | 95 | if (!function_exists('mb_get_info')) { |
96 | - function mb_get_info(?string $type = 'all'): array|string|int|false { return p\Mbstring::mb_get_info((string) $type); } |
|
96 | + function mb_get_info(?string $type = 'all'): array|string|int|false { return p\Mbstring::mb_get_info((string) $type); } |
|
97 | 97 | } |
98 | 98 | if (!function_exists('mb_http_output')) { |
99 | - function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); } |
|
99 | + function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); } |
|
100 | 100 | } |
101 | 101 | if (!function_exists('mb_strwidth')) { |
102 | - function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); } |
|
102 | + function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); } |
|
103 | 103 | } |
104 | 104 | if (!function_exists('mb_substr_count')) { |
105 | - function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); } |
|
105 | + function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); } |
|
106 | 106 | } |
107 | 107 | if (!function_exists('mb_output_handler')) { |
108 | - function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); } |
|
108 | + function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); } |
|
109 | 109 | } |
110 | 110 | if (!function_exists('mb_http_input')) { |
111 | - function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); } |
|
111 | + function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); } |
|
112 | 112 | } |
113 | 113 | |
114 | 114 | if (!function_exists('mb_convert_variables')) { |
115 | - function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); } |
|
115 | + function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); } |
|
116 | 116 | } |
117 | 117 | |
118 | 118 | if (!function_exists('mb_ord')) { |
119 | - function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); } |
|
119 | + function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); } |
|
120 | 120 | } |
121 | 121 | if (!function_exists('mb_chr')) { |
122 | - function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); } |
|
122 | + function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); } |
|
123 | 123 | } |
124 | 124 | if (!function_exists('mb_scrub')) { |
125 | - function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); } |
|
125 | + function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); } |
|
126 | 126 | } |
127 | 127 | if (!function_exists('mb_str_split')) { |
128 | - function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); } |
|
128 | + function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); } |
|
129 | 129 | } |
130 | 130 | |
131 | 131 | if (extension_loaded('mbstring')) { |
132 | - return; |
|
132 | + return; |
|
133 | 133 | } |
134 | 134 | |
135 | 135 | if (!defined('MB_CASE_UPPER')) { |
136 | - define('MB_CASE_UPPER', 0); |
|
136 | + define('MB_CASE_UPPER', 0); |
|
137 | 137 | } |
138 | 138 | if (!defined('MB_CASE_LOWER')) { |
139 | - define('MB_CASE_LOWER', 1); |
|
139 | + define('MB_CASE_LOWER', 1); |
|
140 | 140 | } |
141 | 141 | if (!defined('MB_CASE_TITLE')) { |
142 | - define('MB_CASE_TITLE', 2); |
|
142 | + define('MB_CASE_TITLE', 2); |
|
143 | 143 | } |
@@ -12,12 +12,12 @@ |
||
12 | 12 | use Symfony\Polyfill\Intl\Normalizer as p; |
13 | 13 | |
14 | 14 | if (\PHP_VERSION_ID >= 80000) { |
15 | - return require __DIR__.'/bootstrap80.php'; |
|
15 | + return require __DIR__.'/bootstrap80.php'; |
|
16 | 16 | } |
17 | 17 | |
18 | 18 | if (!function_exists('normalizer_is_normalized')) { |
19 | - function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::isNormalized($string, $form); } |
|
19 | + function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::isNormalized($string, $form); } |
|
20 | 20 | } |
21 | 21 | if (!function_exists('normalizer_normalize')) { |
22 | - function normalizer_normalize($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::normalize($string, $form); } |
|
22 | + function normalizer_normalize($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::normalize($string, $form); } |
|
23 | 23 | } |
@@ -23,288 +23,288 @@ |
||
23 | 23 | */ |
24 | 24 | class Normalizer |
25 | 25 | { |
26 | - public const FORM_D = \Normalizer::FORM_D; |
|
27 | - public const FORM_KD = \Normalizer::FORM_KD; |
|
28 | - public const FORM_C = \Normalizer::FORM_C; |
|
29 | - public const FORM_KC = \Normalizer::FORM_KC; |
|
30 | - public const NFD = \Normalizer::NFD; |
|
31 | - public const NFKD = \Normalizer::NFKD; |
|
32 | - public const NFC = \Normalizer::NFC; |
|
33 | - public const NFKC = \Normalizer::NFKC; |
|
34 | - |
|
35 | - private static $C; |
|
36 | - private static $D; |
|
37 | - private static $KD; |
|
38 | - private static $cC; |
|
39 | - private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; |
|
40 | - private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; |
|
41 | - |
|
42 | - public static function isNormalized(string $s, int $form = self::FORM_C) |
|
43 | - { |
|
44 | - if (!\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) { |
|
45 | - return false; |
|
46 | - } |
|
47 | - if (!isset($s[strspn($s, self::$ASCII)])) { |
|
48 | - return true; |
|
49 | - } |
|
50 | - if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) { |
|
51 | - return true; |
|
52 | - } |
|
53 | - |
|
54 | - return self::normalize($s, $form) === $s; |
|
55 | - } |
|
56 | - |
|
57 | - public static function normalize(string $s, int $form = self::FORM_C) |
|
58 | - { |
|
59 | - if (!preg_match('//u', $s)) { |
|
60 | - return false; |
|
61 | - } |
|
62 | - |
|
63 | - switch ($form) { |
|
64 | - case self::NFC: $C = true; $K = false; break; |
|
65 | - case self::NFD: $C = false; $K = false; break; |
|
66 | - case self::NFKC: $C = true; $K = true; break; |
|
67 | - case self::NFKD: $C = false; $K = true; break; |
|
68 | - default: |
|
69 | - if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) { |
|
70 | - return $s; |
|
71 | - } |
|
72 | - |
|
73 | - if (80000 > \PHP_VERSION_ID) { |
|
74 | - return false; |
|
75 | - } |
|
76 | - |
|
77 | - throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form'); |
|
78 | - } |
|
79 | - |
|
80 | - if ('' === $s) { |
|
81 | - return ''; |
|
82 | - } |
|
83 | - |
|
84 | - if ($K && null === self::$KD) { |
|
85 | - self::$KD = self::getData('compatibilityDecomposition'); |
|
86 | - } |
|
87 | - |
|
88 | - if (null === self::$D) { |
|
89 | - self::$D = self::getData('canonicalDecomposition'); |
|
90 | - self::$cC = self::getData('combiningClass'); |
|
91 | - } |
|
92 | - |
|
93 | - if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) { |
|
94 | - mb_internal_encoding('8bit'); |
|
95 | - } |
|
96 | - |
|
97 | - $r = self::decompose($s, $K); |
|
98 | - |
|
99 | - if ($C) { |
|
100 | - if (null === self::$C) { |
|
101 | - self::$C = self::getData('canonicalComposition'); |
|
102 | - } |
|
103 | - |
|
104 | - $r = self::recompose($r); |
|
105 | - } |
|
106 | - if (null !== $mbEncoding) { |
|
107 | - mb_internal_encoding($mbEncoding); |
|
108 | - } |
|
109 | - |
|
110 | - return $r; |
|
111 | - } |
|
112 | - |
|
113 | - private static function recompose($s) |
|
114 | - { |
|
115 | - $ASCII = self::$ASCII; |
|
116 | - $compMap = self::$C; |
|
117 | - $combClass = self::$cC; |
|
118 | - $ulenMask = self::$ulenMask; |
|
119 | - |
|
120 | - $result = $tail = ''; |
|
121 | - |
|
122 | - $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"]; |
|
123 | - $len = \strlen($s); |
|
124 | - |
|
125 | - $lastUchr = substr($s, 0, $i); |
|
126 | - $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0; |
|
127 | - |
|
128 | - while ($i < $len) { |
|
129 | - if ($s[$i] < "\x80") { |
|
130 | - // ASCII chars |
|
131 | - |
|
132 | - if ($tail) { |
|
133 | - $lastUchr .= $tail; |
|
134 | - $tail = ''; |
|
135 | - } |
|
136 | - |
|
137 | - if ($j = strspn($s, $ASCII, $i + 1)) { |
|
138 | - $lastUchr .= substr($s, $i, $j); |
|
139 | - $i += $j; |
|
140 | - } |
|
141 | - |
|
142 | - $result .= $lastUchr; |
|
143 | - $lastUchr = $s[$i]; |
|
144 | - $lastUcls = 0; |
|
145 | - ++$i; |
|
146 | - continue; |
|
147 | - } |
|
148 | - |
|
149 | - $ulen = $ulenMask[$s[$i] & "\xF0"]; |
|
150 | - $uchr = substr($s, $i, $ulen); |
|
151 | - |
|
152 | - if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr |
|
153 | - || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr |
|
154 | - || $lastUcls) { |
|
155 | - // Table lookup and combining chars composition |
|
156 | - |
|
157 | - $ucls = $combClass[$uchr] ?? 0; |
|
158 | - |
|
159 | - if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) { |
|
160 | - $lastUchr = $compMap[$lastUchr.$uchr]; |
|
161 | - } elseif ($lastUcls = $ucls) { |
|
162 | - $tail .= $uchr; |
|
163 | - } else { |
|
164 | - if ($tail) { |
|
165 | - $lastUchr .= $tail; |
|
166 | - $tail = ''; |
|
167 | - } |
|
168 | - |
|
169 | - $result .= $lastUchr; |
|
170 | - $lastUchr = $uchr; |
|
171 | - } |
|
172 | - } else { |
|
173 | - // Hangul chars |
|
174 | - |
|
175 | - $L = \ord($lastUchr[2]) - 0x80; |
|
176 | - $V = \ord($uchr[2]) - 0xA1; |
|
177 | - $T = 0; |
|
178 | - |
|
179 | - $uchr = substr($s, $i + $ulen, 3); |
|
180 | - |
|
181 | - if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") { |
|
182 | - $T = \ord($uchr[2]) - 0xA7; |
|
183 | - 0 > $T && $T += 0x40; |
|
184 | - $ulen += 3; |
|
185 | - } |
|
186 | - |
|
187 | - $L = 0xAC00 + ($L * 21 + $V) * 28 + $T; |
|
188 | - $lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F); |
|
189 | - } |
|
190 | - |
|
191 | - $i += $ulen; |
|
192 | - } |
|
193 | - |
|
194 | - return $result.$lastUchr.$tail; |
|
195 | - } |
|
196 | - |
|
197 | - private static function decompose($s, $c) |
|
198 | - { |
|
199 | - $result = ''; |
|
200 | - |
|
201 | - $ASCII = self::$ASCII; |
|
202 | - $decompMap = self::$D; |
|
203 | - $combClass = self::$cC; |
|
204 | - $ulenMask = self::$ulenMask; |
|
205 | - if ($c) { |
|
206 | - $compatMap = self::$KD; |
|
207 | - } |
|
208 | - |
|
209 | - $c = []; |
|
210 | - $i = 0; |
|
211 | - $len = \strlen($s); |
|
212 | - |
|
213 | - while ($i < $len) { |
|
214 | - if ($s[$i] < "\x80") { |
|
215 | - // ASCII chars |
|
216 | - |
|
217 | - if ($c) { |
|
218 | - ksort($c); |
|
219 | - $result .= implode('', $c); |
|
220 | - $c = []; |
|
221 | - } |
|
222 | - |
|
223 | - $j = 1 + strspn($s, $ASCII, $i + 1); |
|
224 | - $result .= substr($s, $i, $j); |
|
225 | - $i += $j; |
|
226 | - continue; |
|
227 | - } |
|
228 | - |
|
229 | - $ulen = $ulenMask[$s[$i] & "\xF0"]; |
|
230 | - $uchr = substr($s, $i, $ulen); |
|
231 | - $i += $ulen; |
|
232 | - |
|
233 | - if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) { |
|
234 | - // Table lookup |
|
235 | - |
|
236 | - if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) { |
|
237 | - $uchr = $j; |
|
238 | - |
|
239 | - $j = \strlen($uchr); |
|
240 | - $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"]; |
|
241 | - |
|
242 | - if ($ulen != $j) { |
|
243 | - // Put trailing chars in $s |
|
244 | - |
|
245 | - $j -= $ulen; |
|
246 | - $i -= $j; |
|
247 | - |
|
248 | - if (0 > $i) { |
|
249 | - $s = str_repeat(' ', -$i).$s; |
|
250 | - $len -= $i; |
|
251 | - $i = 0; |
|
252 | - } |
|
253 | - |
|
254 | - while ($j--) { |
|
255 | - $s[$i + $j] = $uchr[$ulen + $j]; |
|
256 | - } |
|
257 | - |
|
258 | - $uchr = substr($uchr, 0, $ulen); |
|
259 | - } |
|
260 | - } |
|
261 | - if (isset($combClass[$uchr])) { |
|
262 | - // Combining chars, for sorting |
|
263 | - |
|
264 | - if (!isset($c[$combClass[$uchr]])) { |
|
265 | - $c[$combClass[$uchr]] = ''; |
|
266 | - } |
|
267 | - $c[$combClass[$uchr]] .= $uchr; |
|
268 | - continue; |
|
269 | - } |
|
270 | - } else { |
|
271 | - // Hangul chars |
|
272 | - |
|
273 | - $uchr = unpack('C*', $uchr); |
|
274 | - $j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80; |
|
275 | - |
|
276 | - $uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588)) |
|
277 | - ."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28)); |
|
278 | - |
|
279 | - if ($j %= 28) { |
|
280 | - $uchr .= $j < 25 |
|
281 | - ? ("\xE1\x86".\chr(0xA7 + $j)) |
|
282 | - : ("\xE1\x87".\chr(0x67 + $j)); |
|
283 | - } |
|
284 | - } |
|
285 | - if ($c) { |
|
286 | - ksort($c); |
|
287 | - $result .= implode('', $c); |
|
288 | - $c = []; |
|
289 | - } |
|
290 | - |
|
291 | - $result .= $uchr; |
|
292 | - } |
|
293 | - |
|
294 | - if ($c) { |
|
295 | - ksort($c); |
|
296 | - $result .= implode('', $c); |
|
297 | - } |
|
298 | - |
|
299 | - return $result; |
|
300 | - } |
|
301 | - |
|
302 | - private static function getData($file) |
|
303 | - { |
|
304 | - if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { |
|
305 | - return require $file; |
|
306 | - } |
|
307 | - |
|
308 | - return false; |
|
309 | - } |
|
26 | + public const FORM_D = \Normalizer::FORM_D; |
|
27 | + public const FORM_KD = \Normalizer::FORM_KD; |
|
28 | + public const FORM_C = \Normalizer::FORM_C; |
|
29 | + public const FORM_KC = \Normalizer::FORM_KC; |
|
30 | + public const NFD = \Normalizer::NFD; |
|
31 | + public const NFKD = \Normalizer::NFKD; |
|
32 | + public const NFC = \Normalizer::NFC; |
|
33 | + public const NFKC = \Normalizer::NFKC; |
|
34 | + |
|
35 | + private static $C; |
|
36 | + private static $D; |
|
37 | + private static $KD; |
|
38 | + private static $cC; |
|
39 | + private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; |
|
40 | + private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; |
|
41 | + |
|
42 | + public static function isNormalized(string $s, int $form = self::FORM_C) |
|
43 | + { |
|
44 | + if (!\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) { |
|
45 | + return false; |
|
46 | + } |
|
47 | + if (!isset($s[strspn($s, self::$ASCII)])) { |
|
48 | + return true; |
|
49 | + } |
|
50 | + if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) { |
|
51 | + return true; |
|
52 | + } |
|
53 | + |
|
54 | + return self::normalize($s, $form) === $s; |
|
55 | + } |
|
56 | + |
|
57 | + public static function normalize(string $s, int $form = self::FORM_C) |
|
58 | + { |
|
59 | + if (!preg_match('//u', $s)) { |
|
60 | + return false; |
|
61 | + } |
|
62 | + |
|
63 | + switch ($form) { |
|
64 | + case self::NFC: $C = true; $K = false; break; |
|
65 | + case self::NFD: $C = false; $K = false; break; |
|
66 | + case self::NFKC: $C = true; $K = true; break; |
|
67 | + case self::NFKD: $C = false; $K = true; break; |
|
68 | + default: |
|
69 | + if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) { |
|
70 | + return $s; |
|
71 | + } |
|
72 | + |
|
73 | + if (80000 > \PHP_VERSION_ID) { |
|
74 | + return false; |
|
75 | + } |
|
76 | + |
|
77 | + throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form'); |
|
78 | + } |
|
79 | + |
|
80 | + if ('' === $s) { |
|
81 | + return ''; |
|
82 | + } |
|
83 | + |
|
84 | + if ($K && null === self::$KD) { |
|
85 | + self::$KD = self::getData('compatibilityDecomposition'); |
|
86 | + } |
|
87 | + |
|
88 | + if (null === self::$D) { |
|
89 | + self::$D = self::getData('canonicalDecomposition'); |
|
90 | + self::$cC = self::getData('combiningClass'); |
|
91 | + } |
|
92 | + |
|
93 | + if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) { |
|
94 | + mb_internal_encoding('8bit'); |
|
95 | + } |
|
96 | + |
|
97 | + $r = self::decompose($s, $K); |
|
98 | + |
|
99 | + if ($C) { |
|
100 | + if (null === self::$C) { |
|
101 | + self::$C = self::getData('canonicalComposition'); |
|
102 | + } |
|
103 | + |
|
104 | + $r = self::recompose($r); |
|
105 | + } |
|
106 | + if (null !== $mbEncoding) { |
|
107 | + mb_internal_encoding($mbEncoding); |
|
108 | + } |
|
109 | + |
|
110 | + return $r; |
|
111 | + } |
|
112 | + |
|
113 | + private static function recompose($s) |
|
114 | + { |
|
115 | + $ASCII = self::$ASCII; |
|
116 | + $compMap = self::$C; |
|
117 | + $combClass = self::$cC; |
|
118 | + $ulenMask = self::$ulenMask; |
|
119 | + |
|
120 | + $result = $tail = ''; |
|
121 | + |
|
122 | + $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"]; |
|
123 | + $len = \strlen($s); |
|
124 | + |
|
125 | + $lastUchr = substr($s, 0, $i); |
|
126 | + $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0; |
|
127 | + |
|
128 | + while ($i < $len) { |
|
129 | + if ($s[$i] < "\x80") { |
|
130 | + // ASCII chars |
|
131 | + |
|
132 | + if ($tail) { |
|
133 | + $lastUchr .= $tail; |
|
134 | + $tail = ''; |
|
135 | + } |
|
136 | + |
|
137 | + if ($j = strspn($s, $ASCII, $i + 1)) { |
|
138 | + $lastUchr .= substr($s, $i, $j); |
|
139 | + $i += $j; |
|
140 | + } |
|
141 | + |
|
142 | + $result .= $lastUchr; |
|
143 | + $lastUchr = $s[$i]; |
|
144 | + $lastUcls = 0; |
|
145 | + ++$i; |
|
146 | + continue; |
|
147 | + } |
|
148 | + |
|
149 | + $ulen = $ulenMask[$s[$i] & "\xF0"]; |
|
150 | + $uchr = substr($s, $i, $ulen); |
|
151 | + |
|
152 | + if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr |
|
153 | + || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr |
|
154 | + || $lastUcls) { |
|
155 | + // Table lookup and combining chars composition |
|
156 | + |
|
157 | + $ucls = $combClass[$uchr] ?? 0; |
|
158 | + |
|
159 | + if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) { |
|
160 | + $lastUchr = $compMap[$lastUchr.$uchr]; |
|
161 | + } elseif ($lastUcls = $ucls) { |
|
162 | + $tail .= $uchr; |
|
163 | + } else { |
|
164 | + if ($tail) { |
|
165 | + $lastUchr .= $tail; |
|
166 | + $tail = ''; |
|
167 | + } |
|
168 | + |
|
169 | + $result .= $lastUchr; |
|
170 | + $lastUchr = $uchr; |
|
171 | + } |
|
172 | + } else { |
|
173 | + // Hangul chars |
|
174 | + |
|
175 | + $L = \ord($lastUchr[2]) - 0x80; |
|
176 | + $V = \ord($uchr[2]) - 0xA1; |
|
177 | + $T = 0; |
|
178 | + |
|
179 | + $uchr = substr($s, $i + $ulen, 3); |
|
180 | + |
|
181 | + if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") { |
|
182 | + $T = \ord($uchr[2]) - 0xA7; |
|
183 | + 0 > $T && $T += 0x40; |
|
184 | + $ulen += 3; |
|
185 | + } |
|
186 | + |
|
187 | + $L = 0xAC00 + ($L * 21 + $V) * 28 + $T; |
|
188 | + $lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F); |
|
189 | + } |
|
190 | + |
|
191 | + $i += $ulen; |
|
192 | + } |
|
193 | + |
|
194 | + return $result.$lastUchr.$tail; |
|
195 | + } |
|
196 | + |
|
197 | + private static function decompose($s, $c) |
|
198 | + { |
|
199 | + $result = ''; |
|
200 | + |
|
201 | + $ASCII = self::$ASCII; |
|
202 | + $decompMap = self::$D; |
|
203 | + $combClass = self::$cC; |
|
204 | + $ulenMask = self::$ulenMask; |
|
205 | + if ($c) { |
|
206 | + $compatMap = self::$KD; |
|
207 | + } |
|
208 | + |
|
209 | + $c = []; |
|
210 | + $i = 0; |
|
211 | + $len = \strlen($s); |
|
212 | + |
|
213 | + while ($i < $len) { |
|
214 | + if ($s[$i] < "\x80") { |
|
215 | + // ASCII chars |
|
216 | + |
|
217 | + if ($c) { |
|
218 | + ksort($c); |
|
219 | + $result .= implode('', $c); |
|
220 | + $c = []; |
|
221 | + } |
|
222 | + |
|
223 | + $j = 1 + strspn($s, $ASCII, $i + 1); |
|
224 | + $result .= substr($s, $i, $j); |
|
225 | + $i += $j; |
|
226 | + continue; |
|
227 | + } |
|
228 | + |
|
229 | + $ulen = $ulenMask[$s[$i] & "\xF0"]; |
|
230 | + $uchr = substr($s, $i, $ulen); |
|
231 | + $i += $ulen; |
|
232 | + |
|
233 | + if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) { |
|
234 | + // Table lookup |
|
235 | + |
|
236 | + if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) { |
|
237 | + $uchr = $j; |
|
238 | + |
|
239 | + $j = \strlen($uchr); |
|
240 | + $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"]; |
|
241 | + |
|
242 | + if ($ulen != $j) { |
|
243 | + // Put trailing chars in $s |
|
244 | + |
|
245 | + $j -= $ulen; |
|
246 | + $i -= $j; |
|
247 | + |
|
248 | + if (0 > $i) { |
|
249 | + $s = str_repeat(' ', -$i).$s; |
|
250 | + $len -= $i; |
|
251 | + $i = 0; |
|
252 | + } |
|
253 | + |
|
254 | + while ($j--) { |
|
255 | + $s[$i + $j] = $uchr[$ulen + $j]; |
|
256 | + } |
|
257 | + |
|
258 | + $uchr = substr($uchr, 0, $ulen); |
|
259 | + } |
|
260 | + } |
|
261 | + if (isset($combClass[$uchr])) { |
|
262 | + // Combining chars, for sorting |
|
263 | + |
|
264 | + if (!isset($c[$combClass[$uchr]])) { |
|
265 | + $c[$combClass[$uchr]] = ''; |
|
266 | + } |
|
267 | + $c[$combClass[$uchr]] .= $uchr; |
|
268 | + continue; |
|
269 | + } |
|
270 | + } else { |
|
271 | + // Hangul chars |
|
272 | + |
|
273 | + $uchr = unpack('C*', $uchr); |
|
274 | + $j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80; |
|
275 | + |
|
276 | + $uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588)) |
|
277 | + ."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28)); |
|
278 | + |
|
279 | + if ($j %= 28) { |
|
280 | + $uchr .= $j < 25 |
|
281 | + ? ("\xE1\x86".\chr(0xA7 + $j)) |
|
282 | + : ("\xE1\x87".\chr(0x67 + $j)); |
|
283 | + } |
|
284 | + } |
|
285 | + if ($c) { |
|
286 | + ksort($c); |
|
287 | + $result .= implode('', $c); |
|
288 | + $c = []; |
|
289 | + } |
|
290 | + |
|
291 | + $result .= $uchr; |
|
292 | + } |
|
293 | + |
|
294 | + if ($c) { |
|
295 | + ksort($c); |
|
296 | + $result .= implode('', $c); |
|
297 | + } |
|
298 | + |
|
299 | + return $result; |
|
300 | + } |
|
301 | + |
|
302 | + private static function getData($file) |
|
303 | + { |
|
304 | + if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { |
|
305 | + return require $file; |
|
306 | + } |
|
307 | + |
|
308 | + return false; |
|
309 | + } |
|
310 | 310 | } |