I'm trying to post to a file service with CDN translating the cli -T option to PHP code, but I don't really know what the equivalent is, or what is the corresponding code that would replicate it. I've seen a options around CURLOPT_HTTPHEADER, but that doesn't seem to work in correspondence to other headers.
The exact thing I'm trying to replicate is this:
curl -XPUT -T "test.png" -v -H "X-Auth-Token:MYTOKEN" -H"Content-Type: text/plain" "https://somecdn.com"
I think it's something like this, but I'm unsure:
$ch = curl_init();
// Set up the options
curl_setopt($ch, CURLOPT_URL, "https://mycdn.com/test.txt");
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"X-Auth-Token: mytoken",
"Content-type: text/plain"
)
);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, array("file" => "#test.txt") );
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
I'm surprised, I suppose, that -T flag doesn't have a similar curl_setopt.
So the precise question is this:
What is the proper way to replicate cURL CLI -T "test.png" in PHP?
Take into consideration as PHP 5.5 uploading file this way (#filename) is deprecated.
Also, PHP 5.5 introduces a new option/flag regarding upload process, called by CURLOPT_SAFE_UPLOAD:
TRUE to disable support for the # prefix for uploading files in
CURLOPT_POSTFIELDS, which means that values starting with # can be
safely passed as fields. CURLFile may be used for uploads instead.
Added in PHP 5.5.0 with FALSE as the default value. PHP 5.6.0 changes
the default value to TRUE.
So if you've PHP 5.5+ you must set CURLOPT_SAFE_UPLOAD (though 5.5 is false by default) to false:
curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
Another option is using the CURLFile class.
And remember: Filename MUST be absolute path.
Related
I have a method to send requests to Telegram, this function act normally as expected on my server. After transfer to costumer server I get error from Telegram: Bad Request: URL host is empty.
The data that is send through Curl is:
$data = array(
"chat_id" => "user_id",
"video" => "#/path/to/file/tested/successfully",
"caption" => "My Text"
);
And options that set for curl is as below:
curl_setopt($ch, CURLOPT_URL, 'URL/TO/TELEGRAM/API');
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0);
curl_setopt($ch, CURLOPT_TIMEOUT, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-type: multipart/form-data"));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
This code work properly on my server and I think there is a configuration that has to be set on server.
Another issue that should be related is: when I provide wrong path to the file, on first server I get expected Error Code: 3, Couldn't open file from curl but on second server I'll get Bad Request: URL host is empty again.
So maybe I can say that curl on second server can not understand that the video index is a file.
First server is dedicated, but second one is shared host (2 host tested) (Discovery 1)
First server php version was 5.5.38, but second one was 5.6 (Discovery 2)
After changing second php version to 5.5.38, it works correctly (Discovery 3)
Any help will be appreciated
in php ver 5.5 and above set curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true) and change the #/pathToFile to new \CURLFile($pathToFile).
according to php changeLog :
Uploads using the #file syntax are now only supported if the CURLOPT_SAFE_UPLOAD option is set to FALSE. CURLFile should be used instead.
turning CURLOPT_SAFE_UPLOAD to false is not best practice and deprecated
read the first comment here for more info about CURLFile.
I'm implementing an integration to an API and according to example in the documentation I need to post a file using -T/--upload-file.
curl -u "username:password" -0 –X POST -T filename.txt -H "Content-Type: text/plain" "http://url"
My solution:
$fp = fopen('/home/myFile.txt', 'rb');
curl_setopt($ch, CURLOPT_INFILE, $fp);
curl_setopt($ch, CURLOPT_INFILESIZE, filesize('/home/myFile.txt'));
The problem however is that CURLOPT_INLINE only works when using PUT, whereas the example is using POST.
I've seen the following solution but I don't think that's what I'm supposed to use since it doesn't seem to be the same thing as -T. I don't see any mention of key name in the documentation either.
curl_setopt($c, CURLOPT_POST, true);
curl_setopt($c, CURLOPT_POSTFIELDS, array('file'=>'#/home/myFile.pdf'));
Is there a way to do this properly?
If you add --libcurl code.c to your curl command line you'll see exactly which libcurl options it used, and then you'll see that CURLOPT_CUSTOMREQUEST is what you miss in your solution to emulate that command line. Ie the CURLOPT_INFILE approach will assume and default to PUT, but you can override that.
UPDATED THANKS TO ANSWERS:
Can someone point out the difference between:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_root);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, "xml"); // tried http_build_query also
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Added this, still no good
return curl_exec($ch); // returns false
and:
$curl = "curl -X POST -d 'xml' {$api_root}";
return `$curl`; // returns expected xml from server
AND/OR
More generally, are there any good breakdowns out there for conversion/reference between php's libcurl default values/headers and those of curl on the command line?
I know this is almost a dupe of curl CLI to curl PHP and CLI CURL -> PHP CURL but I'm hoping for something more definitive.
When you use backticks then PHP invokes a shell. This can be dangerous, especially when you include variables in the command. If someone has a way to influence the value of $api_root they would be able to invoke any command on your system.
Using the API is much safer and probably faster as well as the curl libraries are loaded into PHP.
As for why it's not working it seems others have answered that question :)
curl_exec returns true or false by default. You need to specify CURLOPT_RETURNTRANSFER:
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
Since curl_exec is returning false (not NULL as indicated in the original question), try using curl_error() to determine why it's returning false.
TFM (read it): curl_exec(), curl_setopt()
Edit for posterity's sake:
The OP discovered that an SSL issue was the hindrance. The both libcurl (as called through PHP) and the curl command-line do SSL peer verification for every transaction, unless the user explicitly disables it.
The likely scenario is that the shell environment is using a different CA bundle than PHP's libcurl implementation. To remedy this, set CURLOPT_CAINFO to be the same as the shell's CURL_CA_BUNDLE environment variable and then peer verification should work.
#OP: I'd be curious to know if the above suggestion is confirmed working in your case, or if there is something else different with the SSL configuration.
in your php example you are missing
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
from php manual:
curl_exec
Returns TRUE on success or FALSE on failure. However, if the CURLOPT_RETURNTRANSFER option is set, it will return the result on success, FALSE on failure.
Add this line:
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
To match the CLI version:
$curl = "curl -X POST -d 'xml' {$api_root}";
return `$curl`; // returns expected xml from server
I also needed:
// Thanks to all the answers
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// This appears to default false on CLI, true in libcurl
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
When I use linux and try upload file to remote server using this script then all is well. But if i use Windows then script not working.
Script:
$url="http://site.com/upload.php";
$post=array('image'=>'#'.getcwd().'images/image.jpg');
$this->ch=curl_init();
curl_setopt($this->ch, CURLOPT_URL, $url);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->ch, CURLOPT_TIMEOUT, 30);
curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($this->ch, CURLOPT_POST, 1);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post);
$body = curl_exec($this->ch);
echo $body; // << on Windows empty result
What am I doing wrong?
PHP 5.3
Windows 7 - not working, Ubuntu Linux 10.10 - working
If you are using Windows, your file path separator will be \ not the Linux style /.
One obvious thing to try is
$post=array('image'=>'#'.getcwd().'images\image.jpg');
And see if that works.
If you want to make your script portable so it will work on with Windows or Linux, you can use PHP's predefined constant DIRECTORY_SEPARATOR
$post=array('image'=>'#'.getcwd().'images' . DIRECTORY_SEPARATOR .'image.jpg');
Theoretically, your code should not work(i mean upload) in any, unix or windows. Consider this portion from your code:
'image'=>'#'.getcwd().'images/image.jpg'
In windows getcwd() returns F:\Work\temp
In Linux It returns /root/work/temp
So, your above code will compile like below:
Windows: 'image'=>'#F:\Work\tempimages/image.jpg'
Linux: 'image'=>'#/root/work/tempimages/image.jpg'
Since you mentioned it worked for you in linux, which means /root/work/tempimages/image.jpg somehow existed in your filesystem.
My PHP version:
Linux: PHP 5.1.6
Windows: PHP 5.3.2
You should try var_dump($body) to see what $body really contains. With the way you configured cURL, $body will contain either the response by the server or false, on failure. There is no way to differentiate between an empty response or false with echo. It's possible the request is going through just fine, and the server is just returning nothing.
However, as others have said, your file path seems invalid. getcwd() does not output a final / and you will need to add one to make the code work. Since you said it works on linux, even without the missing slash, I am wondering how it is finding your file.
I would suggest you create a path to the file relative to the PHP script that is running, or provide an absolute path and not rely on getcwd() which probably does not return what you are expecting. The value of getcwd() can be unpredictable across systems and is not very portable.
For example, if the file you are trying to POST resides in the same folder as your PHP script:
$post = array('image' => '#image.jpg'); is sufficient. If needed, provide an absolute path: $post = array('image' => '#/home/youruser/yourdomain/image.jpg');
As Terence said, if you need your code to be portable across Linux & Windows, consider using PHP's Predefined Constant DIRECTORY_SEPARATOR
$url = "http://yoursite.com/upload.php";
// images\image.jpg on Windows images/image.jpg on Linux
$post = array('image' => '#images'.DIRECTORY_SEPARATOR.'image.jpg');
$this->ch = curl_init();
curl_setopt($this->ch, CURLOPT_URL, $url);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->ch, CURLOPT_TIMEOUT, 30);
curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($this->ch, CURLOPT_POST, 1);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post);
$body = curl_exec($this->ch);
var_dump($body);
getcwd() cURL
if working with xampp
Make sure that in php.ini configuration file
Line number 952 is uncommented
i.e
if line is
;extension=php_curl.dll
then make it
extension=php_curl.dll
I think, a better approach would be:
$imgpath = implode(DIRECTORY_SEPARATOR, array(getcwd(), 'images', 'image.jpg'));
$post = array('image'=>'#'.$imgpath);
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);