Gmail SMTP New Method 2023 – PHP

In this tutorial, I am going to show you, how you can use Gmail SMTP for sending emails in PHP.

Video tutorial – Gmail SMTP in PHP

I will be using PHPMailer library. You can find all the code for sending email from PHPMailer documentation.

<?php

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\SMTP;

require 'PHPMailer/src/Exception.php';
require 'PHPMailer/src/PHPMailer.php';
require 'PHPMailer/src/SMTP.php';

//Create an instance; passing `true` enables exceptions
$mail = new PHPMailer(true);

try {
    //Server settings
    $mail->SMTPDebug = SMTP::DEBUG_SERVER;                      //Enable verbose debug output
    $mail->isSMTP();                                            //Send using SMTP
    $mail->Host       = 'smtp.gmail.com';                     //Set the SMTP server to send through
    $mail->SMTPAuth   = true;                                   //Enable SMTP authentication
    $mail->Username   = 'your_email_address@gmail.com';                     //SMTP username
    $mail->Password   = 'app_password';                               //SMTP password
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;            //Enable implicit TLS encryption
    $mail->Port       = 465;                                    //TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`

    //Recipients
    $mail->setFrom('your_email_address@gmail.com', 'Your name');
    $mail->addAddress('support@adnan-tech.com', 'Adnan Tech');

    //Content
    $mail->isHTML(true);                                  //Set email format to HTML
    $mail->Subject = 'Here is the subject';
    $mail->Body    = 'This is the HTML message body <b>in bold!</b>';
    $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';

    $mail->send();
    echo 'Message has been sent';
} catch (Exception $e) {
    echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}

Line #18: You need to set your host to smtp.gmail.com

Line #20: Write your email address

Line #21: Write the app password you will get from your google account in the next step.

First, you need to go to your google account.

Manage google account
Manage google account

Go to security.

Security
Security

Then go to 2-step verification.

2-step verification
2-step verification

After that, go to app passwords.

App passwords
App passwords

Set whatever name you want and generate.

This will generate an app password.

App password for Gmail SMTP - PHP
App password for Gmail SMTP – PHP

You can use this in your SMTP code. Line #21 of the above code.

Make sure there is no space in password. Then try again. You should receive an email now.

Learn how to do it in Node JS from here.

If you need any help in following this, kindly do let me know.

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.

Show WordPress posts in PHP website

In this tutorial, we will teach you how to show WordPress posts in your PHP website. Make sure you run this code from inside your server where the WordPress blog is hosted. This means that if your WordPress blog is hosted on the main domain like “adnan-tech.com”, then this code should be on any of the sub-domain like “web.adnan-tech.com”.

And vice versa, if your WordPress blog is hosted on a sub-domain like “blog.adnan-tech.com”, then this code should be on the main domain like “adnan-tech.com”. This script will not work on localhost because many of the WordPress blogs have some security plugins installed, that prevent any external host to fetch data from it.

Show WordPress posts in PHP

To show all the blog posts from your WordPress website, we will be using WordPress posts API. Just write the following code in the file where you want to show the blog listing. Make sure to change your blog URL in $blog_api_url variable:

<?php
    $blog_api_url = "https://yourblogdomain/wp-json/wp/v2";

    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => $blog_api_url . "/posts",
        CURLOPT_RETURNTRANSFER => 1
    ]);
    $response = curl_exec($curl);
    curl_close($curl);
    
    $posts = json_decode($response);
    foreach ($posts as $post)
    {
        $id = $post->id;
        $date = date("d M, Y", strtotime($post->date));
        $slug = $post->slug;
        $status = $post->status; // "publish"
        if ($status != "publish")
        {
            continue;
        }
        $link = $post->link;
        $title = $post->title->rendered;
        $excerpt = $post->excerpt->rendered;
    
        $curlMedia = curl_init();
        curl_setopt_array($curlMedia, [
            CURLOPT_URL => $blog_api_url . "/media/" . $post->featured_media,
            CURLOPT_RETURNTRANSFER => 1
        ]);
        $responseMedia = curl_exec($curlMedia);
    
        $responseMedia = json_decode($responseMedia);
        $mediaTitle = $responseMedia->title->rendered;
        $altText = $responseMedia->alt_text;
        $mediaSourceUrl = $responseMedia->source_url;

        ?>

        <div style="border: 1px solid black; margin: 10px; padding: 10px;">
            <?php if (!empty($mediaSourceUrl)) { ?>
                <img src="<?php echo $mediaSourceUrl; ?>" alt="<?php echo $altText; ?>" title="<?php echo $mediaTitle; ?>" style="width: 100%;" />
            <?php } ?>
            
            <div>
                <p><?php echo $date; ?></p>
                <h2>
                    <a href="./show-post.php?slug=<?php echo $slug; ?>">
                        <?php echo $title; ?>
                    </a>
                </h2>
                <p><?php echo $excerpt; ?></p>
            </div>
        </div>

    <?php
    }
