HTTP request using fopen and curl_setopt - php

If cURL is unavailable I want to send HTTP requests using fopen. I got the code for a class from a PACKT RESTful PHP book but it does nto work. Any ideas why?
if ($this->with_curl) {
//blah
} else {
$opts = array (
'http' => array (
'method' => "GET",
'header' => array($auth,
"User-Agent: " . RESTClient :: USER_AGENT . "\r\n"),
)
);
$context = stream_context_create($opts);
$fp = fopen($url, 'r', false, $context);
$result = fpassthru($fp);
fclose($fp);
}
return $result;
}

The HTTP context options are laid out here: http://www.php.net/manual/en/context.http.php
The header option is a string, so as #Mob says you should be using \r\n and string concatenation rather than an array. However, user_agent is a valid key, so you could just use that instead.
I'm guessing that the contents of the $auth variable is something along the lines of Authorization: blah - i.e. standard header format?
The below code is a working example. Note that I've changed your fpassthru() (which outputs the content to the browser, and does not store it to $result) to a fread() loop. Alternatively you could have wrapped the fpassthru() call with ob_start(); and $result = ob_get_clean();
<?php
class RESTClient {
const USER_AGENT = 'bob';
}
$url = 'http://www.example.com/';
$username = "fish";
$password = "paste";
$b64 = base64_encode("$username:$password");
$auth = "Authorization: Basic $b64";
$opts = array (
'http' => array (
'method' => "GET",
'header' => $auth,
'user_agent' => RESTClient :: USER_AGENT,
)
);
$context = stream_context_create($opts);
$fp = fopen($url, 'r', false, $context);
$result = "";
while ($str = fread($fp,1024)) {
$result .= $str;
}
fclose($fp);
echo $result;

You're mixing this. Shouldn't it be ::
$opts = array (
'http' => array (
'method' => "GET",
'header' => $auth . "\r\n" . //removed array()
"User-Agent: " . RESTClient :: USER_AGENT . "\r\n" )
)
Here's an example of setting headers from the PHP manual
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en\r\n" .
"Cookie: foo=bar\r\n"
)
);

Related

Post request with file_get_content not working

