Правда ли, что строковые литералы в PHP могут быть закодированы только в кодировке, которая является совместимым расширенным набором ASCII, такой как UTF-8 или ISO-8859-1? - PullRequest
0 голосов
/ 23 сентября 2018

Я сталкиваюсь со следующим текстом со страницы Сведения о типе строки из руководства по PHP:

Учитывая, что PHP не диктует определенную кодировку для строк, можно задаться вопросомкак кодируются строковые литералы.Строка будет закодирована любым способом, который закодирован в файле сценария.Таким образом, если сценарий написан в ISO-8859-1, строка будет закодирована в ISO-8859-1 и так далее.Однако это не применяется, если включен Zend Multibyte;в этом случае сценарий может быть написан в произвольной кодировке (которая объявляется или определяется явным образом), а затем преобразуется в определенную внутреннюю кодировку, которая затем является кодировкой, которая будет использоваться для строковых литералов.Обратите внимание, что существуют некоторые ограничения на кодировку скрипта (или на внутреннюю кодировку, если Zend Multibyte включен) - это почти всегда означает, что эта кодировка должна быть совместимым надмножеством ASCII, таким как UTF-8 или ISO-8859-1.

Поэтому я сомневаюсь, правда ли, что строковые литералы в PHP могут только быть закодированы в кодировке, которая является совместимым расширенным набором ASCII , например UTF-8 или ISO-8859-1 и не в кодировке, которая не совместима с расширенным набором ASCII ?

Можно ли кодировать строковые литералы в PHP в некоторых не-ASCII-совместимых кодировках, таких как UTF-16 , UTF-32 или некоторых других таких не ASCII-совместимая кодировка ?Если да, то будут ли строковые литералы, закодированные в такой кодировке , не совместимой с ASCII, работать с mb_string_ * functions ?Если нет, то в чем причина?

Предположим, Zend Multibyte включен, и я установил внутреннюю кодировку для совместимого расширенного набора ASCII , например UTF-8 или ISO-8859-1 или какое-либо другое не-ASCII-совместимое кодирование .Теперь я могу объявить кодировку, которая не совместима с ASCII , например UTF-16 или UTF-32 вфайл скрипта?

Если да, то в каком случае кодируется строковый литерал?Если нет, то в чем причина?

Кроме того, объясните мне, как эта штука 1060 * работает для строковых литералов, если Zend Multibyte включен?

Как включить Zend Multibyte ?Каково главное намерение включить его на ?Когда требуется включить его Вкл. ?

Было бы лучше, если бы вы могли прояснить мои сомнения с помощью подходящих примеров.

Спасибо.

Ответы [ 3 ]

0 голосов
/ 11 октября 2018

Строковые литералы в файлах исходного кода PHP воспринимаются буквально как необработанные байты, присутствующие в файле исходного кода.Если в вашем исходном коде есть байты, которые представляют строку UTF-16 или что-то еще, то вы можете использовать их напрямую:

$ echo -n '<?php echo "' > test.php
$ echo -n 日本語 | iconv -t UTF-16 >> test.php 
$ echo '";' >> test.php 
$ cat test.php 
<?php echo "??e?g,??";
$ cat test.php | xxd
00000000: 3c3f 7068 7020 6563 686f 2022 feff 65e5  <?php echo "..e.
00000010: 672c 8a9e 223b 0a                        g,..";.
$ php test.php 
??e?g,??$ 
$ php test.php | iconv -f UTF-16
日本語

Это демонстрирует файл исходного кода, якобы написанный в ASCII, но содержащийСтроковый литерал UTF-16 посередине, который выводится как есть.

Большая проблема с этим видом исходного кода состоит в том, что с ним трудно работать.Это где-то между болью в шее и невозможностью получить текстовый редактор для обработки кода PHP в одной кодировке и строковых литералов в другой.Поэтому, как правило, вы хотите хранить весь исходный код, включая строковые литералы, в одной и той же кодировке.

