Replace all occurrences in a string – Javascript

To replace all the occurrences in a string in Javascript, we will use the following method.

For example, you have the following string variable.

let string = "adnan_tech_com"

And you want to replace all underscores with a white space.

You can use the following code to replace all occurrences of underscores with a whitespace.

string = string.split("_").join(" ") // adnan tech com

Explanation

First, you need to split the string by underscore. It will return an array.

let string = "adnan_tech_com"

string = string.split("_") // ["adnan", "tech", "com"]

Then we can join the array by whitespace.

let string = "adnan_tech_com"

string = string.split("_")

string = string.join(" ") // adnan tech com

Don’t use replace()

You should not use “replace” function because it will replace only the first occurrence in a string.

let string = "adnan_tech_com"

string = string.replace("_", " ") // adnan tech_com

Checkout our more tutorials on Javascript.

Get age from date of birth – Javascript

Suppose you are given a date of birth of any user and you have to get his age from it. You can do it in Javascript using the following code:

const date = new Date("1993-07-27")
const current_date = new Date()

let age = current_date.getTime() - date.getTime()
// 948161820692

age = new Date(age)
// 2000-01-18T02:17:18.105Z

age = age.getFullYear()
// 2000

age = age - 1970
// 30

Record and save audio from web – Javascript, Node JS, PHP

In this article, we are going to teach you, how you can record and save audio from web using Javascript. For saving audio files, we will teach you how you can do that with PHP and Node JS.

Let’s get started

First, we will create a folder named “record-audio-from-web”. Inside this folder, create a file named “index.html” and include fontawesome CDN in it. We will be displaying a microphone icon to start recording.

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />

Then we will create a microphone icon.

  1. Give it a unique ID so we can get it in Javascript.
  2. Attach an “onclick” listener that will be called whenever that icon is clicked.
  3. And set the cursor to pointer so user will know that this is clickable.
<i class="fa fa-microphone" id="icon-record-audio" onclick="recordAudio()" style="cursor: pointer;"></i>

Now in Javascript, we first have to create an instance of recorder.

let recorder = null

Get microphone permission

Then we will create that function that will be called when the microphone icon is clicked. This function will:

  1. Get the permission to access laptop’s microphone.
  2. Initialize a media recorder object.
  3. Start recording audio from microphone.
// function to record audio
async function recordAudio() {
    // get permission to access microphone
	navigator.permissions.query({name: 'microphone'})
		.then(function (permissionObj) {
			console.log(permissionObj.state)				
		})
		.catch(function (error) {
			console.log('Got error :', error);
		})

    // get recorder object
	recorder = await doRecordAudio()

    // start audio
	recorder.start()
}

Record audio

Then we will create “doRecordAudio” function that will handle all the recording and stoping mechanism.

function doRecordAudio() {
    return new Promise(function (resolve) {
        // get user audio media
        navigator.mediaDevices.getUserMedia({
            audio: true
        })
        .then(function (stream) {
            // [media recorder goes here]
        })
    })
}

After that, we need to create a media recorder object. Following code goes in the [media recorder goes here] section:

// create media recorder object
const mediaRecorder = new MediaRecorder(stream)

// save audio chunks in an array
const audioChunks = []
mediaRecorder.addEventListener("dataavailable", function (event) {
    audioChunks.push(event.data)
})

// [start and stop listener goes here]

This will create a media recorder object from stream and save all audio chunks (when available) in an array.

Then write the following code in [start and stop listener goes here] section to create start and stop listeners:

// create a start function
const start = function () {
    // [start listener goes here]
}

// create a stop function
const stop = function () {
    return new Promise(function (resolve) {
        // [stop listener goes here]
    })
}

// send the values back to promise
resolve({
    start,
    stop
})

This “start” function gets called from “recordAudio()” function.

Start recording audio

When the start function is called, we need to:

  1. Change the microphone icon to stop icon.
  2. Change onclick listener, so next time the icon is clicked, we will stop the recording.
  3. And play the audio.
  4. Tell the media to start recording.

Following code goes in the [start listener goes here] section:

// when recording starts, set the icon to stop
document.getElementById("icon-record-audio").className = "fa fa-stop-circle"

// on icon clicked
document.getElementById("icon-record-audio").onclick = async function() {
    // stop the recorder
    if (recorder != null) {
        const audio = await recorder.stop()

        // [play audio]

        // [get audio base64 string]
    }
}

// start media recorder
mediaRecorder.start()

If you test now, you will be able to record the audio. The microphone icon will be changed as well. But now you need to find a way to stop the recording.

Stop the recording

When you are done recording the audio, you can click the icon again to stop it. Following code goes in the [stop listener goes here] section. This will:

  1. Attach a listener that will be called when the recording is stopped.
  2. Change the icon back to microphone.
  3. Reset the onclick listener to its initial state.
  4. Convert the audio chunks array into a blob.
  5. Create URL object from blob.
  6. Create an audio object to play when required.
  7. And stop the media recorder.
