2 factor Login Authentication – PHP & Twilio SMS

In this tutorial, we are going to implement 2 factor login authentication. 2 factor login authentication means that user will be verified twice before login.

  1. 1st factor should be what they know, like password or some security question.
  2. 2nd factor will be what they have, like mobile or fingerprint.

Database structure

First create a table where all users data will be stored. You might already have that if you are working on existing project. You need to add a new field “phone” in your existing “users” table because we will be sending SMS to this field value. There should be an option to enable or disable this 2 factor authentication, so a boolean field named “is_tfa_enabled”. Also a pin number which will be sent as SMS.

users

  • id int(11) NOT NULL AUTO_INCREMENT
  • email text NOT NULL
  • password text NOT NULL
  • phone text NOT NULL
  • is_tfa_enabled tinyint(1) NOT NULL
  • pin text NOT NULL

User registration

During registration, we need to add a new field for phone number. Below is a sample registration form with password encryption.

Set default values to following fields:

  • “is_tfa_enabled” as false
  • “pin” as empty
<form method="POST" action="register.php">
	
	<input type="email" name="email">
	<input type="password" name="password">
	<input type="text" name="phone">
	
	<input type="submit" name="register">
</form>

register.php

<?php

	if (isset($_POST["register"]))
	{
		$email = $_POST["email"];
		$phone = $_POST["phone"];
		$password = $_POST["password"];
		$password = password_hash($password, PASSWORD_DEFAULT);

		$conn = mysqli_connect("localhost", "root", "", "tutorials");
		
		$sql = "INSERT INTO users (email, phone, password, is_tfa_enabled, pin) VALUES ('$email', '$phone', '$password', 0, '')";
		mysqli_query($conn, $sql);

		header("Location: login.php");
	}

?>

User login – Send OTP

There will be no extra field in login, it will have email/username and password or whatever fields you are using to login. The important thing is, we need to send an SMS if the user has enabled 2-factor authentication. Below is a typical login form:

<form method="POST" action="login.php" id="form-login">
	<input type="email" name="email">
	<input type="password" name="password">
	
	<input type="submit" name="login">
</form>

We will send an SMS using Twilio if user has enabled 2-factor authentication. First you need to include Twilio PHP library in your project using composer. Open terminal in your project root folder and run the following command to install Twilio:

composer require twilio/sdk

Create an account on Twilio from here. After creating account, you will be given a $15 balance to test the API. On your Twilio console dashboard you will find your “account SID” and “auth token”. You will need to place those on below variables accordingly:

Twilio console

login.php

<?php

	session_start();

	require_once "vendor/autoload.php";
	use Twilio\Rest\Client;

	$sid = "";
	$token = "";

	if (isset($_POST["login"]))
	{
		$email = $_POST["email"];
		$password = $_POST["password"];

		$conn = mysqli_connect("localhost", "root", "", "tutorials");
		
		$sql = "SELECT * FROM users WHERE email = '$email'";
		$result = mysqli_query($conn, $sql);

		if (mysqli_num_rows($result) > 0)
		{
			$row = mysqli_fetch_object($result);
			if (password_verify($password, $row->password))
			{
				if ($row->is_tfa_enabled)
				{
					$row->is_verified = false;
					$_SESSION["user"] = $row;

					$pin = rand(0, 9) . rand(0, 9) . rand(0, 9) . rand(0, 9) . rand(0, 9) . rand(0, 9);
					
					$sql = "UPDATE users SET pin = '$pin'  WHERE id = '" . $row->id . "'";
					mysqli_query($conn, $sql);

					$client = new Client($sid, $token);
					$client->messages->create(
						$row->phone, array(
							"from" => "",
							"body" => "Your adnan-tech.com 2-factor authentication code is: ". $pin
						)
					);

					header("Location: enter-pin.php");
				}
				else
				{
					$row->is_verified = true;
					$_SESSION["user"] = $row;

					header("Location: index.php");
				}
			}
			else
			{
				echo "Wrong password";
			}
		}
		else
		{
			echo "Not exists";
		}
	}

?>
  1. We need to call session_start() in order to use any $_SESSION variable.
  2. If the user has provided correct email and password, then we are checking if that user has enabled 2-factor authentication for his account.
  3. Then we are generating a random pin code of 6 digits and sending it to the user’s phone number.
  4. We are using “is_verified” field in $_SESSION to check if user account is pin verified or not.
  5. After SMS has been sent, you will be redirected to “enter-pin.php” where you need to enter the pin sent in SMS.

enter-pin.php

This file will only contain 1 field to enter pin code. User ID is already been stored in $_SESSION.

<form method="POST" action="enter-pin.php">
	<input type="text" name="pin">
	
	<input type="submit" name="enter_pin">
</form>

And when this form submits, we are simply going to check the entered pin with database and login the user. We also need to empty the pin from database so that it cannot be used again.

<?php

	session_start();

	if (isset($_POST["enter_pin"]))
	{
		$pin = $_POST["pin"];
		$user_id = $_SESSION["user"]->id;

		$conn = mysqli_connect("localhost", "root", "", "tutorials");
		
		$sql = "SELECT * FROM users WHERE id = '$user_id' AND pin = '$pin'";
		$result = mysqli_query($conn, $sql);

		if (mysqli_num_rows($result) > 0)
		{
			$sql = "UPDATE users SET pin = '' WHERE id = '$user_id'";
			mysqli_query($conn, $sql);

			$_SESSION["user"]->is_verified = true;
			header("Location: index.php");
		}
		else
		{
			echo "Wrong pin";
		}
	}

?>

Now after verification user will be redirected to “index.php” which is by default the home of every website. You might already have a check to prevent the user from entering this page without login. Just need to change few things,

  • Check if user is logged in and pin verified.
  • A switch to turn on/off 2-factor authentication.
  • A link to logout the user.

index.php

<?php

session_start();
$conn = mysqli_connect("localhost", "root", "", "tutorials");

if (isset($_SESSION["user"]) && $_SESSION["user"]->is_verified)
{

	$user_id = $_SESSION["user"]->id;

	if (isset($_POST["toggle_tfa"]))
	{
		$is_tfa_enabled = $_POST["is_tfa_enabled"];

		$sql = "UPDATE users SET is_tfa_enabled = '$is_tfa_enabled' WHERE id = '$user_id'";
		mysqli_query($conn, $sql);

		echo "Settings changed";
	}

	$sql = "SELECT * FROM users WHERE id = '$user_id'";
	$result = mysqli_query($conn, $sql);
	$row = mysqli_fetch_object($result);

	?>

	<form method="POST" action="index.php">
		<h1>Enable TFA</h1>

		<input type="radio" name="is_tfa_enabled" value="1" <?php echo $row->is_tfa_enabled ? "checked" : ""; ?>> Yes
		<input type="radio" name="is_tfa_enabled" value="0" <?php echo !$row->is_tfa_enabled ? "checked" : ""; ?>> No

		<input type="submit" name="toggle_tfa">
	</form>

	<a href="logout.php">
		Logout
	</a>

	<?php
}
else
{
	header("Location: login.php");
}

We are displaying 2 radio buttons and an ability to automatically select the radio based on enable or disability of 2-factor authentication. You can use the same condition on all pages which you want to show to only authenticated users. Now we just need to logout the user. We have created a link with text “Logout” which when clicked will redirect the user to “logout.php” page.

