Posts

AJAX CRUD Tutorial Using JavaScript, JSON and PHP – Step by Step Guide!


Previously, we learned how to create a simple REST API in PHP. Today, we are going to learn how to create or insert, read, update and delete records with our AJAX CRUD Tutorial. We will use jQuery, JSON and PHP.

Overview

What is AJAX? It stands for "Asynchronous JavaScript and XML".

I’ll try to explain it in the simplest way: Using AJAX will prevent re-loading the whole page for every button click you make. As a result, it makes the user experience better. Your web app will be faster.

Ajax is not a technology, but a group of technologies. This can include HTML, CSS, JavaScript and server side scripting like PHP.

I highly recommend studying the previous tutorials first before proceeding here. But if you think you can take this one, then go on.

This tutorial will focus on creating, reading, updating and deleting database records. We will do it using a jQuery, JSON and PHP.

jQuery will help us with the AJAX part. JSON data will be handled by the REST API built using PHP.

Program Output - PHP AJAX CRUD Tutorial

Below are some screenshots of our script's output. You can click an image to view the larger version of it. Use the left and right arrow to navigate through the screenshots.

LEVEL 1 Source Code Output

[espro-slider id=7093]

LEVEL 2 Source Code Output

[espro-slider id=7101]

LEVEL 3 Source Code Output

[espro-slider id=8325]

The LEVEL 2 and 3 source code outputs proves that you can add and customize more features. It’s easier and faster if you will learn by following our tutorial below.

Downloading our source codes is your huge advantage as well. For now, let’s proceed to the step by step tutorial of our LEVEL 1 source code. Enjoy!

Set Up The REST API

In this tutorial, we are going to use a REST API built with PHP.

We did not include REST API source code because we want you to focus on learning how to code with AJAX, not PHP.

But the good news is, we made a separate tutorial about how to build a simple REST API with PHP. Click here to learn the step-by-step PHP REST API tutorial.

I highly recommend learning our REST API tutorial first. This is because we are going to use that API for the rest of this tutorial.

But if you already have your own REST API that will work with this tutorial, that's okay as well.

In my case, one example where I can access the REST API is: http://localhost/api/product/read.php

That link will show me the list of products from the database, in JSON format. It looks like the following screenshot.

The data above will be consumed by our AJAX app. The list of products will be displayed in Bootstrap table with buttons like "Read One", "Update" and "Delete". You will see it in the "How To Read JSON Data Using jQuery AJAX?" section of this tutorial.

By the way, I'm using a Chrome extension called JSONView to make the JSON data readable in the browser.

Basic Files & Folders

File Structure

We will have the following files and folders at the end of this LEVEL 1 source code tutorial.

├─ app/
├─── assets/
├────── css/
├───────── style.css
├────── js/
├───────── bootbox.min.js
├───────── jquery.js
├─── products/
├────── create-product.js
├────── delete-product.js
├────── read-one-product.js
├────── read-products.js
├────── update-product.js
├─── app.js
├─ index.html

On the next sections, we will start creating the files and folders to achieve the one above.

Create index.html file

Create index.html file on your project's main folder. Open that file and put the following code.

<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Read Products</title>

    <!-- bootstrap CSS -->
	<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

	<!-- custom CSS -->
	<link href="app/assets/css/style.css" rel="stylesheet" />

</head>
<body>

<!-- our app will be injected here -->
<div id="app"></div>

<!-- jQuery library -->
<script src="app/assets/js/jquery.js"></script>

<!-- bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

<!-- bootbox for confirm pop up -->
<script src="app/assets/js/bootbox.min.js"></script>

<!-- app js script -->
<script src="app/app.js"></script>

<!-- products scripts -->
<script src="app/products/read-products.js"></script>
<script src="app/products/create-product.js"></script>
<script src="app/products/read-one-product.js"></script>
<script src="app/products/update-product.js"></script>
<script src="app/products/delete-product.js"></script>

</body>
</html>

Enable Bootstrap

As you can see in the index.html file above, we enabled Bootstrap via CDN.

If you need to enable Bootstrap via download, that will work as well.

See this tutorial to help you do that.

Create custom CSS file

  1. Create "app" folder.
  2. Open the "app" folder and create the "assets" folder.
  3. Open the "assets" folder and create the "css" folder.
  4. Open the "css" folder and create "style.css" file.

The "style.css" file is our custom CSS file. You can put any CSS in this file for additional web page styling. In our case, we have the following CSS code inside the "style.css" file.

.m-r-10px{ margin-right:10px; }
.m-b-10px{ margin-bottom:10px; }
.m-b-15px{ margin-bottom:15px; }
.m-b-20px{ margin-bottom:20px; }
.w-5-pct{ width:5%; }
.w-10-pct{ width:10%; }
.w-15-pct{ width:15%; }
.w-20-pct{ width:20%; }
.w-25-pct{ width:25%; }
.w-30-pct{ width:30%; }
.w-35-pct{ width:35%; }
.w-40-pct{ width:40%; }
.w-45-pct{ width:45%; }
.w-50-pct{ width:50%; }
.w-55-pct{ width:55%; }
.w-60-pct{ width:60%; }
.w-65-pct{ width:65%; }
.w-70-pct{ width:70%; }
.w-75-pct{ width:75%; }
.w-80-pct{ width:80%; }
.w-85-pct{ width:85%; }
.w-90-pct{ width:90%; }
.w-95-pct{ width:95%; }
.w-100-pct{ width:100%; }
.display-none{ display:none; }
.padding-bottom-2em{ padding-bottom:2em; }
.width-30-pct{ width:30%; }
.width-40-pct{ width:40%; }
.overflow-hidden{ overflow:hidden; }
.margin-right-1em{ margin-right:1em; }
.right-margin{ margin:0 .5em 0 0; }
.margin-bottom-1em { margin-bottom:1em; }
.margin-zero{ margin:0; }
.text-align-center{ text-align:center; }

Download jQuery and Bootbox.js libraries

  1. Open "app" folder.
  2. Open "assets" folder inside "app" folder
  3. Create "js" folder inside "assets" folder.

The "js" folder is where we will put the jQuery and Bootbox.js libraries.

jQuery JavaScript library is needed to make our simple app simple. Download jQuery in this link.

Bootbox.js library is needed to make the "delete" confirmation dialog box look better. Download Bootbox.js in this link.

There are CDNs for these JavaScript libraries as well. You can use them if you want but I prefer the downloaded versions. Both will work.

Create app.js file

The "app.js" file contains some basic HTML and JavaScript functions that can be used by other JS files in our app.

  1. Open "app" folder.
  2. Inside that "app" folder, create "app.js" file.
  3. Open "app.js" file and put the following code.
$(document).ready(function(){

    // app html
    var app_html=`
        <div class='container'>

            <div class='page-header'>
                <h1 id='page-title'>Read Products</h1>
            </div>

            <!-- this is where the contents will be shown. -->
            <div id='page-content'></div>

        </div>`;

    // inject to 'app' in index.html
    $("#app").html(app_html);

});

// change page title
function changePageTitle(page_title){

	// change page title
	$('#page-title').text(page_title);

	// change title tag
	document.title=page_title;
}

