PHP fsockopen POST request

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Klaas Sjaak

Klaas Sjaak

07/03/2019 10:58:43
Quote Anchor link
Hallo,

Ik probeer een POST request naar mijn web server te sturen vanuit een html formulier(ajax), als response zou deze de html bron van de pagina moeten opslaan in een buffer zodat ik deze verder kan bewerken. Op een 1 of andere manier wordt de content van de pagina echter gewoon naar de browser gestuurd ipv gebuffered.

Ik heb ook fgets() gebruikt, het aantal bytes om in te lezen aangepast, maar ook hierbij werd de pagina niet gebuffered.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$rConnect = fsockopen($aUrl['host'],80,$iError,$sError,10);
$sData = urlencode($aUrl['query']);
$sOut = "POST ".$aUrl['path']." HTTP/1.1\r\n";
$sOut .= "Host: ".$aUrl['host']."\r\n";
$sOut .= "Content-Type: application/x-www-form-urlencoded\r\n";
$sOut .= "Content-Length: ".strlen($sData)."\r\n\r\n";
$sOut .= "Connection: Close\r\n\r\n";
// write to socket
fputs($rConnect,$sOut);
$sFileData = "";
// get response
while(!feof($rConnect)){
    $sFileData .= stream_get_line($rConnect,1024,"\n");
}
fclose($rConnect);

Hoop dat iemand een oplossing heeft.
 
PHP hulp

PHP hulp

08/12/2021 10:11:37
 
- Ariën -
Beheerder

- Ariën -

07/03/2019 12:35:42
Quote Anchor link
Ik denk dat cURL een handigere methode is.
https://stackoverflow.com/questions/2138527/php-curl-http-post-sample-code


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
//
// A very simple PHP example that sends a HTTP POST to a remote site
//


$ch = curl_init();

curl_setopt($ch, CURLOPT_URL,"http://www.example.com/tester.phtml");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
            "postvar1=value1&postvar2=value2&postvar3=value3");

// In real life you should use something like:
// curl_setopt($ch, CURLOPT_POSTFIELDS,
//          http_build_query(array('postvar1' => 'value1')));

// Receive server response ...

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$server_output = curl_exec($ch);

curl_close ($ch);

// Further processing ...
if ($server_output == "OK") { ... } else { ... }
?>
Gewijzigd op 07/03/2019 12:39:11 door - Ariën -
 
Klaas Sjaak

Klaas Sjaak

07/03/2019 13:05:47
Quote Anchor link
Dank je voor je reactie, maar ik heb in de code al curl als fallback. Ik wil echter ook sockets implementeren. Code is deel van een module voor mijn cms, dus wordt door anderen ook gebruikt.

Ik heb meerdere scripts gemaakt met sockets en ik kan altijd de response van de server opslaan in een variabel, mijn vraag is dan ook waarom wordt de ouput niet opgeslagen in een variabel maar gewoon verstuurd naar de browser?
 
- Ariën -
Beheerder

- Ariën -

07/03/2019 14:43:55
Quote Anchor link
Ik vraag mij af of er überhaupt nog servers zonder cURL-module in PHP zijn, waarbij een fallback echt nodig is?
Gewijzigd op 07/03/2019 14:44:22 door - Ariën -
 
Klaas Sjaak

Klaas Sjaak

07/03/2019 15:07:50
Quote Anchor link
Het punt is meer dat het mogelijk is om een POST via sockets te doen, en het werkt ook, ik krijg de juiste bron..alleen waarom wordt deze direct naar de browser verstuurd en niet in een variabel opgeslagen?
 
- Ariën -
Beheerder

- Ariën -

07/03/2019 15:12:22
Quote Anchor link
Ik heb geen idee of dit de juiste methode is, maar kan je het niet op deze manier bufferen?
http://php.net/manual/en/function.ob-get-contents.php
 
Klaas Sjaak

Klaas Sjaak

07/03/2019 15:20:36
Quote Anchor link
Dat is idd een optie, maar niet erg elegant imo. Ik denk zelf dat er ergens iets mis gaat, en wat is dat dan precies, dat wil ik graag weten. ;)

iig bedankt voor het meedenken.
Gewijzigd op 07/03/2019 15:21:11 door Klaas Sjaak
 
- Ariën -
Beheerder

- Ariën -

07/03/2019 15:40:06
Quote Anchor link
Volgens mij is het standaard gedrag van fsockopen. In het verre verleden liep ik hier ook tegen aan. En toen heb ik dit ook met output-buffering opgelost. Vaak kan je, net als bij system() via een parameter kiezen of je het wilt bufferen of outputten. Maar bij fsockopen() lijkt dat niet te kunnen.

Omdat cURL behoorlijk flexibeler is, gebruik ik nu haast altijd cURL.
Gewijzigd op 07/03/2019 15:57:35 door - Ariën -
 
Thomas van den Heuvel

Thomas van den Heuvel

07/03/2019 16:57:48
Quote Anchor link
Wat kanttekeningen bij bovenstaande code:

Het HTTP protocol is niet mijn sterkste punt, maar zorgt een witregel (dubbele regelovergang - \r\n\r\n) niet voor de scheiding tussen de headers en de body? Oftewel, jouw Connection: Close valt buiten de boot?

Daarnaast geef je aan dat het een POST request betreft, vertel je hoe lang de gePOSTe data is... maar je verzend vervolgens nergens de data zelf :p.

Na regel 9 moet er waarschijnlijk nog iets volgen als fputs($rConnect, $sData);.

Ook is het mogelijk verstandig als je iets anders doet dan/met die !feof(), met die constructie kan namelijk nogal wat misgaan.

Als dit alles op orde is en je ook een correct request doet zou je eens verder kunnen kijken naar wat er (dan nog) aan de hand is.