I am trying to use file_get_contents to "post" to a url and get auth token. The problem I am having is that it returns a error.
Message: file_get_contents(something): failed to open stream: HTTP request failed! HTTP/1.1 411 Length Required.
I am not sure what is causing this but need help. Here is the function.
public function ForToken(){
$username = 'gettoken';
$password = 'something';
$url = 'https://something.com';
$context = stream_context_create(array (
'http' => array (
'header' => 'Authorization: Basic ' . base64_encode("$username:$password"),
'method' => 'POST'
)
));
$token = file_get_contents($url, false, $context);
if(token){
var_dump($token);
}else{
return $resultArray['result'] = 'getting token failed';
}
}
I tried it with POSTMAN, and it works, so only problem I am having is that why isnt it working with file_get_contents.
Cannot command so i will do it this way. If you use Postman why don't you let Postman generate the code for you. In postman you can click code at a request and you can even select in what coding language you wanne have it. Like PHP with cURL:
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "http://somthing.com/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => array(
"password: somthing",
"username: gettoken"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
Hope this will help!
I can not comment because of my reputation;
In some servers file_get_content is not available...
You may try with CURL like this
Your request havent any data and content length is missing.
You can try this:
public function ForToken(){
$username = 'gettoken';
$password = 'something';
$url = 'https://something.com';
$data = array('foo' => 'some data');
$data = http_build_query($data);
$context_options = array (
'http' => array (
'method' => 'POST',
'header'=> "Content-type: application/x-www-form-urlencoded\r\n"
. "Authorization: Basic " . base64_encode("$username:$password") . "\r\n"
. "Content-Length: " . strlen($data) . "\r\n",
'content' => $data
)
);
$context = context_create_stream($context_options);
$token = file_get_contents($url, false, $context);
if(token){
var_dump($token);
}else{
return $resultArray['result'] = 'getting token failed';
}
}
Here is similar problem:
How to fix 411 Length Required error with file_get_contents and the expedia XML API?
RFC2616 10.4.12
https://www.rfc-editor.org/rfc/rfc2616#section-10.4.12
Code: (Doesn't work, see below)
public function ForToken(){
$username = 'gettoken';
$password = 'something';
$url = 'https://something.com';
$context = stream_context_create(array (
'http' => array (
'header' => 'Authorization: Basic ' . base64_encode("$username:$password") . 'Content-Length: ' . strlen($url) . '\r\n',
'method' => 'POST'
)
));
$token = file_get_contents($url, false, $context);
if(token){
var_dump($token);
}else{
return $resultArray['result'] = 'getting token failed';
}
}
2nd Try:
public function ForToken(){
$username = 'gettoken';
$password = 'something';
$url = 'https://something.com';
$context_options = array (
'http' => array (
'method' => 'POST',
'header'=> "Content-type: application/x-www-form-urlencoded\r\n" . "Authorization: Basic " . base64_encode("$username:$password") . "Content-Length: " . strlen($url) . "\r\n",
'content' => $url
)
);
$context = stream_context_create($context_options);
$token = file_get_contents($url, false, $context);
if(token){
var_dump($token);
}else{
return $resultArray['result'] = 'getting token failed';
}
}
This is from patryk-uszynski's answer formatted with the OP's code.

How to add multiple headers to file_get_content in PHP

$opts = array('http' => array('method' => $_SERVER['REQUEST_METHOD'],
'header' => array("Accept-language: en\r\n",
"Cookie: " . session_name() . "=" . session_id() . "\r\n",
" Content-type: application/x-www-form-urlencoded\r\n"),
'content' => $_POST));
$postdata = http_build_query($_POST);
$context = stream_context_create($opts);
session_write_close(); // This is the key
echo $obsah = file_get_contents("http://localhost/journal/", false, $context);
This code is not working with POST and cookies.
The two existing answers are incorrect.
Newlines (\n) do not need to be added to HTTP headers used in stream_context_create(), and furthermore Carriage Returns (\r) should never be used anywhere near HTTP.
The following code is copied from the OP and corrected:
$postdata = http_build_query($_POST, '', '&', PHP_QUERY_RFC3986);
$opts = array(
'http' => array(
'method' => $_SERVER['REQUEST_METHOD'],
'header' => array(
"Accept-language: en",
"Cookie: " . session_name() . "=" . session_id(),
"Content-type: application/x-www-form-urlencoded",
),
'content' => $postdata,
)
);
$context = stream_context_create($opts);
$obsah = file_get_contents("http://localhost/journal/", false, $context);
echo $obsah
I've also added commas to the last array items so that maintenance will not have unnecessary lines in Git / SVN commits, and configured http_build_query() to use the more modern RFC 3986 encoding.
When passing a header with an array() instead of a string, you don't need the \r\n because PHP's stream_context_create() will do it for you on the header.
You also don't need session_write_close().
When you pass multiple headers there should two \r\n before sending POST data.
Let me explain.
Try this:
$opts = array(
'http' => array(
'method' => $_SERVER['REQUEST_METHOD'],
'header' => array(
"Accept-language: en\r\n",
"Cookie: ".session_name()."=".session_id()."\r\n",
"Content-type: application/x-www-form-urlencoded\r\n\r\n"
),
'content' => $_POST
)
);
$postdata = http_build_query($_POST);
$context = stream_context_create($opts);
session_write_close(); // this is the key
echo $obsah = file_get_contents("http://localhost/journal/", false, $context);

Http POST request get headers and body

I am currently using the below mentioned code to make http post request and it only returns body. I want the body and headers both. How I can I get body and headers both with file_get_content method or CURL?
$sURL = "url";
$sPD = "data";
$aHTTP = array(
'http' =>
array(
'method' => 'POST',
'header' => "Content-Type: application/atom+xml"
'content' => $sPD
)
);
$context = stream_context_create($aHTTP);
$contents = file_get_contents($sURL, false, $context);
echo $contents;
Try:
$context = stream_context_create($aHTTP);
$stream = fopen($sURL, 'r', false, $context);
$contents = stream_get_contents($stream);
$metadata = stream_get_meta_data($stream);
You can also use the HTTP Functions if available.

posting json data with curl and failing

I have this function here:
public static function call($action, array $args)
{
$post_args = array(
'action' => $action,
'args' => $args
);
$stream = json_encode($post_args);
$headers = array(
'Content-type: application/json',
'Accept: application/json',
'Expect:'
);
$userpwd = self::$_user.':'.sha1(sha1(self::$_pass));
$ch = curl_init();
$args = array(
CURLOPT_URL => self::$_url,
CURLOPT_FOLLOWLOCATION => TRUE,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_POST => TRUE,
CURLOPT_POSTFIELDS => $stream,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_USERPWD => $userpwd
);
curl_setopt_array($ch, $args);
$res = curl_exec($ch);
$data = json_decode($res, true);
if (isset($data) === TRUE
&& empty($data) === FALSE
) {
$res = $data;
}
return $res;
}//end call()
and at the URL where I'm posting, I'm just doing:
echo file_get_contents('php://input');
but getting nothing, even though I do post data. What could be the problem? I'm at a dead end.
Also, why do I need CURLOPT_FOLLOWLOCATION set to TRUE when I'm just posting to a simple virtual host URL on my local machine, not doing any redirects.
EDIT:
tried redoing it with fopen like so:
public static function call($action, array $args)
{
$post_args = array(
'action' => $action,
'args' => $args
);
$stream = json_encode($post_args);
$userpwd = self::$_user.':'.sha1(sha1(self::$_pass));
$opts = array(
'http' => array(
'method' => 'POST',
'header' => array(
"Authorization: Basic ".base64_encode($userpwd),
"Content-type: application/json"
),
'content' => $stream
)
);
$context = stream_context_create($opts);
$res = '';
$fp = fopen(self::$_url, 'r', false, $context);
if($fp){
while (!feof($fp)){
$res .= fread($fp, 128);
}
}
return $res;
}//end call()
no success. The connection works with curl and with fopen, since I pass the status along with result (which is just the php://input stream). Any ideas?
Can you be sure about that curl_exec function ends successfully. Also, why don't you use fopen for this purpose. I have written a JSON RPC client and server. I'm sending requests with fopen, and it works perfect.
$httpRequestOptions =
array(
'http'=>array(
'method'=>'POST',
'header'=>'Content-type: application/json',
'content'=>$requestJSON
)
);
$context = stream_context_create($httpRequestOptions);
// send request
if($fileHandler = #fopen($serverURL, 'r', false, $context)){
I'm not writing the rest. You can use this code I have written.
Found out the problem.
I was calling http://localhost/api, since I thought that it would load the index.php automatically, and then I was going to change the default file name for the folder.
The problem was that I didn't add index.php at the end - I should've called http://localhost/api/index.php.
This way it worked with cURL and with fopen.
Any ideas how to call the API without revealing the filename?

How to make a post request without curl?

Considering I don't want to use curl, which is a valid alternative to make a post request? Maybe Zend_http_client?
I just need the basic stuff (I need to request an url with only one post param)
You could use file_get_contents().
The PHP manual has a nice example here. This is just copy past from the manual:
$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);
you can use stream_context_create and file_get_contents
<?php
$context_options = array (
'http' => array (
'method' => 'POST',
'header'=> "Content-type: application/x-www-form-urlencoded\r\n"
. "Content-Length: " . strlen($data) . "\r\n",
'content' => $data
)
);
?>
$context = stream_context_create($context_options);
$result = file_get_contents('http://www.php.net', false, $context);
You can implement it yourself via sockets:
$url = parse_url(''); // url
$requestArray = array('var' => 'value');
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($sock, $url['host'], ((isset($url['port'])) ? $url['port'] : 80));
if (!$sock) {
throw new Exception('Connection could not be established');
}
$request = '';
if (!empty($requestArray)) {
foreach ($requestArray as $k => $v) {
if (is_array($v)) {
foreach($v as $v2) {
$request .= urlencode($k).'[]='.urlencode($v2).'&';
}
}
else {
$request .= urlencode($k).'='.urlencode($v).'&';
}
}
$request = substr($request,0,-1);
}
$data = "POST ".$url['path'].((!empty($url['query'])) ? '?'.$url['query'] : '')." HTTP/1.0\r\n"
."Host: ".$url['host']."\r\n"
."Content-type: application/x-www-form-urlencoded\r\n"
."User-Agent: PHP\r\n"
."Content-length: ".strlen($request)."\r\n"
."Connection: close\r\n\r\n"
.$request."\r\n\r\n";
socket_send($sock, $data, strlen($data), 0);
$result = '';
do {
$piece = socket_read($sock, 1024);
$result .= $piece;
}
while($piece != '');
socket_close($sock);
// TODO: Add Header Validation for 404, 403, 401, 500 etc.
echo $result;
Of course you have to change it to fill your needs or wrap it into a function.
The simplest way if you have PHP configured with pecl_http is:
$response = http_post_data($url, $post_params_string);
The function is documented on php.net:
Documentation http://php.net/manual/en/function.http-post-data.php
Install: http://php.net/manual/en/http.install.php
PECL also provides a well documented way to handle Cookies, Redirects, Authentication etc before the POST:
http://php.net/manual/en/http.request.options.php
If you are using the Zend Framework already you should try the Zend_Http_Client you mentioned:
$client = new Zend_Http_Client($host, array(
'maxredirects' => 3,
'timeout' => 30));
$client->setMethod(Zend_Http_Client::POST);
// You might need to set some headers here
$client->setParameterPost('key', 'value');
$response = $client->request();
RESTclient is a nice little app for this: http://code.google.com/p/rest-client/

Categories