How to create Token-based Download [Part 1]

Reading Time: 8 minutes

In this article, we are going to try and create a token-based Download system where you can download any type of content via an access token. In our example, we will create a little Website that acts as a user interface (enter the code). Creating a backend system including a database will also be covered.

Prerequisites

Our system will be built using PHP as backend, a MySQL-Database (interchangeable) and a little framework called Materialize for styling our Webpage. To run PHP you need a webserver but luckily XAMPP has our back covered as they provide an “all in one” tool for running our PHP-Backend and our Database. With all of this setup and our preferred Editor in front of us, we can start coding.

Create the folder structure

We are going to start by creating the needed files. First, you have to navigate to your installed XAMPP-Folder. The important folder for us is the “htdocs” folder. This holds all files that are accessible through the browser by typing “localhost” in the address bar. You should find a folder called “dashboard”. It holds basic files that are created by XAMPP but are not important for what we want to do.

Folder for the frontend

So in the “htdocs” folder, we want to create a new one and name it for example “download”. That means to access it we need to type “localhost/download” into the address bar. If you do so nothing will show up except for an error saying “can not reach”. That’s because we haven’t started the webserver yet. To do so we want to open the XAMPP Program. Once open look for the Module called “Apache” and click “Start”. Now go back to your browser and search for ” localhost/download” and you should see something like this:

Showing the index of /download folder
How to create Token-based Download
Working webpage with no content

Open your newly created folder. Now comes the part we create the structure of our project. As this is held relatively simple we will make it a simple structure. Start with creating the “index.php” file, then the “style.css” and the “download.js” file. All these names can be changed according to your delight (We could also create a folder for each css and js file but as there are only one of each we won’t do that).

Showing the folder structure
How to create Token-based Download
Files contained in the folder

Folder for the backend

Now comes the interesting part. We need to access a database and we only want people with a token to be able to download a file. We can achieve this by creating a non-public folder. One way is to move up the folder structure (in our case outside of “htdocs”) and place the files there. So move up the folders until you see folders like “apache”, “htdocs” and so on. Create a folder called “download-files” and inside start a file called “backend.php”. This file is per se not accessible through your browser and that is exactly what we want. Now we can start coding!

Coding the User-interface / Frontend

We start with the “Index.php” file. This file will hold the input for the Token and will be the only visible part for the user. First, we want to add “Materialize”, “jQuerry” and our “download.js” to the <header>. As said before Materialize will be used for styling and jQuerry will be used for GET-Request(s) within the “download.js”.

<head>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="style.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="download.js"></script>
</head>

Next, we start with the “visuals”. That means in the <body> Tag we will add the following code:

<body>
    <div class="container">
        <!-- First Card Panel -->
        <div class="card-panel grey lighten-3">Download your video - Description</div>
        <div class="card-panel grey lighten-3">
            <!-- Field to enter Code -->
            <div class="input-field">
                <!-- Input field -->
                <input id="code" type="text" class="validate">
                <!-- Label for Input field -->
                <label for="code">Access Token</label>
                <!-- Text displayed below as helping text AND text for error -->
                <span class="helper-text" data-error="Dein Code ist inkorrekt">Please enter your token</span>
            </div>
            <!-- Start process to check the code -->
            <div class="center-align">
                <!-- Button to check the code -->
                <a class="waves-effect waves-light btn" onclick="checkCode()">Check</a>
                <!-- Banner for showing when the token is wrong -->
                <div id="wrong" class="scale-transition scale-out">Wrong token. Please try again</div>
            </div>
        </div>
    </div>
</body>

The classes are predefined by Materialize so if you want more information on that look here. The Page is divided into 2 card panels. The top one for showing the title and possible description. The second one as input. So the second card contains an input field (id=”code”) with according labels and help-text. Below is a button that has a click event. When the button is being clicked the method “checkCode()” from “download.js” is being called. Whenever the code is wrong the div (id=”wrong”) will be shown.

Showing the Webpage with no function yet
How to create Token-based Download
Webpage but with no functionality yet

So now let’s carry on with the download.js file

Coding the download.js file

