LINUX.ORG.RU

Как работает header()?

 


0

2

header — Отправка HTTP-заголовка.

Если что-то вывести до заголовков, то будет что-то типа «заголовки уже отправлены». Поэтому и возник вопрос.

Какое понимание верное? Сам склоняюсь ко второму.

  1. Сценарий выполняет header(…) и отправляет заголовок в браузер. Если после header(…) идет опять header(…), то он опять обрабатывается и отправляет браузеру. Браузер получается получает каждый заголовок отдельно. После заголовков сценарий отправляет тело в браузер.

  2. Сценарий выполняет каждый header(…), запоминает сформированные заголовки. В конце добавляет тело. Отправляет и заголовки и тело разом.


Зависит от версий разных демонов и настроек. Но обычно тело шлётся сразу или почти сразу как ты что-то начнёшь выводить в echo. Иначе бы смысла в ошибке «заголовки уже отправлены» не было. Если хочешь изменить это поведение - есть такая штука как output buffering (это настройки в php.ini и ряд функций которые можно вызывать уже из кода). Но вообще генерировать заголовки позже тела это и правда не очень разумный выбор.

Что касается запоминаний именно заголовков, то они как раз сначала сохраняются, а потом высылаются все вместе (но вряд ли ли найдешь пример, где это важно, хотя он, один, есть).

firkax ★★★★★
()

Лучше задачу описать, потому что вряд ли ты голым php наружу отдаешь без веб-сервера. И даже кастомные хедеры удобнее отдавать сервером, обычно.

А может ты вообще https://www.php.net/manual/ru/function.ob-start.php ищешь. Судя по оп посту, как раз это. И вообще пахнет php времён 5 версии задача.

easybreezy
()
Последнее исправление: easybreezy (всего исправлений: 3)

Сценарий выполняет каждый header
Браузер получается получает каждый заголовок отдельно.

Нет, это не так. Почитай что-то про http перед написанием веб скриптов, там достаточно пары страниц.

И кусок кода покажи, если можешь - сразу покажем на ошибки.

easybreezy
()
Последнее исправление: easybreezy (всего исправлений: 1)
Ответ на: комментарий от firkax

как раз сначала сохраняются, а потом высылаются все вместе (но вряд ли ли найдешь пример, где это важно, хотя он, один, есть).

У меня был один (к счастью) пример, где content length надо было считать после подсчёта тела самостоятельно и обязательно отдавать. Идиотский пример конечно, но иначе было никак.

Ты не про такое?:)

easybreezy
()
Ответ на: комментарий от firkax

Заголовки отдает веб-сервер, и очевидно что не по одному а все сразу.

вряд ли ли найдешь пример, где это важно, хотя он, один, есть).

Ну так пиши уже.

easybreezy
()
Последнее исправление: easybreezy (всего исправлений: 1)

Какое понимание верное? …

Смотрим документацию:

Remember that header() must be called before any actual output is sent, either by normal HTML tags, blank lines in a file, or from PHP. It is a very common error to read code with include, or require, functions, or another file access function, and have spaces or empty lines that are output before header() is called.

Ну т. е. как только отправили что-то, относящееся к телу ответа (HTTP body), вызывать header() уже поздно.

Исключение из указанного правила - это если вы (или какой framework) включаете режим буферизации вывода с помощью ob_start(), а потом отдаете все с помощью ob_end_flush(). Тогда вроде можно вызывать head() и посередке. Но проверьте - точно не помню.

vinvlad ★★
()
Ответ на: комментарий от no-such-file

Ну и что теперь, тред мог бы выйти смешным. Мне вон фиркакса ответ интересен, особенно в контексте его предыдущих комментариев вида «php5 норм, а 7+ не нужен». Где еще опыта набраться?

easybreezy
()
Последнее исправление: easybreezy (всего исправлений: 1)
Ответ на: комментарий от firkax

Я понимаю, что запрос-ответ состоит из стартовой строки, заголовков и тела.

А почему php пишет что заголовки уже отправлены, если что-то уже вывел на страницу? Может правильнее сказать «заголовки уже сформированы», а то получается как будто заголовки отдельно уходят браузеру, а позже приходит тело.

VolanQ
() автор топика
Последнее исправление: VolanQ (всего исправлений: 1)
Ответ на: комментарий от VolanQ

… Может правильнее сказать «заголовки уже сформированы», а то получается как будто заголовки отдельно уходят браузеру, а позже приходит тело.

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

Заголовки PHP-шка пишет в выходной поток, естественно, до тела. Почитайте спецификацию HTTP-протокола и все вопросы отпадут.

