PHP: Hide the Real File URL and Provide Download via a PHP Script

There are times when you need to store a file (such as one that you sell for profit) outside of the document root of your domain and let the buyers download it via a PHP script so as to hide the real path, web address or URL to that file. Use of this approach enables you to:

  1. Check for permissions first before rendering the file download thus protecting it from being downloaded by unprivileged visitors.
  2. Store the file outside of the web document directory of that domain — a good practice in web security in protecting sensitive and important data.
  3. Count the number of downloads and collect other useful download statistics.
  4. …

Now the actual tip. Given that you have put the file to be downloaded via the PHP script in place at /home/someuser/products/data.tar.gz, write a PHP file with the following content in it and put it in the web document directory where your site visitors can access:

$path = '/home/someuser/products/data.tar.gz'; // the file made available for download via this PHP file
$mm_type="application/octet-stream"; // modify accordingly to the file type of $path, but in most cases no need to do so

header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: " . $mm_type);
header("Content-Length: " .(string)(filesize($path)) );
header('Content-Disposition: attachment; filename="'.basename($path).'"');
header("Content-Transfer-Encoding: binary\n");

readfile($path); // outputs the content of the file

exit();

Now your site visitors can and can only download the protected file via the PHP script.

43 thoughts on “PHP: Hide the Real File URL and Provide Download via a PHP Script”

  1. First, thanks.
    Second, FYI, only relitive paths work on my local apache HTTP server. I can not use ‘/Downloads/test.txt’, I must use ‘../../Downloads/text.txt’. I have yet to get it to work on my real server but I’ll keep trying.

  2. It’s not working for me…

    I’ve tried to use it with ‘pdf’ and ‘doc’ files but it doesn’t work.

    I even changed the Content-Type to ‘application/pdf’ and ‘application/msword’ but it still doesn’t work.

    What it seems to be happening is that it only downloads 1KB of the files.

    For the PDF file for example (456KB) when I try to open I get a message saying that the file is damaged.

    Any ideas of what may be wrong?

    Here’s the script I’m using:

    1) get_file.php:

    2) index.php:

    has a link that calls get_file.php:

    Click here to get the file

    Thanks!

  3. Thanks for sharing this great information. This was helpful to me in learning about how to initiate a file download while protecting the URL of content only to be accessed by authenticated users. Keep up the great work.

  4. Hi your tutorial seems great unfortunatly for me a I have little knoledge of php so I don’t understand how to make it work for me. Can somebody be so kind to explain with some example
    sorry and thank you for your time
    Stefano

  5. Pingback: PHP Security Checklist for Websites and Web Applications – Bottom Line for Every Good PHP Developers

  6. Hi,
    I made a php script from your code, but I can still see the download URL on the page, and so can download the files as well. Do I have to call this script from my download page? I have a thank-you page with the download url.

    Thanks,
    -tejas

  7. The code seems to be working but instead of the file downloading I am getting gibberish in the window. I’ve tried to change the MIME types but nothing seems to be working. The weird thing is that it worked fine the very first time I used it but not since. Does anyone have any ideas?

    Thanks.

  8. Hi im new to all this.
    I need to automate the process of downloading and installing an exe file abc.exe from say ‘http://10.34.45.21:8080/cruisecontrol/artifacts/xxx_trunk_nightly_build/xxx/test/’

    I mean now i have to manually goto ”http://10.34.45.21:8080/cruisecontrol’ then click on each folder before i finally click on the abc.exe file. Then it downloads the exe on my machine. Then i have to double click on the exe to install it. I want to automate this whole process such that when i run the script it will automatically download the exe file and install it. Is it possible to do this using php?

    1. I’m afraid not, or it’d be a major security breach for all the browsers. You can automate the downloading just by giving the full URL address to the file to your site visitors or friends. No need to click through all the directories. However, you can’t make it automatically run on people’s computer after downloading.

  9. I know nothing about PHP, but am looking for a way to allow visitors to part of my site to download an ebook in epub format. Your script is the closest I’ve come to a solution and I thank you for it. However, when the download is completed, the downloaded file receives an additional extension: instead of simply being ROE.epub (the name of the file on the server), it is downloaded as ROE.epub.html.

    Any idea what is wrong? (Could it be that the $mm_type has to be set to a different value than “application/octet-stream”?)

  10. I think I’m missing something. Isn’t the download file itself (at the Real File URL) on the server and viewable by anyone? So copying it to a new location, then downloading, doesn’t change the fact that the orignal file is on the server and viewable by anyone.

    1. There is a folder on server that is publically accessible usually public_html or www but for this to work you should store file in nonpublic folders. Non public folders are not viewable by anyone except scripts/owner. or you can do as ‘Yang Yang’ says

  11. Hi!

    Just wanna tell that this script worked so well for me! I only needed to add some previous filtering code and that’s it.

    I’ve also added your blog to my delicious list 🙂 CU soon!

  12. Excellent script!

    Here’s an interesting question, that probably has a super simple answer, but I do appreciate you putting up with me.

    I’m trying to “download,”/upload a file dynamically to my server, preferably with Php but anything will do. I don’t have access to the actual file name, just a link, such as you created with this script.

    For example, I’m trying to get a video from youtube on to my server. This link will give me the download, but I need to get that file directly to my server instead of my computer first:
    http://bit.ly/eqo2AM

    Any ideas, or could you point me in the right direction? Thank you so much for your help! Get me runnin’ and I’ll definitely link to you as a “consultant”!

  13. just wanted to know that if the file is on someone else’s website, then if i use this script, will my bandwitdh be used?

  14. Hi,
    when I echo the image contents, then it adds 2 white spaces at the start, and thus image gets corrupted..

    Why is that ?

    1. If you are using “echo” for image data, yes – it will corrupt the data.

      For image data, which is binary not text, you should use an “image” statement instead.
      imagepng – for PNG images,
      imagejpg – for JPG images,
      imagegif – for GIF images.

      Also, don’t forget to use the “image_destroy” statement when you are done.

  15. good one, do you have a solution for bigger files? I don’t want to load the whole file to memory at once, say it’s a big like 300MB file. How do i do that?
    thanks.

  16. Hey dude
    Great script but have two very quick questions about this script.

    1. How can i send the user to a page after the download has either started or finished.

    2. How can i get the script to tell my database that the file has been downloaded.

    Thanks ffor your time.

  17. Pingback: PHP Download file outside the Web Root- Tech Support by RAN Services in Augusta, GA

  18. This script works fine.

    If you have a page one.php refering to the download.php to download the file it works fine. Though you can only keep continuing at page one.php after the download is done.

    The page is pausing untill the download is completed how can you avoid this? How can you keep navigating on the one.php?

  19. A thousand thanks!

    It took me a while to realize that there should be no line break in the code. It was driving me crazy!

    Also, this is the link that must be placed in your website to access the download:

    file.extesion

    Also, for newbies like me this can also be useful:
    place this at the beginning, in a new first line
    [/blockquote>

    Again, thanks a lot!!

  20. Hi again,

    Let me ask a question.
    If i have a thousand files i cannot have the same thousand download.php files but say filename1.php, filename2.php…

    Do you know a way of batch creating the download.phps from the name of the files in a folder?

    Or is there a way that the download.php, from the href of the link, knows what file is being asked?

    Thank u!

    1. Actually, it’s relatively simple.

      Change the

      $path = ‘home/someuser/products/data.tar.gz’;

      line to

      $path = ‘home/someuser/products/’ . $_GET[‘filename’];

      Then, when you provide a link to the download file, name it as

      <a href=”download.php?filename=FILENAMEGOESHERE”>download</a>

      Understand?

  21. Hi,

    I am using this script to stream videos from one server to another without the user being able to see the full URL of the videos but now my web host is telling me that their tmp directory is constantly being filled up. What would cause this to happen and what can I do to fix it?

    any help would be appreciated

  22. I am able to get this script to work perfectly when downloading files through a browser on a PC. However, when I try to download a file using this script on a my smartphone (Galaxy Nexus) I download an empty file with the correct name and extension. Do you have an idea why this would happen on a mobile phone/browser?

  23. Just a tip, you might want to add an ‘if file_exists’ to it so that in case of a mistake in the path, no PHP file in which the secret information is being exposed will be downloaded.

    Just put this around the header/readfile/exit:

    if (file_exists($path)) {
    }

    Of course, you can add an else-element to, redirecting to another page or echoing something like ‘Access Denied’ or ‘Doesn’t work’.

  24. Pretty good trick!

    The only problem I have, is that some hosting services (especially for free hosting accounts) do not allow you to store anything above your document root directory.

    I think a better fix for this kind of limitation would be to create your special folder that actually stores the downloadables, and have its permissions marked “x0700”, and have them accessible only through your PHP modules on the server. Another way, would be to rename these files to “dot-named” files if you have that ability with your account. Somelike this example: “saysomething.pdf” => “.saysomething”. Then, you can have PHP read it as normal, but send it as MIME-type “PDF” to the visitor. This can also be used as a means to protect your image files from being scarfed up be harvester-bots, etc. Just as long as you make sure that your PHP module knows the proper MIME-type to send it as.

    Other than that, really great tip. I was looking for a means to do this as a form of “anti-leeching”, together with the proper entries in the site’s “.htaccess” file!

  25. I Have to anonymise a url…how to do that ? the file is hosted on another folders of my server !

  26. Awesome! Thanks for the script. Now I have a page of downloads that are href linked. Would love to figure out how to issue the script in the file just created when the image/text is clicked.

  27. Pingback: Hiring for Custom Script

Comments are closed.

Scroll to Top