// on recording stop listener
mediaRecorder.addEventListener("stop", function () {

    // change the icon back to microphone
    document.getElementById("icon-record-audio").className = "fa fa-microphone"

    // reset the onclick listener so when again clicked, it will record a new audio
    document.getElementById("icon-record-audio").onclick = async function() {
        recordAudio()
    }

    // convert the audio chunks array into blob
    const audioBlob = new Blob(audioChunks)

    // create URL object from URL
    const audioUrl = URL.createObjectURL(audioBlob)

    // create an audio object to play
    const audio = new Audio(audioUrl)
    const play = function () {
        audio.play()
    }

    // send the values back to the promise
    resolve({
        audioBlob,
        play
    })
})

// stop the media recorder
mediaRecorder.stop()

If you test now, you can record the audio and stop the audio. The icon will change from microphone to stop and then from stop to microphone.

Play the audio after recording

In order to play the audio you just recorded, write the following line in the [play audio] section:

audio.play()

“stop” function will return the promise containing the “new Audio” object and calling “play()” will play the audio.

Converting audio to base64

We are already sending audioBlob from “stop” function, so we can create base64 string from it. Write the following code in your [get audio base64 string] section:

// get audio stream
const reader = new FileReader()
reader.readAsDataURL(audio.audioBlob)
reader.onloadend = function() {
    // get base64
    let base64 = reader.result

    // get only base64 data
    base64 = base64.split(',')[1]

    // send base64 to server to save
    sendVoiceNote(base64)
}

This will create a base64 string fom audio.

Sending audio base64 to server

Now we will create a function that will call an AJAX to save this base64 string as audio.

function sendVoiceNote(base64) {
        // create an instance for AJAX
        var ajax = new XMLHttpRequest()

        // set request method as POST, set URL and set asynchronous to true
        ajax.open("POST", "http://localhost:8888/tutorials/record-audio-from-web/sendVoiceNote.php", true)

        // send base64 string to server
        const formData = new FormData()
        formData.append("base64", base64)
        ajax.send(formData)
}

Note: In your server, create a folder named “audios” where all audio files will be saved.

Saving audio file on server – PHP

First, we will teach you how can you save it using PHP. Create a file named “sendVoiceNote.php” and write the following code in it:

<?php

$base64 = $_POST["base64"];

$file_name = "audios/" . time() . ".webm";
file_put_contents($file_name, base64_decode($base64));

echo $file_name;

Try recording an audio again. When you stop the audio, you will see that a new file will be saved in your “audios” folder. You can listen to your audio in your favorite media player (VLC etc).

Saving audio file on server – Node JS

Now we will teach you, how you can save the file using Node JS. Create a Node JS project by running the following commands one-by-one:

> npm install express http express-formidable fs cors
> npm install -g nodemon
> nodemon server.js

Create a file named “server.js” and write the following code in it:

const express = require("express")
const app = express()

const expressFormidable = require("express-formidable")
app.use(expressFormidable())

const cors = require("cors")
app.use(cors())

const fileSystem = require("fs")
const http = require("http").createServer(app)

http.listen(3000, function () {
	app.post("/sendVoiceNote", async function (request, result) {
		const base64 = request.fields.base64

        const buffer = Buffer.from(base64, "base64")
        const voiceNote = "audios/" + new Date().getTime() + ".webm"
        await fileSystem.writeFileSync(voiceNote, buffer)

        result.send(voiceNote)
	})
})

In your client side, change the AJAX “open” function call from:

ajax.open("POST", "http://localhost/record-audio-from-web/sendVoiceNote.php", true)

To:

ajax.open("POST", "http://localhost:3000/sendVoiceNote", true)

So that’s it. That’s how you can record audio from web and save it in your server using Node JS or PHP. If you face any problem in following this, kindly do let me know.

Here is the complete code of all files:

index.html

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
<i class="fa fa-microphone" id="icon-record-audio" onclick="recordAudio()" style="cursor: pointer;"></i>

