In this tutorial, we are going to show you, how you can email a download link of a file to a user when they request to download files from your website. We are going to create a system where you can upload files and the user will be able to download them. But before downloading, they must enter their email address. The link to download the file will be emailed to the user. In this way, you will get a large number of emails. This will help you with a very large email list.
Prevent direct access to files
First, we are going to prevent users from downloading the files directly from the URL. We will be storing all our uploaded files in the “uploads” folder. So, create a new folder named “uploads” at the root of your project. Create a “.htaccess” file in this folder. In this file, write the following single line:
deny from all
This will gives a “403 Forbidden” error whenever someone tries to access the file directly from the browser.
Upload files
Now we are going to create a form that will allow you to upload files. You can create this form in your admin panel because usually, the administrator of the website can upload files.
<form method="POST" action="index.php" enctype="multipart/form-data">
<input type="file" name="file" required />
<input type="submit" name="upload" value="Upload" />
</form>
Create a database named “collect_emails_while_downloading_files” in your phpMyAdmin. Or you can use your own database if you already have one. In this database, you need to create a table where we will store the path and name of all uploaded files.
CREATE TABLE files (
id INTEGER(11) PRIMARY KEY AUTO_INCREMENT NOT NULL,
file_name TEXT NOT NULL,
file_path TEXT NOT NULL
);
Then we need to save the selected file in the uploads folder and its path in the files table in the MySQL database. We will be using PHP PDO prepared statements that will help us from preventing the SQL injection.
<?php
// connect with database
$conn = new PDO("mysql:host=localhost:8889;dbname=collect_emails_while_downloading_files", "root", "root");
// check if form is submitted, for admin panel only
if (isset($_POST["upload"]))
{
// get the file
$file = $_FILES["file"];
// make sure it does not have any error
if ($file["error"] == 0)
{
// save file in uploads folder
$file_path = "uploads/" . $file["name"];
move_uploaded_file($file["tmp_name"], $file_path);
// save file path in database, prevent SQL injection too
$sql = "INSERT INTO files(file_name, file_path) VALUES (:file_name, :file_path)";
$result = $conn->prepare($sql);
$result->execute([
":file_name" => $file["name"],
":file_path" => $file_path
]);
}
else
{
die("Error uploading file.");
}
}
// get all files
$sql = "SELECT * FROM files ORDER BY id DESC";
$result = $conn->query($sql);
$files = $result->fetchAll();
?>
Refresh the page and try uploading a file. You will see it will be saved in your uploads folder and its path and name will be stored in the files table. Also, try accessing that from the browser directly, it will give you a 403 Forbidden error.
Show all uploaded files
In the previous step, we ran a query to fetch all files sorting from latest to oldest. Now we need to show them on a table.
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php foreach ($files as $file): ?>
<tr>
<td><?php echo $file["id"]; ?></td>
<td><?php echo $file["file_name"]; ?></td>
<td>
<!-- button to download file -->
<form method="POST" action="check-email.php" onsubmit="return onFormSubmit(this);">
<input type="hidden" name="id" value="<?php echo $file['id']; ?>" required />
<input type="hidden" name="email" />
<input type="submit" value="Download" />
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
This will show all files in a table with a button to download. When that button is clicked, we need to get the user’s email address so we can email him a download link for that file. That link will be valid for that file and for that email only.
<script>
function onFormSubmit(form) {
// get email address and submit
var email = prompt("Enter your email:", "");
if (email != null && email != "") {
form.email.value = email;
return true;
}
return false;
}
</script>
Send download link in email
We will be using the PHPMailer library to send emails. Open CMD at the root folder of your project and run the following command. Make sure you have the composer downloaded and installed in your system.
composer require phpmailer/phpmailer
Create a table in your database that will store all the download requests of files sent by users. Run the following query in your database in phpMyAdmin:
CREATE TABLE download_requests (
id INTEGER(11) PRIMARY KEY AUTO_INCREMENT NOT NULL,
file_id INTEGER(11) NOT NULL,
email TEXT NOT NULL,
token TEXT NOT NULL,
CONSTRAINT fk_file_id FOREIGN KEY (file_id) REFERENCES files (id) ON DELETE CASCADE ON UPDATE CASCADE
);
Create a file named “check-email.php” and write the following code in it. It will send the email to the user and also will store the data in the above created table.
<?php
// composer require phpmailer/phpmailer
// include PHPMailer library
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php';
// connect with database
$conn = new PDO("mysql:host=localhost:8889;dbname=collect_emails_while_downloading_files", "root", "root");
// get all form values
$id = $_POST["id"];
$email = $_POST["email"];
// generate a unique token for this email only
$token = time() . md5($email);
// get file from database
$sql = "SELECT * FROM files WHERE id = :id";
$result = $conn->prepare($sql);
$result->execute([
":id" => $id
]);
$file = $result->fetch();
if ($file == null)
{
die("File not found");
}
// insert in download requests, prevent SQL injection too
$sql = "INSERT INTO download_requests(file_id, email, token) VALUES (:id, :email, :token)";
$result = $conn->prepare($sql);
$result->execute([
":id" => $id,
":email" => $email,
":token" => $token
]);
// send email to user
$mail = new PHPMailer(true);
try
{
$mail->SMTPDebug = 0;
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = 'your_email@gmail.com';
$mail->Password = 'your_password';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
$mail->setFrom('adnan@gmail.com', 'Adnan');
$mail->addAddress($email); // Add a recipient
$mail->addReplyTo('adnan@gmail.com', 'Adnan');
// Content
$mail->isHTML(true);
$mail->Subject = 'Download your files';
// mention download link in the email
$email_content = "Kindly click the link below to download your files: <br />";
$base_url = "http://localhost:8888/tutorials/collect-emails-while-downloading-files-php-mysql";
$email_content .= "<a href='" . $base_url . "/download.php?email=" . $email . "&token=" . $token . "'>" . $file['file_name'] . "</a>";
$mail->Body = $email_content;
$mail->send();
echo '<p>Link to download files has been sent to your email address: ' . $email . '</p>';
}
catch (Exception $e)
{
die("Message could not be sent. Mailer Error: " . $mail->ErrorInfo);
}
Make sure to change the base URL at line 68. Also, change your email address and password on lines 53 and 54 respectively. This email will be used to send the emails. Goto this link and enable a less secure apps option for that email address.
Test the code now. You will be able to see a list of all uploaded files with a button to download. When clicked, it will show a prompt where you can enter your email address. When clicked “OK”, it will send an email with a download link and also it will store it in the “download_requests” table in the MySQL database.
In your email, you will see a link to download the file. But right now it will give a 404 Not found error because the file is not created yet.
Download the file from email download link
Create a file named “download.php” and write the following code in it. This will directly download the file into your system.
<?php
// connect with database
$conn = new PDO("mysql:host=localhost:8889;dbname=collect_emails_while_downloading_files", "root", "root");
// get variables from email
$email = $_GET["email"];
$token = $_GET["token"];
// check if the download request is valid
$sql = "SELECT *, download_requests.id AS download_request_id FROM download_requests INNER JOIN files ON files.id = download_requests.file_id WHERE download_requests.email = :email AND download_requests.token = :token";
$result = $conn->prepare($sql);
$result->execute([
":email" => $email,
":token" => $token
]);
$file = $result->fetch();
if ($file == null)
{
die("File not found.");
}
// download the file
$url_encoded_file_name = rawurlencode($file["file_name"]);
$file_url = "http://localhost:8888/tutorials/collect-emails-while-downloading-files-php-mysql/uploads/" . $url_encoded_file_name;
// die($file_url);
// headers to download any type of file
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $file["file_name"] . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file["file_path"]));
readfile($file["file_path"]);
Make sure to change your base URL at line 26. Now you can run a complete test cycle again. Upload a file, click the download button, and enter your email. Check your email and then click the download link from the email and the file will be downloaded. Verify the file that is downloaded correctly.
So that’s how you can collect a large number of emails by allowing people to simply download files. You can create a very large email list from it.