How to header stream_context_create? - php

I have the following code:
$options = array(
'http' => array(
'header' => "Content-type: text/html\r\n",
'method' => 'POST'
),
);
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
This is not giving the appropriate result (no result at all), since the equivalent curl is:
function curl($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_POST, 1);
$data = curl_exec($ch);
curl_close($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo $httpcode;
return $data;
}
curl($url);
actually gives the actual result.
Since i'd like to avoid curl in production server, i'd really like the file_get_contents to work. To debug this, I have decided to examine the header for both curl and file_get_contents. In the curl code above, you can notice an echo, which prints the header:
HTTP/1.0 411 Length Required Content-Type: text/html; charset=UTF-8
Content-Length: 1564 Date: Thu, 03 Dec 2015 18:00:25 GMT Server:
GFE/2.0
I'd like to do the same for file_get_contents to examine its headers and hope fully see what is wrong. (you could point out what's wrong yourself if you like).

Something like this should work:
<?php
$url = 'http://example.com/';
$data = ''; // empty post
$options = array(
'http' => array(
'header' => "Content-type: text/html\r\nContent-Length: " . strlen($data) . "\r\n",
'method' => 'POST'
),
);
$context = stream_context_create($options);
$fp = fopen($url, 'r', false, $context);
$meta = stream_get_meta_data($fp);
if (!$fp) {
echo "Failed!";
} else {
echo "Success";
$response = stream_get_contents($fp);
}
fclose($fp);
var_dump($meta);
To get the stream meta data, you will need to switch from file_get_contents to fopen. It makes no difference as under the hood, PHP will connect and issue the response in the same way (using the http:// wrapper).
If php.ini is set to disable allow_url_fopen, the both file_get_contents and fopen will be affected and won't be able to open remote URLs. As long as this isn't the case, fopen of a URL will work the same way as file_get_contents; using fopen just gives you access to the stream which you can then call stream_get_meta_data on.

Related

API has redirecting page - PHP

I need to send data to an API using PHP. The API has a redirect page before showing the final result. The following code shows the content of the redirecting page rather than the final result. How can I wait until the final result?
$url = 'https://example.com/api';
$data = array('text' => "try");
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'GET',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
echo $result;
P.S. I got this code from one of stackoverflow's questions.
You could use cURL to get the final response, using CURLOPT_FOLLOWLOCATION:
From documentation :
CURLOPT_FOLLOWLOCATION: TRUE to follow any "Location: " header that the server sends as part of the HTTP header (note this is recursive, PHP will follow as many "Location: " headers that it is sent, unless CURLOPT_MAXREDIRS is set).
$url = 'https://example.com/api';
$data = array('text' => "try");
$full_url = $url . (strpos($url, '?') === FALSE ? '?' : '')
. http_build_query($data) ;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $full_url) ;
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-type: application/x-www-form-urlencoded',
]);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
curl_close ($ch);
var_dump($response) ;

Call another php from another domain and get the result

