copy() из _FILES, UTF-8 в названиях файлов

Koichi

Новичок
copy() из _FILES, UTF-8 в названиях файлов

Всем привет!
В обязательном порядке прочитал FAQ по теме кодировок и испробовал функции iconv.
Пробовал и другие, но пока что ничего не получается...
Суть проблемы такая:
Есть форма загрузки файлов.
К примеру, поле <input name="file" type="file">
Принимающий скрипт получает название файла и записывает файл с полученным названием в соответствующую директорию:
PHP:
$filenameFile = $_FILES['file']['name'];
$filenameFile = $path."/".$filenameFile;
$copy = copy($_FILES['file']['tmp_name'],$filenameFile);
В итоге, с английскими названиями файлов всё ок.
Но если подгруженный файл был с кириллицей в названии, то сохраняется абракозябрами. Как этого можно избежать?
Причём само название я записываю в текстовый файл (UTF-8) и он успешно считывается через FlashVars.
Когда пытаюсь открыть его через getURL, то получаю ошибку 404.
Пробовал с разными названиями.
Например, растяжка.psd функцией copy() сохраняется на сервере как растяжка.psd
Кто-нибудь сталкивался с такой проблемой?
 

Scud

Новичок
Или конвертировать файлы в транслит, я вот например всегда из 'жопа.psd' делаю 'zopa.psd'
 

dimagolov

Новичок
тут несколько проблем:
1. то как ФС сервера кодирует русские имена файлов (в какой кодировке, явно ведь не в UTF-8)
2. то, как броузер кодирует русский текст в URL как apache использует декодирует URL для обращения к файлам на диске
 

TutanXamoN

Новичок
1. то как ФС сервера кодирует русские имена файлов (в какой кодировке, явно ведь не в UTF-8)
В чём здесь проблема если файл всё же сохраняется на сервере и к нему можно достучаться при обработке?

2. то, как броузер кодирует русский текст в URL как apache использует декодирует URL для обращения к файлам на диске
Никто не запрещает завести хайден поле в форме и в онсабмите засунуть туда транслит имя джаваскриптом.
 

dimagolov

Новичок
TutanXamoN, как я понял, у автора прямой доступ к загруженным файлам по http. Если доступ через скрипт, то проблем нет никаких прописать русское имя в Content-Disposition. А вот если через апач напрямую, то тут сложности
 

TutanXamoN

Новичок
dimagolov
Ето уже другой вопрос)
Но вот я например нигде в посте не нашёл упоминания о том что файл скачивают.
 

Koichi

Новичок
Спасибо за множество ответов!
Я так понял, что уже можно ещё более конкретизировать проблему.
Делаю сайт я на wamp сервере, соответственно под Windows XP (файловая система NTFS, все названия файлов соответственно в юникоде). У провайдера, естественно, Apache на Linux. Но так как наша фирма заказчик, то и требования по конфигурации php.ini и httpd.conf можем предъявить, какие только дадут удобный результат.

Вижу, что пока что самый удобный вариант - это перекодировать принимающим PHP скриптом название файла в транслит (типа, жопа.psd -> zopa.psd) и в файлик со списком названий файлов записывать уже такое название файла, видимо поищу готовый конвертер строк из UTF-8 в транслит.

Чуть подробнее насчёт того, зачем мне это надо.
Есть админка, которая представляет собой что-то типа CMS для создания разделов и записей. С каждой записью подгружается файлик (ZIP или WMV или ещё что-нибудь) для скачивания. Всю инфу моя CMS записывает в текстовые файлики формата UTF-8, чтобы Flash Player через LoadVars смог считать кириллические (и прочие) символы, что вобщем-то успешно получается - все считанные из текстовых файликов названия отображаются в плеере корректно.
Но при клике по кнопке "скачать" вызывается getURL, и вот тут происходит косяк с нелатинскими названиями файлов.
Пробовал и через браузеры, и через плеер, и просто через Explorer. То, с каким названием сохранил файлик PHP скрипт, ничего уже считать не может. А ведь смысл в том, чтобы название у файла оставалось "читаемым", иначе бы я просто переименовывал их в номера (растяжка.psd -> 456732.psd)

Пока что временное решение - сказал что моя CMS не умеет обрабатывать файлы с нелатинскими названиями.
Но неужели нет такого варианта, чтобы PHP скрипт сохранил файлик как-нибудь так, чтобы при обращении получилось исходное название файла?
Может это можно как-нибудь сделать, чтобы при скачивании файла возвращалось изначальное имя?
Например:
- в форму браузера подгружается "растяжка.psd"
- PHP скрипт принял его, дал ему кодовый номер 8765.psd и записал куда-нибудь, что "8765.psd" изначально имел название "растяжка.psd"
- При обращении на скачивания файла "8765.psd" скрипт PHP подменяет его название обратно на изначальное "растяжка.psd"

Хотя в этом есть минус. До сих пор вся клиентская часть у меня была только на Flash, то бишь текстовые файлики, картинки, и файлы для скачивания загружались напрямую с Apache, без использования PHP. То бишь, PHP у меня до сих пор был только для визуального редактирования этих текстовых файликов и аплоада файлов.

Хм, пожалуй всё-таки проще найти конвертер в транслит, если PHP не умеет сохранять файл так, чтобы его можно было получить через URL с юникодом...

Пробовал кириллицу (UTF-8) писать прямо в скрипт. В HTML и в текстовые файлики пишется корректно, но в название файла всё равно по-прежнему пишет абракозябры...

WampServer 2.0 (Apache 2.2.6, PHP 5.2.5)
Текущие настроки php.ini:
default_mimetype = "text/html"
default_charset = "utf-8"
 

kode

never knows best
setlocale(LC_ALL, 'ru_RU.UTF-8');

Главное чтобы при заливке FTP клиент имена файлам не поганил

Кстате, в вантузе имена файлов cp1251 а не UTF-8.
 

джамшут

Новичок
kode, это было давно и не правда :) проблемы с кодировкой имён файлов остались только в линухе.
 

phprus

Moderator
Команда форума
джамшут
проблемы с кодировкой имён файлов остались только в линухе
Да? У меня OpenSuSE 10.2 и локаль ru_RU.UTF-8. Скажите что мне нужно сделать чтобы получить те проблемы, о которых вы говорите?
 

fixxxer

К.О.
Партнер клуба
- в форму браузера подгружается "растяжка.psd"
- PHP скрипт принял его, дал ему кодовый номер 8765.psd и записал куда-нибудь, что "8765.psd" изначально имел название "растяжка.psd"
- При обращении на скачивания файла "8765.psd" скрипт PHP подменяет его название обратно на изначальное "растяжка.psd"
это делается гораздо проще - отдаешь файл скриптом через readfile и указываешь нужное имя в content-disposition.
тут, правда, возникает другая проблема - сама отдача скриптом грузит сервер, тоже конечно решается (просто - nginx X-Accel-Redirect или lighttpd X-Sendfile, сложно - схемы с симлинками и прочие извращения)

UPD: хотя у меня есть подозрение, что проблема у тебя на уровне флэша или что там у тебя такое хитрое где имя файла отображается
 

Koichi

Новичок
kode, но FTP клиент у меня вообще никак не используется, все файлы заливаются на сервер через веб-формы (при создании записи ей даётся id, название, прочие поля, и в той же форме подгружаются соответствующие файлы).
Однако же твою строчку
PHP:
setlocale(LC_ALL, 'ru_RU.UTF-8');
попробую, вдруг для создания файлов функцией copy() она тоже поможет...

fixxxer, да я вот тоже думаю, что отдача файла скриптом - это уж крайний случай. Я хочу избежать вообще каких-либо использований серверных скриптов при просмотре клиентом (текстовые файлики статичны, размещённые файлы тоже).
Со флэшем проблемы нет - если я вручную создал файл с кириллицей в названии, то он откроется через getURL корректно. В текстовом файлике всё тоже записано правильно.
Момент, при котором происходит глюк - это вызов функции copy() в PHP скрипте. Скрипт получает подгруженный файл с именем "растяжка.psd", но сохраняет его под именем "растяжка.psd", как я это и указал в самом первом посте.
Я бы ещё не удивился, если бы у меня это случилось под Linux, насколько я с ним знаком. Но вот чтобы даже под виндой...
Кстати, пробовал уже на провайдерском хосте (который под Linux) - вся та же самая фигня, точно такое же абракозябристое название получается для любого файла с нелатинским названием...

Пока что временное решение - я просто проинструктировал всех подгружающих, чтобы переименовали свои файлы в транслит. Попросить оказалось проще и быстрее, чем искать автотранслитератор.

Кто-нибудь в курсе, останутся ли такие проблемы в PHP 6, или переход на UTF-16 решает их?

-~{}~ 12.03.08 10:35:

kode, ставил в самом начале скрипта. Не помогло, всё осталось так же как и было.
Пробовал и другие варианты - не помогают:
PHP:
declare(encoding="utf-8");
declare(filename_encoding="utf-8");
setlocale(LC_ALL, 'ru_RU.UTF-8');
 

phprus

Moderator
Команда форума
джамшут
В статье есть очень хорошая фраза:
Каждый вступающий на тропу освоения Линукса, рано или поздно сталкивается с проблемой кодировок. Оказывается, что мир вокруг заполнен файлами, содержащими информацию в самых различных кодировках, и вопросы взаимодействия решены не очень...
Видимо полгода работы только на линуксе (полгода у меня даже дома только линукс стоит) и уже достаточное количество лет знакомства с линуксами вообще не это очень рано и по этому я еще ни разу не сталкивался с проблемой кодировок в лине.
Может вы все-таки скажите что мне конкретно нужно сделать чтобы получить проблемы с кодировками?

Koichi
Например, растяжка.psd функцией copy() сохраняется на сервере как растяжка.psd
Это очень похоже на то, что строка находящаяся в кодировке UTF8 отображается так, как будто у нее кодировка cp1251. Напиши пожалуйста какими инструментами ты получаешь это искаженное представление.
 

Koichi

Новичок
Я обратил внимание, что при сохранении каждый нелатинский символ сохраняется двумя символами:
р » СЂ
а » Р°
с » СЃ
т » С‚
я » СЏ
ж » Р¶
к » Рє
а » Р°

-~{}~ 12.03.08 10:51:

Автор оригинала: phprus
джамшут

В статье есть очень хорошая фраза:

Видимо полгода работы только на линуксе (полгода у меня даже дома только линукс стоит) и уже достаточное количество лет знакомства с линуксами вообще не это очень рано и по этому я еще ни разу не сталкивался с проблемой кодировок в лине.
Может вы все-таки скажите что мне конкретно нужно сделать чтобы получить проблемы с кодировками?

Koichi

Это очень похоже на то, что строка находящаяся в кодировке UTF8 отображается так, как будто у нее кодировка cp1251. Напиши пожалуйста какими инструментами ты получаешь это искаженное представление.
Хорошо, я сделал архив: KoichiSenada/PHP/KoichiSenada.fileupload.buggy.rar
Запускается открытием demo.php, пароль demo
Базы там пустые, но вобщем нужно зайти в "Работы", там кликнуть "Создать", и в поле формы "Файл" подгрузить какой-нибудь файлик с нелатинским названием.
После сохранения в каталоге ./works/Files/ появится папка с файлом. Вот у этого файла название всегда получается кривым, если изначально файл содержал в названии нелатинские символы.
Краткое содержание:
PHP:
if (isset($_FILES['file'])) {
  $filenameFile = $_FILES['file']['name'];
  $filenameFile = basename(stripslashes($filenameFile));
  $filenameFile = $pathWorksFiles.$work."/".$filenameFile;
  $copy = copy($_FILES['file']['tmp_name'],$filenameFile);
}
-~{}~ 12.03.08 10:59:

phprus, кстати как ты можешь заметить, после этого в списке работ название файла отобразится всё же в UTF-8, да и в текстовый файлик works.txt он тоже запишется в UTF-8 корректно...
Что же мне сделать с переменной $filenameFile, чтобы функция copy() отработала тоже корректно?

-~{}~ 12.03.08 11:50:

Есть!
Получилось у меня добиться нужного результата под виндой!
PHP:
$filenameFileLocal = iconv("UTF-8","WINDOWS-1251",$filenameFile);
$copy = copy($_FILES['file']['tmp_name'],$filenameFileLocal);
То бишь, именем файла для сохранения стала строка в кодировка WINDOWS-1251, а для всего остального остаётся UTF-8
Проверил, работает. Когда плеер запрашивает этот файл через getURL, то сервер (WampServer) нормально отдаёт его, и открывается диалог Открыть/Сохранить/Отмена.
А вот под линуксом такая фишка не прокатывает.
Наверное, нет кодировки WINDOWS-1251.
Но тогда на что её можно заменить?
 

джамшут

Новичок
а мне больше нравится эта цитата:
Как быть со случаем, когда на сервере лежат файлы от одного пользователя, названные в CP1251 и от другого – в KOI8-R
Отлавливанием виновного, и поручением ему перекодировки
вообще, мне нет никакого желания спорить со слепым о цвете помидор. если ты до сих пор не сталкивался с проблемой кодировок (вот ведь заливает-то..) - значит у тебя ещё всё впереди.
 

Koichi

Новичок
джамшут, это ты на тему обсуждения прочитанной книги? :)
Я пробовал для Linux сделать другую кодировку:
PHP:
$filenameFileLocal = iconv("UTF-8","ISO-8859-1",$filenameFile);
Не помогло! Не смотря на то, что именно их вернула строка:
PHP:
var_dump(iconv_get_encoding('all'));
 
Сверху