EDIT: hoe ziet $aUrl['query'] er uit? Zou het niet handiger zijn als dit een array is en dat je http_build_query() hierop toepast voor het bouwen van $sData?

EDIT: weet je ook zeker dat je nergens de inhoud van $sFileData weergeeft? Bij mij werkt het zonder enige problemen. Overigens, je bouwt dus een rauw HTTP request, dan is het dus ook niet zo verwonderlijk dat je een rauwe HTTP response krijgt - hier zitten headers dus ook bij. Ik weet niet waarom e.e.a. direct wordt weergegeven op je scherm. Ik had dit toen ik met jouw script startte ook, maar bij een aangepaste (en kloppende) versie werkte alles zoals je zou verwachten.
Gewijzigd op 07/03/2019 18:59:59 door Thomas van den Heuvel
 
Klaas Sjaak

Klaas Sjaak

07/03/2019 20:09:36
Quote Anchor link
Dank je wel voor je reactie, heb het script wat aangepast:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
            fwrite($rConnect,"POST ".$aUrl['path']." HTTP/1.1\r\n");
            fwrite($rConnect,"Host: ".$aUrl['host']."\r\n");
            fwrite($rConnect,"Accept: */*\r\n");
            fwrite($rConnect,"User-Agent: SomeTool/2.0\r\n");
            fwrite($rConnect,"Content-type: application/x-www-form-urlencoded\r\n");
            fwrite($rConnect,"Content-length: ".strlen($sData)."\r\n\r\n");
            fwrite($rConnect,$sData."\r\n\r\n");
            stream_set_timeout($rConnect,10);
            $aInfo = stream_get_meta_data($rConnect);
            $sFileData = "";
            // get response
            while(!feof($rConnect) && !$aInfo['timed_out']){
                $sFileData .= fread($rConnect,4096);
                $aInfo = stream_get_meta_data($rConnect);
            }
            fclose($rConnect);

Output nog steeds hetzelfde.


$aUrl['query'] is het query gedeelte van de url afkomstig van de functie parse_url()
EDIT: nope, geef nergens $sFileData weer, dat dacht ik in het begin ook, maar dat is niet het geval.
Gewijzigd op 07/03/2019 20:10:52 door Klaas Sjaak
 
Thomas van den Heuvel

Thomas van den Heuvel

07/03/2019 23:58:24
Quote Anchor link
Oef, dat tweede fragment is echt heel erg traag en lijkt ook niet te doen wat je wilt. Ik weet ook niet of je echt (aparte?!) fwrites wilt doen? Resulteert dat niet in gefragmenteerde requests?

Probeer het anders zo eens (wel even host en doelscript aanpassen):
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
// for debugging
error_reporting(E_ALL);
ini_set('display_startup_errors', true);
ini_set('display_errors', 'stdout');

// REQUEST
$aUrl = array(
    'host' => 'your.server.com',
    'path' => '/path/to/post.test.php',
    'query' => array('fish' => 'moo', 'test' => true),
);


$sData = http_build_query($aUrl['query']); // do not urlencode, http_build_query takes care of this

$iError = 0;
$sError = '';
define('LE', "\r\n"); // line ending, less typing :)

$rConnect = fsockopen($aUrl['host'], 80, $iError, $sError, 10);

if ($rConnect === false) {
    die('connection failed'); // for testing purposes, you want better handling than this obviously
}

$headers = array();
$headers[] = 'POST '.$aUrl['path'].' HTTP/1.0'; // note: HTTP/1.0, so we do not get chunked garbage
$headers[] = 'Host: '.$aUrl['host'];
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
$headers[] = 'Content-Length: '.strlen($sData);
$headers[] = 'Connection: Close'; // immediately hang up after
$headers[] = LE; // blank line indicating end of headers

// write to socket

fputs($rConnect, implode(LE, $headers));
fputs($rConnect, $sData); // EDIT: make sure to actually write POST data :)

// get response
// note fgets() does not support chunked mode, which is part of HTTP 1.1
// if you are going to use fgets make sure to use HTTP 1.0

$sFileData = '';

// This is one way to do it...
/*
while (($line = fgets($rConnect, 1024)) !== false) {
    $sFileData .= $line;
}
*/
// ... or use this

while (!feof($rConnect)) {
    $sFileData .= stream_get_line($rConnect, 1024, "\n");
}

fclose($rConnect);

// RESPONSE
// for testing if everything came across ok

header('Content-Type: text/html; charset=UTF-8');
echo '<pre>'.htmlspecialchars($sFileData, ENT_QUOTES, 'UTF-8').'</pre>';
?>


En /path/to/post.test.php is bijvoorbeeld:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    if (empty($_POST)) {
        $response = 'empty POST';
    }
else {
        // quick test, just bake a JSON response
        $response = json_encode($_POST);
    }

    echo $response;
}

?>

Dit werkt bij mij prima, en produceert niet ongevraagd output.

Dit produceert bij mij het volgende:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
HTTP/1.1 200 OK
Server: nginx/1.10.3
Date: Thu, 07 Mar 2019 23:03:25 GMT
Content-Type: text/html; charset=UTF-8
Connection: close

{"fish":"moo","test":"1"}
Gewijzigd op 08/03/2019 00:06:18 door Thomas van den Heuvel
 
Klaas Sjaak

Klaas Sjaak

08/03/2019 10:33:45
Quote Anchor link
Dank je wel Thomas dat je de moeite hiervoor genomen hebt! Als ik vanavond thuis ben ga ik er weer mee aan de slag. :)

Toevoeging op 08/03/2019 19:46:05:

Jammer dat er geen reputatie systeem op dit forum is, jullie verdienen een dikke pluim.

Problem solved!

Nogmaals bedankt. :)
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.