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) как пробелы, а не некоторые другие причудливые символы пробелов.