Post a file via Request Factory in Kohana - php

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.

Related

Trouble Using eBay Shopping API with PHP (GetSingleItem Request)

I have read over the documentation many times and tried solutions that I found on the internet and I am struggling to retrieve the data I want from the eBay Shopping API using the GetSingleItem request. I believe I have my headers and xml request set up correctly based on the examples in the documentation but I can't work out how to actually send the request and retrieve the xml response. Can someone help me on the next step please?
How do I actually send the request and retrieve the response?
My headers and xml request look like this:
// Create headers
$headers = array
(
'X-EBAY-API-APP-ID: ' . $app_id,
'X-EBAY-API-SITE-ID: ' . $site_id,
'X-EBAY-API-CALL-NAME: ' . $call_name,
'X-EBAY-API-VERSION: ' . $version,
'X-EBAY-API-REQUEST-ENCODING: ' . $encoding,
);
// Generate XML request
$xml_request = '<?xml version="1.0" encoding="utf-8"?>\n';
$xml_request .= '<GetSingleItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">\n';
$xml_request .= '<ItemID>283814879195</ItemID>\n';
$xml_request .= '<IncludeSelector>Details</IncludeSelector>\n';
$xml_request .= '</GetSingleItemRequest>';
What is the next step?
If it helps, this is my complete code so far that I have tried but I get "Failed to load" when I try to use simplexml_load_string. I have removed my app_id for security also:
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
function getItem($itemID) {
$endpoint = 'https://open.api.ebay.com/shopping';
$app_id = 'XXXXXXXXXXX';
$site_id = '3';
$call_name = 'GetSingleItem';
$version = '863';
$encoding = 'xml';
// Create headers to send with CURL request.
$headers = array
(
'X-EBAY-API-APP-ID: ' . $app_id,
'X-EBAY-API-SITE-ID: ' . $site_id,
'X-EBAY-API-CALL-NAME: ' . $call_name,
'X-EBAY-API-VERSION: ' . $version,
'X-EBAY-API-REQUEST-ENCODING: ' . $encoding,
);
// Generate XML request
$xml_request = '<?xml version="1.0" encoding="utf-8"?>\n';
$xml_request .= '<GetSingleItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">\n';
$xml_request .= '<ItemID>283814879195</ItemID>\n';
$xml_request .= '<IncludeSelector>Details</IncludeSelector>\n';
$xml_request .= '</GetSingleItemRequest>';
$session = curl_init($endpoint); // create a curl session
curl_setopt($session, CURLOPT_POST, true); // POST request type
curl_setopt($session, CURLOPT_HTTPHEADER, $headers); // set headers using $headers array
curl_setopt($session, CURLOPT_POSTFIELDS, $xml_request); // set the body of the POST
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // return values as a string, not to std out
$responsexml = curl_exec($session); // send the request
curl_close($session); // close the session
return $responsexml; // returns a string
}
$itemID = '283814879195';
$resp = simplexml_load_string(getItem($itemID)) or die("Failed to load");
print($resp->Item->ItemID);
?>
I was having the same issue.
I'll be posting my project on my Github publicly once I am done, so here you go.
Note that ItemID is being passed into the function. You can ignore the GET in the first bit of code if you intend on hard coding the itemID.
$ItemID = $_GET['itemid'];
itemDetails($ItemID);
Then
function itemDetails($ItemID) {
$url = 'https://open.api.ebay.com/shopping';
$app_id = '[ADD YOUR APP ID]';
$site_id = '0';
$call_name = 'GetSingleItem';
$version = '863';
$encoding = 'xml';
$xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
$xml.= "<GetSingleItemRequest xmlns=\"urn:ebay:apis:eBLBaseComponents\">";
$xml .= "<ItemID>".$ItemID."</ItemID>";
$xml .= "</GetSingleItemRequest>";
$headers = array(
'X-EBAY-API-APP-ID:'.$app_id,
'X-EBAY-API-SITE-ID:'.$site_id,
'X-EBAY-API-CALL-NAME:'.$call_name,
'X-EBAY-API-VERSION:'.$version,
'X-EBAY-API-REQUEST-ENCODING:'.$encoding,
'Content-type:text/xml;charset=utf-8'
);
$connection = curl_init();
curl_setopt($connection, CURLOPT_URL, $url);
curl_setopt($connection, CURLOPT_HTTPHEADER, $headers);
curl_setopt($connection, CURLOPT_POST, 1);
curl_setopt($connection, CURLOPT_POSTFIELDS, $xml);
curl_setopt($connection, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($connection);
echo $result;
curl_close($connection);
}
Hopefully, this helps!

How to upload an image to iNaturalist using php cURL?

Have been working on posting observation photos to iNaturalist using iNaturalist POST/observation_photos api using php cURL but I am not able to do so. Did some research and found this on github, I tried the code but got error 'status':422.
My code:
<?php
require './init.php';
if ( isset($_POST['submitfile']) )
{
// Make sure there are no upload errors
if ($_FILES['upfile']['error'] > 0)
{
die("Error uploading file...");
}
$token = $_SESSION['access_token'];
$file_path = 'c:\Users\hp\Pictures\New folder';
$suffix = 'image/jpeg';
$photo_name = $_FILES['upfile']['name'];
$inat_id = 'White Magnolia';
$boundary = rand(10,100);
$body = '';
$body .= '--' . $boundary . "\r\n";
$body .= 'Content-Disposition: form-data; name="upfile"; filename=' . basename($file_path) . "\"\r\n";
$body .= 'Content-Type: ' . $suffix . "\r\n\r\n";
$body .=file_get_contents($photo_name) . "\r\n";
$body .= '--' . $boundary . "\r\n";
$body .= 'Content-Disposition: form-data; name="observation_photo[observation_id]"' . "\r\n";
$body .= 'Content-Type: application/json' . "\r\n\r\n";
$body .= json_encode(['observation_id' => $inat_id]) . "\r\n";
$body .= '--' . $boundary . '--' . "\r\n";
$photo_payload = array('observation_photos'=>array(
'method'=>'POST',
'timeout'=>'10',
'headers'=> array(
'Authorization'=>'Bearer'.$token,
'Content-Type'=>'multipart/form-data;'
),
'body' => $body
));
$payload = json_encode($photo_payload);
print_r($payload);
echo "<hr><br>";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.inaturalist.org/v1/observation_photos?access_token=".$token);
//curl_setopt($ch, CURLOPT_URL, "https://api.inaturalist.org/v1/observations?access_token=".$token);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
$result = curl_exec($ch);
curl_close($ch);
// Print the result?
print_r($result);
}
?>
<hr>
<br>
<form action="" method="post" enctype="multipart/form-data">
Select file to upload:
<input type="file" name="upfile">
<input type="submit" value="Upload File" name="submitfile">
</form>
The error that I get while uploading image:
I spot 1 or 2 problems.
$file_path = realpath('white magnolia.jpg'); Shouldn't this be a file path (a location) rather than an actual file name?
Is it possible that your $photo_name('white magnolia.jpg') needs an underscore instead of a space? $photo_name('white_magnolia.jpg')
I'm almost certain item 1 above is your main problem, but I thought I'd point out the possibility that you might need an underscore just in case.

Reg : how to send multiple files and other post params in CURL using php

I'm trying to post a request to a REST service using curl in PHP, but it is not working. Listed below is the piece of code, I have tried.
function curl_post_data($log,$url){
$clientid= 18;
$userid = 1614;
$voicesample1filename = realpath("RecordFiles/utterance1.wav");
$voicesample2filename = realpath("RecordFiles/utterance2.wav");
$voicesample3filename = realpath("RecordFiles/utterance3.wav");
$payload['sessionid'] = '13738B27-C664-57B0-2ABF-8873914E971A';
$payload['clienid'] = $clientid;
$payload['userid'] = $userid;
$payload['type'] = 8;
$payload['action'] = 'registration';
// build multipart
$payload = http_build_query($payload);
if ( is_file($voicesample1filename) ) {
$log->LogInfo("File '" . $voicesample1filename . "' exists");
} else {
$log->LogInfo("File '" . $voicesample1filename . "' does not exists");
}
$params = "--ABC1234\r\n"
. "Content-Type: application/x-www-form-urlencoded\r\n"
. "\r\n"
. $payload . "\r\n"
. "--ABC1234\r\n"
. "Content-Type: audio/wav\r\n"
. "Content-Disposition: attachment; utterance1=\"attachment1.wav\"\r\n"
. "\r\n"
. file_get_contents($voicesample1filename) . "\r\n"
. "--ABC1234\r\n"
. "Content-Type: audio/wav\r\n"
. "Content-Disposition: attachment; utterance2=\"attachment2.wav\"\r\n"
. "\r\n"
. file_get_contents($voicesample2filename) . "\r\n"
. "--ABC1234\r\n"
. "Content-Type: audio/wav\r\n"
. "Content-Disposition: attachment; utterance3=\"attachment3.wav\"\r\n"
. "\r\n"
. file_get_contents($voicesample3filename) . "\r\n"
. "--ABC1234--";
$log->LogInfo("Request is :" .$params);
$first_newline = strpos($params, "\r\n");
$multipart_boundary = substr($params, 2, $first_newline - 2);
$request_headers = array();
$request_headers[] = 'Content-Length: ' . strlen($params);
$request_headers[] = 'Content-Type: multipart/form-data; boundary='. $multipart_boundary;
$log->LogInfo("PayLoad Array is :" .print_r($payload,true));
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
//curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($ch, CURLOPT_HTTPHEADER, $request_headers);
$reply = curl_exec($ch);
$arrayOfResult=json_decode($reply,true);
}
If I execute the code, I'm getting multipart request error.
You don't need to use the 'Content-Disposition' things manually. Curl does it automatically when it finds a file to send. You can consider the following example for this case. curl will adjust the required multipart headers if you use something similar with your code.
$params = array("name" => "some-name",
"id" => "1231",
"file1" => "#c:/temp/file1.wav",
"file2" => "#c:/temp/file2.wav"
);

Multipart PUT upload using Curl and PHP to a REST endpoint

I need to HTTP PUT a csv file and some POST fields using multipart POST with PHP and Curl to a REST API endpoint.
The contents of the file upload is stored in a variable $list. The other end point is $url.
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PUT, true);
$post = array(
//Other Post fields array
);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
$fh = fopen('php://memory', 'rw');
fwrite($fh, $list);
rewind($fh);
curl_setopt($ch, CURLOPT_INFILE, $fh);
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($list));
$response = curl_exec($ch);
The above code seems to work the only problem is that the other end point requires a specific fieldname for the file upload. How do i set a filename ?
Am i doing something wrong ?
This is the PUT format they have mentioned on API
Content-Disposition: form-data; name="list[csv]"; filename="RackMultipart20110923-63966-hfpyg"
Content-Length: 33
Content-Type: text/csv
Content-Transfer-Encoding: binary
xxxx
yyyy
zzzz
-------------MultipartPost
Content-Disposition: form-data; name="list[list_type]"
Blacklist
-------------MultipartPost--
FYI that is multipart/form-data. You will need to build the body yourself I think, I don't think cURL could be made to build that sort of request with a PUT request. However, this is not a serious problem:
<?php
function recursive_array_mpfd ($array, $separator, &$output, $prefix = '') {
// Recurses through a multidimensional array and populates $output with a
// multipart/form-data string representing the data
foreach ($array as $key => $val) {
$name = ($prefix) ? $prefix."[".$key."]" : $key;
if (is_array($val)) {
recursive_array_mpfd($val, $separator, $output, $name);
} else {
$output .= "--$separator\r\n"
. "Content-Disposition: form-data; name=\"$name\"\r\n"
. "\r\n"
. "$val\r\n";
}
}
}
// This will hold the request body string
$requestBody = '';
// We'll need a separator
$separator = '-----'.md5(microtime()).'-----';
// First add the postfields
$post = array(
//Other Post fields array
);
recursive_array_mpfd($post, $separator, $requestBody);
// Now add the file
$list = "this,is,some,csv,data"; // The content of the file
$filename = "data.csv"; // The name of the file
$requestBody .= "--$separator\r\n"
. "Content-Disposition: form-data; name=\"list[list_type]\"; filename=\"$filename\"\r\n"
. "Content-Length: ".strlen($list)."\r\n"
. "Content-Type: text/csv\r\n"
. "Content-Transfer-Encoding: binary\r\n"
. "\r\n"
. "$list\r\n";
// Terminate the body
$requestBody .= "--$separator--";
// Let's go cURLing...
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: multipart/form-data; boundary="'.$separator.'"'
));
$response = curl_exec($ch);
If you have any problems with this, try echo $requestBody; before the cURL request and make sure it looks like you expect it to.

CURL - php vs command line bash

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.

Categories