Save and Download BLOB images – PHP and MySQL

In this article, we will show you, how you can save BLOB images in a MySQL database using PHP. You will also be able to download the BLOB images as well. To upload the file to the server and save its path in the MySQL database, you can follow our this tutorial.

Table structure:

Run the following code in your index.php file to create the required table that will hold all saved BLOB images:

<?php
	$conn = mysqli_connect("localhost", "root", "", "blob");
	$sql = "CREATE TABLE IF NOT EXISTS `images` (
		`id` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
        `image` LONGBLOB NOT NULL,
		`name` TEXT NOT NULL,
		`type` VARCHAR (11) NOT NULL
	)";
	mysqli_query($conn, $sql);
?>

Laravel developers can do it in the following way:

use Illuminate\Support\Facades\DB;

Schema::create('images', function (Blueprint $table) {
    $table->id();
    $table->longText("name")->nullable();
    $table->longText("type")->nullable();
    // $table->binary("image");
    // OR
    // $table->longText("image")->charset('binary');
    $table->timestamps();
});

DB::statement("ALTER TABLE images ADD image LONGBLOB DEFAULT NULL AFTER id");

Run your file and you will see a new table created in your phpMyAdmin.

Save BLOB images in MySQL:

First, you need to create an input field from which you can upload an image.

<form method="POST" action="upload.php" enctype="multipart/form-data">
	<p>
		<label>Upload Image</label>
		<input type="file" name="image" accept="image/*" required />
	</p>
	<input type="submit" value="Upload" />
</form>

Create a file named upload.php and write the following code in it:

<?php
	// assume you have a database named 'blob'
	$conn = mysqli_connect("localhost", "root", "", "blob");
	$image = $_FILES["image"];
	$info = getimagesize($image["tmp_name"]);
    if(!$info)
	{
		die("File is not an image");
	}
	$name = $image["name"];
    $type = $image["type"];
	$blob = addslashes(file_get_contents($image["tmp_name"]));

    // if you are developing in Laravel
    // $blob = file_get_contents($file->getRealPath());

	$sql = "INSERT INTO `images` (`image`, `name`, `type`) VALUES ('" . $blob . "', '" . $name . "' , '" . $type . "')";
	mysqli_query($conn, $sql) or die(mysqli_error($conn));
    echo "File has been uploaded.";
?>

Run the code now and you will be displayed an input field and a submit button. Select an image file and hit the submit button, if all goes well, you will see a success message. Then you can check in your database, a new row will be created, the image will be saved as a blob file and the name of the image file will be saved in name column.

Show all Saved BLOB images:

To show all saved BLOB files, you need to run the following code:

<?php
	$conn = mysqli_connect("localhost", "root", "", "blob");
	$sql = "SELECT id, name FROM `images` ORDER BY `id` DESC";
	$result = mysqli_query($conn, $sql);
	
	while ($row = mysqli_fetch_object($result))
	{
?>
	<p>
		<a href="download.php?id=<?php echo $row->id; ?>" target="_blank">
		    <?php echo $row->name; ?>
        </a>
	</p>
<?php } ?>

This will display all saved files in descending order (latest to oldest) in paragraphs. It will also display an anchor tag which when clicked will download the file.

Download BLOB images from MySQL:

To download the Blob file, simply create a file named download.php and write the following code in it:

<?php
	$conn = mysqli_connect("localhost", "root", "", "blob");
	$sql = "SELECT * FROM `images` WHERE `id` = " . $_GET["id"];
	$result = mysqli_query($conn, $sql);
	if (mysqli_num_rows($result) == 0)
	{
		die("File does not exists.");
	}
	$row = mysqli_fetch_object($result);
    header("Content-type: " . $row->type);
	echo $row->image;
?>

To convert the BLOB to base64 in PHP, do the following:

$base64 = "data:" . $row->type . ";base64," . base64_encode($row->image);
// output = data:image/jpeg;base64,9j/4AAQSkZJRgABAQAAAQABA...

Go ahead and click the file name from the list, you will see that file opened in a browser in a new tab. You can simply press Ctrl + S to download the file in your system. Using this method, you can also save your files from direct access from the URL. Since the files are not physically saved anywhere on the server, they will not be directly accessible from the URL.

And since the file can only be accessed via PHP function, you can put additional conditions like allowing download files to premium users only, etc.