logout.php

<?php

session_start();
unset($_SESSION["user"]);
session_destroy();
header("Location: login.php");

?>

Re-send OTP after 30 seconds

If you want to resend the OTP after 30 seconds, first, we need to call a Javascript function using setTimeout method.

setTimeout(function () {
// [call AJAX here]
}, 30 * 1000)

Then we need to call an AJAX to resend the OTP. The following code goes in the [call AJAX here] section:

const form = document.getElementById("form-login")

const ajax = new XMLHttpRequest()
ajax.open("POST", "login", true)

ajax.onreadystatechange = function () {
	if (this.readyState == 4) {
		if (this.status == 200) {
			console.log(this.responseText)
		}
	}
}

const formData = new FormData(form)
ajax.send(formData)

Show timer

If you want to show the timer for 30 seconds. First, create a <div> where the timer text will be displayed.

<div id="timer"></div>

Then we need to call a setInterval function to call each second and decrement the value.

let seconds = 30

const timerInternval = setInterval(function () {
	seconds--
	document.getElementById("timer").innerHTML = seconds
	if (seconds <= 0) {
		stopInterval(timerInternval)
	}
}, 1000)

That’s how you can add 2 factor login authentication with a timer on your website. If you want to know how to add “reset password” feature in your website, check our free tutorial here.

https://drive.google.com/file/d/1NosW0DI4WBG6cFz9f0xzluNAnkBPma1H/view?usp=sharing

UICollectionview with search bar – Swift iOS

In this article, we are going to show you how you can create a UICollectionview with search bar in Swift for your iOS application.

First, we will create a collection view and populate the data in it. We are using a MySQL database for employees table and a PHP API to fetch all employees data from database. The output of API will be in JSON format. So, we will also learn how to encode JSON data in Swift. We will be displaying employee number and name in it.

Create UICollectionView using storyboard

  1. First goto your storyboard, search for collection view and drag in in your main view.
  2. Your collection view will have a cell inside it. Search for label for employee number and drag it inside collection view cell.
Select collection view cell and set a custom class
add an identifer

Now select collection view, goto outlets, and attach data source & delegate of collection view to your view controller class.

Create a class for single cell layout named SingleCellView.swift:

import UIKit

class SingleCellView: UICollectionViewCell {
	// drag label outlet here
}

Select label from storyboard and drag it inside SingleCellView class:

Note: To drag label from storyboard into SingleCellView class, oepn storyboard, goto “Navigate” in menu and select “Open in assistant editor”. Then select the class file from left sidebar and it will appear in second window.

Populate data in UI collection view

We are receiving an array of objects from the API. Each object has employeeNumber, firstName, lastName, email and other fields as displayed above. We need to display them in each collection view cell:

EmployeeModel.swift

import Foundation

class EmployeeModel: Decodable {
    public var employeeNumber: String!
    
    public var firstName: String!
}
  1. Create an outlet for collection view same as we did for collection view cell labels.
  2. Open viewcontroller file and extend it with UICollectionViewDataSource and UICollectionViewDelegate
  3. Implement 2 functions, first for total number of items in collection view, and second for populating data in collection view cell.
  4. Create an array of EmployeeModel objects and initialize it as an empty array.
  5. We will be using NSURLConnection.sendAsynchronousRequest to fetch data from API.
  6. When the response is received, we validate the data using guard statement to make sure it is not null.
  7. Decode the JSON string into EmployeeModel array.

ViewController.swift

import UIKit

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UISearchBarDelegate {
    
    private var data: [EmployeeModel]! = []
    private var realData: [EmployeeModel]! = []
    
    @IBOutlet weak var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let url: URL = URL(string: "http://192.168.43.64/test/api.php")!
        var request: URLRequest = URLRequest(url: url)
        request.httpMethod = "GET"
        
        // if using POST
//        request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
//        let dataStr: String = "value=1&value=2"
//        let postData: Data = dataStr.data(using: .utf8)!
//        request.httpBody = postData
        
        NSURLConnection.sendAsynchronousRequest(request, queue: .main) { (response, data, error) in
            
            guard let data = data else {
                print(error)
                return
            }
            
            let responseString: String! = String(data: data, encoding: .utf8)
            
            do {
                
                let jsonDecoder: JSONDecoder = JSONDecoder()
                self.data = try jsonDecoder.decode([EmployeeModel].self, from: data)
                
                self.realData = self.data
                
                self.collectionView.reloadData()
            } catch {
                print(error.localizedDescription)
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.data.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let singleCell: SingleCellView = collectionView.dequeueReusableCell(withReuseIdentifier: "singleCell", for: indexPath) as! SingleCellView
        
        singleCell.employeeNumber.text = self.data[indexPath.item].employeeNumber
        
        singleCell.firstName.text = self.data[indexPath.item].firstName
        
        return singleCell
    }
}

Add search bar in collection view

First select your collection view and enable section header. This will create a re-usable view inside collection view.

  1. Search for “Search bar” and drag it inside re-usable view. Also give it a identifier like we did for collection view cell.
  2. Set the custom class for re-usableview (in our case SearchBarView.swift), we will create that class in a moment.

SearchBarView.swift

import UIKit

class SearchBarView: UICollectionReusableView {
	// drag search bar outlet here same as we did for collection view cell
}
  1. Add delegate of search bar to our view controller same as we did for collection view delegate.
  2. Extend view controller class with UISearchBarDelegate and implement 2 more functions in this class.
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {

	let searchView: UICollectionReusableView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "SearchBar", for: indexPath)
	return searchView
}

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
	self.data.removeAll()
        
	for item in self.realData {
		if (item.firstName.lowercased().contains(searchBar.text!.lowercased())) {
			self.data.append(item)
		}
	}
        
	if (searchBar.text!.isEmpty) {
		self.data = self.realData
	}
	self.collectionView.reloadData()
}

Now you will have a working UICollectionView with search bar in your iOS application.

Video tutorial:

Get realtime notification from contact us form to admin panel – Node JS

You can receive realtime notification on your admin panel for your website’s contact us form using simple Node JS script. You can download Node JS from here and install it in your system.

Above screenshot is the demo of what we are going to create. On left we have contact us page from where users can send a message to admin. And on right we have admin panel where admin will be able to view messages without refreshing the page.

Sending message from contact us form

Your typical contact us form might have the following fields:

<form action="#">
	<input type="text" id="name">
	<input type="text" id="email">
	<input type="text" id="subject">
	<textarea id="message"></textarea>

	<input type="button" onclick="sendMessage()" value="Send Message">
</form>

<script>
	function sendMessage() {
		//
	}
</script>

You might also have different fields too but it does not matter. The most important thing is, your form should:

  1. Have ID attribute to all fields.
  2. For submit button, input type must be “button”, not “submit”.
  3. The button needs to have an “onclick” listener.
  4. A function with same name must be created inside script tag.

Now we will be sending an event from socket. You can all an AJAX function too if you want to perform other actions too. First you need to include socket-io.js in your project, you can use the below CDN link to do that. Paste the following code anywhere in your contact us page:

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>

Then you have to create an instance for IO object and in sendMessage() function, you have to emit an event using this IO object. Sending an event is commonly refer to as “Emitting an event”.