// function to make form values to json format
$.fn.serializeObject = function()
{
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

Create "products" scripts

Now, we will create several JavaScript files.

  1. Open "app" folder.
  2. Create "products" folder inside "app" folder.
  3. Create the following files inside "products" folder:
    • read-products.js
    • create-product.js
    • read-one-product.js
    • update-product.js
    • delete-product.js

What's the code inside the JavaScript files above? For now, we will leave them empty. But we will fill them out on the next several sections of this tutorial.

Output

Our code so far will have almost empty output. It should look like the following.

How To Read JSON Data Using jQuery AJAX?

Show products on first page load

  1. Open "app" folder.
  2. Open "products" folder inside the "app" folder.
  3. Open read-products.js file inside the "products" folder.

The following code will call the showProducts() method on first load of the web page.

The showProducts() will show the list of products in an HTML table. Put the following code inside read-products.js file.

$(document).ready(function(){

    // show list of product on first load
    showProducts();

});

// showProducts() method will be here

Show products on click of a button

The following code will call showProducts() method in click of a button with read-products-button class.

The button can be found in the "create product" and "update product" HTML template. We will see it in the next sections.

Put the following code under the showProducts(); of the previous section.

// when a 'read products' button was clicked
$(document).on('click', '.read-products-button', function(){
	showProducts();
});

Create showProducts() function

Now we will create the showProducts() method. Replace // showProducts() method will be here comment in read-products.js file with the following code.

// function to show list of products
function showProducts(){

}

Get list of products

The following code will contact our API to get the list of products in JSON format. Put the following code after the opening curly brace of the previous section.

// get list of products from the API
$.getJSON("http://localhost/api/product/read.php", function(data){

});

Add "Create Product" button

We have to add a "Create Product" button in the "products list" view. We will make this button work later in this tutorial.

Place the following code after the opening curly brace of the previous section.

// html for listing products
var read_products_html=`
    <!-- when clicked, it will load the create product form -->
    <div id='create-product' class='btn btn-primary pull-right m-b-15px create-product-button'>
        <span class='glyphicon glyphicon-plus'></span> Create Product
    </div>

Build HTML table

We have to start building the HTML table where the list of products will appear.

The following code will build an HTML table with its heading. Place it after the previous section's code.

<!-- start table -->
<table class='table table-bordered table-hover'>

    <!-- creating our table heading -->
    <tr>
        <th class='w-25-pct'>Name</th>
        <th class='w-10-pct'>Price</th>
        <th class='w-15-pct'>Category</th>
        <th class='w-25-pct text-align-center'>Action</th>
    </tr>`;

	// rows will be here

// end table
read_products_html+=`</table>`;

Build table row per record

We will loop through each record returned by the API. In each record, we will create a table row.

Aside from product data, the table row will have the "action" buttons as well. These include the "Read One", "Edit" and "Delete" buttons.

Replace "// rows will be here" comment of the previous section with the following code.

// loop through returned list of data
$.each(data.records, function(key, val) {

    // creating new table row per record
    read_products_html+=`
        <tr>

            <td>` + val.name + `</td>
            <td>$` + val.price + `</td>
            <td>` + val.category_name + `</td>

            <!-- 'action' buttons -->
            <td>
                <!-- read product button -->
                <button class='btn btn-primary m-r-10px read-one-product-button' data-id='` + val.id + `'>
                    <span class='glyphicon glyphicon-eye-open'></span> Read
                </button>

                <!-- edit button -->
                <button class='btn btn-info m-r-10px update-product-button' data-id='` + val.id + `'>
                    <span class='glyphicon glyphicon-edit'></span> Edit
                </button>

                <!-- delete button -->
                <button class='btn btn-danger delete-product-button' data-id='` + val.id + `'>
                    <span class='glyphicon glyphicon-remove'></span> Delete
                </button>
            </td>

        </tr>`;
});

Inject to page content

We have to make the HTML table appear on our webpage. We will do this by injecting the table to the "page-content" div.

Place the following code after the closing "table" tag

// inject to 'page-content' of our app
$("#page-content").html(read_products_html);

5.9 Change page title

The following code will change the "title" seen on the web page and the "title" seen on the browser tab.

Place the following code after the previous section's code.

// chage page title
changePageTitle("Read Products");

Output

After doing all the steps above, output should look like the following.

How To Create or Insert Data Using jQuery AJAX?

Handle "Create Product" Button Click

  1. Open "app" folder.
  2. Open "products" folder inside the "app" folder.
  3. Open create-product.js file inside the "products" folder.

The following code will handle a click of a button. This button should have "create-product-button" class.

Place the following code inside create-product.js file.

$(document).ready(function(){

    // show html form when 'create product' button was clicked
    $(document).on('click', '.create-product-button', function(){
		// categories api call will be here
    });

	// 'create product form' handle will be here
});

Get list of categories from API

We need to get list of categories from the API because we will build the "categories" select field. This is where the user can select the category of the product.

Replace "// categories api call will be here" of the previous section with the following code.

// load list of categories
$.getJSON("http://localhost/api/category/read.php", function(data){

});

Build "categories option" select field

This is where we build the HTML "select" field with "categories" option.

Place the following code after the opening curly brace of the previous section.

// build categories option html
// loop through returned list of data
var categories_options_html=`<select name='category_id' class='form-control'>`;
$.each(data.records, function(key, val){
    categories_options_html+=`<option value='` + val.id + `'>` + val.name + `</option>`;
});
categories_options_html+=`</select>`;

Add "Read Products" button

The "read products" button is needed so that we can go back to the products list.

Place the following code after the previous section's code.

// we have our html form here where product information will be entered
// we used the 'required' html5 property to prevent empty fields
var create_product_html=`

    <!-- 'read products' button to show list of products -->
    <div id='read-products' class='btn btn-primary pull-right m-b-15px read-products-button'>
        <span class='glyphicon glyphicon-list'></span> Read Products
    </div>

Build "Create Product" HTML Form

Now we will build the actual "creat product" HTML form. This is where the user can enter the new product information that will be sent to the server.

Place the following code after the previous section's code.

<!-- 'create product' html form -->
<form id='create-product-form' action='#' method='post' border='0'>
    <table class='table table-hover table-responsive table-bordered'>

        <!-- name field -->
        <tr>
            <td>Name</td>
            <td><input type='text' name='name' class='form-control' required /></td>
        </tr>

        <!-- price field -->
        <tr>
            <td>Price</td>
            <td><input type='number' min='1' name='price' class='form-control' required /></td>
        </tr>

        <!-- description field -->
        <tr>
            <td>Description</td>
            <td><textarea name='description' class='form-control' required></textarea></td>
        </tr>

        <!-- categories 'select' field -->
        <tr>
            <td>Category</td>
            <td>` + categories_options_html + `</td>
        </tr>

        <!-- button to submit form -->
        <tr>
            <td></td>
            <td>
                <button type='submit' class='btn btn-primary'>
                    <span class='glyphicon glyphicon-plus'></span> Create Product
                </button>
            </td>
        </tr>

    </table>
</form>`;

Show "Create Product" form and change page title

We have to make the HTML button and form appear on our web page. We will change the page title as well.

Place the following code after the previous section's code.

// inject html to 'page-content' of our app
$("#page-content").html(create_product_html);

// chage page title
changePageTitle("Create Product");

Handle "create product" form submit

If the "create product" form is submitted, we need a script to handle it.

Find "// 'create product form' handle will be here" and replace it with the following code.

// will run if create product form was submitted
$(document).on('submit', '#create-product-form', function(){
	// form data will be here
});

Get form data

This is how we get data entered in our "create product" HTML form.

Replace "// form data will be here" of the previous section with the following code.

// get form data
var form_data=JSON.stringify($(this).serializeObject());

Now we will send the data to the server.

Place the following code after the previous section's code.

// submit form data to api
$.ajax({
	url: "http://localhost/api/product/create.php",
	type : "POST",
	contentType : 'application/json',
	data : form_data,
	success : function(result) {
		// product was created, go back to products list
		showProducts();
	},
	error: function(xhr, resp, text) {
		// show error to console
		console.log(xhr, resp, text);
	}
});

return false;

Output

Output should look like the following.

How To Read One Data Using jQuery AJAX?

Handle "read one" button click

The "read one" button is seen on the "product list" view. When click, it should show the complete product details.

  1. Open "app" folder.
  2. Inside the "app" folder, open "products" folder.
  3. Inside the "products" folder, open "read-one-product.js" file.

Place the following code inside "read-one-product.js" file.

$(document).ready(function(){

    // handle 'read one' button click
    $(document).on('click', '.read-one-product-button', function(){
		// product ID will be here
    });

});

Get product ID

Our script need to identify the record to be read. We do it by getting the product ID.

Replace "// product ID will be here" of the previous section with the following code.

// get product id
var id = $(this).attr('data-id');

Read one record from API

We will send the product ID to the API. It will return the data based on the given ID.

Place the following code after the previous section's code.

// read product record based on given ID
$.getJSON("http://localhost/api/product/read_one.php?id=" + id, function(data){
	// read products button will be here
});

Add "read products" button

We need the "read products" button so we can go back to the products list.

Replace "// read products button will be here" of the previous section with the following code.

// start html
var read_one_product_html=`

    <!-- when clicked, it will show the product's list -->
    <div id='read-products' class='btn btn-primary pull-right m-b-15px read-products-button'>
        <span class='glyphicon glyphicon-list'></span> Read Products
    </div>

Show record data in HTML table

We will place the product information returned by te API to an HTML table.

Place the following code after the previous section's code.

<!-- product data will be shown in this table -->
<table class='table table-bordered table-hover'>

    <!-- product name -->
    <tr>
        <td class='w-30-pct'>Name</td>
        <td class='w-70-pct'>` + data.name + `</td>
    </tr>

    <!-- product price -->
    <tr>
        <td>Price</td>
        <td>` + data.price + `</td>
    </tr>

    <!-- product description -->
    <tr>
        <td>Description</td>
        <td>` + data.description + `</td>
    </tr>

    <!-- product category name -->
    <tr>
        <td>Category</td>
        <td>` + data.category_name + `</td>
    </tr>

</table>`;

Show "Read One Product" HTML table and change page title

We have to make the HTML button and table appear on our web page. We will change the page title as well.

Place the following code after the previous section's code.

// inject html to 'page-content' of our app
$("#page-content").html(read_one_product_html);

// chage page title
changePageTitle("Create Product");

Output

Output should look like the following.

How To Update Data Using jQuery AJAX?

Handle "udpate product" button click

The "edit" button is seen on the "product list" view. When click, it should show the "update product" form filled-out with product information.

  1. Open "app" folder.
  2. Inside the "app" folder, open "products" folder.
  3. Inside the "products" folder, open "update-product.js" file.

Place the following code inside "update-product.js" file.

$(document).ready(function(){

    // show html form when 'update product' button was clicked
    $(document).on('click', '.update-product-button', function(){
		// product ID will be here
    });

	// 'update product form' submit handle will be here
});

8.2 Get product ID

Our script need to identify the record to be read. We do it by getting the product ID.

Replace "// product ID will be here" of the previous section with the following code.

// get product id
var id = $(this).attr('data-id');

Read product information

To fill out our "update product" HTML form, we need to get product information from the API.

Place the following code after the previous section's code.

// read one record based on given product id
$.getJSON("http://localhost/api/product/read_one.php?id=" + id, function(data){

	// values will be used to fill out our form
	var name = data.name;
	var price = data.price;
	var description = data.description;
	var category_id = data.category_id;
	var category_name = data.category_name;

	// load list of categories will be here
});

Get list of categories

The list of categories is needed for product's category options. Category records will be rendered as options in a "select" HTML input field.

Replace "// load list of categories will be here" of the previous section with the following code.

// load list of categories
$.getJSON("http://localhost/api/category/read.php", function(data){

	// build 'categories option' html
	// loop through returned list of data
        var categories_options_html=`<select name='category_id' class='form-control'>`;

        $.each(data.records, function(key, val){
            // pre-select option is category id is the same
            if(val.id==category_id){ categories_options_html+=`<option value='` + val.id + `' selected>` + val.name + `</option>`; }

            else{ categories_options_html+=`<option value='` + val.id + `'>` + val.name + `</option>`; }
        });
        categories_options_html+=`</select>`;

	// update product html will be here
});

Add "Read Products" button

The "read products" button is needed so that we can go back to the products list.

Replace "// update product html will be here" of the previous section with the following code.

// store 'update product' html to this variable
var update_product_html=`
    <div id='read-products' class='btn btn-primary pull-right m-b-15px read-products-button'>
        <span class='glyphicon glyphicon-list'></span> Read Products
    </div>

Build "Update Product" form

Now we will build the "udpate product" HTML form. This form will be built with an HTML table and the input fields are filled-out with product information.

Place the following code after the previous section's code.

<!-- build 'update product' html form -->
<!-- we used the 'required' html5 property to prevent empty fields -->
<form id='update-product-form' action='#' method='post' border='0'>
    <table class='table table-hover table-responsive table-bordered'>

        <!-- name field -->
        <tr>
            <td>Name</td>
            <td><input value=\"` + name + `\" type='text' name='name' class='form-control' required /></td>
        </tr>

        <!-- price field -->
        <tr>
            <td>Price</td>
            <td><input value=\"` + price + `\" type='number' min='1' name='price' class='form-control' required /></td>
        </tr>

        <!-- description field -->
        <tr>
            <td>Description</td>
            <td><textarea name='description' class='form-control' required>` + description + `</textarea></td>
        </tr>

        <!-- categories 'select' field -->
        <tr>
            <td>Category</td>
            <td>` + categories_options_html + `</td>
        </tr>

        <tr>

            <!-- hidden 'product id' to identify which record to delete -->
            <td><input value=\"` + id + `\" name='id' type='hidden' /></td>

            <!-- button to submit form -->
            <td>
                <button type='submit' class='btn btn-info'>
                    <span class='glyphicon glyphicon-edit'></span> Update Product
                </button>
            </td>

        </tr>

    </table>
</form>`;

Show "Update Product" form and change page title

We need to show our "update product" HTML on our webpage. We will change the page title as well.

Put the following code after the previous section's code.

// inject to 'page-content' of our app
$("#page-content").html(update_product_html);

// chage page title
changePageTitle("Update Product");

Handle "udpate product" form submission

If the "update product" form is submitted, we need a script to handle it.

Find "// 'update product form' submit handle will be here" and replace it with the following code.

// will run if 'create product' form was submitted
$(document).on('submit', '#update-product-form', function(){

	// get form data will be here 

	return false;
});

Get form data

We will get the product information from our "update product" HTML form.

Replace "// get form data will be here" of the previous section with the following code.

// get form data
var form_data=JSON.stringify($(this).serializeObject());

Send form data to server

After getting the form data, we will send the data to our API.

Place the following code after the previous section's code.

// submit form data to api
$.ajax({
	url: "http://localhost/api/product/update.php",
	type : "POST",
	contentType : 'application/json',
	data : form_data,
	success : function(result) {
		// product was created, go back to products list
		showProducts();
	},
	error: function(xhr, resp, text) {
		// show error to console
		console.log(xhr, resp, text);
	}
});

Output

Output should look like the following.

How To Delete Data Using jQuery AJAX?

Handle "Delete Product" button click

The "delete product" button is seen in the "read products" view. When it was clicked, we need to handle it.

  1. Open "app" folder.
  2. Inside the "app" folder, open "products" folder.
  3. Inside the "products" folder, open "delete-product.js" file.

Place the following code inside "delete-product.js" file.

$(document).ready(function(){

    // will run if the delete button was clicked
    $(document).on('click', '.delete-product-button', function(){
		// product id will be here
	});
});

Get product ID

The product ID is needed to identify which record to delete using the API.

Replace "// product id will be here" of the previous section with the following code.

// get the product id
var product_id = $(this).attr('data-id');

Show "delete confirmation" dialog box

This is where we will use the Bootbox.js library. We will show a dialog box with "Are you sure?" message with "Yes" and "No" buttons.

Place the following code after the previous section's code.

// bootbox for good looking 'confirm pop up'
bootbox.confirm({

	message: "<h4>Are you sure?</h4>",
	buttons: {
		confirm: {
			label: '<span class="glyphicon glyphicon-ok"></span> Yes',
			className: 'btn-danger'
		},
		cancel: {
			label: '<span class="glyphicon glyphicon-remove"></span> No',
			className: 'btn-primary'
		}
	},
	callback: function (result) {
		// delete request will be here
	}
});

Delete record using API

If the user clicked "Yes" on the dialog box, a "delete" request will be sent to the API.

Replace "// delete request will be here" of the previous section with the following code.

if(result==true){

	// send delete request to api / remote server
	$.ajax({
		url: "http://localhost/api/product/delete.php",
		type : "POST",
		dataType : 'json',
		data : JSON.stringify({ id: product_id }),
		success : function(result) {

			// re-load list of products
			showProducts();
		},
		error: function(xhr, resp, text) {
			console.log(xhr, resp, text);
		}
	});

}

Output

How To Search Data Using jQuery AJAX?

This feature is part of our LEVEL 2 source code.

Include two JS file in index.html

<!-- products scripts -->
<script src="app/products/products.js"></script>
<script src="app/products/search-product.js"></script>

Create products.js file

The "products.js" file will contain any functions that can be used by other product components like our "read-products.js" or "search-products.js" files.

Open "app" folder. Open "products" folder. Create "products.js" file.

Open the "products.js" file and put the following code.

// product list html
function readProductsTemplate(data, keywords){

    var read_products_html=`
		<!-- search products form -->
		<form id='search-product-form' action='#' method='post'>
		<div class='input-group pull-left w-30-pct'>

			<input type='text' value='` + keywords + `' name='keywords' class='form-control product-search-keywords' placeholder='Search products...' />

			<span class='input-group-btn'>
				<button type='submit' class='btn btn-default' type='button'>
					<span class='glyphicon glyphicon-search'></span>
				</button>
			</span>

		</div>
		</form>

		<!-- when clicked, it will load the create product form -->
		<div id='create-product' class='btn btn-primary pull-right m-b-15px create-product-button'>
			<span class='glyphicon glyphicon-plus'></span> Create Product
		</div>

		<!-- start table -->
		<table class='table table-bordered table-hover'>

			<!-- creating our table heading -->
			<tr>
				<th class='w-25-pct'>Name</th>
				<th class='w-10-pct'>Price</th>
				<th class='w-15-pct'>Category</th>
				<th class='w-25-pct text-align-center'>Action</th>
			</tr>`;

    // loop through returned list of data
    $.each(data.records, function(key, val) {

        // creating new table row per record
        read_products_html+=`<tr>

            <td>` + val.name + `</td>
            <td>$` + val.price + `</td>
            <td>` + val.category_name + `</td>

            <!-- 'action' buttons -->
            <td>
                <!-- read product button -->
                <button class='btn btn-primary m-r-10px read-one-product-button' data-id='` + val.id + `'>
                    <span class='glyphicon glyphicon-eye-open'></span> Read
                </button>

                <!-- edit button -->
                <button class='btn btn-info m-r-10px update-product-button' data-id='` + val.id + `'>
                    <span class='glyphicon glyphicon-edit'></span> Edit
                </button>

                <!-- delete button -->
                <button class='btn btn-danger delete-product-button' data-id='` + val.id + `'>
                    <span class='glyphicon glyphicon-remove'></span> Delete
                </button>
            </td>
        </tr>`;
    });

    // end table
    read_products_html+=`</table>`;

    // inject to 'page-content' of our app
    $("#page-content").html(read_products_html);
}

Create search-product.js file

The "search-product.js" file will contain a code that catches the submission of "search product" form.

Open "app" folder. Open "products" folder. Create "search-products.js" file.

Open the "search-products.js" file and put the following code.

$(document).ready(function(){

    // when a 'search products' button was clicked
    $(document).on('submit', '#search-product-form', function(){

        // get search keywords
        var keywords = $(this).find(":input[name='keywords']").val();

        // get data from the api based on search keywords
        $.getJSON("http://localhost/api/product/search.php?s=" + keywords, function(data){

            // template in products.js
            readProductsTemplate(data, keywords);

            // chage page title
            changePageTitle("Search products: " + keywords);

        });

        // prevent whole page reload
        return false;
    });

});

Change read-products.js

We want the "product list" and "search product" have the same HTML table template. To do this, we will use the readProductsTemplate() function of products.js file.

Open "app" folder. Open "products" folder. Open "read-products.js' file. Change the showProducts() function to the following code.

// function to show list of products
function showProducts(){

    // get list of products from the API
    $.getJSON("http://localhost/api/product/read.php", function(data){

        // html for listing products
        readProductsTemplate(data, "");

        // chage page title
        changePageTitle("Read Products");

    });
}

Output

How To Paginate Data Using jQuery AJAX?

This feature is part of our LEVEL 2 and LEVEL 3 source codes.

Change JSON URL

To make pagination work, we'll have to change the JSON URL. The contents of this new JSON data will include the "paging" node. It looks like the following.

So we will change the JSON URL from:

http://localhost/api/product/read.php

to

http://localhost/api/product/read_paging.php

It means we have to change something on our code. See the change in the next section.

Show products using JSON URL

Open /app/products/read-products.js file. Replace the code with the following.

$(document).ready(function(){

    // show list of product on first load
    showProductsFirstPage();

    // when a 'read products' button was clicked
    $(document).on('click', '.read-products-button', function(){
        showProductsFirstPage();
    });

    // when a 'page' button was clicked
    $(document).on('click', '.pagination li', function(){
        // get json url
        var json_url=$(this).find('a').attr('data-page');

        // show list of products
        showProducts(json_url);
    });

});

function showProductsFirstPage(){
    var json_url="http://localhost/api/product/read_paging.php";
    showProducts(json_url);
}

// function to show list of products
function showProducts(json_url){

    // get list of products from the API
    $.getJSON(json_url, function(data){

        // html for listing products
        readProductsTemplate(data, "");

        // chage page title
        changePageTitle("Read Products");

    });
}

Add Pagination HTML

Open /app/products/products.js file. Find the ending "table" tag and put the following code under it.

// pagination
if(data.paging){
    read_products_html+="<ul class='pagination pull-left margin-zero padding-bottom-2em'>";

        // first page
        if(data.paging.first!=""){
            read_products_html+="<li><a data-page='" + data.paging.first + "'>First Page</a></li>";
        }

        // loop through pages
        $.each(data.paging.pages, function(key, val){
            var active_page=val.current_page=="yes" ? "class='active'" : "";
            read_products_html+="<li " + active_page + "><a data-page='" + val.url + "'>" + val.page + "</a></li>";
        });

        // last page
        if(data.paging.last!=""){
            read_products_html+="<li><a data-page='" + data.paging.last + "'>Last Page</a></li>";
        }
    read_products_html+="</ul>";
}

Output

After making the changes above, run index.html again. Do a hard refresh. You should see the paging buttons like the one below.

How To Run The Source Code?

We highly recommend for you to follow and study our well-detailed, step-by-step tutorial above first. Nothing beats experience when it comes to learning.

But we believe you will learn faster if you'll see the final source code as well. We consider it as your additional guide.

Imagine the value or skill upgrade it can bring you. The additional income you can get from your work, projects or business. The precious time you save. Isn't that what you want?

By now, you need to download our source codes. To do it, use any download buttons in the next few sections below.

Once you downloaded the source codes, here's how you can run it.

  1. Extract the files to your server directory.
  2. Set up the "api" by following the README.txt inside the "api" folder.
  3. Open your browser and run index.html
  4. If you can see the list of "product" records, it means your set up is correct.

Download LEVEL 1 Source Code

FEATURES LEVEL 1
Create product YES
Read product YES
Read one product YES
Update product YES
Delete product YES
Bootstrap UI YES
PHP REST API source code YES
FREE email support for 3 months YES
Source code updates via email YES
$20 - Download now

Download LEVEL 2 Source Code

FEATURES LEVEL 2
All features of LEVEL 1 YES
Search products YES
Pagination of products & search products YES
Create category YES
Read category YES
Read one category YES
Update category YES
Delete category YES
Search categories YES
Pagination of categories & search categories YES
Navigation bar YES
FREE email support for 6 months YES
$40 - Download now

Download LEVEL 3 Source Code

FEATURES LEVEL 3
All features of LEVEL 2 YES
Inline editing of products & categories YES
Export CSV of products & categories YES
Bootstrap tooltip on some products & categories buttons YES
FREE email support for 1 year YES
$50 - Download now

Why download?

Do you need more reasons to download it?

MORE REASONS TO DOWNLOAD THE CODE ALL
Use new skills for your multiple projects YES
Save huge amount of time learning jQuery AJAX YES
Code examples are direct to the point YES
Well explained and commented source code YES
Fast and friendly email support YES
Free source code updates YES

What's Next?

Our next topic is a bit different: How To Display Facebook Page Events on Website using PHP?

Related Tutorials

Please explore more tutorials on our start page. Click here.

Some Notes

Found An Issue?

If you found a problem with this code, please write a comment below. Please be descriptive about your issue. Please provide the error messages, screenshots (or screencast) and your test URL. Thanks!

Before you write a comment, remember to read this guide and our code of conduct.

Subscribe to CodeOfaNinja

We constantly improve CodeOfaNinja. We update our tutorials and source codes. Receive valuable web programming tutorials and updates to your email. Subscribe now!

Enjoy high-quality web programming tutorials.
Subscribe to CodeOfaNinja now for FREE!

Thank You!

Thanks for reading our AJAX CRUD Tutorial Using jQuery, JSON and PHP!

PHP OOP CRUD Tutorial – Step By Step Guide!


Previously, we learned how to create or insert, read, update, and delete database records with our PHP and MySQL CRUD tutorial for beginners. This time, we will learn object-oriented programming with PHP & MySQL.

Overview

Our tutorial for today is about creating a simple database application. We can achieve it with the help of this PHP OOP CRUD tutorial. You can use this knowledge in your current or future projects.

We use Bootstrap so that our application will have a decent UI. If you're not yet familiar with what Bootstrap is, and you want to learn how to use it in few steps, I highly recommend following our Bootstrap tutorial first.

There are so many PHP object-oriented programming tutorials on the web today, they have different examples and implementations. Some might be completely correct, some maybe not.

I'm writing this tutorial with a clear goal: to give the best PHP OOP CRUD tutorial for beginners. I welcome your comments and suggestions to help me achieve this.

We want to learn the correct PHP OOP implementation. There are PHP frameworks such as CakePHP, CodeIgniter, and Laravel that correctly do it.

Those things are one step higher. For now, we will learn object-oriented programming with PHP & MySQL. Working with a PHP framework should be easy after following this tutorial.

Database Table Structure

The files products.sql and categories.sql are also included in the code download, located at the README folder.

Create a database

  • Open your PhpMyAdmin (http://localhost/phpmyadmin)
  • Create a new database.
  • Put php_oop_crud_level_1 as database name.
  • Click "Create" button.

Create products table

In this section, we will create the "products" table (using PhpMyAdmin) on the database we just created.

Here's how to run an SQL statement using PhpMyAdmin.

  • Click php_oop_crud_level_1 database.
  • Click "SQL" tab.
  • Copy the SQL statement below and paste it in the text area.
  • Click the "Go" button.
-- Table structure for table `products`
CREATE TABLE IF NOT EXISTS `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  `description` text NOT NULL,
  `price` int(11) NOT NULL,
  `category_id` int(11) NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=38 ;

Insert products sample data

We have to put some database records.

Run the following SQL statement using your PhpMyAdmin.

-- Dumping data for table `products`
INSERT INTO `products` (`id`, `name`, `description`, `price`, `category_id`, `created`, `modified`) VALUES
(1, 'LG P880 4X HD', 'My first awesome phone!', 336, 3, '2014-06-01 01:12:26', '2014-05-31 17:12:26'),
(2, 'Google Nexus 4', 'The most awesome phone of 2013!', 299, 2, '2014-06-01 01:12:26', '2014-05-31 17:12:26'),
(3, 'Samsung Galaxy S4', 'How about no?', 600, 3, '2014-06-01 01:12:26', '2014-05-31 17:12:26'),
(6, 'Bench Shirt', 'The best shirt!', 29, 1, '2014-06-01 01:12:26', '2014-05-31 02:12:21'),
(7, 'Lenovo Laptop', 'My business partner.', 399, 2, '2014-06-01 01:13:45', '2014-05-31 02:13:39'),
(8, 'Samsung Galaxy Tab 10.1', 'Good tablet.', 259, 2, '2014-06-01 01:14:13', '2014-05-31 02:14:08'),
(9, 'Spalding Watch', 'My sports watch.', 199, 1, '2014-06-01 01:18:36', '2014-05-31 02:18:31'),
(10, 'Sony Smart Watch', 'The coolest smart watch!', 300, 2, '2014-06-06 17:10:01', '2014-06-05 18:09:51'),
(11, 'Huawei Y300', 'For testing purposes.', 100, 2, '2014-06-06 17:11:04', '2014-06-05 18:10:54'),
(12, 'Abercrombie Lake Arnold Shirt', 'Perfect as gift!', 60, 1, '2014-06-06 17:12:21', '2014-06-05 18:12:11'),
(13, 'Abercrombie Allen Brook Shirt', 'Cool red shirt!', 70, 1, '2014-06-06 17:12:59', '2014-06-05 18:12:49'),
(25, 'Abercrombie Allen Anew Shirt', 'Awesome new shirt!', 999, 1, '2014-11-22 18:42:13', '2014-11-21 19:42:13'),
(26, 'Another product', 'Awesome product!', 555, 2, '2014-11-22 19:07:34', '2014-11-21 20:07:34'),
(27, 'Bag', 'Awesome bag for you!', 999, 1, '2014-12-04 21:11:36', '2014-12-03 22:11:36'),
(28, 'Wallet', 'You can absolutely use this one!', 799, 1, '2014-12-04 21:12:03', '2014-12-03 22:12:03'),
(30, 'Wal-mart Shirt', '', 555, 2, '2014-12-13 00:52:29', '2014-12-12 01:52:29'),
(31, 'Amanda Waller Shirt', 'New awesome shirt!', 333, 1, '2014-12-13 00:52:54', '2014-12-12 01:52:54'),
(32, 'Washing Machine Model PTRR', 'Some new product.', 999, 1, '2015-01-08 22:44:15', '2015-01-07 23:44:15');

Create categories table

Categories table are used to store product categories.

Run the following SQL statement using your PhpMyAdmin.

-- Table structure for table `categories`
CREATE TABLE IF NOT EXISTS `categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(256) NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

Insert categories sample data

We are going to have "Fashion", "Electronics" and "Motors" as categories in our project. I got those three category ideas from eBay, haha!

Run the following SQL statement using your PhpMyAdmin.

-- Dumping data for table `categories`
INSERT INTO `categories` (`id`, `name`, `created`, `modified`) VALUES
(1, 'Fashion', '2014-06-01 00:35:07', '2014-05-30 17:34:33'),
(2, 'Electronics', '2014-06-01 00:35:07', '2014-05-30 17:34:33'),
(3, 'Motors', '2014-06-01 00:35:07', '2014-05-30 17:34:54');

Output

In this section, we were able to set up our database using PhpMyAdmin. It should look like the image below.

We don't have a PHP program output yet. Let's continue on the next section to achieve more output.

Create the Layout Files

To reduce some code mess, we will create the layout files with the codes and assets it needs.

Create header layout file

This layout_header.php file will be included at the beginning of the PHP files that will need it. This way, we won't have to write the same header codes every time.

We use the Bootstrap framework to make our project look good. If you're not yet familiar with you, please learn our Bootstrap tutorial here first.

Bootstrap CSS asset will be included inside the head tags.

  • Create php-oop-crud-level-1 folder and open it.
  • Create layout_header.php file.
  • Place the following code.
<!DOCTYPE html>
<html lang="en">
<head>
 
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
 
    <title><?php echo $page_title; ?></title>
 
    <!-- Latest compiled and minified Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
  
    <!-- our custom CSS -->
    <link rel="stylesheet" href="libs/css/custom.css" />
  
</head>
<body>
 
    <!-- container -->
    <div class="container">
 
        <?php
        // show page header
        echo "<div class='page-header'>
                <h1>{$page_title}</h1>
            </div>";
        ?>

Create footer layout file

This layout_footer.php will be included at the end of each PHP files that needs it. This way, we won't have to write the same footer codes every time.

The assets used in this file are:

Let's go on and create the footer layout file.

  • Open php-oop-crud-level-1 folder.
  • Create layout_footer.php file.
  • Place the following code.
    </div>
    <!-- /container -->
 
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
 
<!-- Latest compiled and minified Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  
<!-- bootbox library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"></script>
 
</body>
</html>

Create custom CSS file

This file is used to change any style we want on our web page. It is also used to override the default style given by Bootstrap.

  • Open php-oop-crud-level-1 folder.
  • Create libs folder.
  • Create css folder.
  • Create custom.css file.
  • Place the following code.
.left-margin{
    margin:0 .5em 0 0;
}
 
.right-button-margin{
    margin: 0 0 1em 0;
    overflow: hidden;
}
 
/* some changes in bootstrap modal */
.modal-body {
    padding: 20px 20px 0px 20px !important;
    text-align: center !important;
}
 
.modal-footer{
    text-align: center !important;
}

Output

The layout files we created in this section is meant to be used inside another PHP file. If we try to run the layout files alone, we won't get any meaningful output.

If you run layout_header.php, it will look like this on the browser.

The custom.css file will look like this.

The layout_footer.php is blank. Let's continue on the next section to see a more meaningful output.

Creating record in PHP the OOP Way

Create a file: create_product.php

Go back to php-oop-crud-level-1 folder, create a file with a name create_product.php and put the following code inside it.

<?php
// set page headers
$page_title = "Create Product";
include_once "layout_header.php";
 
// contents will be here
 
// footer
include_once "layout_footer.php";
?>

Create a "Read Products" Button

The following code will render a button. Replace the comments // contents will be here of the previous section with the following.

echo "<div class='right-button-margin'>
        <a href='index.php' class='btn btn-default pull-right'>Read Products</a>
    </div>";
 
?>
<!-- 'create product' html form will be here -->
<?php

Get a Database Connection

We can use it for retrieving categories or saving new product record later. Put the following code before // set page headers comment of create_product.php file.

// include database and object files
include_once 'config/database.php';
include_once 'objects/product.php';
include_once 'objects/category.php';
 
// get database connection
$database = new Database();
$db = $database->getConnection();
 
// pass connection to objects
$product = new Product($db);
$category = new Category($db);

Create the Database Configuration Class

Getting a database connection will not work without this class. This class file will be included in most PHP files of our PHP OOP CRUD Tutorial.

Create a config folder and inside that folder, create a database.php file. Open that file and put the following code.

<?php
class Database{
  
    // specify your own database credentials
    private $host = "localhost";
    private $db_name = "php_oop_crud_level_1";
    private $username = "root";
    private $password = "";
    public $conn;
  
    // get the database connection
    public function getConnection(){
  
        $this->conn = null;
  
        try{
            $this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
        }catch(PDOException $exception){
            echo "Connection error: " . $exception->getMessage();
        }
  
        return $this->conn;
    }
}
?>

Create a Form in create_product.php

The following code will render an HTML form. Open create_product.php file.

Replace <!-- 'create product' html form will be here --> comment with the following code.

<!-- PHP post code will be here -->
 
<!-- HTML form for creating a product -->
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post">
 
    <table class='table table-hover table-responsive table-bordered'>
 
        <tr>
            <td>Name</td>
            <td><input type='text' name='name' class='form-control' /></td>
        </tr>
 
        <tr>
            <td>Price</td>
            <td><input type='text' name='price' class='form-control' /></td>
        </tr>
 
        <tr>
            <td>Description</td>
            <td><textarea name='description' class='form-control'></textarea></td>
        </tr>
 
        <tr>
            <td>Category</td>
            <td>
            <!-- categories from database will be here -->
            </td>
        </tr>
 
        <tr>
            <td></td>
            <td>
                <button type="submit" class="btn btn-primary">Create</button>
            </td>
        </tr>
 
    </table>
</form>

Loop Through the Categories Records to show as Drop-down

The following code will retrieve categories and put it in a "select" drop-down.

Replace <!-- categories from database will be here --> comment of the previous section with the following code.

<?php
// read the product categories from the database
$stmt = $category->read();
 
// put them in a select drop-down
echo "<select class='form-control' name='category_id'>";
    echo "<option>Select category...</option>";
 
    while ($row_category = $stmt->fetch(PDO::FETCH_ASSOC)){
        extract($row_category);
        echo "<option value='{$id}'>{$name}</option>";
    }
 
echo "</select>";
?>

Create the Object Class for Categories

Of course, the previous section won't work without the category object class. Create objects folder. Create category.php file. Place the following code.

<?php
class Category{
 
    // database connection and table name
    private $conn;
    private $table_name = "categories";
 
    // object properties
    public $id;
    public $name;
 
    public function __construct($db){
        $this->conn = $db;
    }
 
    // used by select drop-down list
    function read(){
        //select all data
        $query = "SELECT
                    id, name
                FROM
                    " . $this->table_name . "
                ORDER BY
                    name";  
 
        $stmt = $this->conn->prepare( $query );
        $stmt->execute();
 
        return $stmt;
    }
 
}
?>

Prepare readName() method

It will get the category name instead of showing just an ID. Add the following code inside our category.php, you will see this method used in the next few sections.

// used to read category name by its ID
function readName(){
     
    $query = "SELECT name FROM " . $this->table_name . " WHERE id = ? limit 0,1";
 
    $stmt = $this->conn->prepare( $query );
    $stmt->bindParam(1, $this->id);
    $stmt->execute();
 
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
     
    $this->name = $row['name'];
}

Code when the Form was Submitted

The user will enter the values in the HTML form and when the create (submit) button was clicked, values will be sent via POST request, the code below will save it in the database.

Open create_product.php file. Replace <!-- PHP post code will be here --> comment with the following code.

<?php 
// if the form was submitted - PHP OOP CRUD Tutorial
if($_POST){
 
    // set product property values
    $product->name = $_POST['name'];
    $product->price = $_POST['price'];
    $product->description = $_POST['description'];
    $product->category_id = $_POST['category_id'];
 
    // create the product
    if($product->create()){
        echo "<div class='alert alert-success'>Product was created.</div>";
    }
 
    // if unable to create the product, tell the user
    else{
        echo "<div class='alert alert-danger'>Unable to create product.</div>";
    }
}
?>

Create the Object Class for Products

The previous section will not work without the product object. Open objects folder. Create product.php file. Open that file and put the following code.

<?php
class Product{
 
    // database connection and table name
    private $conn;
    private $table_name = "products";
 
    // object properties
    public $id;
    public $name;
    public $price;
    public $description;
    public $category_id;
    public $timestamp;
 
    public function __construct($db){
        $this->conn = $db;
    }
 
    // create product
    function create(){
 
        //write query
        $query = "INSERT INTO
                    " . $this->table_name . "
                SET
                    name=:name, price=:price, description=:description, category_id=:category_id, created=:created";
 
        $stmt = $this->conn->prepare($query);
 
        // posted values
        $this->name=htmlspecialchars(strip_tags($this->name));
        $this->price=htmlspecialchars(strip_tags($this->price));
        $this->description=htmlspecialchars(strip_tags($this->description));
        $this->category_id=htmlspecialchars(strip_tags($this->category_id));
 
        // to get time-stamp for 'created' field
        $this->timestamp = date('Y-m-d H:i:s');
 
        // bind values 
        $stmt->bindParam(":name", $this->name);
        $stmt->bindParam(":price", $this->price);
        $stmt->bindParam(":description", $this->description);
        $stmt->bindParam(":category_id", $this->category_id);
        $stmt->bindParam(":created", $this->timestamp);
 
        if($stmt->execute()){
            return true;
        }else{
            return false;
        }
 
    }
}
?>

Output

Form to create product.

Categories drop down in the form.

When you fill out the form and clicked the "Create" button.

Changes in the database.

Reading and Paging Record in PHP the OOP Way

In this part of our PHP OOP CRUD tutorial, we will list the records from the database.

Create File: index.php

Create a new file and name it index.php. This file will show the main page of our web app. Put the following code inside it.

<?php
// set page header
$page_title = "Read Products";
include_once "layout_header.php";
 
// contents will be here
 
// set page footer
include_once "layout_footer.php";
?>

Add a "Create Product" button

The following code will render a button. When this button was clicked, it will show us a page where we can create a record. Replace the // contents will be here comments in the previous section with the following code.

echo "<div class='right-button-margin'>
    <a href='create_product.php' class='btn btn-default pull-right'>Create Product</a>
</div>";

Configure Pagination Variables

Pagination is very important if you have thousands of data from the database. Put the following code before the set page header comment of index.php file.

// page given in URL parameter, default page is one
$page = isset($_GET['page']) ? $_GET['page'] : 1;
 
// set number of records per page
$records_per_page = 5;
 
// calculate for the query LIMIT clause
$from_record_num = ($records_per_page * $page) - $records_per_page;
 
// retrieve records here

Retrieve Records from the Database

Now we will retrieve data from the database. Replace // retrieve records here comment of index.php with the following code.

// include database and object files
include_once 'config/database.php';
include_once 'objects/product.php';
include_once 'objects/category.php';
 
// instantiate database and objects
$database = new Database();
$db = $database->getConnection();
 
$product = new Product($db);
$category = new Category($db);
 
// query products
$stmt = $product->readAll($from_record_num, $records_per_page);
$num = $stmt->rowCount();

Add readAll() Method in product.php

Retrieving records in the previous section won't work without this method. Put the following code inside our "product.php" file which is inside the "objects" folder.

function readAll($from_record_num, $records_per_page){
 
    $query = "SELECT
                id, name, description, price, category_id
            FROM
                " . $this->table_name . "
            ORDER BY
                name ASC
            LIMIT
                {$from_record_num}, {$records_per_page}";
 
    $stmt = $this->conn->prepare( $query );
    $stmt->execute();
 
    return $stmt;
}

Display data from the database

This time, we will show the list of records to the user. An HTML table will hold our data. Put the following code after the section 6.2 code.

// display the products if there are any
if($num>0){
 
    echo "<table class='table table-hover table-responsive table-bordered'>";
        echo "<tr>";
            echo "<th>Product</th>";
            echo "<th>Price</th>";
            echo "<th>Description</th>";
            echo "<th>Category</th>";
            echo "<th>Actions</th>";
        echo "</tr>";
 
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
 
            extract($row);
 
            echo "<tr>";
                echo "<td>{$name}</td>";
                echo "<td>{$price}</td>";
                echo "<td>{$description}</td>";
                echo "<td>";
                    $category->id = $category_id;
                    $category->readName();
                    echo $category->name;
                echo "</td>";
 
                echo "<td>";
                    // read one, edit and delete button will be here
                echo "</td>";
 
            echo "</tr>";
 
        }
 
    echo "</table>";
 
    // paging buttons will be here
}
 
// tell the user there are no products
else{
    echo "<div class='alert alert-info'>No products found.</div>";
}

Put the Read, Edit and Delete Action Buttons

The following code will render three buttons: Read, Edit and Delete button.

Inside the "while" loop of the previous section, there is a comment "read one, edit and delete button will be here", replace that with the following code.

// read, edit and delete buttons
echo "<a href='read_one.php?id={$id}' class='btn btn-primary left-margin'>
    <span class='glyphicon glyphicon-list'></span> Read
</a>
 
<a href='update_product.php?id={$id}' class='btn btn-info left-margin'>
    <span class='glyphicon glyphicon-edit'></span> Edit
</a>
 
<a delete-id='{$id}' class='btn btn-danger delete-object'>
    <span class='glyphicon glyphicon-remove'></span> Delete
</a>";

Create paging.php for Paging Buttons

The following code will show our pagination buttons. Create a new file and name it "paging.php". Open that file and put the following code.

<?php
echo "<ul class='pagination'>";
 
// button for first page
if($page>1){
    echo "<li><a href='{$page_url}' title='Go to the first page.'>";
        echo "First";
    echo "</a></li>";
}
 
// calculate total pages
$total_pages = ceil($total_rows / $records_per_page);
 
// range of links to show
$range = 2;
 
// display links to 'range of pages' around 'current page'
$initial_num = $page - $range;
$condition_limit_num = ($page + $range)  + 1;
 
for ($x=$initial_num; $x<$condition_limit_num; $x++) {
 
    // be sure '$x is greater than 0' AND 'less than or equal to the $total_pages'
    if (($x > 0) && ($x <= $total_pages)) {
 
        // current page
        if ($x == $page) {
            echo "<li class='active'><a href=\"#\">$x <span class=\"sr-only\">(current)</span></a></li>";
        } 
 
        // not current page
        else {
            echo "<li><a href='{$page_url}page=$x'>$x</a></li>";
        }
    }
}
 
// button for last page
if($page<$total_pages){
    echo "<li><a href='" .$page_url. "page={$total_pages}' title='Last page is {$total_pages}.'>";
        echo "Last";
    echo "</a></li>";
}
 
echo "</ul>";
?>

Add the countAll() method in objects/product.php

The following code will be used to count the total number of records in the database. This will be used for pagination.

Open your product.php file which is inside the "objects" folder. Add the following method in the class.

// used for paging products
public function countAll(){
 
    $query = "SELECT id FROM " . $this->table_name . "";
 
    $stmt = $this->conn->prepare( $query );
    $stmt->execute();
 
    $num = $stmt->rowCount();
 
    return $num;
}

Include paging.php in index.php

The following code will show our pagination buttons under our records list. Put the following code after the closing "table" tag of section 6.6 above.

// the page where this paging is used
$page_url = "index.php?";
 
// count all products in the database to calculate total pages
$total_rows = $product->countAll();
 
// paging buttons here
include_once 'paging.php';

Output

Run http://localhost/php-oop-crud-level-1/index.php on your browser, you should see something like the image below.

List of records, page 1.

List of records, page 2.

Updating Record in PHP the OOP Way

I know our PHP OOP CRUD tutorial is kinda long. Please take a break or drink some coffee first!

Create File: update_product.php

Create update_product.php file, open that file and put the following code.

<?php
// retrieve one product will be here
 
// set page header
$page_title = "Update Product";
include_once "layout_header.php";
 
// contents will be here
 
// set page footer
include_once "layout_footer.php";
?>

Create a "Read Products" Button

The following code will render a button. This button, when clicked, will let us go back to the records list. Replace the previous section's "contents will be here" comments with the following code.

echo "<div class='right-button-margin'>
          <a href='index.php' class='btn btn-default pull-right'>Read Products</a>
     </div>";
 
?>
<!-- 'update product' form will be here -->

Retrieve One Product Information Based on the Given ID.

The following code will retrieve data that will populate our HTML form. This is important because this will let the user know what exactly the record he is updating.

Open update_product.php file. Replace "// retrieve one product will be here" comment with the following code.

// get ID of the product to be edited
$id = isset($_GET['id']) ? $_GET['id'] : die('ERROR: missing ID.');
 
// include database and object files
include_once 'config/database.php';
include_once 'objects/product.php';
include_once 'objects/category.php';
 
// get database connection
$database = new Database();
$db = $database->getConnection();
 
// prepare objects
$product = new Product($db);
$category = new Category($db);
 
// set ID property of product to be edited
$product->id = $id;
 
// read the details of product to be edited
$product->readOne();

Add readOne() method in the Product Object Class.

The readOne() method used in the previous section will not work without the following code inside /objects/product.php file.

function readOne(){
 
    $query = "SELECT
                name, price, description, category_id
            FROM
                " . $this->table_name . "
            WHERE
                id = ?
            LIMIT
                0,1";
 
    $stmt = $this->conn->prepare( $query );
    $stmt->bindParam(1, $this->id);
    $stmt->execute();
 
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 
    $this->name = $row['name'];
    $this->price = $row['price'];
    $this->description = $row['description'];
    $this->category_id = $row['category_id'];
}

Put the Values in the Form.

Now we can put the latest values to each form elements. Replace "<!-- 'update product' form will be here -->" comment of update_product.php with the following code.

<!-- post code will be here -->
 
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"] . "?id={$id}");?>" method="post">
    <table class='table table-hover table-responsive table-bordered'>
 
        <tr>
            <td>Name</td>
            <td><input type='text' name='name' value='<?php echo $product->name; ?>' class='form-control' /></td>
        </tr>
 
        <tr>
            <td>Price</td>
            <td><input type='text' name='price' value='<?php echo $product->price; ?>' class='form-control' /></td>
        </tr>
 
        <tr>
            <td>Description</td>
            <td><textarea name='description' class='form-control'><?php echo $product->description; ?></textarea></td>
        </tr>
 
        <tr>
            <td>Category</td>
            <td>
                <!-- categories select drop-down will be here -->
            </td>
        </tr>
 
        <tr>
            <td></td>
            <td>
                <button type="submit" class="btn btn-primary">Update</button>
            </td>
        </tr>
 
    </table>
</form>

Loop Through the Categories Records to show as Drop-down

The following code will list the categories in a drop-down.

Notice that we put "if($product->category_id==$category_id){..." inside the while loop. This is to pre-select the option of the current record.

Replace the previous section's comments "categories select drop-down will be here" with the following code.

<?php
$stmt = $category->read();
 
// put them in a select drop-down
echo "<select class='form-control' name='category_id'>";
 
    echo "<option>Please select...</option>";
    while ($row_category = $stmt->fetch(PDO::FETCH_ASSOC)){
        $category_id=$row_category['id'];
        $category_name = $row_category['name'];
 
        // current category of the product must be selected
        if($product->category_id==$category_id){
            echo "<option value='$category_id' selected>";
        }else{
            echo "<option value='$category_id'>";
        }
 
        echo "$category_name</option>";
    }
echo "</select>";
?>

Code When Form was Submitted

The following code will assign the "posted" values to the object properties. Once assigned, it will update the database with those values using the update() method.

Open update_product.php file. Replace "<!-- post code will be here -->" comment with the following code.

<?php 
// if the form was submitted
if($_POST){
 
    // set product property values
    $product->name = $_POST['name'];
    $product->price = $_POST['price'];
    $product->description = $_POST['description'];
    $product->category_id = $_POST['category_id'];
 
    // update the product
    if($product->update()){
        echo "<div class='alert alert-success alert-dismissable'>";
            echo "Product was updated.";
        echo "</div>";
    }
 
    // if unable to update the product, tell the user
    else{
        echo "<div class='alert alert-danger alert-dismissable'>";
            echo "Unable to update product.";
        echo "</div>";
    }
}
?>

Update Code in the Product Class

The following code will make the previous section's "$product->update()" method work. Open our "product.php" which is inside the "objects" folder and add the following code.

function update(){
 
    $query = "UPDATE
                " . $this->table_name . "
            SET
                name = :name,
                price = :price,
                description = :description,
                category_id  = :category_id
            WHERE
                id = :id";
 
    $stmt = $this->conn->prepare($query);
 
    // posted values
    $this->name=htmlspecialchars(strip_tags($this->name));
    $this->price=htmlspecialchars(strip_tags($this->price));
    $this->description=htmlspecialchars(strip_tags($this->description));
    $this->category_id=htmlspecialchars(strip_tags($this->category_id));
    $this->id=htmlspecialchars(strip_tags($this->id));
 
    // bind parameters
    $stmt->bindParam(':name', $this->name);
    $stmt->bindParam(':price', $this->price);
    $stmt->bindParam(':description', $this->description);
    $stmt->bindParam(':category_id', $this->category_id);
    $stmt->bindParam(':id', $this->id);
 
    // execute the query
    if($stmt->execute()){
        return true;
    }
 
    return false;
     
}

Output

Click any "Edit" button in the index page. The update record form should look like the following.

When you submit the form, a message will be shown.

A record was changed in the database.

Read One Record in PHP the OOP Way

We previously made the code for "update record", this section for reading one record from a database will be easier to do.

Create read_one.php file

This is the page where the data of a single record will be displayed. Create a new file and name it "read_one.php", open that file and put the following code.

<?php
// set page headers
$page_title = "Read One Product";
include_once "layout_header.php";
 
// read products button
echo "<div class='right-button-margin'>";
    echo "<a href='index.php' class='btn btn-primary pull-right'>";
        echo "<span class='glyphicon glyphicon-list'></span> Read Products";
    echo "</a>";
echo "</div>";
 
// set footer
include_once "layout_footer.php";
?>

Read one record based on given record ID

The following code will read a single record from the database. Put the following code before the "set page headers" comments of the previous section.

// get ID of the product to be read
$id = isset($_GET['id']) ? $_GET['id'] : die('ERROR: missing ID.');
 
// include database and object files
include_once 'config/database.php';
include_once 'objects/product.php';
include_once 'objects/category.php';
 
// get database connection
$database = new Database();
$db = $database->getConnection();
 
// prepare objects
$product = new Product($db);
$category = new Category($db);
 
// set ID property of product to be read
$product->id = $id;
 
// read the details of product to be read
$product->readOne();

Display record on HTML table

This time, we will display the record details on an HTML table. Put the following code under the closing "div" tag of "Read Products" button.

// HTML table for displaying a product details
echo "<table class='table table-hover table-responsive table-bordered'>";
 
    echo "<tr>";
        echo "<td>Name</td>";
        echo "<td>{$product->name}</td>";
    echo "</tr>";
 
    echo "<tr>";
        echo "<td>Price</td>";
        echo "<td>${$product->price}</td>";
    echo "</tr>";
 
    echo "<tr>";
        echo "<td>Description</td>";
        echo "<td>{$product->description}</td>";
    echo "</tr>";
 
    echo "<tr>";
        echo "<td>Category</td>";
        echo "<td>";
            // display category name
            $category->id=$product->category_id;
            $category->readName();
            echo $category->name;
        echo "</td>";
    echo "</tr>";
 
echo "</table>";

Output

Click any "Read" button in the index page, you should see something like the image below.

Deleting Record in PHP the OOP Way

This is the last coding part of our PHP OOP CRUD Tutorial. Enjoy every code!

Put this JavaScript code in layout_footer.php

Put the following JavaScript code before the closing "body" tag in layout_footer.php file. We used Bootbox.js to make a Bootstrap-style confirm dialog box.

<script>
// JavaScript for deleting product
$(document).on('click', '.delete-object', function(){
 
    var id = $(this).attr('delete-id');
 
    bootbox.confirm({
        message: "<h4>Are you sure?</h4>",
        buttons: {
            confirm: {
                label: '<span class="glyphicon glyphicon-ok"></span> Yes',
                className: 'btn-danger'
            },
            cancel: {
                label: '<span class="glyphicon glyphicon-remove"></span> No',
                className: 'btn-primary'
            }
        },
        callback: function (result) {
 
            if(result==true){
                $.post('delete_product.php', {
                    object_id: id
                }, function(data){
                    location.reload();
                }).fail(function() {
                    alert('Unable to delete.');
                });
            }
        }
    });
 
    return false;
});
</script>

Create delete_product.php

Create a new file and name it "delete_product.php". This file accepts the ID posted by the JavaScript code in the previous section. A record will be deleted from the database based on posted ID.

Open delete_product.php and put the following code.

<?php
// check if value was posted
if($_POST){
 
    // include database and object file
    include_once 'config/database.php';
    include_once 'objects/product.php';
 
    // get database connection
    $database = new Database();
    $db = $database->getConnection();
 
    // prepare product object
    $product = new Product($db);
     
    // set product id to be deleted
    $product->id = $_POST['object_id'];
     
    // delete the product
    if($product->delete()){
        echo "Object was deleted.";
    }
     
    // if unable to delete the product
    else{
        echo "Unable to delete object.";
    }
}
?>

Delete Code in Product Class

The previous section will not work with the "delete()" method in the product object. Open "product.php" which is inside the "objects" folder and put the following code.

// delete the product
function delete(){
 
    $query = "DELETE FROM " . $this->table_name . " WHERE id = ?";
     
    $stmt = $this->conn->prepare($query);
    $stmt->bindParam(1, $this->id);
 
    if($result = $stmt->execute()){
        return true;
    }else{
        return false;
    }
}

Output

Click any "Delete" button in the index page. A pop up confirmation will be shown.

If the user clicks "OK" the record will be deleted and gone in the table.

A record was deleted in the database.

Search Records in PHP the OOP Way

We'll continue by adding the search feature. This will answer the question: How to search data from database in php? This is a very useful feature because you enable your users to easily search a certain data from our MySQL database.

Please note that this is a bonus section. The code in this section is not included in our LEVEL 1 source code download.

Change index.php

We have to change index.php because we are adding a “search” feature and we want our code to be short. Our index.php will now look like the following code.

<?php
// core.php holds pagination variables
include_once 'config/core.php';
 
// include database and object files
include_once 'config/database.php';
include_once 'objects/product.php';
include_once 'objects/category.php';
 
// instantiate database and product object
$database = new Database();
$db = $database->getConnection();
 
$product = new Product($db);
$category = new Category($db);
 
$page_title = "Read Products";
include_once "layout_header.php";
 
// query products
$stmt = $product->readAll($from_record_num, $records_per_page);
 
// specify the page where paging is used
$page_url = "index.php?";
 
// count total rows - used for pagination
$total_rows=$product->countAll();
 
// read_template.php controls how the product list will be rendered
include_once "read_template.php";
 
// layout_footer.php holds our javascript and closing html tags
include_once "layout_footer.php";
?>

Create read_template.php

Why do we need this template? We need it because exactly the same code can be used by index.php and search.php for displaying a list of records. Using a template means lesser code.

This template holds our search form as well.

<?php
// search form
echo "<form role='search' action='search.php'>";
    echo "<div class='input-group col-md-3 pull-left margin-right-1em'>";
        $search_value=isset($search_term) ? "value='{$search_term}'" : "";
        echo "<input type='text' class='form-control' placeholder='Type product name or description...' name='s' id='srch-term' required {$search_value} />";
        echo "<div class='input-group-btn'>";
            echo "<button class='btn btn-primary' type='submit'><i class='glyphicon glyphicon-search'></i></button>";
        echo "</div>";
    echo "</div>";
echo "</form>";
 
// create product button
echo "<div class='right-button-margin'>";
    echo "<a href='create_product.php' class='btn btn-primary pull-right'>";
        echo "<span class='glyphicon glyphicon-plus'></span> Create Product";
    echo "</a>";
echo "</div>";
 
// display the products if there are any
if($total_rows>0){
 
    echo "<table class='table table-hover table-responsive table-bordered'>";
        echo "<tr>";
            echo "<th>Product</th>";
            echo "<th>Price</th>";
            echo "<th>Description</th>";
            echo "<th>Category</th>";
            echo "<th>Actions</th>";
        echo "</tr>";
 
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
 
            extract($row);
 
            echo "<tr>";
                echo "<td>{$name}</td>";
                echo "<td>{$price}</td>";
                echo "<td>{$description}</td>";
                echo "<td>";
                    $category->id = $category_id;
                    $category->readName();
                    echo $category->name;
                echo "</td>";
 
                echo "<td>";
 
                    // read product button
                    echo "<a href='read_one.php?id={$id}' class='btn btn-primary left-margin'>";
                        echo "<span class='glyphicon glyphicon-list'></span> Read";
                    echo "</a>";
 
                    // edit product button
                    echo "<a href='update_product.php?id={$id}' class='btn btn-info left-margin'>";
                        echo "<span class='glyphicon glyphicon-edit'></span> Edit";
                    echo "</a>";
 
                    // delete product button
                    echo "<a delete-id='{$id}' class='btn btn-danger delete-object'>";
                        echo "<span class='glyphicon glyphicon-remove'></span> Delete";
                    echo "</a>";
 
                echo "</td>";
 
            echo "</tr>";
 
        }
 
    echo "</table>";
 
    // paging buttons
    include_once 'paging.php';
}
 
