Mike: header location versagt wegen Leerzeichen in PHP ?

Hi,

total seltsam.

Das HEADER versagt wenn bereits Leerzeichen zum Browser gesendet wurden, ist klar, aber auch innerhalb PHP? Wie kann das denn?

Beispiel mit 2 Dateien

1. index.php

Inhalt:

  
<?php  
require_once('test.php');  
test();  
exit;  
?>  

2. test.php

Inhalt:

  
<?php  
  
function test()  
{  
header('location:http://google.de');  
}  
  
?> 

########################################

Das bedeutet test.php wird in index.php includet. Wohlgemerkt, kein HTML, kein Leerzeichen oder sonstwas ausserhalb von den PHP-Tags.

Aber! test.php enthält ein Leerzeichen, und zwar direkt neben dem abschliessenden php-tag also bildlich: ?> &nbsp;

Im Prinzip sollte das sowieso egal sein, weil index.php ja keinen leeren Bereich hat, alles innerhalb der TAGS.

Trotzdem kommt die typische Fehlermeldung "Cannot modify header information - headers already sent..." und die Aktion wird nicht ausgeführt.

Entferne ich das Leerzeichen funktioniert es, wie es soll.
-------------------------------------------------------------
Das alleine verstehe ich schon nicht, warum ist das so?

Aber dann kommt noch was Lustiges, wenn ich das Leerzeichen drin lasse und die test.php ändere in:

  
  
<?php  
  
header('location:http://google.de');  
  
function test()  
{  
  
}  
?>  

dann geht es auch problemlos. Also das kann doch nicht sein, entweder das Leerzeichen ist schuld, was nicht nachvollziehbar ist, dann dürfte aber auch nicht das letzte Beispiel funktionieren, denn hier wird ja auch die komplette Datei includet. Bug, oder habe ich einen Denkfehler?

