Here's some tips/snippets for PHP7 (knowledge of PHP5 required).
Please install Github Mermaid extension for Firefox/Chrome to display the diagrams in this document.
-
print_r(); -
implode(', ', $myArray); -
return array_unique($myArray);; -
base_convert($number, $fromBase, $toBase)returns a string; -
unlink($file)returns true if the$filehas been deleted; -
move_uploaded_file($_FILES["photo"]["tmp_name"], "upload/" . $filename);to move an upload file from its temporary state on the server; -
filter_var($field, FILTER_{SANITIZE_STRING,SANITIZE_EMAIL,VALIDATE_EMAIL})is a very useful dummy tester. You also can try:$field = filter_var(trim($field), FILTER_SANITIZE_STRING); $okField = (filter_var($field, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp" => "/^[a-zA-Z\s]+$/")))) ? $field : FALSE;
-
$_REQUESTis a superglobal variable containing the values of other global variables; -
you can set your own custom error handler with
set_error_handler(); REMINDER:trigger_error()throws the error; -
class MyNewException extends Exception {}; -
mysqli_real_escape_string()to provide security against injections.
<=> is a combined comparison operator, returns 0 if both operands are equal, 1 if the left is greater:
echo 1 <=> 1; // 0
echo 1.5 <=> 2.5; // -1
echo "y" <=> "x"; // 1It's a shorthand where you need to use a ternary operator in conjunction with isset() function:
$name = isset($_GET['name']) ? $_GET['name'] : 'anonymous';
$name = $_GET['name'] ?? 'anonymous';REMINDER: here's the syntax:
foreach($colors as $value){ {...} }
foreach($superhero as $key => $value) { {...} }function selfMultiply(&$number){
$number *= $number;
return $number;
}It's recommended to use the require() statement if you're including the library files of files containing the functions and configuration variables that are essential for running your application, such as database configuration file.
class MyClass
{
public function __construct(){
echo __CLASS__ . " was initiated!<br>";
}
public function __destruct(){
echo __CLASS__ . " was destroyed!<br>";
}
}
$obj = new MyClass;
unset($obj);class HelloClass
{
public static $greeting = "Yo!";
public static function sayHello(){
echo self::$greeting;
}
}
echo HelloClass::$greeting; // Strict Warning
$hello->sayHello(); // Yo!NOTE: PDO supports named placeholders (not MySQLi).
$sql = "INSERT INTO persons (first_name, last_name, email) VALUES (?, ?, ?)";
if ($stmt = mysqli_prepare($link, $sql)){
/* sss = string, string, string; type definition also accepts:
* b: binary
* d: double
* i: integer */
mysqli_stmt_bind_param($stmt, "sss", $first_name, $last_name, $email);
$first_name = "Hermione";
$last_name = "Granger";
$email = "hermionegranger@mail.com";
mysqli_stmt_execute($stmt);
} else {
echo "ERROR: Could not prepare query: $sql . " . mysqli_error($link);
}
mysqli_stmt_close($stmt);
mysqli_close($link);config.php:- database heuristics;
- open a connection with
mysqli_connect()(with a die onfalse$linkwith amysqli_connect_error()stack);
- index.php: landing page with using Bootstrap:
require_once "config.php"(this line must be at the beginning of each CRUD files);- a
.page-headerwith a.btnlink tocreate.php; - a table from:
mysqli_query($link, "SELECT * FROM employees");(otherwise display an errormysqli_error($link));- and
mysqli_num_rows($result)not zero; - using
mysqli_fetch_array($result)to create the cells of a row while there's data; - at the end of each row, three icons like
"<a href='RUD.php?id=".$row['id']."' data-toggle='tooltip'>"whereRUDisread,update,deleterespectively; - at the end of the table, IMPORTANT: don't forget to free the result set
mysqli_free_result($result);
- and finally, a
mysqli_close($link)(this line must be at the end of each CRUD files).
create.php:- start the processing form data with
if ($_SERVER["REQUEST_METHOD"] == "POST"):- open connection;
- for each input:
- trim data string from
$_POST; - set error variable if
empty(); - (optional) set error variable if not valid input (check with
filter_var()orctype_digit()); - set variable from input if valid.
- trim data string from
- if not error variable detected:
- prepare statement for
INSERT INTO; - bind variables to the statement and set the parameters;
- attempt to execute the statement and
header("location: index.php");exit();to redirect to the landing page on success; - close the statement.
- prepare statement for
- close connection;
- in the HTML code, create a
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="POST">and for each<input>or<textarea>:.form-group;<label>;<input>with.form-control;<span>with the error variable.
- add a
Cancellink toindex.phpafter the<input type="submit">.
- start the processing form data with
- the RUD files called from each row in the table in
index.phpand the row index is passed in the URL (GET method):read.php:header("location: error.php");exit();if the row index in$_GET["id"]is empty;- trim the index;
- open connection (
require_once "config.php";); - prepare statement
SELECT * FROM employees WHERE id = ?; - bind variables to the statement and set the parameters;
- attempt to execute the statement;
- retrieve field value if
mysqli_num_rows($result) == 1(otherwiseerror.phpredirect); - close the statement;
- close the connection;
- in the HTML code, create a simple form to display the fields:
.form-group;<label>with the name of the column;.form-control-staticwith the field value.
- at the end of the form, add a Back
.btnto aimindex.php.
update.php(inspired byindex.phpandread.php):header("location: error.php");exit();if the row index in$_{POST,GET}["id"]is empty;- POST case:
- open connection (
require_once "config.php";); - for each input:
- set error variable if
empty(); - (optional) set error variable if not valid input (check with
filter_var()orctype_digit()); - set variable from input if valid.
- set error variable if
- if not error variable detected:
- prepare statement for
UPDATE employees SET name=?, address=?, salary=? WHERE id=?; - bind variables to the statement (in a
sssipattern) and set the parameters; - attempt to execute the statement and
header("location: index.php");exit();to redirect to the landing page on success; - close the statement.
- prepare statement for
- open connection (
- close the connection.
- GET case:
- trim the index;
- open connection (
require_once "config.php";); - prepare statement
SELECT * FROM employees WHERE id = ?; - bind variables to the statement and set the parameters;
- attempt to execute the statement;
- retrieve field value if
mysqli_num_rows($result) == 1(otherwiseerror.phpredirect); - close the statement;
- close connection.
- in the HTML code, create a
<form action="<?php echo htmlspecialchars(basename($_SERVER['REQUEST_URI']));?>" method="POST">and for each<input>or<textarea>:.form-group;<label>;<input>with.form-control;<span>with the error variable.
- add a
Cancellink toindex.phpafter the<input type="submit">.
delete.php(inspired bycreate.phpbut GET catchidto pass unto the POST'd form via a hidden input):header("location: error.php");exit();if the row index in$_{POST|GET}["id"]is empty;- open connection (
require_once "config.php";); - prepare statement
DELETE FROM employees WHERE id = ?; - bind variables to the statement and set the parameters (BEWARE:
ifor id); - attempt to execute the statement;
- in the HTML code:
- create a
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="POST">:<div class="alert alert-danger fade in">;<input type="hidden" name="id" value"<?php echo trim($_GET["id"]);?>"/>;.btntoindex.phpas No or<input type="submit">as Yes.
- create a
error.php: just a go back toindex.php.
REMEMBER: open the connection with require_once(config.php) AND manually close it in each page of the CRUD application.
NOTE: no need to prepare a SQL statement in index.php as the SELECT * as no variables. Since the result set may contain only one row, we don't need a while loop but a mysqli_fetch_array($result, MYSQLI_ASSOC).
config.php;register.php:- start the processing form data with
if ($_SERVER["REQUEST_METHOD"] == "POST"):- open connection (
require_once "config.php"); - for
username:- trim data string from
$_POST; - set error variable if
empty(); - in a
SELECTstatement,mysqli_stmt_store_result($stmt)and check if the row exists:- set error variable if
1; - set variable from input if valid.
- set error variable if
- trim data string from
- for
passwordandconfirm_password:- trim data strings from
$_POST; - set error variable if
passwordisempty()or too short; - set error variable if
confirm_passwordis:empty()or;- different from
passwordwhen nopassworderror;
- trim data strings from
- if not error variable detected:
- prepare statement for
INSERT INTO; - bind variables to the statement and set the parameters: BEWARE: use the
password_hash($password, PASSWORD_DEFAULT)to create a password hash; - attempt to execute the statement and
header("location: login.php")to redirect to the login page on success; - close the statement.
- prepare statement for
- close connection.
- open connection (
- in the HTML code, create a
<form action"<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="POST">and for each<input>s (ieusername,passwordandconfirm_password):.form-group;<label>;<input>with.form-control;<span>with the error variable.
- add a link to
login.phpafter the<input type="{submit|reset}">.
- start the processing form data with
login.php:session_start();header("location: welcome.php");exit;if the user is already logged in ieisset($_SESSION["loggedin"]) && $_SESSION["loggedin"] === true);- start the processing form data with
if ($_SERVER["REQUEST_METHOD"] == "POST"):- open connection (
require_once "config.php"); - for each input:
- trim data string from
$_POST; - set error variable if
empty(); - set variable from input if valid.
- trim data string from
- if not error variable detected:
- prepare statement for
SELECT id, username, password FROM users WHERE username = ?; - bind variables to the statement and set the parameters (
$hashed_passwordis bound to thepasswordfrom the table); - attempt to execute the statement; here's 3 cases:
- "No account found" as
usernameerror if notmysqli_stmt_fetch($stmt); - "No valid password" as
passworderror ifpassword_verify($password, $hashed_password); - on success:
session_start();$_SESSION["loggedin"] = true;$_SESSION["id"] = $id;- `$_SESSION["username"] = $username;
header("location: welcome.php").
- "No account found" as
- close the statement.
- prepare statement for
- close connection.
- open connection (
- in the HTML code, create a
<form action"<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="POST">and for each<input>s (ieusernameandpassword):.form-group;<label>;<input>with.form-control;<span>with the error variable.
- add a link to
register.phpafter the<input type="submit">.
welcome.php(dummy hello page):session_start();header("location: login.php");exit;if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true);- in the HTML code:
- use
echo htmlspecialchars($_SESSION["username"])to print the logged user's name; - set a link to
reset-password.php; - set a link to
logout.php.
- use
logout.php(to kill the session and redirect to thelogin.phppage):session_start()- reset all the variables with
$_SESSION = array(); session_destroy();header("location: login.php");exit;.
reset-password.php:session_start();header("location: login.php");exit;if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true);- start the processing form data with
if ($_SERVER["REQUEST_METHOD"] == "POST"):- open connection (
require_once "config.php"); - for
new_passwordandconfirm_password:- trim data string from
$_POST; - set error variable if
new_passwordisempty()or too short; - set error variable if
confirm_passwordis:empty()or;- different from
new_passwordwhen nonew_passworderror;
- set variable from input if valid.
- trim data string from
- if not error variable detected:
- prepare statement for
UPDATE users SET password = ? WHERE id = ?; - bind variables to the statement and set the parameters: BEWARE: use the
password_hash($new_password, PASSWORD_DEFAULT)to create a password hash and use the session id as id ie$_SESSION["id"]; - attempt to execute the statement, on success:
session_destroy();header("location: login.php");exit()to redirect to the login page.
- close the statement.
- prepare statement for
- close connection.
- open connection (
- in the HTML code, create a
<form action"<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="POST">and for each<input>s (ienew_passwordandconfirm_password):.form-group;<label>;<input>with.form-control;<span>with the error variable.
- add a link to
welcome.phpafter the<input type="submit">.
Use session_start(); at the beginning of the files you want to make private (welcome.php, reset_password.php...); don't use it on public pages like register.php except login.php to redirect to the welcome.php page if logged in (so you need to be able to check the $_SESSION["loggedin"] status); NOTE: the session variables are set when the login.php POST processing is a success (account found, valid password).
Let's see what's new in a CRUD application or a Login system if we use the mysqli OO interface:
mysqli_connect():new mysqlias$mysqli;mysqli_connect_error():$mysqli->connect_error;mysqli_query():$mysqli->query()as$result;mysqli_num_rows():$result->num_rows;mysqli_fetch_array($result, MYSQLI_ASSOC):$result->fetch_array(MYSQLI_ASSOC);mysqli_free_result():$result->free();mysqli_error():$mysqli->error;mysqli_close():$mysqli->close();mysqli_prepare():$mysqli->prepare()as$stmt;mysqli_stmt_bind_param():$stmt->bind_param();mysqli_stmt_execute():$stmt->execute();mysqli_stmt_store_result():$stmt->store_result();mysqli_stmt_get_result():$stmt->get_result()as$result;mysqli_stmt_close():$stmt->close().
Let's see what's new in our previous examples when you use PDO. First, here's the new config file:
<?php
define('DB_SERVER', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', 'root');
define('DB_NAME', 'crud_demo'); // or whatever
/* Attempt to connect to MySQL database */
try{
$pdo = new PDO("mysql:host=" . DB_SERVER . ";dbname=" . DB_NAME, DB_USERNAME, DB_PASSWORD);
// Set the PDO error mode to exception
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
die("ERROR: Could not connect. " . $e->getMessage());
}
?>Here's what changes in the core of the program with our $pdo instance (compared to the OO format):
$mysqli->query()as$result:$pdo->query()as $result;$result->num_rows:$result->rowCount();$result->fetch_array(MYSQLI_ASSOC):$result->fetch(PDO::FETCH_ASSOC);$result->free():unset($result);$mysqli->error: use acatch(PDOException $e)after atryblock;$mysqli->close():unset($pdo);$mysqli->prepare()as$stmt:$pdo->prepare()as$stmt;$stmt->bind_param():$stmt->bindParam(":name", $param_name); BEWARE::format as a prepared statement use:nameinstead of a?;$stmt->execute():$stmt->execute();$stmt->store_result(): OBSOLETE: there's absolutely no point in using neitherstore_result()norbind_result()with PDO;$stmt->get_result()as$result: OBSOLETE: you get the$stmt->rowCount()directly after$stmt_execute();$stmt->close():unset($stmt).
Digest by Martial BONIOU, 2021