// tell the user there are no products
else{
    echo "<div class='alert alert-danger'>No products found.</div>";
}
?>

Create core.php in "config" folder

Create a new folder and name it "config". Inside that folder, create a new file and name it "core.php".

This file will hold our pagination variables. Using a core.php file is a good practice, it can be used to hold other configuration values that you might need in the future.

Open core.php and put the following code.

<?php
// page given in URL parameter, default page is one
$page = isset($_GET['page']) ? $_GET['page'] : 1; 
 
// set number of records per page
$records_per_page = 5;
 
// calculate for the query LIMIT clause
$from_record_num = ($records_per_page * $page) - $records_per_page;
?>

Change paging.php code

The new paging.php code will look like the following.

<?php
echo "<ul class=\"pagination\">";
 
// button for first page
if($page>1){
    echo "<li><a href='{$page_url}' title='Go to the first page.'>";
        echo "First Page";
    echo "</a></li>";
}
 
// count all products in the database to calculate total pages
$total_pages = ceil($total_rows / $records_per_page);
 
// range of links to show
$range = 2;
 
// display links to 'range of pages' around 'current page'
$initial_num = $page - $range;
$condition_limit_num = ($page + $range)  + 1;
 
for ($x=$initial_num; $x<$condition_limit_num; $x++) {
 
    // be sure '$x is greater than 0' AND 'less than or equal to the $total_pages'
    if (($x > 0) && ($x <= $total_pages)) {
 
        // current page
        if ($x == $page) {
            echo "<li class='active'><a href=\"#\">$x <span class=\"sr-only\">(current)</span></a></li>";
        }
 
        // not current page
        else {
            echo "<li><a href='{$page_url}page=$x'>$x</a></li>";
        }
    }
}
 