?>

This will fetch the latest posts from your WordPress blog. We are looping through all the posts and saving the necessary variables from the $post object. You can write print_r($post) inside the foreach loop to view an entire $post object. We are only displaying the published posts here. If you want to show the unpublished posts as well, simply comment out the continue; statement. Inside the foreach loop, we are calling another CURL request to get the featured image of the post.

Blog listing

Then, we are creating a <div> inside the foreach loop with a 1-pixel black border and a 10 pixels margin from all sides. We are also giving it a 10 pixels padding so it will margin from inside too. Inside this div, we display the post’s published date, title, and excerpt. An excerpt is a short text from the blog post, you can set it up from the WordPress admin panel for each post separately. If not specified, then it will be the first paragraph of the post.

We are making the title a hyperlink, so when clicked, it will redirect the user to a new page where we can show that post in detail. We are using “./” in the hyperlink because our post detail page is in the same directory. You can also redirect the user to the original post on the WordPress blog using the variable $link. We didn’t put the hyperlink on the image, because if the post does not have a featured image, then the link will not be created. And the user will have no option to redirect to the post detail page.

Single post

To show the post detail inside your website, simply create a file named show-post.php and write the following code in it:

<?php
    $slug = $_GET["slug"];
    $blog_api_url = "https://yourblogdomain/wp-json/wp/v2";

    $curl = curl_init();
    curl_setopt_array($curl, [
        CURLOPT_URL => $blog_api_url . "/posts?slug=" . $slug,
        CURLOPT_RETURNTRANSFER => 1
    ]);
    $response = curl_exec($curl);
    curl_close($curl);

    $posts = json_decode($response);
    if (count($posts) == 0)
    {
        die("Post not found.");
    }
    
    $date = date("d M, Y H:i:s", strtotime($posts[0]->date));
    $status = $posts[0]->status; // "publish"
    if ($status != "publish")
    {
        die("Post not published.");
    }
    $title = $posts[0]->title->rendered;
    $content = $posts[0]->content->rendered;

    $curlMedia = curl_init();
    curl_setopt_array($curlMedia, [
        CURLOPT_URL => $blog_api_url . "/media/" . $posts[0]->featured_media,
        CURLOPT_RETURNTRANSFER => 1
    ]);
    $responseMedia = curl_exec($curlMedia);

    $responseMedia = json_decode($responseMedia);
    $mediaTitle = $responseMedia->title->rendered;
    $altText = $responseMedia->alt_text;
    $mediaSourceUrl = $responseMedia->source_url;
?>

<!-- Post title -->
<h1><?php echo $title; ?></h1>

<!-- Post meta content -->
<p>Posted on <?php echo $date; ?></p>

<!-- Preview featured image -->
<?php if (!empty($mediaSourceUrl)) { ?>
    <img src="<?php echo $mediaSourceUrl; ?>" alt="<?php echo $altText; ?>" title="<?php echo $mediaTitle; ?>" style="width: 100%;" />
<?php } ?>

<!-- Post content-->
<section>
    <?php echo $content; ?>
</section>

This will show the post title in the heading. Date the post was published. Featured image if available, the featured image will also have an alt text that will be displayed in case the image is not found. It will also have a title attribute that will be visible when the user moves the mouse over the image (hover effect). Finally, we are displaying the complete content of the post.

Show comments of the post

To show the comments of the post, first, we need to fetch all the comments of the post. We are again going to use the CURL request on WordPress comments API. Write the following code below post content:

<?php
    $curlComments = curl_init();
    curl_setopt_array($curlComments, [
        CURLOPT_URL => $blog_api_url . "/comments/?post=" . $posts[0]->id,
        CURLOPT_RETURNTRANSFER => 1
    ]);
    $responseComments = curl_exec($curlComments);
    $responseComments = json_decode($responseComments);

    foreach ($responseComments as $comment) {
        if ($comment->status != "approved") {
            continue;
        }
?>
    <div style="border: 1px solid black; margin: 10px; padding: 10px;">
        <?php foreach (((array) $comment->author_avatar_urls) as $avatar_url) { ?>
            <img src="<?php echo $avatar_url; ?>" style="width: 100px;" />
        <?php break; } ?>

        <p><?php echo $comment->author_name; ?></p>
        <p><?php echo $comment->content->rendered; ?></p>
    </div>
<?php } ?>

This will first fetch all the comments of that post. Then it will loop through each comment and will skip the loop iteration if the comment is not approved yet. Then, it will create a <div> tag with styles the same as we did for the blog listing. The author_avatar_urls object in each $comment is an object. So we need to convert that to an array using (array) typecasting. Then we will loop through it, and display the profile image of the user who posted that comment. After that, we are using a break statement so it will not show multiple images, it will stop the loop after displaying one image. User profile images are in different dimensions, but we need to show only one. And finally, we display the name of the person who posted the comment and the comment itself.

Check out our more tutorials on WordPress.

Source code – Show WordPress posts in PHP

[wpdm_package id=’1747′]

Or you can also download it from Github.

Adult image validation – PHP

In this article, we will teach you how to have adult image validation in your PHP website. Suppose you are creating a website where you allow people to upload images. And some people start uploading nudity images. Now you want to stop them.

Video tutorial:

For the sake of simplicity, we are creating a simple HTML form that allows users to upload images.

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

This shows an input file and a submit button. Then we need to download a class named “class.ImageFilter.php”. You can download it from here. I am also writing the class here:

<?php

// class.ImageFilter.php

class ImageFilter
{                              #R  G  B
    var $colorA = 7944996;     #79 3B 24
    var $colorB = 16696767;    #FE C5 BF


    var $arA = array();
    var $arB = array();
    
    public function __construct()
    {
        $this->arA['R'] = ($this->colorA >> 16) & 0xFF;
        $this->arA['G'] = ($this->colorA >> 8) & 0xFF;
        $this->arA['B'] = $this->colorA & 0xFF;
        
        $this->arB['R'] = ($this->colorB >> 16) & 0xFF;
        $this->arB['G'] = ($this->colorB >> 8) & 0xFF;
        $this->arB['B'] = $this->colorB & 0xFF;
    }
    
    function GetScore($image)
    {
        $x = 0; $y = 0;
        $img = $this->_GetImageResource($image, $x, $y);
        if(!$img) return false;

        $score = 0;
        
        $xPoints = array($x/8, $x/4, ($x/8 + $x/4), $x-($x/8 + $x/4), $x-($x/4), $x-($x/8));
        $yPoints = array($y/8, $y/4, ($y/8 + $y/4), $y-($y/8 + $y/4), $y-($y/8), $y-($y/8));
        $zPoints = array($xPoints[2], $yPoints[1], $xPoints[3], $y);

        
        for($i=0; $i<=$x; $i++)
        {
            for($j=0; $j<=$y; $j++)
            {
                $color = imagecolorat($img, $i, $j);
                if($color >= $this->colorA && $color <= $this->colorB)
                {
                    $color = array('R'=> ($color >> 16) & 0xFF, 'G'=> ($color >> 8) & 0xFF, 'B'=> $color & 0xFF);
                    if($color['G'] >= $this->arA['G'] && $color['G'] <= $this->arB['G'] && $color['B'] >= $this->arA['B'] && $color['B'] <= $this->arB['B'])
                    {
                        if($i >= $zPoints[0] && $j >= $zPoints[1] && $i <= $zPoints[2] && $j <= $zPoints[3])
                        {
                            $score += 3;
                        }
                        elseif($i <= $xPoints[0] || $i >=$xPoints[5] || $j <= $yPoints[0] || $j >= $yPoints[5])
                        {
                            $score += 0.10;
                        }
                        elseif($i <= $xPoints[0] || $i >=$xPoints[4] || $j <= $yPoints[0] || $j >= $yPoints[4])
                        {
                            $score += 0.40;
                        }
                        else
                        {
                            $score += 1.50;
                        }
                    }
                }
            }
        }
        
        imagedestroy($img);
        
        $score = sprintf('%01.2f', ($score * 100) / ($x * $y));
        if($score > 100) $score = 100;
        return $score;
    }
    
    function GetScoreAndFill($image, $outputImage)
    {
        $x = 0; $y = 0;
        $img = $this->_GetImageResource($image, $x, $y);
        if(!$img) return false;

        $score = 0;

        $xPoints = array($x/8, $x/4, ($x/8 + $x/4), $x-($x/8 + $x/4), $x-($x/4), $x-($x/8));
        $yPoints = array($y/8, $y/4, ($y/8 + $y/4), $y-($y/8 + $y/4), $y-($y/8), $y-($y/8));
        $zPoints = array($xPoints[2], $yPoints[1], $xPoints[3], $y);


        for($i=1; $i<=$x; $i++)
        {
            for($j=1; $j<=$y; $j++)
            {
                $color = imagecolorat($img, $i, $j);
                if($color >= $this->colorA && $color <= $this->colorB)
                {
                    $color = array('R'=> ($color >> 16) & 0xFF, 'G'=> ($color >> 8) & 0xFF, 'B'=> $color & 0xFF);
                    if($color['G'] >= $this->arA['G'] && $color['G'] <= $this->arB['G'] && $color['B'] >= $this->arA['B'] && $color['B'] <= $this->arB['B'])
                    {
                        if($i >= $zPoints[0] && $j >= $zPoints[1] && $i <= $zPoints[2] && $j <= $zPoints[3])
                        {
                            $score += 3;
                            imagefill($img, $i, $j, 16711680);
                        }
                        elseif($i <= $xPoints[0] || $i >=$xPoints[5] || $j <= $yPoints[0] || $j >= $yPoints[5])
                        {
                            $score += 0.10;
                            imagefill($img, $i, $j, 14540253);
                        }
                        elseif($i <= $xPoints[0] || $i >=$xPoints[4] || $j <= $yPoints[0] || $j >= $yPoints[4])
                        {
                            $score += 0.40;
                            imagefill($img, $i, $j, 16514887);
                        }
                        else
                        {
                            $score += 1.50;
                            imagefill($img, $i, $j, 512);
                        }
                    }
                }
            }
        }
        imagejpeg($img, $outputImage);

        imagedestroy($img);

        $score = sprintf('%01.2f', ($score * 100) / ($x * $y));
        if($score > 100) $score = 100;
        return $score;
    }
    
    function _GetImageResource($image, &$x, &$y)
    {
        $info = GetImageSize($image);
        
        $x = $info[0];
        $y = $info[1];
        
        switch( $info[2] )
        {
            case IMAGETYPE_GIF:
                return @ImageCreateFromGif($image);
                
            case IMAGETYPE_JPEG:
                return @ImageCreateFromJpeg($image);
                
            case IMAGETYPE_PNG:
                return @ImageCreateFromPng($image);
                
            default:
                return false;
        }
    }
}

Now to handle the input file uploaded from the form, we need to create a file named “upload.php”. Following will be the code of this file.

<?php

require_once "class.ImageFilter.php";

if (isset($_FILES["image"])
	&& $_FILES["image"]["size"] > 0)
{
	$type = strtolower($_FILES["image"]["type"]);

	if (in_array($type, ["image/jpeg", "image/jpg", "image/png"]))
	{
		$temp_path = "image.png";
		move_uploaded_file($_FILES["image"]["tmp_name"], $temp_path);

		$filter = new ImageFilter();
		$score = $filter->GetScore($temp_path);

		echo $score;

		if ($score > 60)
		{
			echo "<p>Image contains adult content.</p>";
			exit;
		}
		else
		{
			$file_path = basename($_FILES["image"]["name"]);
			copy($temp_path, $file_path);
		}

		unlink($temp_path);
	}
}
  1. First, we are including the class in our PHP file.
  2. Then we save the image file as “image.png”, you can set any name of your choice.
  3. Then we are creating an instance of ImageFilter class.
  4. Then we are getting the score of the newly created image file. A score of 61 and above is considered to contain nudity content.
  5. Then we are removing the image file we saved.
  6. And display the score to the user, you can remove this line if you do not want to show the scores to the user.
  7. Finally, we are putting a condition that says “if the score is greater than 60, then display an error message.”

So that’s how you can add an adult image validation feature to your PHP website. If you want to see this feature in action, we implemented this feature in our social network project. If you face any difficulty in implementing this in your project, feel free to contact us.

Source code – Adult image validation

[wpdm_package id=’1740′]

Copy entire folder from one storage to another – Laravel

In this tutorial, we are going to show you, how you can copy or move a folder from one storage to another storage folder in Laravel.

Video tutorial

So let’s say in your storage/app/public folder, these folders are already created by Laravel by default. We created 2 folders named folder1 and folder2. In folder1, we have a folder named files and it has some files. Now you want to move the entire files folder with all his files in folder2.

  • storage/app/public
    • folder1
      • files
    • folder2

Copy folder from one storage to another – Laravel

Following will be the code that will copy the entire folder from one storage to another:

// include classes
use Storage;
use Str;

// get all files from source folder
$files = Storage::files("public/folder1/files");

// loop through each file
foreach ($files as $file)
{
    // to get the content the file, we need to get it from public/storage
    // so change the path to public/storage folder
    $file = Str::of($file)->replace("public/folder1/", "public/storage/folder1/");

    // get the content of file
    $file_content = file_get_contents($file);

    // extract the file name from path
    $file_name_parts = explode("/", $file);
    if (count($file_name_parts) > 0)
    {
        // name is at the last index of array
        $file_name = $file_name_parts[count($file_name_parts) - 1];

        // set destination path
        $file_path = "public/folder2/files/" . $file_name;

        // save the file in destination folder
        Storage::put($file_path, $file_content);
    }
}

// delete the source folder
// do this only if you want to move the folder
Storage::deleteDirectory("public/folder1/files");

Explanation

  1. First, we are going to get all the files from the source folder.
  2. Then we will loop through each file.
  3. Then we need to get the content of each file. But in order to get the content of the Laravel storage file, we need to access it from a public shortcut path.
  4. So to change the path, we are going to use another class named Str.
  5. Then we need to call the function of and tell the target string and call the replace function. We will replace the “public/folder1/” (notice slash at the end) with the “public/storage/folder1/”. And save it back in the $file variable.
  6. Now we can get the content of the file by calling the PHP native function file_get_contents and pass the path of the file, and save it in the variable $file_content. If you get any error here, you need to run the following command at the root of your project:
    • php artisan storage:link
  7. Then we need to extract the file name from the file path. First, we will split the file path by slash using PHP explode function. It will return an array and we need to get the last index of this array. So we will check if the array is not empty. Then we will get the last index of the array. So if the length of the array is 5, minus 1 becomes 4, so it will fetch the element at index 4 which is the name of the file.
  8. After that, we are setting the destination path. It will be in the public/folder2/files and the name of the file. Right now, folder2 does not have a files folder, but it will automatically create one. To save the file, we need to call the Storage::put method. Pass the destination path and the content of the file.
  9. In order to have the move functionality, you simply need to remove the source folder after it has been copied. So after the foreach loop, we will call the deleteDirectory method from the Storage class and pass the path of the source folder.
  10. If you run the code now, you will see that folder1 becomes empty but now folder2 has all the files.

If you are working on AJAX and are getting any errors, feel free to check our tutorial on how to check Laravel errors from AJAX requests.

So that’s how you can copy or move an entire folder from one storage to another in Laravel. If you face any problems in following this, kindly do let me know.

Hosting email address send SMTP email in PHP

In this tutorial, we will teach you how to send email from a hosting email address using SMTP in PHP. Recently, Google has disabled its “less secure apps” option. This means that you can no longer send SMTP emails from your Gmail account.


So, today we are going to show you, how you can send SMTP emails from your own hosting email address.

Step 1: Login to cPanel

First step, is to login to your hosting provider and open cPanel. In your cPanel, search for “email” and goto “Email accounts”.

Step 2: Search email address

Then search for desired email address, from which you want to send emails and select “Check email”.

Step 3: Open mail client configurations

On the next page, you need to look for the section “Other webmail features” and click on the “Configure mail clients” box.

Step 4: Check SMTP details of your hosting email address

From here, you need to loop for the following configurations.

Step 5: Send SMTP email

Now, we need to install a library called PHPMailer. Open the command prompt at the root of your project and run the following command:

> composer require phpmailer/phpmailer

Make sure you have downloaded the composer from here. Write the following code in the file from where you want to send the email:

// Import PHPMailer classes into the global namespace
// These must be at the top of your script, not inside a function
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

//Instantiation and passing `true` enables exceptions
$mail = new PHPMailer(true);

try
{
    //Enable verbose debug output
    $mail->SMTPDebug = 0; // SMTP::DEBUG_SERVER;

    //Send using SMTP
    $mail->isSMTP();

    //Set the SMTP server to send through
    $mail->Host = "mail host address";

    //Enable SMTP authentication
    $mail->SMTPAuth = true;

    //SMTP username
    $mail->Username = "email address";

    //SMTP password
    $mail->Password = "password";

    //Enable TLS encryption;
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;

    //TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
    $mail->Port = 587;

    //Recipients
    $mail->setFrom("email address", "your name");

    //Add a recipient
    $mail->addAddress("recipient email address", "recipient name");

    //Set email format to HTML
    $mail->isHTML(true);

    $mail->Subject = "subject";
    $mail->Body    = "body";

    $mail->send();
    echo 'Message has been sent';
}
catch (Exception $e)
{
    die("Message could not be sent. Mailer Error: " . $mail->ErrorInfo);
}

So that’s it. That’s how you can send emails from your hosting email address using SMTP in PHP. If you want to attach files with the email, we have already created a separate tutorial on that. If you face any problems in following this, kindly do let me know.

Laravel Soft Delete – Create a Trash Can using PHP and MySQL

Laravel soft delete allows you to enable some models that will not be permanently deleted by just calling the delete() method. Instead, you need to call the forceDelete() method in order to permanently delete the data.

The deleted models will not be fetched from Eloquent or Query Builder queries. Instead, you need to call a separate function in order to fetch the records along with deleted ones, we will get on that later in this article. Laravel soft delete has several advantages:

  • First, it works like your PC’s recycle bin. If you accidentally deleted from record from your admin panel, it will not be deleted permanently at once.
  • Second, you can display all deleted data on a separate page.
  • You have a backup of your deleted data, so in the future, if you need some old data, you can always get it from recycle bin or trash can.
  • Can display all data to the user and highlight the data that is deleted.
  • Always be able to restore the accidentally deleted records.

Let’s get started

So let’s get started by creating a simple Laravel soft delete module. For the sake of this article, we will be implementing a trash can in our user’s model.

1. Creating a column in the user’s table

First, you need to run the following command to create a migration for soft deleting:

php artisan make:migration add_column_soft_delete_in_users_table

Then you need to open your migration file and add the following line in the Schema::table function inside up() method:

$table->softDeletes();

Then you need to run the migration using the following command:

php artisan migrate

Open your phpMyAdmin and you will see a new column at the end of the user’s table named deleted_at. Its default value will be NULL and it will have a current date & time value once you call the delete() method.

2. Laravel Soft Delete Eloquent Model

Open your user model usually in App\Models\User.php and update it as the following:

use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use HasFactory, Notifiable, SoftDeletes;

    ///////////
}

After that, whenever you call the delete() method on any user object, you will see that deleted_at the field will be updated to the current date & time of that user.

3. Display all Users with Pagination

Let’s say that you have an admin panel. We will be displaying all users (non-deleted) on one page. So first create a route for this in your routes/web.php file:

use App\Http\Controllers\UserController;

Route::group([
    "prefix" => "users"
], function () {
    Route::get("/", [UserController::class, "index"]);

    // [other routes goes here]
});

We have created a group because we will be adding more routes to it. For example, route to delete a user, route to display all deleted users, route to restore a user, and route to permanently delete a user. Run the following command if you do not have the UserController:

php artisan make:controller UserController

Now, create an index() method in your UserController class. Following is what your UserController should look like:

use App\Models\User;

public function index()
{
    $users = User::orderBy("id", "desc")->paginate();
    $trashed = User::onlyTrashed()->count();

    return view("users/index", [
        "users" => $users,
        "trashed" => $trashed
    ]);
}

Create a folder named users and inside this folder, create a file in resources/views/users/index.blade.php. This file should have the following code:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css" />
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.min.js"></script>

<a href="{{ url('/users/trashed') }}">
    Trash ({{ $trashed }})
</a>

<table class="table table-bordered">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Email</th>
        </tr>
    </thead>

    <tbody>
        @foreach ($users as $user)
            <tr>
                <td>{{ $user->id }}</td>
                <td>{{ $user->name }}</td>
                <td>{{ $user->email }}</td>
            </tr>
        @endforeach
    </tbody>
</table>

{{ $users->appends(request()->except("page"))->links() }}

Refresh the page now and you will see a list of all users. Now we need to create a button to delete a user.

4. Delete a User

To delete a user, we will first a heading in our <thead> tag:

<th>Actions</th>

Then in <tbody>, we need to create a form which when submit will first ask for confirmation. If confirmed, then it will mark the user as deleted.

<td>
	<form method="POST" action="{{ url('/users/delete') }}" onsubmit="return confirm('Are you sure you want to delete this user ?');">
		{{ csrf_field() }}
		<input type="hidden" name="id" value="{{ $user->id }}" required>
		<button type="submit" class="btn btn-danger">
			Delete
		</button>
	</form>
</td>

Refresh the page and you will see a delete button along with each user. Then create a route on your web.php file:

Route::post("/delete", [UserController::class, "destroy"]);

The above lines go in the [other routes goes here] section of web.php. Then create a method in your UserController to mark the user as deleted:

public function destroy()
{
    $user = User::find(request()->id);
    if ($user == null)
    {
        abort(404);
    }

    $user->delete();
    return redirect()->back();
}

You can delete the user in one line too, like this: User::destroy(request()->id); but fetching the user first has some advantages:

  • You can perform any other sub-functions before deleting a user.
  • Or check if the user exists or not, and display the proper messages accordingly.

Try deleting a user now, you will see that will no longer be displayed in your Bootstrap table. But you can still see the record in your database using phpMyAdmin. However, you will notice that the deleted_at the field is updated and now has the UTC date and time value when the delete operation was performed.

5. Show All Deleted Users

At 3rd step, we create an anchor tag that displays all the trashed user’s counts. Now is the time to create a route for it. To create a route on your routes/web file.

Route::get("/trashed", [UserController::class, "trashed_users"]);

Then create the following method in your UserController:

public function trashed_users()
{
    $trashed = User::onlyTrashed()->orderBy("id", "desc")->paginate();

    return view("users/trashed", [
        "trashed" => $trashed
    ]);
}

After that, create a file resources/views/users/trashed.blade.php. It will have the following code:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css" />
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.min.js"></script>

<table class="table table-bordered">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Email</th>
            <th>Deleted at</th>
            <th>Actions</th>
        </tr>
    </thead>

    <tbody>
        @foreach ($trashed as $user)
            <tr>
                <td>{{ $user->id }}</td>
                <td>{{ $user->name }}</td>
                <td>{{ $user->email }}</td>
                <td>{{ $user->deleted_at }}</td>
            </tr>
        @endforeach
    </tbody>
</table>

{{ $trashed->appends(request()->except("page"))->links() }}

Refresh the page now and you will see all deleted users in a table. You will also be able to view the date and time when they were deleted.

6. Restore the Deleted Records

First, create another <td> tag at the end of <tbody> tag. In this table cell, we will create a button that will ask for confirmation. And when confirmed, will restore the user.

<td>
    <form method="POST"
        action="{{ url('/users/restore') }}"
        onsubmit="return confirm('Are you sure you want to restore this user ?');">

        {{ csrf_field() }}

        <input type="hidden" name="id" value="{{ $user->id }}" required />
        <button type="submit" class="btn btn-success">
            Restore
        </button>
    </form>
</td>

Then create a route in your web/routes.php that will handle this request.

Route::post("/restore", [UserController::class, "do_restore"]);

After that, create the following method in your UserController:

public function do_restore()
{
    $user = User::withTrashed()->find(request()->id);
    if ($user == null)
    {
        abort(404);
    }

    $user->restore();
    return redirect()->back();
}

Refresh the page now and you will see a “Restore” button along with each delete user. On clicking that, you will be asked for confirmation. If confirmed, you will no longer see that record in the trash can. But you will start seeing that record in all users table.

If you open your database using phpMyAdmin, you will see that user will again have the deleted_at column value as NULL.

7. Permanently Delete Records

Where you are displaying all soft-deleted records in your trash can, you are already displaying a button to restore the record. Now is the time to display another button that will permanently delete the record from the database. Create a button along with the “Restore” button in your trash can:

<form method="POST"
    action="{{ url('/users/delete-permanently') }}"
    onsubmit="return confirm('Are you sure you want to permanently delete this user ?');">

    {{ csrf_field() }}

    <input type="hidden" name="id" value="{{ $user->id }}" required />
    <button type="submit" class="btn btn-danger">
        Delete
    </button>
</form>

Then, you need to create a route that will handle this request.

Route::post("/delete-permanently", [UserController::class, "delete_permanently"]);

Then you need to create a method in your UserController that will permanently delete that record from the database.

public function delete_permanently()
{
    $user = User::withTrashed()->find(request()->id);
    if ($user == null)
    {
        abort(404);
    }

    $user->forceDelete();
    return redirect()->back();
}

Refresh the page now and click on the delete button from the trash can. You will be asked for confirmation. Once confirmed, you will no longer see that record in the trash can nor in all users table. If you check the database, you will see that, that user’s row has been permanently deleted from the database.

Get our social networking site project developed in Laravel:

Social Networking Site in Laravel – Node JS, Socket IO

So that’s how you can implement a complete Laravel soft delete module in your web application.

[wpdm_package id=’1545′]

Save and Download BLOB images – PHP and MySQL

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

Table structure:

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

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

Laravel developers can do it in the following way:

use Illuminate\Support\Facades\DB;

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

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

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

Save BLOB images in MySQL:

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

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

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

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

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

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

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

Show all Saved BLOB images:

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

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

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

Download BLOB images from MySQL:

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

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

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

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

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

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

[wpdm_package id=’1541′]

Premium projects bundle

Buy the 14 premium projects bundle for $1000. The bundle contains projects in the following technologies:

  • Node JS and Mongo DB
  • PHP & MySQL, Laravel
  • Vue JS
  • Android apps

Project’s list

  1. Single page chat application – Vue JS, Node JS, Mongo DB
  2. E-commerce single page application – Vue JS, Node JS, Mongo DB
  3. Chat app – Android, Web admin panel
  4. Email marketing tool – Laravel, Vue JS
  5. Financial ledger – Vue JS, Node JS, Mongo DB
  6. Image sharing web app – Node JS, Mongo DB / MySQL
  7. Movie ticket booking site – PHP & MySQL, MVC
  8. Realtime blog in Node JS and Mongo DB
  9. File transfer web app – Node JS + Mongo DB
  10. Realtime customer support chat widget
  11. Video streaming website – Node JS, Mongo DB
  12. Picture competition web app – Node JS, Mongo DB
  13. Questionnaire – Node JS, Mongo DB
  14. Blog website – Laravel, Google Adsense approved

You can buy each project separately too as well. Besides getting all the pro features of all 14 projects, we also provide additional services to them.

Secure payment

We allow users to make payments easily and securely using their bank accounts. You can contact us here and we will send you an invoice to make the payment.

Source code

Complete source code is included in all the projects. You will enjoy the pro version of each project.

Support

If you encounter any problem in installing the project or deployment, our technical support team is here. You can schedule a meeting with them and they will be able to assist you over AnyDesk or TeamViewer.

Use as a college project

If you are a student and are looking to get ready-to-go projects to learn about code and how real projects work, this will be beneficial for you. Also, Node JS projects are good learning points for students in advanced programming.

Customize as you want

Once you download the projects, you can customize them as per your needs. You can change the color theme, add new features to it, etc.

Get help in deployment

Once projects are set up in your local host, we will be here if you needed any help in deployment to the live server. For Node JS projects, we will assist you in deployment to Heroku. And for Mongo DB projects, we will help you with a deployment to mongodb.com.

Price: $1000

Out TrustPilot reviews

TrustPilot-reviews
TrustPilot-reviews