PHP - Download File

Hello there, aspiring PHP developers! Today, we're going to dive into an exciting topic that will allow you to add some cool functionality to your websites - downloading files using PHP. As your friendly neighborhood computer teacher, I'm here to guide you through this journey step by step. So, grab your favorite beverage, get comfortable, and let's start coding!

PHP - Download File

The readfile() Function

At the heart of file downloading in PHP lies the readfile() function. This nifty little function is your go-to tool when you want to read a file and write its contents to the output buffer. Now, don't worry if that sounds a bit technical - we'll break it down together!

Basic Usage

Let's start with a simple example:

<?php
readfile("example.txt");
?>

In this code snippet, readfile() reads the contents of "example.txt" and outputs it directly to the browser. It's like magic - the file's contents appear on your screen!

Downloading Files

Now, here's where it gets interesting. We can use readfile() to prompt a file download. Let's look at a more complete example:

<?php
$file = "myfile.pdf";

if(file_exists($file)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    readfile($file);
    exit;
}
?>

Wow, that's a lot to take in! Let's break it down:

  1. We specify the file we want to download ($file = "myfile.pdf").
  2. We check if the file exists using file_exists().
  3. If it does, we set up a series of headers:
    • Content-Description tells the browser this is a file transfer.
    • Content-Type sets the MIME type to a generic binary file.
    • Content-Disposition prompts the browser to download the file.
    • The other headers ensure the file isn't cached and is treated correctly.
  4. Finally, we use readfile() to output the file contents.

Common File Types

Different file types may require different headers. Here's a handy table of common file types and their corresponding Content-Type headers:

File Type Content-Type Header
PDF application/pdf
ZIP application/zip
JPEG image/jpeg
PNG image/png
MP3 audio/mpeg
MP4 video/mp4

Creating a Download Link

Now that we know how to trigger a download, let's create a user-friendly download link:

<!DOCTYPE html>
<html>
<body>

<h2>Download Files</h2>
<p><a href="download.php?file=myfile.pdf">Download PDF</a></p>

</body>
</html>

In this HTML, we create a link to a PHP script (download.php) that will handle the file download. We pass the filename as a parameter in the URL.

Now, let's create the download.php script:

<?php
if(isset($_GET['file'])) {
    $file = $_GET['file'];
    $filepath = "uploads/" . $file;

    if(file_exists($filepath)) {
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.basename($filepath).'"');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($filepath));
        readfile($filepath);
        exit;
    } else {
        echo "File not found.";
    }
}
?>

This script does the following:

  1. Checks if a file parameter was passed in the URL.
  2. Constructs the full file path (assuming files are in an "uploads" directory).
  3. If the file exists, it sets up the headers and triggers the download.
  4. If the file doesn't exist, it displays an error message.

Security Considerations

Now, I know what you're thinking - "But teacher, isn't this a bit risky? What if someone tries to download files they shouldn't?" Great question! You're absolutely right, and that's why we need to talk about security.

Validating File Paths

We should never trust user input directly. Here's an improved version of our download script:

<?php
if(isset($_GET['file'])) {
    $file = basename($_GET['file']);
    $filepath = "uploads/" . $file;

    // Validate the file path
    $realPath = realpath($filepath);
    $uploadDir = realpath("uploads/");

    if($realPath === false || strpos($realPath, $uploadDir) !== 0) {
        die("Invalid file path.");
    }

    if(file_exists($filepath)) {
        // ... (rest of the download code)
    } else {
        echo "File not found.";
    }
}
?>

In this version:

  1. We use basename() to strip any directory traversal attempts.
  2. We use realpath() to get the actual path of the file and the uploads directory.
  3. We check if the file's real path starts with the uploads directory path, ensuring we're not accessing files outside of the intended directory.

Conclusion

And there you have it, folks! We've journeyed through the land of PHP file downloads, from the basics of readfile() to creating download links and even touched on some important security considerations. Remember, with great power comes great responsibility - always validate user input and think about security when working with file downloads.

I hope you've enjoyed this lesson as much as I've enjoyed teaching it. Keep practicing, keep coding, and before you know it, you'll be creating amazing PHP applications with all sorts of cool download features. Until next time, happy coding!

Credits: Image by storyset