How to do a POST request

This example shows how to do a simple POST request to another webserver by using a socket connection.

Snippet information

Author:
Jonas John

License:
Public Domain

Language:
PHP

Created:
08/05/2006

Updated:
08/05/2006

Tags:
, ,


/*
** The function:
*/
 
function PostRequest($url, $referer, $_data) {
 
    // convert variables array to string:
    $data = array();    
    while(list($n,$v) = each($_data)){
        $data[] = "$n=$v";
    }    
    $data = implode('&', $data);
    // format --> test1=a&test2=b etc.
 
    // parse the given URL
    $url = parse_url($url);
    if ($url['scheme'] != 'http') { 
        die('Only HTTP request are supported !');
    }
 
    // extract host and path:
    $host = $url['host'];
    $path = $url['path'];
 
    // open a socket connection on port 80
    $fp = fsockopen($host, 80);
 
    // send the request headers:
    fputs($fp, "POST $path HTTP/1.1\r\n");
    fputs($fp, "Host: $host\r\n");
    fputs($fp, "Referer: $referer\r\n");
    fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
    fputs($fp, "Content-length: ". strlen($data) ."\r\n");
    fputs($fp, "Connection: close\r\n\r\n");
    fputs($fp, $data);
 
    $result = ''; 
    while(!feof($fp)) {
        // receive the results of the request
        $result .= fgets($fp, 128);
    }
 
    // close the socket connection:
    fclose($fp);
 
    // split the result header from the content
    $result = explode("\r\n\r\n", $result, 2);
 
    $header = isset($result[0]) ? $result[0] : '';
    $content = isset($result[1]) ? $result[1] : '';
 
    // return as array:
    return array($header, $content);
}
 
 
 
/*
** The example:
*/
 
// submit these variables to the server:
$data = array(
    'test' => 'foobar',
    'okay' => 'yes',
    'number' => 2
);
 
// send a request to example.com (referer = jonasjohn.de)
list($header, $content) = PostRequest(
    "http://www.example.com/",
    "http://www.jonasjohn.de/",
    $data
);
 
// print the result of the whole request:
print $content;
 
// print $header; --> prints the headers


Found a bug? Or do you have a better solution for this?
Feel free to leave a message:

Add a comment


Leave a comment

ldesmarets February 19, 2010 at 17:41
I'm trying to use this class to make a proxy that post a form on phplist from a jquery ajax submit form...

I don't understand why some headers, uurl encoded are changed between the post and the phplist index page:

these are the value data send:

$data = array(
'makeconfirmed' => '1',
'htmlemail' => '1',
'list[2]' => 'signup',
'listname[2]' => 'Un Monde de Papier',
'subscribe' => 'yes',
'emailconfirm' => $_REQUEST['email'],
'email' => $_REQUEST['email'],
);

the post encoded:
makeconfirmed=1&htmlemail=1&list%5B2%5D=signup&listname%5B2%5D=Un+Monde+de+Papier&subscribe=yes&emailconfirm=zzz%40kk.de&email=zzz%40kk.de

finally the request content in index page from phplist

htmlemail => 1
list => Array
listname => Array
subscribe => yes
emailconfirm => zzz@kk.de
email => zzz@kk.de


the list[2] = signup
is transformed in list = Array
so it doesn't work,

thank you if you get something about that
Tom February 09, 2010 at 14:00
Look !
This function works perfect, and is much easyer than all of yours...
Dont know ? but Isn't it?
function file_post_contents($url,$data) {
$url = parse_url($url);

if (!isset($url['port'])) {
if ($url['scheme'] == 'http') { $url['port']=80; }
elseif ($url['scheme'] == 'https') { $url['port']=443; }
}
$url['query']=isset($url['query'])?$url['query']:'';

$url['protocol']=$url['scheme'].'://';
$eol="rn";

$headers = "POST ".$url['protocol'].$url['host'].$url['path']." HTTP/1.0".$eol.
"Host: ".$url['host'].$eol.
"Referer: ".$url['protocol'].$url['host'].$url['path'].$eol.
"Content-Type: application/x-www-form-urlencoded".$eol.
"Content-Length: ".strlen($data).$eol.
$eol.$data;
$fp = fsockopen($url['host'], $url['port'], $errno, $errstr, 30);
if($fp) {
fputs($fp, $headers);
$result = '';
while(!feof($fp)) { $result .= fgets($fp, 128); }
fclose($fp);
// if (!$headers)
{
//removes headers
$pattern="/^.*rnrn/s";
$result=preg_replace($pattern,'',$result);
}
return $result;
}
}

