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!
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:
- We specify the file we want to download (
$file = "myfile.pdf"
). - We check if the file exists using
file_exists()
. - 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.
-
- 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 |
---|---|
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:
- Checks if a file parameter was passed in the URL.
- Constructs the full file path (assuming files are in an "uploads" directory).
- If the file exists, it sets up the headers and triggers the download.
- 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:
- We use
basename()
to strip any directory traversal attempts. - We use
realpath()
to get the actual path of the file and the uploads directory. - 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