Make cURL output STDERR to file (or string) - php

We're trying to debug some cURL errors on the server, and I would like to see the STDERR log. Currently, all we can see for our error is "error code: 7" and that we can't connect to target server. We have contacted the host and made special rule to open the port we need and we're even ignoring the certificate for the time being.
Still, we can't connect. I need to debug this, but I can't see any pertinent information on my end.
The lines mentioning "VERBOSE" and "STDERR" are the most important, I think. Nothing is written to $curl_log. What am I doing wrong? Following the manuals logic, this should be correct...
PHP in use:
<?php
$curl = curl_init();
$curl_log = fopen("curl.txt", 'w');
$url = "http://www.google.com";
curl_setopt_array($curl, array(
CURLOPT_URL => $url, // Our destination URL
CURLOPT_VERBOSE => 1, // Logs verbose output to STDERR
CURLOPT_STDERR => $curl_log, // Output STDERR log to file
CURLOPT_SSL_VERIFYPEER => 0, // Do not verify certificate
CURLOPT_FAILONERROR => 0, // true to fail silently for http requests > 400
CURLOPT_RETURNTRANSFER => 1 // Return data received from server
));
$output = fread($curl_log, 2048);
echo $output; // This returns nothing!
fclose($curl_log);
$response = curl_exec($curl);
//...restofscript...
?>
From PHP manual: http://php.net/manual/en/function.curl-setopt.php
CURLOPT_VERBOSE TRUE to output verbose information. Writes output to STDERR
CURLOPT_STDERR An alternative location to output errors to instead of STDERR.
It is not a permission issue either, I have set file and script permissions to 777 on server side and my local client is windows and has never cared about permission settings (it's only for dev anyway).

You are making couple mistakes in your example:
1) you have to call curl_exec() prior to reading from the "verbose log", because curl_setopt() doesn't perform any action, so nothing can be logged prior to the curl_exec().
2) you are opening $curl_log = fopen("curl.txt", 'w'); only for write, so nothing could be read, even after you write to the file and rewind the internal file pointer.
So the correct shortened code should look like:
<?php
$curl = curl_init();
$curl_log = fopen("curl.txt", 'rw'); // open file for READ and write
$url = "http://www.google.com";
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_VERBOSE => 1,
CURLOPT_STDERR => $curl_log,
CURLOPT_RETURNTRANSFER => 1
));
$response = curl_exec($curl);
rewind($curl_log);
$output= fread($curl_log, 2048);
echo "<pre>". print_r($output, 1). "</pre>";
fclose($curl_log);
// ...
?>
NOTE: verbose log could be longer than 2048 bytes, so you could "fclose" the $curl_log after curl_exec() and then read the whole file with for example file_get_contents().
In that case, the point 2) should not be considered as mistake :-)

A bit late to the party, but this page still pops up high in Google, so let's go.
It seems that CURLOPT_VERBOSE doesn't log anything if CURLINFO_HEADER_OUT is also set to TRUE.
This is a know bug in PHP (#65348), and due to reasons they decided not to fix it.

Putting al above answers together, I use this function to make a Curl Post Request with loggin to a file option:
function CURLPostRequest($url, array $post = NULL, array $options = array(), $log_file = NULL){
$defaults = array(
CURLOPT_POST => 1,
CURLOPT_HEADER => 0,
CURLOPT_URL => $url,
CURLOPT_FRESH_CONNECT => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_FORBID_REUSE => 1,
CURLOPT_TIMEOUT => 4,
CURLOPT_POSTFIELDS => http_build_query($post)
);
if (is_resource($log_file)){
$defaults[CURLOPT_VERBOSE]=1;
$defaults[CURLOPT_STDERR]=$log_file;
$defaults[CURLINFO_HEADER_OUT]=1;
}
$ch = curl_init();
curl_setopt_array($ch, ($options + $defaults));
if( ! $result = curl_exec($ch)){
throw new Exception(curl_error($ch));
}
if (is_resource($log_file)){
$info = curl_getinfo($ch);
if (isset($info['request_header'])){
fwrite($log_file, PHP_EOL.PHP_EOL.'* POST Content'.PHP_EOL.PHP_EOL);
fwrite($log_file, print_r($info['request_header'],true));
fwrite($log_file, http_build_query($post));
}
fwrite($log_file, PHP_EOL.PHP_EOL.'* Response Content'.PHP_EOL.PHP_EOL);
fwrite($log_file, $result.PHP_EOL.PHP_EOL);
}
curl_close($ch);
return $result;
}
Hope this help to someone.

I needed to close the file before being able to read it, this worked for me:
$filename = 'curl.txt';
$curl_log = fopen($filename, 'w'); // open file for write (rw, a, etc didn't help)
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_STDERR, $curl_log);
$result = curl_exec($ch);
fclose($curl_log);
$curl_log = fopen($filename, 'r'); // open file for read
$output= fread($curl_log, filesize($filename));
echo $output;
(PHP 5.6.0, Apache/2.2.15)

