PHP CRUD Operations with Search and Pagination

CRUD operation is the most used functionality in the web application. Almost, all web application uses CRUD functionality to manage and manipulate data in the database. The CRUD (Create, Read, Update and Delete) functionality can be easily implemented using PHP and MySQL. PHP CRUD with MySQL helps to handle view, add, edit, and delete data from the database.

Search and Pagination is a very useful feature to make the data list user-friendly. When you add CRUD functionality to the website, search and pagination are the must-have functionality for the CRUD data list. In this tutorial, we will show you how to implement PHP CRUD operations with search and pagination using MySQL.

In the example code, we will implement the following functionality to integrate CRUD with search filter and pagination in PHP.

  • Fetch and list the users data from the database.
  • Add pagination to the data list.
  • Search and filter records.
  • Add user data in the database.
  • Edit and update user data in the database.
  • Delete record from the database.

Before getting started, take a look the files structure of the PHP CRUD application with pagination and search.

php-crud-with-search-pagination-files-structure-codexworld

Create Database Table

To store the user’s information a table needs to be created in the database. The following SQL creates a users table with some basic fields in the MySQL database.

CREATE TABLE `users` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
 `email` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
 `phone` varchar(15) COLLATE utf8_unicode_ci NOT NULL,
 `created` datetime NOT NULL,
 `modified` datetime NOT NULL,
 `status` enum('1','0') COLLATE utf8_unicode_ci NOT NULL DEFAULT '1' COMMENT '1=Active | 0=Inactive',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Database Class (DB.class.php)

The DB class handles all the operations related to the database.

  • __construct() – Connect to the MySQL database server. Specify the database host ($dbHost), username ($dbUsername), password ($dbPassword), and name ($dbName) as per your database credentials.
  • getRows() – Fetch records from the database based on the specified conditions.
  • insert() – Insert records in the database.
  • update() – Update records in the database based on the specified conditions.
  • delete() – Delete records from the database based on the specified conditions.
<?php
/*
 * DB Class
 * This class is used for database related (connect, insert, update, and delete) operations
 * @author    CodexWorld.com
 * @url        http://www.codexworld.com
 * @license    http://www.codexworld.com/license
 */
class DB{
    private $dbHost     "localhost";
    private $dbUsername "root";
    private $dbPassword "root";
    private $dbName     "codexworld";
    
    public function __construct(){
        if(!isset($this->db)){
            // Connect to the database
            $conn = new mysqli($this->dbHost$this->dbUsername$this->dbPassword$this->dbName);
            if($conn->connect_error){
                die("Failed to connect with MySQL: " $conn->connect_error);
            }else{
                $this->db $conn;
            }
        }
    }
    
