PHP CRUD
This is a Create Rename Update Delete template to manage a single database table. It displays a table of the database contents that has sortable headings.
- Create the database and assign user rights:
CREATE DATABASE books; CREATE USER 'drupal'@'localhost' IDENTIFIED BY 'password'; GRANT ALL on drupal.* TO 'drupal'@'localhost'; USE books;
- Execute SQL to create the necessary table:
CREATE TABLE `books` ( `id` int(11) NOT NULL auto_increment, `title` varchar(100) NOT NULL, `author` varchar(100) NOT NULL, `owner` varchar(25) NOT NULL, `isbn` varchar(13) NOT NULL, PRIMARY KEY (`id`) );
- Create the necessary 8 files in the web server directory:
- style.css
- sort-table.js
- index.php
- edit.php
- delete.php
- config.php
- add.php
- add.html
style.cssEdit
body {background-color: pink;} table, th, td, p { font-size: 1.5em; } table { width:100%; } button { font-size: 1em; } input[type=text], input[type=submit] { font-size: inherit; } a {font-size: 1em;} table {border: 1px solid black; border-collapse: collapse; } th, td { padding: 2px 5px; border: 1px solid black; } thead { background: #ddd; } table#demo2.js-sort-0 tbody tr td:nth-child(1), table#demo2.js-sort-1 tbody tr td:nth-child(2), table#demo2.js-sort-2 tbody tr td:nth-child(3), table#demo2.js-sort-3 tbody tr td:nth-child(4), table#demo2.js-sort-4 tbody tr td:nth-child(5), table#demo2.js-sort-5 tbody tr td:nth-child(6), table#demo2.js-sort-6 tbody tr td:nth-child(7), table#demo2.js-sort-7 tbody tr td:nth-child(8), table#demo2.js-sort-8 tbody tr td:nth-child(9), table#demo2.js-sort-9 tbody tr td:nth-child(10) { background: #dee;}
sort-table.jsEdit
/** * sort-table.js * A pure JavaScript (no dependencies) solution to make HTML * Tables sortable * * Copyright (c) 2013 Tyler Uebele * Released under the MIT license. See included LICENSE.txt * or http://opensource.org/licenses/MIT * * latest version available at https://github.com/tyleruebele/sort-table */ /** * Sort the rows in a HTML Table * * @param Table The Table DOM object * @param col The zero-based column number by which to sort * @param dir Optional. The sort direction; pass 1 for asc; -1 for desc * @returns void */ function sortTable(Table, col, dir) { var sortClass, i; // get previous sort column sortTable.sortCol = -1; sortClass = Table.className.match(/js-sort-\d+/); if (null != sortClass) { sortTable.sortCol = sortClass[0].replace(/js-sort-/, ''); Table.className = Table.className.replace(new RegExp(' ?' + sortClass[0] + '\\b'), ''); } // If sort column was not passed, use previous if ('undefined' === typeof col) { col = sortTable.sortCol; } if ('undefined' !== typeof dir) { // Accept -1 or 'desc' for descending. All else is ascending sortTable.sortDir = dir == -1 || dir == 'desc' ? -1 : 1; } else { // sort direction was not passed, use opposite of previous sortClass = Table.className.match(/js-sort-(a|de)sc/); if (null != sortClass && sortTable.sortCol == col) { sortTable.sortDir = 'js-sort-asc' == sortClass[0] ? -1 : 1; } else { sortTable.sortDir = 1; } } Table.className = Table.className.replace(/ ?js-sort-(a|de)sc/g, ''); // update sort column Table.className += ' js-sort-' + col; sortTable.sortCol = col; // update sort direction Table.className += ' js-sort-' + (sortTable.sortDir == -1 ? 'desc' : 'asc'); // get sort type if (col < Table.tHead.rows[Table.tHead.rows.length - 1].cells.length) { sortClass = Table.tHead.rows[Table.tHead.rows.length - 1].cells[col].className.match(/js-sort-[-\w]+/); } // Improved support for colspan'd headers for (i = 0; i < Table.tHead.rows[Table.tHead.rows.length - 1].cells.length; i++) { if (col == Table.tHead.rows[Table.tHead.rows.length - 1].cells[i].getAttribute('data-js-sort-colNum')) { sortClass = Table.tHead.rows[Table.tHead.rows.length - 1].cells[i].className.match(/js-sort-[-\w]+/); } } if (null != sortClass) { sortTable.sortFunc = sortClass[0].replace(/js-sort-/, ''); } else { sortTable.sortFunc = 'string'; } // Set the headers for the active column to have the decorative class Table.querySelectorAll('.js-sort-active').forEach(function(Node) { Node.className = Node.className.replace(/ ?js-sort-active\b/, ''); }); Table.querySelectorAll('[data-js-sort-colNum="' + col + '"]:not(:empty)').forEach(function(Node) { Node.className += ' js-sort-active'; }); // sort! var rows = [], TBody = Table.tBodies[0]; for (i = 0; i < TBody.rows.length; i++) { rows[i] = TBody.rows[i]; } if ('none' != sortTable.sortFunc) { rows.sort(sortTable.compareRow); } while (TBody.firstChild) { TBody.removeChild(TBody.firstChild); } for (i = 0; i < rows.length; i++) { TBody.appendChild(rows[i]); } } /** * Compare two table rows based on current settings * * @param RowA A TR DOM object * @param RowB A TR DOM object * @returns {number} 1 if RowA is greater, -1 if RowB, 0 if equal */ sortTable.compareRow = function(RowA, RowB) { var valA, valB; if ('function' != typeof sortTable[sortTable.sortFunc]) { sortTable.sortFunc = 'string'; } valA = sortTable[sortTable.sortFunc](RowA.cells[sortTable.sortCol]); valB = sortTable[sortTable.sortFunc](RowB.cells[sortTable.sortCol]); return valA == valB ? 0 : sortTable.sortDir * (valA > valB ? 1 : -1); }; /** * Strip all HTML, no exceptions * @param html * @returns {string} */ sortTable.stripTags = function(html) { return html.replace(/<\/?[a-z][a-z0-9]*\b[^>]*>/gi, ''); }; /** * Helper function that converts a table cell (TD) to a comparable value * Converts innerHTML to a timestamp, 0 for invalid dates * * @param Cell A TD DOM object * @returns {Number} */ sortTable.date = function(Cell) { // If okDate library is available, Use it for advanced Date processing if (typeof okDate !== 'undefined') { var kDate = okDate(sortTable.stripTags(Cell.innerHTML)); return kDate ? kDate.getTime() : 0; } else { return (new Date(sortTable.stripTags(Cell.innerHTML))).getTime() || 0; } }; /** * Helper function that converts a table cell (TD) to a comparable value * Converts innerHTML to a JS Number object * * @param Cell A TD DOM object * @returns {Number} */ sortTable.number = function(Cell) { return Number(sortTable.stripTags(Cell.innerHTML).replace(/[^-\d.]/g, '')); }; /** * Helper function that converts a table cell (TD) to a comparable value * Converts innerHTML to a lower case string for insensitive compare * * @param Cell A TD DOM object * @returns {String} */ sortTable.string = function(Cell) { return sortTable.stripTags(Cell.innerHTML).toLowerCase(); }; /** * Helper function that converts a table cell (TD) to a comparable value * * @param Cell A TD DOM object * @returns {String} */ sortTable.raw = function(Cell) { return Cell.innerHTML; }; /** * Helper function that converts a table cell (TD) to a comparable value * Captures the last space-delimited token from innerHTML * * @param Cell A TD DOM object * @returns {String} */ sortTable.last = function(Cell) { return sortTable.stripTags(Cell.innerHTML).split(' ').pop().toLowerCase(); }; /** * Helper function that converts a table cell (TD) to a comparable value * Captures the value of the first childNode * * @param Cell A TD DOM object * @returns {String} */ sortTable.input = function(Cell) { for (var i = 0; i < Cell.children.length; i++) { if ('object' == typeof Cell.children[i] && 'undefined' != typeof Cell.children[i].value ) { return Cell.children[i].value.toLowerCase(); } } return sortTable.string(Cell); }; /** * Helper function that prevents sorting by always returning null * * @param Cell A TD DOM object * @returns null */ sortTable.none = function(Cell) { return null; }; /** * Return the click handler appropriate to the specified Table and column * * @param Table Table to sort * @param col Column to sort by * @returns {Function} Click Handler */ sortTable.getClickHandler = function(Table, col) { return function() { sortTable(Table, col); }; }; /** * Attach sortTable() calls to table header cells' onclick events * If the table(s) do not have a THead node, one will be created around the * first row */ sortTable.init = function() { var THead, Tables, Handler; if (document.querySelectorAll) { Tables = document.querySelectorAll('table.js-sort-table'); } else { Tables = document.getElementsByTagName('table'); } for (var i = 0; i < Tables.length; i++) { // Because IE<8 doesn't support querySelectorAll, skip unclassed tables if (!document.querySelectorAll && null === Tables[i].className.match(/\bjs-sort-table\b/)) { continue; } // Prevent repeat processing if (Tables[i].attributes['data-js-sort-table']) { continue; } // Ensure table has a tHead element if (!Tables[i].tHead) { THead = document.createElement('thead'); THead.appendChild(Tables[i].rows[0]); Tables[i].insertBefore(THead, Tables[i].children[0]); } else { THead = Tables[i].tHead; } // Attach click events to table header for (var rowNum = 0; rowNum < THead.rows.length; rowNum++) { for (var cellNum = 0, colNum = 0; cellNum < THead.rows[rowNum].cells.length; cellNum++) { // Skip headers marked "js-sort-none" if (THead.rows[rowNum].cells[cellNum].className.match(/\bjs-sort-none\b/)) { continue; } // Define which column the header should invoke sorting for THead.rows[rowNum].cells[cellNum].setAttribute('data-js-sort-colNum', colNum); Handler = sortTable.getClickHandler(Tables[i], colNum); window.addEventListener ? THead.rows[rowNum].cells[cellNum].addEventListener('click', Handler) : window.attachEvent && THead.rows[rowNum].cells[cellNum].attachEvent('onclick', Handler); colNum += THead.rows[rowNum].cells[cellNum].colSpan; } } // Mark table as processed Tables[i].setAttribute('data-js-sort-table', 'true') } // Add default styles as the first style in head so they can be easily overwritten by user styles var element = document.createElement('style'); document.head.insertBefore(element, document.head.childNodes[0]); var sheet = element.sheet; sheet.insertRule('table.js-sort-table.js-sort-asc thead tr > .js-sort-active:not(.js-sort-none):after {content: "\\25b2";font-size: 0.7em;padding-left: 3px;line-height: 0.7em;}', 0); sheet.insertRule('table.js-sort-table.js-sort-desc thead tr > .js-sort-active:not(.js-sort-none):after {content: "\\25bc";font-size: 0.7em;padding-left: 3px;line-height: 0.7em;}', 0); }; // Run sortTable.init() when the page loads window.addEventListener ? window.addEventListener('load', sortTable.init, false) : window.attachEvent && window.attachEvent('onload', sortTable.init) ; // Shim for IE11's lack of NodeList.prototype.forEach if (typeof NodeList.prototype.forEach !== "function") { NodeList.prototype.forEach = Array.prototype.forEach; }
index.phpEdit
<?php //including the database connection file include_once("config.php"); //fetching data in descending order (lastest entry first) //$result = mysql_query("SELECT * FROM users ORDER BY id DESC"); // mysql_query is deprecated $result = mysqli_query($mysqli, "SELECT * FROM books ORDER BY id DESC"); // using mysqli_query instead ?> <html> <head> <title>Our's Books</title> <link rel="stylesheet" href="style.css"> <script type="text/javascript" src="sort-table.js"></script> </head> <body> <h1>Our's Books</h1> <a href="add.html" style="font-size: 2em;">Add a Book</a><br/><br/> <table width='80%' border=0 class="js-sort-table"> <thead> <tr bgcolor='#CCCCCC'> <th class="js-sort-text">Title</th> <th class="js-sort-text">Author</th> <th class="js-sort-text">Owner</th> <th class="js-sort-number">ISBN</th> <th>Update</th> </tr> </thead> <?php //while($res = mysql_fetch_array($result)) { // mysql_fetch_array is deprecated, we need to use mysqli_fetch_array while($res = mysqli_fetch_array($result)) { echo "<tr>"; echo "<td>".$res['title']."</td>"; echo "<td>".$res['author']."</td>"; echo "<td>".$res['owner']."</td>"; echo "<td>".$res['isbn']."</td>"; echo "<td><a href=\"edit.php?id=$res[id]\">Edit</a> | <a href=\"delete.php?id=$res[id]\" onClick=\"return confirm('Are you sure you want to delete this book?')\">Delete</a></td>"; } ?> </table> </body> </html>
edit.phpEdit
<?php // including the database connection file include_once("config.php"); if(isset($_POST['update'])) { $id = $_POST['id']; $title=$_POST['title']; $author=$_POST['author']; $owner=$_POST['owner']; $isbn=$_POST['isbn']; // checking empty fields if(empty($title) || empty($author)) { if(empty($title)) { echo "<font color='red'>Title can't be blank!</font><br/>"; } if(empty($author)) { echo "<font color='red'>Author cannot be blank!</font><br/>"; } } else { //updating the table $result = mysqli_query($mysqli, "UPDATE books SET title='$title',author='$author',owner='$owner',isbn='$isbn' WHERE id=$id"); //redirectig to the display page. In our case, it is index.php header("Location: index.php"); } } ?> <?php //getting id from url $id = $_GET['id']; //selecting data associated with this particular id $result = mysqli_query($mysqli, "SELECT * FROM books WHERE id=$id"); while($res = mysqli_fetch_array($result)) { $title = $res['title']; $author = $res['author']; $owner = $res['owner']; $isbn = $res['isbn']; } ?> <html> <head> <title>Edit Book</title> <link rel="stylesheet" href="style.css"> </head> <body> <a href="index.php" style="font-size: 2em;">Home</a> <br/><br/> <form name="form1" method="post" action="edit.php"> <table border="0"> <tr> <td>Title</td> <td><input type="text" name="title" value="<?php echo $title;?>"></td> </tr> <tr> <td>Author</td> <td><input type="text" name="author" value="<?php echo $author;?>"></td> </tr> <tr> <td>Owner</td> <td><input type="text" name="owner" value="<?php echo $owner;?>"></td> </tr> <tr> <td>ISBN</td> <td><input type="text" name="isbn" value="<?php echo $isbn;?>"></td> </tr> <tr> <td><input type="hidden" name="id" value=<?php echo $_GET['id'];?>></td> <td><input type="submit" name="update" value="Update"></td> </tr> </table> </form> </body> </html>
delete.phpEdit
<?php //including the database connection file include("config.php"); //getting id of the data from url $id = $_GET['id']; //deleting the row from table $result = mysqli_query($mysqli, "DELETE FROM books WHERE id=$id"); //redirecting to the display page (index.php in our case) header("Location:index.php"); ?>
config.phpEdit
<?php $databaseHost = 'localhost'; $databaseName = 'books'; $databaseUsername = 'drupal'; $databasePassword = 'password'; $mysqli = mysqli_connect($databaseHost, $databaseUsername, $databasePassword, $databaseName); ?>
add.phpEdit
<html> <head> <title>Add Book</title> <link rel="stylesheet" href="style.css"> </head> <body> <?php //including the database connection file include_once("config.php"); if(isset($_POST['Submit'])) { $title = $_POST['title']; $author = $_POST['author']; $owner = $_POST['owner']; $isbn = $_POST['isbn']; // checking empty fields if(empty($title) || empty($author) ) { if(empty($title)) { echo "<font color='red'>You must enter a title!</font><br/>"; } if(empty($author)) { echo "<font color='red'>You must enter an author!</font><br/>"; } //link to the previous page echo "<br/><a href='javascript:self.history.back();'>Go Back</a>"; } else { // if all the fields are filled (not empty) //insert data to database $result = mysqli_query($mysqli, "INSERT INTO books(title,author,owner,isbn) VALUES('$title','$author','$owner','$isbn')"); //display success message echo "<font color='green' style='font-size: 2em;'>Book added successfully."; echo "<br/><a href='index.php' style='font-size: 2em;'>View Result</a>"; } } ?> </body> </html>
add.htmlEdit
<html> <head> <title>Add Book</title> <link rel="stylesheet" href="style.css"> </head> <body> <a href="index.php" style="font-size: 2em;">Home</a> <br/><br/> <form action="add.php" method="post" name="form1"> <table width="25%" border="0"> <tr> <td>Title</td> <td><input type="text" name="title"></td> </tr> <tr> <td>Author</td> <td><input type="text" name="author"></td> </tr> <tr> <td>Owner</td> <td><input type="text" name="owner"></td> </tr> <tr> <td>ISBN</td> <td><input type="text" name="isbn"></td> </tr> <tr> <td></td> <td><input type="submit" name="Submit" value="Add"></td> </tr> </table> </form> </body> </html>