HTML wird manchmal nicht komplett geladen?

Wenn PHP auf einen derart krassen Fehler läuft, das nicht der komplette Output an den Client gesendet werden kann, kann PHP dem Client auch keine Fehlermeldung mehr senden (klingt logisch, oder?).

Ich würde so an die Sache ran gehen:

- Schau im Server-Log vom Apache nach, ob da irgendwelche auffälligen Sachen drin stehen, so Sachen wie "Child process died" oder so in der Art - das sieht man, wenn das PHP-Modul segfaulted.
- Schau nach, was der Server in den Headern sendet, wie groß der Content-Length ist, und ob die Anzahl der empfangenen Bytes mit dem Wert übereinstimmt. Das kannst du z.B. mit Firefox-Addon Live HTTP Headers prüfen.

Voraussetzung für die Sache mit Content-Length ist, das du Output-Buffering verwendest und kurz vor dem Senden des Outputs mittels echo an den Client die Länge des Outputs mit strlen() berechnest und mittels header("Content-Length: $bytes"); an den Client übermittelst. Dann weiß der Browser, wieviel er empfangen muss und wird auch versuchen, die Bytes komplett zu laden.

Das ist eines der Hauptprobleme, die Anfänger (wozu ich dich nicht zähle) begehen. Da wird einfach auf Teufel-komm-raus mit echo alles an den Browser gesendet, und irgendwann ist die PHP-Sitzung beendet, der Client weiß davon aber nichts, weil er keine Content-Length kennt, und liest sich evtl. zu Tode.

Kurzer Abriss über den Code-Ablauf:

PHP:
ob_start();
echo "fooo.....";
// sonstige wahnsinnig sinnvolle Logik
echo "weiteres blabla";
// und noch mehr Logik....
echo "blub! Fertig!";
// Jetzt Daten in eine Variable schieben, die eigentlich ohne OB schon längst gesendet worden wären
$content = ob_get_contents();
// Output-Buffer sauber machen (Inhalten verwerfen)
ob_end_clean();
// Header über die Länge der folgenden Daten an den Client mitteilen
header("Content-Length: " . strlen($content));
// Und raus damit...
echo $content;
 
Ich habe nun den PHP-Anteil komplett bis auf:
PHP:
<?php
   error_reporting(E_ALL);
?>
gelöscht.

Beim ersten Seitenaufruf ist zwar alles geladen aber mit Darstellungsfehlern. Das Formular ist unnötigerweise doppelt so hoch. :rolleyes:

Ich habe dann mal ein paar CSS und HTML Änderungen durchgeführt, aber ich kann den Fehler nicht mehr provozieren.

Hmmm... Dann wird es wohl doch ein PHP-Fehler sein. 368138.png

EDIT:

Im PHP-Code selbst kommen maximal 10 echos vor. Aber im HTML-Code kommen sehr vieles echos vor wegen dem selected="selected". Wenn ich mich jetzt nicht verrechnet habe, sind es genau 326 echos wegen dem selected="selected". 368138.png

EDIT:

@saftmeister:
Ich habe deinen Code ganz unten eingefügt.

Aufbau des Skriptes:
1. Javascript
2. CSS Stylesheet
3. PHP-Code
4. HTML Code
5. PHP-Code (von dir)

Es wird ganz normal "fooo.....weiteres blablablub! Fertig!" ausgegeben und ich kann den Fehler nicht mehr provozieren. :confused:
 
Zuletzt bearbeitet:
Saftmeisters Code gehört nicht unverändert an das Ende.
Das ob_start an den Anfang,
die drei echos stehen für deinen Code
und der Rest am Ende.
 
Achso.

Habe ich jetzt gemacht, aber es wird nichts "neues" ausgegeben.

In "Live HTTP headera" steht unter "Content-Lenght" knapp 20000.

An einer anderen Stelle steht aber "Content-Lenght" knapp 1800000.

EDIT:

Falles es hilft:

Das laden der Seite dauert "0,04103 Sekunden" und es nie so das es lange ladet oder so. Nur wenn das Skript ausgeführt wird, kann es über 4-5 Sekunden dauern.

