Форум программистов, компьютерный форум, киберфорум
PHP для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.72/426: Рейтинг темы: голосов - 426, средняя оценка - 4.72
Почетный модератор
11165 / 4124 / 410
Регистрация: 12.06.2008
Сообщений: 11,943
1

Что означает предупреждение "headers already sent"

09.08.2011, 11:14. Просмотров 84679. Ответов 73

На форуме часто бывают вопросы, что при использовании session_start(), header() и setcookie() и некоторых других функций, появляется сообщения типа
Код
Warning: session_start(): Cannot send session cookie - headers already sent in D:\HTTP\a.php on line 5
Warning: session_start(): Cannot send session cache limiter - headers already sent in D:\HTTP\a.php on line 5
или
Код
Warning: Cannot modify header information - headers already sent in D:\HTTP\a.php on line 5
Это связано с тем, что браузеру уже были отправлены данные перед тем, как была вызвана одна из этих функций.
Если кому интересны подробности, то вот
немного теории
Давайте разберёмся, что происходит, когда мы заходим на сайт. Например, когда мы в браузере открываем страницу http://www.example.ru/file.php, то браузер запрашивает у DNS сервера, какой IP адрес принадлежит серверу www.example.ru. После этого он подключается по протоколу TCP к этому IP адресу на порт 80 (этот порт используется по умолчанию для HTTP) и отправляет текстовый запрос наподобие такого:
Код
GET /file.php HTTP/1.1
Host: www.example.ru
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:5.0) Gecko/20100101 Firefox/5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru,chrome://global/locale/intl.properties;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Cookie: user=2; var=blablabla
Этим запросом в первой строке браузер указывает, что хочет просто получить страницу (GET), указывает адрес страницы и версию протокола (сейчас используются только две версии - 1.0 и 1.1... версия 0.9 устарела и сейчас не используется).
Так же обязательным является параметр Host. Т.к. на каждом сервере может быть несколько разных сайтов, то мы должны указать, к какому именно сайту мы хотим обратиться.
Остальные параметры необязательны... ими браузер просто рассказывает о себе (User-Agent) и рассказывает серверу, как он хочет общаться. Но сейчас речь не об этом...

В ответ на этот запрос веб-сервер запускает выполнение нашего php-скрипта, к которому обращается браузер. И веб-сервер отправляет браузеру результат работы скрипта... но перед этим он отправит свои заголовки ответа.
Код
HTTP/1.1 200 OK
Date: Tue, 09 Aug 2011 06:59:22 GMT
Server: Apache
X-Powered-By: PHP/5.3.5
Content-Length: 1234
Content-Type: text/html; charset=windows-1251
Set-Cookie: PHPSESSID=3ms50sjl2pt2s19sns5udiryn6; path=/

<!DOCTYPE html>
<html>
......
Как вы видите, заголовки идут вначале, а после одной пустой строки начинается тело самого html, который мы генерируем с помощью php-скрипта.

И вот мы подошли к основной сути... когда PHP приказывает веб-серверу начать отправлять само содержимое брузеру, то веб-серверу не остаётся ничего, кроме как отправить вначале все заголовки, которые имеются у него на текущий момент. Поэтому после этого PHP уже не сможет изменить эти заголовки.
Функция header() изменяет любой заголовок. Функция setcookie() добавляет куки к заголовку Set-Cookie, поэтому тоже не может работать после отправки заголовков. session_start() добавляет куки с идентификатором сессии (как в примере выше).


А пока найдём пути решения этой проблемы. Чаще всего такие ситуации происходят из-за использования BOM. BOM - это 2 или 3 невидимых символа в начале файла. Эти символы указывают на то, какая используется кодировка. Многие текстовые редакторы по умолчанию добавляют BOM ко всем файлам юникодовской кодировкой (например UTF-8). Например, создадим в блокноте файл
PHP
1
2
3
<?php
 
?>
И сохраним его в кодировке UTF-8. Но если мы теперь просмотрим файл в кодировке cp1251, то увидим, что вначале файла добавлены символы:
Код
п»ї<?php

?>
Именно эти символы и создают проблему. Ведь PHP исполняет свой код только внутри тегов <?php ?>... всё что снаружи отправляется браузеру как есть. Получается, что эти 3 байта сразу же отправятся к браузеру ещё до начала интерпретации PHP-кода. Хотя, по умолчанию в php.ini включен output_buffering и установлен в значение 4096... поэтому проблемы с BOM не должно быть... однако, у многих пользователей она почему-то есть. Подозреваю, что это следствие использования разных кривых сборок.

