I'm using a file_get_contents to interact with an api for simple GET requests... however sometimes it throws headers signifying there's been an error. How can I get these headers and determine if there's a problem?
Php will set $http_response_header after file_get_contents which contains the response headers as an array of header lines/strings. Its not necessary to use curl if all you want is the headers responses (and probably shouldn't, some LAMP stacks still don't have cURL).
Doc on $http_response_header: http://php.net/manual/en/reserved.variables.httpresponseheader.php
Example:
file_get_contents('http://stacksocks.com');
foreach ($http_response_header as $header)
{
echo $header . "<br>\n";
}
Tips taken from post in comments:
1) The value changes with each request
made.
2) When used in methods/functions, the
current value must be passed to the
method/function. Using
$http_response_header directly in the
method/function without being assigned
a value by a function/method parameter
will result in the error message:
Notice: Undefined variable:
http_response_header
3) The array length and value
locations in the array may change
depending on the server being queried
and the response received. I'm not
sure if there are any 'absolute' value
positions in the array.
4) $http_response_header ONLY gets
populated using file_get_contents()
when using a URL and NOT a local file.
This is stated in the description when
it mentions the HTTP_wrapper.
Use curl instead of file_get_contents.
See: http://www.php.net/manual/en/curl.examples-basic.php
I imagine if your communicating with a REST Api then your actaully wanting the Http Status code returned. In which case you could do something like this:
<?php
$ch = curl_init("http://www.example.com/api/users/1");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
if(curl_getinfo($ch, CURLINFO_HTTP_CODE) == 501) {
echo 'Ops it not implemented';
}
fclose($fp);
?>
file_get_contents('http://example.com');
var_dump($http_response_header);
Related
Okay, I haven't been able to find a solution to this as of yet, and I need to start asking questions on SO so I can get my reputation up and hopefully help out others.
I am making a wordpress plugin that retrieves a json list of items from a remote site. Recently, the site added a redirecting check for a cookie.
Upon first request without the cookie, 302 headers are provided, pointing to a second page which also returns a 302 redirect pointing to the homepage. On this second page, however, the set-cookie headers are also provided, which prevents the homepage from redirecting yet again.
When I make a cURL request to a url on the site, however, it fails in a redirect loop.
Now, obviously the easiest solution would be to fix this on the remote server. It should not be implementing that redirect for api routes. But that at the moment is not an option for me.
I have found how to retrieve the set-cookie header value from a 2** code response, however I cannot seem to figure out how to access that value when 302 headers are provided, and cURL returns nothing but an error.
Is there a way to access the headers even when it reaches the maximum (20) redirects?
Is it possible to stop the execution after a set number of redirects?
How can I get this cookie's value so I can provide it in a final request?
If you use the cURL option CURLOPT_HEADER the data you get back from curl_exec will include the headers from each response, including the 302.
If you enable cookie handling in cURL, it should pick up the cookie set by the 302 response just fine unless you prefer to handle it manually.
I often do something like this when there could be multiple redirects:
$ch = curl_init($some_url_that_302_redirects);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIEFILE, ''); // enable curl cookie handling
$result = curl_exec($ch);
// $result contains the headers from each response, plus the body of the last response
$info = curl_getinfo($ch); // info will tell us how many redirects were followed
for ($i = 0; $i < intval($info['redirect_count']); ++$i) {
// get headers from each response
list($headers, $response) = explode("\r\n\r\n", $response, 2);
// DO SOMETHING WITH $headers HERE
// If there was a redirect, headers will be all headers from that response,
// including Set-Cookie headers
}
list($headers, $body) = explode("\r\n\r\n", $response, 2);
// Now $headers are the headers from the final response
// $body is the content from the final response
You already had problems before you started trying to add cookies into the mix. Doing a single redirect is bad for performance. Using a 302 response as a means of dissociating data presentation from data retrieval under HTTP/1,1 or later is bad (it works, but is a violation of the protocol - you should be using a 303 if you really must redirect).
Trying to set a cookie in a 3xx response will not work consistently across browsers. Setting a cookie in an Ajax response will not work consistently across browsers.
It should not be implementing that redirect for api routes
Maybe the people at the remote site are trying to prevent you leeching their content?
Fetch the homepage first in an iframe to populate the cookie and record a flag in your domain on the browser.
I actually found another SO question, of course after I posted, that lead me in the right direction to make this possible, HERE
I used the WebGet class to make the curl request. It has not been maintained for three years, but it still works fine.
It has a function that makes the curl request without following through on the redirect loop.
There are a lot of curl options set in that function, and curl is not returning an error in it, so I'm sure the exact solution could be simpler. HERE is a list of curl options for anyone who would like to delve deeper.
Here is how I handle each of the responses to get the final response
$w = new WebGet();
$cookie_file = 'cookie.txt';
if (!file_exists($cookie_file)) {
$cookie_file_inter = fopen($cookie_file, "w");
fclose($cookie_file_inter);
}
$w->cookieFile = $cookie_file; // must exist and be writable
$w->requestContent($url);
$headers = $w->responseHeaders;
if ($w->responseStatusCode == 302 && isset($headers['LOCATION'])) {
$w->requestContent($headers['LOCATION']);
}
if ($w->responseStatusCode == 302 && isset($headers['LOCATION'])) {
$w->requestContent($headers['LOCATION']);
}
$response = $w->cachedContent;
Of course, this is all extremely bad practice, and has severe performance implications, but there may be some rare use cases that find themselves needing to do this.
This is very basic, but I am kind of confused where I am going wrong (learning how to implement a RESTful Web Service). The context is, I have a simple simulator.php file that simulates an HTTP request to one of my local PHP files. The local PHP file (index.php) does nothing but return a variable with a value. So it's pretty much like this:
<?php
$variable = 'hello';
return $variable;
?>
and my simulator.php file has the following:
?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://localhost/kixeye/index.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$contents = curl_exec($ch);
var_dump($contents);
curl_close($ch);
?>
However, var_dump($contents) does not quite spit out the value of $variable which is being returned from index.php. I don't quite understand why not.
returning something outside of a function won't actually do anything. The cURL request you are making will return the HTML response from the requested page, so what your really want to do is echo the response rather than using return.
Just change the index.php script to this:
<?php
$variable = 'hello';
echo $variable;
?>
And your var_dump() in the second script will output hello.
The $contents variable will contain the web page being returned by the http request done with Curl. If you only need one value from index.php, just echo it, and its value will end up in $contents as a string.
If you want to retrieve several variables, you could try json encode them and then echo the result in index.php. Then you would have to do the reverse in your second script by json decoding $contents.
Alternatively, you could generate and echo valid php code in the first script, and then eval it in the second, but this is very bad practice (the use of eval is strongly discouraged).
See:
json_encode
eval
I have been messing with CURL for the past day and I cannot seem to figure out how to parse out the return data. I know I could write a REGEX to extract data from the response but it seems like there is some function I am probably missing. Here is what I would like to try and do.
I want to make POST to a different domain and get back 3 things
1. the response headers
2. the response data
3. a session cookie
Is there a way I can get those 3 things back separately? right now I just get back a plain text response with the response header and the response data. I would like to be able to do something like
$Response = curl_exec($Curl_Connection);
$ResponseData = $Response['Data'];
$ResponseHeader = $Response['Header'];
ResponseCookie = $Response['Cookie'];
Does curl provide anything like this?
As I answered:
no post data returned when requesting headers CURLOPT_HEADER. PHP CURL
Add:
curl_setopt($Curl_Connection, CURLOPT_HEADER, TRUE);
$Response = curl_exec($Curl_Connection);
$curlHeaderSize=curl_getinfo($ch,CURLINFO_HEADER_SIZE);
$ResponseData = mb_substr($result, $curlHeaderSize);
$ResponseHeader = mb_substr($result, 0, $curlHeaderSize);
preg_match_all('|Set-Cookie: (.*);|U', $ResponseHeader, $content);
$ResponseCookie = implode(';', $content[1]);
According to the curl docs:
/* TRUE to include the header in the output. */
curl_setopt($Curl_Connection, CURLOPT_HEADER, TRUE);
So the header is added to the output of curl_exec command. I've been spitting this out and I don't see any way to retrieve the header separately from the response body. It gets worse when you start reading compressed output (zipped, inflated)
On top of that, it's a one big string, not an array, so in case you you want the header in a format like for example curl_getinfo brings back an array.
The easiest is to do this:
$backend_output = curl_exec($ch);
list( $backend_response_headers, $backend_response_body)
= explode("\r\n\r\n", $backend_output, 2);
That will split those 2 up, but you end up with a string for the response header, not an array which would be so much more helpful. Now making an arrray from that isn't so evident, even with a regex as you can't split on for example something simple like /(\w)\s:(\w)/ as ':' can occur in certain fields. It would be very cool if curl would offer the headers seperately but so far as I go through the docs, it doesn't seem to be there.
Concerning your session cookies, I believe you need to use CURLOPT_COOKIESESSION = true option for that, but I have less experience on cookies as I hardly ever have the professional need to use them. Good luck
update: The headers you can parse with http://php.net/manual/en/function.http-parse-headers.php or a custom function from the user comment section if you lack pecl.
I am using the following PHP:
$xml = simplexml_load_file($request_url) or die("url not loading");
I use:
$status = $xml->Response->Status->code;
To check the status of the response. 200 bening everything is ok, carry on.
However if I get a 403 access denied error, how do I catch this in PHP so I can return a user friendly warning?
To retrieve the HTTP response code from a call to simplexml_load_file(), the only way I know is to use PHP's little known $http_response_header. This variable is automagically created as an array containing each response header separately, everytime you make a HTTP request through the HTTP wrapper. In other words, everytime you use simplexml_load_file() or file_get_contents() with a URL that starts with "http://"
You can inspect its content with a print_r() such as
$xml = #simplexml_load_file($request_url);
print_r($http_response_header);
In your case, though, you might want to retrieve the XML separately with file_get_contents() then, test whether you got a 4xx response, then if not, pass the body to simplexml_load_string(). For instance:
$response = #file_get_contents($request_url);
if (preg_match('#^HTTP/... 4..#', $http_response_header[0]))
{
// received a 4xx response
}
$xml = simplexml_load_string($response);
You'll have to use something like the cURL module or the HTTP module to fetch the file, then use the functionality provided by them to detect an HTTP error, then pass the string from them into simplexml_load_string.
I've got a simple php script to ping some of my domains using file_get_contents(), however I have checked my logs and they are not recording any get requests.
I have
$result = file_get_contents($url);
echo $url. ' pinged ok\n';
where $url for each of the domains is just a simple string of the form http://mydomain.com/, echo verifies this. Manual requests made by myself are showing.
Why would the get requests not be showing in my logs?
Actually I've got it to register the hit when I send $result to the browser. I guess this means the webserver only records browser requests? Is there any way to mimic such in php?
ok tried curl php:
// create curl resource
$ch = curl_init();
// set url
curl_setopt($ch, CURLOPT_URL, "getcorporate.co.nr");
//return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// $output contains the output string
$output = curl_exec($ch);
// close curl resource to free up system resources
curl_close($ch);
same effect though - no hit registered in logs. So far it only registers when I feed the http response back from my script to the browser. Obviously this will only work for a single request and not a bunch as is the purpose of my script.
If something else is going wrong, what debugging output can I look at?
Edit: D'oh! See comments below accepted answer for explanation of my erroneous thinking.
If the request is actually being made, it would be in the logs.
Your example code could be failing silently.
What happens if you do:
<?PHP
if ($result = file_get_contents($url)){
echo "Success";
}else{
echo "Epic Fail!";
}
If that's failing, you'll want to turn on some error reporting or logging and try to figure out why.
Note: if you're in safe mode, or otherwise have fopen url wrappers disabled, file_get_contents() will not grab a remote page. This is the most likely reason things would be failing (assuming there's not a typo in the contents of $url).
Use curl instead?
That's odd. Maybe there is some caching afoot? Have you tried changing the URL dynamically ($url = $url."?timestamp=".time() for example)?