// button for last page
if($page<$total_pages){
    echo "<li><a href='" .$page_url . "page={$total_pages}' title='Last page is {$total_pages}.'>";
        echo "Last Page";
    echo "</a></li>";
}
 
echo "</ul>";
?>

Include core.php and read_template.php

The core.php file will be included at the beginning of index.php file. The read_template.php will be included before the layout_footer.php inclusion. The new index.php will look like the following code

<?php
// core.php holds pagination variables
include_once 'config/core.php';
 
// include database and object files
include_once 'config/database.php';
include_once 'objects/product.php';
include_once 'objects/category.php';
 
// instantiate database and product object
$database = new Database();
$db = $database->getConnection();
 
$product = new Product($db);
$category = new Category($db);
 
$page_title = "Read Products";
include_once "layout_header.php";
 
// query products
$stmt = $product->readAll($from_record_num, $records_per_page);
 
// specify the page where paging is used
$page_url = "index.php?";
 
// count total rows - used for pagination
$total_rows=$product->countAll();
 
// read_template.php controls how the product list will be rendered
include_once "read_template.php";
 
// layout_footer.php holds our javascript and closing html tags
include_once "layout_footer.php";
?>

Create search.php

This is the most important file of this section. This file will display the records based on a user's search term.

Create a new file and name it "search.php". Open that file and put the following code.