Я вижу 2 пути решения это проблемы:
1. Включить в php.ini
Код
output_buffering = 4096
На вашем компьютере это должно помочь. Но если вы позже закачаете свой сайт на хостинг, то у вас не будет уверенности, что там включен этот буфер.
2. Запретить текстовому редактору сохранять BOM. Но тут уже всё зависит от возможностей текстового редактора, который вы используете. Например, я пользуюсь Notepad++... там можно открыть меню "Кодировки" и выбрать "Преобразовать в UTF-8 без BOM".


Если вы уверены, что BOM не используется, значит где-то перед функциями header(), setcookie() и т.п. вы сами отправляете данные пользователю. Возможно, перед открытием тега <?php есть пустая строка... её тоже нужно убрать.
Если вначале вам необходимо отправлять данные, то можно включить использование буфера, что бы данные не отправлялись сразу браузеру:
PHP
1
2
3
4
5
6
<?php
ob_start();
 
echo "Всякие тексты";
header('Content-Type: text/plain; charset=windows-1251');
?>
В этом случае никаких проблем не будет, т.к. ob_start() указывает, что данные вначале надо накапливать в буфере и отправлять браузеру только когда выполнение скрипта будет завершено.
56
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
09.08.2011, 11:14
Ответы с готовыми решениями:

Что означает знак "?" и амперсант в браузерной строке?
Что означает вопросительный знак и амперсант в браузерной строке? Ну скажем так: Или так: ...

Что означает "бинарно-безопасное сравнение"?
Здравствуйте! :) Подскажите, что означает &quot;бинарно-безопасное сравнение&quot;? Например, в мануале к...

Что означает знак "=>" в php?
Добрый день, что бы значил этот знак &quot;=&gt;&quot; ? Пример: $month= array(1 =&gt; 'янв', 'фвр', 'мрт',...

Что означает $_GET["currentPage"]?
Короче, я был в шоке, - не могу найти в Яндексе что означает выражение $_GET, хотя делал...

73
292 / 244 / 65
Регистрация: 15.09.2017
Сообщений: 1,139
09.09.2018, 20:30 41
CyberX346, очень деструктивные мысли. Я лично не понимаю, как можно написать какую-то там CMS, не изучив основы протокола. А потом как угодно изворачиваться, лишь бы не признавать свою фундаментальную ошибку и исправлять ее основательно.
0
0 / 0 / 0
Регистрация: 09.09.2018
Сообщений: 9
09.09.2018, 20:34 42
output_buffering*boolean/integer

You can enable output buffering for all files by setting this directive to 'On'. If you wish to limit the size of the buffer to a certain size - you can use a maximum number of bytes instead of 'On', as a value for this directive (e.g., output_buffering=4096). This directive is always Off in PHP-CLI.

Можем свериться? Я сейчас в больнице и у меня нет возможности постоянно ноутбук использовать. Предлагаю в качестве расследования выложить вашу конфигурацию сервера и параметр настройки. Интересует Cent os и ubuntu. Настройки мамп я тоже выложу. У меня не работало именно на ubuntu lamp и, если там стоит off или php в режиме cli то тогда все обьяснимо.
0
0 / 0 / 0
Регистрация: 09.09.2018
Сообщений: 9
13.09.2018, 09:12 43
Вот. Выбрался на выходные из госпиталя и решил сразу проверить(с ноутбуком наконец-то).

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

при

Код
# Output buffering
php_value output_buffering 4092
в .htaccess

Все работает как надо. Видимо дело в моей недоосведомленности(да и не только моей) потому, что хостеры на этот простейший вопрос разводят руками и ничего внятного ответить не могут. Ну а теперь моя CMS пригодна для любого хостинга. Всем спасибо
0
Эксперт PHP
4217 / 3142 / 1016
Регистрация: 06.01.2011
Сообщений: 9,116
13.09.2018, 11:17 44
Цитата Сообщение от CyberX346 Посмотреть сообщение
Собственно реально все правда: если параметр выключить в htaccess у меня перестает работать авторизация.
Вам и толковали про буферизацию выше. Вот и перестаёт.
Цитата Сообщение от CyberX346 Посмотреть сообщение
теперь моя CMS пригодна для любого хостинга
Выведите что-то более 4092 байт и полетит "CMS для всех хостингов" нафиг.
1
0 / 0 / 0
Регистрация: 09.09.2018
Сообщений: 9
13.09.2018, 12:30 45
Ага. Только нагенерировать 4к до заголовков это еще проблема.
0
292 / 244 / 65
Регистрация: 15.09.2017
Сообщений: 1,139
13.09.2018, 12:45 46
CyberX346, можете "вечно дрожать" или надеяться на авось.
0
0 / 0 / 0
Регистрация: 09.09.2018
Сообщений: 9
13.09.2018, 14:41 47
Учиться программировать чтобы не выходить за 4к или брать году. Я цистерна писал на спор за 3 месяца по приколу. Еще неделю писал форум к ней. Правда до сих пор с ним и парюсь. А вам я не знаю чего пожелать. Разве что зарплаты тысяч так 80 хотя бы чтобы легче было...
0
0 / 0 / 0
Регистрация: 04.05.2019
Сообщений: 2
04.05.2019, 15:48 48
кто нибудь умеет работать в лабвью?
0
pav1uxa
04.05.2019, 17:28
  #49

Не по теме:

Цитата Сообщение от Александр1988до Посмотреть сообщение
кто нибудь умеет работать в лабвью?
Да, вот там посмотрите - https://www.cyberforum.ru/labview-g/

0
62 / 34 / 8
Регистрация: 07.02.2015
Сообщений: 118
28.05.2019, 18:25 50
Приветствую, форумчане.

Столкнулся сегодня со странной историей.
Если в <head> есть строчка <meta name="description" content=""> (именно такая, причем неважно - копипасченная или переписанная "от руки", то Cannot modify header information – headers already sent.
Если я стираю только эту строчку - ошибка исчезает.
Перепечатывал от руки, вставлял из других рабочих файлов.
Кодировки, кавычки, пробелы внутри, пробелы до и после строчки, наличие символов из кириллицы, паразитные символы - все проверено.
Идет реакция чисто на текст, такое ощущение :-)

Решил пока ob_start'ом, но докопаться хочется и надо.

Буду благодарен за помощь, спасибо.
0
Почетный модератор
11165 / 4124 / 410
Регистрация: 12.06.2008
Сообщений: 11,943
29.05.2019, 00:20  [ТС] 51
Цитата Сообщение от AlexNewaro Посмотреть сообщение
Идет реакция чисто на текст, такое ощущение :-)
Возможно, у вас редактор когда видит эту строку, то пытается использовать UTF-8 с BOM. А когда этой строки нет, то сохраняет в какой-то однобайтовой кодировке. Каким редактором пользуетесь? Попробуйте в другом редакторе сохранить.
0
62 / 34 / 8
Регистрация: 07.02.2015
Сообщений: 118
29.05.2019, 00:23 52
Цитата Сообщение от Humanoid Посмотреть сообщение
Возможно, у вас редактор когда видит эту строку, то пытается использовать UTF-8 с BOM. А когда этой строки нет, то сохраняет в какой-то однобайтовой кодировке. Каким редактором пользуетесь? Попробуйте в другом редакторе сохранить.
Я пользуюсь Coda 2, пробовал TextEdit'ом, Komodo Edit, даже виндовый ноут нашел и Dreamviewer'ом каким-то древним.
Все одно и то же.
0
Эксперт PHP
4444 / 3619 / 1521
Регистрация: 24.04.2014
Сообщений: 10,665
29.05.2019, 00:33 53
AlexNewaro, значит неправильно организовано приложение - отправка тела ответа перед заголовками, в сочетании с директивой output_buffering. Добавляя текст превышается значение заданное в данной директиве и ошибка себя проявляет.
1
Почетный модератор
11165 / 4124 / 410
Регистрация: 12.06.2008
Сообщений: 11,943
29.05.2019, 00:36  [ТС] 54
А если вместо этой строки добавить столько же пробелов? Может, там просто эта строка добавляет размер и переполняет буфер.
Иначе сравнивайте кодировку и наличие BOM.

Добавлено через 40 секунд
Не успел... Jewbacabra опередил
1
62 / 34 / 8
Регистрация: 07.02.2015
Сообщений: 118
29.05.2019, 00:40 55
Цитата Сообщение от Humanoid Посмотреть сообщение
А если вместо этой строки добавить столько же пробелов? Может, там просто эта строка добавляет размер и переполняет буфер.
Вы правы, так и случилось.

Цитата Сообщение от Jewbacabra Посмотреть сообщение
неправильно организовано приложение - отправка тела ответа перед заголовками, в сочетании с директивой output_buffering
Видимо да, буду разбираться теперь...


Всем огромное спасибо за помощь!
0
0 / 0 / 0
Регистрация: 17.02.2019
Сообщений: 52
17.09.2019, 23:22 56
Можете помочь.
У меня вылезла ошибка cannot modify header information
В 35 в 36 и 38 строках где куки.
По пробывал способ сохранения без BOM,не помогло,как решить ее?
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?
// Страница авторизации
// Функция для генерации случайной строки
function generateCode($length=6) {
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHI JKLMNOPRQSTUVWXYZ0123456789";
    $code = "";
    $clen = strlen($chars) - 1;
    while (strlen($code) < $length) {
    $code .= $chars[mt_rand(0,$clen)];
    }
    return $code;
}
// Соединямся с БД
$link=mysqli_connect("localhost", "root", "", "testtable");
if(isset($_POST['submit']))
{
    // Вытаскиваем из БД запись, у которой логин равняеться введенному
    $query = mysqli_query($link,"SELECT user_id, user_password FROM users WHERE user_login='".mysqli_real_escape_string($link,$_POST['login'])."' LIMIT 1");
    $data = mysqli_fetch_assoc($query);
    // Сравниваем пароли
    if($data['user_password'] === md5(md5($_POST['password'])))
    {
        // Генерируем случайное число и шифруем его
        $hash = md5(generateCode(10));
        if(!empty($_POST['not_attach_ip']))
        {
            // Если пользователя выбрал привязку к IP
            // Переводим IP в строку
            $insip = ", user_ip=INET_ATON('".$_SERVER['REMOTE_ADDR']."')";
        }
        // Записываем в БД новый хеш авторизации и IP
        mysqli_query($link, "UPDATE users SET user_hash='".$hash."' ".$insip." WHERE user_id='".$data['user_id']."'");
        // Ставим куки
        setcookie("id", $data['user_id'], time()+60*60*24*30);
        setcookie("hash", $hash, time()+60*60*24*30,null,null,null,true); // httponly !!!
        // Переадресовываем браузер на страницу проверки нашего скрипта
        header("Location: 80x.php"); exit();
    }
    else
    {
        print "Вы ввели неправильный логин/пароль";
    }
}
?>
<form method="POST">
Логин <input name="login" type="text" required><br>
Пароль <input name="password" type="password" required><br>
Не прикреплять к IP(не безопасно) <input type="checkbox" name="not_attach_ip"><br>
<input name="submit" type="submit" value="Войти">
</form>
0
Почетный модератор
11165 / 4124 / 410
Регистрация: 12.06.2008
Сообщений: 11,943
18.09.2019, 00:54  [ТС] 57
Цитата Сообщение от NitrailS Посмотреть сообщение
В 35 в 36 и 38 строках где куки.
Обратите внимание, что в вашем выложенном коде нумерация строк сдвинута на 1. Скорее всего, в оригинальном файле у вас в начале есть пустая строка, которую вы сюда не перенесли. Пустую строку нужно убрать. Файл должен начинаться без BOM, без пустых строк и без пробелов.. сразу должен идти "<?". В этом случае проблем быть не должно.
Так же проблема может быть, если одна из вызываемых функций выведет предупреждение. Но, думаю, вы бы это заметили.
0
0 / 0 / 0
Регистрация: 17.02.2019
Сообщений: 52
18.09.2019, 00:59 58
Humanoid, Я кодировки поменял.
Теперь у меня другая проблема с скриптами.
У меня не выводит логин авторизованного человека.
Вместо него выводит Xm.Что-то не получилось
Это скрипт проверки
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?
// Скрипт проверки
 
// Соединямся с БД
$link=mysqli_connect("localhost", "root", "", "testtable");
 
if (isset($_COOKIE['id']) and isset($_COOKIE['hash']))
{
    $query = mysqli_query($link, "SELECT *,INET_NTOA(user_ip) AS user_ip FROM users WHERE user_id = '".intval($_COOKIE['id'])."' LIMIT 1");
    $userdata = mysqli_fetch_assoc($query);
 
    if(($userdata['user_hash'] !== $_COOKIE['hash']) or ($userdata['user_id'] !== $_COOKIE['id'])
 or (($userdata['user_ip'] !== $_SERVER['REMOTE_ADDR'])  and ($userdata['user_ip'] !== "0")))
    {
        setcookie("id", "", time() - 3600*24*30*12, "/");
        setcookie("hash", "", time() - 3600*24*30*12, "/");
        print "xm, что-то не получилось";
    }
    else
    {
        print "hi, ".$userdata['user_login'].". Всё работает!";
    }
}
else
{
    print "Включите куки";
}
?>
А это скрипт авторизации
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<?
// Страница авторизации
 
