У меня есть это домашнее приложение, которое позволяет загружать несколько файлов, я передаю файлы в php с помощью AJAX, создаю новый каталог с помощью php, перемещаю туда загруженные файлы и сохраняю местоположение каталога в базе данных. Затем, чтобы увидеть файлы, я запускаю список местоположений каталога, сохраненных в БД.
Проблема в том, что файлы приходят со всего мира, поэтому очень часто в них присутствуют не латинские символы, например, ü. Когда я повторяю, имя файла в именах php отображается правильно, даже если у них есть имена, написанные на арабском языке, но они сохраняются на сервере с закодированными именами, как, например, вместо ü. Когда я перечисляю файлы из каталога, я вижу имя ü.txt, вставленное в ü.txt, но когда я нажимаю на него, сервер возвращает объект ошибки, не найденный (так как на сервере он сохраняется как ü.txt и читает ссылку как ü.txt).
Я попробовал некоторые из предложенных решений, например, используя iconv, но имена файлов сохраняются таким же образом.
Могу поклясться, что проблемы не было, когда веб-приложение было размещено на Linux, но в данный момент я больше не уверен в этом. Прямо сейчас я временно запускаю его на xampp (в Windows), и кажется, что имена файлов сохраняются в кодировке windows-1252 (кодировка Windows по умолчанию на сервере). Это проблема, связанная с кодировкой Windows по умолчанию?
Если честно, я не знаю, как решить эту проблему, и я был бы признателен за любую помощь. Стоит ли продолжать пытаться сохранить файлы в другой кодировке или лучше подойти к нему по-другому и изменить способ перечисления уже сохраненных и закодированных файлов?
РЕДАКТИРОВАТЬ. Согласно (наконец) закрытым сообщение об ошибке это было исправлено в php 7.1.
В конце концов я решил это следующим подходом:
rawurlencode()
urldecode($filename)
печатать правильные именаa href
автоматически переводятся, поэтому, например, «% 20» становится «», и URL оказывается неверным, поскольку он ссылается на неверное имя файла. Я решил закодировать их обратно и напечатать в итоге что-то вроде этого: print $dirReceived.rawurlencode($file);
($ dirReceived — это каталог, в котором хранятся полученные файлы, определенные ранее в коде)urldecode($filename)
при необходимости сохранить файл с именем UTF-8.Благодаря этому у меня есть файлы, сохраненные на сервере с URL-адресами. Может открывать их в браузере (очень важно, поскольку большинство из них * .pdf) и может загружать их с правильным именем, что позволяет загружать и загружать даже файлы с именами, написанными на арабском, кириллице и т. Д.
Пока что я проверил это и выглядит хорошо. Я думаю о реализации этого в производственном коде. Какие-либо проблемы / мысли по этому поводу?
РЕДАКТИРОВАТЬ.
Поскольку нет никаких возражений, я выбираю ответ, который решил мою проблему. После некоторого тестирования все выглядит хорошо на стороне клиента и сервера. При сохранении файлов на сервере они кодируются URL, при загрузке они декодируются и сохраняются с правильными именами.
В начале я использовал код:
for($i=0;$i<count($_FILES['file']['name']);$i++)
{
move_uploaded_file($_FILES['file']['tmp_name'][$i],
"../filepath/" . $_FILES['file']['name'][$i]);
}
Этот метод вызвал проблему при сохранении файла и заменил каждый специальный символ UTF-8 на кодированный cp1252 (ü сохранен как ü и т. Д.), Поэтому я добавил одну строку и заменил этот код следующим:
for($i=0;$i<count($_FILES['file']['name']);$i++)
{
$fname= rawurlencode($_FILES['file']['name'][$i]);
move_uploaded_file($_FILES['file']['tmp_name'][$i],
"../filepath/" . $fname);
}
Это позволяет мне сохранять любое имя файла на сервере, используя URL-кодировку (% и два шестнадцатеричных числа), которая совместима как с cp1252, так и с UTF-8.
Для отображения сохраненных файлов я использую пути к файлам, которые я сохранил в БД, и перечисляю их для файлов. Я использовал следующий код:
if (is_dir($dir)){
if ($dh = opendir($dir)){
while (($file = readdir($dh)) !== false){
if(is_file($dir . $file)){
echo "<li><a href='".$dir.$file."' download='".$file ."'>".$file."</a></li><br />";
}
}
closedir($dh);
}
}
Поскольку имена файлов в кодировке URL были декодированы автоматически, я изменил его на:
if (is_dir($dir)){
if ($dh = opendir($dir)){
while (($file = readdir($dh)) !== false){
if(is_file($dir . $file)){
echo "<li><a href='";
print $dir.rawurlencode($file);
echo "' download='" . urldecode($file) ."'>".urldecode($file)."</a></li><br />";
}
}
closedir($dh);
}
}
Я не знаю, является ли это лучшим способом ее решения, но работает отлично, также я знаю, что, как правило, хорошей практикой является не использовать php для генерации HTML-тегов, но в настоящий момент у меня есть некоторые критические ошибки, которые необходимо устранить, поэтому сначала, а потом мне придется работать над внешним видом самого кода.
EDIT2
Также здорово то, что мне не нужно менять имена уже загруженных файлов, что в моем случае является большим преимуществом.
Ты используешь $_FILES['upfile']['name']
назвать файл? Это может создать вашу проблему.
Как насчет использования GNU Recode?
$fileName = recode_string('latin1',$_FILES['upfile']['name']);
Синтаксис:
recode_string(string recode type,string $string)
Допустимые наборы символов: http://www.faqs.org/rfcs/rfc1345.html
Каким-то образом вы должны проверить символы в имени загруженного файла.
Вы также можете попробовать sprintf. Отформатированные строковые символы могут быть непредсказуемыми, но, вероятно, будут работать.
$fileName = pathinfo($_FILES['upfile']['name'], PATHINFO_FILENAME);
$fileName = sprintf('./uploads/%s',$fileName);
При сохранении имени файла вы используете mysql_escape_string ();
$fileName = mysql_escape_string($fileName);
И из-за синтаксической грамматики нацисты, которые любят говорить мне, обесцениваются, как будто я еще не знаю.
mysqli_real_escape_string()
Заметьте, что вы написали грамматику нацистам эта любовь опровергает мои ответы, потому что я использую mysql, а не msqli, Get a Life. Я пишу код с тех пор, как это было сделано на телетайпе с типом бумаги и перфокартами. Задолго до твоего рождения.