I'm trying to call a php from another php passing data to it and getting the return value. The two php's are on different domains.
First php:
$url = 'http://myweb.com/custom-php/createCat.php';
$data = array('name' => $name);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
echo $result;
Second php (It's on a Wordpress site):
header("Access-Control-Allow-Origin: *");
require('../wp-load.php');
$name = $_REQUEST['name'];
echo $name;
if(isset($name))
{
echo wp_create_category($name,0);
}
else
{
echo false;
}
I get the following error:
file_get_contents(http://myweb.com/custom-php/createCat.php): failed to open stream: HTTP request failed! HTTP/1.1 500 Internal Server Error
But if i access it via http://myweb.com/custom-php/createCat.php?name=test it works ok.
The request error could be because the allow_url_fopen PHP.ini directive is set off in the remote URL.
So an alternative may be using CURL:
<?php
$url = 'http://myweb.com/custom-php/createCat.php';
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, false);
$result= curl_exec($curl);
curl_close($curl);
?>
Answer to the comment 'how can i send the data i need(a variable with some text)':
Use CURLOPT_POSTFIELDS:
curl_setopt($curl, CURLOPT_POSTFIELDS, "name=test&var=" . urlencode($someText));
When you visit the url you make a get request.
You should do the same in your php:
$url = 'http://myweb.com/custom-php/createCat.php';
$data = array('name' => $name);
$result = file_get_contents($url . '?' . http_build_query($data));
echo $result;
Also, you need to check if the $_REQUEST key is set before using it:
//this header is only required for ajax..
header("Access-Control-Allow-Origin: *");
require('../wp-load.php');
if(isset($_REQUEST['name'];))
{
echo wp_create_category($_REQUEST['name'],0);
}
else
{
echo false;
}

curl fails to correctly send headers

My initial project was of checking whether a certain Apple ID exists or not, I have proceeded doing this in php by navigating to apppleid.apple.com/account/ and pretending to register an account with all the fields blank except the account field, and if I got an error it meant the account existed, otherwise If I got other errors but not an "account exists" error I would return false. However I have encountered a few problems on the way. The first was that you need to preserve all the headers/cookies on the way (which I did) but it still does not work, and apparently always answers with "1". The code can be found here : PASTEBIN. Please follow the link and try to solve this problem, I really need this done. Thank you very much whoever got some time to read this post.
EDIT
code:
<?php
require("simplehtmldom_1_5/simple_html_dom.php");
$input = get_data('https://appleid.apple.com/account');
$html = new simple_html_dom();
$html->load($input);
//echo $input;
$table = array();
foreach($html->find('input') as $inn)
{
$val = "";
try
{
$val = $inn->getAttribute('value');
}
catch (Exception $e)
{
$val = "";
}
//echo $inn->getAttribute('name') . $val . "\n";
if($inn->getAttribute('name') != "" && $inn->getAttribute('name') != "account.name")
{
$table[$inn->getAttribute("name")] = $val;
}
if($inn->getAttribute('name') == "account.name")
{
$table[$inn->getAttribute("name")] = "naclo3samuel#gmail.com";
}
}
$NIX = http_build_query($table);
//set the url, number of POST vars, POST data
$ch = curl_init();
$hs = get_headers("https://appleid.apple.com/account", 0);
$headers = $hs;
curl_setopt($ch,CURLOPT_URL, "https://appleid.apple.com/account/");
curl_setopt($ch,CURLOPT_POST, count($NIX));
curl_setopt($ch,CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch,CURLOPT_POSTFIELDS, $NIX);
//execute post
$result = curl_exec($ch);
echo $result;
//close connection
curl_close($ch);
/* gets the data from a URL */
function get_data($url) {
$ch = curl_init();
$timeout = 5000;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
?>
One of the problems is right here: get_headers("https://appleid.apple.com/account", 0);
This will return something like:
[0] => HTTP/1.1 200 OK
[1] => Date: Sat, 29 May 2004 12:28:13 GMT
[2] => Server: Apache/1.3.27 (Unix) (Red-Hat/Linux)
[3] => Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
[4] => ETag: "3f80f-1b6-3e1cb03b"
[5] => Accept-Ranges: bytes
[6] => Content-Length: 438
[7] => Connection: close
[8] => Content-Type: text/html
What is cURL supposed to do with that? This is not in a format acceptable by CURLOPT_HTTPHEADER and neither headers a Server would expect from a Client request.
I suppose you are trying to stablish Cookie session. I recommend you do all that without use of get_headers() or putting your finger in the headers at all.
Enable cURL's Cookie support by setting the options CURLOPT_COOKIEJAR and CURLOPT_COOKIEFILE, make a call to https://appleid.apple.com/account to initialize your Cookies, and then do the rest.
Example:
$cookies = tmpfile();
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://appleid.apple.com/account/",
CURLOPT_COOKIEJAR => $cookies,
CURLOPT_COOKIEFILE => $cookies,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true
]);
curl_exec();
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $NIX
]);
$result = curl_exec($ch);
$hsize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
$headers = explode("\r\n", substr($result, 0, $hsize));
$result = substr($result, $hsize);

How can PHP test if a given URL returns a 403 error

