PHP, curl, and raw headers - php

When using the PHP curl functions, is there anyway to see the exact raw headers that curl is sending to the server?

You can use curl_getinfo:
Before the call
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
After
$headers = curl_getinfo($ch, CURLINFO_HEADER_OUT);

<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.example.com/");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_exec($ch);
var_dump(curl_getinfo($ch,CURLINFO_HEADER_OUT));
?>
Only available in php 5.1.3
http://php.net/manual/en/function.curl-getinfo.php
You can verify that they are the same by using your console and hitting
curl http://example.com/ -I
or
curl --trace-ascii /file.txt http://example.com/

AFAIK, the PHP/CURL binding still lacks proper support for CURLOPT_DEBUGFUNCTION which is a callback from libcurl that can provide all those details.
That's the primary reason why I recommend people to work out HTTP scripting things with the curl command line tool and its --trace-ascii option FIRST, then translate that into a PHP function.

be sure to set the CURLINFO_HEADER_OUT option before making the curl_getinfo call
curl_setopt($c, CURLINFO_HEADER_OUT, true);

Related

php curl request over ssl fails abruptly

I'm running a curl request from a php script, very straight forward
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://url-here');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postvars);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
curl_close($ch);
This works fine over http but as soon as i use https code execution doesn't pass the curl_exec command and i can't see what the error is. The client side i just receive a 'Connection Reset'.
It's worth noting it does the same thing if i use https://google.com.
Also worth noting that running this from the command like works fine so seems to be an issue running from a php script.
I've added the usual CURLOPT_SSL_VERIFYPEER to false and still no joy.
The same code does however work from my local machine so seems to be isolated to the server.
It's an amazon ec2 instance if that makes any difference.
Welcome any ideas.
Many thanks
Figured this out, curl wasn't compiled with SSL. Did this and all began to work.

cURL request using socks5 proxy fails when using PHP, but it works through the command line

cURL + proxy noob here, having a hard time. I'm having trouble trying to retrieve a web page from a remote secure server via a proxy. Everything has apparently been set up correctly by a remote dev, such that the following command line instruction works and returns what we're looking for:
curl -k --socks5-hostname localhost:xxxx https://hostname/
However, the following PHP does not echo the requested webpage. Instead it echoes the error 'Couldn't resolve host name':
$proxy = 'localhost:xxxx';
$url = 'https://hostname/';
//$proxyauth = 'user:password';
$ch = curl_init();
curl_setopt($ch, CURLOPT_PROXY, $proxy);
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
//curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyauth);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_URL, $url);
$curl_scraped_page = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error)
echo $error;
elseif ($curl_scraped_page)
echo $curl_scraped_page;
If the $url is changed to a public page, such as Google, the request is successful and everyone is happy.
The connection requires an SSH tunnel if that changes anything at all. The tunnel is open and functioning, as proven by the command line request succeeding.
Is there something obvious that is being missed here?
You need to set option CURLOPT_PROXYTYPE to CURLPROXY_SOCKS5_HOSTNAME, which sadly wasn't defined in old PHP versions, circa pre-5.6; if you have earlier in but you can explicitly use its value, which is equal to 7:
curl_setopt($ch, CURLOPT_PROXYTYPE, 7);
In the option CURLOPT_PROXYTYPE you need to set CURLPROXY_SOCKS5_HOSTNAME option instead of CURLPROXY_SOCKS5.
In this case, the DNS query (for hostname resolving) will be sent to SOCKS proxy and not resolved in the local network.
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
This constant available since PHP 5.5.23 and PHP 5.6.7 and cURL 7.18.0, so you can simply use it.

Not setting host header

I have a PHP script that primes my website cache.
I'm trying to bypass the Nginx frontend and grab the headers from the Apache backend.
The following example works (via command line) :
curl -I -H "Host: example.com" 127.0.0.1
However, when I try to do the same in PHP - it does not.
$headers = array("Host: example.com");
$url = "127.0.0.1";
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 60);
curl_setopt ($ch, CURLOPT_HEADER, true);
curl_setopt ($ch, CURLOPT_NOBODY, true);
curl_setopt ($ch, CURLOPT_HTTPHEADER, $headers);
$ret = curl_exec ($ch);
curl_close ($ch);
echo "$ret";
This always returns the first website listed in my apache virtualhost files - not the website listed in the 'host' http headers.
Any idea why it works just fine via command line - but not in the php script?
I don't know if it is possible at all, however what I would try is to pass the URL at init:
$ch = curl_init($url);
And then not with curl_setopt. It's just a suggestion to test, no guarantee this helps. So more a lengthy comment.
You can also enable verbose mode and see what specifically curl sends for request headers, I have outlined this in an answer here: Bad Request. Connecting to sites via curl on host and system. This should show what is going on behind the curtain, very useful if you do not yet sniff the network traffic.
I think here is the answer.
"Do this instead:
$host = "www.example.com";
$url = "http://$host/";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
"

Enable php-curl features in ubuntu