var socket = io("http://192.168.43.64:3000");

function sendMessage() {
	socket.emit("messageSent", {
		"name": document.getElementById("name").value,
		"email": document.getElementById("email").value,
		"subject": document.getElementById("subject").value,
		"message": document.getElementById("message").value
	});

	// Call an AJAX for further actions you want to perform (like saving in database etc.)
}

io constructor will receive an IP address and port number where Node JS server will be running. You can get your local IP address from terminal by running the command: ifconfig and search for line having “ipv4”, your local IP address will be right next to “ipv4”. You can run your Node JS project on any port number other than 8080 (default for apache) and 3306 (default for MySQL). It will return a socket object which can be used to send an receive events from server. To send an event, we will calling a function named emit(eventName, data), it has 2 argument:

  1. First argument is the name of event that needs to be send.
  2. Second will be the data that needs to be send with this event. Here you can place all your contact us fields using their IDs.

Node JS server

Now we need a medium which will listen to this event and respond accordingly. So we assume that you have installed Node JS in your computer.

  1. Create a folder named “nodejs-server” anywhere in your system. I am creating it at desktop.
  2. Open terminal in that folder (shift + right click) and run the following command one at a time:
npm init

This will initialize the folder as Node JS project.

npm install express

This will install the express module used to create a server.

npm install http

This module will be used to start the server at specific port (3000 in our case).

npm install socket.io

This module will be used to listen events from client, and emit events to clients.

server.js

Create a file named “server.js” in newly created folder (“nodejs-server” in our case) and paste the following code in it:

var express = require("express");
var app = express();

var http = require("http").createServer(app);
var io = require("socket.io")(http);

http.listen(3000, function () {
    console.log("Server connected");

    io.on("connection", function (socket) {
        console.log("User " + socket.id);

        socket.on("messageSent", function (message) {
            socket.broadcast.emit("messageSent", message);
        });
    });
});

Remeber this file is a Javascript file so it does not need a <script> tag in it. We will explain each later in a moment. To start the server, run the following command in terminal or command prompt in that folder:

node server.js
  • First we created an instance of express and initialize it, saved it in a variable named “app”.
  • Similarly, we created “http” and “socket.io” instances. Http is created from express module. And socket.io is created from Http.
  • Then we start the server using listen function. First parameter will be port number and second will be a call back function that will be called when the server started running.
io.on("connection", function (socket) {
  • This function will be called when a new client connected with Node JS server. Client is connected by calling io() function from web page.
  • Then we are listening to “messageSent” event from client. That function will be called when client emits that event (in our case, from contact us form).
  • Then we are sending this event to all other connected clients. Broadcast will send the event to all connected clients other than the one who sends it.

Receive realtime notification on admin panel

So we are emitting event from contact us form and broadcasting it to all other connected clients from Node JS app. But who are the “other clients” ?
The one who will be listening to that event. So we are going to make admins to listen to that event. Paste the following code in all files on admin panel where you want to receive realtime notifications. Or you can paste them in admin template’s header or footer file as that will be included in each file.

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/notify/0.4.2/notify.js"></script>

<script>
	var socket = io("http://192.168.43.64:3000");

	socket.on("messageSent", function (message) {
		$.notify("New Message\n" + message.message + "\n\nFrom: " + message.name, {
			autoHide: false,
			className: "success"
		});
	});
</script>

First we added socket IO and created an instance like we did for contact us page. We are using https://notifyjs.jpillora.com/ library to display a simple alert realtime notification but once you have attach an event listener, you can display the realtime notification as per you need. jQuery is also added for notify.js, otherwise you do not need jQuery for socket IO.

That’s how you can receive realtime notification from your contact us form in your admin panel. Learn how to create a realtime customer support chat widget from here.

Custom sort – jQuery UI, AJAX, PHP & MySQL

We are going to implement a custom sort using jQuery UI, which helps you to customize the order of data being displayed on your website. First, add CDN for jquery and jquery UI. Goto cdnjs.com to get CDN link for jQuery and visit this link to get CDN link for jQuery UI. Copy the JS link for jQuery, and CSS and JS links for jQuery UI. Create 2 script tags for jQuery and jQuery UI JS and one link tag for jQuery UI CSS.

index.php

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js">
</script>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css">

<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js">
</script>

First you need to show all data from database. Here we are connecting with our sample database and displaying all products based on their product code.

<?php

    $conn = mysqli_connect("localhost", "root", "", "classicmodels");
    $result = mysqli_query($conn, "SELECT * FROM products ORDER BY productCode DESC");

?>
  1. Create a div container which will enclose all data.
  2. Create a while loop to run through all records in database.
  3. Inside this loop, create a div tag which will represent each product separately.
  4. Give it a class so it will group each product under same class.
  5. and give it a unique ID, now ID will be the value which will tell the order of all products in an array. In our database, unique ID of product is productCode, so we will use that. But you must use as per your database table.
<div id="myData">
    <?php while ($row = mysqli_fetch_object($result)) { ?>

        <div 
            class="item"
            id="<?php echo $row->productCode; ?>"
            style="margin-top: 0px; margin-bottom: 0px;">
                
            <img
                src="<?php echo $row->image; ?>"
                style="width: 200px;">

            <h3><?php echo $row->productName; ?></h3>

        </div>
    <?php } ?>
</div>

Now we need to find a way to able to drag them so we can move them. So,

  1. Create a script tag.
  2. Attach a listener which will be called when the page is fully loaded.
  3. Select the div container using ID.
  4. Call sortable function, it exists in jquery UI. Its constructor will receive an object where you can specify options.
<script>

    window.products = [];
    
    $(function () {
        $("#myData").sortable({
            "items": ".item",
            "opacity": 0.6,
            "cursor": "move",
            "update": function (event, ui) {
                var data = $("#myData").sortable("toArray");
                
                // if using table
                // data = data.filter( n => n );

                window.products = data;
            }
        });
    });
</script>

jQuery UI sortable options

  1. “items”: Selector of each individual item. So we will use the div inside loop having class class=”item”.
  2. “opacity”: Give it an opacity, so when we select some product it will be highlighted among others.
  3. “cursor”: A cursor which will be displayed on div only during dragging an item.
  4. “update”: A function which will be called when you finish dragging some item from one place to another.

The update function has 2 parameters, events and UI (although we are not going to use any of them but you might need them in your case). Inside this function, we will get the new order of items in a variable. Select the main div container tag using its ID selector and call sortable function same as above. And inside it pass the argument “toArray”. It will return all items unique ID in a sorted array.

If you are using tables instead of divs, you might receive first element of array as empty string. You can prevent this by calling filter function to this array. Passing n means to remove null or empty strings.

Save custom sequence in database

Now we will create a button which when clicked will save this data in selected sequence.

<button type="button" onclick="saveData();">Save</button>

Create a function inside script tag:

function saveData() {
    var ajax = new XMLHttpRequest();
    ajax.open("POST", "save.php", true);
    ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    ajax.send("data=" + JSON.stringify(window.products));

    ajax.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            console.log(this.responseText);
        }
    };
}
  1. First create an AJAX object.
  2. Call open method and set the request method to “POST”.
  3. Second parameter will be the name of file where data needs to be sent.
  4. Since this is a post request, so we also need to attach a header for content type.
  5. And send the data will be in name value pair separated by ampersand sign.
  6. Since we want to send an array so we need to convert that into JSON string.
  7. onreadystatechange event will be fired when the response has been received from server.

