Archive

Archive for the ‘кодировка’ Category

PHP и UTF-8

March 7th, 2010 Dmitriy Lyapin No comments

Хорошим тоном считается использовать кодировку UTF-8, несмотря на то, что большинство сайтов рунета до сих пор работают на Windows-1251. В статье я расскажу, что же именно нужно сделать, чтобы PHP сайт правильно заработал с Юникодом, и с каким трудностями мне пришлось столкнуться на пути к прогрессу.

Достаточно ли тега meta?

Вот мой index.php:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
	<meta http-equiv="content-type" content="text/html; charset=utf-8">
	<title>UTF-8</title>
</head>
<body>
	Здравствуй, UTF-8!
</body>

Сохраняю файл в кодировке UTF-8 и вижу в браузере каркозябры. Это меня не может не удивлять, потому что в теге meta указана верная кодировка.

Несмотря на это, все браузеры упорно считают, что документ пришел в Windows-1251.

utf8

Почему?

Статичная страница вместо скрипта

Пробую поменять расширение файла на «.html» и, о чудо! Я вижу надпись «Здравствуй, UTF-8!» Значит, дело в PHP…

Заголовки ответа

А не отправляет ли сервер кодировку в заголовке ответа? Запускаю мониторинг HTTP (как это сделать?) и вижу вот что:

Content-type: text/html; charset=windows-1251

То есть сервер считает, что страница должна быть в кодировке Windows-1251, о чем говорит браузеру заголовком Content-type.

Решение проблемы

Решить проблему можно двумя способами:

  1. Написать в начале скрипта (перед выводом HTML):

    <?php
    header('Content-type: text/html; charset=utf-8');
    ?>
  2. Указать в .htaccess нужную кодировку:

    AddDefaultCharset utf-8

Оба варианта приведут к одному и тому же – сервер вернет нужный нам заголовок:

Content-type: text/html; charset=utf-8

Для чего же тогда тег meta?

Для статичных страничек или же, если пользователь сохранит документ для автономной работы.

Метка BOM

Работая в кодировке UTF-8, нужно знать про злую метку BOM. Это такая последовательность байт, которая идет в начале файла и «помогает» понять кодировку. Однако для PHP эта метка оказывает медвежью услугу. Последовательность байт просто выводится в OUTPUT, в результате чего возникают разные неприятные вещи.

Например, IE отказывается реагировать на директиву DOCTYPE (видимо, он ее ждет в самом начале файла, а там BOM). Если вы используете шаблоны, и для вывода HTML используется несколько файлов, то браузер будет отображать отступы в местах стыка шаблонов.

Решение проблемы – использовать UTF-8 без BOM. Многие редакторы позволяют это делать, например, Notepad++:

bom

Работа с форматом ZIP в C#

February 25th, 2010 Dmitriy Lyapin No comments

icsharpcode

Для упаковки и распаковки ZIP архивов средствами Net Framework существует множество библиотек. Одна из наиболее популярных – ICSharpCode.SharpZipLib. Распространяется библиотека по лицензии GPL и в целом производит приятное впечатление.

Она позволяет работать с форматом ZIP на относительно низком уровне, исползуя классы ZipInputStream, ZipOutputStream, ZipEntry и др. А можно ограничиться функциями «запаковать директорию в архивчик» и «распаковать архивчик в директорию», это умеет класс FastZip.

Все настолько просто, что если бы у меня не возникло загадочных проблем с кириллицей в именах файлов, то не было бы и этой статьи про ZIP и C#.

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

tempDir = Path.GetTempPath() + Guid.NewGuid().ToString() + "\\";
Directory.CreateDirectory(tempDir);
 
...
 
FastZip fz = new FastZip();
fz.CreateZip(filename, tempDir, true, "");

Этот код прекрасно работал при запуске веб-сервера по F5 в VisualStudio. Однако на реальном сервере FastZip отказывался понимать кириллицу в именах файлов и заменял такие символы на знаки вопроса.

Для выявления проблемы я создал папку (»D:\test») с двумя файлами (»первый.txt», «второй.txt») и поставил задачу заархивировать ее. Вместо веб-сервера было написано конслоьное приложение. Вот его код:

public static void Main()
{
	FastZip fz = new FastZip();
	fz.CreateZip("D:\\test.zip", "D:\\test", true, "");
}

К моему удивлению, оно отработало на сервере безупречно! Значит, предположение, что проблема кроется в том, что на локальном компьютере у меня русская версия Windows, а на сервере – американская, было неверным.

Как оказалось, в библиотеке SharpZipLib есть такой класс ZipConstants, а у него есть свойство DefaultCodePage. В консольном приложении ZipConstants.DefaultCodePage = 866 (что хорошо), а на веб-сервере ZipConstants.DefaultCodePage = 437 (что нехорошо).

Решение проблемы оказалось совсем простым. Нужно добавить куда-нибудь перед архивацией эту строчку:

ZipConstants.DefaultCodePage = 866;

Передаю приветы:
- Гоше, проблема была в его коде :)
- Пользователю volser с форума ru-board; спасибо за ссылку, которая решила мою проблему!