    /*
     * Returns rows from the database based on the conditions
     * @param string name of the table
     * @param array select, where, order_by, limit and return_type conditions
     */
    public function getRows($table$conditions = array()){
        $sql 'SELECT ';
        $sql .= array_key_exists("select"$conditions)?$conditions['select']:'*';
        $sql .= ' FROM '.$table;
        if(array_key_exists("where"$conditions)){
            $sql .= ' WHERE ';
            $i 0;
            foreach($conditions['where'] as $key => $value){
                $pre = ($i 0)?' AND ':'';
                $sql .= $pre.$key." = '".$value."'";
                $i++;
            }
        }
        
        if(array_key_exists("like"$conditions) && !empty($conditions['like'])){
            $sql .= (strpos($sql'WHERE') !== false)?' AND ':' WHERE ';
            $i 0;
            $likeSQL '';
            foreach($conditions['like'] as $key => $value){
                $pre = ($i 0)?' AND ':'';
                $likeSQL .= $pre.$key." LIKE '%".$value."%'";
                $i++;
            }
            $sql .= '('.$likeSQL.')';
        }
        
        if(array_key_exists("like_or"$conditions) && !empty($conditions['like_or'])){
            $sql .= (strpos($sql'WHERE') !== false)?' AND ':' WHERE ';
            $i 0;
            $likeSQL '';
            foreach($conditions['like_or'] as $key => $value){
                $pre = ($i 0)?' OR ':'';
                $likeSQL .= $pre.$key." LIKE '%".$value."%'";
                $i++;
            }
            $sql .= '('.$likeSQL.')';
        }
        
        if(array_key_exists("order_by"$conditions)){
            $sql .= ' ORDER BY '.$conditions['order_by']; 
        }
        
        if(array_key_exists("start"$conditions) && array_key_exists("limit"$conditions)){
            $sql .= ' LIMIT '.$conditions['start'].','.$conditions['limit']; 
        }elseif(!array_key_exists("start"$conditions) && array_key_exists("limit"$conditions)){
            $sql .= ' LIMIT '.$conditions['limit']; 
        }
        $result $this->db->query($sql);
        
        if(array_key_exists("return_type"$conditions) && $conditions['return_type'] != 'all'){
            switch($conditions['return_type']){
                case 'count':
                    $data $result->num_rows;
                    break;
                case 'single':
                    $data $result->fetch_assoc();
                    break;
                default:
                    $data '';
            }
        }else{
            if($result->num_rows 0){
                while($row $result->fetch_assoc()){
                    $data[] = $row;
                }
            }
        }
        return !empty($data)?$data:false;
    }
    
    /*
     * Insert data into the database
     * @param string name of the table
     * @param array the data for inserting into the table
     */
    public function insert($table$data){
        if(!empty($data) && is_array($data)){
            $columns '';
            $values  '';
            $i 0;
            if(!array_key_exists('created'$data)){
                $data['created'] = date("Y-m-d H:i:s");
            }
            if(!array_key_exists('modified'$data)){
                $data['modified'] = date("Y-m-d H:i:s");
            }
            foreach($data as $key=>$val){
                $pre = ($i 0)?', ':'';
                $columns .= $pre.$key;
                $values  .= $pre."'".$val."'";
                $i++;
            }
            $query "INSERT INTO ".$table." (".$columns.") VALUES (".$values.")";
            $insert $this->db->query($query);
            return $insert?$this->db->insert_id:false;
        }else{
            return false;
        }
    }
    
    /*
     * Update data into the database
     * @param string name of the table
     * @param array the data for updating into the table
     * @param array where condition on updating data
     */
    public function update($table$data$conditions){
        if(!empty($data) && is_array($data)){
            $colvalSet '';
            $whereSql '';
            $i 0;
            if(!array_key_exists('modified',$data)){
                $data['modified'] = date("Y-m-d H:i:s");
            }
            foreach($data as $key=>$val){
                $pre = ($i 0)?', ':'';
                $colvalSet .= $pre.$key."='".$val."'";
                $i++;
            }
            if(!empty($conditions)&& is_array($conditions)){
                $whereSql .= ' WHERE ';
                $i 0;
                foreach($conditions as $key => $value){
                    $pre = ($i 0)?' AND ':'';
                    $whereSql .= $pre.$key." = '".$value."'";
                    $i++;
                }
            }
            $query "UPDATE ".$table." SET ".$colvalSet.$whereSql;
            $update $this->db->query($query);
            return $update?$this->db->affected_rows:false;
        }else{
            return false;
        }
    }
    
    /*
     * Delete data from the database
     * @param string name of the table
     * @param array where condition on deleting data
     */
    public function delete($table$conditions){
        $whereSql '';
        if(!empty($conditions) && is_array($conditions)){
            $whereSql .= ' WHERE ';
            $i 0;
            foreach($conditions as $key => $value){
                $pre = ($i 0)?' AND ':'';
                $whereSql .= $pre.$key." = '".$value."'";
                $i++;
            }
        }
        $query "DELETE FROM ".$table.$whereSql;
        $delete $this->db->query($query);
        return $delete?true:false;
    }
}

PHP OOP CRUD Operations using PDO Extension and MySQL

Pagination Class (Pagination.class.php)