<script>

    let recorder = null

    function sendVoiceNote(base64) {
        // create an instance for AJAX
        var ajax = new XMLHttpRequest()

        // set request method as POST, set URL and set asynchronous to true
        // ajax.open("POST", "http://localhost:3000/sendVoiceNote", true)
        ajax.open("POST", "http://localhost/record-audio-from-web/sendVoiceNote.php", true)

        // whenever the status of request is changed
        // ajax.onreadystatechange = async function() {
        //     if (this.readyState == 4) {
        //         if (this.status == 200) {
        //             console.log(this.responseText)
        //         }

        //         if (this.status == 500) {
        //             console.log(this.responseText)
        //         }
        //     }
        // }

        // send base64 string to server
        const formData = new FormData()
        formData.append("base64", base64)
        ajax.send(formData)
    }

	function doRecordAudio() {
        return new Promise(function (resolve) {
            // get user audio media
            navigator.mediaDevices.getUserMedia({
                audio: true
            })
            .then(function (stream) {
                // create media recorder object
                const mediaRecorder = new MediaRecorder(stream)

                // save audio chunks in an array
                const audioChunks = []
                mediaRecorder.addEventListener("dataavailable", function (event) {
                    audioChunks.push(event.data)
                })

                // create a start function
                const start = function () {

                    // when recording starts, set the icon to stop
                    document.getElementById("icon-record-audio").className = "fa fa-stop-circle"

                    // on icon clicked
                    document.getElementById("icon-record-audio").onclick = async function() {
                        // stop the recorder
                        if (recorder != null) {
                            const audio = await recorder.stop()

                            // play the audio
                            audio.play()

                            // get audio stream
                            const reader = new FileReader()
                            reader.readAsDataURL(audio.audioBlob)
                            reader.onloadend = function() {
                                // get base64
                                let base64 = reader.result

                                // get only base64 data
                                base64 = base64.split(',')[1]

                                // send base64 to server to save
                                sendVoiceNote(base64)
                            }
                        }
                    }

                    // start media recorder
                    mediaRecorder.start()
                }

                // create a stop function
                const stop = function () {
                    return new Promise(function (resolve) {

                        // on recording stop listener
                        mediaRecorder.addEventListener("stop", function () {

                            // change the icon back to microphone
                            document.getElementById("icon-record-audio").className = "fa fa-microphone"

                            // reset the onclick listener so when again clicked, it will record a new audio
                            document.getElementById("icon-record-audio").onclick = async function() {
                                recordAudio()
                            }

                            // convert the audio chunks array into blob
                            const audioBlob = new Blob(audioChunks)

                            // create URL object from URL
                            const audioUrl = URL.createObjectURL(audioBlob)

                            // create an audio object to play
                            const audio = new Audio(audioUrl)
                            const play = function () {
                                audio.play()
                            }

                            // send the values back to the promise
                            resolve({
                                audioBlob,
                                play
                            })
                        })

                        // stop the media recorder
                        mediaRecorder.stop()
                    })
                }

                // send the values back to promise
                resolve({
                    start,
                    stop
                })
            })
        })
    }

    // function to record audio
	async function recordAudio() {
        // get permission to access microphone
		navigator.permissions.query({name: 'microphone'})
			.then(function (permissionObj) {
				console.log(permissionObj.state)				
			})
			.catch(function (error) {
				console.log('Got error :', error);
			})

        // get recorder object
		recorder = await doRecordAudio()

        // start audio
  		recorder.start()
	}
</script>

server.js

const express = require("express")
const app = express()

const expressFormidable = require("express-formidable")
app.use(expressFormidable())

const cors = require("cors")
app.use(cors())

const fileSystem = require("fs")
const http = require("http").createServer(app)

http.listen(3000, function () {
	app.post("/sendVoiceNote", async function (request, result) {
		const base64 = request.fields.base64

        const buffer = Buffer.from(base64, "base64")
        const voiceNote = "audios/" + new Date().getTime() + ".webm"
        await fileSystem.writeFileSync(voiceNote, buffer)

        result.send(voiceNote)
	})
})

sendVoiceNote.php

<?php

$base64 = $_POST["base64"];

$file_name = "audios/" . time() . ".webm";
file_put_contents($file_name, base64_decode($base64));

echo $file_name;

AJAX in Sweetalert 2

In this article, I am going to teach you, how you can use AJAX in sweetalert 2. As per sweetalert 2 documentation, you can use Fetch API for calling AJAX requests. Fetch API is good, but not for more control over your request, like using POST method, adding headers etc. Fetch API is not so suitable in those cases.

Video tutorial:

AJAX in Sweetalert 2

Following is your code that you get from sweetalert 2 documentation:

Swal.fire({
  title: 'Submit your Github username',
  input: 'text',
  inputAttributes: {
    autocapitalize: 'off'
  },
  showCancelButton: true,
  confirmButtonText: 'Look up',
  showLoaderOnConfirm: true,
  preConfirm: (login) => {
    return fetch(`//api.github.com/users/${login}`)
      .then(response => {
        if (!response.ok) {
          throw new Error(response.statusText)
        }
        return response.json()
      })
      .catch(error => {
        Swal.showValidationMessage(
          `Request failed: ${error}`
        )
      })
  },
  allowOutsideClick: () => !Swal.isLoading()
}).then((result) => {
  if (result.isConfirmed) {
    Swal.fire({
      title: `${result.value.login}'s avatar`,
      imageUrl: result.value.avatar_url
    })
  }
})

Replace that with the following function:

swal.fire({
	title: 'Submit your Github username',
	input: 'text',
	inputAttributes: {
		autocapitalize: 'off'
	},
	showCancelButton: true,
	confirmButtonText: 'Look up',
	showLoaderOnConfirm: true,
	preConfirm: (login) => {

		return new Promise(function (callback) {
			const ajax = new XMLHttpRequest()
			ajax.open("GET", "https://api.github.com/users/" + login, true)

				ajax.onreadystatechange = function () {
					if (this.readyState == 4 && this.status == 200) {
						callback( JSON.parse(this.responseText) )
					}
				}

			ajax.send()
		})
		
	},
	allowOutsideClick: () => !swal.isLoading()
}).then((result) => {
	if (result.isConfirmed) {
		swal.fire({
			title: `${result.value.login}'s avatar`,
			imageUrl: result.value.avatar_url
		})
	}
})

You can notice that the fetch() function has been replaced with a Promise. But now you can use XMLHttpRequest and have more control over your AJAX requests.

Learn more about promises from here.

Split camel case using regex in Javascript

Hello. In this post, we will show you, how you can split a camel case word and capitalize it using regex (regular expression) in Javascript.

InputOutput
adnanTechComAdnan Tech Com

Following code will split the camel case into multiple words and then capitalize it:

// splitting camel case to multiple words
const str = "adnanTechCom".replace(/([a-z])([A-Z])/g, "$1 $2")

