Laravel download file from S3 route (not open in browser) - php

I have the following route that will load a file from the given URL, I need this to actually download the file (mp4, jpg, pdf) rather than open in the browsers in built viewer.
// Download from CDN Route
Route::get('cdn/{url}', function($url)
{
return Redirect::away($url);
})->where('url', '(.*)');
All files are stored externally so apparently Resource::download() wouldn't actually work.
All I have available to me is the Amazon URL: https://mybucket.s3.amazonaws.com/folder/filename.pdf
Any suggestions on how to force the browser to download the file from S3?

In my case simple anchor link is downloading the file ...
file name

Try this code.
Update composer with flysystem
$path = 'https://mybucket.s3.amazonaws.com/folder/filename.pdf';
if(Storage::disk('s3')->has($path)){
$data = Storage::disk('s3')->get($path);
$getMimeType = Storage::disk('s3')->getMimetype($path);
$newFileName = 'filename.pdf';
$headers = [
'Content-type' => $getMimeType,
'Content-Disposition'=>sprintf('attachment; filename="%s"', $newFileName)
];
return Response::make($data, 200, $headers);
}

pari answer download empty file.
$s3Client = AWS::createClient('s3');
$stream = $s3Client->getObject(
[
'Bucket' => 'bucket name',
'Key' => 'filename',
'SaveAs' => '/tmp'.filename
]);
return response($stream['Body'], 200)->withHeaders([
'Content-Type' => $stream['ContentType'],
'Content-Length' => $stream['ContentLength'],
'Content-Disposition' => 'attachment; filename="' .{filename with extention} . '"'
]);

How can we download a video with an external link from another server. It's not s3. It's a normal server, files are there, but it doesn't work. I have written this code
$filename = $video->video_id;
$tempFile = tempnam(sys_get_temp_dir(), $filename);
// dd($tempFile);
copy($video->path, $tempFile);
header("Content-Disposition: attachment; filename = ".$filename);
header("X-Accel-Redirect: ".$filename);
return response()->download($tempFile, $filename);

Related

force download image as response lumen + intervention image

I'm using intervention image on my Lumen project and everything works until I come across on making the encoded image as a downloadable response which upon form submit that contains the image file that will be formatted unto specific format e.g. webp, jpg, png will be sent back as a downloadable file to the user, below is my attempt.
public function image_format(Request $request){
$this->validate($request, [
'image' => 'required|file',
]);
$raw_img = $request->file('image');
$q = (int)$request->input('quality',100);
$f = $request->input('format','jpg');
$img = Image::make($raw_img->getRealPath())->encode('webp',$q);
header('Content-Type: image/webp');
echo $img;
}
but unfortunately, its not my expected output, it just did display the image.
from this post, I use the code and attempt to achieve my objective
public function image_format(Request $request){
$this->validate($request, [
'image' => 'required|file',
]);
$raw_img = $request->file('image');
$q = (int)$request->input('quality',100);
$f = $request->input('format','jpg');
$img = Image::make($raw_img->getRealPath())->encode('webp',$q);
$headers = [
'Content-Type' => 'image/webp',
'Content-Disposition' => 'attachment; filename='. $raw_img->getClientOriginalName().'.webp',
];
$response = new BinaryFileResponse($img, 200 , $headers);
return $response;
}
but its not working, instead it showed me this error
any help, ideas please?
In Laravel you could use the response()->stream(), however, as mentioned in the comments, Lumen doesn't have a stream method on the response. That being said the stream() method is pretty much just a wrapper to return a new instance of StreamedResponse (which should already be included in your dependencies).
Therefore, something like the following should work for you:
$raw_img = $request->file('image');
$q = (int)$request->input('quality', 100);
$f = $request->input('format', 'jpg');
$img = Image::make($raw_img->getRealPath())->encode($f, $q);
return new \Symfony\Component\HttpFoundation\StreamedResponse(function () use ($img) {
echo $img;
}, 200, [
'Content-Type' => 'image/jpeg',
'Content-Disposition' => 'attachment; filename=' . 'image.' . $f,
]);

Downloading a zip file from a folder on my web server

I have an application that allows users to download mulitple files from a S3 bucket through an EC2 instance in one zip folder.
The process works fine, however, I would like the system to create a folder for each user when they want to download files, and then the files are downloaded to this folder and then put in a zip folder, within the user's folder, and then this zip folder is downloaded.
The files are downloading to this folder fine, and they are also zipping correctly, but my problem is that it is not downloading the zip file from the user's folder, and the download is showing as an empty zip file.
Below is my 'download all' code:
mkdir($userId);
$allName = $vshort . "v" . $number . "_All.zip";
$allName = str_replace(" ", "_", $allName);
if (isset($_POST['downloadAll']))
{
$zip = new ZipArchive();
$zip->open("{$userId}/{$allName}", ZipArchive::CREATE);
$s3->registerStreamWrapper();
foreach ($items as $item)
{
$fid = $item->item_file_id;
$file = ItemFile::locateId($fid);
$a = $file[0]->item_file_type;
$b = $file[0]->item_file_app;
$c = $file[0]->item_file_name;
$fileName = $a . "/" . $b . "/" . $c;
$download = $s3->getCommand('GetObject', [
'Bucket' => AWS_BUCKET,
'Key' => $fileName
]);
$streamFile = $c;
$user = User::locate($_SESSION['email']);
$uid = $user->user_id;
$cid = $user->user_company_id;
$history = new History();
$history->insert($fid, $uid, $cid);
$req = $s3->createPresignedRequest($download, '+1 minutes');
$link = (string)$req->getUri();
$stream = file_get_contents($link);
header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
header("Cache-Control: public"); // needed for internet explorer
header("Content-Type: application/'$a'");
header("Content-Disposition: attachment; filename='$c'");
file_put_contents($streamFile, $stream);
$zip->addFile($streamFile);
$downArray[] = $streamFile;
}
$zip->close();
$dLink = "https://mywebsite/" . $userId . "/" . $allName;
$size = filesize($allName);
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=$allName");
header("Content-length: " . $size);
header("Expires: 0");
ob_end_clean();
stream_context_set_default([
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
]
]);
readfile($dLink);
unlink($allName);
foreach ($downArray as $down)
{
unlink($down);
}
}
I have a feeling it is something to do with my headers but I'm not sure, any help will be greatly appreciated.
NOTE: I will be deleting the folder once the user has exited the page.
Below is what I am seeing on the web server
The folder '6' is the user id for the user in question
You appear to be calling readfile() on your download link ($dLink), which would serve the file throught HTTP. You probably meant to call readfile on $allName, the filesystem path of the same file. My guess is that your http request to $dLink is failing somehow. Also, you mkdir($userId), but never use that directory.
Apart from that, it seems your $allName variable contains the basename of the zipfile (i.e 'myzip-v-20_ALL.zip'). I would recommend opening your zipfile to a full path to your data directory, so you keep filesystem and http paths separate.
$allNameFilesystem = "{$userId}/{$allName}";
$allNameHttp = "https://mywebsite/{$userId}{$allName}";
// ...
$zip->open($allNameFilesystem, ZipArchive::CREATE);
// ...
// The download link is $allNameHttp
That is, if you actually need the http path. In this case, if you change readfile to use the filesystem path, you really don't use the http path anymore in your code.

Downloaded file via zend rest is corrupted

I want to download a zip file via zend framework. For this purpose I built the following code snippet:
function fetchAll($params = []) {
$file = __DIR__ . '/../../../../htdocs/_downloads/test.zip';
$response = new Stream();
$response->setStream(fopen($file, 'rb'));
$response->setStatusCode(200);
$response->setStreamName(basename($file));
$headers = new Headers();
$headers->addHeaders([
'Content-Disposition' => 'attachment; filename="' . basename($file) . '"',
'Content-Type' => 'application/octet-stream',
'Content-Length' => filesize($file)
]);
$response->setHeaders($headers);
return $response;
}
The code above is part of a rest resource.
Now I downloaded the file twice: Once with WinSCP, once with my REST API. The files I got have exactly the same size on my disk (1,390,687 bytes). The problem is that I can open the zip file downloaded by WinSCP but cannot open the file downloaded via REST. The error message says that the file is corrupted.

Upload File/Image with class Storage Laravel 5.2

