Создать файл UTF-16 (LE-BOM) в PHP

Я хочу создать файл в PHP со следующими условиями:

  1. Создайте файл с комбинацией строковых значений, полученных из полей ввода, и шестнадцатеричных значений рядом.
  2. Шестнадцатеричное значение должно быть UTF-16 (LE) (BOM).

Больше информации:

  • Я хочу получать значения от пользователя через поля ввода, например, имя, фамилию, возраст и счет
  • Значение age и score необходимо преобразовать в Hex UTF-16 (BOM) и сохранить вместе со значениями name и... типа String в файле с любым расширением, неважно (например, of типа ТХТ).

Позвольте мне привести пример:

Score = 64
Name = Jack
Last Name = Saliv
Age = 21
By default, this file is generated as follows:

64JackSaliv21
And the Hex value becomes this value:
36344A61636B53616C69763231
But I want to get the following value:

䃿JackSaliカ
And the Hex value is:
FFFEFF404A00610063006B00530061006C00690076FFFEFF15

.

В следующих темах я не получил желаемых результатов!

Может я не правильно думаю, но разве строка 64 не будет представлена ​​как 36 00 34 00 в UTF-16 LE?

Chris Haas 14.05.2023 19:09

@ChrisHaas, Да, значение UTF-16 (LE) 64 равно 36 00 34 00, но перед этим значение 64 должно быть преобразовано в шестнадцатеричное, а затем должно быть сохранено шестнадцатеричное значение 64, равное 40. в финальном файле.

Adam Luper 14.05.2023 22:54

Итак, вы хотите сохранить число 64, а не строку 64. UTF предназначена для кодирования символов, а не чисел. Итак, 40 — это не UTF (LE или любая другая) кодировка 64, это просто десятичное число 64, преобразованное в основание 16. Я просто хочу внести ясность. Единственным материалом UTF будет их имя. Верно?

Chris Haas 14.05.2023 23:55

Строка, которую вы говорите, что хотите, это полная ерунда. Это два однобайтовых целых числа, хранящихся в двоичном формате, каждому из которых предшествует бессмысленная спецификация UTF16LE со строкой UTF16LE в середине. Пожалуйста, объясните, почему вы думаете, что вам нужна эта строка.

Sammitch 15.05.2023 00:15

@ChrisHaas, да, в какой-то степени, в конечном итоге я хочу подойти к чему-то вроде этого ответа: stackoverflow.com/a/76192895/21197857

Adam Luper 15.05.2023 00:19

Можете ли вы показать, что вы пробовали раньше, чтобы решить эту проблему?

Blue Robin 15.05.2023 16:00
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
6
87
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Читая ваши Delph вопросы, вместе с вашими комментариями, я действительно не до конца понимаю, что все это должно делать. Однако, учитывая входные данные вместе с выходными, я могу, по крайней мере, приблизиться к ним и сделать их точными с некоторыми дополнительными исправлениями.

По сути, вы можете использовать mb_convert_encoding , чтобы получить UTF-16LE, а затем вы можете получить байты в виде шестнадцатеричных строк, используя распаковать . Чтобы преобразовать десятичные числа в шестнадцатеричные строки, просто используйте dechex.

Из вашего примера я не уверен, почему десятичное число 64 при преобразовании в шестнадцатеричную строку 40 записывается как FF 40, а не только 40 или 40 00, но к переменной $finalStringWithNumbersPadded добавляется FF. Если бы возраст или оценка были больше, чем 255, я не совсем уверен, что делать, так как FF это 1111 1111 и полностью заполнен.

Кроме того, я предполагаю, что у вас есть опечатка в ваших ожидаемых байтах, символ для фамилии должен быть 76 00, а не только 76.

Надеюсь, код говорит сам за себя:

$score = 64;
$firstName = 'Jack';
$lastName = 'Saliv';
$age = 21;

$expected = 'FFFEFF404A00610063006B00530061006C00690076FFFEFF15';
$expectedCorrected = 'FFFEFF404A00610063006B00530061006C0069007600FFFEFF15';

