[php] "Headers already sent" error - hoe te voorkomen?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Millennyum
  • Registratie: Januari 2001
  • Laatst online: 04-05-2023
Op mijn homepage wil ik dmv de volgende php include de meest recente topics van mijn phpBB forum weergeven:

PHP:
1
<?php include("forum/mods/phpbb_fetch_all/include_latestpostings.php");?>


In dit php bestand gebeurt het volgende:

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<?php

//
// This path points to the directory where phpBB is installed. Do
// not enter an URL here. The path must end with a trailing
// slash.
//
// Examples:
// forum in /aaa/bbb/ccc/ and script in /aaa/bbb/ccc/
// --> $phpbb_root_path = './';
// forum in /aaa/bbb/ccc/ and script in /aaa/bbb/
// --> $phpbb_root_path = './ccc/';
// forum in /aaa/bbb/ccc/ and script in /aaa/bbb/ddd/
// --> $phpbb_root_path = '../ccc/';
//

$phpbb_root_path = 'forum/';

define ('IN_PHPBB', true);

if (!file_exists($phpbb_root_path . 'extension.inc'))
{
    die ('<tt><strong>phpBB Fetch All:</strong>
        $phpbb_root_path is wrong and does not point to your forum.</tt>');
}

//
// phpBB related files
//

include_once ($phpbb_root_path . 'extension.inc');
include_once ($phpbb_root_path . 'common.' . $phpEx);
include_once ($phpbb_root_path . 'includes/bbcode.' . $phpEx);

//
// Fetch All related files - we do need all these because the portal is a
// huge example
//

include_once ($phpbb_root_path . 'mods/phpbb_fetch_all/common.' . $phpEx);
include_once ($phpbb_root_path . 'mods/phpbb_fetch_all/posts.' . $phpEx);

//
// start session management
//

$userdata = session_pagestart($user_ip, PAGE_INDEX);
init_userprefs($userdata);

//
// since we are demonstrating span pages we need to set the page offset
//

if (isset($HTTP_GET_VARS['start']) or isset($HTTP_POST_VARS['start']))
{
    $CFG['posts_span_pages_offset'] = isset($HTTP_GET_VARS['start'])
    ? $HTTP_GET_VARS['start'] : $HTTP_POST_VARS['start'];
    if (!intval($CFG['posts_span_pages_offset']))
    {
        $CFG['posts_span_pages_offset'] = 0;
    }
    if (!is_numeric($CFG['posts_span_pages_offset']))
    {
        $CFG['posts_span_pages_offset'] = 0;
    }
    if ($CFG['posts_span_pages_offset'] < 0) {
        $CFG['posts_span_pages_offset'] = 0;
    }
}

// fetch latest postings
$CFG['posts_trim_topic_number'] = 60;
$recent = phpbb_fetch_posts(null, POSTS_FETCH_LAST);


//
// disconnect from the database
//

phpbb_disconnect();

?>
<?php if (isset($recent)) { ?>
<?php for ($i = 0; $i < count($recent); $i++) { ?>
<?php echo '<span class="latesttopics_date">';?>
<?php echo create_date($board_config['default_dateformat'], $recent[$i]['post_time'], $board_config['board_timezone']); ?>
<?php echo '</span>';?>
<?php echo '<span class="latesttopics_topic">';?>
<?php echo ':<br /><img src="http://www.alice-in-wonderland.net/layoutpics/topicarrow.gif" border="0" align="absmiddle" /> <a target="_blank" href="';?>
<?php echo append_sid($phpbb_root_path . 'viewtopic.php?p=' . $recent[$i]['post_id'] . '#' . $recent[$i]['post_id']); ?>
<?php echo '">';?>
<?php echo $recent[$i]['topic_title']; ?>
<?php if ($recent[$i]['topic_trimmed']) { echo '...'; } ?>
<?php echo '</a><br />';?>
<?php echo '</span>';?>
<?php } ?>
<?php } ?>


Wanneer ik dit bestand include krijg ik de melding:
Warning: Cannot modify header information - headers already sent by (output started at /home/aliceinw/public_html/test.html:11) in /home/aliceinw/public_html/forum/includes/sessions.php on line 367

Warning: Cannot modify header information - headers already sent by (output started at /home/aliceinw/public_html/test.html:11) in /home/aliceinw/public_html/forum/includes/sessions.php on line 368
Ik weet wat de oorzaak is van deze melding. Het ligt niet aan spaties e.d. die buiten de php-code vallen, maar het komt doordat in het bestand dat ge-include wordt, er naar sessions.php verwezen wordt, waarin op de regels van de fout de volgende code wordt aangeroepen:

PHP:
1
2
setcookie($cookiename . '_data', serialize($sessiondata), $current_time + 31536000, $cookiepath, $cookiedomain, $cookiesecure);
setcookie($cookiename . '_sid', $session_id, 0, $cookiepath, $cookiedomain, $cookiesecure);


Door die setcookie worden er blijkbaar headers meegestuurd.

Probleemoorzaak is dus bekend. Ik heb alleen geen idee hoe ik moet voorkomen!
Output buffering (ob_start(); gebruiken) heb ik geprobeerd, maar dat hielp niet.
Hoe kan ik ervoor zorgen dat die setcookie aangeroepen wordt voordat er door de geinclude php file output naar mijn webpagina gestuurd wordt?

sessions.php is overigens een standaard bestand van mijn phpBB forum en daar wil ik liever niet in rommelen als dat niet nodig is, want mijn kennis van php is beperkt en ik wil niet dat mijn forum straks niet meer werkt ;)

