When I run curl -I http://api.stackoverflow.com/1.1/badges fro my terminal, it shows me the following headers:
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 42804
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
X-AspNetMvc-Version: 4.0
X-RateLimit-Max: 300
X-RateLimit-Current: 297
X-AspNet-Version: 4.0.30319
Set-Cookie: .ASPXBrowserOverride=; expires=Mon, 08-Oct-2012 04:29:28 GMT; path=/
Date: Tue, 09 Oct 2012 04:29:27 GMT
Yet, when I run the same cURL request through PHP, I get this:
Array
(
[url] => http://api.stackoverflow.com/1.1/badges?10102
[content_type] => application/json; charset=utf-8
[http_code] => 200
[header_size] => 277
[request_size] => 85
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 0.168343
[namelookup_time] => 0.023417
[connect_time] => 0.046293
[pretransfer_time] => 0.046365
[size_upload] => 0
[size_download] => 42804
[speed_download] => 254266
[speed_upload] => 0
[download_content_length] => 42804
[upload_content_length] => 0
[starttransfer_time] => 0.097563
[redirect_time] => 0
[certinfo] => Array
(
)
[redirect_url] =>
)
The major difference that matters to me is that when run through PHP, I do not get the Content-Encoding header, without which I do not know if the content needs to be gzip inflated or not.
Is there a way to get the Content-Encoding header, or to check for gzip compression some other way?
There is no header_response nor accept-encoding in the returned getinfo array. I thought CURLINFO_HEADER_OUT on getinfo would give response headers, but only request headers are given.
But you can get raw headers using the CURLOPT_HEADER option set to true. So I suggest you to do something less natural :
$curl = curl_init();
$opts = array (
CURLOPT_URL => 'http://api.stackoverflow.com/1.1/badges',
CURLOPT_TIMEOUT => 120,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_ENCODING => 'gzip',
CURLOPT_HEADER => true,
);
curl_setopt_array($curl, $opts);
$return = curl_exec($curl);
list($rawHeader, $response) = explode("\r\n\r\n", $return, 2);
$cutHeaders = explode("\r\n", $rawHeader);
$headers = array();
foreach ($cutHeaders as $row)
{
$cutRow = explode(":", $row, 2);
$headers[$cutRow[0]] = trim($cutRow[1]);
}
echo $headers['Content-Encoding']; // gzip
If you set CURLOPT_HEADER to true, curl returns the header alongside the body. If you're just interested in the header, you can set CURLOPT_NOBODY to true and the body is not returned (which emulates the -I flag on the command line).
This example sets just the CURLOPT_HEADER, reads the Content-Encoding header (if it is set) and uncompresses the body:
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "http://api.stackoverflow.com/1.1/badges");
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($curl);
curl_close($curl);
list($header, $body) = explode("\r\n\r\n", $response, 2);
if(preg_match('#Content-Encoding:\s+(\w+)#i', $header, $match)) {
switch (strtolower($match[1])) {
case 'gzip':
$body = gzdecode($body);
break;
case 'compress':
$body = gzuncompress($body);
break;
case 'deflate':
$body = gzdeflate($body);
break;
}
}
echo $header;
echo $body;
Disclaimer: gzdecode might not be available in your PHP-version. I've tested it with PHP 5.4.4 and it worked.
You could also install the HTTP_Request2-PEAR package which does that for you (plus you get easy access to the headers without HTTP-header parsing):
include 'HTTP/Request2.php';
$request = new HTTP_Request2('http://api.stackoverflow.com/1.1/badges',
HTTP_Request2::METHOD_GET);
$response = $request->send();
echo $response->getBody();
Related
I am calling a REST endpoint in PHP using cURL to fetch some JSON data:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
echo $result;
curl_close($ch);
It takes 2.5 seconds to fetch the data using the above code on my localhost. The same code takes around 7.5 seconds when run on the live server. When the URL is opened directly on a browser it takes only 1.5 seconds.
My question is: Why does it take so long for cURL to fetch data on the live server and how can I solve this problem?
Below is the output of curl_getinfo($ch) on the server:
Array
(
[content_type] => application/json
[http_code] => 200
[header_size] => 420
[request_size] => 113
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 7.305496
[namelookup_time] => 0.150378
[connect_time] => 0.473187
[pretransfer_time] => 0.473237
[size_upload] => 0
[size_download] => 1291504
[speed_download] => 176785
[speed_upload] => 0
[download_content_length] => -1
[upload_content_length] => 0
[starttransfer_time] => 1.787901
[redirect_time] => 0
[redirect_url] =>
[certinfo] => Array
(
)
[primary_port] => 80
[local_port] => 53962
)
I found the solution to my problem. As I had mentioned in the question, the service was loading the fastest in browsers. So, I checked the 'Request Headers' of the request in the 'Network' tab of Google Chrome Inspector. I copied those headers and used them in my cURL request in PHP. After scraping those headers I found that all I needed to do was to add an Accept-Encoding header. I passed a value of gzip like so:
curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
but setting it to an empty string also works.
curl_setopt($ch, CURLOPT_ENCODING, '');
According to the php.net manual for CURLOPT_ENCODING:
The contents of the "Accept-Encoding: " header. This enables decoding
of the response. Supported encodings are "identity", "deflate", and
"gzip". If an empty string, "", is set, a header containing all
supported encoding types is sent.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "set ur url");
curl_setopt($ch, CURLOPT_ENCODING , "gzip");
curl_setopt($ch, CURLOPT_ENCODING, '');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Please check this example
I'm trying to run an URL (which have signout functionality) through the CURL. But it is returning 302 http code. Same url when i run through the POSTMAN ( Google Chrome addon ) or POSTER ( Firefox Addon) , then it is return proper result ( {"status" : "success" } ). Any help would be greatly appreciated.
URL (JAVA APPLICATION URL) : http://website.mywebsite.com:8083/VideoBook/signout.action
MY CODE :
// Open log file
$logfh = fopen("GeoserverPHP.log", 'w') or die("can't open log file");
// Initiate cURL session
$service = "http://website.mywebsite.com:8083/VideoBook/";
$request = "signout.action";
$url = $service . $request;
$ch = curl_init($url);
// Optional settings for debugging
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_STDERR, $logfh);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_COOKIESESSION, true);
curl_setopt($ch, CURLOPT_REFERER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, true);
//Required GET request settings
// $passwordStr = "geosolutions:Geos";
// curl_setopt($ch, CURLOPT_USERPWD, $passwordStr);
//GET data
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/json"));
//GET return code
$successCode = 200;
$buffer = curl_exec($ch);
echo "CURL INFO : <BR/> " ;
print_r(curl_getinfo($ch));
echo "CURL OUTPUT : <BR/> " ;
print_r($buffer);
// Check for errors and process results
$info = curl_getinfo($ch);
if ($info['http_code'] != $successCode) {
$msgStr = "# Unsuccessful cURL request to ";
$msgStr .= $url." [". $info['http_code']. "]\n";
fwrite($logfh, $msgStr);
} else {
$msgStr = "# Successful cURL request to ".$url."\n";
fwrite($logfh, $msgStr);
}
fwrite($logfh, $buffer."\n");
curl_close($ch);
fclose($logfh);
OUTPUT IN BROWSER :
CURL INFO :
Array
(
[url] => http://website.mywebsite.com:8083/VideoBook/signout.action
[content_type] =>
[http_code] => 302
[header_size] => 254
[request_size] => 105
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 0.58976
[namelookup_time] => 0.004162
[connect_time] => 0.297276
[pretransfer_time] => 0.297328
[size_upload] => 0
[size_download] => 0
[speed_download] => 0
[speed_upload] => 0
[download_content_length] => 0
[upload_content_length] => 0
[starttransfer_time] => 0.589739
[redirect_time] => 0
[redirect_url] => https://hpecp.mywebsite.com:8443/cas/login?service=http%3A%2F%2Fwebsite.mywebsite.com%3A8083%2FVideoBook%2Flogin.action
[primary_ip] => 125.21.227.2
[certinfo] => Array
(
)
[primary_port] => 8083
[local_ip] => 10.0.0.8
[local_port] => 50710
)
CURL OUTPUT :
LOG File Details :
* Hostname was NOT found in DNS cache
* Trying 125.21.227.2...
* Connected to website.mywebsite.com (125.21.227.2) port 8083 (#0)
> GET /VideoBook/signout.action HTTP/1.1
Host: website.mywebsite.com:8083
Accept: application/json
< HTTP/1.1 302 Moved Temporarily
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Location: https://hpecp.mywebsite.com:8443/cas/login?service=http%3A%2F%2Fwebsite.mywebsite.com%3A8083%2FVideoBook%2Flogin.action
< Content-Length: 0
< Date: Tue, 20 May 2014 06:02:29 GMT
<
* Connection #0 to host website.mywebsite.com left intact
* Issue another request to this URL: 'https://hpecp.mywebsite.com:8443/cas/login?service=http%3A%2F%2Fwebsite.mywebsite.com%3A8083%2FVideoBook%2Flogin.action'
* Hostname was NOT found in DNS cache
* Trying 15.126.214.121...
* Connected to hpecp.mywebsite.com (15.126.214.121) port 8443 (#1)
* successfully set certificate verify locations:
* CAfile: none
CApath: /etc/ssl/certs
* Unknown SSL protocol error in connection to hpecp.mywebsite.com:8443
* Closing connection 1
# Unsuccessful cURL request to http://website.mywebsite.com:8083/VideoBook/signout.action [302]
try to add ssl verify false and follow location and now all set
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
//output:-
CURL INFO :
Array ( [url] => https://exampl.com:8443/cas/login?service=http%3A%2F%2Fexample%3A8083%2FVideoBook%2Flogin.action [content_type] => text/html;charset=UTF-8 [http_code] => 200 [header_size] => 593 [request_size] => 273 [filetime] => -1 [ssl_verify_result] => 18 [redirect_count] => 1 [total_time] => 3.073 [namelookup_time] => 0 [connect_time] => 0.577 [pretransfer_time] => 1.794 [size_upload] => 0 [size_download] => 8003 [speed_download] => 2604 [speed_upload] => 0 [download_content_length] => 8003 [upload_content_length] => -1 [starttransfer_time] => 2.387 [redirect_time] => 0.686 )
You so need to check auth credentials on your end
I think, adding these three parameter CURLOPT_REFERER, CURLOPT_COOKIEJAR, CURLOPT_COOKIEFILE and an valid cookie file can solve this. I didn't tested the code.
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
Do the job.
In order to log out of any kind of session, you first need to be logged in, so the service must be expecting some reference to an existing session.
Either it expects you to give it information about which user should be logged out, or it is intended to log your script out after a series of calls to other services.
What it cannot do is automatically log out the user who is accessing your page, because it has no way of seeing them. The request originates entirely on your server, and only contains the information you pass to it with CURL. Nor will you be able to give it the information a browser would have, unless your script is on the same domain, as the browser will not pass your script the cookies set by the other site.
I am using Curl in PHP to call an API.
According to their documentation, they are returning "Authentication-Callback" within the returned page's header.
It works perfectly when I paste the URL into the browser, but Curl seems to leave it out.
Here is my code
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://api.themoviedb.org/3/authentication/token/new?api_key=[MY_API_KEY]&language=en');
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$results = curl_exec($ch);
$headers = curl_getinfo($ch);
Here is the returned header
Array
(
[url] => http://api.themoviedb.org/3/authentication/token/new?api_key=[MY_API_KEY]&language=en&
[content_type] => application/json;charset=utf-8
[http_code] => 200
[header_size] => 470
[request_size] => 137
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 0.109
[namelookup_time] => 0
[connect_time] => 0.047
[pretransfer_time] => 0.047
[size_upload] => 0
[size_download] => 116
[speed_download] => 1064
[speed_upload] => 0
[download_content_length] => 116
[upload_content_length] => 0
[starttransfer_time] => 0.109
[redirect_time] => 0
[certinfo] => Array
(
)
)
As far as I can tell, everything is right. Curl returns the data that I need perfectly, just not the correct headers.
Any help is appreciated!
What you're doing right now is getting stored information about the header via curl_getinfo() which only gets the information in the OPT list on that page.
What you should do instead is to return the header and then manually separate it:
curl_setopt($ch, CURLOPT_HEADER, 1);
// The rest of your options
$output = curl_exec($ch);
// Since the end of the header is always delimited by two newlines
$output = explode("\n\n", $output, 2);
$header = $output[0];
$content = $output[1];
This is more work but will get you the real headers.
This is my code to do what phsource has suggested the headers are put into the $headers array
# Extract headers from response
preg_match_all('%HTTP/\\d\\.\\d.*?(\\r\\n|\\n){2,}%si', $curl_result, $header_matches);
$headers = preg_split('/\\r\\n/', str_replace("\r\n\r\n",'',array_pop($header_matches[0])));
# Convert headers into an associative array
if(is_array($headers))
{
foreach ($headers as $header)
{
preg_match('#(.*?)\:\s(.*)#', $header, $header_matches);
if(isset($header_matches[1]))
{
$headers[$header_matches[1]] = $header_matches[2];
$headers['lowercase'][strtolower($header_matches[1])] = $header_matches[2];
}
}
}
# Remove the headers from the response body
$curl_result = preg_replace('%HTTP/\\d\\.\\d.*?(\\r\\n|\\n){2,}%si','',$curl_result);
you may want to replace \r\n with PHP_EOL as you see fit
With every Twitter request I make, the returned HTTP headers should include X-RateLimit-Limit.
However, I seem unable to retrieve these using PHP. Can someone tell me what bone-headed mistake I've made?
I've set my curl up in the normal way and am able to successfully GET and POST requests.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE);
curl_setopt($ch, CURLOPT_VERBOSE, TRUE);
$response = curl_exec($ch);
$response_info=curl_getinfo($ch);
$erno = curl_errno($ch);
$er = curl_error($ch);
curl_close($ch);
I'm able to get some response information, like http_code
$response_info['http_code']
But this line just returns null
//Doesn't bloody work. No idea why!
$rate_limit = $response_info['X-RateLimit-Limit'];
I'm running PHP Version 5.3.10.
EDIT
This is the result of print_r($response_info);
Array
(
[url] => https://api.twitter.com/1/statuses/home_timeline.json...
[content_type] => application/json;charset=utf-8
[http_code] => 200
[header_size] => 695
[request_size] => 410
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 1.239977
[namelookup_time] => 0.007361
[connect_time] => 0.155783
[pretransfer_time] => 0.465397
[size_upload] => 0
[size_download] => 99425
[speed_download] => 80182
[speed_upload] => 0
[download_content_length] => 99425
[upload_content_length] => 0
[starttransfer_time] => 0.794829
[redirect_time] => 0
[certinfo] => Array()
[redirect_url] =>
[request_header] => GET /1/statuses/home_timeline.json... HTTP/1.1
Host: api.twitter.com
Accept: */*
)
curl_getinfo does not return the response headers, only other meta info about the request. To retrieve headers, set CURLOPT_HEADER to true. That will include the headers in the output. To separate them from the response body do:
list($headers, $body) = explode("\n\n", $response, 2);
To parse the headers, explode again:
$headers = explode("\n", $headers);
foreach ($headers as $header) {
list($key, $value) = explode(':', $header, 2);
$headers[trim($key)] = trim($value);
}
echo $headers['X-RateLimit-Limit'];
I have banged my head on this long enough. I hope someone can help me figure this out. I'm not sure anymore whether my problems are caused by cURL, php, Apache, Oracle or a brain fart.
I'm trying to post to a form on an Oracle server. By hand, I can make a GET-like url that will bring up the correct page. I want to do POST to hide the variables (and there could be a lot of them) and because the originating form's method is POST. Either way I can't get the response via my php/cURL program.
My specific questions:
The obvious one, why doesn't it work?
Why can I do the request by hand and not by program?
Why does the access.log have a GET in there?
Why is my request header being rewritten to include the
/DAD/scheme/app of the Oracle server?
Will my programming ego ever be the same?
Here's my current code:
*<?php
$error_dump = 'stderr.txt';
$error_dump_handle = fopen($error_dump,'a');
$ch = curl_init();
$url = 'http://www2.blah.com/pls/blah/blah.blaQuery';
$url_enc_fields = array(
'LAST_NAME' => 'MacBlahBlah',
'FIRST_NAME' => 'Blahberina',
'CONTAINS' => 'Y',
... and more fields ...
);
$url_enc_fields = http_build_query($url_enc_fields);
//$url = $url.'?'.$url_enc_fields; //previous GET attempt
$content_length = strlen($url_enc_fields);// number of bytes
$content_length = 'Content-Length:' . $content_length;
$headers = array(
'Request: POST ' . $url_enc_fields . 'HTTP/1.1', //An attempt to force the request
'Accept: */*',
'Content-Type: application/x-www-form-urlencoded',
'Referer:http://blah.com/pls/blah/blah.startup?code1=MM&code2=bleep',
'Expect: ',
$content_length
);
curl_setopt($ch,CURLOPT_HEADER,1);
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
curl_setopt($ch,CURLINFO_HEADER_OUT,TRUE);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,FALSE);
curl_setopt($ch,CURLOPT_FOLLOWLOCATION,TRUE); // one of many guesses
curl_setopt($ch,CURLOPT_FRESH_CONNECT,TRUE);
// NOTE: no cookies or passwords involved
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,180);
curl_setopt($ch,CURLOPT_TIMEOUT,180);
curl_setopt($ch,CURLOPT_VERBOSE,TRUE);
curl_setopt($ch,CURLOPT_STDERR,$error_dump_handle);
curl_setopt($ch,CURLOPT_ENCODING,'chunked'); // Added because the response was chunked, no difference
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST,TRUE); // Apparently futile
curl_setopt($ch,CURLOPT_POSTFIELDS,$url_enc_fields);
$postResult = curl_exec($ch);
$info = curl_getinfo($ch);
$pretty_info = print_r($info,true);
> echo '<br/><pre>'; print_r($info); print_r($url_enc_fields);
> print_r($headers);
echo '</pre>';
$now_time = getdate();$format = '-------------- %f -----------';
fprintf($error_dump_handle,$format,$now_time[0]);
fprintf($error_dump_handle,$pretty_info);
fprintf($error_dump_handle,curl_error($ch));
fclose($error_dump_handle);
curl_close($ch);
?>*
------------ Here is the current logging -------------
From my error dump:
-------------- 1323725891.000000 -----------Array
(
[url] => http://www2.blah.com/pls/blah/blah.blaQuery
[content_type] => text/html; charset=iso-8859-1
[http_code] => 404
[header_size] => 205
[request_size] => 601
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 0.203
[namelookup_time] => 0
[connect_time] => 0.078
[pretransfer_time] => 0.078
[size_upload] => 146
[size_download] => 336
[speed_download] => 1655
[speed_upload] => 719
[download_content_length] => -1
[upload_content_length] => 0
[starttransfer_time] => 0.203
[redirect_time] => 0
**[request_header] => POST /pls/blah/blah.blaQuery HTTP/1.1**
Host: blah.com
Accept-Encoding: chunked
Request: POST LAST_NAME=MacBlahBlah&FIRST_NAME=Blahberina&CONTAINS=Y&...some other fields... HTTP/1.1
Accept: */*
Content-Type: application/x-www-form-urlencoded
Referer:http://blah.com/pls/wllpub/blah.startup?code1=MM&code2=bleep
Content-Length:146
From my Apache access.log:
*##.##.##.## - - [12/Dec/2011:14:38:06 -0700] "GET /cgi-bin/mydir/mysubmit_form.php HTTP/1.1" 200 2698 "-" "Mozilla/5.0 (Windows NT 6.0; WOW64; rv:8.0) Gecko/20100101 Firefox/8.0"*
Why is it doing a GET?
The HTML code returned:
http://www2.blah.com/pls/blah/blah.blaQuery
HTTP/1.1 404 Not Found
Date: Mon, 12 Dec 2011 22:03:53 GMT
Server: Oracle-Application-Server-10g/10.1.2.2.0 Oracle-HTTP-Server
Transfer-Encoding: chunked Content-Type: text/html; charset=iso-8859-1
Not Found
The requested URL pls/blah/blah.blaQuery was not found on this server.
Oracle-Application-Server-10g/10.1.2.2.0 Oracle-HTTP-Server Server at www2 Port 80
try
$fields = array(
'LAST_NAME' => 'MacBlahBlah',
'FIRST_NAME' => 'Blahberina',
'CONTAINS' => 'Y',
... and more fields ...
);
$url_enc_fields = http_build_query($fields);
and then
curl_setopt($ch,CURLOPT_POST,count($fields)); // Apparently futile
curl_setopt($ch,CURLOPT_POSTFIELDS,$url_enc_fields);
I didn't check these changes, but this is how I usually do it