The Pagination class is used to generate links to control paging of the data list. You can see all the configuration options and reference of the PHP Pagination class from here.

Data list with Search and Pagination (index.php)

Initially, all the users data is retrieved from the database and listed in the webpage with Add, Edit, and Delete link. Also, search and pagination options are added to the CRUD data list.

  • The Add link redirect user to the addEdit.php page to perform the Create operation.
  • The Edit link redirects the user to the addEdit.php page with respective ID to perform the Update operation.
  • The Delete link redirects the user to the userAction.php file with action_type and id params to perform the Delete operation.
  • The Search option allows sorting the record set by the user’s name/email/phone.
    • Get search keywords from URL.
    • Pass search query in like_or param of getRows() function.
    • Retrieve filtered data based on the keywords.
  • The Pagination helps to retrieve a limited number of records from the database and access data through links.
    • Define offset and limit.
    • Initialize Pagination class and pass configuration options (Base URL, Total Rows Count, and Per Page Limit).
    • Call the createLinks() method of Pagination class to render the pagination links.
<?php

// Start session
session_start();

// Get session data
$sessData = !empty($_SESSION['sessData'])?$_SESSION['sessData']:'';

// Get status message from session
if(!empty($sessData['status']['msg'])){
    $statusMsg $sessData['status']['msg'];
    $statusMsgType $sessData['status']['type'];
    unset($_SESSION['sessData']['status']);
}

// Load pagination class
require_once 'Pagination.class.php';

// Load and initialize database class
require_once 'DB.class.php';
$db = new DB();

// Page offset and limit
$perPageLimit 2;
$offset = !empty($_GET['page'])?(($_GET['page']-1)*$perPageLimit):0;

// Get search keyword
$searchKeyword = !empty($_GET['sq'])?$_GET['sq']:'';
$searchStr = !empty($searchKeyword)?'?sq='.$searchKeyword:'';

// Search DB query
$searchArr '';
if(!empty($searchKeyword)){
    $searchArr = array(
        'name' => $searchKeyword,
        'email' => $searchKeyword,
        'phone' => $searchKeyword
    );
}

// Get count of the users
$con = array(
    'like_or' => $searchArr,
    'return_type' => 'count'
);
$rowCount $db->getRows('users'$con);

// Initialize pagination class
$pagConfig = array(
    'baseURL' => 'index.php'.$searchStr,
    'totalRows' => $rowCount,
    'perPage' => $perPageLimit
);
$pagination = new Pagination($pagConfig);

// Get users from database
$con = array(
    'like_or' => $searchArr,
    'start' => $offset,
    'limit' => $perPageLimit,
    'order_by' => 'id DESC',
);
$users $db->getRows('users'$con);

?>

<!-- Display status message -->
<?php if(!empty($statusMsg) && ($statusMsgType == 'success')){ ?>
<div class="alert alert-success"><?php echo $statusMsg?></div>
<?php }elseif(!empty($statusMsg) && ($statusMsgType == 'error')){ ?>
<div class="alert alert-danger"><?php echo $statusMsg?></div>
<?php ?>

<div class="row">
    <div class="col-md-12 search-panel">
        <!-- Search form -->
        <form>
        <div class="input-group">
            <input type="text" name="sq" class="form-control" placeholder="Search by keyword..." value="<?php echo $searchKeyword?>">
            <div class="input-group-btn">
                <button class="btn btn-default" type="submit">
                    <i class="glyphicon glyphicon-search"></i>
                </button>
            </div>
        </div>
        </form>
        
        <!-- Add link -->
        <span class="pull-right">
            <a href="addEdit.php" class="btn btn-primary"><i class="glyphicon glyphicon-plus"></i> New User</a>
        </span>
    </div>
    
    <!-- Data list table --> 
    <table class="table table-striped table-bordered">
        <thead>
            <tr>
                <th></th>
                <th>Name</th>
                <th>Email</th>
                <th>Phone</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
            <?php
            if(!empty($users)){ $count 0; 
                foreach($users as $user){ $count++;
            ?>
            <tr>
                <td><?php echo '#'.$count?></td>
                <td><?php echo $user['name']; ?></td>
                <td><?php echo $user['email']; ?></td>
                <td><?php echo $user['phone']; ?></td>
                <td>
                    <a href="addEdit.php?id=<?php echo $user['id']; ?>" class="glyphicon glyphicon-edit"></a>
                    <a href="userAction.php?action_type=delete&id=<?php echo $user['id']; ?>" class="glyphicon glyphicon-trash" onclick="return confirm('Are you sure to delete?')"></a>
                </td>
            </tr>
            <?php } }else{ ?>
            <tr><td colspan="5">No user(s) found......</td></tr>
            <?php ?>
        </tbody>
    </table>
    
    <!-- Display pagination links -->
    <?php echo $pagination->createLinks(); ?>
</div>

Create & Update Records (addEdit.php)

The addEdit.php file holds the HTML form to receive input from the user for add and edit data.

  • Initially, the form data is submitted to the PHP script (userAction.php) to insert records in the users table.
  • If the ID parameter exists on the URL, the existing user data will be retrieved from the database based on this ID and the data is pre-filled in the input fields. The data is submitted to the PHP script (userAction.php) to update the existing record in the users table.
  • If any error occurred, the error message will be shown and the pre-filled data will be rendered in the form fields.
<?php

// Start session
session_start();

$postData $userData = array();

// Get session data
$sessData = !empty($_SESSION['sessData'])?$_SESSION['sessData']:'';

// Get status message from session
if(!empty($sessData['status']['msg'])){
    $statusMsg $sessData['status']['msg'];
    $statusMsgType $sessData['status']['type'];
    unset($_SESSION['sessData']['status']);
}

// Get posted data from session
if(!empty($sessData['postData'])){
    $postData $sessData['postData'];
    unset($_SESSION['sessData']['postData']);
}

// Get user data
if(!empty($_GET['id'])){
    include 'DB.class.php';
    $db = new DB();
    $conditions['where'] = array(
        'id' => $_GET['id'],
    );
    $conditions['return_type'] = 'single';
    $userData $db->getRows('users'$conditions);
}

// Pre-filled data
$userData = !empty($postData)?$postData:$userData;

// Define action
$actionLabel = !empty($_GET['id'])?'Edit':'Add';

?>

<!-- Display status message -->
<?php if(!empty($statusMsg) && ($statusMsgType == 'success')){ ?>
<div class="alert alert-success"><?php echo $statusMsg?></div>
<?php }elseif(!empty($statusMsg) && ($statusMsgType == 'error')){ ?>
<div class="alert alert-danger"><?php echo $statusMsg?></div>
<?php ?>

<!-- Add/Edit form -->
<div class="panel panel-default">
    <div class="panel-heading"><?php echo $actionLabel?> User <a href="index.php" class="glyphicon glyphicon-arrow-left"></a></div>
    <div class="panel-body">
        <form method="post" action="userAction.php" class="form">
            <div class="form-group">
                <label>Name</label>
                <input type="text" class="form-control" name="name" value="<?php echo !empty($userData['name'])?$userData['name']:''?>">
            </div>
            <div class="form-group">
                <label>Email</label>
                <input type="text" class="form-control" name="email" value="<?php echo !empty($userData['email'])?$userData['email']:''?>">
            </div>
            <div class="form-group">
                <label>Phone</label>
                <input type="text" class="form-control" name="phone" value="<?php echo !empty($userData['phone'])?$userData['phone']:''?>">
            </div>
            <input type="hidden" name="id" value="<?php echo !empty($userData['id'])?$userData['id']:''?>">
            <input type="submit" name="userSubmit" class="btn btn-success" value="SUBMIT"/>
        </form>
    </div>
</div>

CRUD Operations (userAction.php)

The userAction.php file is used to perform the add, edit, and delete operations using PHP and MySQL (DB class).

  • Add / Edit Form Submit – If the form is submitted, the data is inserted or updated in the database based on the id field.
  • Query String in URL – If action_type parameter exists in the URL, the record is deleted from the database based on ID given in the query string with id parameter.

After the data manipulation, the status is stored in SESSION and the user redirects back to the respective page.

<?php

// Start session
session_start();

// Load and initialize database class
require_once 'DB.class.php';

$db = new DB();

$tblName 'users';

// Set default redirect url
$redirectURL 'index.php';

if(isset($_POST['userSubmit'])){

    // Get submitted data
    $name   $_POST['name'];
    $email  $_POST['email'];
    $phone  $_POST['phone'];
    $id     $_POST['id'];
    
    // Submitted user data
    $userData = array(
        'name'  => $name,
        'email' => $email,
        'phone' => $phone
    );
    
    // Store submitted data into session
    $sessData['postData'] = $userData;
    $sessData['postData']['id'] = $id;
    
    // ID query string
    $idStr = !empty($id)?'?id='.$id:'';
    
    // If the data is not empty
    if(!empty($name) && !empty($email) && !empty($phone)){
        if(filter_var($emailFILTER_VALIDATE_EMAIL)){
            if(!empty($id)){
                // Update data
                $condition = array('id' => $id);
                $update $db->update($tblName$userData$condition);
                
                if($update){
                    $sessData['postData'] = '';
                    $sessData['status']['type'] = 'success';
                    $sessData['status']['msg']  = 'User data has been updated successfully.';
                }else{
                    $sessData['status']['type'] = 'error';
                    $sessData['status']['msg']  = 'Some problem occurred, please try again.';
                    
                    // Set redirect url
                    $redirectURL 'addEdit.php'.$idStr;
                }
            }else{
                // Insert data
                $insert $db->insert($tblName$userData);
                
                if($insert){
                    $sessData['postData'] = '';
                    $sessData['status']['type'] = 'success';
                    $sessData['status']['msg']  = 'User data has been added successfully.';
                }else{

                    $sessData['status']['type'] = 'error';
                    $sessData['status']['msg']  = 'Some problem occurred, please try again.';
                    
                    // Set redirect url
                    $redirectURL 'addEdit.php';
                }
            }
        }else{
            $sessData['status']['type'] = 'error';
            $sessData['status']['msg']  = 'Please enter a valid email address.';
            
            // Set redirect url
            $redirectURL 'addEdit.php'.$idStr;
        }
    }else{
        $sessData['status']['type'] = 'error';
        $sessData['status']['msg']  = 'All fields are mandatory, please fill all the fields.';
        
        // Set redirect url
        $redirectURL 'addEdit.php'.$idStr;
    }
    
    // Store status into the session
    $_SESSION['sessData'] = $sessData;
}elseif(($_REQUEST['action_type'] == 'delete') && !empty($_GET['id'])){
    // Delete data
    $condition = array('id' => $_GET['id']);
    $delete $db->delete($tblName$condition);
    if($delete){
        $sessData['status']['type'] = 'success';
        $sessData['status']['msg']  = 'User data has been deleted successfully.';
    }else{
        $sessData['status']['type'] = 'error';
        $sessData['status']['msg']  = 'Some problem occurred, please try again.';
    }
    
    // Store status into the session
    $_SESSION['sessData'] = $sessData;
}

// Redirect the user
header("Location: ".$redirectURL);
exit();

PHP CRUD Operations without Page Refresh using Ajax

Conclusion

Our simple CRUD operations with PHP and MySQLi, help you to implement data management (select, insert, update, and delete) functionality in the web application. Also, this example script will add pagination with search to make the CRUD data list more user-friendly. You can easily enhance the PHP CRUD with search and pagination script functionality as per your needs.

Do you want to get implementation help, or enhance the functionality of this script? Click here to Submit Service Request

4 Comments

  1. Abbe Said...
  2. Bwino Said...
  3. Danny Said...

Leave a reply

keyboard_double_arrow_up