Вы также можете легко попасть в неприятности:

$ echo -n '<?php echo "' > test.php
$ echo -n 漢字 | iconv -t UTF-16 >> test.php 
$ echo '";' >> test.php 
$ cat test.php | xxd
00000000: 3c3f 7068 7020 6563 686f 2022 feff 6f22  <?php echo "..o"
00000010: 5b57 223b 0a                             [W";.

"漢字"здесь кодируется feff 6f22 5b57, который содержит 22 или ", строковый литерал-терминатор, что означает, что у вас сейчас есть синтаксическая ошибка.

По умолчанию интерпретатор PHP ожидает, что код PHP будет ASCIIсовместимы, поэтому, если вы хотите сохранить строковые литералы и остальную часть исходного кода в одной кодировке, вы в значительной степени ограничены ASCII-совместимыми кодировками.Однако расширение Zend Multibyte позволяет вам использовать другие кодировки , если вы соответственно объявляете используемую кодировку (в php.ini, если она не совместима с ASCII).Таким образом, вы можете написать свой исходный код, скажем, в Shift-JIS;возможно даже со строковыми литералами в какой-то другой кодировке *.

* (В этот момент я перестану вдаваться в детали, потому что что с тобой не так ?!)

Резюме:

  • PHP должен понимать весь код PHP;по умолчанию он понимает ASCII, а с Zend Multibyte он может понимать и другие кодировки.
  • Строковые литералы в исходном коде могут содержать любые байты, которые вы хотите, если PHP не интерпретирует их как специальные символы встроковый литерал (например, пример 22 выше), в этом случае вам нужно их экранировать (с обратной косой чертой в кодировке общего исходного кода).
  • Строковое значение во время выполнения будет необработаннымпоследовательность байтов, которую PHP читает из строкового литерала.

Сказав все это, обычно боль в шее расходится с кодировками, совместимыми с ASCII.Это боль в текстовых редакторах и легко приводит к mojibake, если какой-то инструмент в вашем рабочем процессе неправильно обрабатывает файл.Самое большее, я бы посоветовал использовать ASCII-совместимые кодировки, например:

echo "日本語";  // UTF-8 encoded (let's hope)

Если вам нужен не-ASCII-совместимый строковый литерал, вы должны использовать байтовую нотацию:

echo "\xfe\xff\x65\xe5\x67\x2c\x8a\x9e";

Или преобразование:

echo iconv('UTF-8', 'UTF-16', '日本語');

[..] будут ли строковые литералы, закодированные в таком кодировке, не совместимом с ASCII, работать с функциями mb_string_*?

Конечно, строки в PHP являются необработанными байтовыми массивами для любых целей и задач.Неважно, как вы получили эту строку.Если у вас есть строка UTF-16, полученная с помощью любого из методов, показанных выше, в том числе путем жесткого кодирования ее в UTF-16 в исходный код, у вас есть строка в кодировке UTF-16, и вы можете передать ее через любую и все строковые функции, которыезнаю, как с этим справиться.

0 голосов
/ 15 октября 2018

Поэтому я сомневаюсь, правда ли, что строковые литералы в PHP могут быть закодированы только в кодировке, которая является совместимым расширенным набором ASCII, такой как UTF-8 или ISO-8859-1, а не в кодировкекоторый не является совместимым надмножеством ASCII?

Это не так.

Возможно ли кодировать строковые литералы в PHP в некоторых не ASCII-совместимых кодировках, таких как UTF-16, UTF-32 или какая-то другая не ASCII-совместимая кодировка?Если да, то будут ли строковые литералы, закодированные в такой кодировке, не совместимой с ASCII, работать с функциями mb_string_ *?Если нет, то в чем причина?

Как говорит @deceze, вы можете легко преобразовать строку в нужную вам кодировку с помощью mb_convert_encoding или iconv .

Из Сведения о типе строки в PHP Manual, String будет закодирован любым способом, который закодирован в файле сценария.PHP, созданный с поддержкой Zend Multibyte и расширением mbstring, может анализировать и запускать файлы PHP, закодированные в кодировке, не совместимой с ASCII, например UTF-16, см. Тесты в Zend / многобайтовых .

Zend/tests/multibyte/multibyte_encoding_003.phpt продемонстрировано для запуска источников с кодировкой UTF-16 LE, которые правильно выводят Hello World.

Zend / tests / multibyte / multibyte_encoding_003.phpt

--TEST--
Zend Multibyte and UTF-16 BOM
--SKIPIF--
<?php
if (!in_array("zend.detect_unicode", array_keys(ini_get_all()))) {
  die("skip Requires configure --enable-zend-multibyte option");
}
if (!extension_loaded("mbstring")) {
  die("skip Requires mbstring extension");
}
?>
--INI--
zend.multibyte=1
mbstring.internal_encoding=iso-8859-1
--FILE--
<?php
print "Hello World\n";
?>
===DONE===

--EXPECT--
Hello World
===DONE===

$ run-tests.php --keep-php --show-out --show-php Zend / tests / multibyte / multibyte_encoding_003.phpt

 ... skip some trivial message ...
Running selected tests.
TEST 1/1 [multibyte_encoding_003.phpt]
========TEST========
<?php
print "Hello World\n";
?>
===DONE===
========DONE========

========OUT========
Hello World
===DONE===
========DONE========
PASS Zend Multibyte and UTF-16 BOM [multibyte_encoding_003.phpt]
=====================================================================
Number of tests :    1                 1
Tests skipped   :    0 (  0.0%) --------
Tests warned    :    0 (  0.0%) (  0.0%)
Tests failed    :    0 (  0.0%) (  0.0%)
Expected fail   :    0 (  0.0%) (  0.0%)
Tests passed    :    1 (100.0%) (100.0%)
---------------------------------------------------------------------
Time taken      :    0 seconds
=====================================================================

$файл multibyte_encoding_003.php

multibyte_encoding_003.php: PHP script text, Little-endian UTF-16 Unicode text

Другой пример - Zend/tests/multibyte/multibyte_encoding_004.phpt, он запускает источник с кодировкой Shift JIS .

Zend / tests/multibyte/multibyte_encoding_004.phpt (Примечание. Некоторые японские символы отображаются неправильно из-за смешивания кодировки в одном файле, а для LC_MESSAGE установлено значение UTF-8)

--TEST--
test for mbstring script_encoding for flex unsafe encoding (Shift_JIS)
--SKIPIF--
<?php
if (!in_array("zend.detect_unicode", array_keys(ini_get_all()))) {
  die("skip Requires configure --enable-zend-multibyte option");
}
if (!extension_loaded("mbstring")) {
  die("skip Requires mbstring extension");
}
?>
--INI--
zend.multibyte=1
zend.script_encoding=Shift_JIS
mbstring.internal_encoding=Shift_JIS
--FILE--
<?php
        function \\\($)
        {
                echo $;
        }

        \\\("h~t@\");
?>
--EXPECT--
h~t@\

$run-tests.php --keep-php --show-out --show-php
./multibyte_encoding_004.phpt

 ... skip some trivial message ...
Running selected tests.
TEST 1/1 [multibyte_encoding_004.phpt]
========TEST========
<?php
        function \\\($)
        {
                echo $;
        }

        \\\("h~t@\");
?>
========DONE========

========OUT========
h~t@\
========DONE========
PASS test for mbstring script_encoding for flex unsafe encoding (Shift_JIS) [multibyte_encoding_004.phpt]
=====================================================================
Number of tests :    1                 1
Tests skipped   :    0 (  0.0%) --------
Tests warned    :    0 (  0.0%) (  0.0%)
Tests failed    :    0 (  0.0%) (  0.0%)
Expected fail   :    0 (  0.0%) (  0.0%)
Tests passed    :    1 (100.0%) (100.0%)
---------------------------------------------------------------------
Time taken      :    0 seconds
=====================================================================

$ file Zend / tests / multibyte / multibyte_encoding_004.php

multibyte_encoding_004.php: PHP script text, Non-ISO extended-ASCII text

$ cat Zend / tests / multibyte / multibyte_encoding_004.php |iconv -f SJIS -t utf-8

<?php
        function 予蚕能($引数)
        {
                echo $引数;
        }

        予蚕能("ドレミファソ");
?>

Возможно ли кодировать строковые литералы в PHP в некоторых кодировках, не совместимых с ASCII, таких как UTF-16, UTF-32 или некоторые другиедругое такое не ASCII-совместимое кодирование?Если да, то будут ли строковые литералы, закодированные в такой кодировке, не совместимой с ASCII, работать с функциями mb_string_ *?Если нет, то в чем причина?

Ответ на первый вопрос - да, тесты для Zend Multibyte убедительно продемонстрированы.Ответ на второй вопрос также положительный, если дать правильные подсказки кодирования для mb_string_*.

Предположим, Zend Multibyte включен, и я установил внутреннюю кодировку для совместимого расширенного набора ASCII,такие как UTF-8 или ISO-8859-1 или некоторые другие не ASCII-совместимые кодировки.Теперь я могу объявить кодировку, которая не является совместимым надмножеством ASCII, например UTF-16 или UTF-32, в файле сценария?

Если да, то в этом случае, какую кодировку получат строковые литералызакодировано в?Если нет, то в чем причина?

Да, выходные данные, генерируемые второй командой, представляют собой кодировку UTF-32 (представляет один символ в виде 4 байтов)

$ echo -e '<?php\necho "Hello 中文";' | php  | hexdump -C
00000000  48 65 6c 6c 6f 20 e4 b8  ad e6 96 87              |Hello ......|
0000000c

$ echo '<?php\\necho "Hello 中文";' | iconv -t utf-16 | php -d zend.multibyte=1 -d zend.script_encoding=UTF-16 -d mbstring.internal_encoding=UTF-32 | hexdump -C
00000000  00 00 00 48 00 00 00 65  00 00 00 6c 00 00 00 6c  |...H...e...l...l|
00000010  00 00 00 6f 00 00 00 20  00 00 4e 2d 00 00 65 87  |...o... ..N-..e.|
00000020

Также, объясните мне, как эта штука кодирования работает для строковых литералов, если включен Zend Multibyte?

Функция Zend Multibyte реализована в Zend / zend_multibyte.c , Пусть движок Zend знаетбольше кодирования, чем Ascii и UTF-8, это только интерфейс для кодирования, потому что реализация по умолчанию - фиктивная функция , реальная реализация - расширение mbstring, поэтому mbstring является обязательнымрасширение для получения многобайтовой поддержки при загрузке .

$ php -m | grep mbstring
mbstring
$ php -n -m | grep mbstring # -n disable mbstring, No configuration (ini) files will be used.
$ echo -e '<?php\n echo "Hello 中文\n"; ' | iconv -t utf-16 | php -n -d zend.multibyte=1

Fatal error: Could not convert the script from the detected encoding "UTF-32LE" to a compatible encoding in Unknown on line 0

Как включить Zend Multibyte?Каково главное намерение включить его?Когда требуется включить его?

Объявите zend.multibyte = 1 в php.ini, чтобы включить разбор исходных файлов в многобайтовых кодировках. Также вы можете передать -d zend.multibyte=1 в исполняемый файл PHP Cli, как в примере выше, чтобы включить многобайтовую поддержку в PHP Zendдвигатель.

0 голосов
/ 11 октября 2018

Как включить Zend Multibyte?

Скомпилируйте PHP с помощью флага --enable-zend-multibyte (до PHP 5.4) и активируйте параметр zend.multibyte в php.ini.

Cf.https://secure.php.net/manual/en/ini.core.php#ini.zend.multibyte и https://secure.php.net/manual/en/configure.about.php#configure.options.php

...