vinvlad ★★
()
Ответ на: комментарий от vinvlad

PHP-шный движок просто пишет в выходной поток соответствующий ответ в формате HTTP

Эээ? Вам бы самому почитать что-то:)

easybreezy
()
Последнее исправление: easybreezy (всего исправлений: 1)
Ответ на: комментарий от VolanQ

А почему php пишет что заголовки уже отправлены, если что-то уже вывел на страницу?

Да твою ж.. если ты шлёшь вывод в http и получаешь

headers already sent by

Значит кто-то отправил эти headers. И или это твой скрипт, или другой, который ты вызывал до него. Ответь, не используешь ли ты cms.

Если у тебя это один скрипт, и выше него ничего не инклудится, то рекомендую перед обучением php прочитать что угодно про http, хотя бы Википедию.

easybreezy
()
Последнее исправление: easybreezy (всего исправлений: 1)
Ответ на: комментарий от vinvlad

PHP-шный движок просто пишет в выходной поток соответствующий ответ в формате HTTP

Цитата твоя? «Пхпшный движок» вообще про http не знает.

Если ты имел ввиду под «пхпшный движок» свою веб-хероту типа fpm, так и пиши. Но вообще это не «PHP-шный движок»

easybreezy
()
Последнее исправление: easybreezy (всего исправлений: 1)
Ответ на: комментарий от easybreezy

Цитата твоя? «Пхпшный движок» вообще про http не знает.

Нет не моя :) У вас как-то странно прочитанный текст преобразуется в голове ) Вот то, что я написал:

Дойдет ли все одним куском или по частям, PHP вообще не знает …

vinvlad ★★
()

По стандарту HTTP заголовки и тело ответа разделяет двойной символ новой строки. Так вот, если был произведен хоть какой-то вывод не при помощи header(), а при помощи echo, либо если твой файл с PHP-кодом начинается, упаси Господь, не с <?php, то тогда PHP в первый раз вставляет в вывод \r\n\r\n, что означает то, что мы теперь выводим тело ответа и с этого момента мы больше не можем отправлять заголовки. Если вывода никакого сделано еще не было, то мы можем свободно использовать header() столько раз, сколько хотим.

Фнукция ob_start(), а также опция output_buffering (может что-то еще) в php.ini могут переопределить это поведение, но так делать не стоит

r0ck3r ★★★★★
()
Последнее исправление: r0ck3r (всего исправлений: 1)
Ответ на: комментарий от easybreezy

Почему не стоит так делать? Лучше писать код, который отправляет заголовки тогда, когда нужно отправлять заголовки, а выводит данные тогда, когда нужно отправлять данные.

r0ck3r ★★★★★
()
Ответ на: комментарий от r0ck3r

Лучше писать код, который отправляет заголовки тогда, когда нужно отправлять заголовки, а выводит данные тогда, когда нужно отправлять данные.

Ну так может до генерации тела я не знаю, какой будет нужен хедер.

easybreezy
()
Ответ на: комментарий от VolanQ

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

Если изучаешь, то выкинь лишний вебсервер пока и юзай встроенный, -S насколько помню.

Там все очевидно будет.

easybreezy
()
Ответ на: комментарий от VolanQ

А выходной поток это php://output? Если так, то разве туда заголовки пишутся?

Под «выходным потоком» я подразумевал тот поток, куда выводит данные команда echo - ну т.е. тот поток данных, который передается веб-серверу.

vinvlad ★★
()
Ответ на: комментарий от easybreezy

Вообщем понимание появилось как работает header. Я плохо понимаю как http работает. Мне казалось что на запрос клиента ожидается ответ сервера и что ответ приходит разом со всеми заголовками. Наткнулся на такой пример. Здесь тело отдается порциями получается? Я правильно понимаю что первая отправка браузеру идет при i=1 и в этот же момент отправляются все заголовки, а потом тело порциями уходит?

<?php
echo "<h3>Please waiting for 10 seconds...</h3>";
 
for ($i = 1; $i <= 10; $i++) {
    echo $i;
    flush();
    sleep(1);
}
 
echo "<h3>Thx!</h3>";
?>
VolanQ
() автор топика
Ответ на: комментарий от VolanQ

В данном случае, заголовки отправляются в выходной поток при отработке echo "<h3>Please waiting for 10 seconds...</h3>" и после них туда отправляется и начальная часть BODY - т.е. строка <h3>Please waiting for 10 seconds...</h3>.

