TS: Post2Host via SSL

0 60

Post2Host via SSL

TS
  • php
  • tls
  • webserver
  1. 0
    dedlfix
    1. 0
      TS
      1. 0
        dedlfix
  2. 1
    MudGuard
    1. 0

      Post2Host via SSL, Fehler gefunden

      TS
      1. 0
        pl
      2. 0
        dedlfix
        1. 0
          TS
          1. 0
            dedlfix
            1. 0
              TS
              1. 0
                dedlfix
          2. 0
            pl
            1. 1
              dedlfix
              1. -1
                pl
                1. 0
                  dedlfix
                  1. 0
                    TS
                    1. 0
                      dedlfix
                    2. 0
                      1unitedpower
          3. -1
            pl
      3. 0
        1unitedpower
        1. 0
          TS
        2. -1
          pl
  3. 0
    pl
  4. 0

    Funktion für Post2Host via SSL, Zwischenstand 2019-05-30

    TS
    1. 0
      Mitleser
      1. 0
        TS
        1. 0
          Mitleser
          1. 0
            TS
      2. 1
        1unitedpower
        1. 0
          Mitleser
        2. 0
          TS
          1. 1
            1unitedpower
            1. 0
              TS
      3. 0
        pl
        1. 0

          PHP und PUT

          TS
          1. 0
            dedlfix
          2. 0
            pl
            1. 0
              dedlfix
              1. 0
                pl
                1. 0
                  dedlfix
              2. 0
                TS
                1. 0
                  dedlfix
                  1. 0
                    TS
                    1. 1
                      dedlfix
                    2. 1
                      1unitedpower
          3. 0
            pl
            1. 0
              pl
              1. 0
                TS
                1. 0
                  pl
                  1. 0
                    TS
                    1. 0
                      pl
                      1. 0
                        dedlfix
                        1. 0
                          pl
                  2. 0
                    JürgenB
                    1. 0
                      pl
        2. 0
          Mitleser
          1. 0
            pl
            1. 1
              Mitleser
    2. 1
      dedlfix
_Der_ Fehler ist gefunden und weiter unten wird das Skript dann auch ohne die weiteren Fehler samt Beschreibung nochmal gepostet werden

Hello,

ich mühe mich ab, per PHP Post2Host mit SSL zum Laufen zu bringen. Leider bekomme ich immer nur die Statusmeldung von Server:

HTTP/1.1 400 Bad Request
Date: Mon, 27 May 2019 12:07:32 GMT
Server: Apache/2.2.22 (Debian)
Vary: Accept-Encoding
Content-Length: 226
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
</body></html>

Das Testscript zum Posten sieht so aus:

<?php   ### function_post2host.php ###

function PostToHost($host,$path,$data,$ssl=FALSE,$autoport=TRUE,$user=FALSE,$pass=FALSE,$referer=FALSE)
{
    //Daten anpassen
    if(is_array($data))
	{
		$data_to_send = '';
		foreach($data as $name => $var)
	    {
            $data_to_send .= urlencode($name).'='.urlencode($var).'&';
        }
        $data_to_send = substr($data_to_send,0,-1);
    }
    else $data_to_send = 'data=' . urlencode($data);
  
	//SSL einbinden, falls gewünscht

	if($ssl === TRUE)
	{
		$port = 443;
		$host = 'ssl://' . $host;
	}
	else {$port = 80; }

	if ($autoport === TRUE) 
	{
		### alter nothing;
	}
	elseif (is_numeric($autoport))
	{
		$port = $autoport;
	}
    else {return false;}
	  
	//Verbindung öffnen
	if (false === ($fp = fsockopen($host, $port)))
	{ 
		return false;
	}	
  
	stream_set_timeout($fp, 30);
  
	//Header erzeugen
	fputs($fp,"POST ".$path." HTTPS/1.1\r\n");
	fputs($fp,"Host: ".$host."\r\n");
  
	if($user != "" && $pass != "") 
	{
		fputs($fp, "Authorization: Basic " . base64_encode($user.":".$pass)."\r\n");
	}
  
	if (FALSE !== $referer) 
	{
		fputs($fp, "Referer: " . urlencode($referer) . "\r\n");
	}
	fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
	fputs($fp, "Content-length: " . strlen($data_to_send) . "\r\n");
	fputs($fp, "Connection: close\r\n\r\n");
	fputs($fp, $data_to_send);
  
	//Antwort abfangen
    $res = '';
	while(!feof($fp)) 
	{
		$res .= fgets($fp, 128);
	}
	
	//Verbindung schliessen
	fclose($fp);
	
	//Antwort zurückgeben
	return $res;
}

###--------------------------------------------------------------------
# PostToHost($host,$path,$data,$ssl=FALSE,$autoport=TRUE,$user=FALSE,$pass=FALSE,$referer=FALSE)

$_data = array();
$_data ['eins'] = 'erster Eintrag';
$_data ['zwei'] = 'zweiter Eintrag';
$_data ['drei'] = 'dritter Eintrag';

echo PostToHost("bitworks.de",'/sensor/postresponder.php',$_data,TRUE);

?>

Im Error-Log des angeposteten Servers ist leider nichts zu finden.
Wo steckt der Fehler? Wie kann sich zum Debugging vorgehen?

Glück Auf
Tom vom Berg

--
Es gibt nichts Gutes, außer man tut es!
Das Leben selbst ist der Sinn.