<?php
// core.php holds pagination variables
include_once 'config/core.php';
 
// include database and object files
include_once 'config/database.php';
include_once 'objects/product.php';
include_once 'objects/category.php';
 
// instantiate database and product object
$database = new Database();
$db = $database->getConnection();
 
$product = new Product($db);
$category = new Category($db);
 
// get search term
$search_term=isset($_GET['s']) ? $_GET['s'] : '';
 
$page_title = "You searched for \"{$search_term}\"";
include_once "layout_header.php";
 
// query products
$stmt = $product->search($search_term, $from_record_num, $records_per_page);
 
// specify the page where paging is used
$page_url="search.php?s={$search_term}&";
 
// count total rows - used for pagination
$total_rows=$product->countAll_BySearch($search_term);
 
// read_template.php controls how the product list will be rendered
include_once "read_template.php";
 
// layout_footer.php holds our javascript and closing html tags
include_once "layout_footer.php";
?>

Add search() and countAll_BySearch() methods

Open "product.php" file which is inside the "objects" folder. Add the following methods in the class.

// read products by search term
public function search($search_term, $from_record_num, $records_per_page){
 
    // select query
    $query = "SELECT
                c.name as category_name, p.id, p.name, p.description, p.price, p.category_id, p.created
            FROM
                " . $this->table_name . " p
                LEFT JOIN
                    categories c
                        ON p.category_id = c.id
            WHERE
                p.name LIKE ? OR p.description LIKE ?
            ORDER BY
                p.name ASC
            LIMIT
                ?, ?";
 
    // prepare query statement
    $stmt = $this->conn->prepare( $query );
 
    // bind variable values
    $search_term = "%{$search_term}%";
    $stmt->bindParam(1, $search_term);
    $stmt->bindParam(2, $search_term);
    $stmt->bindParam(3, $from_record_num, PDO::PARAM_INT);
    $stmt->bindParam(4, $records_per_page, PDO::PARAM_INT);
 
    // execute query
    $stmt->execute();
 
    // return values from database
    return $stmt;
}
 
public function countAll_BySearch($search_term){
 
    // select query
    $query = "SELECT
                COUNT(*) as total_rows
            FROM
                " . $this->table_name . " p 
            WHERE
                p.name LIKE ? OR p.description LIKE ?";
 
    // prepare query statement
    $stmt = $this->conn->prepare( $query );
 
    // bind variable values
    $search_term = "%{$search_term}%";
    $stmt->bindParam(1, $search_term);
    $stmt->bindParam(2, $search_term);
 
    $stmt->execute();
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 
    return $row['total_rows'];
}