Как все это дело получит веб-обозреватель - какими порциями - это не особо существенно, да и не известно заранее. Веб-обозреватель просто считывает TCP-поток с HTTP-ответом. Сначала, естественно, строку статуса и заголовки. Потом и тело ответа. Если тело очень длинное, оно прилетает несколькими порциями.

Вызов функции flush() гарантирует лишь то, что данные отправлены веб-серверу. Но сам веб-сервер может у себя эти данные накапливать и отправлять, когда ему удобнее и оптимальнее.

vinvlad ★★
()
Последнее исправление: vinvlad (всего исправлений: 1)
Ответ на: комментарий от r0ck3r

Что у тебя может измениться во время генерации тела,

Попытался ответить на этот комментарий без мата и оскорблений. 4 раза писал коммент, потом стирал. Без мата не получается вообще никак.

easybreezy
()
Ответ на: комментарий от VolanQ

Я плохо понимаю как http работает.

Ну так иди и почитай. Бесплатный саппорт тут нашел, или что? Тебе выше разные люди писали, что если бы ты хотел _учиться_, то учился бы.

easybreezy
()
Ответ на: комментарий от VolanQ

Этот скрипт не шлёт никаких http хедеров, более того, он не имеет никакого отношения к http .

Тред дебилов, я понимаю теперь почему пхп считают злом. Господь, жги.

Ага, внезапно (!), кто бы мог подумать, они снова мешают html с php . h3... Дайте мне скора на самозабан.

easybreezy
()
Последнее исправление: easybreezy (всего исправлений: 4)
Ответ на: комментарий от easybreezy

Этот скрипт не шлёт никаких http хедеров, … Тред дебилов …

Ссылочка специально для шибко «умного»: )))

ini.default-mimetype

Если, к примеру, поменять значение этой настройки на text/plain, то внезапно (для Вас) получим хедер:

Content-Type: text/plain; charset=UTF-8

Так что, как минимум один хедер этот скрипт шлет :)

И хватит уже тут самоутверждаться в треде, не имея на то никаких реальных оснований.

vinvlad ★★
()
Ответ на: комментарий от easybreezy

Вот сейчас я окончательно понял, почему к php плохо относятся. Да, тут все плохо.

Относится можно по разному - никто не заставляет «любить» PHP :) Но вот пытаться кого-то поучать и, тем более, над кем-то «ёрничать» нужно осторожно. Могут и опустить ))

Ну и текст отдельных постов нужно читать и воспринимать в контексте всего треда, а не фрагментарно.

vinvlad ★★
()
Ответ на: комментарий от vinvlad
<?php
echo "<h3>Please waiting for 10 seconds...</h3>";
 
for ($i = 1; $i <= 10; $i++) {
    echo $i;
    flush();
    sleep(1);
}
 
echo "<h3>Thx!</h3>";
?>

Где здесь про http хоть что-то? Ты можешь это запустить на любом http воркере, но это не значит что этот код про http.

До чего лор докатился.

easybreezy
()
Ответ на: комментарий от vinvlad

Могут и опустить ))

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

easybreezy
()
Последнее исправление: easybreezy (всего исправлений: 1)
Ответ на: комментарий от easybreezy

Где здесь про http хоть что-то?

Еще раз повторяю:

текст отдельных постов нужно читать и воспринимать в контексте всего треда, а не фрагментарно.

ТС запускал этот скрипт на веб-сервере, который получал от PHP-шной части следующие части HTTP-ответа:

  • строку статуса
  • как минимум, один HTTP заголовок
  • разделитель хедеров и BODY (перевод строки)
  • HTTP BODY

Интересовало TC-а, в какой момент веб-серверу от PHP отправлялись заголовки HTTP-ответа, на что он и получил конкретный ответ.

vinvlad ★★
()
Ответ на: комментарий от easybreezy

… если уж совсем в детали погружаться, то HTTP-статус и HTTP-хедеры можно задавать и переопределять до тех пор, пока PHP-шный интерпретатор реально не отправит веб-серверу первую порцию данных.

У PHP-шки есть внутренний буфер, где накапливаются данные, относящиеся к HTTP BODY - это чтобы не спамить веб-сервер мелкими фрагментами данных. При заполнении буфера его содержимое отправляется веб-серверу. Явно задержать отправку буферизуемых данных можно с помощью ob_start(). Так вот, до первой отправки буферизованных данных header() и http_response_code() еще могут отработать успешно. Но если ob_start() не используется, то гарантированно отработать эти функции могут только до выполнения первой команды echo, ну или если явно проверить факт НЕотправки заголовков с помощью headers_sent().

vinvlad ★★
()