Thanks !!
Tom February 09, 2010 at 13:45
Why this code does not work in my Case ??
The PostVars on the Serverside of the ClientArray:
$data = array(
'test' => 'foobar',
'okay' => 'yes',
'number' => 2
);
is (print_r($_POST)):
6 Array 2 ( 1 1 1 1 1 [ 4 test 5 ] => 6 foobar 1 1 1 1 1 1 [ 4 okay 5 ] => 3 yes 1 1 1 1 1 1 [ 6 number 5 ] => 1 2 1 2 ) 0

I dont understand,...
guillaume bretou December 08, 2009 at 18:48
Hi there,

There is a small thing to add :
urlencode() for the key and the value. Because, if you want to send data with special characters, it will fail.

while(list($n,$v) = each($_data))
{
$n = urlencode($n);
$v = urlencode($v);
$data[] = "$n=$v";
}

Cheers !
Josh Lyon September 20, 2009 at 09:23
Sorry to keep posting, but I found a solution to my earlier issue related to chunked encoding. Simply put, it seems that the fgets function (and other php functions) don't support chunked encoding which is part of the HTTP 1.1 standard. On the other hand, HTTP 1.0 does not support chunked encoding, so I simply changed the code to make all requests as HTTP 1.0 requests.

I should also note that the 1000 iterations colin suggested for the loop catch was not allowing the application to completely pull down the data for really large files. I increased this number quite significantly to allow large files to download using this method.

Thanks again for the code snippet!
Josh Lyon September 20, 2009 at 07:44
I've done a bit more research and I believe this has to do with the fact that the response I am getting is a chunked reply. When analyzing the header of the reply I noticed that there was a setting for:

Transfer-Encoding: chunked

Further research indicates that the format I am seeing with linebreak, size, linebreak every once in a while throughout the file is based on the chunked transfer-encoding type. I'm going to continue to do research, but if anyone else has thoughts on the matter please post them here.
Josh Lyon September 18, 2009 at 22:17
When I use this code, I always seem to get a line at the beginning of the content which appears to be the size of the content that is returned (in Hex). For example, 7B indicates 123 bytes of information. There are also a few trailing blank lines and a 0.

When I run the post request in a standard HTML form, I don't see this at the beginning and end of the content.

I can strip out those extraneous lines after the content is returned, but I was just curious why that was showing up and if I should tweak the code.
polaqo August 26, 2009 at 23:11
Hi, i've had a problem with this and i don´t know how to solve it perhabs you can help me. I connect to a server (the connection seems to work just fine) but the server response it´s just "Continue". Why does this happen?
PD: Im tryng to request a .php page not a .html
cocoy August 04, 2009 at 11:45
Hi, does this work well with large data? say, over 2kb.. this would solve the problem on limited size of GET requests on IE7 and lower browsers.

Also, can this be done with Ajax? :D

Thanks
Joseph July 23, 2009 at 01:11
Esta es una version un poco mas limpia y clara:

function PostRequest($url, $data)
{
// Se verifican los datos.
if (!is_array($data)) throw new Exception('Los datos deben pasarse como un array.');

// Se convierte la data en string (a=1&b=2).
$data_query = http_build_query($data);

// Se extrae la info de la url.
$url_parsed = parse_url($url);

// Se verifica que la petición hecha sea del tipo HTTP.
if ($url_parsed['scheme'] != 'http') throw new Exception('Solo se soportan peticiones HTTP.');

// Se abre una conexión vía socket.
$fp = @fsockopen($url_parsed['host'], 80);

if ($fp === FALSE) throw new Exception("No se pudo abrir la conexión con {$url_parsed['host']}.");

// Se hace la petición.
fputs($fp, "POST {$url_parsed['path']} HTTP/1.1rn");
fputs($fp, "Host: {$url_parsed['host']}rn");
fputs($fp, "Referer: $urlrn");
fputs($fp, "Content-type: application/x-www-form-urlencodedrn");
fputs($fp, "Content-length: ". strlen($data_query) ."rn");
fputs($fp, "Connection: closernrn");
fputs($fp, $data_query);

// Se almacena el resultado en una variable.
$result = '';
while(!feof($fp)) $result.= fgets($fp, 128);

// Se cierra la conexión.
fclose($fp);

// Se retorna el resultado.
return $result;
}