save.php

Create a new file named “save.php” which will handle the request. First make a connection with database. Create a new table in database which will hold the sequence of products, its structure will be as below:

Table name: product_order, columns:

id integer auto increment
product_id integer
order_number integer
Then in “save.php” paste the following code:

<?php

    $conn = mysqli_connect("localhost", "root", "", "classicmodels");

    $data = json_decode($_POST["data"]);

    mysqli_query($conn, "DELETE FROM product_order");

    $sql = "INSERT INTO product_order(product_id, order_number) VALUES";

    for ($a = 0; $a < count($data); $a++)
    {
        $sql .= " ('" . $data[$a] . "', '" . ($a + 1) . "')";

        if ($a < count($data) - 1)
        {
            $sql .= ",";
        }
    }

    mysqli_query($conn, $sql);
    echo "Done";

?>

First get all data that we are receiving in a separate variable, and since we are sending JSON string so we need to decode that JSON back in PHP array. First of all, whenever the sequence of products changes, we have to remove all the previous sequence from database. Then we will prepare an SQL query to insert the new sequence in product order table. So loop through each product ID. Product ID will be what we are receiving from AJAX. Order number must be starting from 1, to 2 3 and so on, that is why we are incrementing in variable $a.

Display data by custom sort

Now go back to index.php and change the SQL query to following:

<?php

$conn = mysqli_connect("localhost", "root", "", "classicmodels");

$result = mysqli_query($conn, "SELECT * FROM products INNER JOIN product_order ON products.productCode = product_order.product_id ORDER BY product_order.order_number ASC");

?>

So we just need to change this query to display products based on order number from product_order table. Inner join with product_order, based on productID. And order by order_number from product_order table. Ascending order will make it start from 1 to 2 and 3 and so on.

That’s how you can implement a custom sort in jQuery UI using AJAX, PHP and MySQL.

[wpdm_package id=’219′]

class file for com.google.android.gms.internal.zzbfm not found Firebase and Google maps – Solution

Today, we will share with you the solution for class “zzbfm” not found error while working on Firebase and Google maps.

If you are ever facing an error in android that says:

class file for com.google.android.gms.internal.zzbfm not found

It is most likely when you just integrated Firebase library in your project that is already using maps, location or places.

The solution to this is:

  1. Version number of google maps and Firebase should be same.
  2. Change “implementation fileTree” to “compileOnly fileTree”
  3. Enable multiDex and add multiDex library

app > build.gradle

android {
    compileSdkVersion 28
//    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "your.application.id"
        minSdkVersion 22
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        multiDexEnabled true // important
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
//    implementation fileTree(include: ['*.jar'], dir: 'libs')
    compileOnly fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'com.google.android.gms:play-services-maps:11.8.0'
    implementation 'com.google.android.gms:play-services-location:11.8.0'
    implementation 'com.google.android.gms:play-services-places:11.8.0'

    implementation 'com.google.firebase:firebase-core:11.8.0'
    implementation 'com.google.firebase:firebase-messaging:11.8.0'
    implementation 'com.google.firebase:firebase-database:11.8.0'

    implementation 'com.android.support:multidex:1.0.3'
}
apply plugin: 'com.google.gms.google-services'

build.gradle

buildscript {
    repositories {
        jcenter()
        google()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.2'
        classpath 'com.google.gms:google-services:4.0.1'
    }
}

If your problem persists, please mention it in the comments section below. Check Google cloud platform for more services.

Learn how to embed maps without API key.

Maps without API Key – By Coordinates & By Address

Emoji ratings feedback – Javascript

Learn how to get feedback from your website users using emoji ratings. We will be using plain Javascript. No external library has been used in this tutorial.

Below is a list of all possible emojis at the time of writing this. You can found any new emoji missing, please do inform us in the comments section below.

SmileyHTML code
😀&#x1F600;
😁&#x1F601;
😂&#x1F602;
😃&#x1F603;
😄&#x1F604;
😅&#x1F605;
😆&#x1F606;
😇&#x1F607;
😈&#x1F608;
😉&#x1F609;
😊&#x1F60A;
😋&#x1F60B;
😌&#x1F60C;
😍&#x1F60D;
😎&#x1F60E;
😏&#x1F60F;
😐&#x1F610;
😑&#x1F611;
😒&#x1F612;
😓&#x1F613;
😔&#x1F614;
😕&#x1F615;
😖&#x1F616;
😗&#x1F617;
😘&#x1F618;
😙&#x1F619;
😚&#x1F61A;
😛&#x1F61B;
😜&#x1F61C;
😝&#x1F61D;
😞&#x1F61E;
😟&#x1F61F;
😠&#x1F620;
😡&#x1F621;
😢&#x1F622;
😣&#x1F623;
😤&#x1F624;
😥&#x1F625;
😦&#x1F626;
😧&#x1F627;
😨&#x1F628;
😩&#x1F629;
😪&#x1F62A;
😫&#x1F62B;
😬&#x1F62C;
😭&#x1F62D;
😮&#x1F62E;
😯&#x1F62F;
😰&#x1F630;
😱&#x1F631;
😲&#x1F632;
😳&#x1F633;
😴&#x1F634;
😵&#x1F635;
😶&#x1F636;
😷&#x1F637;
🙁&#x1F641;
🙂&#x1F642;
🙃&#x1F643;
🙄&#x1F644;
🤐&#x1F910;
🤑&#x1F911;
🤒&#x1F912;
🤓&#x1F913;
🤔&#x1F914;
🤕&#x1F915;
🤠&#x1F920;
🤡&#x1F921;
🤢&#x1F922;
🤣&#x1F923;
🤤&#x1F924;
🤥&#x1F925;
🤧&#x1F927;
🤨&#x1F928;
🤩&#x1F929;
🤪&#x1F92A;
🤫&#x1F92B;
🤬&#x1F92C;
🤭&#x1F92D;
🤮&#x1F92E;
🤯&#x1F92F;
🧐&#x1F9D0;

Create input slider range

Create a div to display default emoji ratings, for example if you want the default feedback about communication to be “satisfied” then display the following emoji:

<div class="emoji-container">

<h3>Communication</h3>

<div class="emoji">
	🙂
</div>

<p class="emoji-text">Satisfied</p>

<input type="range" name="status[communication]" min="0" max="4" step="1">
</div>

To view the emoji in large size, simply change the font size of emoji class. If you want to show the horizontal arrows for input type range, just change the cursor CSS property.

<style>
	.emoji {
		font-size: 60px;
	}
	input[type="range"] {
		cursor: ew-resize;
	}
</style>

Change emoji ratings with slider

Now create an array to store all type of emojis you want to display with your slider, and the meaning of each emoji in array of objects. Then we need to loop through all input type ranges and attach onmousemove listener to each slider.

Whenever the value of slider changes, we will get the emoji object using value of slider, and display it in emoji-container. This will replace emoji and its meaning text to whatever the value of current slider is.

If you are using only one slider in your document, you can use simply document.querySelector(“.emoji-container”) to get the container div of that emoji.

<script>
	var emojis = [
		{ emoji: "&#x1F621", text: "Hate it"},
		{ emoji: "&#x1F613", text: "Difficult to understand"},
		{ emoji: "&#x1F642", text: "Satisfied"},
		{ emoji: "&#x1F600", text: "Very happy"},
		{ emoji: "&#x1F618", text: "Loved it"}
	];

	var range = document.querySelectorAll("input[type='range']");
	for (var a = 0; a < range.length; a++) {
		range[a].onmousemove = function (event) {
			var index = this.value;
			var emojiContainer = this.closest(".emoji-container");

			emojiContainer.querySelector(".emoji").innerHTML = emojis[index].emoji;
			emojiContainer.querySelector(".emoji-text").innerHTML = emojis[index].text;
		};
	}
</script>

To save these feedback in database, enclose all your emoji-container divs in form tag and specify method as POST, and action to the file which will process this form data. If you sending input type file too, you also need to add an attribute enctype=”multipart/form-data” to form tag.

<form method="POST" action="save-feedback.php">
	<!-- All above emoji containers here -->
	<input type="submit">
</form>

Save data in database

We have created a simple database named tutorials and a table named feedback. It just has three columns, communicationservice and support. The data type of these columns will be INTEGER as in database we just be saving ratings on a scale of 1 to 5. First parameter in $_POST array will be name of input type range, and second will be the associative index we have set. Here we are receiving 3 types of feedback from user. The insert query is pretty basic.

save-feedback.php

<?php

$conn = mysqli_connect("localhost", "root", "", "tutorials");

$communication = $_POST["status"]["communication"];
$service = $_POST["status"]["service"];
$support = $_POST["status"]["support"];

$sql = "INSERT INTO feedback(communication, service, support) VALUES('$communication', '$service', '$support')";
mysqli_query($conn, $sql);

echo "Done";

?>

Change the emoji using slider and hit the submit button. You will see a new row will be inserted in database with integer value in respective columns. These integer values will tell the user feedback on a scale of 1 to 5.

Display on admin side

Now you might have an admin panel where you want to see the ratings given by user. So we will call a simple AJAX request to fetch those feedbacks from database. Our emojis array will remain same, and we can display the respective emoji based on database column value. First create an API page that will return all feedbacks in JSON format.

get-feedback.php

<?php

$conn = mysqli_connect("localhost", "root", "", "tutorials");

$sql = "SELECT * FROM feedback";
$result = mysqli_query($conn, $sql);

$data = array();
while ($row = mysqli_fetch_object($result))
{
	array_push($data, $row);
}
echo json_encode($data);

?>

Now back in index.php, we will send a simple AJAX request which will return all feedbacks in JSON string. We will parse that JSON into javascript arrays and objects. Create a div where all emojis needs to be displayed and display them using simple for loop.

<div id="feedback"></div>
var ajax = new XMLHttpRequest();
ajax.open("GET", "get-feedback.php", true);
ajax.send();

ajax.onreadystatechange = function () {
	if (this.readyState == 4 && this.status == 200) {
		var data = JSON.parse(this.responseText);
		var html = "";

		for (var a = 0; a < data.length; a++) {
			var communicationIndex = data[a].communication;
			var communication = emojis[communicationIndex];

			var serviceIndex = data[a].service;
			var service = emojis[serviceIndex];

			var supportIndex = data[a].support;
			var support = emojis[supportIndex];
				
			html += "<p>Communication: <span class='emoji'>" + communication.emoji + "</span>" + communication.text + "";

			html += "<p>Service: <span class='emoji'>" + service.emoji + "</span>" + service.text + "</p>";

			html += "<p>Support: <span class='emoji'>" + support.emoji + "</span>" + support.text + "</p>";
		}

		document.getElementById("feedback").innerHTML = html;
	}
};

Run this script on your admin panel and you will be able to view the user added feedback in emoji ratings and their meaning.

Learn how to calculate average ratings from here.

[wpdm_package id=’216′]

Multiple file upload in bootstrap modal – PHP & MySQL

We will teach you how you can create a bootstrap modal that handles multiple file upload and save them in MySQL database.

Download Bootstrap FileDialog

You are going to need a library called Bootstrap FD, you can get it from here. After downloading the library, extract the ZIP file and goto “dist” folder. Here you will find CSS and JS files, copy them in your project and include them in your header or footer. This library requires bootstrap and jQuery to be included in your project. If you have setup the bootstrap and jQuery, you can just use their CDN links rather than downloading.

<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>

<link rel="stylesheet" href="bootstrap.fd.css">
<script src="bootstrap.fd.js"></script>

First we have included the bootstrap CSS file, then jQuery and then bootstrap JS file. Because bootstrap JS also requires jQuery so you must include the jQuery before bootstrap JS. You can change the version number of CDN links if there is new version available.

Show multiple file upload dialog

Create a button which when clicked will call a function in Javascript. To open the bootstrap modal, we have to use the function $.FileDialog() and this will open the pop-up where you can drag and drop your files. For multiple file upload, we will not be using an input type file. But we will be using a library called FileDialog. You can also set options for this dialog, for example, whether you want the user to select only images files or all type of files etc.

<form>
	<button type="button" onclick="selectFiles();">
		Select files
	</button>

	<input type="submit">
</form>
<script>
	function selectFiles() {
		$.FileDialog({
			"accept": "image/*"
		})
	}
</script>

To preview the image files selected by user, just add a div tag and give it a unique ID.

<div id="selected-images"></div>

Preview selected images

And change your $.FileDialog function to the following. “files.bs.filedialog” function will be called when user select the files and press “OK”. Create a global array which will hold all images. All selected images will be received in “event.files” array, so loop through it and push in that global array. Create a string variable which will hold the img tag HTML. In the same loop, we are creating an img tag and each object of “event.files” array contains a variable named “content” while contains the content of image. This can be used.

window.selectedImages = [];

$.FileDialog({
	"accept": "image/*"
}).on("files.bs.filedialog", function (event) {
	var html = "";
	for (var a = 0; a < event.files.length; a++) {
		selectedImages.push(event.files[a]);
		html += "<img src='" + event.files[a].content + "'>";
	}
	document.getElementById("selected-images").innerHTML += html;
});

To save these images on server, give your form a unique ID and attach an onsubmit event with it. We will be using FormData object to send all images and other form fields via AJAX. And onsubmit event will prevent the default behaviour of form. This will prevent the form from submitting and will call your javascript function.

Call AJAX to upload file

This function will create a new FormData object and append all images in it. Make sure to add brackets “[]” with images key so it will send all images as array. Otherwise, only the last selected image will be processed by server. Then it sends a neat AJAX request in Vanilla JS and attach the form data in it.

After the server processed the files and send the response back to client, you will need to show some text to user or wants to redirect to different page. So in “onreadystatechange” event you can put all your code which needs to be executed once response is received from server.

<form id="form" onsubmit="return submitForm();">
function submitForm() {
	var form = document.getElementById("form");
	var formData = new FormData(form);

	for (var a = 0; a < selectedImages.length; a++) {
		formData.append("images[]", selectedImages[a]);
	}

	var ajax = new XMLHttpRequest();
	ajax.open("POST", "Http.php", true);
	ajax.send(formData);

	ajax.onreadystatechange = function () {
		if (this.readyState == 4 && this.status == 200) {
			console.log(this.responseText);
		}
	};

	return false;
}