Alvast bedankt voor de hulp!

Acties:
  • 0 Henk 'm!

Verwijderd

Millennyum schreef op zondag 02 maart 2008
Door die setcookie worden er blijkbaar headers meegestuurd.
Je meent het :|
Probleemoorzaak is dus bekend. Ik heb alleen geen idee hoe ik moet voorkomen!
Output buffering (ob_start(); gebruiken) heb ik geprobeerd, maar dat hielp niet.
Hoe kan ik ervoor zorgen dat die setcookie aangeroepen wordt voordat er door de geinclude php file output naar mijn webpagina gestuurd wordt?
Output buffering gebruiken. Dat het niet hielp betekent dat je het niet goed deed, of dat dat script dat je include heel smerig direct naar de outputstream schrijft.

Als je nou eens helemaal aan het begin van je script, vóór de includes ob_start() aanroept, en pas nádat alle benodigde headers verstuurd zijn je de output flusht, moet alles goed gaan. Controleer voor de zekerheid de nesting van output buffering op de plek waar je de output wilt flushen.

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Als je dan toch van die echo statements gebruikt, waarom open en sluit je dan steeds opnieuw een PHP blok? Lijkt me vrij overbodig, niet?

Overigens zou ik alle HTML in HTML modus outputten (dus buiten een PHP blok laten) en alle PHP stukjes dan wel in PHP blokken laten.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

headers already sent by (output started at /home/aliceinw/public_html/test.html:11
Weet je zeker dat regel 11 van test.html die regel met setcookie is?

Acties:
  • 0 Henk 'm!

  • Kalentum
  • Registratie: Juni 2004
  • Nu online
ik zou alle output die include_latestpostings.php genereert (html code dus) 'bufferen' in een variabele. Dus die echo statements vanaf regel 83 in een $html_latest_posting stoppen (of alles in een functie stoppen en die html code laten retourneren).

op het moment dat je die postings wil laten tonen in je html is een echo $html_latest_posting genoeg.

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Daar kun je veel beter gewoon output buffering voor gebruiken. Dan weet je tenminste zeker dat het goed gaat.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 16-09 15:42

Sebazzz

3dp

Michali schreef op zondag 02 maart 2008 @ 11:21:
Daar kun je veel beter gewoon output buffering voor gebruiken. Dan weet je tenminste zeker dat het goed gaat.
Of ervoor zorgen dat je alle headers eerst output.
Je kan ook alles wat je wilt outputten in een variabele gooien en deze pas aan het einde van je script eruit gooien. (makkelijker)

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Het lijkt me juist dat output buffering heel wat gemakkelijker is. Hiervoor hebben ze een mooie functionaliteit voor, dus dan zou ik niet voor zo'n ondergeschikte eigen oplossing kiezen. Je kunt dan immers ook een stuk minder makkelijk debuggen, omdat var_dump bijvoorbeeld standaard direct naar je output buffer schrijft.

Gewoon ob_start() aanroepen in het begin van je script en ob_end_flush() aan het eind lijkt me toch heel wat simpeler dan alles opslaan in een globale variabel?

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • Kalentum
  • Registratie: Juni 2004
  • Nu online
Normaal gesproken veeg je eerst alle data die je wilt tonen bij elkaar en vervolgens roep je een template aan waarin de pagina getoond wordt.

ik kan me dan ook niet voorstellen dat je ooit zou moeten kijken naar die output buffer functies.

Acties:
  • 0 Henk 'm!

  • Millennyum
  • Registratie: Januari 2001
  • Laatst online: 04-05-2023
Ho wacht even allemaal... Voor de duidelijkheid: ik heb geen verstand van php en alle scriptjes die hier staan heb ik ergens van internet gehaald, en alleen hier en daar wat getweaked. Output buffering en dergelijke zegt me alleen wat omdat ik dat via het Googlen op de foutmelding ben tegengekomen.

Dus Cheetah, je hoeft niet zo neerbuigend te doen. Ik ben al blij dat ik snap wat er fout gaat :|
En alle anderen: jullie oplossingen klinken heel mooi, maar ik heb dus geen idee hoe ik dat zou moeten doen :)

In mijn include_latestpostings.php bestand heb ik ob_start() op regel 2 gezet en ob_end_flush() voor de allerlaatste ?>
Dat hielp dus niet. Heb ik het op de verkeerde plek gezet?

