3

I have a file download website and I serve the files through Laravel for hotlink protection, but it seems like downloads keep my php processes alive for a very long time (as some users have bad download speed).

For hotlink protection I create a session when the user enters the download page and check it when they click the download button.

Is there any way to do the hotlink protection or can I just lower memory usage?

This is the code that triggers the download:

if($request->session()->get('file') == $apk->generated_filename) 
        {   
            $headers = array
            (
                'Content-Type' => 'application/vnd.android.package-archive'
            );
            Apk::find($apk->id)->increment('downloads_co');
            return response()->download(config('custom.storage') . $apk->generated_filename, $apk->filename, $headers);
        }
Karan Thakkar
  • 1,492
  • 2
  • 17
  • 24
Alex
  • 4,674
  • 5
  • 38
  • 59

4 Answers4

1

Use X-Accel-Redirect and to an internal location


The absolute best way is to make use of http://nginx.org/r/internal on the nginx side, and do a response with the HTTP Response Header Field of X-Accel-Redirect on the upstream side for nginx to handle.

Unless prevented by http://nginx.org/r/proxy_ignore_headers et al, nginx performs special processing of the X-Accel-Redirect upstream HTTP response header — it causes an internal redirect within nginx (which you should do to a location marked with the internal directive, to make sure that the only possible way to access such files directly is exclusively through such an internal redirect).


The idea here is that your PHP script can still handle authentication and hotlink protection in any way you deem necessary — user authentication, link expiration, individual AI-based blacklisting and all — but then at the end of the day, once the script is done, the actual feeding of the file to the client will be done in the most efficient way possible directly through nginx.

(Note that using the internal keyword is very important — it ensures that the only way to resume the download, once interrupted for whichever reason, would through contact with your PHP script first. So, with this clever and proven trick from the nginx cookbook, you'll be getting the best of both worlds — complete control over hotlinking and best resource utilisation.)

cnst
  • 25,870
  • 6
  • 90
  • 122
1

you should read file by buffer size ( for example 2k ) and then send response , don't send whole response at once , write script like below to download file :

    ignore_user_abort(true);
    set_time_limit(0); \

    $path = "/absolute_path_to_your_files/"; // change the path to fit your websites document structure

    $dl_file = preg_replace("([^\w\s\d\-_~,;:\[\]\(\).]|[\.]{2,})", '', $_GET['download_file']); // simple file name validation
    $dl_file = filter_var($dl_file, FILTER_SANITIZE_URL); // Remove (more) invalid characters
    $fullPath = $path.$dl_file;

    if ($fd = fopen ($fullPath, "r")) {
        $fsize = filesize($fullPath);
        $path_parts = pathinfo($fullPath);
        $ext = strtolower($path_parts["extension"]);
        switch ($ext) {
            case "pdf":
                header("Content-type: application/pdf");
                header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\""); // use 'attachment' to force a file download
                break;
            // add more headers for other content types here
            default;
                header("Content-type: application/octet-stream");
                header("Content-Disposition: filename=\"".$path_parts["basename"]."\"");
                break;
        }
        header("Content-length: $fsize");
        header("Cache-control: private"); //use this to open files directly
        while(!feof($fd)) {
            $buffer = fread($fd, 2048);
            echo $buffer;
        }
    }
    fclose ($fd);
Behzad kahvand
  • 425
  • 4
  • 13
0

You could use a .htaccess for that.

You can either use this generator or use the following code and adapt it yourself.

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yourdomain.com [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ - [NC,F,L]
Kerel
  • 732
  • 6
  • 20
0
location ~* \.(gif|png|jpe?g)$ {
  expires 7d;
  add_header Pragma public;
  add_header Cache-Control "public, must-revalidate, proxy-revalidate";

  # prevent hotlink
  valid_referers none blocked ~.google. ~.bing. ~.yahoo. server_names ~($host);
  if ($invalid_referer) {
    rewrite (.*) /static/images/hotlink-denied.jpg redirect;
    # drop the 'redirect' flag for redirect without URL change (internal rewrite)
  }
}

# stop hotlink loop
location = /static/images/hotlink-denied.jpg { }

Reference : http://nodotcom.org/nginx-image-hotlink-rewrite.html

Amitesh Bharti
  • 14,264
  • 6
  • 62
  • 62