PHP-имена файлов в HTTP-заголовках: проблема с пробелами
работа с CakePHP и Java Web Start я генерирую необходимое .jnlp-файл в контроллере, в котором, среди прочего, я устанавливаю имя файла как поле заголовка. Это прекрасно работает, пока я не пытаюсь использовать специальные символы в именах файлов. Тем не менее, я хотел бы включить каждый символ, который возможен в основных операционных системах в качестве имени файла. Поэтому я пытаюсь удалить все недопустимые символы, заменив их пустыми строками. Но, кажется, есть проблема с пробелы, которые должны быть разрешены в именах файлов.
вот код:
$panel_id = 1
$panelname = 'w h i t e s p a c e s';
$filename = sprintf('"Project_%d_%s.jnlp"', $panel_id, $panelname);
$invalid_chars = array('<', '>', '?', '"', ':', '|', '', '/', '*', '&');
$filename = str_replace($invalid_filenamechars, '', $filename);
$this->header('Content-Disposition: attachment; filename=' . $filename);
когда я это делаю, результирующее имя файла в заголовке "Project_1_w h i t e s p a c e", в то время как Windows 7 хочет сохранить файл как "Project_1_w". Итак, похоже, что моя ОС не принимает неоткрытые пробелы в именах файлов? Я был бы доволен этим объяснением, если бы не следующее: Я оставил строки 4 и 5, так что код выглядит
$panel_id = 1
$panelname = 'w h i t e s p a c e s';
$filename = sprintf('"Project_%d_%s.jnlp"', $panel_id, $panelname);
$this->header('Content-Disposition: attachment; filename=' . $filename);
и теперь Windows желая сохранить файл со всеми его пробелами, я все еще не могу понять, почему. Если я смотрю на имена файлов в заголовках с помощью wireshark, оба они одинаковы. И если sprintf-линия заменена на $filename = 'w h i t e s p a c e'
или даже $filename = $panelname
он сокращает имя файла, как в первом codesnippet. Но я могу заменить sprintf синтаксисом dottet-string-concat, и он работает.
может ли кто-нибудь сказать мне, что я упускаю из виду?
2 ответов
разница в двойных кавычках. С первым кодом вы получите:
Content-Disposition: attachment; filename=Project_1_w h i t e s p a c e s.jnlp
со вторым кодом вы получите:
Content-Disposition: attachment; filename="Project_1_w h i t e s p a c e s.jnlp"
что вы, вероятно, хотите, что-то вроде:
$panel_id = 1;
$panelname = 'w h i t e s p a c e s';
$filename = sprintf('"Project_%d_%s.jnlp"', $panel_id, $panelname);
$invalid_chars = array('<', '>', '?', '"', ':', '|', '\', '/', '*', '&');
$filename = str_replace($invalid_filenamechars, '', $filename);
$this->header('Content-Disposition: attachment; filename="'.$filename.'"');
это удаляет любые двойные кавычки в пределах $filename, но затем гарантирует, что $filename всегда окружен двойными кавычками.
RFC2616, который является спецификацией HTTP/1.1, говорит:
поле Content-Disposition response-header было предложено в качестве средство для исходного сервера предложить имя файла по умолчанию, если пользователь запрашивает сохранение содержимого в файл. Это использование происходит из определения содержания-диспозиция в RFC 1806.
content-disposition = "Content-Disposition" ":" disposition-type *( ";" disposition-parm ) disposition-type = "attachment" | disp-extension-token disposition-parm = filename-parm | disp-extension-parm filename-parm = "filename" "=" quoted-string disp-extension-token = token disp-extension-parm = token "=" ( token | quoted-string )
пример Контент-Disposition: вложение; filename= " fname.ext"
таким образом, посылая этот:
header('Content-Disposition: attachment; filename="' . $filename . '"');
соответствует второй форме (quoted-string
) и должен делать то, что вы ожидаете - позаботьтесь только о том, чтобы отправить SPACE
(ASCII dec 32 / hex 20) как пробелы, а не некоторые другие причудливые символы пробелов.