I've read that if Guzzle cannot determine Content-Length, it will send Transfer-Encoding: Chunked headers and cURL on the back-end will handling the chunking. But I'm obviously hitting post_max_size limit. ("POST Content-Length of 524288375 bytes exceeds the limit of 8388608 bytes) when POSTing to a working uploadChunkerController. I know the upload handler (endpoint) works with smaller files. I feel I have something configured wrong with my Guzzle options. I have to set verify to false and I need to post an api_key with the request.
$client = new Client();
$fh = fopen('../storage/random-500M.pdf', 'r');
$url = 'https://local:8443/app_dev.php/_uploader/bigupload/upload';
$request = $client->request(
'POST',
$url,
[
'verify' => false,
'multipart' => [
[
'name' => 'api_key',
'contents' => 'abc123'
],
[
'name' => 'file',
'contents' => $fh,
'filename' => 'bigupload.pdf'
]
]
]
);
Editing php.ini settings is not an option nor the solution. I've found a lot of 'solutions' that appear to be for older versions of Guzzle. Am I thinking too hard about this? Is there a simpler solution?
After digging through Guzzle and cURL source code, there's no 'automatic' way for them to send 'chunks'. Headers aren't set and there's no way for them to slice up the file being sent. I've come up with my own solution using Guzzle vs raw PHP cURL calls.
/**
* #Route("/chunks", name="chunks")
*/
public function sendFileAction()
{
$jar = new \GuzzleHttp\Cookie\SessionCookieJar('SESSION_STORAGE', true);
$handler = new CurlHandler();
$stack = HandlerStack::create($handler);
$client = new Client(['cookies'=>true, 'handler' => $stack]);
$filename = 'files/huge-1gig-file.jpg';
$filesize = filesize($filename);
$fh = fopen($filename, 'r');
$chunkSize = 1024 * 2000;
$boundary = '----iCEBrkUploaderBoundary' . uniqid();
$url = 'https://localhost/app_dev.php/_uploader/bigupload/upload';
rewind($fh); // probably not necessary
while (! feof($fh)) {
$pos = ftell($fh);
$chunk = fread($fh, $chunkSize);
$calc = $pos + strlen($chunk)-1;
// Not sure if this is needed.
//if (ftell($fh) > $chunkSize) {
// $pos++;
//}
$request = $client->request(
'POST',
$url,
[
'cookies' => $jar,
'debug' => false,
'verify' => false,
'headers' => [
'Transfer-Encoding' => 'chunked',
'Accept-Encoding' => 'gzip, deflate, br',
'Accept' => 'application/json, text/javascript, */*; q=0.01',
'Connection' => 'keep-alive',
'Content-disposition' => 'attachment; filename="' . basename($filename) . '"',
'Content-length' => $calc - $pos,
'Content-Range' => 'bytes ' . $pos . '-' . $calc . '/' . $filesize
],
'multipart' => [
[
'name' => 'api_key,
'contents' => 'aaabbbcc-deff-ffed-dddd-1234567890123'
],
[
'name' => 'file',
'contents' => $chunk,
'filename' => basename($filename),
'headers' => [
'Content-Type' => 'multipart/form-data; boundary=' . $boundary
]
]
]
]
);
}
return new Response('ok', 200);
}
I hope this helps someone else out. Comments/Suggestions welcome.
Chunked transfer encoding doesn't help in this case.
It's used to provide content ASAP by sending (and generating) it by parts. It has nothing to do with size limits (like in your scenario).
The only way for you is to increase the limit on the server.
Related
I am trying to upload a string (html) to my NextCloud over the Webdav API (documentation). I have used multipart file upload, because I read that it is the normal way to achieve file uploads to the API. When I upload a file it properly creates it and I the upload goes through, but it always adds this to the file:
----------------------------371289179749834008757921
Content-Disposition: form-data; name="data"
Hello world
----------------------------371289179749834008757921--
I just want the "Hello world" part to be put into the file. This is the code I use to upload the string as a file:
function sendToNextCloud(string $fileName, string $content)
{
$client = new Client();
$headers = [
'Authorization' => 'Basic Password',
];
$options = [
'multipart' => [
[
'name' => 'file',
'contents' => $content,
'filename' => $fileName,
'headers' => [
'Content-Type' => 'multipart/form-data'
]
]
]];
$request = new \GuzzleHttp\Psr7\Request('PUT', 'nextcloud:8080/remote.php/webdav/' . $fileName, $headers);
dump($request, $options);
$res = $client->sendAsync($request, $options)->wait();
dump($res->getBody()->getContents());
if ($res->getStatusCode() == 201) {
dump('Successfully sent');
}
return "test";
}
Do I need to alter the content type in the multipart headers, set a different option or use a different way of uploading?
Thank you for your help.
I found the solution to my problem:
use GuzzleHttp\Client;
$client = new Client();
$url = "https://webdav.example.com/file.txt";
$headers = [
'Content-Type' => 'text/plain',
'Authorization' => 'Basic ' . base64_encode('username:password')
];
$contents = "This is the contents of the file";
$response = $client->put($url, [
'headers' => $headers,
'body' => $contents
]);
if ($response->getStatusCode() == 201) {
echo "File uploaded successfully";
} else {
echo "Failed to upload file";
}
This creates a file from a simple string without using multipart and just a simple PUT method.
I am trying to create Video ad Campaigns using LinkedIn API. I am using Laravel, Guzzle and I have followed steps given in documentation to upload video
Initialize Upload for Video
Upload the Video
Finalize Video Upload
On Initialization I receive success response with multiple upload Urls depending on the file size. Using these uploadUrl I am making request to upload the file chunk using Guzzle but in response it is throwing INternal server error 500. I understand it can be server error but not sure if that raised to any header, param or token.
Please help If anyone has faced similar issue and got resolved. I am sharing the response of the initialize upload and request being made using Guzzle.
Doc Link
Response of Initialize APi
{#1344 // app/Services/LinkedIn/LinkedInCampaignService.php:328
+"value": {#1324
+"uploadUrlsExpireAt": 1669664693370
+"video": "urn:li:video:C4D10AQGwksU16dn3Zw"
+"uploadInstructions": array:2 [
0 => {#1325
+"uploadUrl": "https://www.linkedin.com/dms-uploads/C4D10AQGwksU16dn3Zw/uploadedVideo?sau=aHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2FtYnJ5L2FtYnJ5LXZpZGVvLz94LWxpLWFtYnJ5LWVwPUFRTE9OS2RwQmlCOS1BQUFBWVM2bndCNTd1MTR1Yjh5bVVKQ1BERDhFcVhIN1hxcXl1OHBiM3BuUVVCLV82dng2cjZscGVkWmNJajZFZXR2c2trZ1pKM1Z2MVJwWDRxQnQ4T1Z1SWxHNGlUbk85eF9tX082dE11MHhySnhod0RmbFNzUlBvWV90b1Fjdmd0TlZUTlNOQ2RlQkZKR2Zodk8tSktkcWlGMUFpa3pDZjVveDFMcnBQbkY3TXBaYkVkdlpKQXJnMGQ4R3gxQmFZWGR2SFA4aXdtRWRGdGlrSGNLRXVTa283eDhvWnNOZXRVX3I2WVlQa2dXaC1rZlVGbkh0MnNqVW03akItLVFtaGpzX3lwYTdiaEtMd0oxRFZyaEhvUE9KeGl2eFZKSEFELWVFM2txd2tHOWlvblByVm9IMU9tM2N4NXdTMU9TLUgtbjZyMmo4aHZIMFg5ckdlNWNSQkNjdUt0RmVCRkpGMzVoYnN1ZXdCZ3k1UkdxMjdpT1ZFVWRVVUdOelpxRWRKQXlGQXlFTTgteUtwbmVQalpORnFQcFVnVHl6cG80c3hqMGo2VDl6Nlp2cWNlcE1SaDBoZDRhY2Vhc1luUHNfUTc1cWNjbFBXQ2hKclpWU2NhaktRWk9WNlAyc3ZUU190cWFNQkZ1VGtWQ2Q3a0RIY2o5VmVaam1YY3hFREdpWVQzVmM4Vy1ieDdqZFRXMHBpRk9ZcURPTndTcjJZajNBZU4tcXVmRThtQy1qMzA4eEdic3NVQ0wxTTVSZTJjVmVxOS1pbDVQWmQ2MDRXU2lBSXhhejNDM09aenZmaXYtRkRwWlBIaEdscGVCYTdadFAycGRJMXR4eUpUdzVtcFFMTExiN1o2WGNscWoybWFlWkJwUkxZU0VIZXZ0Q29qMXNSUDRrcHQ0ZFluTUw1U0J6RV9qU2ZacW1pS21SS29RcnNrYWZrcUtUY0tMV1o5ZmZKTWZvaGNHTVE2ZTlRdlBJaGJHZ3ZSSFlWdFBjd1BOOG5uSG5rXzFIcE1SWWtWeGdoTVlhQm5KVGJrWDIxaExzYVBNVHlyM2FTQnlTME54c0c2UENMX202eDN2NlBmUC1nQXo1UDZOUGkxUHRubDE2Nm92Tm5ZNHNTdWxrNDdlaGVfZ1FZcnJDalZIbGVYZW4wU0g4TGUwaDNLczFLckdsekpyY0pqMjhQa29NQUdXN1ZCdktZN0ctdFZ0T0Q1cEswTTNsMUthUUQteGxsWnpVV3JLN2V2ZmtfZnEtZWNENTR5aHpKb1FVTzVmbWhDeDVIWERjT1ZYckhlWXlqVFlpbVQ5R1ZmdU9fbkdSZWtTczZENHZ6eVljejN1S0QxVmEzY3dnTU9heWQ4S3RBaVRjMGU3ZFVPdmJaMklNUnhnUlNKQnBaTmtDaHRybGRKQlJJUjRlakdMUkxJS2FpRElRUDlzMGkwUHZhNHVPOG8%253D&pn=1&m=91877349&app=4647153&sync=0&v=beta&ut=1cmOzfpLG0Caw1"
+"lastByte": 4194303
+"firstByte": 0
}
1 => {#1345
+"uploadUrl": "https://www.linkedin.com/dms-uploads/C4D10AQGwksU16dn3Zw/uploadedVideo?sau=aHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2FtYnJ5L2FtYnJ5LXZpZGVvLz94LWxpLWFtYnJ5LWVwPUFRTE9OS2RwQmlCOS1BQUFBWVM2bndCNTd1MTR1Yjh5bVVKQ1BERDhFcVhIN1hxcXl1OHBiM3BuUVVCLV82dng2cjZscGVkWmNJajZFZXR2c2trZ1pKM1Z2MVJwWDRxQnQ4T1Z1SWxHNGlUbk85eF9tX082dE11MHhySnhod0RmbFNzUlBvWV90b1Fjdmd0TlZUTlNOQ2RlQkZKR2Zodk8tSktkcWlGMUFpa3pDZjVveDFMcnBQbkY3TXBaYkVkdlpKQXJnMGQ4R3gxQmFZWGR2SFA4aXdtRWRGdGlrSGNLRXVTa283eDhvWnNOZXRVX3I2WVlQa2dXaC1rZlVGbkh0MnNqVW03akItLVFtaGpzX3lwYTdiaEtMd0oxRFZyaEhvUE9KeGl2eFZKSEFELWVFM2txd2tHOWlvblByVm9IMU9tM2N4NXdTMU9TLUgtbjZyMmo4aHZIMFg5ckdlNWNSQkNjdUt0RmVCRkpGMzVoYnN1ZXdCZ3k1UkdxMjdpT1ZFVWRVVUdOelpxRWRKQXlGQXlFTTgteUtwbmVQalpORnFQcFVnVHl6cG80c3hqMGo2VDl6Nlp2cWNlcE1SaDBoZDRhY2Vhc1luUHNfUTc1cWNjbFBXQ2hKclpWU2NhaktRWk9WNlAyc3ZUU190cWFNQkZ1VGtWQ2Q3a0RIY2o5VmVaam1YY3hFREdpWVQzVmM4Vy1ieDdqZFRXMHBpRk9ZcURPTndTcjJZajNBZU4tcXVmRThtQy1qMzA4eEdic3NVQ0wxTTVSZTJjVmVxOS1pbDVQWmQ2MDRXU2lBSXhhejNDM09aenZmaXYtRkRwWlBIaEdscGVCYTdadFAycGRJMXR4eUpUdzVtcFFMTExiN1o2WGNscWoybWFlWkJwUkxZU0VIZXZ0Q29qMXNSUDRrcHQ0ZFluTUw1U0J6RV9qU2ZacW1pS21SS29RcnNrYWZrcUtUY0tMV1o5ZmZKTWZvaGNHTVE2ZTlRdlBJaGJHZ3ZSSFlWdFBjd1BOOG5uSG5rXzFIcE1SWWtWeGdoTVlhQm5KVGJrWDIxaExzYVBNVHlyM2FTQnlTME54c0c2UENMX202eDN2NlBmUC1nQXo1UDZOUGkxUHRubDE2Nm92Tm5ZNHNTdWxrNDdlaGVfZ1FZcnJDalZIbGVYZW4wU0g4TGUwaDNLczFLckdsekpyY0pqMjhQa29NQUdXN1ZCdktZN0ctdFZ0T0Q1cEswTTNsMUthUUQteGxsWnpVV3JLN2V2ZmtfZnEtZWNENTR5aHpKb1FVTzVmbWhDeDVIWERjT1ZYckhlWXlqVFlpbVQ5R1ZmdU9fbkdSZWtTczZENHZ6eVljejN1S0QxVmEzY3dnTU9heWQ4S3RBaVRjMGU3ZFVPdmJaMklNUnhnUlNKQnBaTmtDaHRybGRKQlJJUjRlakdMUkxJS2FpRElRUDlzMGkwUHZhNHVPOG8%253D&pn=2&m=91877349&app=4647153&sync=0&v=beta&ut=3GSFILXAS0Caw1"
+"lastByte": 5253879
+"firstByte": 4194304
}
]
+"uploadToken": ""
}
}
Calling Upload Urls
public function uploadChunkedVideo($fileName, $uploadInstructions)
{
try {
$fileHandler = fopen(storage_path('app') . '/' . $fileName, 'r');
$client = new Client();
$uploadPartIds = [];
foreach ($uploadInstructions as $instruction) {
$chunkedUpload = $client->put($instruction->uploadUrl, [
'headers' => [
'Content-Type' => 'application/octet-stream',
'Authorization' => 'Bearer ' . $this->accessToken,
'LinkedIn-Version' => config('services.linkedIn.version'),
],
'multipart' => [
[
'name' => $fileName,
'contents' => fread($fileHandler, $instruction->lastByte - $instruction->firstByte),
]
],
]);
//Push etag
$uploadPartIds[] = $chunkedUpload->getHeader('ETag')[0];
}
} catch (\GuzzleHttp\Exception\ServerException $e) {
dd($e->getResponse()->getBody()->getContents());
}
}
This worked for me.
$fileHandler = fopen(storage_path('app') . '/' . $fileName, 'r');
$client = new Client();
$uploadPartIds = [];
foreach ($uploadInstructions as $instruction) {
$chunkedUpload = $client->put($instruction->uploadUrl, [
'headers' => [
'Content-Type' => 'application/octet-stream',
'Authorization' => 'Bearer ' . $this->accessToken,
'LinkedIn-Version' => config('services.linkedIn.version'),
],
'body' => fread($fileHandler, $instruction->lastByte - $instruction->firstByte),
]);
//Push etag
$uploadPartIds[] = $chunkedUpload->getHeader('ETag')[0];
info($uploadPartIds);
}
return $uploadPartIds;
I'm using the Azure OCR Service to get the text of an image back (
https://learn.microsoft.com/de-de/azure/cognitive-services/Computer-vision/QuickStarts/PHP).
So far everything is up and running, but now I would like to use a local file instead of an already uploaded one.
$url->setQueryVariables($parameters);
$request->setMethod(HTTP_Request2::METHOD_POST);
// Request body
$request->setBody("{body}"); // Replace with the body, for example, "{"url": "http://www.example.com/images/image.jpg"}
Unfortunately I don't know how to pass the raw binary as the body of my POST request in PHP.
At first, when we refer local file, we should use 'Content-Type': 'application/octet-stream' in a header, then we can send requests that use a stream resource as the body.
Here's my working code using Guzzle for your reference:
<?php
require 'vendor/autoload.php';
$resource = fopen('./Shaki_waterfall.jpg', 'r');
$client = new \GuzzleHttp\Client();
$res = $client->request('POST', 'https://westus.api.cognitive.microsoft.com/vision/v1.0/analyze', [
'query' => [
'visualFeatures' => 'Categories',
'details' => '',
'language' => 'en'
],
'headers' => [
'Content-Type' => 'application/octet-stream',
'Ocp-Apim-Subscription-Key' => '<Ocp-Apim-Subscription-Key>'
],
'body' => $resource
]);
echo $res->getBody();
Using HTTP_Request2:
<?php
require_once 'HTTP/Request2.php';
$request = new Http_Request2('https://westus.api.cognitive.microsoft.com/vision/v1.0/analyze');
$url = $request->getUrl();
$headers = array(
'Content-Type' => 'application/octet-stream',
'Ocp-Apim-Subscription-Key' => '<Ocp-Apim-Subscription-Key>',
);
$request->setHeader($headers);
$parameters = array(
'visualFeatures' => 'Categories',
'details' => '',
'language' => 'en',
);
$url->setQueryVariables($parameters);
$request->setMethod(HTTP_Request2::METHOD_POST);
$request->setBody(fopen('./Shaki_waterfall.jpg', 'r'));
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
I am able to upload a file to an API endpoint using Postman.
I am trying to translate that into uploading a file from a form, uploading it using Laravel and posting to the endpoint using Guzzle 6.
Screenshot of how it looks in Postman (I purposely left out the POST URL)
Below is the text it generates when you click the "Generate Code" link in POSTMAN:
POST /api/file-submissions HTTP/1.1
Host: strippedhostname.com
Authorization: Basic 340r9iu34ontoeioir
Cache-Control: no-cache
Postman-Token: 6e0c3123-c07c-ce54-8ba1-0a1a402b53f1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="FileContents"; filename=""
Content-Type:
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="FileInfo"
{ "name": "_aaaa.txt", "clientNumber": "102425", "type": "Writeoff" }
----WebKitFormBoundary7MA4YWxkTrZu0gW
Below is controller function for saving the file and other info. The file uploads correctly, I am able to get the file info.
I think the problem I am having is setting the multipart and headers array with the correct data.
public function fileUploadPost(Request $request)
{
$data_posted = $request->input();
$endpoint = "/file-submissions";
$response = array();
$file = $request->file('filename');
$name = time() . '_' . $file->getClientOriginalName();
$path = base_path() .'/public_html/documents/';
$resource = fopen($file,"r") or die("File upload Problems");
$file->move($path, $name);
// { "name": "test_upload.txt", "clientNumber": "102425", "type": "Writeoff" }
$fileinfo = array(
'name' => $name,
'clientNumber' => "102425",
'type' => 'Writeoff',
);
$client = new \GuzzleHttp\Client();
$res = $client->request('POST', $this->base_api . $endpoint, [
'auth' => [env('API_USERNAME'), env('API_PASSWORD')],
'multipart' => [
[
'name' => $name,
'FileContents' => fopen($path . $name, 'r'),
'contents' => fopen($path . $name, 'r'),
'FileInfo' => json_encode($fileinfo),
'headers' => [
'Content-Type' => 'text/plain',
'Content-Disposition' => 'form-data; name="FileContents"; filename="'. $name .'"',
],
// 'contents' => $resource,
]
],
]);
if($res->getStatusCode() != 200) exit("Something happened, could not retrieve data");
$response = json_decode($res->getBody());
var_dump($response);
exit();
}
The error I am receiving, screenshot of how it displays using Laravel's debugging view:
The way you are POSTing data is wrong, hence received data is malformed.
Guzzle docs:
The value of multipart is an array of associative arrays, each
containing the following key value pairs:
name: (string, required) the form field name
contents:(StreamInterface/resource/string, required) The data to use in the
form element.
headers: (array) Optional associative array of custom headers to use with the form element.
filename: (string) Optional
string to send as the filename in the part.
Using keys out of above list and setting unnecessary headers without separating each field into one array will result in making a bad request.
$res = $client->request('POST', $this->base_api . $endpoint, [
'auth' => [ env('API_USERNAME'), env('API_PASSWORD') ],
'multipart' => [
[
'name' => 'FileContents',
'contents' => file_get_contents($path . $name),
'filename' => $name
],
[
'name' => 'FileInfo',
'contents' => json_encode($fileinfo)
]
],
]);
$body = fopen('/path/to/file', 'r');
$r = $client->request('POST', 'http://httpbin.org/post', ['body' => $body]);
http://docs.guzzlephp.org/en/latest/quickstart.html?highlight=file
In Laravel 8 with guzzle I am using this:
The idea is that you are reading the file with fread or file_get_content, then you can use the Laravel getPathname() which points to the file in /tmp
$response = $this
->apiClient
->setUserKey($userToken)
->post(
'/some/url/to/api',
[
'multipart' => [
'name' => 'avatar',
'contents' => file_get_contents($request->file('avatar')->getPathname()),
'filename' => 'avata.' . $request->file('avatar')->getClientOriginalExtension()
]
]
);
I'm sending an API request to Box.com to get the thumbnail of a PNG image. I'm using Laravel. When I'm using the following code I'm getting raw string data that I want to convert PNG image.
$client = new Client('https://api.box.com/{version}/files/{file_id}', [
'version' => '2.0',
'file_id' => $id,
'request.options' => [
'headers' => [
'Authorization' => 'Bearer ' . self::getAccessToken(),
]
]
]);
$request = $client->get('thumbnail.png?min_height=256&min_width=256');
try {
$response = $request->send();
dd($response->getBody(true));
Without returning the getBody() method string I don't get anything as Box.com will be returned with the contents of the thumbnail in the body.
Here's the example string I'm getting:
b"""
‰PNG\r\n
\x1A\n
\x00\x00\x00\rIHDR\x00\x00\x01\x00\x00\x00\x01\x00\x08\x06\x00\x00\x00\r¨f\x00\x00\x00\x06bKGD\x00ÿ\x00ÿ\x00ÿ ½§“\x00\x00\x00\tpHYs\x00\x00\x00H\x00\x00\x00H\x00FÉk>\x00\x00\x00\tvpAg\x00\x00\x01\x00\x00\x00\x01\x00\x00²gÜŠ\x00\x00€\x00IDATxÚÌýiŒ-[–߇ýö\x14Ã9™y3ï}ᄅޫªî®êê2%Ñ$[à \x19¶!Y&)\x1A”iC\x10`Ø0\x04I¶õÙ\x06,\x7F0\x0F$a›0!Û0M‘¢\x04\x0E¦Dv³\x075ÙÕC©ç¡º»z¨ù½\x1AÞ|ç\x1CΉˆ=ùÃÚ\x11'ÎÉ“Ã}]2\x1C\x0Fùnæ\x19"vìØkí5ü×\x7F©Óó'\x19#)…RŠ˜\x13™ù‘Ñãoy眧ïí;²|ˆë\x0FÅö\x05óôÿ4~B©qÌ?¹ýÕŒš>¿ÿÈ{Æ£”"ç<½7~\x7F¼¿Ý×wÏ“sFk½ýZÊ \x00\x12ÞwXcpÎñcÿäGøíßü5BPüþ—¾Ž±†\x14#\x19è;O×]\x00‰¾_ã½/3¤dš²"gEŒ\x11¥ÔtÍÍØ˳ș\x10#Zk¬5[ã\x1AŸWJ2»Z),š#ÆÇPÆž¶î{3G\t\r0*•ëRÖÆZGJi\x1A_y\x13\x15ÖT\fÞ“‰h5Η¡ª\x1CÚ\x18\x19óà‰1¢†\fYAUUÔuÍ0\f[ÏDk1\x1Ac\x1C9'B\x08TUÅb± gMí\x0Eù÷þÝÿ€ÿî\x7Fï_áÃ'ï¡ŒA;M&SåŒÒzöüT¹Ç²\UùㆵôÿoÇî3»êÏÈ<Úýg‚\x14eRµ ÕÖE\x00RJ{\x05cç4Üb8EP惓Co^$“IYm>ªæ\x0F-ï\x15ÎÛ>¼}“6\n
Õü~÷)»ËBRþVY\x16f\x1CÐ\x1A\x1E<xÈ_ùË\x7F™EÓÒwkÖë\x18#\x17\x17ç\x18c\x08>\x12Ä\x18I)\x10cœÎ•\x15¨œ\x01CJyKè'eE\x16¥“5Z+Œ¶“ ŒB©õ¶\n
•û1„\\x16~Ö#Þ{¯£°§,Š8\x15Á×J¡´"%EŒ‰œå»:Éx´QXeE¦væ\x162!\x04\x08ÊU4ÖÑ…\x04Q\x06\x14É\f\fhEÉ”9Ù܇(¥ñ\x08Á³^iÛ\x03ž>{Äßø›ÿ1_{ó+üÅÿÉÿ”>\U¶Š”\x1Dz6wj:›h€<{Äó¹Ø}Ö7¥›>£§g÷9n\x12þ}r2Wƒä”ÉãDŒS¢.\vÿøûø`æ\vr÷çºÁlÞß\x7Fù¡Pä4\x1A\x14£ÕPVnÙùwÏ?*©ÛŒgßw÷Ýëí\x1F#"\x13\x08¡çøø˜¿ÿ÷ÿ.¿÷{¿‹ÖŽÓ§kúÁ£µ,ê¾ï\x19\x06Oˆ‘˜â´ÐSJò\x13#1&RÊh}yÞ)S!ceë}™¢Ë\x16€R\n
cŒì¶Jì-äûƘÉJ˜Ïáø¤2²ãÇl\x08I\x11"(•€#Îò“ˆ$\x15‰9àCOïûÙcV[\x16L\x08\x01¥ÀY+c\x18Ç]þ‹1N?ãx¼÷Ó=Ž–R\x08‘~è9;\x7FJU+\x1E?y‡ÿìïü'üÌg\x7F†E]ã»\x0E•6s²µ.ÆŸG<^c¾á]wÌç÷ÆÏd™z]~H\x19•òô÷üGM?Yþ¥<¶2WE;_«M6ãß|È&5\x7F°y:±Ñ\n
ãì¥\t™Ÿì;e\x1EM¦×l‚.\v\x14h}…rØ£¡çç¹Í1í¶;nÍüïq\x11ì;¯ì\x142“!\x052"Ø'GGü½¿÷Ÿó³?û9¾÷{¿Ÿ\x0F\x1F< ÷žÞwX+\x06X\x08\x1E\fÞ\x0FÄ\x14\x10‹xŸÂºäô\žƒ¸3æÙï£ÐUUEJi\x12<Hh£ÐFîËÚ†¾ï'ÛwŒ»°Œ(ô\x13Ï,\x08-®KR\t2h¥‘Ó)òÌÚ\x00è‡\x01¯\x03É(bH"ú9#L$£Š|¦òyKJ‰aÐ8[Íž]$„HΉõúŒÃ£CŽ\x0F\x0Fù+\x7FåÿÈK¯üUþù\x7Fñ¿Åã'OX.Ýf:)›ËölnŸ«\¿ùßÛ›ã~Ï÷*ËtRæ)m¹&›‘̧2ð\x1D·y|?å<½µ»aoddöúÓ‹Çy\À(…¾”§›È»\x03Þ½»¼{C›kŒ\x0Fø*Óyòcaï.~ÝuPÛ\x13z\e\x05°ï3û\x1Eêh2ßÖ¯Úún\n
taÍÑbÉÃ\x07ïóïü;ÿK\x16Í]#\x11c “ñƒ‡œéûž¾\x1Fd×Lž\x10â4®4w\x03r"cQJO×\x11Aß\×\x1A‡RfÚ±Æç Ôæ>1Ôuµ–õz\rdb\x1CPJÏ”Ž™¬¹5tµ\v”PjÛ]J)cŒÞ|'\e(f<ˆ•1~?¥´eam”N\x002ιò¹éœÉ8SSW\vbô(•È$BJhmq®¢®\x174®Á\x0Fž”áoüÍ¿Å\v/Üålý”¦YÈwrBa‹BS›e¦Š\x1D|źÝ]só¿s¾z³š\x1Fzwy“E\x19Í]»\rgW!_z\x1ElÄä*¹Ø\x1AÃÎÝMÚcnY>\x00Ì\x17çü{»æøü³J)2Š´õ³çØØA“ðß4Žç\x19óüßçµnæ÷–RÂ\x02Ýê”ÿè/ý%â ‹»ëÖ¬V+Ö«5Cß³Z\x08!L®À\èÈ\x19=úØåÖ·\x03•\x1A¥2"$QLp\x15ÑF¡t&\x13G\eqúŽµ\x16k\r©ëŠ¶mpÎaŒ#¥LUÕhm&!ݧ,÷í†9³ež‹{¡ËwÆu´\x11à]·qsÂm×M\\x05MŒ©Ä\x17Ƶ‚\x04\x0EÕÜòbº×\x18Å\x12\x18úu·¢®\x1DëÕ\x05ÿç¿úWyvzŠVfR®JAVâjŒëJ+0*£È¨œP)A”ŸÑ\x1CÏyg=çòy\x10{b\fHÏ~¶ærßòÞ±<ækr\x1Eó¹ÊÍÈ;nëÍk¸Ä\x00òü\v{LÏ‹ßF\x1AJ`nôÓ®\vœMç\x1Fýݙ߹{ì¾~\eÿþºÏìúúû”ÓíŽmí\x1F\x06ÏñCþÊ_ù?ñæW¿ÆA}‡¾ëI)•\x1D¿g\x18\x06Bð\fÃÀ0øiל+J¥ÔF‚Ô¾lÉÆnR\n
RÊ[Šd¾«j‹°\eŒ1²àË÷mp¶Áššº^Hl`Çú\x19M~õôžµ¶ü¾]PJQUM±Fdg\x7Fn\ WLãìy¥K\x01ÉyÌ#çqGTEð7ë'F\t¤\x06ßs~q΋/ÞãÇ~ô\x1Fó\x0FÿÁ?äèè„uwQ\x02ŸvÚu·×Æ•ÃÛz\x06ã#Ú\x08½(\x10ÚñáE™èœÐÈç2iKñl6¶¼y>;\eÞMY·<›Ã›â\x169ƒV%\x12¨•BoìÅí%¶'ò\x7F8Ì\x16Ý8˜]µ+˜i.|W(šÍw/¿öQŽ}©¿yŠlþÞüõKãʱ<#Mß_prÒð\x13?úÃüê/\x7Fžû/½N7x\x06?L»d\x08Pv©\x10\x02>xB\f¨Ùœ¥Q9•hù|wÜÝiE\x10M\x11‚0\tÿ˜\x01\x18?\eBÀûHJ\n
"""
I got the success response for image as unique string values
$response = $this->client->request('GET', '/ap/generate-example/qr/image', [
'headers' => [
'Content-Type' => 'application/json',
'user_name' => 'user_name',
'password' => 'password',
'Authorization' => "Bearer assdadga",
'width' => '300',
'height' => '300',
'imgtype' => 'jpg'
],
// 'sink' => '/uploads/images'
]);
$body = $response->getBody();
$base64 = base64_encode($body);
$mime = "image/jpeg";
$img = ('data:' . $mime . ';base64,' . $base64);
dd($img);
Output:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCADcANwBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaE
let's view this with
<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQA" />
I've figured it out myself using Guzzle3 on Laravel 5.1. Here's the relevant code which I hope you may find helpful in future:
In your model or if you prefer to use controller then it's fine:
/**
* Get download link from Box.com
*
* #param $id
* #return bool|int|string
*/
public static function getDownloadLink($id)
{
$client = new Client('https://api.box.com/{version}/files/{file_id}', [
'version' => '2.0',
'file_id' => $id,
'request.options' => [
'headers' => [
'Authorization' => 'Bearer ' . self::getAccessToken(),
]
]
]);
$request = $client->get('content');
try {
$response = $request->send();
$result = $response->getEffectiveUrl();
} catch (BadResponseException $e) {
$result = $e->getResponse()->getStatusCode();
if ($result === 401) {
self::regenerateAccessToken();
return self::getDownloadLink($id);
}
}
return count($result) ? $result : false;
}
In the above static method, I've sent a GET request to the Box.com API and the API returns with an effectiveUrl and that's the direct download file link we're looking for.