[wpdm_package id=’1541′]

Firebase Storage – Upload, Download, and Delete

In this tutorial, we are going to teach you, how you can upload, download and delete files from Firebase Storage. Firebase Storage is a service provided by Google that allows you to save files on their server. The free plan allows you to upload data up to 1 GB. More data can be bought from the Firebase Pricing page.

What you are going to learn:

  1. Upload files on Firebase Storage.
  2. Save the data in Realtime Database.
  3. Fetch files from the Firebase Storage.
  4. Download files from Firebase Storage.
  5. Fix CORS issue if working in localhost.
  6. Install gsutil.
  7. Delete files from Firebase Storage.

Video tutorial:

Upload file

We are going to upload the file to the Firebase storage and save its path in Firebase Realtime Database. It is another service provided by Google to save data in JSON format. To upload the file, we are going to show a form with an input type file that allows the user to select any type of file. We will be using Vue JS to render the HTML to view the data in real-time, for example, newly uploaded files will be displayed automatically and deleted files will be removed from the view without having to refresh the page.

<div id="app">
	<form id="upload-form">
		<input type="file" name="file" required />
		<input type="submit" value="Upload" />
	</form>

    [show all uploaded here]
</div>

<script src="vue.min.js"></script>

This will display a form with an input type file to upload a file. And a submit button which when clicked will submit the form. Vue JS production file can be downloaded from here. Now you need to attach a submit event listener to this form using Javascript.

<script type="module">

	// [initialize firebase here]

	window.addEventListener("load", function () {
		document.getElementById("upload-form").addEventListener("submit", function () {
			event.preventDefault();
			var form = event.target;

			var file = form.file.files[0];
			console.log(file);
			// [upload in storage here]
		});
	});
</script>

If you select the file and hit submit, you will see your selected file object in the browser console. Now you need to do 2 things; initialize firebase, and upload the file. To initialize firebase, you need to create an app at Firebase Console.

  1. Add new project.
  2. Enter name of project.
  3. When project is created, select “web”.
  4. Copy the firebaseConfig variable.

Replace the [initialize firebase here] section with the following:

import { initializeApp } from "https://www.gstatic.com/firebasejs/9.1.0/firebase-app.js";

import { getStorage, ref as stRef, uploadBytes } from "https://www.gstatic.com/firebasejs/9.1.0/firebase-storage.js";

import { getDatabase, ref as dbRef, push, set } from "https://www.gstatic.com/firebasejs/9.1.0/firebase-database.js";

// Your web app's Firebase configuration
const firebaseConfig = {
	apiKey: "",
	authDomain: "",
	projectId: "",
	storageBucket: "",
	messagingSenderId: "",
	appId: ""
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);

// Get a reference to the storage service, which is used to create references in your storage bucket
const storage = getStorage(app);

const database = getDatabase();
const databaseReference = dbRef(database, "files");

Replace the firebaseConfig variable with your firebase configurations. Now replace the [upload in storage here] section with the following:

const storageRef = stRef(storage, "files/" + file.name);

uploadBytes(storageRef, file).then(function (snapshot) {
	var newFileRef = push(databaseReference);

	set(newFileRef, {
		"name": file.name
	});
});

This will upload the file in Firebase Storage in a folder named “files”. You can see it in your project’s dashboard in left menu in “Storage” page. Also, it will create a new element in “files” array in “Realtime Database” page.

Displaying Uploaded Files in Firebase Storage

Now the file is being uploaded in Firebase Storage and it’s path is also being saved in realtime database. Now you need to show all uploaded files. Replace the [show all uploaded here] section with the following:

<table>
	<tr>
		<th>ID</th>
		<th>Name</th>
		<th>File</th>
		<th>Actions</th>
	</tr>

	<tr v-for="file in files">
		<td>{{ file.id }}</td>
		<td>{{ file.name }}</td>
		<td>
			[download link here]
		</td>
		<td>
			[delete button here]
		</td>
	</tr>
</table>

This will create a simple HTML table. Now you need to do the following things:

  1. Initialize Vue JS.
  2. Get all data from realtime database.
  3. Render in HTML table.

You can initialize the Vue JS from the following code:

var vueApp = new Vue({
	el: "#app",
	data: {
		files: []
	},
    // [updated event goes here]
});

