Suppose you have a file hosted on an Apache server that is protected by Basic HTTP Authentication, often via an old-school ‘.htaccess’ file, to prevent anonymous users from downloading it without a valid username/password. Then someone asks you to wrap that protected file download with some kind of GUI, maybe a simple HTML form to gather some standard user data (e.g. name and email address). The trouble is once the user has submitted the form they then get prompted separately by the browser to enter a username/password for the HTTP authentication, and this two step process is a bad user experience and looks unprofessional. What you really want to do is ask the user for the username and password as part of the first form, and then just supply those credentials behind the scenes so the download just starts once the form has been submitted. I was recently asked to solve this exact problem, and there simply wasn’t time to address this properly with a nicer solution.
So here is a simple way to pass in credentials for Basic HTTP Authentication from a PHP download script. You must have the PHP “Client URL Library” (“cURL”) extension installed on the web server hosting the PHP script.
If you just want to download the complete working script, you can get it from my GitHub Gist. If you’d like to read about some of the details, please continue…
I’ve hard-coded all the parameters at the top of the script for convenience/simplicity, but you have the option of supporting multiple download files by passing these in via form data, or using some other code logic as required. Likewise I’ve used very simple error-handling by just halting execution on any error – I would recommend changing this to an Exception-based model as required. An obvious error to handle is if the user supplies an incorrect username/password. Ideally you should just display the form again with their other data repopulated, so they just have to re-enter the username/password credentials.
You’ve got two easy options when downloading a remote file to the client browser via a PHP script: (i) cache the file in server memory before streaming to the client, or (ii) download it to a temp file on the PHP script’s server before streaming to the client. If you’re only working with small files and have plenty of memory, option (i) is quicker/easier so that’s what I’ve done here. It’s trivial to change the code to use a temp file using the ‘CURLOPT_FILE’ cURL option.
In order to make sure each PHP process has enough memory available to cache the file contents, you must use the following line:
ini_set('memory_limit', '128M');Code language: PHP (php)
I’ve arbitrarily allowed 128MB of memory here, but you should choose the smallest amount needed for the file(s) in question.
In my case, the Apache server hosting the protected download was running SSL, so I had to add the following extra options to allow cURL to connect and authenticate properly:
curl_setopt($curl, CURLOPT_SSLVERSION, 3); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);Code language: PHP (php)
Just comment out/remove these lines if you’re not using SSL. There are some other possible cURL SSL options that are commented out in my example script as I didn’t need them, but I’ve included them for completeness.
It’s a simple solution to an ugly problem, but I hope it will be useful to someone.