// capitalizing the string
const capitalize = str.charAt(0).toUpperCase() + str.slice(1)
console.log(capitalize)

capitalize variable will now have value:

Adnan Tech Com

This regular expression will search for all words that ends with small letter and begin with capital alphabet. Then give a space between each of such word.

The above replace call replaces the match of the regex (which happens to match everything) with the first capture group ($1) followed by a space, followed by the second capture group ($2).

For capitalization, you can also use a CSS property as well:

text-transform: capitalize;

Convert datetime to local timezone – Javascript, PHP and MySQL

In this article, you will learn how to convert UTC datetime to user’s local timezone using Javascript.

Your database is centralized, but your user’s are located on different geolocations. Time stored in your database is usually UTC by default. But your users should see the time according to their timezone. So how are you going to do it ?

Table of contents:

  1. Save datetime in UTC
  2. Get user’s local timezone
  3. Convert UTC to timezone

Save datetime in UTC

First, we will create a users table. Run the following query in your phpMyAdmin.

CREATE TABLE IF NOT EXISTS users(
    id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name TEXT,
    created_at DATETIME
)

Then we will insert a row in this table.

INSERT INTO users(name, created_at) VALUES ('Adnan', UTC_TIMESTAMP())

Note that we are using UTC_TIMESTAMP() MySQL built-in function. This will return the current UTC date and time.

Get user’s local timezone

To get the user’s local timezone, we will use the Intl object of Javascript. It stands for internationalization.

const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone

DateTimeFormat() creates a new DateTimeFormat object.

resolvedOptions() will return a new object. Its object’s properties reflects the locale and datetime format sets during the initialization of Intl.DateTimeFormat() object.

timeZone will return the timezone of user’s local computer.

We saved it in a variable. Now we will call an AJAX request to fetch the records from database using PHP.

const ajax = new XMLHttpRequest()
ajax.open("POST", "get-data.php", true)

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

const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
const formData = new FormData()
formData.append("time_zone", timeZone)
ajax.send()

This will call an AJAX request and attach the timezone value with the request.

Convert UTC datetime to local timezone

To convert the UTC value from database to user’s local timezone, first we need to get the value of user’s timezone from the AJAX request. So create a file named get-data.php and inside this file, creates a connection with the MySQL database.

<?php

$conn = new PDO("mysql:host=localhost;dbname=your_db_name", "db_user", "db_password");

Then we will get the timezone from AJAX request and fetch the single user’s record.

$time_zone = $_POST["time_zone"] ?? "";
if (!empty($time_zone))
{
    date_default_timezone_set($time_zone);
}

$sql = "SELECT * FROM users";
$result = $conn->prepare($sql);
$result->execute([]);
$user = $result->fetchObject();

Finally, we will convert the timestamp from UTC to user’s local timezone and return it to the client.

echo date("d M, Y h:i:s a", strtotime($user->created_at . " UTC"));

If you open your browser’s console tab, you will see the date and time but in your own timezone.

Using DateTimeZone class

Calling date_default_timezone_set() will set the entire request’s timezone to the user timezone. If you want to convert only one column’s value to user’s local timezone, you can use PHP built-in DateTimeZone class.

First, you need to create its object:

$dateTimeZone = new DateTimeZone($time_zone);

Then, you can create a datetime object from timestamp stored in MySQL database and set it to use the timezone of user.

$dateTime = new DateTime($user->created_at);
$dateTime->setTimezone($dateTimeZone);

Finally, we can display the date and time in the format.

echo $dateTime->format("d M, Y h:i:s a");

That’s how you can convert UTC datetime to user’s local timezone using Javascript.

End-to-end encryption in Javascript, PHP and MySQL

End-to-end encrypted chats are more secured than the ones where encryption is done on the server side. Because the messages get encrypted even before sending them to the server. This will prevent any read or alter operation of messages in-transit. Let’s learn how to do it.

We will be using Javascript for encryption and decryption. And we will be using PHP for handling AJAX requests. All the encrypted messages will be stored in MySQL database.

Table of contents

  1. Setup database
  2. Private and public keys
  3. Encrypt message
  4. Decrypt message

Setup database

First, open your phpMyAdmin and create a database named end_to_end_encryption. Then create a file named db.php and write the following code in it.

<?php

$conn = new PDO("mysql:host=localhost;dbname=end_to_end_encryption", "root", "");

The second and third parameters are username and password to the database. You can change them as per your server. Then we will create a file named index.php and write the following code in it.

<?php

require_once "db.php";

$sql = "CREATE TABLE IF NOT EXISTS users(
  id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
  email VARCHAR(255) NOT NULL,
  privateKey TEXT DEFAULT NULL,
  publicKey TEXT DEFAULT NULL
)";
$conn->prepare($sql)->execute();

$sql = "CREATE TABLE IF NOT EXISTS messages(
  id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
  sender VARCHAR(255) NOT NULL,
  receiver VARCHAR(255) NOT NULL,
  message TEXT NOT NULL,
  iv TEXT NOT NULL
)";
$conn->prepare($sql)->execute();

?>

This will create 2 tables. One for users where we will store each user’s private and public key. Second table where we will store all our encrypted messages. We will also store IV (initialization vector) required for decrypting the message. The IV will also be encrypted. Run the following URL in the browser.