I'm trying something with curl in php.
I read about the use of CURLOPT_VERBOSE to help debugging.
But it gives no output. I checked my phpinfo() and under cURL stands:
debug => no
I guess that is the problem here. How can I set this to yes?
I looked in php.ini and could find it.
Also no luck on google.
also no luck here: How to enable features for php-curl
I hope someone can help me!
Having a debug build of cURL isn't required for the CURLOPT_VERBOSE setting to work, but by default CURLOPT_VERBOSE information gets output to STDERR which is only visible on the console. So if you are running PHP from a browser, the verbose output isn't sent anywhere you can see.
You can set the option CURLOPT_STDERR to a file handle and the verbose output should be written there.
You should be able to do this:
$stdout = fopen('php://output', 'w+');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.example.com');
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_STDERR, $stdout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
I'm not sure if I'm encountering a PHP bug at the moment (running PHP 5.4.5 via FastCGI) because I don't see the verbose output in the browser, but if I run it from the command line I do. If I fwrite to $stdout I do see that output in the browser but still nothing from cURL so I know the handle is valid.
If you experience the same issue, here is a workaround:
$tempout = fopen('php://temp', 'w+');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.example.com');
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_STDERR, $tempout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
rewind($tempout);
$debug = stream_get_contents($tempout);
echo $debug; // the data from CURLOPT_VERBOSE
Hope that helps.

PHP cURL sending to port 8080

today I am trying to make a curl call to somesite which is listening to port 8080. However, calls like this get sent to port 80 and not 8080 instead:
$ch = curl_init();
curl_setopt($ch, CURLOPT_PORT, 8080);
curl_setopt($ch, CURLOPT_URL, 'http://somesite.tld:8080');
curl_setopt($ch, CURLOPT_POST, count($data));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$target_response = curl_exec($ch);
curl_close($ch);
am i missing something here?
Just a note, I've had this issue before because the web host I was using was blocking outbound ports aside from the standard 80 and 443 (HTTPS). So you might want to ask them or do general tests. In fact, some hosts often even block outbound on port 80 for security.
Simple CURL GET request: (Also added json/headers if required, to make your life easier in need)
<?php
$chTest = curl_init();
curl_setopt($chTest, CURLOPT_URL, "http://example.com:8080/?query=Hello+World");
curl_setopt($chTest, CURLOPT_HTTPHEADER, array('Content-Type: application/json; charset=utf-8', 'Accept: application/json'));
curl_setopt($chTest, CURLOPT_HEADER, true);
curl_setopt($chTest, CURLOPT_RETURNTRANSFER, true);
$curl_res_test = curl_exec($chTest);
$json_res_test = explode("\r\n", $curl_res_test);
$codeTest = curl_getinfo($chTest, CURLINFO_HTTP_CODE);
curl_close($chTest);
?>
Example POST request:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://example.com:8080');
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json; charset=utf-8', 'Accept: application/json'));
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"Hello" : "World", "Foo": "World"}');
// Set timeout to close connection. Just for not waiting long.
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$curl_res = curl_exec($ch);
?>
Charset is not a required HTTP header and so are the others, the important one is Content-Type.
For the examples I used JSON MIME type, You may use whatever you want, take a look at the link:
http://en.wikipedia.org/wiki/Internet_media_type
Make sure that the php_curl.dll extension is enabled on your php, and also that the ports are open on the target serve.
Hope this helps.
Have you tried to SSH into the server that runs this and verify the iptables rules, and/or attempt to connect via telnet to the target server?
sh
telnet somesite.tld 8080
If nothing else, it will help troubleshoot your problem and eliminate network issues.
First check that you're able to connect using something other than PHP's horrible Curl syntax:
Chrome's Postman is easy to use if you're on your local machine,
else look at using (for linux users)
curl somesite:8080
wget -qO- somesite:8080
Once you've established you can connect, then you can go about the horrible business of using PHP Curl. There are wrappers, but they're flaky that I've found.
Both Curl, Wget or similar can be very easily configured to use GET and POST methods. It's not advisible, but for more than one complicated operation using Curl I've simply given up trying to configure PHP's library correctly and simply dropped to the command line.
THERE ARE SECURITY IMPLICATIONS. You need to take great care to ensure that anything you give it, particularly if it's from a form or an external source, is appropriately escaped.
<?
//Strip out any possible non-alpha-numeric character for security
$stringToSend = preg_replace('[^a-zA-Z]', '', $stringToSend);
$return = shell_exec("curl -X POST -d $stringToSend http://example.com/path/to/resource");
Your web server is misconfigured. The code you provided works for me.
Also, your code can be simpler. Just put the URI into the init call and drop the CURLOPT_PORT and CURLOPT_URL lines:
$ch = curl_init('http://somesite.tld:8080');
Are you sure that the server you intent to join isn't firewalled? And that Selinux is disabled?
Maby you can use
--local-port [-num]
Set a preferred number or range of local port numbers to use for the connection(s). Note that port numbers by nature are a scarce resource that will be busy at times so setting this range to something too narrow might cause unnecessary connection setup failures. (Added in 7.15.2)
Source: http://curl.haxx.se/docs/manpage.html#--ftp-pasv
// Use PHP cURL to make a request to port 8080 on a server
$ch = curl_init();
curl_setopt($ch, CURLOPT_PORT, 8080);
curl_setopt($ch, CURLOPT_URL, 'http://somesite.tld:8080');
curl_setopt($ch, CURLOPT_POST, count($data));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$target_response = curl_exec($ch);
curl_close($ch);
curl_setopt($ch, CURLOPT_URL, 'http://somesite.tld:8080');
PHP cURL sending to port 8080
$ch = curl_init();
curl_setopt($ch, CURLOPT_PORT, 8080);
curl_setopt($ch, CURLOPT_URL, 'http://somesite.tld:8080');
curl_setopt($ch, CURLOPT_POST, count($data));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$target_response = curl_exec($ch);
curl_close($ch);
curl_setopt($ch, CURLOPT_URL, 'http://somesite.tld:8080');
try this option for curl
curl_setopt($ch, CURLOPT_PROXY,"localhost:8080");
or use this
curl_setopt($ch, CURLOPT_PROXY,"yourservername:8080");
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "your-domain-name");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch); `
?>

Categories