akzeptierte Antworten

  1. Tach!

    Ich kürz das mal auf ein paar Zeilen zusammen, die zwar nicht zusammenstehen, mir aber das Problem zu sein scheinen.

    	if($ssl === TRUE)
    		$host = 'ssl://' . $host;
    	if (false === ($fp = fsockopen($host, $port)))
    	//Header erzeugen
    	fputs($fp,"POST ".$path." HTTPS/1.1\r\n");
    	fputs($fp,"Host: ".$host."\r\n");
    

    Bist du sicher, dass der Hostname in beiden Fällen mit Protokollangabe zu notieren ist?

    dedlfix.

    1. Hello,

      Ich kürz das mal auf ein paar Zeilen zusammen, die zwar nicht zusammenstehen, mir aber das Problem zu sein scheinen.

      	if($ssl === TRUE)
      		$host = 'ssl://' . $host;
      	if (false === ($fp = fsockopen($host, $port)))
      	//Header erzeugen
      	fputs($fp,"POST ".$path." HTTPS/1.1\r\n");
      	fputs($fp,"Host: ".$host."\r\n");
      

      Bist du sicher, dass der Hostname in beiden Fällen mit Protokollangabe zu notieren ist?

      Beim fsockopen() auf jeden Fall. Beim Senden habe ich es eben mal rausgenommen, nützt aber nichts.

      Könnte allerdings sein, dass der Server mit PHP beim Content-Type kein "application/x-www-form-urlencoded", sodern nur "multipart/form-data" mag.

      Meine alte Post2Host-Version für HTTP-Post arbeitet nämlich mit "multipart/form-data". Da funktionierts.

      Müsste ich zum Testen nochmal alles umbauen mit Boundaries usw.

      Ich bin jetzt etwas entnervt, weil mir einfach keine Debuggingstrategie einfallen will. Wo und wie könnte ich "bildgebend" diagnostizieren?

      Glück Auf
      Tom vom Berg

      --
      Es gibt nichts Gutes, außer man tut es!
      Das Leben selbst ist der Sinn.
      1. Tach!

        Könnte allerdings sein, dass der Server mit PHP beim Content-Type kein "application/x-www-form-urlencoded", sodern nur "multipart/form-data" mag.

        Stell mal sicher, dass PHP sich zeigen darf über die ini-Direktive expose_php. Und dann schau, ob PHP bei dem Request überhaupt zum Zuge kommt, also ob im Response-Header eine Angabe zur PHP-Version zu sehen ist.

        dedlfix.

  2. Hi,

    	fputs($fp,"POST ".$path." HTTPS/1.1\r\n");
    

    Auch wenn über SSL transportiert wird, muß das hier m.W. HTTP/1.1 heißen.

    (und wenn es bei ssl doch HTTPS heißen müßte, müßte das S hier vom ssl-Parameter der Methode abhängig sein)

    cu,
    Andreas a/k/a MudGuard

    1. Hello Andreas,

      	fputs($fp,"POST ".$path." HTTPS/1.1\r\n");
      

      Auch wenn über SSL transportiert wird, muß das hier m.W. HTTP/1.1 heißen.

      (und wenn es bei ssl doch HTTPS heißen müßte, müßte das S hier vom ssl-Parameter der Methode abhängig sein)

      Viiiielen Dank. Genauso ist es!

      Das fiel mir aber auch eben auf der Couch sitzend ein, als ich nochmal im Internet geblättert habe. Es gibt zu diesem Thema dort eine Menge Unsinn geschrieben, aber an einigen Stellen springt einen das HTTP förmlich an.

      Nun funktionierts.

      Wenn es morgen wieder regnet, werde ich das Skriptlein und das Drumherum mal aufräumen und zu einem kleinen Artikel für @Matthias Scharwies bzw. unser Wiki verarbeiten. Ich bin extra drei Tage früher nach Hause gekommen, um das alte Holz vom Dach endlich von meinem Hinterhof zu entfernen (muss ich immer ca. 20m den Berg rauftragen bis zur Straße). Aber wenn es regnet und der PC ruft, ist das ein guter Grund, sich nochmal zu drücken ;-)

      Jetzt bleibt nur noch die Frage, ob es geschickt ist, ganze Dateiinhalte (Megabytes) per application/x-www-form-urlencoded zum Server zu schaffen, oder ob man dafür doch besser multipart/form-data benutzen sollte?

      Glück Auf
      Tom vom Berg

      --
      Es gibt nichts Gutes, außer man tut es!
      Das Leben selbst ist der Sinn.
      1. Jetzt bleibt nur noch die Frage, ob es geschickt ist, ganze Dateiinhalte (Megabytes) per application/x-www-form-urlencoded zum Server zu schaffen,

        Ganz bestimmt nicht mit diesem Enctype.

        oder ob man dafür doch besser multipart/form-data benutzen sollte?

        Selbstverständlich damit. Diesen Content-Type kannst Du auch mit PHP erzeugen. MFG

      2. Tach!

        Jetzt bleibt nur noch die Frage, ob es geschickt ist, ganze Dateiinhalte (Megabytes) per application/x-www-form-urlencoded zum Server zu schaffen, oder ob man dafür doch besser multipart/form-data benutzen sollte?

        Übertragen werden müssen die Daten ja wohl auf jeden Fall. Was sind die Eigenschaften der beiden Typen?

        application/x-www-form-urlencoded überträgt alles als lange String-Wurst key=value&key=value. Alles was kein alphanumerisches Zeichen ist, muss prozentkodiert werden. Das geht bei Binärdaten sehr auf die zu übertragende Menge. Nicht wesentlich besser wird die Sache, wenn Komprimierung eingesetzt wird. Am Server muss auf alle Fälle alles %XX-Zeug wieder rausgeparst werden. Diese Methode kann man bei den geplanten Datenmengen lediglich für Text-Inhalt oder Base64-kodierte Daten ohne gravierende Nachteile nehmen. Base64 braucht dann aber auch wieder einer Dekodiervorgang. - Außerdem belegt PHP belegt noch viel Speicher, weil es dir die Daten in $_POST übergibt, also im Memory.

        multipart/form-data hingegen kann Daten auch ohne weiteres binär transportieren. Damit enfällt das Kodieren auf Senderseite und das Dekodieren auf Empfängerseite. Der Empfangsprozess muss lediglich nach der Boundary Ausschau halten. Zudem schreibt dir der Webserver eine Datei und schont so den Arbeitsspeicher.

        dedlfix.

        1. Hello,

          multipart/form-data hingegen kann Daten auch ohne weiteres binär transportieren. Damit enfällt das Kodieren auf Senderseite und das Dekodieren auf Empfängerseite. Der Empfangsprozess muss lediglich nach der Boundary Ausschau halten. Zudem schreibt dir der Webserver eine Datei und schont so den Arbeitsspeicher.

          Das ist aber ein Spiel mit dem Feuer. Im binären Strom könnte durchaus zufällig die Bytefolge einer Boundary versteckt sein.

          In wieweit unterscheiden sich Base64 und Urlencoding im Deflationesverhältnis? Wie rechne ich das aus?

          Die Übertragungsart "multipart/form-data" werde ich als Option aber auch noch einbauen.

          welcher Portbereich?

          Welchen Portbereich sollte ich für die freie Portwahl wählen?

          Glück Auf
          Tom vom Berg

          --
          Es gibt nichts Gutes, außer man tut es!
          Das Leben selbst ist der Sinn.
          1. Tach!

            multipart/form-data hingegen kann Daten auch ohne weiteres binär transportieren. Damit enfällt das Kodieren auf Senderseite und das Dekodieren auf Empfängerseite. Der Empfangsprozess muss lediglich nach der Boundary Ausschau halten. Zudem schreibt dir der Webserver eine Datei und schont so den Arbeitsspeicher.

            Das ist aber ein Spiel mit dem Feuer. Im binären Strom könnte durchaus zufällig die Bytefolge einer Boundary versteckt sein.

            Nein, kann nicht, weil das deiner Verantwortung unterliegt, die Boundary so zu wählen, dass kein Konflikt entsteht, sagt die RFC. Also vorher testen, ob die Boundary in den Daten vorkommt und zur Not eine andere erzeugen.

            In wieweit unterscheiden sich Base64 und Urlencoding im Deflationesverhältnis? Wie rechne ich das aus?

            Nicht gescheit. Base64 benötigt ja durchgehend 4 Bytes für 3, Prozent-Kodierung lässt aber alle Buchstaben (plus ein wenig mehr) unverändert durch. Dafür braucht es dann aber auch 3 Byte pro Byte für alles andere. Das wird bei Binärkrams wohl meistens zugunsten von Base64 ausfallen.

            dedlfix.

            1. Hello Dedlfix,

              Das ist aber ein Spiel mit dem Feuer. Im binären Strom könnte durchaus zufällig die Bytefolge einer Boundary versteckt sein.

              Nein, kann nicht, weil das deiner Verantwortung unterliegt, die Boundary so zu wählen, dass kein Konflikt entsteht, sagt die RFC. Also vorher testen, ob die Boundary in den Daten vorkommt und zur Not eine andere erzeugen.

              Das wäre eine Idee. Wenn ich das richtig in Erinnerung habe, gibt es aber immer nur eine Boundary für alle Parts, oder irre ich mich da?

              Glück Auf
              Tom vom Berg

              --
              Es gibt nichts Gutes, außer man tut es!
              Das Leben selbst ist der Sinn.
              1. Tach!

                Wenn ich das richtig in Erinnerung habe, gibt es aber immer nur eine Boundary für alle Parts, oder irre ich mich da?

                "Boundary" ist ein Parameter von multipart/form-data. Da du diesen Content-Type nur einmal angibst, kannst du da also auch nur eine Boundary angeben.

                dedlfix.

          2. Hello,

            Das ist aber ein Spiel mit dem Feuer. Im binären Strom könnte durchaus zufällig die Bytefolge einer Boundary versteckt sein.

            Das ist richtig. Die Wahrscheinlichkeit ist jedoch gering. Browser jedenfalls und auch JS FormData erzeugen die Boundary als Zufallsstring.

            Die Übertragungsart "multipart/form-data" werde ich als Option aber auch noch einbauen.

            Immerhin ist dafür serverseitig alles schon vorhanden was zum Parsen/Datenwiederherstellung benötigt wird.

            MFG

            PS: Schau Dir mal PUT an. Da wird der Dateiname im URL und die Datei selbst im Messagebody übertragen. Das kannst Du auch modifizieren, also Dateiname und weitere Parameter an den URL anhängen oder in eigenen HTTP Headers. Der Binärstream/Datei wird serverseitig ganz einfach aus STDIN gelesen.

            1. Tach!

              PS: Schau Dir mal PUT an. Da wird der Dateiname im URL und die Datei selbst im Messagebody übertragen. Das kannst Du auch modifizieren, also Dateiname und weitere Parameter an den URL anhängen oder in eigenen HTTP Headers. Der Binärstream/Datei wird serverseitig ganz einfach aus STDIN gelesen.

              Du schreibst das so, also ob PUT für Dateiübertragungen geschaffen worden wäre. Seine Aufgabe ist jedoch ganz allgemeiner Art, Daten anzulegen oder zu ändern. Dabei müssen aber Folgerequests immer dasselbe Ergebnis haben. Das heißt, das entspricht einem Edit, das immer wieder in denselben Datensatz schreibt ihn bei Bedarf aber auch anlegt, und keinem Create, welches mit jedem Request neue Datensätze erzeugt. Wenn mit derselben URL und PUT immer wieder neue Daten/Dateien erzeugt werden, ist das eine Verwendung abseits der Intention. Wenn man also beispielsweise immer wieder neue Wetterdaten zum Server senden möchte, und damit die Datensammlung erweitert wird, ist PUT nicht die vorgesehene Methode, sondern POST. Ein Szenario für PUT wäre hingegen, wenn lediglich die neuesten Daten verwaltet werden sollen, also wenn mit jedem Request immer derselbe oder dieselben Datensätze für die aktuellen Wetterdaten überschrieben werden, ohne weitere Daten für zum Beispiel eine Historie abzulegen.

              Das PHP-Handbuch schreibt etwas zu File-Uploads mit PUT. Verglichen mit dem herkömmlichen POST (abgesehen von obiger Problematik) ist PUT-Fileupload jedenfalls nicht "ganz einfach". Man muss hier selbst mit Dateisystemfunktionen öffnen, kopieren und schließen, statt dem einfachen Aufruf von move_uploaded_file() bei POST - zumindest wenn man die Datei ohne weitere Verarbeitung am Stück ablegen möchte.

              dedlfix.

              1. Verglichen mit dem herkömmlichen POST (abgesehen von obiger Problematik) ist PUT-Fileupload jedenfalls nicht "ganz einfach".

                Das ist Quatsch. Gerade PUT macht die Sache extrem einfach, weil je Request eine Datei kommt: Messageboy == Dateiinhalt, das Parsen entfällt! Das kann man übrigens auch mit POST so machen und anstatt mit multipart/form-data den Server zu vergewaltigen, erzeugt jeder Upload einfach einen eigenen Serverprozess.

                Im Prinzip ist die Requestmethode auch egal, es kommt nur darauf an die Idee zu verstehen. MFG

                1. Tach!

                  Das kann man übrigens auch mit POST so machen und anstatt mit multipart/form-data den Server zu vergewaltigen, erzeugt jeder Upload einfach einen eigenen Serverprozess.

                  Das Nutzen von vorhandenen Mitteln ist Vergewaltigen? Warum ist das Hantieren mit Serverprozessen, das bisher nicht nötig war, kein solches?

                  Im Prinzip ist die Requestmethode auch egal, es kommt nur darauf an die Idee zu verstehen.

                  Es kommt auch darauf an, zu verstehen dass nicht jede Individuallösung auch derartig entscheidende Vorteile bringt, dass es sich lohnt, Entwicklungsaufwand in diese zu stecken, anstatt einfach das vorhandene Bewährte zu verwenden.

                  dedlfix.

                  1. Hello dedlfix,

                    Es kommt auch darauf an, zu verstehen dass nicht jede Individuallösung auch derartig entscheidende Vorteile bringt, dass es sich lohnt, Entwicklungsaufwand in diese zu stecken, anstatt einfach das vorhandene Bewährte zu verwenden.

                    Mir kommt es eher darauf an, die beiden gängigen Methoden so sicher in Funktionen zu verpacken, dass sie leicht verwendbar sind und man bei Fehlern qualifizierte Rückmeldungen erhält.

                    ##Was fehlt noch?

                    • den gesamten Portbereich von 1 bis 65535 zulassen?
                    • Cookies mitsenden?
                    • ...

                    Glück Auf
                    Tom vom Berg

                    --
                    Es gibt nichts Gutes, außer man tut es!
                    Das Leben selbst ist der Sinn.
                    1. Tach!

                      Es kommt auch darauf an, zu verstehen dass nicht jede Individuallösung auch derartig entscheidende Vorteile bringt, dass es sich lohnt, Entwicklungsaufwand in diese zu stecken, anstatt einfach das vorhandene Bewährte zu verwenden.

                      Mir kommt es eher darauf an, die beiden gängigen Methoden so sicher in Funktionen zu verpacken, dass sie leicht verwendbar sind und man bei Fehlern qualifizierte Rückmeldungen erhält.

                      Dann fällt vermutlich weg, den Server erst konfigurieren zu müssen, damit bestimmte HTTP-Verben auch beim richtigen PHP-Script ankommen, geschweige mit Prozessen zu jonglieren.

                      ##Was fehlt noch?

                      • den gesamten Portbereich von 1 bis 65535 zulassen?
                      • Cookies mitsenden?

                      Weiß ich nicht, ich kenne die Aufgabenstellung nicht.

                      Was soll mit der Portbereichbegrenzung erreicht/verhindert werden?

                      Cookies, für Session-IDs? Wäre sinnvoll. Es gibt aber auch noch andere Verfahren, Authentifizierungsinformationen mitzusenden. Ich würde lediglich eine generelle Möglichkeit schaffen, individuelle Header setzen zu können. Damit sind auch Cookies zumindest grundlegend erschlagen. Komfortables Handling von Cookies ist auch sicher nicht Kernaufgabe deiner Requesterstellung und deshalb eine Aufgabe für eine andere Komponente.

                      dedlfix.

                    2. Mir kommt es eher darauf an, die beiden gängigen Methoden so sicher in Funktionen zu verpacken, dass sie leicht verwendbar sind und man bei Fehlern qualifizierte Rückmeldungen erhält.

                      ##Was fehlt noch?

                      Die PHP-FIG hat für HTTP einen eigenen Standard: PSR-7: HTTP message interfaces. Implementierungen gibt es zu Hauf bei packagist. Die beliebteste Implementierung, gemessen an der Anzahl der Installationen, ist derzeit Guzzle. Vielleicht findest du da ja noch Inspiration für deine Library.

                      Dein Anfangs-Beispiel würde mit Guzzle etwa so aussehen:

                      $data = [
                         'eins' => 'erster Eintrag',
                         'zwei' => 'zweiter Eintrag',
                         'drei' => 'dritter Eintrag'
                      ];
                      
                      $client = new Client();
                      $response = $client->post('https://bitworks.de', ['form_data' => $data]);
                      echo $response->getBody();
                      
          3. Eon interessanter Content-Type ist übrigens application/tar. Da werden die Dateien einfach aneinandergehängt und für PHP gibts Libraries. Der serverseitige Parser in PHP kennt jedoch diesen Enctype nicht, da musst Du eine Erweiterung schreiben. Is aber auch kein Prolem. MFG

      3. Jetzt bleibt nur noch die Frage, ob es geschickt ist, ganze Dateiinhalte (Megabytes) per application/x-www-form-urlencoded zum Server zu schaffen, oder ob man dafür doch besser multipart/form-data benutzen sollte?

        Dem schließt sich die Frage an, ob es zumutbar ist, die Dateiinhalte komplett in den Hauptspeicher zu laden, oder ob es nicht besser wäre, die Inhalte zu streamen. Du experimentierst ja in letzter Zeit viel mit dem Raspberry Pi, der ja nur 1GB RAM hat, da könnte Streaming dann durchaus sinnvoll sein.

        1. Hello,

          Jetzt bleibt nur noch die Frage, ob es geschickt ist, ganze Dateiinhalte (Megabytes) per application/x-www-form-urlencoded zum Server zu schaffen, oder ob man dafür doch besser multipart/form-data benutzen sollte?

          Dem schließt sich die Frage an, ob es zumutbar ist, die Dateiinhalte komplett in den Hauptspeicher zu laden, oder ob es nicht besser wäre, die Inhalte zu streamen. Du experimentierst ja in letzter Zeit viel mit dem Raspberry Pi, der ja nur 1GB RAM hat, da könnte Streaming dann durchaus sinnvoll sein.

          Das ist wahr. Denn die nächste Aufgabe wäre dann ja die Übertragung von Kameradaten.

          Es wird also nicht langweilig ;-)

          Glück Auf
          Tom vom Berg

          --
          Es gibt nichts Gutes, außer man tut es!
          Das Leben selbst ist der Sinn.
        2. Jetzt bleibt nur noch die Frage, ob es geschickt ist, ganze Dateiinhalte (Megabytes) per application/x-www-form-urlencoded zum Server zu schaffen, oder ob man dafür doch besser multipart/form-data benutzen sollte?

          Dem schließt sich die Frage an, ob es zumutbar ist, die Dateiinhalte komplett in den Hauptspeicher zu laden, oder ob es nicht besser wäre, die Inhalte zu streamen. Du experimentierst ja in letzter Zeit viel mit dem Raspberry Pi, der ja nur 1GB RAM hat, da könnte Streaming dann durchaus sinnvoll sein.

          Genau! Deswegen ist ja PUT so interessant! CPU und RAM gefälliger gehts nicht: STDIN auf ein FileHandle umlegen, fertig. Kein Parsen, keine temporäreren Dateien. Und: Jede Datei bekommt einen eigenen Serverprozess. MFG

  3. Status 400 kann viele Ursachen haben. Und auch solche die sich nicht im error_log wiederfinden. Aber wenn Du schon die Credentials für ein Auth.Basic hast, dann sicher auch eine akkurate Beschreibung für die API welche Du zu bedienen gedenkst.

    Mit den von Dir gezeigten Enctypes ist es auf jeden Fall möglich, diesen POST mit einem Browser auszuführen. Und wenn das geklappt hat, dann baust Du den Request 1:1 mit PHP nach. MFG

  4. Hello,

    ##Zwischenstand 30.05.2019:

    <?php   ### function_post2host.php ###
    
    function PostToHost($host,$path,$data,$ssl=FALSE,$autoport=TRUE,$user=FALSE,$pass=FALSE,$referer=FALSE)
    {
        //Daten anpassen
        if(is_array($data))
    	{
    		$data_to_send = '';
    		foreach($data as $name => $var)
    	    {
                $data_to_send .= urlencode($name) . '=' . urlencode($var) . '&';
            }
            $data_to_send = rtrim($data_to_send, '&');
        }
        else $data_to_send = 'data=' . urlencode($data);
      
    	//SSL einbinden, falls gewünscht
    
    	if($ssl === TRUE)
    	{
    		$port = 443;
    		$target = 'ssl://' . $host;
    	}
    	else
    	{
    		$port = 80; 
    		$target = $host;	
    	}
    
    	if ($autoport === TRUE) 
    	{
    		### alter nothing;
    	}
    	elseif (is_numeric($autoport) && (0 < $autoport) && ($autoport < 65536))
    	{
    		$port = $autoport;
    	}
        else {return false;}
    	  
    	//Verbindung öffnen
    	if (false === ($fp = fsockopen($target, $port, $errno, $errstr, 30)))
    	{ 
    		return false;
    	}	
      
    	stream_set_timeout($fp, 30);
      
    	//Header erzeugen
    	fputs($fp,"POST " . $path . " HTTP/1.1\r\n");    
    	fputs($fp,"Host: " . $host . "\r\n");
      
    	if(($user !== FALSE) && ($pass !== FALSE)) 
    	{
    		fputs($fp, "Authorization: Basic " . base64_encode($user.":".$pass)."\r\n");
    	}
      
    	if (FALSE !== $referer) 
    	{
    		fputs($fp, "Referer: " . urlencode($referer) . "\r\n");
    	}
    	fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
    	fputs($fp, "Content-length: " . strlen($data_to_send) . "\r\n");
    	fputs($fp, "Connection: close\r\n\r\n");
    	fputs($fp, $data_to_send);
      
    	//Antwort abfangen
        $res = '';
    	while(!feof($fp)) 
    	{
    		$res .= fgets($fp, 128);
    	}
    	
    	//Verbindung schliessen
    	fclose($fp);
    	
    	//Antwort zurückgeben
    	return $res;
    }
    
    ###============================================================================
    #
    # PostToHost($host,$path,$data,$ssl=FALSE,$autoport=TRUE,$user=FALSE,$pass=FALSE,$referer=FALSE)
    
    $_data = array();
    $_data ['eins'] = 'erster Eintrag';
    $_data ['zwei'] = 'zweiter Eintrag';
    $_data ['drei'] = 'dritter Eintrag';
    
    echo "<pre>\r\n";
    echo PostToHost("bitworks.de", '/sensor/postresponder.php', $_data, TRUE);
    echo "</pre>\r\n";
    
    ?>
    

    Es fehlen noch Cookies bzw. Additional Headers.

    Die Übertragung per "multipart/form-data" bedarf wohl eher einer eigenständigen Funktion, da hierfür z. B. noch umfangreiche Regeln für den Aufbau der Part-Header sowie Übergabe der Parameter dafür und deren Plausiplitätskontrolle ermittelt werden müssen (z. B. für Fileupload, Kontrolle der Boundary, usw.).

    Glück Auf
    Tom vom Berg

    --
    Es gibt nichts Gutes, außer man tut es!
    Das Leben selbst ist der Sinn.
    1. Es fehlen noch Cookies bzw. Additional Headers.
      Die Übertragung per "multipart/form-data" bedarf wohl eher einer eigenständigen Funktion, da hierfür z. B. noch umfangreiche Regeln für den Aufbau der Part-Header sowie Übergabe der Parameter dafür und deren Plausiplitätskontrolle ermittelt werden müssen (z. B. für Fileupload, Kontrolle der Boundary, usw.).

      Ich mache jetzt mal einen auf "pl" und antworte mit Perl. Cookies & Co lassen sich ähnlich komfortabel reinpacken:

      use HTTP::Request::Common;
      use LWP::UserAgent;
      my $ua = LWP::UserAgent->new;
      my $filename = '/tmp/kitten.jpg';
      my $req = $ua->request(
      	POST 'https://example.org/',
      	Content_Type => 'multipart/form-data',
      	Content => [
      		'file' => [$filename]
      	]
      );
      

      Mit Sicherheit gibt es ein Äquivalent in PHP.

      1. Hello,

        Es fehlen noch Cookies bzw. Additional Headers.
        Die Übertragung per "multipart/form-data" bedarf wohl eher einer eigenständigen Funktion, da hierfür z. B. noch umfangreiche Regeln für den Aufbau der Part-Header sowie Übergabe der Parameter dafür und deren Plausiplitätskontrolle ermittelt werden müssen (z. B. für Fileupload, Kontrolle der Boundary, usw.).

        Ich mache jetzt mal einen auf "pl" und antworte mit Perl. Cookies & Co lassen sich ähnlich komfortabel reinpacken:

        use HTTP::Request::Common;
        use LWP::UserAgent;
        my $ua = LWP::UserAgent->new;
        my $filename = '/tmp/kitten.jpg';
        my $req = $ua->request(
        	POST 'https://example.org/',
        	Content_Type => 'multipart/form-data',
        	Content => [
        		'file' => [$filename]
        	]
        );
        

        Mit Sicherheit gibt es ein Äquivalent in PHP.

        Wie das mit PHP funktioniert, weiß ich wohl.
        Da kann man aber durch etliche verschiedene Header noch einiges steuern. Deshalb will ich das nicht einfach hier in diese Funktion reinklatschen. Die wird nämlich dann unbenutzbar, weil total unübersichtlich.

        Glück Auf
        Tom vom Berg

        --
        Es gibt nichts Gutes, außer man tut es!
        Das Leben selbst ist der Sinn.
        1. Wie das mit PHP funktioniert, weiß ich wohl.
          Da kann man aber durch etliche verschiedene Header noch einiges steuern. Deshalb will ich das nicht einfach hier in diese Funktion reinklatschen. Die wird nämlich dann unbenutzbar, weil total unübersichtlich.

          Ja! Deshalb baut man sowas auch lieber selber, statt auf Standardbibliotheken zu setzen!

          1. Hello,

            Wie das mit PHP funktioniert, weiß ich wohl.
            Da kann man aber durch etliche verschiedene Header noch einiges steuern. Deshalb will ich das nicht einfach hier in diese Funktion reinklatschen. Die wird nämlich dann unbenutzbar, weil total unübersichtlich.

            Ja! Deshalb baut man sowas auch lieber selber, statt auf Standardbibliotheken zu setzen!

            ?

            Glück Auf
            Tom vom Berg

            --
            Es gibt nichts Gutes, außer man tut es!
            Das Leben selbst ist der Sinn.
      2. use HTTP::Request::Common;
        use LWP::UserAgent;
        my $ua = LWP::UserAgent->new;
        my $filename = '/tmp/kitten.jpg';
        my $req = $ua->request(
        	POST 'https://example.org/',
        	Content_Type => 'multipart/form-data',
        	Content => [
        		'file' => [$filename]
        	]
        );
        

        Mit Sicherheit gibt es ein Äquivalent in PHP.

        Zum Beispiel Guzzle:

        $file = '/tmp/kitten.jpg';
        $client = new Client();
        $response = $client->post(
            'https://example.com',
            'multipart' => [
                [
                    'name'     => basename($file),
                    'contents' => fopen($file, 'r')
                ]
            ]
        );
        
        1. Zum Beispiel Guzzle:

          Das ist zu einfach. Dann wird es nämlich nicht unbenutzbar, weil total unübersichtlich.

        2. Hello,

          use HTTP::Request::Common;
          use LWP::UserAgent;
          my $ua = LWP::UserAgent->new;
          my $filename = '/tmp/kitten.jpg';
          my $req = $ua->request(
          	POST 'https://example.org/',
          	Content_Type => 'multipart/form-data',
          	Content => [
          		'file' => [$filename]
          	]
          );
          

          Mit Sicherheit gibt es ein Äquivalent in PHP.

          Zum Beispiel Guzzle:

          $file = '/tmp/kitten.jpg';
          $client = new Client();
          $response = $client->post(
              'https://example.com',
              'multipart' => [
                  [
                      'name'     => basename($file),
                      'contents' => fopen($file, 'r')
                  ]
              ]
          );
          

          Die Bedienung der Schnittstelle (Funktionsargumente) sieht übersichtlich aus. Ich bin gespannt auf den Code und das Fehlerverhalten/Rückmeldungen...

          Glück Auf
          Tom vom Berg

          --
          Es gibt nichts Gutes, außer man tut es!
          Das Leben selbst ist der Sinn.
          1. Die Bedienung der Schnittstelle (Funktionsargumente) sieht übersichtlich aus. Ich bin gespannt auf den Code und das Fehlerverhalten/Rückmeldungen...

            Den Quelltext kannst du auf Github nachlesen. Jenachdem ob die API synchron oder asynchron benutzt, gibt es verschiedene Fehlerbehandlungs-Mechanismen. Bei der synchronen Variante, werden Exceptions geworfen, bei der asynchronen Verwendung werden Promises rejected. Welche Fehler wo erzeugt werden, kannst du sehen, indem du das Repository bei Github nach throw bzw. nach rejection durchsuchst. Außerdem findest du im Ordner src/Exception diverse Guzzle-spezfische Exceptions.

            1. Hello,

              danks für den Tipp.

              Schießt zwar für die Simpellösung übers Ziel hinaus, aber liest sich sehr interessant. Nur nicht in fünf Minuten :-O

              Glück Auf
              Tom vom Berg

              --
              Es gibt nichts Gutes, außer man tut es!
              Das Leben selbst ist der Sinn.
      3. Na wenn schon Perl dann richtig:

        use HTTPsRequest;
        
        HTTPsRequest->common(
          host    => 'example.com',
          method  => 'PUT',
          uri     => '/ws.html?file=mesg.txt;size=1024',
          content => file_get_content('mesg.txt')
        );
        

        MFG

        1. Hello,

          Na wenn schon Perl dann richtig:

          use HTTPsRequest;
          
          HTTPsRequest->common(
            host    => 'example.com',
            method  => 'PUT',
            uri     => '/ws.html?file=mesg.txt;size=1024',
            content => file_get_content('mesg.txt')
          );
          

          Soweot mir das im Gedächtnis ist (von PHP 5.x) hat PHP für PUT serienmäßig keinen Handler. Den müsste man erst einrichten. Vielleicht magst Du ja mal recherchieren, ob es schon fertige Lösungen gibt.

          Glück Auf
          Tom vom Berg

          --
          Es gibt nichts Gutes, außer man tut es!
          Das Leben selbst ist der Sinn.
          1. Tach!

            Soweot mir das im Gedächtnis ist (von PHP 5.x) hat PHP für PUT serienmäßig keinen Handler. Den müsste man erst einrichten. Vielleicht magst Du ja mal recherchieren, ob es schon fertige Lösungen gibt.

            Vergiss das mit dem PUT, warum auch immer pl denkt, PUT sei die Methode für Dateiübertragungen. POST hat keine Nachteile und funktioniert ohne Verrenkungen.

            dedlfix.

          2. Hi Tom,

            Die Requestmethode ist doch völlig egal, lass Dich davon nicht verwirren. Wesentlich ist: Sofern ein Messagebody gesendet wurde, gibt es einen Requestheader Content-Length und das heißt, daß Daten aus STDIN zu lesen sind. Was mit PHP selbstverständlich auch möglich ist.

            Und sobald es, unabhängig von der Requestmethode, einen QUERY_STRING gibt, parst PHP die Daten und stellt diese Parameter in $_GET bereit.

            Also, PUT in PHP verarbeiten: Gemäß Content-Length wird STDIN gelesen (hier ist die Datei die in das Socket geschrieben wurde) und in $_GET stehen die dazugehörigen Parameter (falls gesendet). Einfacher gehts nicht. MFG

            1. Tach!

              Die Requestmethode ist doch völlig egal, lass Dich davon nicht verwirren.

              Requestmethoden sind nicht einfach nur da, um da zu sein. Sie haben ihren Sinn. Lieber nicht von pls Perl- plus persönliche Vorgehensweise verwirren lassen.

              Wesentlich ist:

              PHP hat seit langem einen bewährten Weg, mit Dateiuplods empfangsseitig umzugehen. Es gibt keine Notwendigkeit, das nicht zu verwenden. Zumindest kann ich nicht erkennen, warum du, TS, dir hier Gedanken machst. Ist es, weil du den Request, warum auch immer, zu Fuß erstellen möchtest? Die Methoden zum Senden sind ebenfalls altbekannt und gut abgehangen. Es gibt Bibliotheken, die bereits ausreichend Energie in das Thema gesteckt haben.

              dedlfix.

              1. PHP hat seit langem einen bewährten Weg, mit Dateiuplods empfangsseitig umzugehen.

                Genau!

                1. Tach!

                  PHP hat seit langem einen bewährten Weg, mit Dateiuplods empfangsseitig umzugehen.

                  Genau!

                  Nein, das ist nicht der PHP-Weg, den ich meinte, sondern POST method uploads.

                  dedlfix.

              2. Hello,

                PHP hat seit langem einen bewährten Weg, mit Dateiuplods empfangsseitig umzugehen. Es gibt keine Notwendigkeit, das nicht zu verwenden. Zumindest kann ich nicht erkennen, warum du, TS, dir hier Gedanken machst. Ist es, weil du den Request, warum auch immer, zu Fuß erstellen möchtest? Die Methoden zum Senden sind ebenfalls altbekannt und gut abgehangen. Es gibt Bibliotheken, die bereits ausreichend Energie in das Thema gesteckt haben.

                Bibliotheken sind meistens einige Megabytes groß und müssen i.d.R. bei jedem Request vollständiv geladen werden.

                Mir geht es darum

                • Verständnis zu schaffen für die wesentliche Methode/Funktion
                • die schlankste Möglickkeit (Stand Alone Function) bei voller Fehlerkontrolle zu finden

                Dass man dann intelligente Bibliotheken bauen kann, hat @1unitedpower ja schon mit dem Hinweis auf guzzle erwähnt. Aber alleine das Kundigmachen über die Schnittstelle und das Verifizieren der Funktionsweise dauert schon Tage.

                Glück Auf
                Tom vom Berg

                --
                Es gibt nichts Gutes, außer man tut es!
                Das Leben selbst ist der Sinn.
                1. Tach!

                  Bibliotheken sind meistens einige Megabytes groß und müssen i.d.R. bei jedem Request vollständiv geladen werden.

                  Pauschale Verdächtigungne bringen dich nicht zur Wahrheit. Heutzutage bemüht man sich, die Includes über Autoloader zu organisieren, und die Dateien nicht zu überfrachten, so dass lediglich die Dateien geladen werden, die wirklich für den Request benötigt werden.

                  dedlfix.

                  1. Hello,

                    Bibliotheken sind meistens einige Megabytes groß und müssen i.d.R. bei jedem Request vollständiv geladen werden.

                    Pauschale Verdächtigungne bringen dich nicht zur Wahrheit. Heutzutage bemüht man sich, die Includes über Autoloader zu organisieren, und die Dateien nicht zu überfrachten, so dass lediglich die Dateien geladen werden, die wirklich für den Request benötigt werden.

                    Das mag wohl sein. Aber:

                    • die Fragmente (Klassen) sind immer noch größer, als eine einzelne Funktion
                    • das Nachladen erfodert Ladezeit von typisch 8 bis 15 ms pro Klasse. Nicht alle Server haben schon SSDs oder unbegrenzt Cache.

                    "Keep it small" ist deshalb mMn immer noch nicht obsolete.

                    Glück Auf
                    Tom vom Berg

                    --
                    Es gibt nichts Gutes, außer man tut es!
                    Das Leben selbst ist der Sinn.
                    1. Tach!

                      • die Fragmente (Klassen) sind immer noch größer, als eine einzelne Funktion

                      Ja, mag sein, aber wenn du deine Funktionen alle in eine Datei wirfst und die komplett laden musst, muss man schon wieder genauer hinsehen, was sich am Ende ergibt. Nur zu spekulieren, ist keine verlässliche Vorgehensweise. Andererseits kann man sich auch sagen, dass der Aufwand, den Unterschied herauszufinden die eingesparte Zeit nicht wert ist, und erst dann anfangen zu optimieren, wenn Probleme spürbar werden.

                      • das Nachladen erfodert Ladezeit von typisch 8 bis 15 ms pro Klasse. Nicht alle Server haben schon SSDs oder unbegrenzt Cache.

                      "Keep it small" ist deshalb mMn immer noch nicht obsolete.

                      Das ist ein durchaus valider Punkt. Nur bringt es auch nichts, sich immer nur am Minimum zu orientieren. Effizient arbeiten zu können, ist auch wichtig. Nicht umsonst nimmst du ja PHP als Hochsprache, das alles andere als effizient ist, verglichen mit hardwarenäheren Sprachen oder Maschinencode. Diese Entscheidung kann man nicht immer zugunsten der Minimalität und zu ungunsten des eigenen Aufwands treffen.

                      dedlfix.

                    2. Bibliotheken sind meistens einige Megabytes groß und müssen i.d.R. bei jedem Request vollständiv geladen werden.

                      Mal abgesehen davon, dass ich den ersten Teil deiner Aussage stark anzweifle: 1MB PHP-Quelltext sind in der Opcode-Repräsentation schon deutlich weniger Masse, außerdem bringt PHP seit Jahren einen Opcode-Cache mit, dadurch kann man sich das Parsen und die Opcode-Generierung pro Request sparen. Die Arbeit fällt dann nur einmal beim Cache-Warmup an.

                      • die Fragmente (Klassen) sind immer noch größer, als eine einzelne Funktion
                      • das Nachladen erfodert Ladezeit von typisch 8 bis 15 ms pro Klasse. Nicht alle Server haben schon SSDs oder unbegrenzt Cache.

                      "Keep it small" ist deshalb mMn immer noch nicht obsolete.

                      Das ist Micro-Management. Wenn es dir wirklich auf Performance und Ressourcen-Sparsamkeit ankommt, solltest du erst recht eine fertige Library benutzen. Guzzle bietet sehr durchdachte Optimierungen an, wenn du die auch noch implementieren möchtest, wächst deine Funktion zu einem unbezwingbaren Spaghetti-Monster an. Ein Beispiel habe ich schon angeführt: Deine Funktion erwartet, dass die hochzuladende Datei, komplett in den Hauptspeicher geladen wird. Bei einer 1GB großen Datei, wird also auch 1GB Arbeitsspeicher belegt, wenn das PHP-Memory-Limit vorher nicht erreicht ist und der Prozess unfreiwillig beendet werden muss. Guzzle unterstützt Streaming, d.h. die Datei wird stückweise gelesen und in den Ausgabe-Stream geschrieben. Außerdem unterstützt Guzzle asynchrone Requests, das heißt man muss sie nicht streng sequentiell versenden und auf die Antwort warten, so wie in deiner Funktion, sondern kann sie konkurrierend verschicken.

                      Ich möchte dir garnicht ausreden, deine Vorgehensweise weiter zu verfolgen, aber das Effizienz-Argument ist nicht haltbar.

          3. Hi Tom;

            guck mal:

            PUT /getpost.php?file=asdf&size=123 HTTP/1.0
            Connection: Close
            Content-Length: 4
            Content-Type: application/octet-stream
            Host: rolfrost
            
            asdf
            =================================================================
            HTTP/1.1 200 OK
            Date: Sun, 02 Jun 2019 06:57:55 GMT
            Server: Apache/2.2.14 (Win32) PHP/5.3.0
            X-Powered-By: PHP/5.3.0
            Content-Length: 57
            Connection: close
            Content-Type: text/plain;charset=UTF-8
            
            Array
            (
                [file] => asdf
                [size] => 123
            )
            BODY:
            asdf
            

            Das ist Request/Response. Serverseitig hab ich (getpost.php):

            <?php
            header("Content-Type: text/plain");
            
            print_r($_GET);
            
            echo "BODY:\n";
            echo file_get_contents("php://input");
            

            Also kein Problem an die Daten zu kommen. Einfacher gehts wirklich nicht. MFG

            PS: Anstatt asdf kannst beliebige Dateiinhalte senden.

            1. Untenstehender Code funktioniert. Request PHP:

              $host = "example";
              $port = 80;
              $file = "d:/tmp/red.gif";
              $content = file_get_contents($file);
              $url = sprintf("%s?filename=%s", "/getpost.php", urlencode(basename($file)));
              
              $len = strlen($content);
              $socket = fsockopen($host, $port);
              fputs($socket,"PUT $url HTTP/1.0\n");
              fputs($socket,"Content-Length: $len\n");
              fputs($socket, "Host: $host\n\n");
              fputs($socket, $content);
              
              # Response ausgeben
              while(!feof($socket)) {
                  echo fgets($socket, 128);
              }
              

              Serverseitig PHP:

              header("Content-Type: text/plain");
              echo "Anzahl Bytes gesendet: ", $_SERVER{'CONTENT_LENGTH'}, "\n\n";
              
              print_r($_GET);
              $body = file_get_contents("php://input");
              echo "BODY:\n", $body;
              
              
              # Datei probeweise anlegen
              $filename = $_GET['filename'];
              $fp = fopen("d:/tmp/upload/$filename", "wb");
              fputs($fp, $body);
              

              (Ohne Fehlerbehandlung, ohne Auth.Baisc)

              PS: Alternative RequestMethod: fputs($socket,"Zitrone $url HTTP/1.0\n");

              1. Hello,

                welche PHP-Version auf welcher Plattform?

                Glück Auf
                Tom vom Berg

                --
                Es gibt nichts Gutes, außer man tut es!
                Das Leben selbst ist der Sinn.
                1. 5.3.0 auf Win32

                  und im Log des Apache findet sich:

                  127.0.0.1 - - [02/Jun/2019:10:31:45 +0200] "Zitrone /getpost.php?filename=red.gif HTTP/1.0" 200 592

                  Wie bereits angemerkt, die Requestmethode ist völlig Wurst.

                  MFG

                  1. Hello,

                    5.3.0 auf Win32

                    und im Log des Apache findet sich:

                    127.0.0.1 - - [02/Jun/2019:10:31:45 +0200] "Zitrone /getpost.php?filename=red.gif HTTP/1.0" 200 592

                    Wie bereits angemerkt, die Requestmethode ist völlig Wurst.

                    Nur dann, wen man jegliche Schichtgrenzen missachtet.

                    Du beförderst durch deine Votgehensweise alle Programmschritte tegelwidrig eine Schicht tiefer. Sowas wird im Zusammenspiel mit mehr Umgebung ggf. schwer handhabbar.

                    Glück Auf
                    Tom vom Berg

                    --
                    Es gibt nichts Gutes, außer man tut es!
                    Das Leben selbst ist der Sinn.
                    1. Du beförderst durch deine Votgehensweise alle Programmschritte tegelwidrig eine Schicht tiefer.

                      Nein. Vielmehr ist es PHP was die Regeln missachtet. Z.B. dadurch, daß sich in $_GET Daten befinden obwohl die Requestmethode eine ganz Andere ist.

                      Und dann ist es auch so, daß das Vorhandensein eines MesageBody nicht von der Requestmethode abhängt sondern vom Header Content-Length. Das Kannst Du in RFC nachlesen.

                      Grundsätzlich ist es nunmal so, daß PHPs $_GET Daten hat, wenn es einen QUERY_STRING gibt. Und ein Solcher ist bekanntlich von der Requestmethode unabhängig. Daß das Array $_GET nun heißt ist nicht gerade eine zweckmäßige Wahl für diesen Namen. Zumal dadurch der Layer in die Anwendung verschleppt wird.

                      Wie auch immer, mit meinem gezeigten Code wird der Layer transparent, von der Namensgebung $_GET abgesehen. Aber Du kannst Dich auch davon trennen indem Du einen eigenenen Parser für den QUERY_STRING schreibst, das ist überhaupt kein Problem, urldecode() gibt es und wo Du splitten musst, ist auch klar.

                      Es kommt immer darauf an, die Idee zu verstehen! Ein transparenter Layer heißt: Der Name der Requestmethode kommt in der Anwendung gar nicht vor. Ebensowenig HTTP//HTTPS.

                      MFG

                      1. Tach!

                        Vielmehr ist es PHP was die Regeln missachtet. Z.B. dadurch, daß sich in $_GET Daten befinden obwohl die Requestmethode eine ganz Andere ist.

                        Grundsätzlich ist es nunmal so, daß PHPs $_GET Daten hat, wenn es einen QUERY_STRING gibt. Und ein Solcher ist bekanntlich von der Requestmethode unabhängig. Daß das Array $_GET nun heißt ist nicht gerade eine zweckmäßige Wahl für diesen Namen.

                        $_GET ist ein Name. Welche Regel besagt, dass der korrekt sein muss? Oder dass sich Querystring-Daten nicht in $_GET befinden dürfen?

                        Aber Du kannst Dich auch davon trennen indem Du einen eigenenen Parser für den QUERY_STRING schreibst, das ist überhaupt kein Problem, urldecode() gibt es und wo Du splitten musst, ist auch klar.

                        Der Sinn dahinter ist konkret welcher? parse_url() und parse_str() gibt es ebenfalls, wenn man den Automatismus namens $_GET nicht nutzen möchte.

                        dedlfix.

                        1. Eine Abstraktion könnte so aussehen, daß es eine Methode param() gibt, die unabhängig von der Requestmethode den oder die Werte zu einem namentlich genannten Parameter liefert.

                          Und damit ein Parser diesen Komfort bieten kann, wird der Requestheader Content-Type betrachtet. Meine Erweiterung in Perl sieht so aus, daß für den hier vorgstellten Webservice der Content-Type: application/body+query gesendet wird.

                          Der hierzu relevante Teil der Kontrollstruktur im Parser:

                              elsif( $self->{CONTENT_TYPE} eq 'application/body+query' ){
                                  # QUERY_STRING mit Parametern + Message Body mit Binary
                                  $self->{param} = $self->qparse($self->{QUERY_STRING});
                              }
                          

                          Und so hat man den Transportlayer samt seiner Requestmethoden vollständig aus der Anwendung raus. Diese Philosophie wurde und wird in Perl schon immer gelebt. Hat sich ja auch bewährt, aber sowas von! MFG

                  2. Hallo,

                    5.3.0 auf Win32

                    never change a running system 😎

                    Gruß
                    Jürgen

                    1. Nun, mit der Abwärtskompatiblität in PHP sieht es schon recht bescheiden aus. Aber was gehts mich an, ich muss das nicht mehr mitmachen. Der Preis für meine Erwerbsunfähigkeit war hoch genug.

        2. Na wenn schon Perl dann richtig:

          use HTTPsRequest;
          

          Can't locate HTTPsRequest.pm in @INC (you may need to install the HTTPsRequest module)

          1. Na wenn schon Perl dann richtig:

            use HTTPsRequest;
            

            Can't locate HTTPsRequest.pm in @INC (you may need to install the HTTPsRequest module)

            Das Modul ist eine eigene Entwicklung. Es macht genau das, was Tom mit PHP machen will: Einen HTTP Request in ein Socket schreiben. In Perl ist das IO::Socket::SSL. Ein bischen kniffelig ist es, eine chunked Response wieder zusammenzuflicken, aber ansonsten ist das alles auch kein Hexenwerk: HTTP zu Fuß halt.

            Als Alternative zur LibWWW wo man 'zig Instanzen erstellen muss um einen Request feuern zu können, geht das mit meinem Modul über einen einzigen Funktionsaufruf. MFG

            1. Na wenn schon Perl dann richtig:

              use HTTPsRequest;
              

              Can't locate HTTPsRequest.pm in @INC (you may need to install the HTTPsRequest module)

              Das Modul ist eine eigene Entwicklung.

              Das macht die Beurteilung Deines Statements "Na wenn schon Perl dann richtig" (für alle außer Dir) dann eher schwierig 😉

    2. Tach!

      Es fehlen noch Cookies bzw. Additional Headers.

      Spricht eigentlich etwas dagegen, PHPs Stream-Context zu verwenden, statt den Request selbst zusammenzubauen? Du musst ja bei deiner Vorgehensweise für jeden möglichen Header einen neuen Parameter zur Funktion hinzufügen, und beim Verwenden die Reihenfolge beachten und für nicht benötigte einen Ersatz (null) übergeben. Zudem ist man auf genau diese Parameter beschränkt.

      Die Übertragung per "multipart/form-data" bedarf wohl eher einer eigenständigen Funktion, da hierfür z. B. noch umfangreiche Regeln für den Aufbau der Part-Header sowie Übergabe der Parameter dafür und deren Plausiplitätskontrolle ermittelt werden müssen (z. B. für Fileupload, Kontrolle der Boundary, usw.).

      Oder man nimmt eine Bibliothek, die das schon erledigt hat.

      dedlfix.