Paras Chopra
Paras Chopra

Reputation: 4149

How to post data in PHP using file_get_contents?

I'm using PHP's function file_get_contents() to fetch contents of a URL and then I process headers through the variable $http_response_header.

Now the problem is that some of the URLs need some data to be posted to the URL (for example, login pages).

How do I do that?

I realize using stream_context I may be able to do that but I am not entirely clear.

Thanks.

Upvotes: 340

Views: 418017

Answers (4)

Damiano Falcioni
Damiano Falcioni

Reputation: 61

Here a function that perform also some checks in particular:

  • allow_url_fopen is enabled
  • protocol wrapper is available (especially for https check if openssl extension is enabled)
  • error_get_last after the call
  • returned http status code after the call
function file_get_contents_post($url, $payload, $contentType) {
    $protocol = strtolower(strtok($url, ':'));
    if(($protocol == 'http' || $protocol == 'https') && !ini_get("allow_url_fopen"))
        throw new Exception('Can not open urls with file_get_contents as allow_url_fopen is set to false.');
    if(!in_array($protocol, stream_get_wrappers()))
        throw new Exception('Can not open '.$protocol.' urls with file_get_contents as no wrapper available.'.($protocol == 'https' ? ' OPENSSL extension is '.(!extension_loaded('openssl')?'NOT ':'').'enabled' : ''));

    $content = @file_get_contents($url, false, stream_context_create(array(
        'http'=>array(
            'method'=>'POST',
            'header'=>($contentType!=null ? 'Content-Type: '.$contentType.'\r\n' : '').($payload!=null ? 'Content-Length: '.strlen($payload).'\r\n' : ''),
            'content'=>$payload!=null ? $payload : '',
            'ignore_errors'=>true
        ),
        'ssl'=>array(
            'cafile'=>dirname(__FILE__).'/cacert.pem' //downloaded from https://curl.se/ca/cacert.pem
        )
    )));
    if ($content === false)
        throw new Exception('Error calling '.$url.': '.(error_get_last()!=null?error_get_last()['message']:'No error reported'));
    if($protocol == 'http' || $protocol == 'https') {
        preg_match('{HTTP\/\S*\s(\d{3})}', $http_response_header[0], $match);
        $httpReturnCode = intval($match[1]);
        if ($httpReturnCode < 200 || $httpReturnCode > 299)
            throw new Exception('URL returned http code '.$httpReturnCode.': '.$content);
    }
    return $content;
}

Note that the payload must be provided already encoded, so to avoid errors on manually crafter payloads, should be preferable to use

  • http_build_query for Content-Type application/x-www-form-urlencoded
  • json_encode for Content-Type application/json
  • ...

to build your payload.

If some of the initial checks fails you can try to fallback to the CURL equivalent:

function curl_post($url, $payload, $contentType) {
    try {
        if(!function_exists('curl_init'))
            throw new Exception('Function curl_init not found. PHP CURL extension is '.(!extension_loaded('curl')?'NOT ':'').'enabled');
        $ch = curl_init();
        if ($ch === false)
            throw new Exception('PHP CURL: failed to initialize');
        if (isset($payload))
            curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        if (isset($contentType))
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:'.$contentType));
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__).'/cacert.pem');   //downloaded from https://curl.se/ca/cacert.pem
        $content = curl_exec($ch);
        if ($content === false)
            throw new Exception(curl_error($ch), curl_errno($ch));
        $httpReturnCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if ($httpReturnCode < 200 || $httpReturnCode > 299)
            throw new Exception('PHP CURL: URL call returned error code '.$httpReturnCode.': '.$content);
        return $content;
    } catch(Throwable $ex) {
        throw $ex;
    } finally {
        if (is_resource($ch)) {
            curl_close($ch);
        }
    }
}

Upvotes: 1

Pascal MARTIN
Pascal MARTIN

Reputation: 401182

Sending an HTTP POST request using file_get_contents is not that hard, actually : as you guessed, you have to use the $context parameter.


There's an example given in the PHP manual, at this page : [HTTP context options][2] *(quoting)* :
$postdata = http_build_query(
    array(
        'var1' => 'some content',
        'var2' => 'doh'
    )
);

$opts = array('http' =>
    array(
        'method'  => 'POST',
        'header'  => 'Content-Type: application/x-www-form-urlencoded',
        'content' => $postdata
    )
);

$context  = stream_context_create($opts);

$result = file_get_contents('http://example.com/submit.php', false, $context);

Basically, you have to create a stream, with the right options (there is a full list on that page), and use it as the third parameter to file_get_contents -- nothing more ;-)


As a sidenote : generally speaking, to send HTTP POST requests, we tend to use curl, which provides a lot of options an all -- but streams are one of the nice things of PHP that nobody knows about... too bad...

Upvotes: 671

user2525449
user2525449

Reputation: 275

$sUrl = 'http://www.linktopage.com/login/';
$params = array('http' => array(
    'method'  => 'POST',
    'content' => 'username=admin195&password=d123456789'
));

$ctx = stream_context_create($params);
$fp = @fopen($sUrl, 'rb', false, $ctx);
if(!$fp) {
    throw new Exception("Problem with $sUrl, $php_errormsg");
}

$response = @stream_get_contents($fp);
if($response === false) {
    throw new Exception("Problem reading data from $sUrl, $php_errormsg");
}

Upvotes: -2

Macbric
Macbric

Reputation: 482

An alternative, you can also use fopen

$params = array('http' => array(
    'method' => 'POST',
    'content' => 'toto=1&tata=2'
));

$ctx = stream_context_create($params);
$fp = @fopen($sUrl, 'rb', false, $ctx);
if (!$fp)
{
    throw new Exception("Problem with $sUrl, $php_errormsg");
}

$response = @stream_get_contents($fp);
if ($response === false) 
{
    throw new Exception("Problem reading data from $sUrl, $php_errormsg");
}

Upvotes: 24

Related Questions