First, I'm sorry for my bad English.
I want to upload a file/image from my driver to my project directory using class Storage. I want that every file/image will be uploaded/moved to my public/img directory. I use Form::file('img') on my views and on my post controller, I write this
$img = Input::file('img');
if ($img !== null) {
$filename = $img->getClientOriginalName();
Storage::disk('uploads')->put('filename', $filename);
$jenis->img = $filename;
}
and on my config/filesystem I write this
'uploads' => [
'driver' => 'local',
'root' => public_path() . '/img',
],
But, nothing happen on my public/img directory, no new file/image on there.
Can u help me whats wrong with my code?
and I hope u guys can help me with another good way on how to upload a file/image in laravel
Looks like your problem is you're not storing the file, you're referencing its name not its contents.
Try this:
Storage::disk('uploads') -> put($filename, file_get_contents($img -> getRealPath()));
In my filesystem file I configure my image directory in this way:
'uploads' => [
'driver' => 'local',
'root' => public_path("/img"),
],
I think that you can use your way but is another point.
To get the file from your view you should use File::get Laravel function:
$filename = $img->getClientOriginalName();
Storage::disk('uploads')->put($filename, \File::get($file));
With this would be enough, you save the file with the name of file uploaded in directory specify in filesystem.
if ($request->hasFile('original_pic')) {
$original_pic = $request->file('original_pic');
$file_extension=$original_pic>getClientOriginalExtension();
$filename = time() . '.' . $file_extension;
# upload original image
Storage::put('ArticlesImages/' . $filename, (string) file_get_contents($original_pic), 'public');
# croped image from request.
$image_parts = explode(";base64,", $request->input('article_image'));
$image_base64 = base64_decode($image_parts[1]);
Storage::put('ArticlesImages/croped/' . $filename, (string) $image_base64, 'public');
# get image from s3 or local storage.
$image_get = Storage::get('ArticlesImages/croped/' . $filename);
# resize 50 by 50 1x
$image_50_50 = Image::make($image_get)
->resize(340, 227)
->encode($file_extension, 80);
Storage::put('ArticlesImages/1x/' . $filename, (string) $image_50_50, 'public');
$file_url = Storage::url('ArticlesImages/croped/' . $filename);
return response()->json(['success' => true, 'filename' => $filename, 'file_url' => $file_url], 200);
}

Laravel 5.1 - how to download pdf file from S3 bucket

I am using Laravel's Storage facade and I am able to upload the pdf to S3 and I am also able to get() its contents but I cannot display or download it to the end user as an actual pdf file. It just looks like raw data. Here is the code:
$file = Storage::disk($storageLocation)->get($urlToPDF);
header("Content-type: application/pdf");
header("Content-Disposition: attachment; filename='file.pdf'");
echo $file;
How can this be done? I have checked several articles (and SO) and none of them have worked for me.
I think something like this will do the job in L5.2:
public function download($path)
{
$fs = Storage::getDriver();
$stream = $fs->readStream($path);
return \Response::stream(function() use($stream) {
fpassthru($stream);
}, 200, [
"Content-Type" => $fs->getMimetype($path),
"Content-Length" => $fs->getSize($path),
"Content-disposition" => "attachment; filename=\"" .basename($path) . "\"",
]);
}
you can create a download url, using the getObjectUrl method
somthing like this:
$downloadUrl = $s3->getObjectUrl($bucketname, $file, '+5 minutes', array(
'ResponseContentDisposition' => 'attachment; filename=$file,'Content-Type' => 'application/octet-stream',
));
and pass that url to the user. that will direct the user to an amzon page which will start the file download (the link will be valid for 5 minutes - but you can change that)
another option, is first saving that file to your server, and then let the user download the file from your server
You can do with this code (replace with your directory and your file name) ....
Storage::disk('s3')->download('bucket-directory/filename');
If your bucket is private, this is the way to obtain a url to download the file.
$disk = \Storage::disk('s3');
if ($disk->exists($file)) {
$command = $disk->getDriver()->getAdapter()->getClient()->getCommand('GetObject', [
'Bucket' => \Config::get('filesystems.disks.s3.bucket'),
'Key' => $file,
'ResponseContentDisposition' => 'attachment;'
]);
$request = $disk->getDriver()->getAdapter()->getClient()->createPresignedRequest($command, '+5 minutes');
$url = (string)$request->getUri();
return response()->json([
'status' => 'success',
'url' => $url
]);
}
In Laravel 5.7 it can be done with streamDownload:
return response()->streamDownload(function() use ($attachment) {
echo Storage::get($attachment->path);
}, $attachment->name);
$filename = 'test.pdf';
$filePath = storage_path($filename);
$header = [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="'.$filename.'"'
];
return Response::make(file_get_contents($filePath), 200, $header);
$d = file_full_path_here...
$d = str_replace(' ', '%20', $d); //remove the white space in url
ob_end_clean();
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=" . $d);
header("Content-Type: application/pdf");
return readfile($d);
I figured it out. Silly mistake. I had to remove the single quotes from filename.
Fix:
$file = Storage::disk($storageLocation)->get($urlToPDF);
header("Content-type: application/pdf");
header("Content-Disposition: attachment; filename=file.pdf");
echo $file;

Categories