Learn how to do case-sensitive search in MySQL. By default, MySQL search text-based column values without case sensitivity. For example, if your database looks like this:
Table: users
id
email
1
support@adnan-tech.com
2
support@Adnan-tech.com
And if you run the following query:
SELECT * FROM users WHERE email = "support@Adnan-tech.com";
It will return both records. However, it should have return only the 2nd record. The reason why, is because, usually the collation of text-based columns in MySQL is utf8_general_ci which is case insensitive.
So you just need to change the collation of “email” column in “users” table by running the following command:
ALTER TABLE users MODIFY email VARCHAR(255) COLLATE utf8mb4_bin;
If you run the query again, you will only see the 2nd row. Even though the 1st row value is also same, it is in lower-case and the query is in upper case “A”.
This is because utf8mb4_bin, it ensures that the search and sort on this column should be case sensitive.
That is how you can do case-sensitive search in MySQL using utf8mb4_bin collation. It is really helpful specially if you are searching on column that has UUID values.
I was looking for a tool that allows me to write API documentation so I can provide it to the frontend developers and also for myself. I checked many but didn’t find any that fits to all of my requirements. So I decided to create one of my own. Creating my own tool gives me flexibility to modify it as much as I want.
I also wanted it to share it with other developers who might be having problem in finding the tool to write documentation for their API. So I uploaded it on Github and it is available for anyone for free.
How to write API documentation
A tool is created in PHP and MySQL that allows developers to write API documentation, and this tool is available for free. You can create multiple sections to group the APIs based on modules. For example, user authentication, user posts, comments, replies can be separate sections.
To write each API, you need to tell:
The section where it goes.
The name of the endpoint. It can be the URL of API.
The method, it can be either GET or POST. But since you will have the code, you can add more methods as per your needs.
Add a little description about the API, for example what this API does.
Headers:
You need to tell the key of header, whether it is required or optional. And a little description about the header, for example, it’s possible values.
Parameters:
Parameters are usually send in the URL. You can define them along with their key, and value and whether they are optional or not.
Arguments:
For defining the arguments, you need to specify it’s type too. Whether it can be an integer, a string, boolean value or a file object.
Example request body. You can write the CURL code inside it to give an example.
Status codes and their responses.
I wrote a complete documentation of a project using this tool. You can check that from here.
Real estate business that requires a website for their business, we are providing a free website for them in PHP and MySQL (Laravel framework).
Screenshots
Features
Following are the key features in this project. More features can be added on-demand.
Admin panel
There is a dedicated admin panel from where admin can manage all properties, set business email, phone and address. He can also manage the banners on home page. Administrator can also see all the messages received from “contact us” form from use side.
Properties
In this free real estate website, you can mention the properties available. From admin panel, you can add, edit or delete any property you want. You just need to enter the property name and its price. You can also upload an image of the property. For more information, you can write the detail on the “description” box.
Apart from these, you can also mention the following attributes of the property:
Area of property.
Number of floors.
Number of rooms.
Number of bedrooms.
Number of bathrooms.
Parking space.
And payment process (Cash, Bank, Cheque etc.).
Home banners
You can upload banners for home page. When user lands on your real estate website, he will see those banners right infront of him. You can upload as many banners as you want, but the ideal number is 3. You can delete any banner whenever you want.
Business information
To update the business information like phone, email and address. You don’t need to go into source code and update these on all places. On admin panel, you can goto “settings” and enter their values and they will be updated on all places in the website. You can also set the name of website from settings page.
Social network
Same as you can update your business information, you can enter your social media links from admin panel. Right now you can set the following social network links:
Facebook
Twitter
Instagram
LinkedIn
But more can be added on-demand.
Contact us
On user-side, we have a “contact us” form from where user can enter his name and email and send a message. You can see all user’s sent messages on admin panel. You can see their name and email, so if you want to contact them back, you can do easily.
Installation
Create a database “real_estate” in your phpMyAdmin.
Previously we did password less authentication in Node JS and Mongo DB, in this article we will do it in PHP and MySQL.
Suppose you are trying to login to someone’s computer. You might open an incognito window in order to prevent the password from being saved in the browser. But what if he has installed a keylogger in his computer ? He can track your keystrokes and will know your email and password.
You can try typing your password from virtual keyboard, but what if he has also installed a screen recroding software that quitely records the screen ?
So the website developers must provide a way to secure their users from such vulnerabilities.
The best way is to allow users to login without entering their password. In-fact, there will be no password. User just have to enter his email address. We will send him a verification code. He needs to enter that code to verify.
That code will be auto-generated and will not be used again once user is logged-in. So even if some keylogging or screen recording software knows the verification code, it will be of no use. Because the code will not work next time someone tries with that user’s email address.
Create a Table
First I am going to create users table. If you already have one, you just need to add another column code in it.
<?php
$db_name = "test";
$username = "root";
$password = "";
$conn = new PDO("mysql:host=localhost;dbname=" . $db_name, $username, $password);
$sql = "CREATE TABLE IF NOT EXISTS users(
id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
email TEXT NULL,
code TEXT NULL
)";
$result = $conn->prepare($sql);
$result->execute();
I am using PDO to prevent SQL injection. If you want to know more about PHP PDO, you can check our guide here. If you refresh the page now and check your phpMyAdmin, you will have users table created in your database.
users-table-password-less-authentication-php
Login Form
Next we need to create a form to ask for user’s email address. It will also have a submit button.
This will create an input field and a submit button.
Send email in PHP
Then we need to generate a random code and send an email with that verification code. For sending email, we will be using a library PHPMailer. You can download it and extract the folder in your project’s root directory.
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'PHPMailer/src/Exception.php';
require 'PHPMailer/src/PHPMailer.php';
require 'PHPMailer/src/SMTP.php';
function send_mail($to, $subject, $body)
{
//Create an instance; passing `true` enables exceptions
$mail = new PHPMailer(true);
try {
//Server settings
$mail->SMTPDebug = 0; //Enable verbose debug output
$mail->isSMTP(); //Send using SMTP
$mail->Host = 'mail.adnan-tech.com'; //Set the SMTP server to send through
$mail->SMTPAuth = true; //Enable SMTP authentication
$mail->Username = 'support@adnan-tech.com'; //SMTP username
$mail->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('support@adnan-tech.com', 'Adnan Afzal');
$mail->addAddress($to); //Name is optional
//Content
$mail->isHTML(true); //Set email format to HTML
$mail->Subject = $subject;
$mail->Body = $body;
$mail->AltBody = $body;
$mail->send();
// echo 'Message has been sent';
} catch (Exception $e) {
// echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}
}
if ($_SERVER["REQUEST_METHOD"] == "POST")
{
$email = $_POST["email"];
$str = "qwertyuiopasdfghjklzxcvbnm1234567890";
$code = "";
for ($a = 1; $a <= 6; $a++)
{
$code .= $str[rand(0, strlen($str) - 1)];
}
$subject = "Login";
$body = "Your verification code is " . $code;
$sql = "SELECT * FROM users WHERE email = :email";
$result = $conn->prepare($sql);
$result->execute([
":email" => $email
]);
$user = $result->fetch();
if ($user == null)
{
$sql = "INSERT INTO users(email, code) VALUES (:email, :code)";
$result = $conn->prepare($sql);
$result->execute([
":email" => $email,
":code" => $code
]);
send_mail($email, $subject, $body);
header("Location: verify.php?email=" . $email);
exit();
}
$sql = "UPDATE users SET code = :code WHERE email = :email";
$result = $conn->prepare($sql);
$result->execute([
":email" => $email,
":code" => $code
]);
send_mail($email, $subject, $body);
header("Location: verify.php?email=" . $email);
exit();
}
Here, first I am generating a random 6 character code. Then I am setting the body of the email in a $body variable.
Then I am checking if the user already exists in the database. If not, then insert a new row in database. Sends an email and redirect the user to the verification page.
If user already exists, then I am simply updating his code column. Sends an email and redirect to a new page to verify the code.
Note: You need to enter your correct SMTP credentials (email and password) in order to send the email.
Verify the Code
Create a new file verify.php and inside it, first get the email from the URL. Then create a form with an hidden input field for email. One input field for user to enter the code sent at email, and a submit button.
We are creating a hidden input field so that it will be sent along with form. Now when the form submits, we need to check if user has provided correct code.
if ($_SERVER["REQUEST_METHOD"] == "POST")
{
$email = $_POST["email"] ?? "";
$code = $_POST["code"] ?? "";
$sql = "SELECT * FROM users WHERE email = :email AND code = :code";
$result = $conn->prepare($sql);
$result->execute([
":email" => $email,
":code" => $code
]);
$user = $result->fetch();
if ($user == null)
{
die("Invalid code.");
}
$sql = "UPDATE users SET code = NULL WHERE id = :id";
$result = $conn->prepare($sql);
$result->execute([
":id" => $user["id"]
]);
die("Logged-in");
}
If the user provides an in-valid code, then we are simply displaying him an error message. If he has provided the correct code, then we are setting his code column to NULL so it won’t be used again.
You can also try sending an AJAX and pass the code value as null, it still won’t be logged-in.
// for testing only
const ajax = new XMLHttpRequest()
ajax.open("POST", "verify.php", true)
const formData = new FormData()
formData.append("email", "support@adnan-tech.com")
formData.append("code", null)
ajax.send(formData)
So that’s it. That’s how you can add password-less authentication system in your application using PHP and MySQL. If you face any problem in following this, kindly do let me know.
A clone of TrustPilot website is created in PHP and MySQL using Laravel framework version 11. For frontend rendering, I am using Vue JS 3 and on admin side I am using React JS.
Files included:
.php
.css
.js
Features:
User can post reviews about a company.
Can flag a review.
Can share reviews on social media.
Company owners can claim a company by verifying their email address.
Automatically takes screenshot of a company home page.
A Job Portal website is created in PHP and MySQL using MVC architecture. MVC stands for Model-View-Controller and this architectural design is used by many websites for scalability.
✅ Compatible with almost every shared/dedicated/VPS hosting.
✅ Free support.
New features:
✅ Optimized sending bulk emails.
Files included:
.php
.css
.js
Tech stack:
PHP +7.0
MySQL +5.0
Bootstrap 4
Vue JS 3
Recruiter can post a job
Recruiter posted jobs
Change status of applicant
Edit/delete job
A recruiter can edit or delete any of his posted jobs at any time. This helps if the recruiter needs to change the requirements for a job or delete if the vacancy is already been filled.
Jobs Listing
Users will get a listing of all the jobs posted by recruiters.
Job Detail
They can view the job details by clicking the job title.
Filter Jobs
On the jobs listing page, users can filter jobs by the type of job they want, like developer, designer, etc. By the location to see if the job is in their city or if they can relocate to that city. Or by the nature of the job i.e. is the job part-time, full-time, or remote. Users can also search the jobs in their salary range. This way they can find jobs that pay them according to their needs.
Real-time updates on new jobs
Users will get real-time updates whenever a new job is posted by the recruiter. They do not have to refresh the page to check if there is any new job. To develop this feature, I have used sockets. You need to install Node JS in your system or server to make this feature work. Even if you do not have Node JS installed, all other features will work except for real-time job updates.
Email notifications of new jobs
Users can turn on notifications from recruiters. Whenever that recruiter posts a new job, all the users who have turned on their notifications will receive an email.
Admin can see all the stats
The admin of the website can see the total number of users registered. The total number of jobs that have been posted by recruiters. And the total number of applications that have been submitted for those jobs. The admin can see all this information on his dashboard.
Manage users
Admin will have the option to add new users to the website. While adding, he/she can select if the user be an applicant or a recruiter. Admin can also manage existing users. Admin can edit the user and can also delete the user if required. Admin can change the password of the user as well. This is helpful if the user is finding it difficult to receive the password reset email. Or if you want to prevent the user from logging in.
Deployment
This Job Portal website can be deployed on any server that supports PHP and MySQL.
Hello. In this article, we are going to show you some MongoDB and MySQL equivalent queries. This will help you greatly if you want to convert a MySQL project into MongoDB or vice-versa.
Video tutorial:
Introduction
First, let’s give a small introduction to both of these databases.
MongoDB
MongoDB is schema-less database architecture. Means that the schema or structure of the database does not needs to be defined. Schema will automatically gets created as data comes in. It is used where data needs to be loosely-coupled.
MySQL
MySQL is a structured query language. The structure of the database and its tables needs to be defined before creating them. It is used where data needs to be tightly-coupled.
MongoDB
MySQL
It is schema-less.
Schema needs to be defined.
Non-relational database.
Relational database.
It has collections.
It has tables.
It has documents.
It has rows.
Used for loosely-coupled data.
Used for tightly-coupled data.
Horizontal scaling.
Vertical scaling.
Each document can have different structure.
Each row must have same structure.
Data is not dependent on other collections.
Data might be dependent on other tables.
Uses nested objects and arrays.
Uses separate tables and joins them using foreign keys.
1. Creating collections/tables
MongoDB
As mentioned above, MongoDB collections does not needs to be created. They will be created automatically once a document is inserted in it.
MySQL
To create a table in MySQL database, you can run the following query:
CREATE TABLE IF NOT EXISTS users(
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
name TEXT NOT NULL,
age INTEGER DEFAULT 0
);
This will create a table named “users” having 3 columns “id”, “name” and “age”. ID will be a unique key that will automatically be incremented once a new row is inserted. While “name” will be a text string field and “age” will be an integer number.
2. Inserting documents/rows
MongoDB
To insert a document in a MongoDB collection, you can run the following query:
db.users.insertOne({
name: "Adnan",
age: 30
});
This will insert a new document in “users” collection. It will automatically assign unique ObjectId to it named “_id”.
This will sort the users documents by name in descending order, skip 1 record and return only 1 record.
Similar query can be run on MySQL in the following way:
SELECT * FROM users WHERE age = 30 ORDER BY id DESC LIMIT 1, 1
LIMIT {skip}, {limit} this is the syntax of LIMIT command in SQL.
3.4 Less or greater than
In MongoDB, you can use $lt (less than) and $gt (greater than) operators like this:
db.users.find({
age: {
$lt: 30
}
}).toArray()
This will return the users whose age is less than 30. Following query will return the users whose age is greater than 30:
db.users.find({
age: {
$gt: 30
}
}).toArray()
You can also use $lte and $gte operators for “less than and equal to” and “greater than and equal to” conditions respectively.
Above are the MongoDB queries, following are their equivalent MySQL queries:
/* less than */
SELECT * FROM users WHERE age < 30;
/* less than and equal to */
SELECT * FROM users WHERE age <= 30;
/* greater than */
SELECT * FROM users WHERE age > 30;
/* greater than and equal to */
SELECT * FROM users WHERE age >= 30;
4. Updating data
To update a document in MongoDB collection, you would do the following:
UPDATE users SET age = age + 3 WHERE name = "Adnan"
5. Delete data
To delete a document from MongoDB collection, you can run the following query:
db.users.deleteOne({
name: "Adnan"
})
This will delete one document from users collection whose name is “Adnan”. To delete multiple, you can use deleteMany() function instead.
In MySQL, you can do:
DELETE FROM users WHERE name = "Adnan" LIMIT 1
6. Relationships
MongoDB
MongoDB is not a relational database. Data saved in one collection is not dependent on another collection’s data.
For example, if you want to save job history of each user. You do not have to create a separate collection for that. You can simply push a new job in document’s array.
Whereas, MySQL is a relational database. Data saved in one table might be dependent on another table’s data.
If you want to achieve the above in MySQL, you would have to create a separate table for that and create user_id as foreign key and reference it to your “users” table.
CREATE TABLE IF NOT EXISTS jobs(
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
title TEXT NOT NULL,
company TEXT NOT NULL,
period TEXT NOT NULL,
user_id INTEGER NOT NULL,
CONSTRAINT fk_user_id_jobs FOREIGN KEY (user_id) REFERENCES users(id)
)
After that, you can insert a new job of that user using the following query:
INSERT INTO jobs (title, company, period, user_id) VALUES ("Developer", "adnan-tech.com", "3 years", 1)
This will insert a new row in “jobs” table and link it with “users” table using its foreign ID “user_id”.
jobs-table
To fetch the data both from users and jobs table, you have to perform a join operation.
SELECT * FROM users INNER JOIN jobs ON users.id = jobs.user_id
This will return all the users along with their jobs.
jobs-table-join-users-table
So you have learned to create many MongoDB queries to their equivalent MySQL queries and vice-versa. If you have any question related to this, feel free to comment it in the section below. You can also check our more tutorials on MongoDB to learn more.
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 ?
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.
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.
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 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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:
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:
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.
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.
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.
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: