Asked  1 Year ago    Answers:  5   Viewed   29 times

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:

  <a href="/download" class="btn btn-large pull-right"><i class="icon-download-alt"> </i> Download Brochure </a>

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

 Answers

4

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);
Wednesday, June 2, 2021
 
tdous
 
5

You could manually create the response like so:

$encryptedContents = Storage::get($fileRecord->file_path);
$decryptedContents = Crypt::decrypt($encryptedContents);

return response()->make($decryptedContents, 200, array(
    'Content-Type' => (new finfo(FILEINFO_MIME))->buffer($decryptedContents),
    'Content-Disposition' => 'attachment; filename="' . pathinfo($fileRecord->file_path, PATHINFO_BASENAME) . '"'
));

You can check out the Laravel API for more info on what the parameters of the make method are. The pathinfo function is also used to extract the filename from the path so it sends the correct filename with the response.

Saturday, May 29, 2021
 
2

I don't know whether Laravel supports the change of auth table name on fly or not. I can suggest you a quick solution.

According to generalization theory of database design, you should store same type of information to one entity set. And according to specialization theory, if entity set can have various types of information for each entity, break them down into sub entity sets.

Suggestion:

  • Create user_types table with column id & name (store user type names here)
  • Create table users with 4 columns id, email/username, password & user_type_id (user_type_id is foreign key references id of user_types)
  • Create 3 separate tables named administrators, parents or employees. All 3 tables should have one column user_id which is a foreign key references users table.
  • Create relationship in model
  • After a user login, you can determine which type of user he/she is from the user<->user_type relation
  • You can get rid of the usertype dropdown from login page view now (You were disclosing some important information (3 user types) about your application to the whole planet, isn't it harmful for your application?)

More info about generalization & specialization: Generalization, Specialization and Aggregation

Saturday, May 29, 2021
 
relipse
 
5

I know this is an old question. I'm just posting this answer for historical purposes:

Laravel now has the possibility to localize the resources. https://laravel.com/docs/5.5/controllers#restful-localizing-resource-uris

Localizing Resource URIs By default, Route::resource will create resource URIs using English verbs. If you need to localize the create and edit action verbs, you may use the Route::resourceVerbs method. This may be done in the boot method of your AppServiceProvider:

use IlluminateSupportFacadesRoute;

/**
 * Bootstrap any application services.
 *
 * @return void
 */

public function boot() {
    Route::resourceVerbs([
        'create' => 'crear',
        'edit' => 'editar',
    ]); } 

Once the verbs have been customized, a resource route registration such as Route::resource('fotos', 'PhotoController') will produce the following URIs:

/fotos/crear

/fotos/{foto}/editar
Saturday, May 29, 2021
 
5

This happens because Response::download() loads the file in to memory before serving it to the user. Admittedly this is a flaw in the framework, but most people do not try to serve large files through the framework.

Solution 1 - Put the files you want to download in the public folder, on a static domain, or cdn - bypass Laravel completely.

Understandably, you might be trying to restrict access to your downloads by login, in which case you'll need to craft your own download method, something like this should work...

function sendFile($path, $name = null, array $headers = array())
{
    if (is_null($name)) $name = basename($path);

    // Prepare the headers
    $headers = array_merge(array(
        'Content-Description'       => 'File Transfer',
        'Content-Type'              => File::mime(File::extension($path)),
        'Content-Transfer-Encoding' => 'binary',
        'Expires'                   => 0,
        'Cache-Control'             => 'must-revalidate, post-check=0, pre-check=0',
        'Pragma'                    => 'public',
        'Content-Length'            => File::size($path),
    ), $headers);

    $response = new Response('', 200, $headers);
    $response->header('Content-Disposition', $response->disposition($name));

    // If there's a session we should save it now
    if (Config::get('session.driver') !== '')
    {
        Session::save();
    }

    // Send the headers and the file
    ob_end_clean();
    $response->send_headers();

    if ($fp = fread($path, 'rb')) {
        while(!feof($fp) and (connection_status()==0)) {
            print(fread($fp, 8192));
            flush();
        }
    }

    // Finish off, like Laravel would
    Event::fire('laravel.done', array($response));
    $response->foundation->finish();

    exit;
}

This function is a combination of Response::download() and Laravel's shutdown process. I've not had a chance to test it myself, I don't have Laravel 3 installed at work. Please let me know if it does the job for you.

PS: The only thing this script does not take care of is cookies. Unfortunately the Response::cookies() function is protected. If this becomes a problem you can lift the code from the function and put it in your sendFile method.

PPS: There might be an issue with output buffering; if it is a problem have a look in the PHP manual at readfile() examples, there's a method that should work there.

PPPS: Since you're working with binary files you might want to consider replacing readfile() with fpassthru()

EDIT: Disregard PPS and PPPS, I've updated the code to use fread+print instead as this seems more stable.

Thursday, July 29, 2021
 
Dunc
 
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :