int21h: php.exe POST und GET Daten übergeben

Hi,

Mit der php.exe kann man ja eine PHP-Datei parsen lassen und das Ergebnis auf stdout ausgeben lassen (php -f file.php).
Bei einer normalen Datei klappt das auch wunderbar, nur Frage ich mich, wie ich nun einen QUERY_STRING oder die POST-Daten mitparsen lassen kann? (Sprich: Das Programm arbeitet z.B mit $_GET["var"] oder $_POST["var"]
Ich wäre für jede Hilfe sehr dankbar!

  1. Hi!

    Mit der php.exe kann man ja eine PHP-Datei parsen lassen und das Ergebnis auf stdout ausgeben lassen (php -f file.php).

    Ja. Aber das ist für den reinen Einsatz in der Kommandozeile gedacht, nicht als eigenständiger Webserver oder sowas.

    Bei einer normalen Datei klappt das auch wunderbar, nur Frage ich mich, wie ich nun einen QUERY_STRING oder die POST-Daten mitparsen lassen kann? (Sprich: Das Programm arbeitet z.B mit $_GET["var"] oder $_POST["var"]

    Die Frage ist eher, wie kommt der Query-String vom Client zum PHP-Script? Wie willst Du denn Dein Script aufrufen? Mit dem Browser geht das nur über eie Webserver, und da bekommst Du von diesem auch die $_POST und $_GET Arrays zur Verfügng gestellt, nicht so beim Einsatz der CLI-Version von PHP.

    Siehe auch:
    http://de3.php.net/manual/de/features.commandline.php

    Wenn Du ein PHP-Script über die Shell aufrufst, kannst Du diesem Argumente übergeben, siehe:
    http://www.dclp-faq.de/q/q-php-shell.html

    Wenn ein Script GET und POST Variablen verwendet ist es sicherlich einmal für eine Webserver-Umgebung und nicht für eine Shell-Umgebung geschrieben worden.

    Grüße
    Andreas

    1. Die Frage ist eher, wie kommt der Query-String vom Client zum PHP-Script? Wie willst Du denn Dein Script aufrufen? Mit dem Browser geht das nur über eie Webserver, und da bekommst Du von diesem auch die $_POST und $_GET Arrays zur Verfügng gestellt, nicht so beim Einsatz der CLI-Version von PHP.

      Das genau is ja das Problem. Ich schreibe mir gerade einen eigenen Webserver. Und wenn eine *.php Datei angefordert wird. dann wollte ich "einfach" die angeforderte Datei an den PHP-Parser (php.exe) übergeben, dass Ergebnis von stdoud des Parser abfangen und mittels
      HTTP zurücksenden. Nur weiss ich nicht, wie ich das mit GET und POST machen soll. Der QUERY_STRING wird ja nur in der Umgebungsvariable
      abgelegt und die POST-Daten stehen dem Script als STDIN zur Verfügung. Nur weiß ich eben nicht, wie ich dass alles mittels php.exe parsen kann.

      1. Hallo!

        Das genau is ja das Problem. Ich schreibe mir gerade einen eigenen Webserver.

        Ah, so ist das! Das rückt die Frage natürlich in ein ganz anderes Licht ;-)

        Und wenn eine *.php Datei angefordert wird. dann wollte ich "einfach" die angeforderte Datei an den PHP-Parser (php.exe) übergeben, dass Ergebnis von stdoud des Parser abfangen und mittels
        HTTP zurücksenden. Nur weiss ich nicht, wie ich das mit GET und POST machen soll. Der QUERY_STRING wird ja nur in der Umgebungsvariable
        abgelegt und die POST-Daten stehen dem Script als STDIN zur Verfügung. Nur weiß ich eben nicht, wie ich dass alles mittels php.exe parsen kann.

        Da bin ich ehrlich gesagt etwas überfragt, da ich mich hiermit noch nicht beschäftigt habe. Was Du auf alle Fälle brauchst ist eien Schnittstelle zu PHP, da es für Deinen Server vermutlich noch kein PHP-Modul gibt, musst Du PHP über CGI ansprechen. Hierzu musst Du halt die CGI-Spezifikation lesen und entsprechend implementieren, denke ich.

        Versuchs mal hier:
        http://hoohoo.ncsa.uiuc.edu/cgi/

        Wenn ich http://hoohoo.ncsa.uiuc.edu/cgi/interface.html richtig deute funktioniert das ganze z.B. bei einem POST Request ganz grob so:

        0. Ein Client sendet eine Anfrage an ein PHP-Script per POST
        1. Du setzt die Umgebungsvariablen entsprechend der CGI-Spezifikation
        2. Du schickst den Query-String an stdin von php.exe mit dem Dateinamen als Argument
        3. Du liest die Ausgabe von PHP
        4. Du erzeugst die fehlenden Header
        5. Du schickst alles zusammen an den Client zurück

        Mit welcher Programmiersprache schreibst Du den Web-Server?

        Mit ist nicht ganz so klar wie PHP die GET-Parameter bekommt, ich vermute mal dass PHP versucht die aus den entsprechenden Umgebungsvariablen nach CGI-Spezifikation selbst auszulesen und in den Array zu schreiben, naja, wie gesagt, "ich vermute" ;-)

        Außerdem bin ich nicht so sicher wo die Umgebungsvariablen gesetzt werden.

        Grüße
        Andreas

        1. Mit welcher Programmiersprache schreibst Du den Web-Server?

          Den Webserver schreibe ich komplett in Java (1.4.2). Die Standardfunktionen funktionieren bereits, nur dass parsen von php files klappt nicht. Mittlerweile denke ich, dass das einlesen des QUERY_STRINGs oder der POST Daten in einem Script beim parsen mit php.exe überhaupt nicht geht. :(
          Trotzdem vielen Dank für deine Hilfe!

          1. Hi!

            Den Webserver schreibe ich komplett in Java (1.4.2).

            Ah.

            Die Standardfunktionen funktionieren bereits, nur dass parsen von php files klappt nicht. Mittlerweile denke ich, dass das einlesen des QUERY_STRINGs oder der POST Daten in einem Script beim parsen mit php.exe überhaupt nicht geht. :(

            Doch, Apache & Co. machen das ja auch irgendwie, und man gibt bei der CGI-Version ja nur den Pfad zur binary-File an, der werden dann die Daten übergeben, auf welche Weise auch immer, vermutlich über eine bidirektionale pipe. CGI ist ja standardisiert, das heißt das PHP im Prinzip mit jedem Webserver laufen müsste, der CGI unterstützt, und eben das musst Du mit Deinem Webserver hinbekommen.

            Ich weiß jetzt allerdings nicht wie gut das mit Java geht. Die Übergabe von GET-Parametern passiert soweit ich das jetzt weiß wirklich über die Umgebungsvariablen, die man z.B. in PHP mit setenv() setzt, in Java kenne ich keine solche Funktion. Jedenfalls müsste PHP dann theoretisch diese Umegebunsvariable(QUEREY_STRING) automatisch analysieren und entsprechend den $_GET Array mit den Werten füllen. Vermutlich braucht PHP aber mehr als einen Wert um überhaupt was zu machen, ich würde schon alle Umgebungsvariablen setzen so wie

            hier: http://hoohoo.ncsa.uiuc.edu/cgi/env.html

            und hier: http://de3.php.net/manual/de/install.commandline.php#install.commandline.using-variables

            beschrieben.

            Ich denke dass es Sache des Servers ist den genauen Pfad des angeforderten Scriptes zusammenzusetzen(document-root + URL-Pfad), und soweit ich das weiß wird eben dieser absolute Pfad zum Script als Argument an den Interpreteraufruf angehängt, und nicht als Umgebungsvariable übermittelt.

            Aber vielleicht solltest Du mal einen Blick in den Quelltext eines möglichst einfachen Webservers werfen, z.B. http://hoohoo.ncsa.uiuc.edu/docs/setup/Compilation.html#get_source bei mir bekomme ich das irgendwie gerade nicht entpackt, aber das sind nur 300 KB, da sollte man den Teil bzgl. CGI doch finden und dann siehst Du wie es geht, wenn auch vemtulich in einer anderen Sprache.

            Grüße
            Andreas

            1. Ich bin schon ein gutes Stück weiter, und weiß jetzt, dass ich die POST Daten mit einer Pipe in das Script bringen kann (echo POSTDATEN | php file.php) und für die GET Daten setze ich eine Umgebungsvariable. Im Script kann ich auch bereits auf die Daten mittels $_ENV['QUERY_STRING'] und $fp = fopen("C://stdin", "r") zugreifen. Nur funktionieren die Arrays $_GET[] und $_POST immer noch nicht. Meine einzige Frage is nun, wie fülle ich diese Arrays?

              1. Hi!

                Ich bin schon ein gutes Stück weiter, und weiß jetzt, dass ich die POST Daten mit einer Pipe in das Script bringen kann (echo POSTDATEN | php file.php)

                Das würde ich nicht machen, die POST-Daten können schonmal etwas größer sein und dann kannst Du so probleme bekommen (ist mir mal passiert). ich würde eine bidirektionale pipe öffnen, so dass Du direkt auf STDIN schreiben kannst, und STDOUT auslesen.

                und für die GET Daten setze ich eine Umgebungsvariable. Im Script kann ich auch bereits auf die Daten mittels $_ENV['QUERY_STRING'] und $fp = fopen("C://stdin", "r") zugreifen. Nur funktionieren die Arrays $_GET[] und $_POST immer noch nicht. Meine einzige Frage is nun, wie fülle ich diese Arrays?

                AFAIK erstellt PHP diese Arrays mit Hilfe der gesetzten Umgebungsvariablen. Ich würde mir mal den PHP-Source ansehen, das hae ich gerade mal gemacht.

                Z.B. findest Du da solche Dinge in der Datei cgi_main.c im Verzeichnis cgi in Zeile 983:

                /* Make sure we detect we are a cgi - a bit redundancy here,
                    but the default case is that we have to check only the first one. */
                 if (getenv("SERVER_SOFTWARE")
                  || getenv("SERVER_NAME")
                  || getenv("GATEWAY_INTERFACE")
                  || getenv("REQUEST_METHOD")) {
                  cgi = 1;
                 }

                Das heißt obige Variablen müssen (korrekt) gesetzt sein, da PHP sonst nicht versucht wie in der CGI-spec.  auf die Umgebungsvariablen zuzugreifen. Was Du machst ist PHP ohne jegliches Konzept anzusprechen, klar bekommst Du dann mit tricks Variablen aus den Umgebungsvariablen und STDIN, aber darum geht es nicht. Du brauchst eien definierte3 Schnittstelle wo für Dich nur CGI in Frage kommt. Hierzu musst Du a) Wissen wie die Schnittstelle funktioniert(also Welche Variablen wie gesetzt werden, was wie übergeben/angesprochen wird...). Der Einfachheit halbe kannst Du Dir auch im PHP-Source ansehen was genau gefprdert wird. Oben das ist nur ein Beispiel. Es gibt sicher noch weitere Hürden, am sichersten wäre es daher eine korrekte CGI-Schnittstelle zu implementieren. Das ist glaube ich gar nicht so schwer. Also so ganz komm eich mit dem Code nicht klar, auf alle Fälle werden GET-Variablen automatisch aus dem QUERY_STRING extrahiert, naja, aber ich habe nicht wirklich herausbekommen können unter welchen Voraussetzungen das passiert.

                Also ich habe mir mal die genaus CGI-Spezifikation angesehen, die ist gar nicht so lang und recht einfach zu verstehen. Ich habe das in wengen Minuten überflogen udn kann sagen da steht alles drin was Du wisen musst.

                Da steht z.B.:

                Servers MUST provide the following metavariables to scripts. See the individual descriptions for exceptions and semantics.

                CONTENT_LENGTH
                    CONTENT_TYPE
                    GATEWAY_INTERFACE
                    PATH_INFO
                    QUERY_STRING
                    REMOTE_ADDR
                    REQUEST_METHOD
                    SCRIPT_NAME
                    SERVER_NAME
                    SERVER_PORT
                    SERVER_PROTOCOL
                    SERVER_SOFTWARE

                Mit genauen Angaben wie diese Variabnlen auszusehen haben und wie sie übergeben werden sollten. Diese Variablen solltest Du recht einfach setzen können und schon sollte es gehen!

                da steht z.B. auch dass ein Script welches CGI verwendet(also auch die PHP-Implamentation) vor jeder Antwort den Inhalt von REQUEST_METHOD prüfen soll, und das hast Du schonmal nicht gesetzt.

                PHP im Speziallen prüpft mindestens(!) SERVER_SOFTWARE, SERVER_NAME, GATEWAY_INTERFACE und REQUEST_METHOD bevor es überhaupt irgendwas in Richtung CGI tut. Kann sein dass später noch mehr geprüft ist, was sogar sehr wahrscheinlich ist. Also, setze obige Umgebungsvariablen korrekt und es sollte funktionieren.

                lies: http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html

                und implementiere das danach! Und lies es komplett bis Du alles verstanden hast, das wird nicht lange dauern.

                Immerhin hast Du dann eine richtige CGI-Schnittstelle mit der Du dann auch PERL usw. ansprechen kannst! Und ohne wirst Du PHP nicht anständig zum laufen bekommen, denn die Alternative ist eine eigene SAPI zu schreiben, was sicherlich erheblich aufwändiger ist!

                Viele Grüße
                Andreas

                PS: Kannst Du mir verraten wie Du in Java Umgebungsvariablen setzt? Ist das identisch für Windows und Unix? Und sag Bescheid ob es funktioniert :-)

                1. Hi!

                  Z.B. findest Du da solche Dinge in der Datei cgi_main.c im Verzeichnis cgi in Zeile 983:

                  /* Make sure we detect we are a cgi - a bit redundancy here,
                      but the default case is that we have to check only the first one. */
                  if (getenv("SERVER_SOFTWARE")
                    || getenv("SERVER_NAME")
                    || getenv("GATEWAY_INTERFACE")
                    || getenv("REQUEST_METHOD")) {
                    cgi = 1;
                  }

                  In Zeile 569 dieser Datei(Pfad im Source: sapi/cgi/cgi_main.c) steht übrigens auch noch ein interessanter Kommentar:

                  /* {{{ init_request_info

                  initializes request_info structure

                  specificly in this section we handle proper translations
                    for:

                  PATH_INFO
                   derived from the portion of the URI path following
                   the script name but preceding any query data
                   may be empty

                  PATH_TRANSLATED
                      derived by taking any path-info component of the
                   request URI and performing any virtual-to-physical
                   translation appropriate to map it onto the server's
                   document repository structure

                  empty if PATH_INFO is empty

                  The env var PATH_TRANSLATED **IS DIFFERENT** than the
                   request_info.path_translated variable, the latter should
                   match SCRIPT_FILENAME instead.

                  SCRIPT_NAME
                      set to a URL path that could identify the CGI script
                   rather than the interpreter.  PHP_SELF is set to this.

                  REQUEST_URI
                      uri section following the domain:port part of a URI

                  SCRIPT_FILENAME
                      The virtual-to-physical translation of SCRIPT_NAME (as per
                   PATH_TRANSLATED)

                  These settings are documented at
                    http://cgi-spec.golux.com/

                  Based on the following URL request:

                  http://localhost/info.php/test?a=b

                  should produce, which btw is the same as if
                    we were running under mod_cgi on apache (ie. not
                    using ScriptAlias directives):

                  PATH_INFO=/test
                    PATH_TRANSLATED=/docroot/test
                    SCRIPT_NAME=/info.php
                    REQUEST_URI=/info.php/test?a=b
                    SCRIPT_FILENAME=/docroot/info.php
                    QUERY_STRING=a=b

                  but what we get is (cgi/mod_fastcgi under apache):

                  PATH_INFO=/info.php/test
                    PATH_TRANSLATED=/docroot/info.php/test
                    SCRIPT_NAME=/php/php-cgi  (from the Action setting I suppose)
                    REQUEST_URI=/info.php/test?a=b
                    SCRIPT_FILENAME=/path/to/php/bin/php-cgi  (Action setting translated)
                    QUERY_STRING=a=b

                  Comments in the code below refer to using the above URL in a request

                  */

                  Grüße
                  Andreas

                  1. Hallo,

                    nur mal eben den Titel etwas korrigiert, denn das Thema ist IMHO interessanter als der ursprüngliche Titel vermuten läßt ;-)
                    Wenn ich irgendwo Mist erzählt habe bitte ich den Wissenden mich zu korrigieren :)

                    Grüße
                    Andreas