eamelink: regel 11 in de test.html is de plek waar de php include staat, dus waar include_latestpostings.php wordt neergezet. In dat php bestand wordt weer verwezen naar sessions.php, waarin de setcookie regel staat.
Ik denk zeker dat het hier mee te maken heeft, want als je het testbestand (http://www.alice-in-wonderland.net/test.html) aanroept, krijg je de eerste keer wel een foutmelding en na een refresh niet meer. Dan heb je denk ik al een sessie id meegekregen, waardoor dat stukje niet meer aangeroepen wordt en de headers dus ook niet meegestuurd worden.

Acties:
  • 0 Henk 'm!

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

Het probleem is waarschijnlijk dat je een stukje php in een stukje html wilt includen. Op het moment dat Apache bij dat stuk php aankomt, is het stuk html al verstuurd. Dat is de body van de HTTP response, er kunnen dan dus geen dingen meer aan de header toegevoegd worden (die wordt compleet geacht en verstuurd zodra er stukken body verstuurd moeten worden).

Je zult dus je structuur iets moeten omgooien; Een php bestand nemen en daar je html door laten uitspugen bijvoorbeeld, of die html aan het einde includen.

Een makkelijke oplossing voor jou is om nu op regel 1 van test.html dit te zetten :

PHP:
1
<?php ob_start() ?>


En dan helemaal aan het einde van je test.html:

PHP:
1
<?php ob_end_flush() ?>

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
rutgerw schreef op zondag 02 maart 2008 @ 12:17:
Normaal gesproken veeg je eerst alle data die je wilt tonen bij elkaar en vervolgens roep je een template aan waarin de pagina getoond wordt.

ik kan me dan ook niet voorstellen dat je ooit zou moeten kijken naar die output buffer functies.
Eens, maar output buffering kan ook voor andere zaken handig zijn. Bijvoorbeeld voor het cachen van (delen van) je output.

Bovendien kan het zijn dat er een probleem is met een applicatie die niet zo netjes is opgezet, dan kun je er altijd op terugvallen. Helemaal ombouwen is dan geen optie natuurlijk.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • FragFrog
  • Registratie: September 2001
  • Nu online
Michali schreef op zondag 02 maart 2008 @ 12:58:
Eens, maar output buffering kan ook voor andere zaken handig zijn. Bijvoorbeeld voor het cachen van (delen van) je output.
Kan, maar daar zijn veel betere oplossingen voor - danwel in de vorm van een compiling template engine die caching ondersteunt danwel je daadwerkelijke data cachen met behulp van bijvoorbeeld memcache.

Het enige goede argument voor output buffering in mijn opinie is externe code die content echo'ed die je zelf niet aan kan passen. In bijna alle andere gevallen is het overbodige overhead bedoeld om een slordige code-opzet te fixen. Als je dan weinig verstand hebt van PHP prima, maar op deze manier leer je het ook niet.

Ik sluit me dan ook volledig aan bij eamelink: verander je opzet eens naar PHP met HTML (met behulp van bijvoorbeeld heredoc bijvoorbeeld) in plaats van andersom, of output die HTML pas op het laatst. Nog mooier is templates te gaan gebruiken, dan heb je zeker dit soort problemen niet meer :)

[ Site ] [ twitch ] [ jijbuis ]


Acties:
  • 0 Henk 'm!

  • Millennyum
  • Registratie: Januari 2001
  • Laatst online: 04-05-2023
eamelink schreef op zondag 02 maart 2008 @ 12:55:
Een makkelijke oplossing voor jou is om nu op regel 1 van test.html dit te zetten :

PHP:
1
<?php ob_start() ?>


En dan helemaal aan het einde van je test.html:

PHP:
1
<?php ob_end_flush() ?>
U is super! Ik had de output buffer code dus blijkbaar in het verkeerde bestand geplaatst...

Ik zou zelf ook het liefste een 'nette' oplossing hebben, maar mijn index.html omzetten naar index.php ga ik niet voor zoiets doen. Zoekmachines zien het dan namelijk als een andere pagina en dan kan ik opnieuw beginnen met het opbouwen van rankings. Ik zou het kunnen oplossen met een mod-rewrite, maar goed, dan ben je dus omwegen aan het bedenken om een andere omweg te voorkomen...

Bedankt voor alle hulp!

En michali: ik heb het aantal 'echo' statements wat verkleind. Dat was inderdaad niet nodig.

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
eamelink schreef op zondag 02 maart 2008 @ 11:16:
[...]

Weet je zeker dat regel 11 van test.html die regel met setcookie is?
Dat is inderdaad de regel waar de output al gestart is en dankzij de uitgebreide foutmelding is dit een van de eenvoudigste fouten om te debuggen.
Millennyum schreef op zondag 02 maart 2008 @ 10:38:
Ik weet wat de oorzaak is van deze melding. Het ligt niet aan spaties e.d. die buiten de php-code vallen, maar het komt doordat in het bestand dat ge-include wordt, er naar sessions.php verwezen wordt, waarin op de regels van de fout de volgende code wordt aangeroepen:
Neen. Daar verstuur je een header, wat niet meer kan nadat de output gestart is. En waar die output gestart is staat dus letterlijk in de foutmelding.

{signature}

Pagina: 1