From php manual for function curl_setopt:
CURLOPT_FILE The file that the transfer should be written to. The default is STDOUT (the browser window).

You should put
$output = fread($curl_log, 2048);
echo $output; // This returns nothing!
fclose($curl_log);
after $response = curl_exec($curl); otherwise, file is closed during curl is executing.

Related

curl windows: the provided file handle is not writable

I have a random "hang without errors" while executing curl requests. I'm trying to detect the origin as the web server and php logs don't show any errors, so I tried to enable CURLOT_STDERR.
I have the following code:
$file = 'curl.txt';
$curl = curl_init();
$curl_log = fopen($file, 'rw');
var_export(is_writable($file));
$url = 'http://www.google.com';
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_VERBOSE => 1,
CURLOPT_STDERR => $curl_log,
CURLOPT_RETURNTRANSFER => 1
));
$response = curl_exec($curl);
rewind($curl_log);
$output= fread($curl_log, 2048);
echo '<pre>'. print_r($output, 1). '</pre>';
fclose($curl_log);
is_writable returns true, but curl execution dies with the following error:
curl_setopt_array(): the provided file handle is not writable
I'm running PHP 7.0.15 Fast CGI on a Windows Machine.
It seems the CURL user doesn't have write permissions, but I can write on that file using other PHP functions.
Thank you very much for your help hanshenrik.
var_dump(fwrite($curl_log,'test')); returned 0.
So I changed the line $curl_log = fopen($file, 'rw'); to $curl_log = fopen($file, 'a'); and problem solved.

Curl returns nothing with a function, but returns json object in terminal. How to debug?