Edit:

Die Zahl 20000 ändert sich aber nicht, auch wenn ich den gesamten PHP-Code lösche.
 
Zuletzt bearbeitet:
Korrekt. So wie sheel beschrieben hat. Mich macht aber grad eines stutzig: Du schreibst, dass du keine Fehler-Anzeigen gesehen hast. Wenn da auch beim Anfügen von meinem Beispiel-Code ans Ende deines Codes keine Fehler angezeigt werden, wundere ich mich ein wenig:

header() kann nur gesendet werden, wenn vorher kein anderer Content an den Browser gesendet wurde. Das ist ja, wenn du meinen Code ans Ende gestellt hast, nicht der Fall. Folglich sollte eine Meldung zu sehen sein "Cannot send header....".

Wenn diese Meldung nicht kommt, ist bei dir vermutlich die Fehler-Anzeige deaktiviert. Zusätzlich zum Error-Reporting kann es möglich sein, mittels

PHP:
// Schreib mich an den Anfang deines Scripts
ini_set('display_errors', 1);
ini_set('log_errors', 0);

einzuschalten.

Bringt das irgendeine Veränderung?
 
Bevor ich das ausprobiere möchte ich kurz erklären wie das ganze bei mir "funktioniert".

Ich habe ein vBulletin-Template:
In diesem Template ist minimaler HTML-Code für das "vBulletin-Layout" und eine Variable für den Include einer PHP-Datei.

Dann habe ich eine PHP-Datei die das "vBulletin-Backend" ladet, die Navigation "erstellt" und das eigentliche Skript includet.

So wird es dann schließlich includet:
PHP:
   ob_start();
   (@include_once ('./skript.php')) OR die ('Internal File Error!');
   $Skript = ob_get_contents();
   ob_end_clean();

Die Variable "$Skript" steht dann auch im Template.

Im Skript selber ($Skript) ist der JS, PHP und HTML-Anteil drin.

Wo soll ich denn deinen Code genau einbauen?

PHP:
// Javascript
// CSS-Stylesheet

// PHP-Code

// HTML-Code

Ich habe es jetzt IN DEN PHP-Code eingefügt und es erscheint kein Fehler.
 
Zuletzt bearbeitet:
Ich erklär dir mal was da eigentlich passiert, dann kannst du es denk ich selbst entscheiden, wo du das einbauen musst.

Output-Buffering wendet man an, wenn man verhindern möchte, das PHP den Output direkt und unmittelbar an den Client sendet, an der Stelle, im Code, wo man echo, printf, etc. eingebaut hat. Hier mal ein Beispiel-Code (nicht für den Einbau in deine Scripte bestimmt, sondern nur zum veranschaulichen):

PHP:
<?php
function viel_viel_logik_in_einer_funktion()
{
  unset($variable);
  /*
   * unendlich viel weiterer Code hier....
   * ...
   */

  return 0;
}

session_start();

echo "<html><body>";

viel_viel_logik_in_einer_funktion();

echo "</body></html>";

Ok, schauen wir uns das mal an:

1. In dem Script oben wird zunächst eine Funktion definiert. Was die Funktion macht ist erstmal egal, wichtig ist aber, das in der Funktion Fehler sein könnten, die ein Notice, Warning, Error oder Fatal error nach sich ziehen.
2. Wir gehen mal davon aus, das in der Funktion ein Notice geworfen wird.
3. Unterhalb der Funktionsdefinition wird erstmal mittels session_start() ein Header (Cookie) an den Client gesendet.
4. Anschließend kommt ein bisschen Ausgabe
5. Die definierte Funktion wird aufgerufen
6. Widerum ein bisschen Ausgabe


- An Punkt 1 und 2 wird erstmal keine Information an den Client (Browser) geschickt, es ist ja nur eine Funktionsdefinition, deren Code noch nicht ausgeführt wird.
- An Punkt 3 wird ein HTTP-Header gesendet, also eine nicht direkt sichtbare Ausgabe im Browser, sondern eher Informationen über den nachfolgenden Output des Servers an den Client.
- Punkt 4 ist zum ersten mal eine unmittelbare Ausgabe an den Client
- Punkt 5 ist eine implizite unmittelbare Ausgabe an den Client, denn eine Notice wird auch als Content an den Browser gesendet, der es als Text darstellt.
- Punkt 6 ist eine unmittelbare Ausgabe an den Browser.

Unmittelbar heißt, in dem Moment, in dem der Code ausgeführt wurde, wird der Content bereits abgesendet.
Implizit bedeutet in dem Falle, das du nicht per Code eine Ausgabe machst, sondern PHP das selbst tut (außer das error_reporting ist entsprechend nicht eingestellt oder display_errors ist deaktiviert).

Da das HTTP-Protokol aber vorsieht, das der Server dem Client mitteilt, wieviel er (der Client) laden soll, ist der Beispiel-Code ein Verstoß gegen das HTTP-Protokol. Da du aber am Anfang des Scripts im Code noch nicht weißt, wieviele Bytes du wohl senden wirst, gibt es einen Trick:

Man hebt sich die Ausgabe bis zum Schluss auf, sendet erst nach dem kompletten Abarbeiten der Logik und Ausgaben einen HTTP-Header über die Länge des Inhalts, den die Ausgabe ergeben hat und erst dann die Ausgabe selbst. Das Aufheben kann man mit dem sog. Output-Buffering erledigen. PHP wird, wenn ob_start() aufgerufen wird, die Ausgaben nicht direkt an den Client senden, sondern in einem Puffer vorhalten. Wenn man ob_get_contents() aufruft, gibt PHP diesen Puffer zurück. ob_end_clean() löscht den Puffer. Wenn man den kompletten Inhalt der Ausgabe jetzt in einer Variablen hat, kann man die Länge mittels strlen() berechnen und HTTP-Protokoll-Konform dem Browser mitteilen, wieviele Daten man senden wird.


Mit dieser Erklärung solltest du es eigentlich selbst entscheiden können, wo im Code du das positionieren solltest.
 
Danke für die ausführliche Erklärung.

Ich verstehe es leider nicht 100%.

Was kannst Du mir denn empfehlen?

Mein akutuelles Skript sieht jetzt so aus:

// "extra" JS-Skript
// "extra" CSS-Stylesheet
// HTML-Code für das Layout des HTML-Formulars
// PHP-Code
// HTML-Code (Formular und Layout)

Soll ich wieder alles bis auf den PHP-Code auslagern?

Das schwierige an der Sache ist die Forensoftware vBulletin. Denn das Skript soll Teil der Forensoftware sein. Zumindest was Layout und "Navigation" betrifft (Wer ist Online? Anzeige und Navbar).
Ich vermute auch hier die "kleinen" Fehler.

Der genaue "Verlauf" sieht so aus:
-> das_tolle_skript.php (das wird vom User aufgerufen)
--> Include vBulletin-Backend, vBulletin-Template und eigentliche Skript (skript.php)

Das ist so eine blöde Variante, aber ich kenne keine andere. Offiziell wird auch nur diese "Angeboten" bzw. beschrieben.
 
Ich kenne den Sourcecode von vBulletin jetzt nicht und möchte es ehrlich gesagt auch nicht runterladen und anschauen, ich hoffe, du verstehst das.

Wenn vBulletin kein Output-Buffering benutzt (du kannst den Sourecode nach ob_start() durchsuchen lassen), kannst du das prima selbst machen.

1. Im Kopf der das_tolle_script.php schreibst du das ob_start() rein.
2. Dann kommt der vBulletin-include und der restliche Code, so wie es momentan eingebaut ist.
3. Am Ende, also nach deinem eigenen Code schreibst du alles, was ich im Beispiel ab der Zeile mit ob_get_contents() geschrieben habe.

Wenn vBulletin allerdings selbst Output-Buffering verwendet, sieht das etwas anders aus. Dann müsste man sich etwas anderes überlegen. Aber schau erstmal selbst. Dann sehen wir weiter.
 
Zurück