Как убедить Zend Framework отправлять дублирующиеся заголовки?

С Content-Security-Policy Заголовки часто необходимо отправить более одного такого заголовка или объединить эти заголовки перед отправкой. Это связано с тем, что каждый модуль / пакет приложения может определять свой собственный CSP.

Сейчас у ZF3, похоже, нет способа справиться с таким сценарием. Если я пытаюсь добавить несколько заголовков CSP, они продолжают перезаписывать друг друга, так что отправляется только последний добавленный заголовок.

Код для воспроизведения вопроса

$headers = $controller->getResponse()->getHeaders();
$headers->addHeader(new ContentSecurityPolicy($someDirectives));
$headers->addHeader(new ContentSecurityPolicy($someOtherDirectives));

Ожидаемые результаты

Ожидаемый результат — ответ с двумя заголовками CSP (ИЛИ объединенный CSP).

Фактические результаты

Второе дополнение перезаписывает первое, ответ содержит только один CSP.

Вопрос

Как я могу заставить ZF3 отправлять несколько заголовков с одинаковым именем поля?


Для получения дополнительной информации об этой проблеме, также посмотрите мою собственную проблему на github https://github.com/zendframework/zend-http/issues/159

2

Решение

Вы должны быть в состоянии создать простой обходной путь, используя GenericMultipleHeader в качестве ссылки (и изменение запятой на точку с запятой):

class MultiContentSecurityPolicy extends ContentSecurityPolicy implements MultipleHeaderInterface {

public static function fromString($headerLine)
{
list($fieldName, $fieldValue) = GenericHeader::splitHeaderLine($headerLine);
if (strpos($fieldValue, ';')) {
$headers = [];
foreach (explode(';', $fieldValue) as $multiValue) {
$headers[] = new static($fieldName, $multiValue);
}
return $headers;
} else {
$header = new static($fieldName, $fieldValue);
return $header;
}
}

public function toStringMultipleHeaders(array $headers)
{
$name  = $this->getFieldName();
$values = [$this->getFieldValue()];
foreach ($headers as $header) {
if (! $header instanceof static) {
throw new Exception\InvalidArgumentException(
'This method toStringMultipleHeaders was expecting an array of headers of the same type'
);
}
$values[] = $header->getFieldValue();
}
return $name . ': ' . implode(';', $values) . "\r\n";
}

}

Затем используйте этот класс вместо ContentSecurityPolicy:

$headers = $controller->getResponse()->getHeaders();
$headers->addHeader(new MultiContentSecurityPolicy($someDirectives));
$headers->addHeader(new MultiContentSecurityPolicy($someOtherDirectives));

С Зендом проверяет интерфейс, а не класс, должно работать нормально.

2

Другие решения

Это принятый стандарт HTTP, и PHP Core поддерживает это. http://php.net/manual/en/function.header.php

Если вы установите заголовки в PHP header("TESTHeader: Test1"); header("TESTHeader: Test2") только один пройдет, и это правильно в спецификации RFC2616 Раздел 4.2 Страница 31&32

Если вы хотите отправить несколько значений, ваш заголовок должен выглядеть так: header("TESTHeader: Test1, Test2");, хотя можно отправлять несколько заголовков с одинаковыми именами через PHP, это не рекомендуется в качестве браузеров & серверы, получающие 2 набора одного и того же заголовка, должны преобразовать их в вышеуказанный стиль, это может вызвать проблемы, так как вы не будете точно знать, в каком формате они находятся. header("TESTHeader: Test1", false); header("TESTHeader: Test2", false), в зависимости от соблюдения сервером или клиентами версии RFC или HTTP.

Таким образом, этот ответ является причиной того, почему вам не разрешено отправлять один и тот же заголовок несколько раз в ZF3, он не может определить, когда использовать перезапись или нет, основываясь на том, что вы установили заголовок. чтобы обойти это и использовать многозначные заголовки, которые вы можете использовать Ответ джима

1

Создайте свой собственный класс множественного заголовка, добавьте нужную вам функцию (MultipleHeaderInterface), затем добавьте свой заголовок во множественную группу и, наконец, вызовите его в своем

$headers = $controller->getResponse()->getHeaders();

(вызовите новую функцию с новым fromStringHeaders)

0