Then include “onValue” in your “firebase-database” import. So your firebase database import line will become:

import { getDatabase, ref as dbRef, push, set, onValue } from "https://www.gstatic.com/firebasejs/9.1.0/firebase-database.js";

Note the “onValue” in the import block. Similarly, add the “getDownloadURL” in the import of “firebase-storage”. So your firebase storage import line will become:

import { getStorage, ref as stRef, uploadBytes, getDownloadURL } from "https://www.gstatic.com/firebasejs/9.1.0/firebase-storage.js";

Note the “getDownloadURL” in the import block. Then write the following code in your Javascript:

onValue(databaseReference, function (snapshot) {
	snapshot.forEach(function (childSnapshot) {
		const value = childSnapshot.val();

		const storageRefDownload = stRef(storage, "files/" + value.name);
		getDownloadURL(storageRefDownload).then(function (url) {
			vueApp.files.push({
				"id": childSnapshot.key,
				"name": value.name,
				"url": url
			});
		});
	});
});

You can apply the following CSS styles to make the table look a little nice:

<style>
	table, th, td {
		border: 1px solid black;
		border-collapse: collapse;
	}
	th, td {
		padding: 25px;
	}
</style>

Download File from Firebase Storage

Now you need to download the file. First, you need to replace the [download link here] section with the following:

<a v-bind:href="file.url" v-bind:download="file.name" onclick="downloadFile();">Download</a>

Create the following function in your Javascript:

function downloadFile() {
	// prevent default href action
	event.preventDefault();

	// get URL from href
	var anchor = event.target;
	var url = anchor.getAttribute("href");

	// get blob data
	const xhr = new XMLHttpRequest();
	xhr.responseType = "blob";
	xhr.onload = function (event) {
		const blob = xhr.response;

		// get clickable URL of blob data
		const blogUrl = window.URL.createObjectURL(blob);

		// replace href with new blob value
		anchor.setAttribute("href", blogUrl);

		// remove the onclick listener
		anchor.removeAttribute("onclick");

		// download the file
		anchor.click();

		// free up the memory
		window.URL.revokeObjectURL(blogUrl);
	};
	xhr.open("GET", url);
	xhr.send();
}

// make the function global so it can be accessible from anchor tag onclick
window.downloadFile = downloadFile;

Run the code now, and you will be able to download the file.

Note: If you get a CORS error while working in localhost, then do the following steps:

  1. Download gsutil from here.
  2. Extract the ZIP and paste the folder to a permanent location in your system.
  3. Open the terminal or command prompt in that extracted folder and run the following command in it:
./install.sh
  1. Once installed, run the following command to initialize it:
gcloud init
  1. It will ask for your project name too.
  2. After the project is set and gcloud is initialized, create a file named “cors.json” at the root of your project.
  3. Your “cors.json” must have the following content:
[
	{
		"origin": ["*"],
		"method": ["GET"],
		"maxAgeSeconds": 3600
	}
]
  1. Then run the following command in your terminal:
gsutil cors set cors.json gs://<your-cloud-storage-bucket>
  1. Now try to download the file again, your CORS error should be fixed.

Delete File from Firebase Storage

First, replace the [delete button here] section with the following:

<form class="delete-form">
	<input type="hidden" name="id" v-bind:value="file.id" />
	<input type="hidden" name="name" v-bind:value="file.name" />
	<input type="submit" value="Delete" />
</form>

Then add “deleteObject” in your import of “firebase-storage”. So your import line will look like this:

import { getStorage, ref as stRef, uploadBytes, getDownloadURL, deleteObject } from "https://www.gstatic.com/firebasejs/9.1.0/firebase-storage.js";

Then add the following event in your [updated event goes here] section:

updated: function () {
	var forms = document.querySelectorAll(".delete-form");
    for (var a = 0; a < forms.length; a++) {
    	forms[a].setAttribute("onsubmit", "onDeleteFormSubmit();");
    }
}

This will attach an event listener to every delete form, which will be called when the form is submitted. Now you need to create the following function in your Javascript:

function onDeleteFormSubmit() {
	event.preventDefault();
	var form = event.target;

	const tempDbRef = dbRef(database, "files/" + form.id.value);
	set(tempDbRef, null);

	const deleteStorageReference = stRef(storage, "files/" + form.name.value);
	deleteObject(deleteStorageReference);

	for (var a = 0; a < vueApp.files.length; a++) {
		if (vueApp.files[a].id == form.id.value) {
			vueApp.files.splice(a, 1);
			break;
		}
	}
}
window.onDeleteFormSubmit = onDeleteFormSubmit;

This will first delete the data from the real-time database. Then it will delete the file from Firebase Storage. Finally, it will remove it from the Vue JS array, so it will automatically be removed from the HTML table too.

You can also create a realtime chat in Firebase. Learn how to do it from here.

Now you will be able to upload files to the Firebase Storage and save its path in Realtime Database. And also to download and delete the files from it. If you face any problems facing this tutorial, kindly let us know in the comments section below.

Email download link of a file – PHP and MySQL

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.

Enable less secure apps – Gmail

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.

Learn how to send attachment with an email using PHP.

Attach files in email – PHP

[wpdm_package id=’1281′]

Show progress of download with remaining time – Javascript

Convert time to different timezones

Learn how to show progress of download with remaining time in Javascript. We will be creating a simple bootstrap progress bar.

There are multiple ways to download a file from some website. The easiest way is to simply put an anchor tag with a text “Download”. And give the download attribute. Set the hypertext reference to the file which needs to be download. When the user clicks on it, the file will be downloaded using default browser download manager or via IDM.

However, there are some scenarios where that technique will not help. Take an example of a file with a very large size i.e. 1GB or greater, or a user running on a slow internet connection. The chances are the file may get interrupted during the download. In this case, user might have to re-download the file again. Even if he is using IDM, if the link gets expired then IDM will not resume the file. Instead it will download the file again from start.

Download file inside the browser

The second approach is to download the file inside the browser, show progress of download using a progress bar to the user. When the file is completely downloaded, then show a button which when clicked, will save the file in the selected destination on his computer. In this way, the file will be saved in the computer in just a couple of seconds. Because the file was already been downloaded inside the browser.

There are many other reasons for implementing this technique. For example, you can show advertisements to users until the file gets downloaded. This will help you monetize your website as well.

Get file from server

First we are going to get the file from the server and make it available for download. So, create a button that when clicked when send an AJAX request and get the file from the server. Also, an anchor tag must be created which will give the hypertext reference to the file when completely download in the browser. Lastly, we will add a progress bar which will show the progress of download.

<button id="download-button">Download</button>

<a id="save-file">Save File</a>

<progress id="progress" value="0"></progress>

Now in javascript, first we attach an onclick listener to the button. And call an AJAX request to the file which needs to be downloaded.

<script>
    var fileName = "Archive.zip";

	document.querySelector('#download-button')
		.addEventListener('click', function() {
			request = new XMLHttpRequest();
			request.responseType = 'blob';
			request.open('get', fileName, true);
			request.send();

			request.onreadystatechange = function() {
				if(this.readyState == 4 && this.status == 200) {
					var obj = window.URL.createObjectURL(this.response);
					document.getElementById('save-file').setAttribute('href', obj);

					document.getElementById('save-file').setAttribute('download', fileName);
					setTimeout(function() {
						window.URL.revokeObjectURL(obj);
					}, 60 * 1000);
				}
			};
	});
</script>

First we are creating an AJAX object. Note that the response type must be “blob”. By default, AJAX response type is text but since we wanted the download-able file to be returned from AJAX so we must set the response type to “blob”. In open function, first set the method of ajax which will be GET, then the second parameter should be the complete path of file which needs to be downloaded. We have created a variable where you can place your dynamic value. The first parameter will tell that the request must be asynchronous.

send() in AJAX

send() function will send the request to download the file and onreadystatechange will be called multiple times whenever the state of request changes. For example, when the request sent, when the request received and when the response is sent from the server. Here the readyState having value 4 and status having value 200 indicates the completion of request.

When the response is successfully received, we know that the response will be a downloadable file. Basically it will return the URL from where the user can save the file in his computer. So we will create an object using that URL, we will be using Javascript built-in URL object and call the function createObjectURL and pass the response received from ajax. Note that this response is not a responseText variable which is a string.

When the object is created using that URL, we will simply assign that as hypertext reference to our anchor tag. We are also setting the download attribute to anchor tag which tells the browser that the hypertext link to this anchor tag should be made downloadable.