$data = array('nombre' => 'Pancho','apellido' => 'Villa');
$result = PostRequest('http://localhost/www/labs/test.php', $data);
PaHtP July 20, 2009 at 11:12
Merci pour la fonction j'en avais grandement besoin (sorry not speak english)
francis January 15, 2009 at 22:42
Thx to Michael and Colin for the HTTPS version, which is working fine!
Colin January 10, 2009 at 02:26
Great... it looks like all the backslashes have been stripped out of my last post rendering it gibberish.
Colin January 08, 2009 at 09:05
Example of ssl post with built-in loop that catches it after 1000 iterations in case of accidental screw-ups during testing. I haven't used fsockopen before today so apologies if I've made some obvious gaffe but this seems to work OK for me...

function PostRequest($url, $referer, $_data) {

// convert variables array to string:
$data = array();
while(list($n,$v) = each($_data)){
$data[] = "$n=$v";
}
$data = implode('&', $data);
// format --> test1=a&test2=b etc.

// parse the given URL
$url = parse_url($url);

// extract host and path:
$host = $url['host'];
$path = $url['path'];

// open a socket connection on port 80
$fp = fsockopen("ssl://".$host, 443);

// send the request headers:
fputs($fp, "POST $path HTTP/1.1rn");
fputs($fp, "Host: $hostrn");
fputs($fp, "Referer: $refererrn");
fputs($fp, "Content-type: application/x-www-form-urlencodedrn");
fputs($fp, "Content-length: ". strlen($data) ."rn");
fputs($fp, "Connection: closernrn");
fputs($fp, $data);

$result = '';
$safe=0;
while(!feof($fp)&&$safe<1000) {
// receive the results of the request
$result .= fgets($fp, 128);
$safe++;
}

// close the socket connection:
fclose($fp);

// split the result header from the content
$result = explode("rnrn", $result, 2);

$header = isset($result[0]) ? $result[0] : '';
$content = isset($result[1]) ? $result[1] : '';

// return as array:
return array($header, $content);
}

/*
** The example:
*/

// submit these variables to the server:
$data = array(
'var'=>'value'
);

// send a request to example.com (referer = jonasjohn.de)
list($header, $content) = PostRequest(
"https://www.example.com/path/",
"http://www.myhost.com",
$data
);

// print the result of the whole request:
print $content;
Colin January 08, 2009 at 08:26
I would be a bit careful with this in testing:
while(!feof($fp)) {
// receive the results of the request
$result .= fgets($fp, 128);
}
I found during tests (I was trying to make it SSL compatible) that it failed to work (my fault, no doubt!), which normally wouldn't matter but this loop just didn't stop and completely filled my website's disk space with the amount of output it was shoving into the error_log and didn't stop even when the file was deleted! Result - downtime!
It might be worth putting in a counter to only allow it to loop a certain number of times before dying, at least until you're sure you've got it right!
tnt November 26, 2008 at 12:09
Awesome! Works like a charm!
Michael Wegner June 05, 2008 at 16:17
you can now use url's with query to send post requests to
Michael Wegner June 05, 2008 at 16:16
function PostRequest($url, $referer, $_data) {

// convert variables array to string:
$data = array();
while(list($n,$v) = each($_data)){
$data[] = "$n=$v";
}
$data = implode('&', $data);
// format --> test1=a&test2=b etc.

// parse the given URL
$url = parse_url($url);
if ($url['scheme'] != 'http') {
die('Only HTTP request are supported !');
}

// extract host and path:
$host = $url['host'];
$path = $url['path'];
$query = $url['query'];

// open a socket connection on port 80
$fp = fsockopen($host, 80);
echo "path: $path?$query\r\n";
// send the request headers:
fputs($fp, "POST $path?$query HTTP/1.1\r\n");
fputs($fp, "Host: $host\r\n");
fputs($fp, "Referer: $referer\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ". strlen($data) ."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $data);

$result = '';
while(!feof($fp)) {
// receive the results of the request
$result .= fgets($fp, 128);
}

// close the socket connection:
fclose($fp);

// split the result header from the content
$result = explode("\r\n\r\n", $result, 2);

$header = isset($result[0]) ? $result[0] : '';
$content = isset($result[1]) ? $result[1] : '';

// return as array:
return array($header, $content);
}