Http.php

In this file, create a connection with your database (you might have already set up). Create a separate table where path of each image will be saved. Loop through all the images, insert them in database, and finally save the image file in your server. Create a new folder named “images” or any other of your choice, where all images will be stored. Timestamp is prepended with each image name just to make it unique. As you might have seen, if you download some image from facebook or whatsapp, it always has a different name no matter if that image is uploaded by another person.

<?php

$conn = mysqli_connect("localhost", "root", "", "tutorials");

for ($a = 0; $a < count($_FILES["images"]["name"]); $a++)
{
	$path = "images/" . time() . "-" . $_FILES["images"]["name"][$a];

	$sql = "INSERT INTO images(image_path) VALUES('$path')";
	mysqli_query($conn, $sql);

	move_uploaded_file($_FILES["images"]["tmp_name"][$a], $path);
}

echo "Done";

That’s how you can create a bootstrap modal that handles multiple file upload and save them in MySQL database in PHP.

Learn how to show progress bar while uploading the file.

[wpdm_package id=’213′]

Android cache SQLite

You can optimize your app performance by using cache data in Android using SQLite. We will be using Stetho library to see the cached data.

Basic use of cache in SQLite is to display frequently accessed data faster in your android app. And to reduce the overhead on the server. There are already tons of libraries available that automatically handles the API cache data for you. But nothing gives more control than writing the code by yourself. So in this tutorial, we will create a custom cache mechanism in SQLite. So we can decide when to expire the cache and which data needs to be cached in android system and which should not.

Volley default cache

By default, Volley does provide a method to cache the API response data. But it only caches the response which is already been received using Volley request. Consider this, you have a list of employee records which are being fetched from API. And then you have another API which receives employee ID and gives you detail about that employee. If you are using Volley’s cache mechanism then it only displays that employee data faster whose details you have already been seen. But using your custom technique, you can save all employees data in the SQLite cache. And get the detail of any employee using their ID.

1. Create an API

You might have your own API code based on your project, but for sake of this tutorial we have create a basic API which connects with database. Fetch all rows from employees table, push the data in an array and send the response back in JSON. We could have use the mysqli_fetch_all() function but it is not supported in some of the PHP versions. So following this technique you will be able to use this without having to worry about version of PHP.

<?php

$conn = mysqli_connect("localhost", "root", "", "classicmodels");
$result = mysqli_query($conn, "SELECT * FROM employees");

$data = array();
while ($row = mysqli_fetch_object($result))
{
    array_push($data, $row);
}
echo json_encode($data);

?>

Setup android project

We have created a new android project to demonstrate the working of SQLite cache. But you might be implementing this in your own project. So we will only discuss the libraries you need to install. And some minor settings you need to do in some of your project files. Open your app > build.gradle file and paste the following dependencies in it:

implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.volley:volley:1.1.1'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.facebook.stetho:stetho:1.5.1'

You can change the version number as per your project’s target SDK version. Android studio will highlight the dependencies if there is an update in Volley, Gson and Stetho libraries. After adding these dependencies, you need to sync the project. Then add internet permission in your AndroidManifest.xml file before starting of application tag. This will help you to call HTTP requests:

<uses-permission android:name="android.permission.INTERNET" />

Stetho library will be used to display SQLite inside google chrome inspect tools. Create a new class named MyApplication.java and extend it with Application:

package com.adnan.app.sqlitecache;

import android.app.Application;
import com.facebook.stetho.Stetho;

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        Stetho.initializeWithDefaults(this);
    }
}

This will initialize the Stetho library and whenever you have some data in SQLite database tables, you will be able to see it by running chrome://inspect in your browser address bar (where you put website URL). Then set this class as application main class by giving name attribute to application tag in AndroidManifest.xml:

<application
        android:name=".MyApplication"

Setup layouts

Now we will setup the layout to create a recycler view where all employees data will be displayed. Also an adapter layout where each single employee data will be displayed. Create an adapter class which will hold each employee item, and a model class which tells the structure of data received from server. Create a recycler view in your activity layout file and get its instance in activity class file and initialize it.

EmployeeModel.java

package com.adnan.app.sqlitecache.models;

public class EmployeeModel {

    private String firstName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
}

EmployeeAdapter.java

package com.adnan.app.sqlitecache.adapters;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.adnan.app.sqlitecache.R;
import com.adnan.app.sqlitecache.models.EmployeeModel;

import java.util.ArrayList;

public class EmployeeAdapter extends RecyclerView.Adapter {

    private Context context;
    private ArrayList models;

    public EmployeeAdapter(Context context, ArrayList models) {
        this.context = context;
        this.models = models;
    }

    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(context).inflate(R.layout.single_employee, viewGroup, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
        viewHolder.name.setText(models.get(i).getFirstName());
    }

    @Override
    public int getItemCount() {
        return models.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        private TextView name;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            name = itemView.findViewById(R.id.name);
        }
    }
}

We are passing the activity context and models array from activity to adapter using adapter’s constructor. Context will help to setup the single layout file and models array helps to tell how many items should be rendered in this adapter and each item’s index.

single_employee.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:layout_margin="20dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Name"
        android:id="@+id/name"/>

</RelativeLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/rv" />

</RelativeLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {
	private RecyclerView rv;
	private EmployeeAdapter adapter;
	private ArrayList models;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		rv = findViewById(R.id.rv);
		rv.setHasFixedSize(true);

		LinearLayoutManager layoutManager = new LinearLayoutManager(this);
		rv.setLayoutManager(layoutManager);

		models = new ArrayList<>();
		adapter = new EmployeeAdapter(this, models);
		rv.setAdapter(adapter);
	}
}

Get data from API

We will be using Volley library to send an HTTP request to API and fetch response as JSON string. Make sure you have added Volley dependency and synced the project. Also, make sure you have added internet permission in your android manifest. Create a new method in activity class and call it from onCreate method after the adapter has been set in recycler view.

private void getData() {
	String url = "Your API URL";
	RequestQueue requestQueue = Volley.newRequestQueue(this);

	StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
		@Override
		public void onResponse(String response) {
			Log.i("my_log", response);
		}
	}, new Response.ErrorListener() {
		@Override
		public void onErrorResponse(VolleyError error) {
			Log.i("my_log", error.getMessage());
		}
	});

	requestQueue.add(stringRequest);
}

Here our request method is GET and you can place your API URL in a variable named url. At this point, if you run the app in debug mode and open your logcat, you will be able to see the response after a few seconds (depends on the server and query execution time). If you saw any error in logcat, make sure you have added internet permission and double-check your API URL set in url variable.

This function will be called when the app is ran for the first time. Because for the first time, the android cache will empty since there is no data in SQLite database.

Mirror android to PC or Mac

Sometimes you might want to see your android device in your PC or Mac. You can use Vysor app which is available for both Mac and Windows, however, we do not recommend that because of too many pop-up ads. But we recommend to use the scrcpy library. You can install it from instructions on GitHub site and to run it, simply attach your android device and run the following command in your terminal:

> scrcpy

Convert JSON to ArrayList

We will be using Gson library to convert JSON string into Java array list. In onResponse of Volley request, create a try catch block because converting JSON to array will throw an exception if the data is not in correct JSON format. Even if you have any special character in your database, it will not be able to parse JSON data. We need to use the TypeToken class to convert json to array, if it were simple object then we would have simply used EmployeeModel.class but in case of array, we have to use TypeToken.

try {
	Gson gson = new Gson();
	Type type = new TypeToken<ArrayList<EmployeeModel>>() {}.getType();
	models = gson.fromJson(response, type);
} catch (Exception e) {
	Log.i("my_log", e.getMessage());
}

Filter data in adapter

Create a new method named showData() in activity and call it after the JSON has been converted into array list of models.

MainActivity.java

private void showData() {
	adapter.setFilter(models);
}

And in adapter add a new method which will remove old model data and add new data, and update the adapter to render the items again. The reason we are doing this is because at the time of assigning adapter to recycler view, our arraylist was empty. So if we do not use this method, then we will not be able to see any data in recycler view.

EmployeeAdapter.java

public void setFilter(ArrayList data) {
	this.models.clear();
	this.models.addAll(data);
	notifyDataSetChanged();
}

Show progress bar

If you want to display progress bar inside each adapter item, you can place this progress bar tag in your adapter layout file. This is typically useful when you are displaying images from HTTP, as they may take some time to display, so you can show a progress bar when the image is fully loaded. But here we will be displaying one progress bar in center of the screen, so we are creating progress bar tag in activity layout.

activity_main.xml

<ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:id="@+id/progressBar"/>

MainActivity.java

private ProgressBar progressBar;

// in onCreate after setContentView
progressBar = findViewById(R.id.progressBar);

// update showData method
private void showData() {
	adapter.setFilter(models);
	progressBar.setVisibility(View.GONE);
}

Setup SQLite

Create a new class named SQLiteManager and extend it from SQLiteOpenHelper. It has 2 abstract methods, onCreate and onUpgrade so you must implement them in your class. onCreate will be called only once, but onUpgrade will be called whenever you change your database version. Create a constructor for this class and call the super constructor, in super constructor we will tell the database name and version. In onCreate method, you will set your all tables structure (DDL). You can perform any function you want in onUpgrade method, but the common practice is, since we are upgrading the database version, it means that we may have remove some columns and have added some new columns, may be created a new table altogether. So the best practice is to remove all old tables structures and all data in them. Then call the onCreate method manually.

SQLiteManager.java

package com.adnan.app.sqlitecache.managers;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.adnan.app.sqlitecache.models.EmployeeModel;
import java.util.ArrayList;

public class SQLiteManager extends SQLiteOpenHelper {

    public SQLiteManager(Context context) {
        super(context, "android_cache", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "CREATE TABLE IF NOT EXISTS employees(" +
                "name TEXT NOT NULL)";
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE employees");
        onCreate(db);
    }
}

Insert data in SQLite

Add the following method in your SQLiteManager class:

SQLiteManager.java

public void addData(EmployeeModel employeeModel) {
	SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
	ContentValues contentValues = new ContentValues();

	contentValues.put("name", employeeModel.getFirstName());
	sqLiteDatabase.insert("employees", null, contentValues);
	sqLiteDatabase.close();
}

Now in your activity class, in Volley onResponse method, when the JSON response has been converted to array list models, we will loop through all data in array and call this function for each employee. So create an instance of SQLiteManager class and initialize it and do the following:

MainActivity.java

private SQLiteManager sqLiteManager;

// in onCreate
sqLiteManager = new SQLiteManager(this);

// in Volley onResponse after models = gson.fromJson(response, type);
for (int a = 0; a < models.size(); a++) {
	sqLiteManager.addData(models.get(a));
}

This will add the data in SQLite database whenever we call an API request. But this will always append new data, so we need to find a way to delete old data whenever new data is received from API.

Delete data from SQLite

Create the following function in your SQLiteManager class:

SQLiteManager.java

public void deleteOldCache() {
	SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
	sqLiteDatabase.execSQL("DELETE FROM employees");
	sqLiteDatabase.close();
}

And call this function from your activity class:

MainActivity.java

// in Volley onResponse before for (int a = 0; a < models.size(); a++) and after models = gson.fromJson(response, type);
sqLiteManager.deleteOldCache();

View data from SQLite

At this point, the data has been saved correctly in SQLite. Now we need to make the app to read from SQLite database if there is any data, otherwise the data will be fetched from API. So the first time when app gets installed, it will not have any data in SQLite, so it will fetch from API and save in SQLite. Next time it will found the data, so it will read it from SQLite instead of sending the API request again.

SQLiteManager.java

public ArrayList getData() {
	ArrayList data = new ArrayList<>();
	SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
	Cursor cursor = sqLiteDatabase.rawQuery("SELECT * FROM employees", null);

	if (cursor.moveToFirst()) {
		do {
			EmployeeModel employeeModel = new EmployeeModel();
			employeeModel.setFirstName(cursor.getString(0));
			data.add(employeeModel);
		} while (cursor.moveToNext());
	}

	return data;
}

MainActivity.java

ArrayList cache = sqLiteManager.getData();

if (cache.size() > 0) {
	models = cache;
	showData();
} else {
	getData();
}

Now it will only fetch the data from API once and saved it in SQLite. Next time it will fetch from SQLite rather than from API. But the only problem is, it will always fetch it from SQLite. So we need to find a way to expire the cache after some time.

Set cache expiry time

You can set the expiry time of cache in simple seconds and you can do the math of converting seconds into minutes and hours and days etc. For example, if you want to expire the cache after 18 hours, you can simply do (60 * 60 * 18 = 64800). We will be using android shared preferences to store the time when data was cached or saved in SQLite. Then before checking if to get data from cache or from API, we need to check if the cache has been expired. We can do that by taking the difference between current time and the time when data was cached. Since Java date function returns time in milliseconds, so we can simply convert them to seconds by dividing them with 1000. Then our condition will say:

Check if there is any data in cache AND the cache is not expired.

MainActivity.java

private SharedPreferences preferences;

// in onCreate
preferences = PreferenceManager.getDefaultSharedPreferences(this);

boolean isCacheExpire = false;
long cacheTime = preferences.getLong("cache", 0);

if (cacheTime > 0) {
	long currentTime = new Date().getTime();
	long difference = currentTime - cacheTime;
	long seconds = difference / 1000;

	if (seconds > 20) {
		isCacheExpire = true;
	}
}

if (cache.size() > 0 && !isCacheExpire) {
	models = cache;
	showData();
} else {
	getData();
}

And set the cache time in shared preference in Volley onResponse method, after data has been saved in SQLite:

preferences.edit().putLong("cache", new Date().getTime()).apply();

Complete MainActivity.java

package com.adnan.app.sqlitecache;

import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;

import com.adnan.app.sqlitecache.adapters.EmployeeAdapter;
import com.adnan.app.sqlitecache.managers.SQLiteManager;
import com.adnan.app.sqlitecache.models.EmployeeModel;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;

public class MainActivity extends AppCompatActivity {
    private RecyclerView rv;
    private EmployeeAdapter adapter;
    private ArrayList models;
    private ProgressBar progressBar;
    private SQLiteManager sqLiteManager;
    private SharedPreferences preferences;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        progressBar = findViewById(R.id.progressBar);
        sqLiteManager = new SQLiteManager(this);
        preferences = PreferenceManager.getDefaultSharedPreferences(this);