This is the URL that I am trying to get content from:
$url = 'http://mgcash.com/api/?a=get_offers&key=13658244dad4cfb3&country=US&ua=Mozilla/5.0%20%28Macintosh;%20Intel%20Mac%20OS%20X%2010.10;%20rv:35.0%29%20Gecko/20100101%20Firefox/35.0&format=json';
So I tried file_get_contents() and that one is working fine. Then I tried this function that always worked, but not in this case.
class SimpleCurl
{
public static function get($url, $params=array())
{
$url = $url . '?' . http_build_query($params, '', '&');
$ch = curl_init();
$options = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => false
];
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}
Then I tried using terminal with following command:
curl -X GET "http://mgcash.com/api/?a=get_offers&key=13658244dad4cfb3&country=US&ua=Mozilla/5.0%20%28Macintosh;%20Intel%20Mac%20OS%20X%2010.10;%20rv:35.0%29%20Gecko/20100101%20Firefox/35.0&format=json"
And that worked. It returned correct JSON object, without any problems.
Can anyone please let me know how do you debug CURL and figure what is the problem here?
After further tests and debugging I noticed following. Since my project require JSON object I am passing that fetched CURL $content trough $json_data = json_decode($content); and it returns nothing. Blank!
But if I try to echo or print_r before it goes trough json_decode(), I am literraly getting some RAW information/text and not JSON object. What the...
You're not passing $params to the get function and your $url ends up like http://mgcash.com/api/?a=get_offers&key=13658244dad4cfb3&country=US&ua=Mozilla/5.0%20%28Macintosh;%20Intel%20Mac%20OS%20X%2010.10;%20rv:35.0%29%20Gecko/20100101%20Firefox/35.0&format=json? note the appended ?
You can change the get function to only concatenate the query string when $params is not empty, something like this:
...
if (!empty($params)){
$url = $url . '?' . http_build_query($params, '', '&');
}
You should use CURLOPT_VERBOSE to output debug information:
CURLOPT_VERBOSE - TRUE to output verbose information. Writes output to STDERR, or the file specified using CURLOPT_STDERR.
Though if you're running your script in a browser, you wouldn't see the verbose log, because by default it outputs all info to stderr (usually that output can be seen in your error.log).
So to see the logged info you should either look into your error.log, run your script in a terminal, or provide another file handler for cURL to output the log. In the most simple case you can just redirect the output to stdout as follows:
$options = [
CURLOPT_VERBOSE => true,
CURLOPT_STDERR => fopen('php://stdout', 'w'),
...
];
In this case you'd see your log in your browser. Or, alternatively, you can provide any other filename to fopen to output the log in a file.
Reference: http://php.net/manual/en/function.curl-setopt.php

curl_exec() prints the returned JSON data, won't put it into a variable

There are many such questions on Stack Overflow & elsewhere, but they all seem to be for earlier versions of PHP as their answers refer to CURLOPT_RETURNTRANSFER, open_basedir and allow_url_include.
I am using PHP 5.4.17. Here’s my code:
$curl = curl_init();
if ($curl === False)
{
die('Fatal error initiating CURL');
}
curl_setopt_array($curl,
array(CURLOPT_HTTPGET => True,
CURLOPT_RETURNTRANSFER => True,
CURLOPT_FOLLOWLOCATION => True,
CURLOPT_URL => $gatewayURL . $parameters
));
$rawJasonData = curl_exec($curl);
curl_close($curl);
if ($rawJasonData === False)
The code seems to be OK—although I will admit that this is my first time using CURL—because the returned JSON data is echoed.
I want to capture it in a variable, how do I do that (without resorting to output buffering)?
[Update] I am certain that I don't var_dump() or echo the result myself. Neither 1 instead of True, nor uppercase TRUE make any difference.
I am developing locally, but using an entry in the Windows HOST file in my URL, not localhost.
Not sure why cURL isn't working for you, but since you are just making a simple GET request, why not just do:
$rawJasonData = file_get_contents($gatewayURL.$parameters);
Likely a non issue, but:
curl_setopt_array($curl,
array(CURLOPT_HTTPGET => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_HEADER => 0,
CURLOPT_URL => $gatewayURL . $parameters));
In previous versions of PHP, I encountered significant issues with using True when setting curl options. Give 1 a shot and see what happens. This worked for me, but it could have been due to the environment I was working in. Just wanting to mention this in case you have some weird environment (like I had) that caused the most odd problems.
As for personal preference, I prefer using the following method to set options:
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_CURLOPT_HTTPGET, 1);
As for your question -- I'd remove CURLOPT_FOLLOWLOCATION as that will follow redirects and you shouldn't have any in your case.
I suspect that CURLOPT_FOLLOWLOCATION is the issue here.
The big issue I am seeing with your code is the use of the first uppercase in True and False when it should be TRUE and FALSE. Here is my refactored version of your code that should work:
$curl = curl_init();
if (!$curl) {
die('Fatal error initiating CURL');
}
$curl_options = array();
$curl_options['CURLOPT_HTTPGET'] = TRUE;
$curl_options['CURLOPT_RETURNTRANSFER'] = TRUE;
$curl_options['CURLOPT_HTTPGET'] = TRUE;
$curl_options['CURLOPT_HTTPHEADER'] = array('Content-Type: application/json', 'Accept: application/json');
$curl_options['CURLOPT_URL'] = $gatewayURL . $parameters;
curl_setopt_array($curl, $curl_options);
$rawJasonData = curl_exec($curl);
curl_close($curl);
if (!$rawJasonData)
I added CURLOPT_HTTPGET as TRUE to force GET behavior from curl as well as JSON related headers in CURLOPT_HTTPHEADER.
Past all of that you have checks that were set as === False which are a bit excessive. Simply setting a if (!$curl) { and an if (!$rawJasonData) would work as expected.
If that still somehow does not work, change the TRUE values to a 1 like this:
$curl_options = array();
$curl_options['CURLOPT_HTTPGET'] = 1;
$curl_options['CURLOPT_RETURNTRANSFER'] = 1;
$curl_options['CURLOPT_HTTPGET'] = 1;

How to get a .jpg image from external website and store it (Storing it seperate from CURL)

I am currently attempting to make a function in my class which gets data from an external server.
I am able to get the data with CURL, but I do not want to use CURL to directly store it in a file.
This is semi difficult to explain so I will show you.
This is my function for getting the image:
function getCharacterPortrait($CharID, $size){
$url = "http://image.eveonline.com/character/{$CharID}_{$size}.jpg";
$ch = curl_init($url);
curl_setopt_array($ch, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_ENCODING => "",
CURLOPT_AUTOREFERER => true,
));
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
So, what I want to do from here, is take the $data which is the raw image I presume, and store it in a .jpg in a specified file.
I have found a similar explanation for this using CURL, but CURL was used to directly store it. I would like the script that is calling the function to get the image to store the file.
Sorry if I am being a bit confusing, but I think you get the premise of what I am saying. If more explaining is needed please do say so.
How about this?
$a = implode('',#file('http://url/file.jpg'));
$h = fopen('/path/to/disk/file.jpg','wb');
fwrite($h,$a);
fclose($h);
Just write all the data cURL gave you to a file with file_put_contents() for example?
[your curl code...]
file_put_contents('localcopy.jpg', $data);
Edit:
Apparently there is also a cURL option to download to a file like:
$fp = fopen($path, 'w');
curl_setopt($ch, CURLOPT_FILE, $fp);
Found at http://www.phpriot.com/articles/download-with-curl-and-php
Use it
$url = "http://image.eveonline.com/character/{$CharID}_{$size}.jpg";
$local_path = "myfolder/{$CharID}_{$size}.jpg";
$file = file_get_contents($url);
file_put_contents($file, $local_path);

file_get_contents() for short urls

file_get_contents() doesn't read data for short urls
Example:
http://wp.me/pbZy8-1WM,
http://bit.ly/d00E2C
Please help me in handle this. OR Is there any CURL function to handle above links?
This in general works fine. If you find it doesn't do the right thing you can explicitly use a stream context:
$url = "http://bit.ly/d00E2C";
$context = stream_context_create(array('http' => array('max_redirects' => 5)));
$val = file_get_contents($url, false, $context);
should do it. No need to touch CURL for that.
On my machine, I cannot replicate your problem; I receive the page as intended. However, should the issue be with the redirect, this may solve your problem.
<?php
$opts = array(
'http' => array(
'follow_location' => 1,
'max_redirects' => 20
)
);
$context = stream_context_create($opts);
echo file_get_contents('http://wp.me/pbZy8-1WM', false, $context);
I imagine there may be a directive that toggles redirect following, but I have not yet found it. I will edit my answer should I.
What you can do is using curl with CURLOPT_FOLLOWLOCATION set to True:
$ch = curl_init("http://bit.ly/d00E2C");
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$result = curl_exec($ch);
curl_close($ch);
echo $result;

Categories