Контекст: мы создаем файлы CSV и PDF, содержащие числа, отформатированные во французском формате (разделитель тысяч - это пробел без перерывов).
При чтении файлов CSV или PDF при загрузке с рабочего сервера вместо пробела появляется символ ?
. При загрузке с нашего сервера разработки мы получаем правильные файлы.
У нас есть небольшой скрипт, который помог обеспечить минимальное воспроизведение.
header('Content-Description: File Transfer');
header('Content-Type: text/plain; charset=UTF-8');
header('Content-Disposition: attachment; filename="'.date('YmdHis').'.txt"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
$fmt = new NumberFormatter('fr_FR', NumberFormatter::DECIMAL);
$fmt->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
echo $fmt->format(12390);
Этот скрипт корректно работает на виртуальной машине.
Шестнадцатеричное содержимое загружаемого файла:
31 32 c2 a0 33 39 30 2c 30 30
c2 a0
являющийся пространством без перерывов UTF-8
При запуске на нашем производственном сервере точно такой же сценарий выводит файл, содержащий следующее шестнадцатеричное содержимое:
31 32 e2 80 af 33 39 30 2c 30 30
e2 80 af
- это то, что отличает его от вышеупомянутого. Похоже, это узкий непрерывный символ из Unicode, закодированный в UTF-8
Что мы делаем не так?
- Мы попытались сравнить конфигурации PHP и Nginx, но они очень похожи и не смогли найти ничего, связанного с кодировкой.
- Расширение mbstring включено с обеих сторон.
- Когда мы комментируем заголовок для принудительной загрузки, текст корректно отображается браузером на обоих серверах (нет
?
)
Обновление
По какой-то причине на сервере языковой стандарт fr_FR
использует обычный неразрывный пробел. В то время как на другом сервере тот же код заканчивается языком, использующим узкий неразрывный пробел.
Похоже, что в разных инструментах плохая поддержка узкого неразрывного пространства.
Текущий обходной путь заключается в принудительном использовании обычного неразрывного пробела, и в итоге он работает должным образом. Это далеко не идеал.
Если у кого-то есть объяснение, почему один и тот же языковой стандарт приводит к другому символу группировки, я был бы рад прочитать его и узнать, как получить согласованную настройку между серверами.