revokeObjectURL

Since the object is created inside the browser, so it is also occupying some space. We can free it’s allocated resources after a few seconds. For example, the average size of file is 1GB and the user downloads 6 or 7 files, but if you do not free the object resources, then it might end up taking a lot of space in memory of your browser. So we are freeing the resources after 60 seconds, and we need to call the revokeObjectURL function and pass the object variable in it.

Display download progress

Now we need to create a progress bar and a text which will show the download percentage in textual format. In the above step, you can see that we have already created a progress tag, now we also need to create a span tag which shows the progress in percentage.

<span id="progress-text"></span>

<script>
	var progress = document.getElementById("progress");
	var progressText = document.getElementById("progress-text");

	request.onprogress = function(e) {
		progress.max = e.total;
        progress.value = e.loaded;

        var percent_complete = (e.loaded / e.total) * 100;
    	percent_complete = Math.floor(percent_complete);

    	progressText.innerHTML = percent_complete + "%";
	};
</script>

In javascript, first we are getting both nodes (progress & span) in separate variables. AJAX also provides us a method to track progress in an event called onprogress, it will have an argument and it tells the total amount of data that needs to be transferred (the size of file) and the which is currently been transferred so far.

We will set the total amount of data as the maximum value for the progress bar. And it continually changes the value of progress bar to the amount of data being transferred. So you will see the progress bar gradually moves from left to right as the file gets downloaded. The speed of progress bar depends on the size of the file and your internet connection.

File download percentage

So the progress bar has been set, now we display the percentage of the file downloaded in numbers. As we have already created a span tag in HTML and a variable for it in javascript. So we just need to calculate the percentage and display in span tag. We can calculate the percentage of the file downloaded by dividing the file currently downloaded by total size of file. That will return the value in between 0 and 1, for example 0.841. Multiplying this by 100 will return in 84.1 which means that 84.1 percent file has been downloaded.

If you do not want to display the decimal points with it, you can call the floor method and it will return the integer value. Then we simply set this percentage in span tag and add the percentage sign with it too.

Display transfer rate

At this point, if you were downloading that file via IDM or browsers default download manager, you will be able to view the downloading speed of your file. So our next step is to show downloading speed too. Create a simple span tag and get it in javascript as we did earlier. To get the downloading speed, we have to apply some math on it.

<span id="download-progress-text"></span>

<script>
    var downloadProgressText = document.getElementById("download-progress-text");

document.querySelector('#download-button')
		.addEventListener('click', function() {
    var startTime = new Date().getTime();
//// previous code in download button click listener
});

    request.onprogress = function(e) {
        var duration = ( new Date().getTime() - startTime ) / 1000;
    	var bps = e.loaded / duration;
        var kbps = bps / 1024;
        kbps = Math.floor(kbps);

        downloadProgressText.innerHTML = kbps + " KB / s";
    };
</script>

Getting the download speed means we need to know how much KB of data is transferred in one second. Since we are getting downloaded data in bytes so we can convert that in kilo bytes by simply dividing by 1024. First we will get the duration since the file started downloading till now. We can get it by getting the difference between current time and start time. That will return the time in milliseconds, so we can convert that into seconds by dividing with 1000.

When we get the total duration of AJAX then we can get the bytes transferred per second by dividing the data currently transferred by this duration. Now we have the Bytes per second, we can simply convert that to KB by dividing with 1024. Since there are 1024 bytes in one KB. This value may also be in decimal points, so we will convert that into integer too by using the same Math.floor() function. Lastly, we have set this variable in span tag and also display KB/s as string in it.

Get remaining time of download

The algorithm to calculate the remaining time is pretty simple. We get the difference between total size of file and the file currently being downloaded, and divide that by amount of data downloaded in bytes per second. This gives the time in seconds. But we need to show it in minutes too. For example, if this returns 90 seconds, then we need to display it as 1 minute and 30 seconds.

request.onprogress = function(e) {
        ...

        var time = (e.total - e.loaded) / bps;
        var seconds = time % 60;
        var minutes = time / 60;

        seconds = Math.floor(seconds);
        minutes = Math.floor(minutes);

        progress.setAttribute("aria-valuemax", e.total);
        progress.setAttribute("aria-valuenow", e.loaded);
        progress.style.width = percent_complete + "%";
        progress.innerHTML = percent_complete + "%";

        downloadProgressText.innerHTML = kbps + " KB / s" + "<br>" + minutes + " min " + seconds + " sec remaining";
};