// Convert to UTF-16LE and get hex, https://stackoverflow.com/a/16080439/231316
$nameAsUtf16LE = unpack('H*', mb_convert_encoding($firstName.$lastName, 'UTF-16LE', 'UTF-8'));

// UTF-16LE BOM
$utf16LeBom = 'FFFE';

// Convert to hex strings
$scoreAsHex = dechex($score);
$ageAsHex = dechex($age);

$finalString = sprintf(
    '%1$s%2$s%3$s',
    $utf16LeBom.$scoreAsHex,
    strtoupper($nameAsUtf16LE[1]), // This is 1-based, not 0-based
    $utf16LeBom.$ageAsHex,
);

$numberPadding = 'FF';
$finalStringWithNumbersPadded = sprintf(
    '%1$s%2$s%3$s',
    $utf16LeBom.$numberPadding.$scoreAsHex,
    strtoupper($nameAsUtf16LE[1]), // This is 1-based, not 0-based
    $utf16LeBom.$numberPadding.$ageAsHex,
);

echo 'Calculated         : '.$finalString;
echo PHP_EOL;
echo 'Padded             : '.$finalStringWithNumbersPadded;
echo PHP_EOL;
echo 'Expected           : '.$expected;
echo PHP_EOL;
echo 'Expected Corrected : '.$expectedCorrected;

assert($finalStringWithNumbersPadded === $expectedCorrected);

/* Output:
Calculated         : FFFE404A00610063006B00530061006C0069007600FFFE15
Padded             : FFFEFF404A00610063006B00530061006C0069007600FFFEFF15
Expected           : FFFEFF404A00610063006B00530061006C00690076FFFEFF15
Expected Corrected : FFFEFF404A00610063006B00530061006C0069007600FFFEFF15
*/

Демо: https://3v4l.org/XTdjA#v8.2.6

Редактировать

Чтобы записать строку шестнадцатеричных символов на диск в виде двоичных данных, вы можете использовать pack:

$bindata = pack('H*', 'FFFEFF404A00610063006B00530061006C0069007600FFFEFF15');
file_put_contents('testing.data', $bindata);

Спасибо, это именно то, что я хотел, к сожалению, я не могу оставить отзыв (вам нужно не менее 15 репутации, чтобы проголосовать), но я определенно очень рад, что на этом сайте есть такие профессиональные пользователи, как вы.

Adam Luper 16.05.2023 08:33

Можно ли дать объяснение этим значениям и что они делают? strtoupper($nameAsUtf16LE[1]) Я имею в виду это значение [1]. И какая польза от этого значения «%1$s%2$s%3$s»? Нужны ли этим кодам специальные ресурсы, программное или аппаратное обеспечение для работы на хосте? (Оказывают ли они давление на хозяина?)

Adam Luper 16.05.2023 08:42

Могу ли я добавить больше значений в команду sprintf? Например, почтовый индекс или идентификационный номер (тип оценки и возраст), а также адрес и описание (например, имя и фамилия)? Если я захочу добавить эти значения в коды, какими будут коды?

Adam Luper 16.05.2023 08:50

Я странный человек, который всегда использует полную форму для команд printf . В строке %1$s1$ означает «первый предоставленный заполнитель», а s означает интерпретировать его как строку. Вы никоим образом не обязаны использовать printf вообще, я просто сделал это, потому что иногда я думаю, что это облегчает чтение вместо объединения, в этом контексте нет никакой разницы, однако вы также можете делать с ним все, что хотите: 3v4l.org/lPrUK

Chris Haas 16.05.2023 09:18
$nameAsUtf16LE — это переменная, созданная путем преобразования предоставленной строки в UTF-16LE, а затем запуска функции unpack. pack и unpack — это действительно странные функции, в которые вы могли бы потратить часы, но просто знайте, что unpack в этом случае возвращает вам шестнадцатеричные значения предоставленной строки. Результатом unpack является массив, и по внутренним причинам есть только одно значение, и оно находится в индексе 1, следовательно, $nameAsUtf16LE[1]. strtoupper() просто заставляет шестнадцатеричный код быть в верхнем регистре, чтобы соответствовать вашим образцам, fffe против FFFE.
Chris Haas 16.05.2023 09:25

