Имя файла, получаемое при работе с модулем ZipArchive, из-за бага в этом модуле требует некоторого преобразования через промежуточные однобайтовые кодировки.
Нужно провести такую цепочку преобразований:
UTF-8 -> encode1 -> encode2 (encode3) -> UTF-8
В php это будет так:
$out_str = iconv('UTF-8', $encode1.'//IGNORE', $in_str);
$out_str = iconv($encode1, $encode2.'//IGNORE', $out_str);
$out_str = iconv($encode3, 'UTF-8//IGNORE', $out_str);
Но проблема в том, что для каждой конфигурации сервера эти кодировки могут отличаться.
Чтобы их найти нужно воспользоваться методом перебора.
Для начала найдем все кодировки, которые поддерживает функция iconv.
Для этого в консоли сервера вызовем:
$ iconv -l
Из набора кодировок нужно взять только те, которые содержат наименование "CPxxx", где xxx - число.
С помощью скрипта провести полный перебор:
$all_encoding = []; // сюда вставляем список всех кодировок iconv
$out_encoding = array_filter($all_encodings, function($item){return strpos(strtolower($item), 'cp') !== false;});
foreach($out_encoding as $encode1)
{
foreach($out_encoding as $encode2)
{
foreach($out_encoding as $encode3)
{
$str = iconv('UTF-8', $encode1.'//IGNORE', $out);
$str = iconv($encode1, $encode2.'//IGNORE', $str);
$str = iconv($encode3, 'UTF-8//IGNORE', $str);
if($str !== false && $str !== '')
echo $encode1.'::'.$encode2.'::'.$encode3.'::'.$str.'<br>';
}
}
}
Визуально ищем тот вариант, где имя файла восстановилось.
В моем случае это:
UTF-8 -> cp437 -> cp437 (cp866) -> UTF-8
В коде это выглядит так:
$out_str = iconv('UTF8', 'CP437//IGNORE', $in_str);
$out_str = iconv('CP437', 'CP437//IGNORE', $out_str);
$out_str = iconv('CP866', 'UTF8//IGNORE', $out_str);