Skip to content

Commit 8407bfe

Browse files
committed
feat: use mbstring if iconv is not working
Signed-off-by: Jack Cherng <[email protected]>
1 parent bbf3ec1 commit 8407bfe

File tree

3 files changed

+51
-10
lines changed

3 files changed

+51
-10
lines changed

composer.json

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
"phan/phan": "^5",
3737
"phpunit/phpunit": "^9 || ^10"
3838
},
39+
"suggest": {
40+
"ext-iconv": "Either \"ext-iconv\" or \"ext-mbstring\" is requried.",
41+
"ext-mbstring": "Either \"ext-iconv\" or \"ext-mbstring\" is requried."
42+
},
3943
"scripts": {
4044
"analyze": [
4145
"phan --color"

composer.lock

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/MbString.php

+41-4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@
1717
*/
1818
class MbString extends \ArrayObject implements \Stringable
1919
{
20+
public const MBSTRING_CONVMETHOD_ICONV = 1;
21+
public const MBSTRING_CONVMETHOD_MBSTRING = 2;
22+
23+
/**
24+
* The way to convert text encoding.
25+
*
26+
* @var int
27+
*/
28+
public static $convMethod;
29+
2030
/**
2131
* UTF-32 string without endian bytes.
2232
*
@@ -46,7 +56,8 @@ class MbString extends \ArrayObject implements \Stringable
4656
*/
4757
public function __construct(string $str = '', string $encoding = 'UTF-8')
4858
{
49-
static::$utf32Header = static::$utf32Header ?? static::getUtf32Header();
59+
static::$convMethod ??= static::detectConvEncoding();
60+
static::$utf32Header ??= static::getUtf32Header();
5061

5162
$this->encoding = $encoding;
5263
$this->set($str);
@@ -328,11 +339,37 @@ public function count(): int
328339
protected static function getUtf32Header(): string
329340
{
330341
// just use any string to get the endian header, here we use "A"
331-
$tmp = iconv('UTF-8', 'UTF-32', 'A');
342+
$tmp = self::convEncoding('A', 'UTF-8', 'UTF-32');
332343
// some distributions like "php alpine" docker image won't generate the header
333344
return $tmp && \strlen($tmp) > 4 ? substr($tmp, 0, 4) : '';
334345
}
335346

347+
protected static function detectConvEncoding(): int
348+
{
349+
if (\function_exists('iconv') && iconv('UTF-8', 'UTF-32', 'A') !== false) {
350+
return static::MBSTRING_CONVMETHOD_ICONV;
351+
}
352+
353+
if (\function_exists('mb_convert_encoding') && mb_convert_encoding('A', 'UTF-32', 'UTF-8') !== false) {
354+
return static::MBSTRING_CONVMETHOD_MBSTRING;
355+
}
356+
357+
throw new \RuntimeException('Either "iconv" or "mbstring" extension is required.');
358+
}
359+
360+
protected static function convEncoding(string $str, string $from, string $to): string
361+
{
362+
if (static::$convMethod === static::MBSTRING_CONVMETHOD_ICONV) {
363+
return iconv($from, $to, $str);
364+
}
365+
366+
if (static::$convMethod === static::MBSTRING_CONVMETHOD_MBSTRING) {
367+
return mb_convert_encoding($str, $to, $from);
368+
}
369+
370+
throw new \RuntimeException('Unknown conversion method.');
371+
}
372+
336373
/**
337374
* Convert the output string to its original encoding.
338375
*
@@ -344,7 +381,7 @@ protected function outputConv(string $str): string
344381
return '';
345382
}
346383

347-
return iconv('UTF-32', $this->encoding, static::$utf32Header . $str);
384+
return static::convEncoding(static::$utf32Header . $str, 'UTF-32', $this->encoding);
348385
}
349386

350387
/**
@@ -358,6 +395,6 @@ protected function inputConv(string $str): string
358395
return '';
359396
}
360397

361-
return substr(iconv($this->encoding, 'UTF-32', $str), \strlen(static::$utf32Header));
398+
return substr(static::convEncoding($str, $this->encoding, 'UTF-32'), \strlen(static::$utf32Header));
362399
}
363400
}

0 commit comments

Comments
 (0)