php

Change filename from URL when user downloads file


File links are all http://website.com/f/xxx.png/zip/txt and so on.
I need to set it up so that if a user downloads that file it would download with a different name.
I have seen how to do this on a normal page, but I have no clue how making it work when the image itself is linked to is done.

Appreciate any help :)

Edit: Using the rewrite Steven Jeffries posted,

header('Content-Disposition: inline; filename=' . $originalFileName . "'");
header("Content-Type:" . $mimeType);
$im = imagecreatefrompng($filePathOnServer);
imagepng($im);

to display images and

header('Content-Disposition: attachment; filename=' . $originalFileName . "'");
header("Content-Type:" . $mimeType);

to make other files download solved the issues I had.


Solution

  • I think an easy way to do this would be to redirect download links to another script that handles what to download, etc. Basically, I'd set up a download dir, add some rewrite rules, and then create a script to handle what gets output.

    Something like this (untested):

    /path-to-web-root/download/.htaccess

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^.* /downloads/handle-downloads.php
    

    /path-to-web-root/download/handle-downloads.php

    $url = trim($_SERVER['REQUEST_URI'], '/');
    
    if (preg_match('^#downloads/(?<real_filename>.*?)/(?<options>.*)/(?<fake_filename>.*)$#', $url, $matches)) {
        // Double check my regex, but basically pull the real filename from the url here
        $actual_file = "/path-to-webroot/f/{$matches['real_filename']}";
        $options = explode('/', $matches['options']);
        if (in_array('zip', $options)) {
            // Handle zip, etc.
        }
        
        $fake_filename = $matches['fake_filename'];
    
        if (file_exists($actual_file)) {
            header('Content-Description: File Transfer');
            header('Content-Type: application/octet-stream');
            header('Content-Disposition: attachment; filename="'.basename($fake_filename).'"');
            header('Expires: 0');
            header('Cache-Control: must-revalidate');
            header('Pragma: public');
            header('Content-Length: ' . filesize($actual_file));
            readfile($actual_file);
            exit;
        }
    }
    

    Then, instead of having the download link being website.com/f/xxx.png/zip/txt, you could instead do website.com/download/xxx.png/zip/txt/new-filename.png. This would allow you to set the filename to whatever you wanted since the browser will just take what's at the end of the url.

    Edit: I've included the relevant code from readfile's manual page.