How to do a POST request

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

function post_request($url, $data, $referer='') {
 
    // Convert the data array into URL Parameters like a=b&foo=bar etc.
    $data = http_build_query($data);
 
    // parse the given URL
    $url = parse_url($url);
 
    if ($url['scheme'] != 'http') { 
        die('Error: Only HTTP request are supported !');
    }
 
    // extract host and path:
    $host = $url['host'];
    $path = $url['path'];
 
    // open a socket connection on port 80 - timeout: 30 sec
    $fp = fsockopen($host, 80, $errno, $errstr, 30);
 
    if ($fp){
 
        // send the request headers:
        fputs($fp, "POST $path HTTP/1.1\r\n");
        fputs($fp, "Host: $host\r\n");
 
        if ($referer != '')
            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);
        }
    }
    else { 
        return array(
            'status' => 'err', 
            'error' => "$errstr ($errno)"
        );
    }
 
    // 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 structured array:
    return array(
        'status' => 'ok',
        'header' => $header,
        'content' => $content
    );
}
Snippet Details



// Submit those variables to the server
$post_data = array(
    'test' => 'foobar',
    'okay' => 'yes',
    'number' => 2
);
 
// Send a request to example.com 
$result = post_request('http://www.example.com/', $post_data);
 
if ($result['status'] == 'ok'){
 
    // Print headers 
    echo $result['header']; 
 
    echo '<hr />';
 
    // print the result of the whole request:
    echo $result['content'];
 
}
else {
    echo 'A error occured: ' . $result['error']; 
}

Sorry folks, comments have been deactivated for now due to the large amount of spam.

Please try to post your questions or problems on a related programming board, a suitable mailing list, a programming chat-room,
or use a QA website like stackoverflow because I'm usually too busy to answer any mails related
to my code snippets. Therefore please just mail me if you found a serious bug... Thank you!


Older comments:

nick July 04, 2011 at 19:40
Hello, this script is really cool. The only problem I experience is that if the content of the response is longer than 8000 characters, the content length is included into it in hex. Does anyone else experience that or knows why?
Hari July 01, 2011 at 21:46
This was very useful.
pokono June 22, 2011 at 23:12
thanks you so much!
KuLiBiN June 09, 2011 at 11:50
Thank you!!!
Dibran Mulder May 25, 2011 at 11:54
Thanks works just fine!!
luc April 08, 2011 at 17:01
Thanks a lot, saved me another 10 minutes of coding and probably debugging :p
salvia January 10, 2011 at 05:25
Could you help me?
What if i have 2 values and certain form name? is it possible?

fot example i have such form and want to change it for php request:

<form action="http://page.com/user/login" method="post" name="loginFormElement">
<div class="form-login">

<label>Username:</label>
<div class="input">
<input type="text" value="" id="name" name="username"/>
</div>

<label>
Pass:</label>

<div class="input">

<input type="password" value="" name="password"/>
</div>
<div>
<input type="submit" class="button btn-login" onclick="document.forms['loginFormElement'].submit();return false;" value="Login" />
</div>
</div>
</form>

so i have 2 values $_POST['username'], $_POST['password'] and have such submit-action:

document.forms['loginFormElement'].submit();return false;

is it possible to change it for php?
how does it looks like?
i will be grateful for example
Wolfdvs December 20, 2010 at 23:05
I hope that help you
function post_request($host, $path, $values, &$error = null)
{
$rs = '';
$data = http_build_query($values);
$size = strlen($data);

$fp = fsockopen($host,80, $errno, $errstr, 30);

if($fp) {

$request = "POST $path HTTP/1.1rn";
$request.= "Host: $hostrn";
$request.= "Content-type: application/x-www-form-urlencodedrn";
$request.= "Content-Length: ".$size."rn";
$request.= "Connection: Closernrn";
$request.= $data;

fwrite($fp, $request);

while(!feof($fp)) {
$rs .= fgets($fp, 128);
}

} else {
$error = "$errstr ($errno)";
}

fclose($fp);

list($header, $content) = explode("rnrn", $rs, 2);

return array('header' => $header, 'content' => $content);
}
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 !!
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);
}