// Функция для генерации случайной строки
function generateCode($length=6) {
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHI JKLMNOPRQSTUVWXYZ0123456789";
    $code = "";
    $clen = strlen($chars) - 1;
    while (strlen($code) < $length) {
            $code .= $chars[mt_rand(0,$clen)];
    }
    return $code;
}
 
// Соединямся с БД
$link=mysqli_connect("localhost", "root", "", "testtable");
 
if(isset($_POST['submit']))
{
    // Вытаскиваем из БД запись, у которой логин равняеться введенному
    $query = mysqli_query($link,"SELECT user_id, user_password FROM users WHERE user_login='".mysqli_real_escape_string($link,$_POST['login'])."' LIMIT 1");
    $data = mysqli_fetch_assoc($query);
 
    // Сравниваем пароли
    if($data['user_password'] === md5(md5($_POST['password'])))
    {
        // Генерируем случайное число и шифруем его
        $hash = md5(generateCode(10));
 
        if(!empty($_POST['not_attach_ip']))
        {
            // Если пользователя выбрал привязку к IP
            // Переводим IP в строку
            $insip = ", user_ip=INET_ATON('".$_SERVER['REMOTE_ADDR']."')";
        }
 
        // Записываем в БД новый хеш авторизации и IP
        mysqli_query($link, "UPDATE users SET user_hash='".$hash."' ".$insip." WHERE user_id='".$data['user_id']."'");
 
        // Ставим куки
        setcookie("id", $data['user_id'], time()+60*60*24*30);
        setcookie("hash", $hash, time()+60*60*24*30,null,null,null,true); // httponly !!!
 
        // Переадресовываем браузер на страницу проверки нашего скрипта
        header("Location: check.php"); exit();
    }
    else
    {
        print "Вы ввели неправильный логин/пароль";
    }
}
?>
<form method="POST">
Логин <input name="login" type="text" required><br>
Пароль <input name="password" type="password" required><br>
Не прикреплять к IP(не безопасно) <input type="checkbox" name="not_attach_ip"><br>
<input name="submit" type="submit" value="Войти">
</form>
И вообщем я не могу понять почему теперь не выводит логин,хотя 2 дня назад выводил логин.
0
Почетный модератор
11165 / 4124 / 410
Регистрация: 12.06.2008
Сообщений: 11,943
18.09.2019, 11:49  [ТС] 59
NitrailS, не знаю. Предлагаю выводить отладочную информацию и анализировать, какое именно условие не подошло. Например, там, где вы выводите сообщение "что-то пошло не так" заодно через var_dump() выводите куки, _SERVER и userdata. После этого смотрите, какое значение оказалось неожиданным. Если не будет получаться, то создайте новую тему с вопросом... кто-нибудь, возможно, поможет. Просто, самому разобраться будет быстрее, чем ждать других людей.

Цитата Сообщение от NitrailS Посмотреть сообщение
PHP
1
mysqli_query($link,"SELECT user_id, user_password FROM users WHERE user_login='".mysqli_real_escape_string($link,$_POST['login'])."' LIMIT 1");
Вы же используете mysqli... там можно использовать mysqli_prepare()/mysqli_stmt_bind_param(), что бы вставлять переменные в запрос. Это более правильный путь, который уменьшит вероятность ошибки из-за того, что вам уже не надо задумываться про экранирование символов.
0
0 / 0 / 0
Регистрация: 21.10.2017
Сообщений: 1
24.09.2019, 14:59 60
$&&& = mysqli_real_escape_string(); - это функция очистка от спец символов. Попробуй просто $&&& = rtrim();

Добавлено через 2 минуты
А Humanoid - респект!
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.09.2019, 14:59

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

Что означает символ "&" ?
Добрый вечер. Увидел запись$username = &amp;$_SESSION; Что означает знак &amp; перед сессией

Что означает "?" ?
Добрый день! Встречаю такую запись, например $attributes ?? Что означают два знака вопроса?

Не работает setcookies: "Cannot modify header information - headers already sent by"
Доброго времени суток , проблема заключается в том что когда пытаюсь установить cookie то возникает...

Ошибка : "Warning: Cannot modify header information - headers already sent by"
При вводе логина и пароля выходят две ошибки: Warning: Cannot modify header information - headers...

Ошибка "Cannot modify header information - headers already sent by" - PHP
Привет. у меня проблем с header - не могу найти свой ошибку. если нужна могу отправит вам все...

Ошибка: "Cannot send session cache limiter - headers already sent"
Сайт выдаёт ошибку: A PHP Error was encountered Severity: Warning Message: session_start():...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.