PHP readdir с европейскими символами
-
21-09-2019 - |
Вопрос
Я получаю файлы изображений, в имени файла которых есть чешские символы (например, ěščřžýáíé), и я хочу переименовать их без акцентов, чтобы они были более совместимы для Интернета.Я думал, что мог бы использовать простую функцию str_replace, но, похоже, она работает с файловым массивом не так, как со строковым литералом.
Я прочитал файлы с помощью readdir, предварительно проверив расширение.
function readFiles($dir, $ext = false) {
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
while (($file = readdir($dh)) !== false) {
if($ext){
if(end(explode('.', $file)) == $ext) {
$f[] = $file;
}
} else {
$f[] = $file;
}
}
closedir($dh);
return $f;
} else {
return false;
}
} else {
return false;
}
}
$files = readFiles(".", "jpg");
$search = array('š','á','ž','í','ě','é','ř','ň','ý','č',' ');
$replace = array('s','a','z','i','e','e','r','n','y','c','-');
$string = "čšěáýísdjksnalci sášěééalskcnkkjy+ěéší";
$safe_string = str_replace($search, $replace, $string);
echo '<pre>';
foreach($files as $fl) {
$safe_files[] = str_replace($search, $replace, $fl);
}
var_dump($files);
var_dump($safe_files);
var_dump($string);
var_dump($safe_string);
echo '</pre>';
Выходной сигнал
array(6) {
[0]=>
string(21) "Hl�vka s listem01.jpg"
[1]=>
string(23) "Hl�vky v atelieru02.jpg"
[2]=>
string(17) "Jarn� v�hon03.jpg"
[3]=>
string(17) "Mlad� chmel04.jpg"
[4]=>
string(23) "Stavba chmelnice 05.jpg"
[5]=>
string(21) "Zimni chmelnice06.jpg"
}
array(6) {
[0]=>
string(21) "Hl�vka-s-listem01.jpg"
[1]=>
string(23) "Hl�vky-v-atelieru02.jpg"
[2]=>
string(17) "Jarn�-v�hon03.jpg"
[3]=>
string(17) "Mlad�-chmel04.jpg"
[4]=>
string(23) "Stavba-chmelnice-05.jpg"
[5]=>
string(21) "Zimni-chmelnice06.jpg"
}
string(53) "čšěáýísdjksnalci sášěééalskcnkkjy+ěéší"
string(38) "cseayisdjksnalci-saseeealskcnkkjy+eesi"
Прямо сейчас я работаю на WAMP, но ответы, которые работают на разных платформах, еще лучше :)
Решение
Согласно меткам 0xFFFD (которые отображаются в Firefox в виде бриллиантов с вопросительным знаком внутри), вы уже не читаете их, используя правильную кодировку (которая была бы Unicode / UTF-8).Насколько я нашел это ошибка, похоже, это связано.
Вот еще одна тема SO по этому поводу: проблема с php readdir с именем файла на японском языке
Кстати, подождите, пока они не установят стабильность PHP6, а затем используйте его.
Не имеет отношения к проблеме:в Нормализатор это лучший инструмент для избавления от диакритические знаки.
Другие советы
Если это работает со строками, но не с массивами, просто примените его к строкам :-)
$search = array('š','á','ž','í','ě','é','ř','ň','ý','č',' ');
$replace = array('s','a','z','i','e','e','r','n','y','c','-');
len = count($safe_files)
for ($i=0; $i<len; $i++)
$safe_files[$i] = str_replace($search, $replace, $safe_files[$i]);
Я думаю, что str_replace ( место расположения ) принимайте массивы только для 2 первых параметров, а не для последнего.Возможно, я ошибаюсь, но в любом случае это должно сработать.
Если каким-либо образом у вас возникла реальная проблема с кодировкой, это может быть просто из-за того, что ваша операционная система использует однобайтовую кодировку, в то время как ваш исходный файл использует другую, возможно, UTF-8.
В этом случае сделайте что-то вроде :
$search = array('š','á','ž','í','ě','é','ř','ň','ý','č',' ');
$replace = array('s','a','z','i','e','e','r','n','y','c','-');
$code_encoding = "UTF-8"; // this is my guess, but put whatever is yours
$os_encoding = "CP-1250"; // this is my guess, but put whatever is yours
len = count($safe_files)
for ($i=0; $i<len; $i++)
{
$safe_files[$i] = iconv($os_encoding , $code_encoding, $safe_files[$i]); // convert before replace
/*
ALternatively :
$safe_files[$i] = mb_convert_encoding($safe_files[$i], $code_encoding , $os_encoding );
*/
$safe_files[$i] = str_replace($search, $replace, $safe_files[$i]);
}
mb_convert_encoding() требует расширения ext/mbstring, а iconv() требует расширения ext/ iconv.
Возможно, это не прямой ответ на ваш вопрос, но вы, возможно, захотите взглянуть на iconv()
функция в PHP и многое другое, в частности //TRANSLIT
параметр, который вы можете добавить ко второму аргументу.Я использовал его несколько раз, переводя строки из Франции и Восточной Европы в их аналоги, понятные для a-z и URL.
От PHP.net (http://www.php.net/manual/en/function .iconv.php)
Если вы добавляете строку //TRANSLIT к out_charset, активируется транслитерация.Это означает, что когда символ не может быть представлен в целевой кодировке, он может быть аппроксимирован одним или несколькими аналогично выглядящими символами.
Ваш исходный код (и тестовая строка), похоже, написан в utf8, в то время как имена файлов, похоже, используют однобайтовую кодировку.Я бы посоветовал вам использовать ту же кодировку для вашей строки замены.Чтобы избежать проблем с кодировкой исходного кода, было бы лучше писать символы с ударением в вашем коде в шестнадцатеричной форме (например, \xE8 для "č" и т.д.).
Итак, я заставил это работать в моей системе Windows XP с помощью этого
$search = array('š','á','ž','í','e','é','r','n','ý','c',' ');
$replace = array('s','a','z','i','e','e','r','n','y','c','-');
$files = readFiles(".", "jpg");
$len = count($files);
for($i = 0; $i < $len; $i++){
if(mb_check_encoding($files[$i], 'ASCII')){
$safe_files[$i] = $files[$i];
}else{
$safe_files[$i] = str_replace(
$search, $replace, iconv("iso-8859-1", "utf-8//TRANSLIT", $files[$i]));
}
if($files[$i] != $safe_files[$i]){
rename($files[$i], $safe_files[$i]);
}
}
Я не знаю, совпадение это или нет, но звоню mb_get_info()
Шоу
[internal_encoding] => ISO-8859-1
Вот еще одна функция, которую я нашел полезной на странице PHP strtr
<?
// Windows-1250 to ASCII
// This function replace all Windows-1250 accent characters with
// thier non-accent ekvivalents. Useful for Czech and Slovak languages.
function win2ascii($str) {
$str = StrTr($str,
"\xE1\xE8\xEF\xEC\xE9\xED\xF2",
"\x61\x63\x64\x65\x65\x69\x6E");
$str = StrTr($str,
"\xF3\xF8\x9A\x9D\xF9\xFA\xFD\x9E\xF4\xBC\xBE",
"\x6F\x72\x73\x74\x75\x75\x79\x7A\x6F\x4C\x6C");
$str = StrTr($str,
"\xC1\xC8\xCF\xCC\xC9\xCD\xC2\xD3\xD8",
"\x41\x43\x44\x45\x45\x49\x4E\x4F\x52");
$str = StrTr($str,
"\x8A\x8D\xDA\xDD\x8E\xD2\xD9\xEF\xCF",
"\x53\x54\x55\x59\x5A\x4E\x55\x64\x44");
return $str;
}
?>
В принципе, преобразовать европейские символы в эквивалент ascii не было такой уж проблемой, но я не смог найти надежного способа переименовать файлы (т. Е. Файлы ссылок с символами, отличными от ascii).
Для UTF-8 используйте PHP-функцию utf8_encode.Microsoft Windows использует ISO-8859-1, поэтому в этом случае необходимо преобразование.
Пример - перечисление файлов в каталоге:
<?php
$dir_handle = opendir(".");
while (false !== ($file = readdir($dir_handle)))
{
echo utf8_encode($file)."<br>";
}
?>
Area5one прав - это проблема другой кодировки.
Когда я обновил свой компьютер с XP до Win7, я также обновил свои версии MySQL и PHP.Где-то на этом пути PHP-программы, которые раньше работали, перестали работать.В частности, scandir, readdir и utf-8 жили счастливо вместе, но больше не живут.
Итак, я изменил свой код.Переменные, относящиеся к данным, взятым с жесткого диска, заканчиваются на "_iso", чтобы отразить кодировку Windows ISO-8859-1, данные из базы данных MySQL передаются в переменных, заканчивающихся на "_utf".Таким образом, код из area5one хотел бы, чтобы это:$dir_handle_iso = opendir(".");while (false !== ($file_iso = readdir($dir_handle_iso))) { $file_utf = utf8_encode($file);...}
Это работает для меня на 100%:
setlocale(LC_ALL,"cs_CZ");
$new_str = iconv("UTF-8","ASCII//TRANSLIT",$orig_str);
$file = mb_convert_encoding($file, 'UTF-8', "iso-8859-1");Сработало у меня (Windows, датские символы).