PHP - имена файлов в HTTP-заголовках: проблема с пробелами - PullRequest
7 голосов
/ 31 августа 2011

Работа с 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», в то время как 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, это сокращает имя файла, как в первом codenini. Но я могу заменить sprintf синтаксисом dottet-string-concat, и он работает.

Может кто-нибудь сказать мне, что я пропускаю?

Ответы [ 2 ]

7 голосов
/ 31 августа 2011

Разница заключается в двойных кавычках. С первым кодом вы получите:

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 всегда заключено в двойные кавычки.

3 голосов
/ 31 августа 2011

RFC2616, который является спецификацией HTTP / 1.1, говорит это:

Поле заголовка ответа Content-Disposition было предложено как означает, что исходный сервер предлагает имя файла по умолчанию, если пользователь запрашивает, чтобы содержимое было сохранено в файл. Это использование является производным из определения Content-Disposition в 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 )

Примером является Содержание-Диспозиция: вложение; имя файла = "fname.ext"

Таким образом, отправив это:

header('Content-Disposition: attachment; filename="' . $filename . '"');

соответствует второй форме (quoted-string) и должен делать то, что вы ожидаете - позаботьтесь об отправке только SPACE (ASCII dec 32 / hex 20) в качестве пробела, а не некоторых других причудливых пробельных символов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...