Output

php-mysql-oop-crud-tutorial

File Upload in PHP the OOP Way

In this section, we will add a "file upload" feature. This feature is included in the LEVEL 2 source code download.

Change HTML form

Open create_product.php and find the "form" tag. Change that line to the following code. The "enctype" enables the form to submit a file to the server.

<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post" enctype="multipart/form-data">

On the same HTML table, find the closing "tr" tag of the "Category" field. Add the following code. This adds an input field where the user can browse the file he wants to upload.

<tr>
    <td>Photo</td>
    <td><input type="file" name="image" /></td>
</tr>

Set value of "image" field

Open create_product.php and add the new "image" field. The value will be the file name of the submitted file. We used the built-in sha1_file() function the make the file name unique.

Open create_product.php file. Place the following code under $product->category_id = $_POST['category_id']; code.

$image=!empty($_FILES["image"]["name"])
        ? sha1_file($_FILES['image']['tmp_name']) . "-" . basename($_FILES["image"]["name"]) : "";
$product->image = $image;

Change create() method

Open "objects" folder and open the "product.php" file inside it. Find the "create()" method.

Add the "image" field by changing the query to:

// insert query
$query = "INSERT INTO " . $this->table_name . "
            SET name=:name, price=:price, description=:description,
                category_id=:category_id, image=:image, created=:created";

On the sanitize section, it will be:

$this->image=htmlspecialchars(strip_tags($this->image));

Then bind the value.

$stmt->bindParam(":image", $this->image);

Add the "image" property at the top of the class, maybe after public $category_id;

public $image;

Using the PhpMyAdmin, add an "image" field in the products table. Set the type to VARCHAR with 512 in length.

Call uploadPhoto() method

Open create_product.php and find this line.

// product was created in database
echo "<div class='alert alert-success'>Product was created.</div>";

Put the following code under the code above. This will call the uploadPhoto() method that will try to upload the file to server.

// try to upload the submitted file
// uploadPhoto() method will return an error message, if any.
echo $product->uploadPhoto();

Add uploadPhoto() method

The previous section will not work without the complete code of uploadPhoto() method.

Open "objects" folder and open the "product.php" file inside it. Add the following method inside the class.

// will upload image file to server
function uploadPhoto(){
 
    $result_message="";
 
    // now, if image is not empty, try to upload the image
    if($this->image){
 
        // sha1_file() function is used to make a unique file name
        $target_directory = "uploads/";
        $target_file = $target_directory . $this->image;
        $file_type = pathinfo($target_file, PATHINFO_EXTENSION);
 
        // error message is empty
        $file_upload_error_messages="";
 
    }
 
    return $result_message;
}

Validate submitted file

Now we will validate the submitted file by:

  • Identifying if it's a real or fake image.
  • Limit the allowed file types.
  • Prevent multiple file on the server.
  • Deny uploading files with large file size.
  • Making sure the "uploads" directory exists.

Add the following code after $file_upload_error_messages=""; of the previous section.

// make sure that file is a real image
$check = getimagesize($_FILES["image"]["tmp_name"]);
if($check!==false){
    // submitted file is an image
}else{
    $file_upload_error_messages.="<div>Submitted file is not an image.</div>";
}
 
// make sure certain file types are allowed
$allowed_file_types=array("jpg", "jpeg", "png", "gif");
if(!in_array($file_type, $allowed_file_types)){
    $file_upload_error_messages.="<div>Only JPG, JPEG, PNG, GIF files are allowed.</div>";
}
 
// make sure file does not exist
if(file_exists($target_file)){
    $file_upload_error_messages.="<div>Image already exists. Try to change file name.</div>";
}
 
// make sure submitted file is not too large, can't be larger than 1 MB
if($_FILES['image']['size'] > (1024000)){
    $file_upload_error_messages.="<div>Image must be less than 1 MB in size.</div>";
}
 
// make sure the 'uploads' folder exists
// if not, create it
if(!is_dir($target_directory)){
    mkdir($target_directory, 0777, true);
}

Return error messages

If the file is valid, we will upload the file to server. Specifically, in the "uploads" folder. If there's any error, we will return it to be shown to the user.

Place the following code after the previous section's code.

// if $file_upload_error_messages is still empty
if(empty($file_upload_error_messages)){
    // it means there are no errors, so try to upload the file
    if(move_uploaded_file($_FILES["image"]["tmp_name"], $target_file)){
        // it means photo was uploaded
    }else{
        $result_message.="<div class='alert alert-danger'>";
            $result_message.="<div>Unable to upload photo.</div>";
            $result_message.="<div>Update the record to upload photo.</div>";
        $result_message.="</div>";
    }
}
 
// if $file_upload_error_messages is NOT empty
else{
    // it means there are some errors, so show them to user
    $result_message.="<div class='alert alert-danger'>";
        $result_message.="{$file_upload_error_messages}";
        $result_message.="<div>Update the record to upload photo.</div>";
    $result_message.="</div>";
}

Show uploaded image file

Open "objects" folder and open "product.php" file. Find readOne() method. Add the "image" field in the method. The new method should look like the following.

function readOne(){
 
    $query = "SELECT name, price, description, category_id, image
        FROM " . $this->table_name . "
        WHERE id = ?
        LIMIT 0,1";
 
    $stmt = $this->conn->prepare( $query );
    $stmt->bindParam(1, $this->id);
    $stmt->execute();
 
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 
    $this->name = $row['name'];
    $this->price = $row['price'];
    $this->description = $row['description'];
    $this->category_id = $row['category_id'];
    $this->image = $row['image'];
}

Open read_one.php file and find the closing "tr" tag of the "Category" field in the HTML table. Add the following code. This will show the uploaded image.

echo "<tr>";
    echo "<td>Image</td>";
    echo "<td>";
        echo $product->image ? "<img src='uploads/{$product->image}' style='width:300px;' />" : "No image found.";
    echo "</td>";
echo "</tr>";

Output

Click the "Create" button, you will see something like the image below.

When you submitted the form, it will show a message prompt.

If you tried to upload an invalid image file, for example a PDF file. It will show an error message.

If you click the "Read" button of a record with an image, it will look like the following.

If the record has no image, it will say "No image found." message.

Download source codes

Download LEVEL 1 Source Code

FEATURES LEVEL 1
Object Oriented Programming Source Code YES
PDO extension used YES
Create product YES
Read product YES
Update product YES
Delete product YES
Price display with dollar sign YES
Pagination YES
Bootstrap UI YES
SQL file in "dev" folder YES
$20 - Download now

Download LEVEL 2 Source Code

FEATURES LEVEL 2
All features of LEVEL 1 above YES
HTML5 (font-end) validation for create product YES
HTML5 (font-end) validation for update product YES
Category selection for create and update product. YES
Buttons with Glyphicons YES
Search products by name or description YES
HTML5 (font-end) validation for search product YES
Pagination in search YES
Allow user to input page number (read and search list) YES
Export / download records to CSV YES
Price display with dollar sign, comma and decimal point YES
Multiple delete YES
File upload field when creating or updating record YES
$40 - Download now

Download LEVEL 3 Source Code

FEATURES LEVEL 3
All features of LEVEL 1 and 2 above YES
Bootstrap navigation bar YES
Select category in navigation YES
Higlight category in navigation YES
Create category YES
Read category YES
Update category YES
Delete category YES
View products by category YES
Pagination for category YES
Search category YES
Pagination for category search YES
Server side validation for create product & category YES
Server side validation for update product & category YES
Sorting by fields YES
Pagination for sorting by fields YES
jQuery UI enabled YES
Search product by date range - record date created YES
Pagination for earch product by date range YES
jQuery UI calendar for picking date YES
$50 - Download now

How To Run The Source Codes?

We highly recommend for you to follow and study our well-detailed, step-by-step tutorial above first. Nothing beats experience when it comes to learning.

But we believe you will learn faster if you’ll see the final source code as well. We consider it as your additional guide.

Imagine the value or skill upgrade it can bring you. The additional income you can get from your work, projects or business. The precious time you save. Isn’t that what you want?

By now, you need to download our source codes. To do it, use any download buttons in the next few sections below.

Once you downloaded the source codes, here’s how you can run it.

  1. Extract the files to your server directory.
  2. Create your database using PhpMyAdmin, database name is "php_oop_crud_level_3" *
  3. Import the SQL file called "php_oop_crud_level_3.sql" located in the "dev" folder.
  4. You run index.php file. For example: http://localhost/php-oop-crud-level-3/index.php

* Database name and SQL file is different for LEVEL 1 and 2 source codes.

Why download the source codes?

Do you need more reasons to download it?

MORE REASONS TO DOWNLOAD THE CODE ALL
Use new skills for your multiple projects YES
Save huge amount of time learning Bootstrap and PHP YES
Code examples are direct to the point YES
Well explained and commented source code YES
Fast and friendly email support YES
Free source code updates YES

What's Next?

I hope you learned a lot from our PHP OOP CRUD Tutorial! Learning PHP Object Oriented Programming is fun and it can dramatically improve your career.

Up next: You have two choices.

A. Learn our PHP Login Script with Session Tutorial – Step by Step Guide! - Let's put our PHP OOP CRUD knowledge to work by building a simple PHP login script.

B. Learn How to create a simple REST API in PHP - Step by Step Guide! - this is required before we go to our JavaScript programming tutorials.

Related Tutorials

Please explore more tutorials on our start page. Click here.

Notes

Found An Issue?

If you found a problem with this code, please write a comment below. Please be descriptive about your issue. Please provide the error messages, screenshots (or screencast) and your test URL. Thanks!

Before you write a comment, remember to read this guide and our code of conduct.

Subscribe to CodeOfaNinja

We constantly improve CodeOfaNinja. We update our tutorials and source codes. Receive valuable web programming tutorials and updates to your email. Subscribe now!

Enjoy high-quality web programming tutorials.
Subscribe to CodeOfaNinja now for FREE!

Thank You!

Please note that this post is in continuous development, meaning I'll update it every now and then.

If you have a friend or know someone who needs this PHP OOP CRUD Tutorial, please share this page to them! I know you will help them a lot by doing it. Thanks!

PHP CRUD Tutorial for Beginners – Step By Step Guide!

Previously, we learned how to run your first PHP script. This time, we will learn CRUD operations with PHP and MySQL. CRUD stands for Create, Read, Update and Delete database records.

Overview

This tutorial is for your if:

  • You need a high quality and updated reference for a PHP CRUD tutorial.
  • You need to learn how to do CRUD operations in PHP and MySQL.
  • You are beginner in this kind of PHP web programming.

Coding CRUD with PHP and MySQL is one of the basics. PHP web programmers must be able to code it with less effort. We can perform this task using any of the three PHP Database extensions:

  1. Using the MySQL extension.
  2. Using the MySQLi extension.
  3. Using the PDO extension.

PHP 5.5 deprecated the MySQL extension. It is not recommended to use these days.

If you are programming with PHP, you'll have to use either MySQLi (i means improved) or PDO extension.

With that in mind, we will use the PDO extension. It is the newest and actively developed way of programming these CRUD grids.

Project file structure

Our PHP CRUD tutorial will contain the following main files.

  • dev/products.sql – contains the database table structure and sample data used in this project. Once you created your database in PhpMyAdmin, you can import this file.
  • config/database.php – used for database connection and configuration.
  • create.php – used for creating a new record. It contains an HTML form where the user can enter details for a new record.
  • index.php – used for reading records from the database. It uses an HTML table to display the data retrieved from the MySQL database.
  • read_one.php – used for reading one or single record from database. It uses an HTML table to display the data retrieved from the MySQL database.
  • update.php – used for updating a record. It uses an HTML form which will be filled out with data based on the given “id” parameter.
  • delete.php – used for deleting a record. It accepts an “id” parameter and deletes the record with it. Once it execute the delete query, it will redirect the user to the index.php page.

Prepare the database

Create the database

On your PhpMyAdmin, create a database named "php_beginner_crud_level_1".

If you're not sure how to do it, please take a look at the following example. Follow only the "create database" part.

Create the database table

Next, run the following SQL code. This is to create our products database table. If you're not sure how to do this, take a look at this resource.

--
-- Table structure for table `products`
--

CREATE TABLE IF NOT EXISTS `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  `description` text NOT NULL,
  `price` double NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;

Dump sample data on the table

Again, run the following SQL code on your PhpMyAdmin. This will insert the sample data or record it on our products database table.

--
-- Dumping data for table `products`
--

INSERT INTO `products` (`id`, `name`, `description`, `price`, `created`, `modified`) VALUES
(1, 'Basketball', 'A ball used in the NBA.', 49.99, '2015-08-02 12:04:03', '2015-08-06 06:59:18'),
(3, 'Gatorade', 'This is a very good drink for athletes.', 1.99, '2015-08-02 12:14:29', '2015-08-06 06:59:18'),
(4, 'Eye Glasses', 'It will make you read better.', 6, '2015-08-02 12:15:04', '2015-08-06 06:59:18'),
(5, 'Trash Can', 'It will help you maintain cleanliness.', 3.95, '2015-08-02 12:16:08', '2015-08-06 06:59:18'),
(6, 'Mouse', 'Very useful if you love your computer.', 11.35, '2015-08-02 12:17:58', '2015-08-06 06:59:18'),
(7, 'Earphone', 'You need this one if you love music.', 7, '2015-08-02 12:18:21', '2015-08-06 06:59:18'),
(8, 'Pillow', 'Sleeping well is important.', 8.99, '2015-08-02 12:18:56', '2015-08-06 06:59:18');

As you may have noticed, steps 1 and 2 are both SQL queries. Yes, they can run at the same time. But I wanted it to be on separate steps to emphasize those SQL queries' purpose.

Create database connection file

This section will answer the question: how to connect to MySQL database with PDO?

  • Create php-beginner-crud-level-1 folder and open it.
  • Create config folder and open it.
  • Create database.php file.
  • Place the following code inside it.
<?php
// used to connect to the database
$host = "localhost";
$db_name = "php_beginner_crud_level_1";
$username = "root";
$password = "";

try {
    $con = new PDO("mysql:host={$host};dbname={$db_name}", $username, $password);
}

// show error
catch(PDOException $exception){
    echo "Connection error: " . $exception->getMessage();
}
?>

Output

We have set up the database successfully! The only output we have so far is the database, database table, and sample records we set up via PhpMyAdmin.

Let's proceed to the next section below.

Create or insert record in PHP

HTML5 boilerplate for create.php

We use the Bootstrap user interface for this project. If you are not familiar with Bootstrap, please learn our Bootstrap Tutorial for Beginners.

  • Go back to php-beginner-crud-level-1 folder.
  • Create a new create.php file.
  • Place the code following code inside the create.php file.
<!DOCTYPE HTML>
<html>
<head>
    <title>PDO - Create a Record - PHP CRUD Tutorial</title>

    <!-- Latest compiled and minified Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />

</head>
<body>

    <!-- container -->
    <div class="container">

        <div class="page-header">
            <h1>Create Product</h1>
        </div>

    <!-- html form to create product will be here -->

    </div> <!-- end .container -->

<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>

<!-- Latest compiled and minified Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</body>
</html>

HTML form to input new record data

Now we are going to start answering the question: how to create a record with PDO?

The code below will create an HTML form with input fields that matches the fields in the database. Replace <!-- html form to create product will be here --> comment of the previous section with the following code.

<!-- PHP insert code will be here -->

<!-- html form here where the product information will be entered -->
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post">
	<table class='table table-hover table-responsive table-bordered'>
		<tr>
			<td>Name</td>
			<td><input type='text' name='name' class='form-control' /></td>
		</tr>
		<tr>
			<td>Description</td>
			<td><textarea name='description' class='form-control'></textarea></td>
		</tr>
		<tr>
			<td>Price</td>
			<td><input type='text' name='price' class='form-control' /></td>
		</tr>
		<tr>
			<td></td>
			<td>
				<input type='submit' value='Save' class='btn btn-primary' />
				<a href='index.php' class='btn btn-danger'>Back to read products</a>
			</td>
		</tr>
	</table>
</form>

Code to create a new record

We are still working on the create.php file. Once the user filled out the form and clicked the save button, the code below will save it to the MySQL database.

Replace <!-- PHP insert code will be here --> comment of the previous section with the following code.

<?php
if($_POST){

	// include database connection
	include 'config/database.php';

	try{

		// insert query
		$query = "INSERT INTO products SET name=:name, description=:description, price=:price, created=:created";

		// prepare query for execution
		$stmt = $con->prepare($query);

		// posted values
		$name=htmlspecialchars(strip_tags($_POST['name']));
		$description=htmlspecialchars(strip_tags($_POST['description']));
		$price=htmlspecialchars(strip_tags($_POST['price']));

		// bind the parameters
		$stmt->bindParam(':name', $name);
		$stmt->bindParam(':description', $description);
		$stmt->bindParam(':price', $price);

		// specify when this record was inserted to the database
		$created=date('Y-m-d H:i:s');
		$stmt->bindParam(':created', $created);

		// Execute the query
		if($stmt->execute()){
			echo "<div class='alert alert-success'>Record was saved.</div>";
		}else{
			echo "<div class='alert alert-danger'>Unable to save record.</div>";
		}

	}

	// show error
	catch(PDOException $exception){
		die('ERROR: ' . $exception->getMessage());
	}
}
?>

Output

Congrats! For the first time, we can now see an output on a web page. Go to this URL:

http://localhost/php-beginner-crud-level-1/create.php

You will see the output that looks like the following images.

When the user fills out the form.

When the user submitted the form.

A new record added to the database.

Read records in PHP

Basic HTML code for index.php

Create a new index.php file. We prepare this to read records from the database. It answers the question: how to read records with PDO?

Place the following code inside the index.php file.

<!DOCTYPE HTML>
<html>
<head>
	<title>PDO - Read Records - PHP CRUD Tutorial</title>

	<!-- Latest compiled and minified Bootstrap CSS -->
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />

	<!-- custom css -->
	<style>
	.m-r-1em{ margin-right:1em; }
	.m-b-1em{ margin-bottom:1em; }
	.m-l-1em{ margin-left:1em; }
	.mt0{ margin-top:0; }
	</style>

</head>
<body>

    <!-- container -->
    <div class="container">

        <div class="page-header">
            <h1>Read Products</h1>
        </div>

        <!-- PHP code to read records will be here -->

    </div> <!-- end .container -->

<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>

<!-- Latest compiled and minified Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

<!-- confirm delete record will be here -->

</body>
</html>

Read records from the database

This time we will read records from the database.

Replace <!-- PHP code to read records will be here --> comment of the previous section with the following code.

<?php
// include database connection
include 'config/database.php';

// delete message prompt will be here

// select all data
$query = "SELECT id, name, description, price FROM products ORDER BY id DESC";
$stmt = $con->prepare($query);
$stmt->execute();

// this is how to get number of rows returned
$num = $stmt->rowCount();

// link to create record form
echo "<a href='create.php' class='btn btn-primary m-b-1em'>Create New Product</a>";

//check if more than 0 record found
if($num>0){

	// data from database will be here

}

// if no records found
else{
	echo "<div class='alert alert-danger'>No records found.</div>";
}
?>

Add HTML table with heading

This is the HTML table that will hold and display data from the database.

Replace // data from database will be here comment of the previous section with the following code.

//start table
echo "<table class='table table-hover table-responsive table-bordered'>";

	//creating our table heading
	echo "<tr>
		<th>ID</th>
		<th>Name</th>
		<th>Description</th>
		<th>Price</th>
		<th>Action</th>
	</tr>";

	// table body will be here

// end table
echo "</table>";

Add HTML table body

This part is where we will loop through the list of records from the database. This loop will create the rows of data on our HTML table.

Replace // table body will be here comment of the previous section with the following code.

// retrieve our table contents
// fetch() is faster than fetchAll()
// http://stackoverflow.com/questions/2770630/pdofetchall-vs-pdofetch-in-a-loop
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
	// extract row
	// this will make $row['firstname'] to
	// just $firstname only
	extract($row);

	// creating new table row per record
	echo "<tr>
		<td>{$id}</td>
		<td>{$name}</td>
		<td>{$description}</td>
		<td>${$price}</td>
		<td>";
			// read one record
			echo "<a href='read_one.php?id={$id}' class='btn btn-info m-r-1em'>Read</a>";

			// we will use this links on next part of this post
			echo "<a href='update.php?id={$id}' class='btn btn-primary m-r-1em'>Edit</a>";

			// we will use this links on next part of this post
			echo "<a href='#' onclick='delete_user({$id});'  class='btn btn-danger'>Delete</a>";
		echo "</td>";
	echo "</tr>";
}

Output

Go to this URL:

http://localhost/php-beginner-crud-level-1/index.php

You will see the records retrieved from the database. It will look like the image below.

Read one record in PHP

Basic HTML code for read_one.php

Create a new read_one.php file. This is where we will read and display the details of a single database record.

Place the following code inside the read_one.php file.

<!DOCTYPE HTML>
<html>
<head>
	<title>PDO - Read One Record - PHP CRUD Tutorial</title>

    <!-- Latest compiled and minified Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />

</head>
<body>

    <!-- container -->
    <div class="container">

        <div class="page-header">
            <h1>Read Product</h1>
        </div>

        <!-- PHP read one record will be here -->

        <!-- HTML read one record table will be here -->

	</div> <!-- end .container -->

<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>

<!-- Latest compiled and minified Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</body>
</html>

Read one record from the database

The following code is how we retrieve a single database record.

Replace <!-- PHP read one record will be here --> comment of the previous section with the following code.

<?php
// get passed parameter value, in this case, the record ID
// isset() is a PHP function used to verify if a value is there or not
$id=isset($_GET['id']) ? $_GET['id'] : die('ERROR: Record ID not found.');

//include database connection
include 'config/database.php';

// read current record's data
try {
	// prepare select query
	$query = "SELECT id, name, description, price FROM products WHERE id = ? LIMIT 0,1";
	$stmt = $con->prepare( $query );

	// this is the first question mark
	$stmt->bindParam(1, $id);

	// execute our query
	$stmt->execute();

	// store retrieved row to a variable
	$row = $stmt->fetch(PDO::FETCH_ASSOC);

	// values to fill up our form
	$name = $row['name'];
	$description = $row['description'];
	$price = $row['price'];
}

// show error
catch(PDOException $exception){
	die('ERROR: ' . $exception->getMessage());
}
?>

Display record details

The following HTML table will hold and display the details of a single database record.

Open read_one.php file.

Replace <!-- HTML read one record table will be here --> comment with the following code.

<!--we have our html table here where the record will be displayed-->
<table class='table table-hover table-responsive table-bordered'>
	<tr>
		<td>Name</td>
		<td><?php echo htmlspecialchars($name, ENT_QUOTES);  ?></td>
	</tr>
	<tr>
		<td>Description</td>
		<td><?php echo htmlspecialchars($description, ENT_QUOTES);  ?></td>
	</tr>
	<tr>
		<td>Price</td>
		<td><?php echo htmlspecialchars($price, ENT_QUOTES);  ?></td>
	</tr>
	<tr>
		<td></td>
		<td>
			<a href='index.php' class='btn btn-danger'>Back to read products</a>
		</td>
	</tr>
</table>

Output

To read one record from the database, try to click any Read button from our index.php file.

You can also go to this URL:

http://localhost/php-beginner-crud-level-1/read_one.php?id=9

You will see an output like the image below.

Update record in PHP

Basic HTML code for udpate.php

Create a new update.php file. We are preparing to update a selected record from the database.

This will answer the question: how to update a record with PDO?

Place the following code inside the new update.php file.

<!DOCTYPE HTML>
<html>
<head>
	<title>PDO - Update a Record - PHP CRUD Tutorial</title>

    <!-- Latest compiled and minified Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />

</head>
<body>

    <!-- container -->
    <div class="container">

        <div class="page-header">
            <h1>Update Product</h1>
        </div>

        <!-- PHP read record by ID will be here -->

        <!-- HTML form to update record will be here -->

    </div> <!-- end .container -->

<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>

<!-- Latest compiled and minified Bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</body>
</html>

Read a record by ID parameter

We have to get the record ID and store it in the $id variable. We access the $_GET['id'] variable to do it.

What we are trying to do here is to get the related data based on the given record ID. This is the way to auto-fill the HTML form with existing data from the database.

Replace <!-- PHP read record by ID will be here --> comment of the previous section with the following code.

<?php
// get passed parameter value, in this case, the record ID
// isset() is a PHP function used to verify if a value is there or not
$id=isset($_GET['id']) ? $_GET['id'] : die('ERROR: Record ID not found.');

//include database connection
include 'config/database.php';

// read current record's data
try {
	// prepare select query
	$query = "SELECT id, name, description, price FROM products WHERE id = ? LIMIT 0,1";
	$stmt = $con->prepare( $query );

	// this is the first question mark
	$stmt->bindParam(1, $id);

	// execute our query
	$stmt->execute();

	// store retrieved row to a variable
	$row = $stmt->fetch(PDO::FETCH_ASSOC);

	// values to fill up our form
	$name = $row['name'];
	$description = $row['description'];
	$price = $row['price'];
}

// show error
catch(PDOException $exception){
	die('ERROR: ' . $exception->getMessage());
}
?>

HTML form to update a record

This form will show the data retrieved using the previous section's code.

We read a single record from the database, based on the given ID parameter.

Open update.php file. Replace <!-- HTML form to update record will be here --> comment with the following code.

<!-- PHP post to update record will be here -->

<!--we have our html form here where new record information can be updated-->
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"] . "?id={$id}");?>" method="post">
	<table class='table table-hover table-responsive table-bordered'>
		<tr>
			<td>Name</td>
			<td><input type='text' name='name' value="<?php echo htmlspecialchars($name, ENT_QUOTES);  ?>" class='form-control' /></td>
		</tr>
		<tr>
			<td>Description</td>
			<td><textarea name='description' class='form-control'><?php echo htmlspecialchars($description, ENT_QUOTES);  ?></textarea></td>
		</tr>
		<tr>
			<td>Price</td>
			<td><input type='text' name='price' value="<?php echo htmlspecialchars($price, ENT_QUOTES);  ?>" class='form-control' /></td>
		</tr>
		<tr>
			<td></td>
			<td>
				<input type='submit' value='Save Changes' class='btn btn-primary' />
				<a href='index.php' class='btn btn-danger'>Back to read products</a>
			</td>
		</tr>
	</table>
</form>

Code to update the record

The following code will save the changes in the database.

That is if the user changes some value on the form and hits the Save Changes button.

Replace <!-- PHP post to update record will be here --> comment of the previous section with the following code.

<?php

// check if form was submitted
if($_POST){

	try{

		// write update query
		// in this case, it seemed like we have so many fields to pass and
		// it is better to label them and not use question marks
		$query = "UPDATE products
					SET name=:name, description=:description, price=:price
					WHERE id = :id";

		// prepare query for excecution
		$stmt = $con->prepare($query);

		// posted values
		$name=htmlspecialchars(strip_tags($_POST['name']));
		$description=htmlspecialchars(strip_tags($_POST['description']));
		$price=htmlspecialchars(strip_tags($_POST['price']));

		// bind the parameters
		$stmt->bindParam(':name', $name);
		$stmt->bindParam(':description', $description);
		$stmt->bindParam(':price', $price);
		$stmt->bindParam(':id', $id);

		// Execute the query
		if($stmt->execute()){
			echo "<div class='alert alert-success'>Record was updated.</div>";
		}else{
			echo "<div class='alert alert-danger'>Unable to update record. Please try again.</div>";
		}

	}

	// show errors
	catch(PDOException $exception){
		die('ERROR: ' . $exception->getMessage());
	}
}
?>

Output

To update a database record, run the index.php file and click any Edit button.

Or, go to this URL:

http://localhost/php-beginner-crud-level-1/update.php?id=9

You will see the result like the images below.

Update record form.

Submitted form.

Changes in the database.

Delete record in PHP

Tell the user if record was deleted

This will tell the user if there is a deleted record after clicking the delete button and OK in the pop-up.

Open index.php file. Replace // delete message prompt will be here comment with the following code.

$action = isset($_GET['action']) ? $_GET['action'] : "";

// if it was redirected from delete.php
if($action=='deleted'){
	echo "<div class='alert alert-success'>Record was deleted.</div>";
}

JavaScript to confirm record deletion

The user clicks on the Delete button in index.php.

Next, he will verify the deletion by clicking OK on the pop-up.

That user activity will execute the following JavaScript code.

Open index.php file. Replace <!-- confirm delete record will be here --> comment with the following code.

<script type='text/javascript'>
// confirm record deletion
function delete_user( id ){

	var answer = confirm('Are you sure?');
	if (answer){
		// if user clicked ok,
		// pass the id to delete.php and execute the delete query
		window.location = 'delete.php?id=' + id;
	}
}
</script>

Delete record from the database

The code below will delete a record from the database using the given ID parameter.

This answers the question: how to delete a record with PDO?

Create a new delete.php file, place the following code and save it.

<?php
// include database connection
include 'config/database.php';

try {

	// get record ID
	// isset() is a PHP function used to verify if a value is there or not
	$id=isset($_GET['id']) ? $_GET['id'] : die('ERROR: Record ID not found.');

	// delete query
	$query = "DELETE FROM products WHERE id = ?";
	$stmt = $con->prepare($query);
	$stmt->bindParam(1, $id);

	if($stmt->execute()){
		// redirect to read records page and
		// tell the user record was deleted
		header('Location: index.php?action=deleted');
	}else{
		die('Unable to delete record.');
	}
}

// show error
catch(PDOException $exception){
	die('ERROR: ' . $exception->getMessage());
}
?>

Output

Once the user clicks any Delete button, it will show a confirmation pop-up.

If the user clicks the "OK" button, the record will be deleted from the database. It will tell the user via message prompt that the record was deleted.

The record is gone in the database as well.

Pagination in PHP

Please note that this is a bonus section and is not included in the LEVEL 1 source code download. We will have to add or remove some codes we've done above so that pagination will work.

Set pagination variables

The following variables are used to calculate the correct numbers for the LIMIT clause of our SELECT query.

We will see how our SELECT query will change later.

Place the following code below include 'config/database.php'; line of index.php file.

// PAGINATION VARIABLES
// page is the current page, if there's nothing set, default is page 1
$page = isset($_GET['page']) ? $_GET['page'] : 1;

// set records or rows of data per page
$records_per_page = 5;

// calculate for the query LIMIT clause
$from_record_num = ($records_per_page * $page) - $records_per_page;

Add LIMIT clause in SELECT query

This will enable paginated requests to the database. Still on the index.php file, change the following code from:

$query = "SELECT id, name, description, price FROM products ORDER BY id DESC";
$stmt = $con->prepare($query);
$stmt->execute();

to:

// select data for current page
$query = "SELECT id, name, description, price FROM products ORDER BY id DESC
	LIMIT :from_record_num, :records_per_page";

$stmt = $con->prepare($query);
$stmt->bindParam(":from_record_num", $from_record_num, PDO::PARAM_INT);
$stmt->bindParam(":records_per_page", $records_per_page, PDO::PARAM_INT);
$stmt->execute();

Count total number of records

Counting the total number of records will help calculate the correct pagination numbers.

Below the closing table tag in the index.php file, add the following code.

// PAGINATION
// count total number of rows
$query = "SELECT COUNT(*) as total_rows FROM products";
$stmt = $con->prepare($query);

// execute query
$stmt->execute();

// get total rows
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$total_rows = $row['total_rows'];

Include paging file

Add the following code after the previous section's code.

// paginate records
$page_url="index.php?";
include_once "paging.php";

Why a $page_url variable is needed? Because we made paging.php re-usable. You can use it for other objects you want to paginate.

For example, you're trying to paginate your read_categories.php, you will need to do:

$page_url="read_categories.php?";

You will have to follow the code pattern of sections 10.1 to 10.3 when you use the paging.php file.

Create paging.php

Create a new paging.php file. Place the following code and save it.

<?php
echo "<ul class='pagination pull-left margin-zero mt0'>";

// first page button will be here

// clickable page numbers will be here

// last page button will be here

echo "</ul>";
?>

Add first page button

Replace // first page button will be here comment of the previous section with the following code.

// first page button
if($page>1){

	$prev_page = $page - 1;
	echo "<li>
		<a href='{$page_url}page={$prev_page}'>
			<span style='margin:0 .5em;'>«</span>
		</a>
	</li>";
}

Add clickable page numbers

Open paging.php file.

Replace // clickable page numbers will be here comment with the following code.

// clickable page numbers

// find out total pages
$total_pages = ceil($total_rows / $records_per_page);

// range of num links to show
$range = 1;

// display links to 'range of pages' around 'current page'
$initial_num = $page - $range;
$condition_limit_num = ($page + $range)  + 1;

for ($x=$initial_num; $x<$condition_limit_num; $x++) {

	// be sure '$x is greater than 0' AND 'less than or equal to the $total_pages'
	if (($x > 0) && ($x <= $total_pages)) {

		// current page
		if ($x == $page) {
			echo "<li class='active'>
				<a href='javascript::void();'>{$x}</a>
			</li>";
		}

		// not current page
		else {
			echo "<li>
				<a href='{$page_url}page={$x}'>{$x}</a> 
			</li>";
		}
	}
}

Add last page button

Open paging.php file.

Replace // last page button will be here comment with the following code.

// last page button
if($page<$total_pages){
	$next_page = $page + 1;

	echo "<li>
		<a href='{$page_url}page={$next_page}'>
			<span style='margin:0 .5em;'>»</span>
		</a>
	</li>";
}

Output

Run index.php file on the browser:

http://localhost/php-beginner-crud-level-1/index.php

You should see the pagination buttons like the images below.

Read records page 1.

Read records page 2.

File upload in PHP

Now we are going to add a file upload feature when creating a record.

Add HTML "file" field

Open the create.php file and scroll down to the form. Find the opening "form tag and enable the file upload by changing it to:

<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post" enctype="multipart/form-data">

Find the closing tr tag of the price field. Once found, add the following code after it.

<tr>
	<td>Photo</td>
	<td><input type="file" name="image" /></td>
</tr>

Add "image" field

Still in create.php file. Scroll up and change the insert SQL query.

It should look like the following code. The new image field will store the file name of the submitted file.

// insert query
$query = "INSERT INTO products
			SET name=:name, description=:description,
				price=:price, image=:image, created=:created";

// prepare query for execution
$stmt = $con->prepare($query);

$name=htmlspecialchars(strip_tags($_POST['name']));
$description=htmlspecialchars(strip_tags($_POST['description']));
$price=htmlspecialchars(strip_tags($_POST['price']));

// new 'image' field
$image=!empty($_FILES["image"]["name"])
		? sha1_file($_FILES['image']['tmp_name']) . "-" . basename($_FILES["image"]["name"])
		: "";
$image=htmlspecialchars(strip_tags($image));

// bind the parameters
$stmt->bindParam(':name', $name);
$stmt->bindParam(':description', $description);
$stmt->bindParam(':price', $price);
$stmt->bindParam(':image', $image);

// specify when this record was inserted to the database
$created=date('Y-m-d H:i:s');
$stmt->bindParam(':created', $created);

Using PhpMyAdmin, add an "image" field in the products table as well.

Set variables for file upload

We will start the code for the file upload feature. Find the following line in the create.php file.

echo "<div class='alert alert-success'>Record was saved.</div>";

Under the code above, we will add the following code.

The if($image){ code will verify if there's an uploaded image.

If there is, inside the if statement, we will set the initial variables needed for the file upload.

// now, if image is not empty, try to upload the image
if($image){

	// sha1_file() function is used to make a unique file name
	$target_directory = "uploads/";
	$target_file = $target_directory . $image;
	$file_type = pathinfo($target_file, PATHINFO_EXTENSION);

	// error message is empty
	$file_upload_error_messages="";

}

Make sure submitted file is a real image

Now we will start validating the submitted file. The code below will identify if the submitted file is a real or fake image.

Place the following code under $file_upload_error_messages=""; of the previous section.

// make sure that file is a real image
$check = getimagesize($_FILES["image"]["tmp_name"]);
if($check!==false){
	// submitted file is an image
}else{
	$file_upload_error_messages.="<div>Submitted file is not an image.</div>";
}

Make sure certain file types are allowed

The following code will limit the allowed file types. Place it under the code of the previous section.

// make sure certain file types are allowed
$allowed_file_types=array("jpg", "jpeg", "png", "gif");
if(!in_array($file_type, $allowed_file_types)){
	$file_upload_error_messages.="<div>Only JPG, JPEG, PNG, GIF files are allowed.</div>";
}

Make sure file does not exist

There's a very small chance that the submitted file name will be the same as the one that exists in the server. This is because of the sha1_file() method we used in section 10.2 above.

But just in case there's a file with the same name, tell the user. Place the following code after the previous section's code.

// make sure file does not exist
if(file_exists($target_file)){
	$file_upload_error_messages.="<div>Image already exists. Try to change file name.</div>";
}

Make sure submitted file is not too large

Uploading a very large photo is not recommended in this case. So we will set the file size limit to less than 1 MB. Place the following code after the code of the previous section.

// make sure submitted file is not too large, can't be larger than 1 MB
if($_FILES['image']['size'] > (1024000)){
	$file_upload_error_messages.="<div>Image must be less than 1 MB in size.</div>";
}

Make sure the 'uploads' folder exists

The "uploads" folder is where we will put the submitted file. Make sure it exists by using the following code. Place it under the code of the previous section.

// make sure the 'uploads' folder exists
// if not, create it
if(!is_dir($target_directory)){
	mkdir($target_directory, 0777, true);
}

Try to upload the file

The move_uploaded_file built-in PHP function will place the uploaded file on the server directory.

Place the following code under the previous section's code.

// if $file_upload_error_messages is still empty
if(empty($file_upload_error_messages)){
	// it means there are no errors, so try to upload the file
	if(move_uploaded_file($_FILES["image"]["tmp_name"], $target_file)){
		// it means photo was uploaded
	}else{
		echo "<div class='alert alert-danger'>
			<div>Unable to upload photo.</div>
			<div>Update the record to upload photo.</div>
		</div>";
	}
}

// if $file_upload_error_messages is NOT empty
else{
	// it means there are some errors, so show them to user
	echo "<div class='alert alert-danger'>
		<div>{$file_upload_error_messages}</div>
		<div>Update the record to upload photo.</div>
	</div>";
}

Output

Form to create a product with file upload field.

When the form was submitted.

The "uploads" folder was created, with the uploaded file inside.

The file name was saved in the database.

Show uploaded image in PHP

Add image field in query

Open the read_one.php file and apply the following changes to the code.

Add image field to the $query variable. It should look like the following.

$query = "SELECT id, name, description, price, image FROM products WHERE id = ? LIMIT 0,1";

Add '$image' variable after the '$price' variable.

$image = htmlspecialchars($row['image'], ENT_QUOTES);

Add HTML image tag

Find the closing tr tag of the Price field in the HTML table and put the following code after it.

It will show the uploaded image or 'No image found.' if no image was uploaded.

<tr>
	<td>Image</td>
	<td>
	<?php echo $image ? "<img src='uploads/{$image}' style='width:300px;' />" : "No image found.";  ?>
	</td>
</tr>

Output

Click the Read One button of the record we created with a file upload.

You should see something like the images below.

Record with an image.

Record without image.

Download Source Codes

Download LEVEL 1 Source Code

FEATURES LEVEL 1
PDO extension used YES
Create product YES
Read product YES
Update product YES
Delete product YES
Price display with dollar sign YES
SQL file in "dev" folder YES
$20 - Download now

Download LEVEL 2 Source Code

FEATURES LEVEL 2
All features of LEVEL 1 above YES
HTML5 (font-end) validation for create product YES
HTML5 (font-end) validation for update product YES
Category selection for create and update product. YES
Bootstrap UI YES
Buttons with Glyphicons YES
Pagination YES
Search products by name or description YES
HTML5 (font-end) validation for search product YES
Pagination in search YES
Allow user to input page number (read and search list) YES
Export / download records to CSV YES
Price display with dollar sign, comma and decimal point YES
Multiple delete YES
Create & update record with file upload YES
$40 - Download now

Download LEVEL 3 Source Code

FEATURES LEVEL 3
All features of LEVEL 1 and 2 above YES
Bootstrap navigation bar YES
Select category in navigation YES
Higlight category in navigation YES
Create category YES
Read category YES
Update category YES
Delete category YES
View products by category YES
Pagination for category YES
Search category YES
Pagination for category search YES
Server side validation for create product & category YES
Server side validation for update product & category YES
Sorting by fields YES
Pagination for sorting by fields YES
jQuery UI enabled YES
Search product by date range - record date created YES
Pagination for earch product by date range YES
jQuery UI calendar for picking date YES
$50 - Download now

Why download?

Do you need more reasons to download it?

MORE REASONS TO DOWNLOAD THE CODE ALL
Use new skills for your multiple projects YES
Save huge amount of time learning Bootstrap and PHP YES
Code examples are direct to the point YES
Well explained and commented source code YES
Fast and friendly email support YES
Free source code updates YES

How To Run The Source Code?

We highly recommend you follow and study our well-detailed, step-by-step tutorial above first. Nothing beats experience when it comes to learning.

But we believe you will learn faster if you’ll see the final source code as well. We consider it as your additional guide.

Imagine the value or skill upgrade it can bring you. The additional income you can get from your work, projects, or business. The precious time you save. Isn’t that what you want?

By now, you need to download our source codes. To do it, use any download buttons in the next few sections below.

Once you downloaded the source codes, here’s how you can run them.

  1. Extract the files to your server directory.
  2. Create your database using PhpMyAdmin, database name is "php_beginner_crud_3" - if you downloaded our LEVEL 3 source code.
  3. Import the SQL file called "php_beginner_crud_3.sql" located in the "dev" folder.
  4. You run index.php on the browser.

If you have any more questions, please feel free to contact me now. You can do it by sending a message to our email [email protected]

Thanks for supporting our website and projects here at codeofaninja.com!

Online Resources

What's Next?

After learning from this PHP CRUD tutorial, we can go one step higher. We can do this by learning object-oriented programming (OOP) in PHP.

Object-oriented programming (OOP) is a programming language model organized around objects rather than "actions" and data rather than logic. This is very exciting.

To learn more, we created the next tutorial just for you! Let's go and learn:
PHP, MySQL, and OOP CRUD Tutorial - Step by Step Guide!

Related Tutorials

Please explore more tutorials on our start page. Click here.

Notes

Found An Issue?

If you found a problem with this code, please write a comment below. Please be descriptive about your issue. Please provide the error messages, screenshots (or screencast) and your test URL. Thanks!

Before you write a comment, remember to read this guide and our code of conduct.

Subscribe to CodeOfaNinja

We constantly improve CodeOfaNinja. We update our tutorials and source codes. Receive valuable web programming tutorials and updates to your email. Subscribe now!

Enjoy high-quality web programming tutorials.
Subscribe to CodeOfaNinja now for FREE!

Thank You!

Please share this post if you think this is a useful PHP CRUD Tutorial. We hope you mastered how to create, read, update and delete database records and more. Thanks for learning here in codeofaninja.com!