        rv = findViewById(R.id.rv);
        rv.setHasFixedSize(true);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        rv.setLayoutManager(layoutManager);

        models = new ArrayList<>();
        adapter = new EmployeeAdapter(this, models);
        rv.setAdapter(adapter);

        ArrayList cache = sqLiteManager.getData();
        boolean isCacheExpire = false;
        long cacheTime = preferences.getLong("cache", 0);

        if (cacheTime > 0) {
            long currentTime = new Date().getTime();
            long difference = currentTime - cacheTime;
            long seconds = difference / 1000;

            if (seconds > 20) {
                isCacheExpire = true;
            }
        }

        if (cache.size() > 0 && !isCacheExpire) {
            models = cache;
            showData();
        } else {
            getData();
        }
    }

    private void getData() {
        String url = "Your API URL here";
        RequestQueue requestQueue = Volley.newRequestQueue(this);

        StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener() {
            @Override
            public void onResponse(String response) {
                try {
                    Gson gson = new Gson();
                    Type type = new TypeToken<ArrayList<EmployeeModel>>() {

                    }.getType();
                    models = gson.fromJson(response, type);
                    sqLiteManager.deleteOldCache();

                    for (int a = 0; a < models.size(); a++) {
                        sqLiteManager.addData(models.get(a));
                    }

                    preferences.edit().putLong("cache", new Date().getTime()).apply();

                    showData();
                } catch (Exception e) {
                    Log.i("my_log", e.getMessage());
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.i("my_log", error.getMessage());
            }
        });

        stringRequest.setShouldCache(false);
        requestQueue.add(stringRequest);
    }

    private void showData() {
        adapter.setFilter(models);
        progressBar.setVisibility(View.GONE);
    }
}

Run the app now. And you are all set in implementing SQLite cache in your android app. We have used android SQLite to save the data in the cache. But you can also use android’s shared preferences if the data that needs to be cached is relatively small.

[wpdm_package id=’211′]

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′]

How to create and read RSS feed for your website – PHP

RSS feed is formerly known as RDF Site Summary feed, now it stands for Really Simple Syndication. It is a form of web feed that allows other computer programs to fetch updates about the website. Programs known as RSS aggregators are created which reads the feed in XML format in a standardized way.

Examples

For example, if you are running an E-commerce site. Then creating an RSS feed will help visitors to view the latest products on your website. Similarly, if you are running a blog. Then your RSS feed will be about the latest posts that you have published on your blog.

RSS feeds are XML files, so they must follow all the standard formats of XML. That includes the special characters. If your feed has some special characters like a single or double quote, you need to convert them to HTML entities before publishing or updating your feed.

RSS aggregators

The programs or scripts that are used to read these feeds are known as RSS aggregators. They follow a specific pattern to read and display feeds to users. So you must follow the rules and proper tags of XML to reach the global audience. There are a lot of tags which can be used in RSS but the most common are title, description, link, language, image, url, category, copyright and author.

How to create an RSS feed

There are multiple ways to create an RSS feed for your website and different people adopt different ways, that’s okay. You can either create a button on the admin panel to generate feeds and export the XML file. Then you can upload it manually using your cPanel file manager. Or you can add a function that will create or update an XML file whenever you post something new on your website. We will be using the second technique in this tutorial.

Also, you will need to create a button on your website’s main page from where users can see your feeds. One common practice is to create an anchor tag in HTML that will redirect the user to that XML file. User can then add that RSS link in this RSS aggregator software. Then will automatically be notified when you upload something new on your website. and your RSS feed gets updated.

Standard format

The standard format of creating an RSS feed is:

<?xml version="1.0" ?>
<rss version="2.0">
    <channel>
        <title></title>
        <description></description>
        <language>en-US</language>
        <link>http://website.com/</link>

        <item>
            <title>Pont Yacht
            <description>Measures 38 inches Long.</description>
            <link>http://website.com/prod.php?id=3212</link>
        </item>
    </channel>
</rss>

You can display as many item tags as you want but the format should remain the same. So copy and paste the following code in file where you want to generate your RSS feed. Typically whenever you post something new on your website.

<?php

$web_url = "http://" . $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];

$str = "<?xml version='1.0' ?>";
$str .= "<rss version='2.0'>";
	$str .= "<channel>";
		$str .= "<title>My website</title>";
		$str .= "<description>My website</description>";
		$str .= "<language>en-US</language>";
		$str .= "<link>$web_url</link>";

		$conn = mysqli_connect("localhost", "root", "", "classicmodels");
		$result = mysqli_query($conn, "SELECT * FROM products ORDER BY productCode DESC");

		while ($row = mysqli_fetch_object($result))
		{
			$str .= "<item>";
				$str .= "<title>" . htmlspecialchars($row->productName) . "</title>";
				$str .= "<description>" . htmlspecialchars($row->productDescription) . "</description>";
				$str .= "<link>" . $web_url . "/product.php?id=" . $row->productCode . "</link>";
			$str .= "</item>";
		}

	$str .= "</channel>";
$str .= "</rss>";

file_put_contents("rss.xml", $str);
echo "Done";
?>

First we are creating a variable $web_url that will hold the base URL of the website. You can just set this variable a static value. But we are trying to make it dynamic so you won’t have difficulty when moving to different domains. Then we are creating a string variable $str that will hold all the RSS feed value in string format. We will be using this variable when creating an XML file.

<channel>

Channel tag will be served as a category since you might have different types of data on your website. So you can put different data in different channel tags. For example, you might have an E-commerce site and also the latest blog posts from one of your blog site.

Then we have title, description, link and url tags, they will be used to explain the properties of channel tag. The link must be your website’s main URL and language can be in one of the standard language codes. For getting website main URL we will be using PHP built-in SERVER variable and SERVER_NAME will return the name of the server which in this case will be localhost, and REQUEST_URI will return the address of folder from where this script is getting executed.

Then we are connecting with the database and fetching all the latest products in descending order (newest to oldest). You can see that we are using htmlspecialchars() function which helps to convert special characters into HTML entities. Since XML do not interpret special characters. So if you have any special characters and you are not using this function, then it might trigger an error in your RSS feed.

Saving XML file

Finally, we are calling file_put_contents() function which will create an XML file with the content of $str variable. If the file with same name already exists, it will simply update the file and override the previous content. Or if you are using Linux, make sure you have folder’s write permission in order to create that file.

If you run the script now you will be able to see a file named rss.xml created in your project’s root folder. You can drag that file in your browser, and you will see the feed in proper XML format. Now the last thing you can do is to display a link in your website which when clicked will redirect the user to this page.

Link to feed

We will be creating an anchor tag which when clicked will redirect the visitors to that XML file. We have also downloaded a logo of RSS from the internet. Instead of text we will be placing this image inside the anchor tag. Just copy and paste the following code anywhere in your website where you want to display a link to this RSS feed:

<a href="rss.xml" target="_blank">
	<img src="feed-icon.png" style="width: 100px;">
</a>

Since we want the feed to open in a new tab so it will not disrupt the user from using the site, so we have added an attribute target=”_blank” which will tell the browser to open that link in a new tab.

[wpdm_package id=’207′]