Reputation: 4149
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
Reputation: 61
Here a function that perform also some checks in particular:
error_get_last
after the callfunction 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
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.
$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 ;-)
Upvotes: 671
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
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