По большому счету, я не думаю, что этот код вообще будет заметен. Если вы нажмете предоставленную ссылку 3v4l, вы увидите вкладку «Производительность», которая показывает незначительность. «Нужны ли этим кодам специальные ресурсы… для запуска на хосте» — Просто PHP с расширением mbstring, которое, как мне кажется, в наши дни довольно часто устанавливается по умолчанию.

Chris Haas 16.05.2023 09:31

Отлично, какой метод следует использовать для сохранения конечного значения (например, FFFE404A00610063006B00530061006C0069007600FFFE15)? (Я хочу, чтобы конечное значение было сохранено как Hex в файле, то есть, если мы откроем файл с помощью Hex Editor, это значение будет отображать FFFE404A00610063006B00530061006C0069007600FFFE15) Я использовал метод stackoverflow.com/a/9973915/21197857 , но не сохранил шестнадцатеричное значение, а сохранил само значение в виде строки!

Adam Luper 16.05.2023 13:43

@AdamLuper, я добавил внизу образец записи на диск. Я отмечу, что попытка создать строковое представление данных для визуальной проверки, а затем преобразовать его обратно в двоичный файл, как мы делаем, немного странная/неэффективная. Тем не менее, если вы не обрабатывали много данных, я не думаю, что это имеет большое значение, и поскольку это немного странно (без обид), это значительно упрощает визуальную отладку и, возможно, тестирование.

Chris Haas 16.05.2023 15:26

Вы преподали мне много новых уроков, я вам благодарен. В основном я хотел задать этот вопрос на PHP, чтобы узнать, и я многому научился, и я действительно извиняюсь, если вопросы, которые я задавал, были простыми и странными, потому что мне было очень интересно узнать результаты кода с похожим подходом на двух разных платформах! ! (Delphi и PHP) и я не представлял, что PHP имеет возможность быть настолько гибким, конечно я думаю, что эти коды не очень полезны для других или устарели или может быть вообще бесполезны для кого-то еще, но эти советы от Вы узнали, что это было здорово для меня.

Adam Luper 16.05.2023 16:43

Я столкнулся с проблемой, и я хочу найти для нее простое решение, если шестнадцатеричные значения Age и Score являются отдельными буквами (например, значения от 10 до 15, чьи шестнадцатеричные значения становятся A, B, C, D, E, F и т. д.) Как мне поставить ноль перед этими однобуквенными значениями, чтобы эти значения не смешивались с другими значениями рядом с ними (или что я должен сделать, чтобы преобразовать нечетное значение в четное значение! Например, если не ошибаюсь думаю значение А должно быть 0А) чтобы однобуквенное значение стало двухбуквенным? (Учитывая, что шестнадцатеричные значения представляют собой две буквы -> 00)

Adam Luper 16.05.2023 19:14

Вы прыгаете между несколькими различными кодировками и системами счисления, что действительно создает путаницу. и вы также (эффективно) создаете двоичный формат файла. В начале и ближе к концу по непонятным причинам есть спецификация, поскольку мы отметили, что прикрепление спецификации к числовым данным не имеет никакого смысла. Большинство/все форматы двоичных файлов имеют четко определенную структуру, либо записи фиксированной длины, сигилы для интерпретации/завершения данных, количество байтов для структур переменной длины или указатели байтов. Как только этот файл станет «усовершенствованным», я не совсем уверен, как вы его прочтете.

Chris Haas 16.05.2023 20:07

В любом случае, еще один способ преобразовать целое число в шестнадцатеричную строку — использовать sprintf, см.: stackoverflow.com/a/47789382/231316 , но вам также может понадобиться преобразовать порядок байтов: stackoverflow.com/a/ 35100432/231316

Chris Haas 16.05.2023 20:10

Другие вопросы по теме