How can I test whether a given URL is a 403 error?
define('HTTP_STATUS', 403);
echo var_dump(http_response_code("badURL.com"));
and
var_dump(http_response_code("bad_url.com"));
have not worked for me
http_response_code is for setting or retrieving the response status sent back to the client invoking your PHP script, it is not for making requests out to other services located somewhere on the Internet.
You can use file_get_contents to make a request to another service, then use $http_response_header to get the headers (including the HTTP response code).
function get_response_code($url) {
#file_get_contents($url);
list($version, $status, $text) = explode(' ', $http_response_header[0], 3);
return $status;
}
var_dump(get_response_code('http://badurl.com'));
This will also support all forms of URLs that file_get_contents support, including HTTPS (if compiled with SSL support).
If you want to perform a ´HEAD` request instead, to avoid having to potentially download any content (.. but which may have its own issues, where it might not return the same error code), you can either use cURL or a custom HTTP verb with file_get_contents:
file_get_contents($url,
false,
stream_context_create(array(
'http' => array(
'method' => 'HEAD'
)
)
);
Or using cURL instead:
$ch = curl_init($url);
// if you want to issue a HEAD request instead, uncomment the following
// updated from Havenard's comment - you might also want to set
// CURLOPT_SSL_VERIFYPEER to false if you don't want to verify SSL certificates.
// curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return status;
You can use cURL:
$curl = curl_init('http://badurl.com/');
curl_setopt_array($curl, array(
CURLOPT_NOBODY => true, // use HEAD method, no body data
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false
));
curl_exec($curl);
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
Not like that, certainly.
Try actually getting it:
$fp = fsockopen("badURL.com",80,$errno,$errstr,1); // 1 second timeout to prevent lag
if( !$fp) echo "Failed to connect! ".$errno." ".$errstr;
else {
fputs($fp,"HEAD / HTTP/1.0\r\nHost: badURL.com\r\n\r\n");
$line = fgets($fp); // get first line
fclose($fp); // not interested in the rest
list($version,$status,$statusText) = explode(" ",$line,3);
var_dump($status);
}

PHP cURL POST returns a 415 - Unsupported Media Type

I've got a simple PHP script that sends an HTTP POST request via cURL, and expects a json string in response (would have loved to use an existing library like pecl_http/HTTPRequest for this, but can't). The call consistently fails with a 415 error - Unsupported Media Type. I think I'm not configuring cURL correctly, but after much searching, I can't find out what I'm doing wrong. Here's some code:
class URLRequest
{
public $url;
public $headers;
public $params;
public $body;
public $expectedFormat;
public $method;
public function URLRequest($aUrl, array $aHeaders, array $aParams, $aFormat = "json", $isPost = false, $aBody = "+")
{
$this->url = $aUrl;
$this->headers = $aHeaders;
$this->params = $aParams;
$this->expectedFormat = $aFormat;
$this->method = ($isPost ? "POST" : "GET");
$this->body = $aBody;
}
public function exec()
{
$queryStr = "?";
foreach($this->params as $key=>$val)
$queryStr .= $key . "=" . $val . "&";
//trim the last '&'
$queryStr = rtrim($queryStr, "&");
$url = $this->url . $queryStr;
$request = curl_init();
curl_setopt($request, CURLOPT_URL, $url);
curl_setopt($request, CURLOPT_HEADER, 1);
curl_setopt($request, CURLOPT_HTTPHEADER, $this->headers);
curl_setopt($request, CURLOPT_RETURNTRANSFER, 1);
//curl_setopt($request, CURLOPT_SSL_VERIFYPEER, false);
if($this->method == "POST")
{
curl_setopt($request, CURLOPT_POST, 1);
curl_setopt($request, CURLOPT_POSTFIELDS, $this->body);
//this prevents an additions code 100 from getting returned
//found it in some forum - seems kind of hacky
curl_setopt($request, CURLOPT_HTTPHEADER, array("Expect:"));
}
$response = curl_exec($request);
curl_close($request);
preg_match("%(?<=HTTP/[0-9]\.[0-9] )[0-9]+%", $response, $code);
$resp = "";
if($this->expectedFormat == "json")
{
//parse response
}
elseif($this->expectedFormat == "xml")
{
//parse response
}
return $resp;
}
}
$url = "http://mydomain.com/myrestcall";
$query = array( "arg_1" => "test001",
"arg_2" => "test002",
"arg_3" => "test003");
$headers = array( "Accept-Encoding" => "gzip",
"Content-Type" => "application/json",
"Accept" => "application/json",
"custom_header_1" => "test011",
"custom_header_2" => "test012",
"custom_header_3" => "test013");
$body = array( "body_arg_1" => "test021",
"body_arg_2" => array("test022", "test023"),
"body_arg_3" => "test024");
$request = new URLRequest($url, $headers, $query, "json", true, $body);
$response = $request->exec();
...and the response:
HTTP/1.1 415 Unsupported Media Type
Server: Apache-Coyote/1.1
X-Powered-By: Servlet 2.5; JBoss-5.0/JBossWeb-2.1
Content-Type: text/html;charset=utf-8
Content-Length: 1047
Date: Mon, 18 Jun 2012 16:30:44 GMT
<html><head><title>JBoss Web/2.1.3.GA - Error report</title></head><body><h1>HTTP Status 415 - </h1><p><b>type</b> Status report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ().</u></p><h3>JBoss Web/2.1.3.GA</h3></body></html>
Any insights or ideas?
Thanks in advance!
Problem solved! Here's the issue:
Sending an associative-array of headers DOES NOT WORK with cURL. There are several forums scattered around that show examples using an associative array for headers. DON'T DO IT!
The correct way (which is also scattered around the internets, but that I'm too dense to have noticed) is to construct your header key/value pairs as strings, and pass a standard array of these strings when setting the CURLOPT_HTTPHEADER option.
So in summary,
WRONG:
$headers = array( "Accept-Encoding" => "gzip",
"Content-Type" => "application/json",
"custom_header_1" => "test011",
"custom_header_2" => "test012",
"custom_header_3" => "test013");
RIGHT:
$headers = array( "Accept-Encoding: gzip",
"Content-Type: application/json",
"custom_header_1: test011",
"custom_header_2: test012",
"custom_header_3: test013");
I hope this comes in handy to some other noble doofus down the road before they waste as much time debugging as I did.
If I had to guess, I would assume that the same rule applies to the POST body key/value pairs as well, which is why #drew010 's comment about using http_build_query() or json_encode() to stringify your message body is a great idea as well.
Thanks to everyone for your very useful comments, and for you time and consideration. In the end, a side by side comparison of the http traffic (captured via Wireshark) revealed the issue.
Thanks!
I think the problem is that you are passing an array as the CURLOPT_POSTFIELDS option. By passing an array, this forces the POST request to use multipart/form-data when the server is probably expecting application/x-www-form-urlencoded.
Try changing
curl_setopt($request, CURLOPT_POSTFIELDS, $this->body);
to
curl_setopt($request, CURLOPT_POSTFIELDS, http_build_query($this->body));
See http_build_query for more information and also this answer: My cURL request confuses some servers?
I had the same problem and I fixed changing the header.
My code:
$authorization = 'authorization: Bearer '.trim($apiKey);
$header = [
'Content-Type: application/json',
$authorization
];
curl_setopt($session, CURLOPT_HTTPHEADER, $header);
I don't know why the array function doesn't work :
curl_setopt($session, CURLOPT_HTTPHEADER, array('Content-Type:
application/json',
$authorization));
This worked for me
$data ="data";
$headers = [
"Content-Type: application/json",
"X-Content-Type-Options:nosniff",
"Accept:application/json",
"Cache-Control:no-cache"
];
$auth = $USER . ":" . $PASSWORD;
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL, $url);
curl_setopt($curl,CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl,CURLOPT_ENCODING, "");
curl_setopt($curl,CURLOPT_MAXREDIRS, 10);
curl_setopt($curl,CURLOPT_TIMEOUT, 0);
curl_setopt($curl,CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl,CURLOPT_HTTP_VERSION,CURL_HTTP_VERSION_1_1);
curl_setopt($curl,CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($curl,CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($curl, CURLOPT_USERPWD, $auth);
curl_setopt($curl,CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($curl);

Categories