I am now using Guzzle to send multiple files uploaded by users to another server.
From my understanding, we can send files using Guzzle by using this code:
'multipart' => [
[
'name' => 'FileContents',
'contents' => file_get_contents($path . $name),
'filename' => $name
],
[
'name' => 'FileInfo',
'contents' => json_encode($fileinfo)
]
],
However, as the number of the files uploaded may not be the same and the code above can be used to send only one file. How can I send the unknown number of files using Guzzle? Thank you very much!
It depends on the server you sending request to. Is it able to handle an array inside FileContents and FileInfo? Or something like FileContents_1, FileContents_2, FileContents_N? It depends on your server.
Anyway in Guzzle you can easily fill the array with a loop:
$multipart => []
foreach ($files as $file) {
$multipart[] = [
'name' => 'FileContents[]',
'contents' => fopen($path . $name, 'r'),
'filename' => $name
];
$multipart[] = [
'name' => 'FileInfo[]',
'contents' => json_encode($fileinfo)
]
}
P.S.
Also it's better to use fopen() instead of file_get_contents(), because you don't need to read the files in your script, only to pass them to Guzzle.
Related
I have the following Postman request for testing a third party API;
What I am trying to do is convert this into code using Laravel's HTTP class, the code i currently have is;
public function uploadToThridParty()
{
$uploadContents = [
'id' => 'this-is-my-id',
'fileUpload' => true,
'frontfile' => Storage::get('somefrontfile.jpg'),
'sideview' => Storage::get('itsasideview.png'),
];
$request = Http::withHeaders(
[
'Accept' => 'application/json',
]
);
$response = $request
->asForm()
->post(
'https://urltoupload.com/upload', $uploadContents
)
}
But every time I run this, the 3rd party API comes back with Invalid ID, even though if i use Postman with the same ID it works fine.
I cant seem to figure out where i am going wrong with my code;
As #Cbroe mention about attach file before sending post request you can make this like this example:
public function uploadToThridParty()
{
$uploadContents = [
'id' => 'this-is-my-id',
'fileUpload' => true
];
$request = Http::withHeaders(
[
'Accept' => 'application/json',
]
);
$response = $request
->attach(
'frontfile', file_get_contents(storage_path('somefrontfile.jpg')), 'somefrontfile.jpg'
)
->attach(
'sideview', file_get_contents(storage_path('itsasideview.png')), 'itsasideview.jpg'
)
->post(
'https://urltoupload.com/upload', $uploadContents
)
}
Also i think you need remove asForm method because it's override your header accept type to application/x-www-form-urlencoded that is way your exception is Invalid ID
Some third party API would require you to have the request with content type as multipart/form data
you can double check all the headers being pass on your postman request HEADERS tab and view on Hidden headers.
If you indeed need your request to be in multipart/form-data, You can use the multipart options of guzzle.
Although this doesnt seem to be on Laravel HTTP-Client docs, you can simply pass a asMultipart() method in your HTTP request
just check the /vendor/laravel/framework/src/Illuminate/Support/Facades/Http.php for full reference of HTTP client.
You can have your request like this.
public function uploadToThridParty() {
$uploadContents = [
[
'name' => 'id',
'contents' => 'this-is-my-id'
],
[
'name' => 'fileUpload',
'contents' => true
],
[
'name' => 'frontfile',
'contents' => fopen( Storage::path( 'somefrontfile.jpg' ), 'r')
],
[
'name' => 'sideview',
'contents' => fopen( Storage::path( 'itsasideview.jpg' ), 'r')
],
];
$request = Http::withHeaders(['Accept' => 'application/json']);
$response = $request->asMultipart()->post('https://urltoupload.com/upload', $uploadContents );
}
Hi I am trying to send an image. The documentation states that I can send a file using multipart/form-data.
Here is my code:
// I checked it, there really is a file.
$file = File::get(Storage::disk('local')->path('test.jpeg')) // it's the same as file_get_contents();
// Here I use the longman/telegram-bot library.
$serverResponse = Request::sendPhoto([
'chat_id' => $this->tg_user_chat_id,
'photo' => $file
]);
// Here I use Guzzle because I thought that there might be an
// error due to the longman/telegram-bot library.
$client = new Client();
$response = $client->post("https://api.telegram.org/$telegram->botToken/sendPhoto", [
'multipart' => [
[
'name' => 'photo',
'contents' => $file
],
[
'name' => 'chat_id',
'contents' => $this->tg_user_chat_id
]
]
]);
Log::info('_response', ['_' => $response->getBody()]);
Log::info(env('APP_URL') . "/storage/$url");
Log::info('response:', ['_' => $serverResponse->getResult()]);
Log::info('ok:', ['_' => $serverResponse->getOk()]);
Log::info('error_code:', ['_' => $serverResponse->getErrorCode()]);
Log::info('raw_data:', ['_' => $serverResponse->getRawData()]);
In both cases, I get this response:
{\"ok\":false,\"error_code\":400,\"description\":\"Bad Request: invalid file HTTP URL specified: Wrong URL host\"}
Other download methods (by ID and by link) work. Can anyone please point me in the right direction?
Using the php-telegram-bot
library, sendPhoto can be used like so:
<?php
require __DIR__ . '/vendor/autoload.php';
use Longman\TelegramBot\Telegram;
use Longman\TelegramBot\Request;
// File
$file = Request::encodeFile('/tmp/image.jpeg');
// Bot
$key = '859163076:something';
$telegram = new Telegram($key);
// sendPhoto
$chatId = 000001;
$serverResponse = Request::sendPhoto([
'chat_id' => $chatId,
'photo' => $file
]);
The trick is to use Request::encodeFile to read the local image.
What I have till now
Right now I have a working oauth2 authentication between a laravel user and the dropbox API. Every user can upload files to their personal folder.
The Problem
After Uploading a file with laravel with the Dropbox API v2 I can see that there is a empty (0 Bytes) file uploaded.
Used to accomplish this task:
Laravel
Guzzle
Dropbox API Library
What am I missing?
The Code
My function for processing a form looks like this:
$formFile = $request->file('fileToUpload');
$path = $formFile->getClientOriginalName();
$file = $formFile->getPathName();
$result = Dropbox::files()->upload($path, $file);
return redirect('dropboxfiles');
And my files->upload function in my Dropbox Library looks like this:
$client = new Client;
$response = $client->post("https://content.dropboxapi.com/2/files/upload", [
'headers' => [
'Authorization' => 'Bearer '.$this->getAccessToken(),
'Content-Type' => 'application/octet-stream',
'Dropbox-API-Arg' => json_encode([
'path' => $path,
'mode' => 'add',
'autorename' => true,
'mute' => true,
'strict_conflict' => false
])
],
'data-binary' => '#'.$file
]);
The file, as I said, gets uploaded successfully. Correct name, but 0 Bytes. So empty file.
Thank you so much in advance for your help!
Update
With the following code I made it work. My question is though if there is a better "Laravel-Like" Solution instead of using fopen?
$response = $client->post("https://content.dropboxapi.com/2/files/upload", [
'headers' => [
'Authorization' => 'Bearer '.$this->getAccessToken(),
'Dropbox-API-Arg' => json_encode([
'path' => $path,
'mode' => 'add',
'autorename' => true,
'mute' => true,
'strict_conflict' => false
]),
'Content-Type' => 'application/octet-stream',
],
'body' => fopen($file, "r"),
]);
How #Greg mentioned (see cross-linking reference) I was able to solve this issue by using
'body' => fopen($file, "r"),
instead of
'data-binary' => '#'.$file
This is, how Greg mentioned, because data-binary is used in Curl requests. Other HTTP Clients, like Guzzle in my case use different names.
I am trying to post image content as a parameter of the multiform request. The following code works.
$read_image = base64_encode(file_get_contents('Large.jpg'));
$client = new Client(['debug' => true ,'handler' => $stack,]);
$request = $client->Request(
'POST',
'https://mylandoapp.lndo.site/testdrive/post',
[
'multipart' =>
[
[
'name' => 'image',
'contents' => $read_image,
],
],
]
);
I am able to get the value using following code.
$data =$request->request->all();
$my_image = $data[$image];
When I try to add the file name, the image content is an empty array.
$request = $client->Request(
'POST',
'https://mylandoapp.lndo.site/testdrive/post',
[
'multipart' =>
[
[
'name' => 'image',
'contents' => $read_image,
'filename' => 'custom_filename.txt',
],
],
]);
How can I pass file name a well as file content using multiform post request?
Could be trivial, but first check that is actually a Guzzle issue and not a php memory limit issue. Base64 encoding a "Large.jpg" will triple the string length of $read_image. Check the php error log to see if your not running out of buffer length. I would try with a smaller JPEG first.
I am using "guzzlehttp/guzzle": "~6.0", and trying to post a file to an API endpoint. The file posts fine when using RequestBin but the API is not getting the header it requires. The Header is not sent to Request bin either. According to the docs, I need to do an array of associative arrays. http://docs.guzzlephp.org/en/latest/quickstart.html#post-form-requests
However, this is not working. Here's the Guzzle request:
$client = new GuzzleHttp\Client(['base_uri' => '127.0.0.1:3000']);
$response = $client->request('POST', '/process', [
'multipart' => [
[
'name' => 'file',
'contents' => $file,
'bucketName' => 'test',
'headers' => ['X-API-Key' => 'abc345']
],
]
]);
What am I doing wrong that it's not sending the header?
Thank you very much,
Josh
Headers is an $option, that's mean it must be at the same level as multipart.
<?php
$response = $client->request('POST', '/process', [
'multipart' => [
[
'name' => 'file',
'contents' => 'test',
'bucketName' => 'test',
],
],
'headers' => ['X-API-Key' => 'abc345'] // <------- HERE
]);
You were probably using multipart in conjunction with form_params , this is not explicitly explained in the documentation of laravel but guzzle won't work with both
Note
multipart cannot be used with the form_params option. You will need to
use one or the other. Use form_params for
application/x-www-form-urlencoded requests, and multipart for
multipart/form-data requests.
This option cannot be used with body, form_params, or json
To solve this problem you will need to parse all the params to multipart, if you are using laravel or lumen you can do it in this way
if(!empty($this->files))
{
//if there is an image parse all the rest parameters to
// multipart
$file_keys=array_keys($this->files);
foreach($this->files as $k => $file)
{
$http = $http->attach($k, file_get_contents($file),$k);
}
foreach($this->data as $dk =>&$d)
{
if(!in_array($dk,$file_keys))
{
if(is_array($d))
{
$d=json_encode($d);
}
$http = $http->attach($dk,$d);
}
}
return $http=$http->post($this->url);
}
//if there isn't any file just send all as form_params
return $http=$http->post($this->url,$this->data);