I tried to download jpg/png image from storage folder its gets corrupted after downloaded.
This is my controller
public function download($filename) {
$headers = array(
'Content-Type: image/png',
);
return response()->download(storage_path() . '/'.$filename, 'final.png', $headers);
}
after open it look like this
Even i used core php script to download still iam facing same problem.
I believe that the Laravel framework might be introducing whitespace which might be ruining the header() function.
Use ob_end_clean() before your first header() call to remove any extra whitespace.
add this method before like this
ob_end_clean();
$headers = array(
'Content-Type: image/png',
);
return response()->download(storage_path() . '/'.$filename, 'final.png', $headers);
!enjoy
After Download .jpg,png,gif and .xlsx
Yes ! Its working;
I was reading this problem for 15 days and finally got the solution
Larabel 5.8 & PHP 7.3
public function download_user_photo($id) {
ob_end_clean();
$photo = UserGallery::find($id);
$path = 'storage/users/'.$photo->image_url;
enter code here
if (\File::exists($path)) {
return response()->download($path);
} else {
return redirect()->back()->with('danger', 'Image does not exist.');
}
}
Related
Hello fellow coders !
I am looking for a solution to show a html page while my php code prepares a .zip which is then downloaded. The reason is because sometimes the zips are quite bigger and take time to make.
The HTML page would be a basic "Please wait while your .zip files is being prepared".
The PHP side used is Symfony. So I come into my getInboxExportAction function by calling https://myapi.com/orders/orderid/inbox/export.
The download function (makeExportDownloadRequestResponse) works fine. But if I add a flush after making my $response, the .zip is printed to the html, instead of being downloaded...
public function getInboxExportAction(Request $request, $orderId)
{
$response = new Response($this->twig->render('base.html.twig',
['content' => '
<h1>Download</h1>
<p>Your zip is being prepared for download, please wait...</p>
']));
$response->headers->set('Content-Type', 'text/html');
//Here I would like to echo + flush my html.
//Then stop the flush and continue my code
$receivedOrder = $this->fetchRequestedReceivedOrder($orderId);
if (!$receivedOrder instanceof ReceivedOrder) {
return $receivedOrder;
}
if (!$receivedOrder->getSentorder()) {
$this->makeErrorResponse('Sent order was not found', Response::HTTP_BAD_REQUEST);
}
return $this->makeExportDownloadRequestResponse($receivedOrder->getSentorder(), $request->get('format'));
}
I am also very open to any other ideas anyone would have to fix this issue :)
Thanks,
Edit : My $this->makeExportDownloadRequestResponse() function returns a response, not a path. We unlink the file on the server for storage reasons.
$content = file_get_contents($zipTmpFile);
unlink($zipTmpFile);
$response = new Response($content);
$dispositionHeader = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT,
'myFile_' . date('Y_m_d_h_i_s') . '.zip');
$response->headers->set('Content-Disposition', $dispositionHeader);
return $response;
Second edit : I understand that what I'm trying to do (change the content-type within one call) I generally frowned upon. I'm currently trying to think of a more elegant solution.
In your getInboxExportAction, just return a response with your text.
Then, in this response, add a <meta http-equiv="refresh" content="1;url=xxx"> tag to redirect the user to another action that will generate the zip file.
You can also handle this redirection with javascript.
Note that you can use a StreamedResponse to handle the zip download: https://symfony.com/doc/current/components/http_foundation.html#streaming-a-response
The most important thing is you set $response->headers->set('Content-Type', 'text/html');, the browser will not download the .zip file.
If your makeExportDownloadRequestResponse method can return the absolute .zip file path (or you can calculate it), you can try:
public function getInboxExportAction(Request $request, $orderId)
{
$response = new Response($this->twig->render('base.html.twig',
['content' => '
<h1>Download</h1>
<p>Your zip is being prepared for download, please wait...</p>
']));
$response->headers->set('Content-Type', 'text/html');
//Here I would like to echo + flush my html.
//Then stop the flush and continue my code
$receivedOrder = $this->fetchRequestedReceivedOrder($orderId);
if (!$receivedOrder instanceof ReceivedOrder) {
return $receivedOrder;
}
if (!$receivedOrder->getSentorder()) {
$this->makeErrorResponse('Sent order was not found', Response::HTTP_BAD_REQUEST);
}
// prepare the to be downloaded zip file
// then, do sth to get the .zip file path
$zipFilePath = $this->makeExportDownloadRequestResponse($receivedOrder->getSentorder(), $request->get('format'));
// re-set header
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename=whateverName.zip');
header('Content-Length: ' . filesize($zipFilePath));
readfile($zipFilePath);
}
It will let browser downloads the zip file.
Finally, If your function is work as an API, and you need a frontend JS to execute it, try with Blob class on JS.
You can indeed use a StreamedResponse to get it rid of this issue. About the fact that the whole .wip file content being displayed because of the flush, try to call ob_flush before
I have build a laravel application where I have some files on public/files directory. if I give this link to others such as download Link, they have chance to know my directory ..
Suppose the link i have to give download link as
www.abc.com/files/45454553535.zip
But i don't want to let Users know that it's there in files directory. So How Do i hide the directory?
Keep your files in the storage directory. That way you can serve the file to the users through code.
Try to follow the documentation: https://laravel.com/docs/5.4/filesystem
I don't know whether this would work or not but giving you an idea. Create a php file use like this:
header('Content-Type: application/zip');
$a=file_get_contents(file.zip)
echo $a;
From this user will not know from where the contents are fetched.
Try this.
public function getDownload()
{
$filename='45454553535.zip'
$file= public_path(). "/files/".$filename;
$headers = array(
'Content-Type: application/zip',
);
return Response::download($file, $filename, $headers);
}
".files/45454553535.zip"will not work as you have to give full physical path.
Update 20/05/2016
Laravel 5, 5.1, 5.2 or 5.* users can use the following method instead of Response facade. However, my previous answer will work for both Laravel 4 or 5.
return response()->download($file, $filename, $headers);
You can just create a your controller and route.
Route::get('files/{filename}', [
'as' => 'file.get',
'uses' => 'FileController#get',
]);
Controller should check your proper directory. Try to keep your files in storage path, not public.
class FileController extends Controller
{
private $path;
public function __construct()
{
$path = storage_path()
. '/your-valid-directory/';
}
public function get($filename)
{
$file_path = $this->path
. filter_var($filename, FILTER_SANITIZE_STRING);
if (file_exists($file_path) && is_readable($file_path)) {
return response(file_get_contents($file_path), 200, [
'Content-Type: application/zip',
]);
} else {
abort(404);
}
}
}
Now you can get access to specific file by:
{{ route('file.get', ['filename' => '45454553535.zip') }}
This action generate link looks like: your-domain.com/files/45454553535.zip. :)
Anyway in my opinion - in the future just make file factory with specific headers, directories.
Good luck!
Hi everyone! I'm working on a Laravel 5.2 application in which the user can download a variety of files. One of these is a 'User guide', explaining how the website is set up and functionalities etc. I would like the PDF to be streamed in another page, so that the user is still within the application. The controller which I am using is:
public function userguidePDF(){
return response()->stream('../public/download/userguide.pdf');
}
But this returns:
Argument 1 passed to
Symfony\Component\HttpFoundation\StreamedResponse::__construct() must
be callable, string given, called in
/path/to/laravel/vendor/laravel/framework/src/Illuminate/Routing/ResponseFactory.php
on line 117 and defined
I have searched on the internet for a method, which leaded me to the following syntax:
return response()->stream($callback, 200, $headers);
Unfortunately, I am unable to find more documentation on the parameters because I don't understand them. Could someone please explain to me what the $callback, 200, $header are as parameters and how I can use this?
https://laravel.com/docs/5.2/responses#view-responses
public function userguidePDF() {
return response()->file(
public_path('download/userguide.pdf')
);
}
$callback should be a function that ouputs your PDF. For example:
$callback = function()
{
$handle = fopen("../public/download/userguide.pdf", "r");
$filecontent= fread($handle, filesize("../public/download/userguide.pdf"));
fclose($handle);
return $filecontent;
};
You can use download also
return Response::download($file, 'filename.pdf', $headers);
here is the documentation for streaming and also downlaod.
https://laravel.com/api/5.2/Illuminate/Routing/ResponseFactory.html#method_stream
EDIT
Use headers like this
// We'll be outputting a PDF
header('Content-Type: application/pdf');
// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');
I'm creating a application that lets a user download a file. After the download i want the file to be deleted. The end of my code is like this:
return Response::download(public_path() . '/uploads/_tmp/' . urldecode($filename));
which means that the function ends on the return an i am not able to delete the file. I have tried to call a 'after' filter on the route but then the file gets deleted to quickly.
Any ideas?
You can use deleteFileAfterSend http://laravel.com/docs/5.0/responses#other-responses
return response()->download($filePath, $fileName, $headers)->deleteFileAfterSend(true);
I personally use the following;
$response = Response::make(file_get_contents($path_to_file), $status_code, $headers);
Status code is obviously the code which you want to return.
Within the $header parameter you can pass an array with the indexes Content-Type and Content-Disposition.
Then you can simply unlink $path_to_file and return $response.
Much easier way of deleting a file would be to use Jon's answer for versions of Laravel > 4.0.
You can use deleteFileAfterSend http://laravel.com/docs/5.0/responses#other-responses
return response()->download($filePath, $fileName, $headers)->deleteFileAfterSend(true);
Simply use this line of code:
return response()->download($file_path)->deleteFileAfterSend(true);
Here, inside download function the file path will be passed as an argument. Let's say for an example you want to backup your database in a file and also want to delete with downloading:
$date = Carbon::now()->format('Y-m-d_h-i');
$pub_path = public_path();
$file_path = $pub_path . '/application/db_backups/' . $date . '.sql';
$output = shell_exec('mysqldump -h58.84.34.65 -uwsit -pwsit97480 websms > ' . $file_path);
return response()->download($file_path)->deleteFileAfterSend(true);
If you want to delete the source file after downloading, simply write it as follows
return response()->download($filePath)->deleteFileAfterSend(true);
$filename = storage_path() . '/testing.txt';
App::finish(function($request, $response) use ($filename)
{
unlink($filename);
});
return Response::download($filename);
For Laravel 5.8 use stream download. In the callback function, delete the file after echo the contents.
Let's take a look at the solution:
return response()->streamDownload(function () use ($pathToTheFile) {
echo Storage::get($pathToTheFile);
Storage::delete($pathToTheFile);
}, 'my-awesome-file-name');
I don't know if it works for the oldest or the latest versions.
unlink('./path/filename.extension');
In Laravel application I'm trying to achieve a button inside view that can allow user to download file without navigating to any other view or route
Now I have two issues:
(1) below function throwing
The file "/public/download/info.pdf" does not exist
(2) Download button should not navigate user to anywhere and rather just download files on a same view, My current settings, routing a view to '/download'
Here is how Im trying to achieve:
Button:
<i class="icon-download-alt"> </i> Download Brochure
Route :
Route::get('/download', 'HomeController#getDownload');
Controller :
public function getDownload(){
//PDF file is stored under project/public/download/info.pdf
$file="./download/info.pdf";
return Response::download($file);
}
Try this.
public function getDownload()
{
//PDF file is stored under project/public/download/info.pdf
$file= public_path(). "/download/info.pdf";
$headers = array(
'Content-Type: application/pdf',
);
return Response::download($file, 'filename.pdf', $headers);
}
"./download/info.pdf"will not work as you have to give full physical path.
Update 20/05/2016
Laravel 5, 5.1, 5.2 or 5.* users can use the following method instead of Response facade. However, my previous answer will work for both Laravel 4 or 5. (the $header array structure change to associative array =>- the colon after 'Content-Type' was deleted - if we don't do those changes then headers will be added in wrong way: the name of header wil be number started from 0,1,...)
$headers = [
'Content-Type' => 'application/pdf',
];
return response()->download($file, 'filename.pdf', $headers);
File downloads are super simple in Laravel 5.
As #Ashwani mentioned Laravel 5 allows file downloads with response()->download() to return file for download. We no longer need to mess with any headers. To return a file we simply:
return response()->download(public_path('file_path/from_public_dir.pdf'));
from within the controller.
Reusable Download Route/Controller
Now let's make a reusable file download route and controller so we can server up any file in our public/files directory.
Create the controller:
php artisan make:controller --plain DownloadsController
Create the route in app/Http/routes.php:
Route::get('/download/{file}', 'DownloadsController#download');
Make download method in app/Http/Controllers/DownloadsController:
class DownloadsController extends Controller
{
public function download($file_name) {
$file_path = public_path('files/'.$file_name);
return response()->download($file_path);
}
}
Now simply drops some files in the public/files directory and you can server them up by linking to /download/filename.ext:
File Name // update to your own "filename.ext"
If you pulled in Laravel Collective's Html package you can use the Html facade:
{!! Html::link('download/filename.ext', 'File Name') !!}
In the accepted answer, for Laravel 4 the headers array is constructed incorrectly. Use:
$headers = array(
'Content-Type' => 'application/pdf',
);
Quite a few of these solutions suggest referencing the public_path() of the Laravel application in order to locate the file. Sometimes you'll want to control access to the file or offer real-time monitoring of the file. In this case, you'll want to keep the directory private and limit access by a method in a controller class. The following method should help with this:
public function show(Request $request, File $file) {
// Perform validation/authentication/auditing logic on the request
// Fire off any events or notifiations (if applicable)
return response()->download(storage_path('app/' . $file->location));
}
There are other paths that you could use as well, described on
Laravel's helper functions documentation
While using laravel 5 use this code as you don`t need headers.
return response()->download($pathToFile); .
If you are using Fileentry you can use below function for downloading.
// download file
public function download($fileId){
$entry = Fileentry::where('file_id', '=', $fileId)->firstOrFail();
$pathToFile=storage_path()."/app/".$entry->filename;
return response()->download($pathToFile);
}
HTML href link click:
<a ="{{ route('download',$name->file) }}"> Download </a>
In controller:
public function download($file){
$file_path = public_path('uploads/cv/'.$file);
return response()->download( $file_path);
}
In route:
Route::get('/download/{file}','Controller#download')->name('download');
I think that you can use
$file= public_path(). "/download/info.pdf";
$headers = array(
'Content-Type: ' . mime_content_type( $file ),
);
With this you be sure that is a pdf.
// Try this to download any file. laravel 5.*
// you need to use facade "use Illuminate\Http\Response;"
public function getDownload()
{
//PDF file is stored under project/public/download/info.pdf
$file= public_path(). "/download/info.pdf";
return response()->download($file);
}
HTML link click
<a class="download" href="{{route('project.download',$post->id)}}">DOWNLOAD</a>
// Route
Route::group(['middleware'=>['auth']], function(){
Route::get('file-download/{id}', 'PostController#downloadproject')->name('project.download');
});
public function downloadproject($id) {
$book_cover = Post::where('id', $id)->firstOrFail();
$path = public_path(). '/storage/uploads/zip/'. $book_cover->zip;
return response()->download($path, $book_cover
->original_filename, ['Content-Type' => $book_cover->mime]);
}
This is html part
<a href="{{route('download',$details->report_id)}}" type="button" class="btn btn-primary download" data-report_id="{{$details->report_id}}" >Download</a>
This is Route :
Route::get('/download/{id}', 'users\UserController#getDownload')->name('download')->middleware('auth');
This is function :
public function getDownload(Request $request,$id)
{
$file= public_path(). "/pdf/"; //path of your directory
$headers = array(
'Content-Type: application/pdf',
);
return Response::download($file.$pdfName, 'filename.pdf', $headers);
}
you can use simply inside your controller:
return response()->download($filePath);
Happy coding :)
If you want to use the JavaScript download functionality then you can also do
<a onclick="window.open('info.pdf) class="btn btn-large pull-right"><i class="icon-download-alt"> </i> Download Brochure </a>
Also remember to paste the info.pdf file in your public directory of your project