File download using Guzzle and Dropbox API on laravel - 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';
}

Related

Generating and downloading a text file on the fly in Laravel

My data is stored in the database and I need to give it out of it in a text file. There is no point in creating a file on disk, but an attempt to generate a response with a file does not work. Found a way like this but it doesn't work ERR_INVALID_RESPONSE
$contents = 'My data from db';
$filename = 'example.txt';
return response()->streamDownload(function () use ($contents) {
echo $contents;
}, $filename);
In your route name the route with something reasonable like:
Route::get('filename.txt', [FooController::class, 'foo']);
And in your controller at foo() action:
$headers = [
'Content-Type' => 'application/plain',
'Content-Description' => 'File name',
];
$contents = 'My data from db';
return \Response::make($contents, 200, $headers);

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 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

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

Path of the file stored in s3 does not match with provided - Using Laravel

I'm building a service to upload images with laravel and stored in a aws s3 bucket, this is the function responsible for store image.
public function fromUrl(Request $request)
{
$validator = Validator::make($request->all(), [
'files' => 'required|array|min:1',
'files.*' => 'string',
]);
if (!$validator->fails()) {
$paths = [];
foreach ($validator->validate()['files'] as $file) {
$url = config('services.s3.host') . Storage::disk('s3')->put('images/public', file_get_contents($file), 'public');
array_push($paths, $url);
}
return $paths;
} else {
throw new ValidateException([
'message' => $validator->errors()->toArray(),
'rules' => $validator->failed()
]);
}
}
The request body looks like this.
{
"files": [
"https://image-url-1",
"https://image-url-2"
]
}
I expect that the path returned when saving the image is something like this.
[
"https://my-bucket-url/images/public/random-name-for-image1",
"https://my-bucket-url/images/public/random-name-for-image2"
]
but instead I'm getting the following.
[
"https://my-bucket-url/1",
"https://my-bucket-url/1"
]
You are misusing put in your example.
Firstly the first parameter is the path plus filename and you have no filename random logic. The third parameter is options array.
$randomFileName = uniqid(rand(), true);
$path = 'images/public/' . $randomFileName;
Storage::disk('s3')->put($path, file_get_contents($file));
This code will save an element at images/public/$randomFileName. To return the proper path you can use the url() method.
$url = Storage::disk('s3')->url($path);
array_push($paths, $url);

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);

Resources