Главная » Программирование для чайников » php [ Добавить статью ]

Проблемы с кириллицей при распоковке zip-архивов с помощью php (скрипт PclZip)

Данный глюк обнаружил на работе, когда менеджеры начали жаловаться, что одна из функций самописной CMS не работает. Начав разбираться я обнаружил, что одна из папок, в которую php-скрипт перемещал распакованные из zip-архива файлы, постоянно забивалась каким-то мусором (файлами с непонятной кодировкой, у которых вместо букв — квадратики и прочие ошмётки).

Скрипт заключался в следующем: распаковывал файлы из архива, проделывал над ними махинации и затем удалял их. То-есть папка не должна была ничем заполняться. Я проверил скрипт — всё казалось в порядке. Попробовал удалить эти файлы с помощью файлового менеджера — не получилось:

А ведь именно из-за этих мусорных файлов и отказала функция, на которую жаловались менеджеры. Написал в службу поддержки хостинга — они их удалили.

Буквально через час смотрю — снова эти файлы. В общем изучил ситуацию и пришёл к выводу, что это так распаковываются файлы из zip-архива, в названиях которых присутствуют русские буквы (кириллические символы). Сразу стало очевидно, что проблема с кодировкой. Сказать менеджерам, чтобы они не использовали кириллицу в именах файлов внутри архиве — бесполезно, обязательно накасячат (к тому же зачем оставлять такой баг). Пришлось по-быстрому всё исправить.

Устранение проблемы

Конечно же всё оказалось очень просто. Для распаковки файлов использовалась php-библиотека "PclZip". Открываем ее и видим функцию privReadCentralFileHeader, в которой присутствует следующий код:

// ----- Get filename
//--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 4, "File name length : ".$p_header['filename_len']);
if ($p_header['filename_len'] != 0)
{
  $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len'];
}
else
  $p_header['filename'] = '';

Всё что нам необходимо — перевести название файла в нужную нам кодировку. В моём случае это была UTF-8, поэтому я исправил строчку получения имени файла вот на такую:

$p_header['filename'] = iconv( "866", "UTF-8", fread($this->zip_fd, $p_header['filename_len'] ));

После этого всё стало работать корректно. Глюки наконец-то исчезли (как оказалось, им было уже порядка года^^).

Удаление с сервера файлов с нарушенной кодировкой в имени

А как же удалить файлы с нарушенной кодировкой, если при любой попытке это сделать файловый менеджер выдаёт ошибку "невозможно удалить файл"? Я нашёл такое решение: написал простенький php-скрипт, который обходит все файлы в папке, берёт их имена и удаляет с сервера (функция unlink).

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


Похожие статьи:

Добавлено: 21.10.2011 | Просмотров: 8814 | Рейтинг: 5.0/2 |
Теги: PHP, zip, кириллица


Комментарии (4)
0   Спам
4. Кирилл   24.11.2011   01:35 [Материал]
эх, ничего не помогло. изначально у меня имена в ютф-8, не понимаю почему библиотека их не хавает? уже дошел до того, что перед созданием архива, меняю кодировку имен (переименовываю), но результатов нет. В самой библиотеке пытался воздействовать на функцию которая получает имена файлов - также бесполезно. короче, я в шоке уже...
Ответ: Так с чего же ты взял, что изначально они у тебя в utf-8)) В windows имена файлов закодированы в win-1251.
0   Спам
3. Кирилл   23.11.2011   12:31 [Материал]
мне очень надо, чтоб под виндовс работало. этот скрипт архивирует файлы у меня на компьютере и заливает на хостинг (распаковываю уже через панель хостера, т.е. этот скрипт не будет использоваться). если есть решение в лоб, то какое? я буду архивировать и кириллицу, и латиницу, даже если это для латиницы работать не будет, я сделаю 2 разные библиотеки...

Так конечно, спасибо за информацию, что такая проблема встречается только на локальной машине, не всегда доходят руки проверить это и на хостинге...
Ответ: Не, все работать будет)) просто будет работать только на Windows.

Я думаю нужное место в коде ты уже нашел. Осталось перекодировать, но не как в примере этой статьи: в твоем случае там будет фигурировать 'windows-1251'. Поиграйся с 866, win и utf, всего 4 комбинаций разных с участием кодировки win =) Там всё-таки от кода зависит, конкретно не могу подсказать что во что кодировать, поэтому советую перебор вот такой. +Советую использовать отладочный вывод в файл и в каком-нибудь notepad++ смотреть - там кодировку можно на ходу быстро менять.
0   Спам
2. Кирилл   22.11.2011   15:35 [Материал]
на локальной машине
Ответ: Скорее всего Windows. Если да, то с 95% вероятностью на хостинге нормальном линуксовом все будет отлично работать. Просто в Windows названия файлов кодируются в win, а не utf8. Не стоит утруждаться делать изменения в библиотеке только ради того, чтобы на локальном сервере работало (к тому если сделать в лоб, то тогда на linux перестанет работать^^)
0   Спам
1. Кирилл   21.11.2011   19:03 [Материал]
привет! у меня не получается Архивация с кириллическими именами :) решения в интернете нигде нет, только как - используйте "латиницу в именах" :( пробывал твой способ (на авось добавлял функцию iconv для $p_header['extra'], а также для privReadFileHeader). ничего не помогло, не понимаю я эту библиотеку... если можешь помочь, помоги пожалуйста или может посоветуй какую другую библиотеку...
Ответ: Скрипт выполнялся на локальной машине или на Linux-сервере?
Имя *:
Email *:
Код *: