Working on a PHP script to essentially dump the results of a query into a .csv and then upload to a specific folder on our enterprise Google Docs.
The file is created and sent over to Docs just fine. However, it isn't being placed in the proper directory.
This is the function I'm using where $file, $folder, and $newtoken are strings like 'dump.csv', '0B0rVKeOmIwGXMGU2MzYyN2EtZWV...', [auth token from Google].
function insert($file, $folder, $newtoken){
$mime = "Media multipart posting\n--END_OF_PART\n";
$mime .= "Content-Type: application/atom+xml\n\n";
$xml="<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:docs=\"http://schemas.google.com/docs/2007\">
<category scheme=\"http://schemas.google.com/g/2005#kind\"
term=\"http://schemas.google.com/docs/2007#document\"/>
<title>example document</title>
<docs:writersCanInvite value=\"true\" />
</entry>
";
$mime.=$xml."\n--END_OF_PART\n";
$document = "Content-Type: text/plain\n\n";
$handle = fopen($file, "r");
$contents = fread($handle, filesize($filename));
fclose($handle);
$document.=$contents;
$itemURL = "https://docs.google.com/feeds/default/private/full";
$mime .= $document."\n--END_OF_PART--\n";
$headers = array();
$headers[] = "POST /feeds/default/private/full/folder%3A".$folder."/contents HTTP/1.1";
$headers[] = "Host: docs.google.com";
$headers[] = "GData-Version: 3.0";
$headers[] = "Authorization: GoogleLogin auth=".$newtoken."";
$headers[] = "Content-Length: ".strlen($mime);
$headers[] = "Content-Type: multipart/related; boundary=END_OF_PART";
$headers[] = "Slug: Test";
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,$itemURL);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl,CURLOPT_POSTFIELDS, $mime);
$result = curl_exec($curl);
curl_close($curl);
echo 'Response: '.$result;
}
Maybe I have the folder ID wrong (just copied from URL while viewing in Google Docs)?
Bonus: Can I manipulate the content-type headers to get Google to convert the file to a spreadsheet?
You have
$headers[] = "POST /feeds/default/private/full/folder%3A".$folder."/contents HTTP/1.1";
and then:
curl_setopt($curl,CURLOPT_URL,$itemURL);
Make up your mind. I think the first one is wrong; you can't change the URL via the CURLOPT_HTTPHEADER option. Set $itemURL to the full URL (including /feeds/default/private/full/folder%3A".$folder."/contents) and remove the first line.
Related
Im currently working with some kind of API. I have wrote simple functions which allows me to add new content, however Im stuck on uploading images.
Here's simple CURL command in documentation:
curl -v -s -u username:password \
-H "Content-Type: multipart/form-data" \
-H "Accept: application/api+json" \
-F "image=#img1.jpeg;type=image/jpeg" \
-F "image=#img2.jpeg;type=image/jpeg" \
-XPUT ''
And a sample REQUEST:
PUT /images HTTP/1.1
Host: example
Content-Type: multipart/form-data; boundary=vjrLeiXjJaWiU0JzZkUPO1rMcE2HQ-n7XsSx
--vjrLeiXjJaWiU0JzZkUPO1rMcE2HQ-n7XsSx
Content-Disposition: form-data; name="image"; filename="img1.jpg"
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
Now, there is my function:
$headers_put = array(
"Content-Type: multipart/form-data; boundary=vjrLeiXjJaWiU0JzZkUPO1rMcE2HQ-n7XsSx",
"Accept: application/+json",
);
function putImages($ch, $headers, $ad, $images){
$url = '/images';
$files = [];
foreach($images as $key => $image) {
$number = $key +1;
$paths = parse_url($image, PHP_URL_PATH);
$paths = $_SERVER['DOCUMENT_ROOT'] . $paths;
$cfile = new CURLFile(''. $paths, 'image/jpeg', 'image'.$key);
$files[$key] = $cfile;
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, $files);
$result = curl_exec($ch);
var_dump($result);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo "\n";
}
Finally, the response is:
{"errors":{"error":{"#key":"unsupported-form-element"}}}"
What Im doing wrong? Any ideas? Thank you kindly for any help.
After several approaches using curl_file_create without getting it to work. I think the mobile.de-API is just implemented badly.
I ended up implementing a custom routine for CURLOPT_POSTFIELDS that is creating the complete multipart manually. I borrowed most of the code from the PHP manpage as "The CURLFile class".
Create an array of the filenames
Create multipart header (see code below)
function curl_custom_postfields(array $files = array()) {
// build file parameters
foreach ($files as $k => $v) {
switch (true) {
case false === $v = realpath(filter_var($v)):
case !is_file($v):
case !is_readable($v):
continue; // or return false, throw new InvalidArgumentException
}
$data = file_get_contents($v);
$body[] = implode("\r\n", array(
"Content-Disposition: form-data; name=\"image\"",
"Content-Type: image/jpeg",
"",
$data,
));
}
// generate safe boundary
do {
$boundary = "---------------------" . md5(mt_rand() . microtime());
} while (preg_grep("/{$boundary}/", $body));
// add boundary for each parameters
array_walk($body, function (&$part) use ($boundary) {
$part = "--{$boundary}\r\n{$part}";
});
// add final boundary
$body[] = "--{$boundary}--";
$body[] = "";
// set options
return array(implode("\r\n", $body), $boundary);
}
Use that function ;)
$postfields = $this->curl_custom_postfields($files);
Add boundary to http header
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: multipart/form-data; boundary=' . $postfields[1], 'Accept: application/vnd.de.mobile.api+json'));
Add Postfields
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields[0]);
It's not the cleanest solution at all so please use it with care. But at least it works.
I have the same problem and found a solution but only for single images.
The trick is that your array MUST look like these:
$images = array(
'image' => 'PATH/IMG.jpg',
);
That means that the the key must be "image" and nothing other!
I hope that helps ;)
Could you help me to understand how to add new products to Volusion using the Volusion API in PHP with something like cURL?
Any useful links will be appreciated.
Make XML file in the format like this with name "myXML.txt".
<Import>
<Products>
<ProductID>360</ProductID>
<productcode>10035</productcode>
<vendor_partno>035</vendor_partno>
<productname>Asus Video Card ATI Doulat</productname>
<listprice>6.95</listprice>
<productprice>2</productprice>
<vendor_price>3.83</vendor_price>
<stockstatus>100</stockstatus>
<upc_code>99999</upc_code>
<categoryids>107,134</categoryids>
<productdescriptionshort />
<productdescription />
<productweight>0.00</productweight>
<freeshippingitem />
<minqty />
<maxqty />
</Products>
</Import>
Then copy and paste this in your editor
<?php
$file = file_get_contents('myXML.txt', true);
// Create the Xml to POST to the Webservice
$Xml_to_Send = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>";
$Xml_to_Send .= "<Volusion_API>";
// $Xml_to_Send .= "<!--";
$Xml_to_Send .= $file;
// $Xml_to_Send .= "\"\"";
// $Xml_to_Send .= "-->";
$Xml_to_Send .= "</Volusion_API>";
$url = "https://www.xxxxxusa.com/net/WebService.aspx?Login=xxxx#xxxxxxxcom.com&EncryptedPassword=0000000000000000000000000000xxxxxxxxxx&Import=Update";
// Create the Header
$header = array(
"MIME-Version: 1.0",
"Content-type: text/xml; charset=utf-8",
"Content-transfer-encoding: text",
"Request-number: 1",
"Document-type: Request",
"Interface-Version: Test 1.4"
);
// Post and Return Xml
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $Xml_to_Send);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
$data = curl_exec($ch);
// Check for Errors
if (curl_errno($ch)){
print curl_error($ch);
} else {
curl_close($ch);
}
// Display the Xml Returned on the Browser
echo $data;
?>
Remember this use your own API credential. Try this hope you got the answer.
I've been trying to use the Volusion API to import order data with no luck and support through Volusion is limited. I tend to lean towards a PHP solution, and their web site has this example for using the API for Import with php...
<?php
// Create the Xml to POST to the Webservice
$Xml_to_Send = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>";
$Xml_to_Send .= "<Volusion_API>";
$Xml_to_Send .= "<!--";
$Xml_to_Send .= " xml input file for \"\"";
$Xml_to_Send .= "-->";
$Xml_to_Send .= "</Volusion_API>";
// Create the Header
$url = "https://www.xxxxxcomusa.com/net/WebService.aspx?Login=xxxxx#xxxxcomusa.com &EncryptedPassword=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&Import=Insert";
$header = "POST".$url." HTTP/1.0 \r\n";
$header .= "MIME-Version: 1.0 \r\n";
$header .= "Content-type: text/xml; charset=utf-8 \r\n";
$header .= "Content-length: ".strlen($post_string)." \r\n";
$header .= "Content-transfer-encoding: text \r\n";
$header .= "Request-number: 1 \r\n";
$header .= "Document-type: Request \r\n";
$header .= "Interface-Version: Test 1.4 \r\n";
$header .= "Connection: close \r\n\r\n";
$header .= $Xml_to_Send;
// Post and Return Xml
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 4);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $header);
$data = curl_exec($ch);
// Check for Errors
if (curl_errno($ch)){
print curl_error($ch);
} else {
curl_close($ch);
}
// Display the Xml Returned on the Browser
echo $data;
?>
I've edited this accordingly in order to get an order updated (used "Import=Update") but there is no 'data' output on the resulting page and the record does not get updated. I am able to get data returned from the api using a similar url so I know my encrypted password is correct. I think I also determined that the line that reads...
$header = "POST".$url." HTTP/1.0 \r\n";
should read ...
$header = "POST ".$url." HTTP/1.0 \r\n";
with a space after POST but I'm still not able to successfully update a record. I was hoping someone might have had success and can share more specifics on how you were able to import an update using the Volusion API (and hopefully PHP).
Instead of trying with CUSTOMREQUEST you can use below one. It sends your headers appropriately.
First make the header as below:
$header = array(
"MIME-Version: 1.0",
"Content-type: text/xml; charset=utf-8",
"Content-transfer-encoding: text",
"Request-number: 1",
"Document-type: Request",
"Interface-Version: Test 1.4"
);
After that make your post request as below with the above header.
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $Xml_to_Send);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
Here is the code I ended up with but as I mention above it appears that Import=Update does not work with Volusion Order data, but similar code should work when trying to use the Volusion API and PHP to import. Thanks again for your help Sabuj!
<?php
$file = file_get_contents('mydir/singleorder.txt', true);
// Create the Xml to POST to the Webservice
$Xml_to_Send = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>";
$Xml_to_Send .= "<Volusion_API>";
// $Xml_to_Send .= "<!--";
$Xml_to_Send .= $file;
// $Xml_to_Send .= "\"\"";
// $Xml_to_Send .= "-->";
$Xml_to_Send .= "</Volusion_API>";
$url = "https://www.xxxxxusa.com/net/WebService.aspx?Login=xxxx#xxxxxxxcom.com&EncryptedPassword=0000000000000000000000000000xxxxxxxxxx&Import=Update";
// Create the Header
$header = array(
"MIME-Version: 1.0",
"Content-type: text/xml; charset=utf-8",
"Content-transfer-encoding: text",
"Request-number: 1",
"Document-type: Request",
"Interface-Version: Test 1.4"
);
// Post and Return Xml
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $Xml_to_Send);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
$data = curl_exec($ch);
// Check for Errors
if (curl_errno($ch)){
print curl_error($ch);
} else {
curl_close($ch);
}
// Display the Xml Returned on the Browser
echo $data;
?>
First you should echo your file.
Because I was having the same issue, the remaining code is correct but may be your file path is wrong and doesn't get by PHP so thats why the records is not inserted.
When I changed the directory path is like this..
$file = file_get_contents('singleorder.txt', true);
It will be always in the same directory.
It started work fine. So try this for solution.
Is it possible to simulate a file upload request in Kohana 3.2? I was trying the following but not having much luck:
$file = file_get_contents('../../testimage.jpg');
$request = new Request('files');
$request->method(HTTP_Request::POST);
$request->post('myfile', $file);
//$request->body($file);
$request->headers(array(
'content-type' => 'multipart/mixed;',
'content-length' => strlen($file)
));
$request->execute();
This Kohana forum post indicates that it should be possible. Given the similarity to your code, I'm guessing you already found that. As that's not working for you, you could try cURL:
$postData = array('myfile' => '#../../testimage.jpg');
$uri = 'files';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_POST, true);
$response = curl_exec($ch);
If you want to use the Kohana Request, you could try building your own multipart body using this code (I don't have the proper setup to test it right now, but it should be close to what you need):
$boundary = '---------------------' . substr(md5(rand(0,32000)), 0, 10);
$contentType = 'multipart/form-data; boundary=' . $boundary;
$eol = "\r\n";
$contents = file_get_contents('../../testimage.jpg');
$bodyData = '--' . $boundary . $eol;
$bodyData .= 'Content-Type: image/jpeg' . $eol;
$bodyData .= 'Content-Disposition: form-data; name="myfile"; filename="testimage.jpg"' . $eol;
$bodyData .= 'Content-Transfer-Encoding: binary' . $eol;
$bodyData .= $contents . $eol;
$bodyData .= '--' . $boundary . '--' . $eol . $eol;
$request = new Request('files');
$request->method(HTTP_Request::POST);
$request->headers(array('Content-Type' => $contentType));
$request->body($data);
$request->execute();
Found a pull request from GitHub that discusses the matter. I ended up adding some testing-code to my controller to get around the problem:
if ($this->request->query('unittest'))
{
// For testing, don't know how to create internal requests with files attached.
// #link http://stackoverflow.com/questions/10988622/post-a-file-via-request-factory-in-kohana
$raw_file = file_get_contents(APPPATH.'tests/test_data/sample.txt');
}
A Request::files() method would be nice tho.
From bash terminal, I successfully executed the following command.
curl -v -L -F file='#/var/www/dev/public_html/sixties.mov' -F title='my video' -F description='this is a video' -F language='eng' -F license='a2be14e1-37d9-11dd-ae16-0800200c9a66' -F country='US' http://johnuser:johnpass#website.com/api/media
Now I want to create a PHP script that uses the phpcurl library to execute an equivalent command. My code below is shown, but it's not working. The http://johnuser:johnpass#website.com/api/media server is giving me a generic error message. I'm pretty sure I'm making a mistake by not passing the right parameters or setting the right flags in my php code. Can anyone tell me what's wrong?
$url = 'http://johnuser:johnpass#website.com/api/media';
$fields = array();
$fields['file'] = '#/var/www/dev/public_html/sixties.mov';
$fields['title'] = 'my video';
$fields['description'] = 'this is a test';
$fields['language'] = 'eng';
$fields['country'] = 'US';
$fields['license'] = 'a2be14e1-37d9-11dd-ae16-0800200c9a66';
foreach($fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
rtrim($fields_string,'&');
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST,count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
//execute post
$result = curl_exec($ch);
//close connection
curl_close($ch);
print_r($result);
The error message I got is {"status":{"message":"typeMismatch ","error":true,"code":500}}
I think this is what you need to be doing, if you want upload a file:
// Parameters
$url = 'http://website.com/api/media';
$username = 'johnuser';
$password = 'johnpass';
$upload_file = '/var/www/dev/public_html/sixties.mov';
// Declare a couple of arrays we will need
$fields = $headers = array();
// Standard POST fields
$fields['title'] = 'my video';
$fields['description'] = 'this is a test';
$fields['language'] = 'eng';
$fields['country'] = 'US';
$fields['license'] = 'a2be14e1-37d9-11dd-ae16-0800200c9a66';
// Boundary string for multipart message
$boundary = '--=-=-'.md5(uniqid()).rand().'-=-=--';
// Start the body with the file to be uploaded
$body = "--$boundary\r\n"
. "Content-Disposition: form-data; name=\"file\"; filename=\"".basename($upload_file)."\"\r\n"
. "Content-Type: application/octet-stream\r\n" // You should put the right MIME type here
. "\r\n"
. file_get_contents($upload_file) . "\r\n";
// Loop the fields and build the rest of the body
foreach ($fields as $name => $value) {
$body .= "--$boundary\r\n"
. "Content-Disposition: form-data; name=\"$name\"\r\n"
. "\r\n"
. "$value\r\n";
}
// Finish the body
$body .= "--$boundary--";
// Add a couple of headers
$headers[] = "Content-Type: multipart/form-data; boundary=\"$boundary\"";
$headers[] = 'Content-Length: ' . strlen($body);
$ch = curl_init();
// Set the cURL options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
// Execute post
$result = curl_exec($ch);
// Close connection
curl_close($ch);
print_r($result);
POST file uploads are done with a MIME multipart message, using the multipart/form-data sub-type.