http://localhost/end-to-end-encryption-js-php-mysql/index.php

You need to insert 2 users manually in the user’s table to properly understand the mechanism of end-to-end encryption.

We assume that you have a folder named end-to-end-encryption-js-php-mysql where you placed your index.php file. After running the above URL in the browser, you need to check your phpMyAdmin. You will now see your 2 tables created.

Private and public keys

Private and public keys of each user is unique and it is used to encrypt and decrypt the messages. We will encrypt the message using sender’s private key with receiver’s public key. Similarly, we will decrypt the message using logged-in user’s private and other user’s public key. So we will create a form in our index.php file.

<form onsubmit="doLogin(this)">
  <input type="email" name="email" id="email" placeholder="Enter email" />
  <input type="submit" value="Login" />
</form>

You need to perform the function below in your own login module. We are not going into the authentication because that is not in the scope of this tutorial. When the form submits, we will call an AJAX request to authenticate the user.

<script>
  function doLogin() {
    event.preventDefault()
    
    const form = event.target
    const formData = new FormData(form)
    
    const ajax = new XMLHttpRequest()
    ajax.open("POST", "login.php", true)
    ajax.onreadystatechange = function () {
      if (this.readyState == 4 && this.status == 200) {
        if (!this.responseText) {
          updateKeys()
        }
      }
    }

    ajax.send(formData)
  }
</script>

Create a file named login.php that will tell if the logged-in user has private and public keys.

<?php

require_once "db.php";
$email = $_POST["email"];

$sql = "SELECT publicKey FROM users WHERE email = ?";
$result = $conn->prepare($sql);
$result->execute([
  $email
]);
$user = $result->fetchObject();

echo ($user && $user->publicKey != null);
exit();

This will return true or false indicating if the user has public key in the database. If not, then the client side will call another AJAX request from the function updateKeys() to generate the keys and save them in database.

async function updateKeys() {
      const keyPair = await window.crypto.subtle.generateKey(
          {
              name: "ECDH",
              namedCurve: "P-256",
          },
          true,
          ["deriveKey", "deriveBits"]
      )

      const publicKeyJwk = await window.crypto.subtle.exportKey(
          "jwk",
          keyPair.publicKey
      )

      const privateKeyJwk = await window.crypto.subtle.exportKey(
          "jwk",
          keyPair.privateKey
      )

      const formData = new FormData()
      formData.append("email", document.getElementById("email").value)
      formData.append("publicKey", JSON.stringify(publicKeyJwk))
      formData.append("privateKey", JSON.stringify(privateKeyJwk))

      const ajax = new XMLHttpRequest()
      ajax.open("POST", "update-keys.php", true)
      ajax.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
          console.log(this.responseText)
        }
      }

      ajax.send(formData)
}

We are using P-256 curve algorithm to generate a key pair. Then we are exporting private and public keys JWK (JSON Web Token). To save them in database, we are converting them to JSON string. Now we need to create a file named update-keys.php that will update those keys in user’s table.

<?php

require_once "db.php";

$email = $_POST["email"];
$publicKey = $_POST["publicKey"];
$privateKey = $_POST["privateKey"];

$sql = "UPDATE users SET publicKey = ?, privateKey = ? WHERE email = ?";
$result = $conn->prepare($sql);
$result->execute([
  $publicKey,
  $privateKey,
  $email
]);

echo "Updated";
exit();

Try running the index.php file again. Enter any of the user’s email address from database and hit “Login”. You will see the message “Updated” in the browser console. But you will see it just once, because once the public keys are updated, this function won’t gets called. If you check your phpMyAdmin, you will see that the private and public key of that user will be updated. You should do that for both users so each user will have its own private and public keys.

Encrypt message

Now that each user has its own private and public keys, we can use them to encrypt messages and save them in database. Create a file named send.php that will display a form to enter sender and receiver’s email addresses and a message to encrypt.

<form onsubmit="sendMessage()" id="form-message">
  <input type="email" name="sender" placeholder="Sender email" />
  <input type="email" name="receiver" placeholder="Receiver email" />
  <textarea name="message" placeholder="Message"></textarea>
  <input type="submit" value="Send" />
</form>

We will create 2 Javascript variables that will hold the sender’s private key and receiver’s public key values.

<script>
  let publicKey = ""
  let privateKey = ""
</script>

We are using let because these values will be updated later. Create a function that will be called when the above form submits.

function sendMessage() {
  event.preventDefault()

  if (publicKey == "" || privateKey == "") {
    const form = event.target
    const formData = new FormData(form)
    
    const ajax = new XMLHttpRequest()
    ajax.open("POST", "get-keys.php", true)
    ajax.onreadystatechange = function () {
      if (this.readyState == 4 && this.status == 200) {
        const response = JSON.parse(this.responseText)
        privateKey = JSON.parse(response[0])
        publicKey = JSON.parse(response[1])
        doSendMessage()
      }
    }

    ajax.send(formData)
  } else {
    doSendMessage()
  }
}

This will first check if the private and public keys are already fetched. If fetched, then it will call doSendMessage() function that we will create later. If not fetched, then we will first fetch the keys and then call the 2nd function. We are using this check because if you are sending multiple messages to the same recipient, then it should not get private and public keys on each send message request.

Now we will create a file named get-keys.php to fetch the sender’s private key and receiver’s public key.

<?php

require_once "db.php";

$sender = $_POST["sender"];
$receiver = $_POST["receiver"];

$sql = "SELECT privateKey FROM users WHERE email = ?";
$result = $conn->prepare($sql);
$result->execute([
  $sender
]);
$userSender = $result->fetchObject();

$sql = "SELECT publicKey FROM users WHERE email = ?";
$result = $conn->prepare($sql);
$result->execute([
  $receiver
]);
$userReceiver = $result->fetchObject();

echo json_encode([
  $userSender->privateKey,
  $userReceiver->publicKey
]);
exit();

When the keys are returned on the client side, the variables will be updated and the second function will be called to send the message.

async function doSendMessage() {
      const form = document.getElementById("form-message")
      const formData = new FormData()
      formData.append("sender", form.sender.value)
      formData.append("receiver", form.receiver.value)

      const publicKeyObj = await window.crypto.subtle.importKey(
          "jwk",
          publicKey,
          {
              name: "ECDH",
              namedCurve: "P-256",
          },
          true,
          []
      )

      const privateKeyObj = await window.crypto.subtle.importKey(
          "jwk",
          privateKey,
          {
              name: "ECDH",
              namedCurve: "P-256",
          },
          true,
          ["deriveKey", "deriveBits"]
      )

      const derivedKey = await window.crypto.subtle.deriveKey(
          { name: "ECDH", public: publicKeyObj },
          privateKeyObj,
          { name: "AES-GCM", length: 256 },
          true,
          ["encrypt", "decrypt"]
      )

      const encodedText = new TextEncoder().encode(form.message.value)
      const iv = new TextEncoder().encode(new Date().getTime())
      const encryptedData = await window.crypto.subtle.encrypt(
          { name: "AES-GCM", iv: iv },
          derivedKey,
          encodedText
      )
      const uintArray = new Uint8Array(encryptedData)
      const string = String.fromCharCode.apply(null, uintArray)
      const base64Data = btoa(string)
      const b64encodedIv = btoa(new TextDecoder("utf8").decode(iv))

      formData.append("message", base64Data)
      formData.append("iv", b64encodedIv)
  
      const ajax = new XMLHttpRequest()
      ajax.open("POST", "send-message.php", true)
      ajax.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
          console.log(this.responseText)
        }
      }

      ajax.send(formData)
}

We will use the same P-256 curve algorithm to import the private and public keys we used to exporting it. Then we will create derived key from both (private and public) keys. We will use the derived key, IV and encoded message to encrypt the message. Once the message is encrypted, we will convert the encrypted message and IV to base64 string and send them in the AJAX request. IV will be used to decrypt the message. Then we will create a file named send-message.php to save the data in the database.

<?php

require_once "db.php";

$sender = $_POST["sender"];
$receiver = $_POST["receiver"];
$message = $_POST["message"];
$iv = $_POST["iv"];

$sql = "INSERT INTO messages(sender, receiver, message, iv) VALUES (?, ?, ?, ?)";
$result = $conn->prepare($sql);
$result->execute([
  $sender,
  $receiver,
  $message,
  $iv
]);
echo $conn->lastInsertId();

Run the file send.php in the browser. Enter sender and receiver’s email address, type the message and hit “send”. If all goes well, then you will see the inserted message ID in the browser console.

Decrypt message

Now we need to decrypt the encrypted messages. Create a file named read.php. Here we will create a form to enter sender and receiver’s email address to fetch their messages.

<form onsubmit="readMessages()" id="form-read">
  <input type="email" name="sender" placeholder="Sender email" />
  <input type="email" name="receiver" placeholder="Receiver email" />
  <input type="submit" value="Read" />
</form>

Then we will create a Javascript function that will be called when the above form submits.

function readMessages() {
  event.preventDefault()

  const form = event.target
  const formData = new FormData(form)
  
  const ajax = new XMLHttpRequest()
  ajax.open("POST", "get-messages.php", true)
  ajax.onreadystatechange = async function () {
    if (this.readyState == 4 && this.status == 200) {
      const response = JSON.parse(this.responseText)

      const publicKeyObj = await window.crypto.subtle.importKey(
          "jwk",
          JSON.parse(response.publicKey),
          {
              name: "ECDH",
              namedCurve: "P-256",
          },
          true,
          []
      )

      const privateKeyObj = await window.crypto.subtle.importKey(
          "jwk",
          JSON.parse(response.privateKey),
          {
              name: "ECDH",
              namedCurve: "P-256",
          },
          true,
          ["deriveKey", "deriveBits"]
      )

      const derivedKey = await window.crypto.subtle.deriveKey(
          { name: "ECDH", public: publicKeyObj },
          privateKeyObj,
          { name: "AES-GCM", length: 256 },
          true,
          ["encrypt", "decrypt"]
      )

      for (let a = 0; a < response.messages.length; a++) {
        const iv = new Uint8Array(atob(response.messages[a].iv).split("").map(function(c) {
            return c.charCodeAt(0)
        }))
        const initializationVector = new Uint8Array(iv).buffer
        const string = atob(response.messages[a].message)
        const uintArray = new Uint8Array(
            [...string].map((char) => char.charCodeAt(0))
        )
        const decryptedData = await window.crypto.subtle.decrypt(
            {
                name: "AES-GCM",
                iv: initializationVector,
            },
            derivedKey,
            uintArray
        )
        const message = new TextDecoder().decode(decryptedData)
        console.log(message)
      }
    }
  }

  ajax.send(formData)
}

This will call an AJAX request to get the messages. The API will also return the private and public keys required to decrypt the message. Same code can be used to import the keys that we used for sending the message. Create a file named get-messages.php and write the following code in it.

<?php

require_once "db.php";

$sender = $_POST["sender"];
$receiver = $_POST["receiver"];

$sql = "SELECT * FROM messages WHERE sender = ? AND receiver = ?";
$result = $conn->prepare($sql);
$result->execute([
  $sender,
  $receiver
]);
$messages = $result->fetchAll(PDO::FETCH_OBJ);

$sql = "SELECT privateKey FROM users WHERE email = ?";
$result = $conn->prepare($sql);
$result->execute([
  $sender
]);
$userSender = $result->fetchObject();

$sql = "SELECT publicKey FROM users WHERE email = ?";
$result = $conn->prepare($sql);
$result->execute([
  $receiver
]);
$userReceiver = $result->fetchObject();

echo json_encode([
  "messages" => $messages,
  "privateKey" => $userSender->privateKey,
  "publicKey" => $userReceiver->publicKey
]);
exit();

If you run the read.php file now, you will see the decrypted messages in console tab. However, if you see the “network” tab of browser, you will see that the messages are being returned encrypted from the server. That means that your messages are decrypted online when they arrived on the client side. Thus, they are safe in-transit.

end to end encryption
end to end encryption

That’s how you can do end-to-end encryption in Javascript with PHP and MySQL. No external library has been used in this tutorial, so the code used here will work on all frameworks.

Add emoji between text – jQuery

In this tutorial, we will teach you, how you can add emoji between text using jQuery. Emoji picker is a library that allows you to select a wide variety of emojis. It is a Javascript library that returns the emoji character. You can append the emoji in your input fields as well.

This library is very useful specially if you are developing a chat app. For example, user can share emojis in messages.

But it has one problem: what happens when user has typed a message, now he wants to add the emoji in between the message ? The library does not provide such functionality by default.

So that we are going to do, is to get the current cursor position on the input field and set the emoji in-between the text.

Requirements:

  1. jQuery
  2. Emoji picker
  3. twemoji

After downloading all the above files, create 2 folders “css” and “js”. Place the CSS files in “css” folder and Javascript files in “js” folder.

After that, you need to include all these files in your code:

<link rel="stylesheet" href="css/emojis.css" />

<script src="js/jquery.js"></script>
<script src="js/DisMojiPicker.js"></script>
<script src="js/twemoji.min.js"></script>

Then, create an input field where you will enter the text and give it a unique ID.

<textarea id="textInput"></textarea>

Create a container where the emoji picker will be displayed. Give it a unique ID as well.

<div id="emojis"></div>

In your Javascript, initialize the emoji picker.

<script>
	$("#emojis").disMojiPicker()
	twemoji.parse(document.body)
</script>

If you refresh the page now, you will start seeing the emoji picker. Now we need to make it to set the emoji in input field.

// callback function that will be called when an emoji is clicked from emoji picker
$("#emojis").picker(function (emoji) {
	// get the current cursor position on textarea field
	const cursorPosition = $("#textInput").prop("selectionStart")

	// get the current value of texarea field
	const value = $("#textInput").val()

	// check if cursor is at the end of the text
	if (cursorPosition == value.length) {
		// append the emoji at the end
		$("#textInput").val(value + emoji)
	} else {
		// if cursor is in between the text
		// then prepend the emoji before next character
		$("#textInput").val(value.replace(value[cursorPosition], emoji + value[cursorPosition]))
	}
})

We created a single page chat application in MEVN stack where we implemented this emoji picker. You can check that project here.

[wpdm_package id=’2918′]

Call function when user stops writing input field – Javascript

In this article, we are going to show you a technique that helps you call a function when the user stops writing in an input field, using Javascript. Suppose you have an input field for search and you want to show search suggestions to the user as he types. So typically you do the following:

<!-- input field -->
<input id="input" oninput="onInput()" />

<script>

	// function to be called whenever input field text value is changed
	function onInput() {
		// get the input field DOM in a separate variable
		const self = event.target

		// write your logic here to get suggestions
		console.log(self.value)
	}
</script>

The problem with this method is, if you are calling an AJAX request inside onInput() function, then it will call an HTTP request on each input change. So if the user types 5 characters in 1 second, it calls 5 AJAX requests in 1 second. But you should only call the AJAX request once.

So we will be using a technique called debounce. Change your onInput() function to the following:

// timer object
let timer;

// function to be called whenever input field text value is changed
function onInput() {
	// get the input field DOM in a separate variable
	const self = event.target
	
	// if user types another key before 500 milliseconds,
	// then remove the timer, so the function will not gets called
	clearTimeout(timer)

	// this will create a timer every time input field has a value
	timer = setTimeout(function () {
		// write your own logic when user stops typing
		console.log(self.value)
	}, 500)
}

You can see that we have created a global variable timer. Comments have been added with each line for an explanation. Now your AJAX request will only be called when the user stops writing.

You can also check our auto-search suggestion tutorial for a real-world example.

2 ways to disable chrome autocomplete on input fields

Google Chrome by default autocomplete the input field. The HTML autocomplete attribute no longer works on chrome. We present to you 2 methods you can use to disable the autocomplete feature for input fields in chrome and other browsers.

  1. Set input DOM value
  2. Use textarea (recommended)

1. Set input DOM value

When the page loads, wait for half second, then set the input value to empty.

<input type="text" name="username" id="disable-autocomplete" />

<script>
	window.addEventListener("load", function () {
		setTimeout(function () {
			document.getElementById("disable-autocomplete").value = ""
		}, 500)
	})
</script>

We are using wait for 0.5 seconds to let the chrome autocomplete set the value. Then we will override that value to empty.

2. Use textarea (recommended)

We can also use a textarea tag instead of the input field, which will look exactly like a standard input field.

<textarea name="username" rows="1"
	style="resize: none;
		min-height: fit-content;
		font-family: sans-serif;
		font-size: 14px;"

	oninput="this.value = this.value.replace(/\n/g, '')"></textarea>

resize: none; will remove the resize icon to the bottom right of textarea.

Some CSS frameworks like bootstrap give minimum height to a textarea field. You can override that value by setting min-height: fit-content; style.

To set the font the same for input fields, we are setting the font family to “sans-serif”, and size to “14px”. If you are using any framework like Bootstrap, you need to give the “inherit” property to “font-family”, “font-size”, and “font-weight”. This will take the font from its parent element.

rows=”1″ attribute is necessary as it will only make the textarea look like 1 row.

Finally, we are adding an attribute oninput that will be an event listener. This will be called whenever the element gets the user input. We are using a regular expression to convert all the new line characters to empty. This means we are disabling the enter key press. Otherwise, a new line would be started whenever the user presses enter key in the textarea.

Textarea as password

If you want to have your <textarea> tag to be treated as password input field, you can do it the following way:

<textarea name="password" rows="1"
    style="resize: none;
        min-height: fit-content;
        font-family: sans-serif;
        font-size: 14px;"
    id="maskedPassword"></textarea>
    
<input type="hidden" id="hiddenPassword" />

Then in Javascript, you need to do the following:

const maskedPassword = document.getElementById('maskedPassword')
const hiddenPassword = document.getElementById('hiddenPassword')

maskedPassword.addEventListener('input', function (event) {
    const input = event.target.value
    
    // Prevent adding asterisks to the hidden input value
    if (input.length > hiddenPassword.value.length) {
        const newChar = input[input.length - 1]
        hiddenPassword.value += newChar
    } else {
        hiddenPassword.value = hiddenPassword.value.slice(0, input.length)
    }

    maskedPassword.value = '*'.repeat(input.length)
})

Explanation:

  • <textarea>: First we create a <textarea> tag where user will enter his password. Whatever user enters here will be replaced with asterisk “*”.
  • <input />: Then created a hidden input field where the actual password value will be stored.
  • In Javascript, we get DOM of both <textarea> and hidden <input> field.
  • Attach an input event listener to the <textarea> that will be called whenever user type anything in it. This will also be called if user copy/paste something in it.
  • Line 5: Getting the value of <textarea>.
  • Line 8: Make sure the length of <textarea> should be 1 character greater than the hidden <input> field.
  • Line [9-10]: Get the last character of textarea and append it in hidden input field.
  • Line 12: If textarea value is less than hidden input field, meaning user has pressed backspace or remove some characters, then replace the hidden input field value to where it was before (last entered value).
  • Line 15: Replace every character in textarea with asterisk “*”.

Disable copy, cut and paste

As this is a password field, so you must not allow users to copy, cut or paste from that input field. You can disable copy, cut and paste features on password field.

// Disable copying, cutting, and pasting
maskedPassword.addEventListener("copy", function (event) {
    event.preventDefault()
    // alert("Copy is disabled!")
})

maskedPassword.addEventListener("cut", function (event) {
    event.preventDefault()
    // alert("Cut is disabled!")
})

maskedPassword.addEventListener("paste", function (event) {
    event.preventDefault()
    // alert("Paste is disabled!")
})

That’s how you can disable autocomplete for input fields in Google Chrome along with disabling copy, cut and paste feature.

Disable autocomplete on textarea

If you are using <textarea>, you will notice that it also has an autocomplete feature. To disable the autocomplete feature on textarea, you need to do 2 things:

  • Set readonly attribtue as soon as textarea gets focused.
  • Remove readonly attribute just after 10 milliseconds.
<textarea name="address" id="address"></textarea>

<script>
    document.getElementById("address").addEventListener("focus", function() {
        const self = this;
        this.setAttribute("readonly", true);
        setTimeout(function () {
            self.removeAttribute("readonly");
        }, 10);
    });
</script>

If you set readonly attribute on textarea tag, the autocomplete feature does not work. But that means that user is also not able to type anything in textarea field. So you remove the readonly attribute right after 10 milliseconds that will not be noticeable by users.

If you face any problem in following this, kindly do let me know. Check out our tutorial to disable mouse scroll on input number fields.