Laravel : I received song file "form-data" from one of API then i need to forward that file to another API. Any idea to forward? - laravel

Laravel project 1 controller how to forward file to API-2
Input::file('songFile')->move("/tmp", $newname);
i used this function and store tmp location then how to use this tmp location file and forward?

In order to post a file to API endpoint, you can follow the following code.
try{
$path = 'var/www/html/myproject/public/file.txt';//your file path
if (!empty($path) && file_exists($path)) {
$guzzleResponse = $client->post($api_url, [
'multipart' => [
[
'name' => 'file',// it is the name as specfied in the payload of api_url
'contents' => fopen($path, 'r')// or you can use file_get_contents()
]
],
'headers' => $headers
]);
}
if ($guzzleResponse->getStatusCode() == 200) {
$response = json_decode($guzzleResponse->getBody());// whatever you want to do with response
}
}catch(RequestException $e){
return $e; //You can also handle specific status codes here using eg $e->getResponse()->getStatusCode() == '400'
}
Also $headers can be like this
[
'Accept' => 'application/json',
'Authorization' => 'Bearer '. $userToken,
]
See more information in Guzzle

Related

How to do concurrent guzzle http post request to rest api in laravel?

I want to make concurrent Guzzle http requests in laravel to rest api i have users in 100k i want to perform billing for users.
Currently my guzzle http is doing synchronous calls to rest api which is taking 6 hours to complete 100k post requests and the requests does not have any call backs they are just post request with users msisdn and unique id in json format.
How to do concurrent 50 requests per second so that billing is performed quickly.
Following is part of my code which i use taken from https://docs.guzzlephp.org/en/stable/quickstart.html#concurrent-requests
$requests = function ($total) {
$url = "url here";
$auth = base64_encode($username . ":" . $password);
for ($i = 0; $i < $total; $i++) {
$msgdata =[
'msisdn'=>$msisdn,
$subscription
=>$subscriptionInfo];
yield new Request('post', $url,
[
'headers' =>
[
'Content-Type' => 'application/json',
'Authorization' => $authorizaton
],
'body' => json_encode($msgdata)
]);
}
$pool = new Pool($client, $requests(50), [
'concurrency' => 5,
'fulfilled' => function (Response $response, $index) {
// this is delivered each successful response
echo $response;
},
'rejected' => function (RequestException $reason, $index) {
// this is delivered each failed request
echo $reason;
},
]);
// Initiate the transfers and create a promise
$promise = $pool->promise();
// Force the pool of requests to complete.
$promise->wait();
i am getting response as
"status":401,"error":"Unauthorized"
But request params are not incorect idk why it is giving response as incorect
finally i found the solution to my problem, the problem was in request header and body parameters.
changed this
yield new Request('post', $url,
[
'headers' =>
[
'Content-Type' => 'application/json',
'Authorization' => $authorizaton
],
'body' => json_encode($msgdata)
]);
to
yield new Request('post', $url,
[
'Content-Type' => 'application/json',
'Authorization' => $authorizaton
],
json_encode($msgdata)
);

Error: Pass content as json or plain text

I am using guzzle to post data to the api as below. When i post, the api returns Error: Pass content as json or plain text. Is it possible to convert content to JSON or Plain Text in the code below
How can I resolve this?
Controller
$headers = [
'Content-Type' => 'application/x-www-form-urlencoded',
];
$client = new \GuzzleHttp\Client([
'headers' => $headers
]);
$body = '{
"item" : Summer-Jacket,
"content" : Hi
}';
$url = "https://api.com";
$request = $client->post($url,
[
'body' => $body
] );
$response = $request->send();
Firstly your body is not even valid JSON. Strings needs to have "string" around them
To post JSON with guzzle, you can instead use the RequestOptions for exactly that.
$result = $client->post("https://api.com", [
RequestOptions::JSON => [
'item' => 'Summer-Jacket',
'content' => 'hi',
]
)->getBody();

File upload corruption

Im trying to upload a file to sharepoint
Successful try with just axios is the following
Failure if i upload using Guzzle
Uploaded file at the end is corrupted
There are a few things you need to modify to get this working (tested on my end):
To get the contents of the file, you need $request->file('file') and then use file_get_contents() on it. You can lose the get() part.
Make sure you're sending the header to accept multipart/form-data too:
"Accept" => "multipart/form-data"
Fields name and filename in a form are two different things. Former is the name of the field while the latter is the name of the file. You need to send both.
Try this:
protected function uploadFile(Request $request){
$file = $request->file('file');
$body = [
"headers" => [
"Accept" => "multipart/form-data",
"Authorization" => "Bearer {$this->token}"
],
"multipart" => [
"name" => "file",
"contents" => file_get_contents($file),
"filename" => $file->getClientOriginalName()
]
];
return (new Client)->request('POST', 'https://.sharepoint.com/...', $body);
}
P.S. - You can check whether a file is valid or not using isValid():
if ($request->file('file')->isValid()) {
//
}
Official docs on this: https://laravel.com/docs/7.x/requests#retrieving-uploaded-files
When providing content to be uploaded to Guzzle client as string,
Guzzle tries to infer necessary information about the file such as filename, content-type.
You can help Guzzle to infer these information correctly to build the multipart request by passing information about about the filename and content-type in the multipart payload.
[
//...
'multipart' => [
[
'name' => 'fileName',
'contents' => $request->file('file')->get(),
'filename' => $request->file('file')->getName(),
'headers' => [
'content-type' => $request->file('file')->getMimeType(),
]
]
]
]
Add content-type as blob.
axios.post(
'https://sharepoint....'
,data.get('file')
{
'headers' {
'Authorization': `Bearer ${this.token}`
,'Content-Type': 'blob',
}
}
)
Try something like this.
Remove the ->get() of your $request->file()
//Get the file object from the request.
$file = $request->file('file');
//Make the request
return (new Client)->request('POST', 'https://.sharepoint.com/sites....', [
'headers' => [ 'Authorization' => "Bearer {$this->token}" ],
'multipart' => [
[
'name' => 'FileContents',
'contents' => $file,
'filename' => $file->getClientOriginalName()
],
],
]);
In my opinion, you should store it somewhere in your local server temporarily first, and then you sent that file to sharepoint, deleted the temporary file, I think if you send it right away without storing it, the file will be corrupted. Please try the way below
$file = $request->file('logo');
$original_name = $file->getClientOriginalName(); // get original file
$name = time() . '_' . $original_name; // store it in different name so it would not be duplicated
$path = base_path() .'/public_html/your_project/public/temporary/'; // full path of file folder
// store the uploaded file
$file->move($path, $name);
$body = [
"headers" => [
"Authorization" => "Bearer {$this->token}"
],
"multipart" => [
"name" => "logo",
"contents" => fopen($path . $name, 'r')
]
];
$response = (new Client)->request('POST', 'https://.sharepoint.com/...', $body);
// remove the file after done
unlink($path . $name);
return $response;
Hope this would work for you! Please correct me if I was wrong

Laravel : Force the download of a string without having to create a file

I'm generating a CSV, and I want Laravel to force its download, but the documentation only mentions I can download files that already exist on the server, and I want to do it without saving the data as a file.
I managed to make this (which works), but I wanted to know if there was another, neater way.
$headers = [
'Content-type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="download.csv"',
];
return \Response::make($content, 200, $headers);
I also tried with a SplTempFileObject(), but I got the following error : The file "php://temp" does not exist
$tmpFile = new \SplTempFileObject();
$tmpFile->fwrite($content);
return response()->download($tmpFile);
Make a response macro for a cleaner content-disposition / laravel approach
Add the following to your App\Providers\AppServiceProvider boot method
\Response::macro('attachment', function ($content) {
$headers = [
'Content-type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="download.csv"',
];
return \Response::make($content, 200, $headers);
});
then in your controller or routes you can return the following
return response()->attachment($content);
A Laravel 7 approach would be (from the docs):
$contents = 'Get the contents from somewhere';
$filename = 'test.txt';
return response()->streamDownload(function () use ($contents) {
echo $contents;
}, $filename);
Try this:
// Directory file csv, You can use "public_path()" if the file is in the public folder
$file= public_path(). "/download.csv";
$headers = ['Content-Type: text/csv'];
//L4
return Response::download($file, 'filename.csv', $headers);
//L5 or Higher
return response()->download($file, 'filename.csv', $headers);

File download using Guzzle and Dropbox API on laravel

I'm trying to create a function that I can use to download a specified file to a local folder on my machine. The request is successful and I do receive the filedata, however, I can't figure out how to extract the and write it to the specified path. How can I do it ?
Here's my function :
public function dropboxFileTransfer()
{
$local = fopen('files/get.zip', 'r');
$file = $this->client->get('https://api-content.dropbox.com/1/files/auto/dropbox-sdk-php-1.1.5.zip', [
'headers' => [
'Authorization' => 'Bearer ' . \Session::get('dtoken'),
],
]);
$stream = Stream::factory($file->getBody()->__toString());
$dest = Stream::factory($local);
$dest->write($stream);
return 'ok';
}

Resources