This file will be used for checking if our code is valid and if so to open a new tab that will automatically download the file. The download will be achieved by our backend that comes later. So let’s start by creating our main function checkCode()

function checkCode() {
}

This function will do nothing so let’s change that. We need to check if our code is valid. To do so we create a GET-Request with jQuerry. What we want to do is access the “checkCode.php” and appending the code as a parameter. We do so by typing the following code:

function checkCode() {
    //Get the Code entered
    var codeEl = document.getElementById("code");
    var code = codeEl.value;
    //Call backend for checking code
    $.get("checkCode.php", {code: code}, function (data) {}
}

When calling the $.get() function we have to pass 3 parameters. The URL as a string, the code which will be the parameter for the URL and a function that is being called when we get a response. Inside this function we add the following:

$.get("checkCode.php", {code: code}, function (data) {
        //If successfull open download window
        if (data.success) {
            //Work around for Popup blocking
            //Open a new blank tab
            var tabOpen = window.open("about:blank", 'newtab');
            //After 0.1 seconds set the location for download
            window.setTimeout(function () {
                tabOpen.location = 'http://localhost/download/sendData.php/?code=' + code;
            }, 100);
            //Close new open tab after one second
            window.setTimeout(function () {
                tabOpen.close();
            }, 1000);
        }
});

Let’s break this part of the code down. First, we have an if-statement. This will check if the “data-object” contains boolean success. If so and only if it is true we go into the next part. We know the token is correct. So we open a new blank tab. With a timeout of 100ms, we wait and then change the location to ” http://localhost/PrivateVideoDownload/backend/sendData.php/?code=’ + code”. This is the link for downloading the file according to the given token. The only reason we open a blank tab first is that we get flagged as popup otherwise and the user won’t be able to download the file. After one second we close the newly opened (optional).

Display warnings for incorrect token

But what will happen if the entered code is wrong? We want to notify the user. We have two ways to do so.

  1. Change the color of the Input field and show the error message
  2. Show the banner below the button for clearly indicating that the code is wrong

For the first part we want to create two more functions:

//Function to toggle (on or off) that code is invalid by toggling class
function toggleIncorrect(){
    var code = document.getElementById("code");
    code.classList.toggle("invalid");
}
//Function to toggle (on or off) that code is valid by toggling class
function toggleCorrect(){
    var code = document.getElementById("code");
    code.classList.toggle("valid");
}

The “toggleIncorrect()” function will get the input filed by its id and toggle the class “invalid”. That will render the input field in red color and show the defined error message. The toggleCorrect() function will do the “opposite” and render the field in a green color

For the second part we need to add the following function:

//Function to toggle (on or off) the Warning by toggling the class
function toggleWarning() {
    var element = document.getElementById("wrong");
    element.classList.toggle("scale-out");
}

This will toggle the scaled-out class of our banner. What that means is that with materialize you will have a little popout animation when the code is wrong and will disappear when it is correct.

Calling the functions

With both functions in place, all that is missing is the logic to when calling which function. This will happen within checkCode().

function checkCode() {
    //Get the Text that says your code is wrong and if visible (!scale-out) then toggle
    var element = document.getElementById("wrong");
    if (!element.classList.contains('scale-out')) {
        toggleWarning();
    }
    //Get the Code entered
    var codeEl = document.getElementById("code");
    var code = codeEl.value;
...

Before we look for the entered code we want to check if the banner showing that the code is wrong has been triggered before and is visible to the user. We do this by check whether the classList contains the class “scale-out”. If so the banner is not visible. Otherwise (see the “!” for negating) we want to toggle it to remove the banner.

So after this call, the banner should be invisible no matter what! Let’s carry on with the next part:

if (data.success) {
            ...
            window.setTimeout(function () {
                tabOpen.close();
            }, 1000);

            //Toggle Warning if visible --> Closes it
            if (!element.classList.contains('scale-out')) {
                toggleWarning();
            }
            //Toggle valid if not yet --> Set the input field as valid
            if (!codeEl.classList.contains('valid')) {
                toggleCorrect();
            }
        } 

The last two if-statements are for making the banner invisible and the input field show as valid. Now onto the last piece of coder for this part

$.get("backend/checkCode.php", {code: code}, function (data) {
...
} else {
            //Code was wrong! Show Toast and toogle Warning and invalid the input field
            M.toast({ html: 'Your token is incorrect!' })
            toggleIncorrect();
            toggleWarning();
        }

These lines of code server three purposes:

  1. Show an item called “a toast”. This is a little box (also served by Materialize) that pops in and can contain any HTML code
  2. Toggle the input field to show as invalid
  3. Toggle the banner to show the “incorrect”-message

If we are finished implementing the backend as well (Part 2) we will see how the warnings will work.

Showing the warning
How to create Token-based Download
The final result in how it will look

Conclusion part 1

After this part, we should have a solid webpage that is accessible but not functional. All of that will follow in part two so stay tuned. If all worked out you should have a folder structure for further use and two files with code that look like this:

Index.php
<html>

<head>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="style.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="download.js"></script>
</head>

<body>
    <div class="container">
        <!-- First Card Panel -->
        <div class="card-panel grey lighten-3">Download your video - Description</div>
        <div class="card-panel grey lighten-3">
            <!-- Field to enter Code -->
            <div class="input-field">
                <!-- Input field -->
                <input id="code" type="text" class="validate">
                <!-- Label for Input field -->
                <label for="code">Access Token</label>
                <!-- Text displayed below as helping text AND text for error -->
                <span class="helper-text" data-error="Dein Code ist inkorrekt">Please enter your token</span>
            </div>
            <!-- Start process to check the code -->
            <div class="center-align">
                <!-- Button to check the code -->
                <a class="waves-effect waves-light btn" onclick="checkCode()">Check</a>
                <!-- Banner for showing when the token is wrong -->
                <div id="wrong" class="scale-transition scale-out">Wrong token. Please try again</div>
            </div>
        </div>
    </div>
</body>

</html>
download.js
function checkCode() {
    //Get the Text that says your code is wrong and if visible (!scale-out) then toggle
    var element = document.getElementById("wrong");
    if (!element.classList.contains('scale-out')) {
        toggleWarning();
    }
    //Get the Code entered
    var codeEl = document.getElementById("code");
    var code = codeEl.value;
    //Call backend for checking code
    $.get("backend/checkCode.php", {code: code}, function (data) {
        //If successfull open download window
        if (data.success) {
            //Work around for Popup blocking
            //Open a new blank tab
            var tabOpen = window.open("about:blank", 'newtab');
            //After 0.1 seconds set the location for download
            window.setTimeout(function () {
                tabOpen.location = 'http://localhost/PrivateVideoDownload/backend/sendData.php/?code=' + code;
            }, 100);
            //Close new open tab after one second
            window.setTimeout(function () {
                tabOpen.close();
            }, 1000);

            //Toggle Warning if visible --> Closes it
            if (!element.classList.contains('scale-out')) {
                toggleWarning();
            }
            //Toggle valid if not yet --> Set the input field as valid
            if (!codeEl.classList.contains('valid')) {
                toggleCorrect();
            }
        } else {
            //Code was wrong! Show Toast and toogle Warning and invalid the input field
            M.toast({ html: 'Dein Zugangscode ist inkorrekt' })
            toggleIncorrect();
            toggleWarning();
        }
    });
}
//Function to toggle (on or off) the Warning by toggling the class
function toggleWarning() {
    var element = document.getElementById("wrong");
    element.classList.toggle("scale-out");
}
//Function to toggle (on or off) that code is invalid by toggling class
function toggleIncorrect(){
    var code = document.getElementById("code");
    code.classList.toggle("invalid");
}
//Function to toggle (on or off) that code is valid by toggling class
function toggleCorrect(){
    var code = document.getElementById("code");
    code.classList.toggle("valid");
}

If so congratulation you have made a few big steps into finishing this system. Thanks for reading and stay tuned for part two and all the other cool stuff we post.

If you have any questions about today’s tutorial, just ask us in the comments, on Twitter or Instagram or send us a mail.

Liam

3 comments

Leave a Reply

Your email address will not be published. Required fields are marked *