skip to Main Content

I would like to trigger an action when Apache detects that a certain file URL has been started for download (or: successfully downloaded).

Example: when https://example.com/download/token_A6FZ523/myfile.zip is downloaded by a client, execute the following query to a SQLite database:

INSERT INTO downloads(date, tokenID) VALUES(CURRENT_TIMESTAMP, "A6FZ523");

Usage: then, in a PHP Dashboard, I can check who has downloaded the delivered files.

I could do this by:

  • running a script every minute on the server,
  • parsing the Apache logs /var/log/apache2/other_vhosts_access.log in search for a pattern download/token_.*/myfile.zip

  • execute the INSERT INTO query in this case

This seems rather complex and the fact of having to run the script every minute is not a nice solution.

What is a good solution to ask Apache to save to a SQLite database the information “The file associated to download token A6FZ523 has been downloaded by the client.”?
Or maybe should PHP be used instead?

2

Answers


  1. I think your problem lies in that you are directly fetching a file that is stored on the server, as opposed to using PHP to “serve” this file programatically. This isn’t the first problem you will encounter with this method, you also can’t check for security or get the file from external file storage (generally speaking, you don’t store files directly on the web server these days!).

    But, simple to do once you know how 🙂

    Firstly, lets change the URL you download your file from to something like https://example.com/download.php?token=A6FZ523

    So, we are sending a GET variable to a php script named “download.php”. In that script you will have something like the following:

    <?php 
    $token = $_GET['token'];
    
    // Get the information about the file from the DB, something like:
    // SELECT filename, size, path FROM files WHERE token = $token;
    // Giving you $filename, $size and $path
    
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename=' . $filename); 
    header('Content-Transfer-Encoding: binary');
    header('Connection: Keep-Alive');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . $size);
    
    echo file_get_contents($path);
    
    // This will be on a completed download
    // INSERT INTO downloads(date, tokenID) VALUES(CURRENT_TIMESTAMP, $token);
    ?>
    

    When the download.php file is called, the token is taken and matched to a file’s info in the DB. You then set headers which basically tells the browser “this is a file”, your browser responds accordingly by implementing a file download as normal. You then read the contents of the file to the user. Once this has been completed, you can log the download via another DB call.

    A big thing to say is that this script (obviously with the DB calls written in) should do the very basics for you, but there is a lot more to add depending on your usage scenario. Think security, input validation, where you store your files and sending a MIME type header.

    Hopefully that should point you in the right direction though 🙂

    Login or Signup to reply.
  2. If you have access to server and authority to install thins you could add mod_log_sql and have the apache save the log directly into a database table (it even parse the info for you) them in your dashboard you can just do simple queries. The “thing” here it seams that you are in need to get the name of the downloader, therefore you should add that “tokenID” to your URL and set the Apache to deny the url if tokenID is not present. You would need to parse the tokenID from url in the log thought.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search