Mike

  1. Moin!

    total seltsam.

    Nö, logisch.

    Das HEADER versagt wenn bereits Leerzeichen zum Browser gesendet wurden, ist klar, aber auch innerhalb PHP? Wie kann das denn?

    Ist ja nicht "innerhalb" PHP.

    Beispiel mit 2 Dateien
    2. test.php

    <?php

    function test()
    {
    header('location:http://google.de');
    }

    ?>

      
    Wenn am Ende dieser Datei noch ein Leerzeichen steht, ist das gleichbedeutend mit dem Befehl echo " "; an dieser Stelle.  
      
    Und wenn du dir dann mal den Programmfluss mit diesem zusätzlichen Echo ansiehst, wirst du feststellen, dass dein require\_once() in der index-Datei dieses Echo eben ausführt, bevor die Funktion mit dem header() aufgerufen wird. Folglich ist schon Ausgabe erfolgt, bevor der Header gesendet wird.  
      
    Wenn du header() aus der Funktion herausnimmst, wird dieser Befehl ausgeführt, bevor das Leerzeichen ausgegeben wird - dann funktioniert alles.  
      
    Um zu vermeiden, dass nachfolgende Leerzeichen in Includes dir die Show zerstören, ist es sinnvoll, das schließende PHP-Tag "?>" wegzulassen. Die Coding-Standards von Zend fordern das beispielsweise sogar explizit, das ist also kein "unsicheres Verlassen auf irgendeinen Automatismus", sondern gehört so. PHP ist es egal, ob die Datei "ordnungsgemäß" geschlossen wird, oder ob der PHP-Bereich offen bleibt.  
      
     - Sven Rautenberg
    
    1. Hi,

      »» Das HEADER versagt wenn bereits Leerzeichen zum Browser gesendet wurden, ist klar, aber auch innerhalb PHP? Wie kann das denn?

      Ist ja nicht "innerhalb" PHP.

      Nein? Wenn ich die Datei nicht include, sondern direkt einfüge ist es doch auch innerhalb oder nicht?

      »» 2. test.php

      Wenn am Ende dieser Datei noch ein Leerzeichen steht, ist das gleichbedeutend mit dem Befehl echo " "; an dieser Stelle.

      »»

      Ja in der index.php klar, aber die test.php wird doch nur eingefügt in einem bereits bestehenden php Bereich.

      Und wenn du dir dann mal den Programmfluss mit diesem zusätzlichen Echo ansiehst, wirst du feststellen, dass dein require_once() in der index-Datei dieses Echo eben ausführt, bevor die Funktion mit dem header() aufgerufen wird. Folglich ist schon Ausgabe erfolgt, bevor der Header gesendet wird.

      Wenn dem so ist, dürfte doch mein letztes Beispiel nicht funktionieren, aber du sagst ja weiter:

      Wenn du header() aus der Funktion herausnimmst, wird dieser Befehl ausgeführt, bevor das Leerzeichen ausgegeben wird - dann funktioniert alles.

      »»

      ach so, ok zumindest das verstehe ich.

      Um zu vermeiden, dass nachfolgende Leerzeichen in Includes dir die Show zerstören, ist es sinnvoll, das schließende PHP-Tag "?>" wegzulassen. Die Coding-Standards von Zend fordern das beispielsweise sogar explizit, das ist also kein "unsicheres Verlassen auf irgendeinen Automatismus", sondern gehört so. PHP ist es egal, ob die Datei "ordnungsgemäß" geschlossen wird, oder ob der PHP-Bereich offen bleibt.

      den schliessenden tag soll ich weglassen. Mal davon abgeshen, dass dann blöd mit dem Editor zu arbeiten ist wegen Syntaxhervorhebung, kommt dann auch mein persönlicher Ordnungssinn nicht klar. Beide Tags weg ok, aber einer alleine?

      Gruss
      Mike

      1. Hi nochmal,

        hmmm es liegt also tatsächlich an dem abschliessenden ?>

        Denn ohne den könnten auch noch tausende Leerzeichen drin sein und keine Probleme bereiten.

        Also ich weiss nicht, ich würde sowas BUG nennen. Keine Programmiersprache kann doch allen Ernstes empfehlen einen einleitenen Tag zu machen und den abschliesssenden auf keinen Fall.

        Mike

        1. Moin!

          hmmm es liegt also tatsächlich an dem abschliessenden ?>

          Nein, es liegt an dem Leerzeichen dahinter. Das ist die Ursache für dein Problem.

          Nochmal zur Klarstellung der Codeablauf:

          index.php:
            require_once(test.php); <- Programmablauf wird in dieser Datei unterbrochen, eine neue Datei wird ausgeführt.

          test.php:
            function test()... <- Definition einer Funktion - kommt in den Speicher, tut nix.
            echo " "; <- Ausgabe des Leerzeichens, weil es hinter dem ?> im HTML-Bereich steht.
            EOF <- Dateiende, zurück zur Index.php

          index.php
            test(); <- Funktionsaufruf. Der ruft die im Speicher befindliche Funktionsdefinition auf. Was NICHT passiert ist, dass der Funktionsaufruf in irgendeiner Weise nochmal mit der Datei "test.php" verknüpft wird.
             header(); <- scheitert wegen der vorhergehenden Ausgabe des Leerzeichens.

          Denn ohne den könnten auch noch tausende Leerzeichen drin sein und keine Probleme bereiten.

          Richtig, weil Leerzeichen im PHP-Teil kein ausführbarer Code sind und auch zu keiner Ausgabe führen.

          Also ich weiss nicht, ich würde sowas BUG nennen. Keine Programmiersprache kann doch allen Ernstes empfehlen einen einleitenen Tag zu machen und den abschliesssenden auf keinen Fall.

          Stimmt so ja auch nicht. Es wird empfohlen, in "reinen PHP-Dateien", die keinerlei HTML-Teil enthalten, das einzige schließende PHP-Tag am Dateiende wegzulassen, um möglichen Problemen mit noch danach folgendem Whitespace (auch Zeilenumbrüche etc. verursachen das Problem) schon direkt aus dem Weg zu gehen.

          Es ist eine Empfehlung, keine Vorschrift - jeder Coding-Standard ist nur eine Empfehlung, wenn man sich dran halten will, darf man das tun, wenn nicht, bricht auch keine Welt zusammen. Wenn man weiß, warum die Empfehlung gegeben wurde, und deren Ursache sicher im Griff hat, so dass sie nicht auftreten kann, dann spricht nichts dagegen, sie zu ignorieren.

          - Sven Rautenberg

          1. Hi,

            index.php:
              require_once(test.php); <- Programmablauf wird in dieser Datei unterbrochen, eine neue Datei wird ausgeführt.

            Aha, das kann ich nachvollziehen.

            Wäre also so wie:

            <?php
            $a =1
            ?>
            <!-- Unterbrochen und somit HTML BEREICH -->
            <?php
            $b=2
            ?>

            Damit sind aber einige  PHP-Schulweisheiten zu diesem Thema ad acta.

            • Code immer innerhalb von php-tags
            • Beim includen wird die Datei genau an der Stelle so eingesetzt wo sie aufgerufen wurde als wenn man sie direkt dort reinschreibt.

            Und was daran nicht ganz logisch ist, wenn die bildliche Darstellung der Unterbrechung richtig ist: Was wenn innerhalb einer Funktion etwas included wird. Das Beispiel oben kann man ja auch so trennen, aber eine Funktion kann man ja nicht mittendrin unterbrechen. PHP kann es offensichtlich, warum auch immer das Sinn machen soll.

            »» ...Keine Programmiersprache kann doch allen Ernstes empfehlen ...

            Stimmt so ja auch nicht. Es wird empfohlen,....»»

            Habe doch auch empfohlen geschrieben.

            Es ist eine Empfehlung, keine Vorschrift - jeder Coding-Standard ist nur eine Empfehlung, wenn man sich dran halten will, darf man das tun, wenn nicht, bricht auch keine Welt zusammen.

            Ja und auch wenn ich empfohlen gesagt habe, sagst du doch selbst:

            Die Coding-Standards von Zend fordern das beispielsweise sogar explizit

            Inwieweit könnte diese "Forderung" von Zend dem normalen PHP-Programmierer mal Probleme machen? Denn ich habe noch nie ein Includefile gesehen, mit einem offenen Tag.

            Mike

            1. Moin!

              Wäre also so wie:

              <?php
              $a =1
              ?>
              <!-- Unterbrochen und somit HTML BEREICH -->
              <?php
              $b=2
              ?>

              Damit sind aber einige  PHP-Schulweisheiten zu diesem Thema ad acta.

              • Code immer innerhalb von php-tags

              Wieso dies? Daran ändert sich doch nichts, nur weil das schließende PHP-Tag optional ist und alternativ das Dateiende gilt.

              • Beim includen wird die Datei genau an der Stelle so eingesetzt wo sie aufgerufen wurde als wenn man sie direkt dort reinschreibt.

              Das war noch nie so. Beweis: Man kann include/require nicht an jeder beliebigen Stelle einer Datei platzieren. Versuch das beispielsweise mal innerhalb einer Klassendefinition:

                
              class myClass {  
                
              include_once('klassen_konstanten.php');  
                
              public function blah() {}  
              }  
              
              

              Wird nicht funktionieren.

              include/require eröffnet vielmehr eine Art Subroutinenaufruf, dessen Code in der einzubindenden Datei steht, und dessen "Auswirkungen" beispielsweise in Form von neu deklarierten Funktionen, Klassen, Variablen etc. dann auch wieder im Hauptskript verfügbar sind.

              Außerdem kann die eingebundene Datei sogar einen Rückgabewert an die einbindende Datei liefern. Siehe return. Der Rückgabewert wird dann als Funktionsergebnis von include/require im aufrufenden Skript verfügbar sein. Allerdings ist diese Vorgehensweise nicht unbedingt ein guter Ersatz für die Verwendung von Funktionen - nur falls du jetzt auf Ideen kommst... :)

              Und was daran nicht ganz logisch ist, wenn die bildliche Darstellung der Unterbrechung richtig ist: Was wenn innerhalb einer Funktion etwas included wird. Das Beispiel oben kann man ja auch so trennen, aber eine Funktion kann man ja nicht mittendrin unterbrechen. PHP kann es offensichtlich, warum auch immer das Sinn machen soll.

              Innerhalb einer Funktion darf include/require vorkommen. Und wenn die Funktion aufgerufen wird, wird das Inkludieren durchgeführt. Wenn nicht, dann nicht.

              »» »» ...Keine Programmiersprache kann doch allen Ernstes empfehlen ...
              »»
              »» Stimmt so ja auch nicht. Es wird empfohlen,....»»

              Habe doch auch empfohlen geschrieben.

              Naja, die Programmiersprache empfiehlt es ja auch nicht, sondern die Zend Coding Standards. Nun ja, da Zend einer der Hauptbeteiligten an PHP ist, hat das natürlich ein gewisses Gewicht, aber es gibt noch ausreichend viele andere Coding-Standards, die in der PHP-Welt ebenfalls verwendet werden - daran sollte man sich jetzt nicht aufhängen.

              Ich erwähnte ja schon: Dein Ursprungsproblem ist das Leerzeichen an der falschen Stelle, nicht das schließende Tag. Coding Standards dienen auch nicht unbedingt dazu, der Programmiersprache leichteres Skriptparsing zu erlauben, sondern in erster Linie sollen sie das Programmieren erleichtern und den Quellcode lesbar machen.

              »» Die Coding-Standards von Zend fordern das beispielsweise sogar explizit

              Inwieweit könnte diese "Forderung" von Zend dem normalen PHP-Programmierer mal Probleme machen? Denn ich habe noch nie ein Includefile gesehen, mit einem offenen Tag.

              Wenn du gegen die Zend Coding Standards verstößt, wird man vermutlich deinen Quellcode niemals als Contribution zum Zend Framework akzeptieren, denn da sind diese Coding Standards verpflichtend. Gleiches gilt natürlich auch für andere Projekte, die dieselben oder - in diesem Punkt identische - andere Standards vorschreiben, deren Einhaltung bei Beiträgen zu dem Projekt verpflichtend ist.

              Ansonsten: Der schließende Tag eines PHP-Blocks am Ende einer Datei ist optional, und in einigen Fällen ist das Weglassen hilfreich...

              - Sven Rautenberg

            2. Hi,

              Damit sind aber einige  PHP-Schulweisheiten zu diesem Thema ad acta.

              woher Du diese Weisheiten her hast, ist mir wohlgemerkt nicht klar.

              • Code immer innerhalb von php-tags

              Die "<?php ... ?>"-Symbolik dient dazu, dass der PHP-Code als solcher erkannt werden kann. Andernfalls handelt es sich einfach nur um Text.

              • Beim includen wird die Datei genau an der Stelle so eingesetzt wo sie aufgerufen wurde als wenn man sie direkt dort reinschreibt.

              Demnach würde Dein Code wie folgt aussehen:

                
              <?php  
              <?php  
                
              function test()  
              {  
              header('location:http://google.de');  
              }  
                
              ?>  
              test();  
              exit;  
              ?>
              

              Nicht wirklich, oder?

              Cheatah

              --
              X-Self-Code: sh:( fo:} ch:~ rl:| br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
              X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
              X-Will-Answer-Email: No
              X-Please-Search-Archive-First: Absolutely Yes