No need to create another span tag for it, we will display this data inside span we created for displaying transfer rate. We use the modulus operator to get the remaining seconds, and we apply that to 60 since there are 60 seconds in 1 minute. Similarly, we can divide the time to 60 and it returns the time in minutes since 60 seconds composed of 1 minute.

These seconds and minutes may also be in decimal points, so we convert them to an integer using Math.floor() function as above. Lastly, we are appending that along with KB/s and prepending a line break (<br>) for readability.

Abort ajax request

We can abort any AJAX request using simple abort() function from ajax object. So we are simply creating a button which when clicked will abort the ajax request and you will see that progress of download, text, seconds and minutes will be stopped.

<button onclick="request.abort();" type="button">Abort</button>

Conclusion

This tutorial does not include any external library like jQuery. So you should be able to apply this in your project without having to include any library. It only contains Vanilla JS.

Though we could have use the NetworkInformation API to check transfer rate but it does not support all browsers at the time of writing this. So we do not want you to implement this in your website. Then later find out that your users are having problem downloading the file 🙂

We have tried to create this tutorial as simple and accurate as we can. But if you still find any problem on our side, please do not hesitate to get in touch with us.

[wpdm_package id=’209′]

Upload, Download and Delete files – PHP

We will teach you how you can upload, download and delete files in PHP. We will be implementing 3 functions and will be creating 3 files for each function:

  1. upload.php for uploading the file
  2. index.php for downloading the file
  3. delete.php for deleting the file

Upload file

Start off, by creating 2 files index.php and upload.php, also create a folder named uploads all uploaded files will be stored in this folder. If you are using Mac, you may need to enable permission by following the below steps:

Folder permission for Mac users

Folder permission for Mac users

Now you need to create a simple form that allows a user to select file from his computer to upload in your server:

<form method="POST" action="upload.php" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="submit" value="Upload">
</form>

Next create a file named upload.php and paste the following code in it:

<?php

// Getting uploaded file
$file = $_FILES["file"];

// Uploading in "uplaods" folder
move_uploaded_file($file["tmp_name"], "uploads/" . $file["name"]);

// Redirecting back
header("Location: " . $_SERVER["HTTP_REFERER"]);

At this point, if you execute the index.php file you will be able to select file and when you click Upload button, the selected file should be saved in uploads folder.

Download file

In order to download the file, we are going to display a list of all files and a Download button. Paste the following code in index.php file:

<?php

// This will return all files in that folder
$files = scandir("uploads");

// If you are using windows, first 2 indexes are "." and "..",
// if you are using Mac, you may need to start the loop from 3,
// because the 3rd index in Mac is ".DS_Store" (auto-generated file by Mac)
for ($a = 2; $a < count($files); $a++)
{
    ?>
    <p>
    	<!-- Displaying file name !-->
        <?php echo $files[$a]; ?>

        <!-- href should be complete file path !-->
        <!-- download attribute should be the name after it downloads !-->
        <a href="uploads/<?php echo $files[$a]; ?>" download="<?php echo $files[$a]; ?>">
            Download
        </a>
    </p>
    <?php
}

At this point, if you refresh index.php you will see a list of all your uploaded files along with a Download button. Clicking on the Download button, will open a Download dialog based on your browser.

Delete file

In order to delete the file, first display a button to be clicked to delete. Href should be the full path of the file. The following code should be inserted inside the loop, after the Download button:

<a href="delete.php?name=uploads/<?php echo $files[$a]; ?>" style="color: red;">
    Delete
</a>

Create a new file named delete.php and paste the following code in it:

<?php

// Built-in PHP function to delete file
unlink($_GET["name"]);

// Redirecting back
header("Location: " . $_SERVER["HTTP_REFERER"]);

Now you will see a red button with a text Delete, on click it will delete the file and refresh the index.php page so you will see the remaining files. That’s how you can upload, download and delete the files in PHP.

You can also learn to:

  1. Upload file in Node JS
  2. Download files in BLOB
  3. Upload, download, and delete from Firebase storage from here