Thursday, December 27, 2018

The Work Around Solution to Composer Broken When PHP 7.3 Installed via Homebrew

How to Add Constants in Larvel 5

There was an error came out after I upgraded PHP version to 7.3. When I execute composer --version or composer update, a lot of error messages shown:

PHP Warning: preg_match(): JIT compilation failed: no more memory in 
phar:///usr/local/bin/composer.phar/vendor/symfony/console/Application.php on line 755
   :
   :

The composer was broken!

This is a known PHP 7.3 bug.

After searching the solution, somebody suggests a work around below:

  1. Edit php.ini file (locate at /usr/local/etc/php/7.3/php.ini).

  2. Disable PHP PCRE JIT compilation:

    [Pcre]
    ;pcre.jit=1 
    pcre.jit=0
    

Then the composer is alive again! It’s great!
Remember to change back to the original setting while the bug fix.

Tuesday, December 4, 2018

Database Connection Setup in Laravel

How to Add Constants in Larvel 5

Lraravel supports MySQL, PostgreSQL, SQL Server and SQLite database. Database setup is stored in .env file and config/database.php.

The priority of database setup information is:
.env > config/database.php

Setup procedure for database connection:

SQLite:

  1. Add a empty sqlite database file.
    > touch database/database.sqlite
  2. Comment out:
   #DB_CONNECTION=mysql 
   #DB_HOST=127.0.0.1
   #DB_PORT=3306
   #DB_DATABASE=homestead
   #DB_USERNAME=homestead
   #DB_PASSWORD=secret
  1. Add commends to .env file:
   DB_CONNECTION=sqlite  
   DB_DATABASE=database/database.sqlite
  1. php artisan migrate

MySQL:

  1. Add a new database in mysql server.
  2. Edit .env file:
   DB_CONNECTION=mysql 
   DB_HOST=127.0.0.1
   DB_PORT=3306
   DB_DATABASE=xxxxx
   DB_USERNAME=xxxxx
   DB_PASSWORD=xxxx
  1. php artisan migrate
   Migration table created successfully.
   Migrating: 2014_10_12_000000_create_users_table
   Migrated:  2014_10_12_000000_create_users_table
   Migrating: 2014_10_12_100000_create_password_resets_table
   Migrated:  2014_10_12_100000_create_password_resets_table

Using artisan command to create a database in mysql.

What if I want to create a database in Laravel?
Please refer to this article Using an Artisan command to create a database in Laravel or Lumen

Monday, December 3, 2018

The Installation of Laravel

How to Add Constants in Larvel 5

Laravel is a PHP framework for web development. Here goes the installation procedure.

1. Install Composer (if not installed)

> brew install composer

2. Install Laravel

> composer global require laravel/installer

3. Add path to $PATH

Edit and add the following code to the shell configuration file:

  • zsh: .zshrc

  • bash: .bash_profile

# Laravel
export PATH="$HOME/.composer/vendor/bin:$PATH"

Close and restart the terminal.

4. Start coding

> cd (your laravel project directory)
> laravel new (project name)
  :
  :
> cd (project name)
> php artisan serve

-> open browser
-> http://localhost:8000

Tuesday, November 13, 2018

How to Upload Multiple Files in PHP

How to Add Constants in Larvel 5

When we upload multiple files using PHP, the $_FILES variable as an array is not as a usual form as we think. It is formed by using file’s attribute as the key, not the index number. Thus, we can not loop through $_FILES variable with PHP 'foreach' loop statement.

1. $_FILES Variable Structure

The $_FILES variable is formed as follows:

array(5) {
["name"]=> array(2) { [0]=> string(17) "IMG_2586w_1x1.JPG"
                      [1]=> string(17) "IMG_2541w_1x1.JPG"
                    }
["type"]=> array(2) { [0]=> string(10) "image/jpeg"
                      [1]=> string(10) "image/jpeg"
                    }
["tmp_name"]=> array(2) { [0]=> string(26) "/private/var/tmp/phpwJBYnV"
                          [1]=> string(26) "/private/var/tmp/phpzbodce"
                        }
["error"]=> array(2) { [0]=> int(0)
                       [1]=> int(0)
                     }
["size"]=> array(2)  { [0]=> int(952096)
                       [1]=> int(879215)
                     }
}

This form of array needs to be converted to the form below, where the file’s index is the key instead of file’s attribute. This step is necessary for going to further process.

array(2) {
[0]=> array(5) { ["name"]=> string(17) "IMG_2586w_1x1.JPG"
                 ["type"]=> string(10) "image/jpeg"
                 ["tmp_name"]=> string(26) "/private/var/tmp/phpt3l7ct"
                 ["error"]=> int(0)
                 ["size"]=> int(952096)}
[1]=> array(5) { ["name"]=> string(17) "IMG_2541w_1x1.JPG"
                 ["type"]=> string(10) "image/jpeg"
                 ["tmp_name"]=> string(26) "/private/var/tmp/phpPIhTD2"
                 ["error"]=> int(0)
                 ["size"]=> int(879215)}
}

2. Converting Function

A converting function is written as follows:

/* convert multiple uploading files array $_FILES 
   to an array with an index as the key.
   from : [attribute] => [ [index] => [value], [index] => [value] ]
   to:    [index] => [ [attribute] => [value], [attribute] => [value] ]
*/
function convert_upload_file_array($upload_files) {
  $converted = array();

  foreach ($upload_files as $attribute => $val_array) {
    foreach ($val_array as $index => $value) {
      $converted[$index][$attribute] = $value;
    }
  }
  return $converted;
}

3. Multiple Uploading Files Setup

Now, the multiple files uploading process can be started from a upload form page:

upload.html

<form action="product.php" method="post" enctype="multipart/form-data">
  <input type="file" class="form-control-file" name="prod_pic[]" id="prod_pic[]">
  <button type="submit" class="btn btn-primary">Save Prodcut Info</button>
</form>

Note that the 'name' property of the <input> tag should be added an array tag '[]'. In addition, enctype="multipart/form-data" should be added in the tag in order to enable the file uploading function. Thus, the $_FILES variable can be an array to carry multiple files information.

<form .... enctype="multipart/form-data">
     :
  <input ... name="prod_pic[]">
  <input ... name="prod_pic[]">
     :
</form>  

Then, the product.php converts $_FILE variable and save files to the destination path.

product.php

<?php
  if (isset($_FILES['prod_pic'])) {
    $pics = convert_upload_file_array($_FILES['prod_pic']);

    foreach ($pics as $key => $pic) {
      $target = "images/{$pic['name']}";
      move_uploaded_file($pic['tmp_name'], $target);
    }
  }
?>

Monday, November 12, 2018

Insert and Update An Image to MySQL Server Field with Blob Data Type in PHP

How to Add Constants in Larvel 5

Normally the images are stored in a file directory, not in the database. It is because that storing image data in database will make database bulky. In addition, there is some techniques to take care of. How to store and retrieve an image from MySQL server? Here is how:

1. Blob data type in MySQL server

First, create a blob type field in MySQL server:

mysql> describe products;
+-----------------+-----------------------+------+-----+---------+----------------+
| Field           | Type                  | Null | Key | Default | Extra          |
+-----------------+-----------------------+------+-----+---------+----------------+
| prod_id         | mediumint(8) unsigned | NO   | PRI | NULL    | auto_increment |
| prod_pic        | mediumblob            | YES  |     | NULL    |                |
| prod_pic_type   | varchar(11)           | YES  |     | NULL    |                |
+-----------------+-----------------------+------+-----+---------+----------------+

2. Insert into MySQL server:

Add enctype="multipart/form-data" in the <form> tag in order to enable the file upload functionality.
Set the type to ‘file’ for <input> tag.

Upload image file form:

<form action="index.php" method="post" enctype="multipart/form-data">
  <input type="file" name="prod_pic" accept=".jpg, .jpeg, .png">
  <button type="submit">Submit</button>  
</form>

Insert image into MySQL server in index.php

$prod_pic = $mysqli->real_escape_string(file_get_contents($_FILES['prod_pic']['tmp_name']));
$prod_pic_type = $_FILES['prod_pic']['type'];
 :
 :
$sql = "UPDATE products 
        SET prod_pic      = '{$prod_pic}',
            prod_pic_type = '{$prod_pic_type}'
        WHERE prod_id = {$prod_id}";
$mysqli->query($sql) or die($mysqli->connect_error);
$mysqli->close(); 

As you can see, the key part is:

file_get_contents($_FILES['prod_pic']['tmp_name'])

and

$mysqli->real_escape_string(......)

3. Retrieve an image from MySQL server:

There are two methods to retrieve images from MySQL server:

A. Get image with a function.

Somewhere in the page: (using Smarty template engine)

 <img src="get_image.php?prod_id={$product.prod_id}" />

get_image.php

<?php
  $mysqli = new mysqli( _DBHOST, _DBUSER, _DBPASSWD, _DBNAME);
  if ($mysqli->connect_error){
    die ('DB Error: ('.$mysqli->connect_errno.' )'.$mysqli->connect_error);
  } else {
    $mysqli->set_charset('utf8');
  }

  $prod_id = isset($_REQUEST['prod_id']) ? filter_var($_REQUEST['prod_id'], FILTER_SANITIZE_NUMBER_INT) : 0;

  $sql = "SELECT prod_pic, prod_pic_type FROM products WHERE prod_id = '{$prod_id}'";
  $result = $mysqli->query($sql) or die($mysqli->connect_error);
  $product = $result->fetch_assoc();
  $mysqli->close();

  header("Content-type: ".$product['prod_pic_type']);
  echo $product['prod_pic'];
?>

The last two lines of code is the key part.

header("Content-type: ".$product['prod_pic_type']);  
echo  $product['prod_pic'];

B. Using base64 encode to show the image

<img src="data:image/{$product.prod_pic_type};base64,{base64_encode($product.prod_pic)}" />

( using Smarty template engine )

4. Conclusion

Method B seems to be a better choice since it does not need to retrieve data from server twice as method A does. Also, method B is more concise and cleaner. It’s only one line of code and an extra PHP function is not necessary.

Monday, November 5, 2018

Deploy A PHP MySQL Application to Heroku

How to Add Constants in Larvel 5

I usually put my apps on Heroku since I have developed apps in Ruby on Rails. It’s a reliable PaaS service and provides a free dyno for users. Therefore, Heroku is an excellent place to show your apps to others.

Heroku is known as a very friendly PaaS service for Ruby on Rail. Just few git commends, an app in RoR can be easily deployed to Heroku. Now it supports PHP as well. The following steps are the real operations of the deployment of my app to Heroku. It seems that very simple and similar to the deployment of RoR, only clearDB (MySQL) needs to be installed manually.

Install Composer

Composer is PHP’s package manager. Using brew to install composer is the easiest way in macOS.

$ brew install composer

Add An Empty composer.json File in the Root Directory

The Heroku PHP Support will be applied to applications only when the application has a file named composer.json in the root directory. Just add a text file with a pair of curly braces in the root directory if there is no depending package.

composer.json

{}

git commit

$ git add .
$ git commit -m ‘add composer.json file’

Heroku Login

Follow the instruction from: Getting Started with PHP : Set-up

$ heroku login
heroku: Enter your login credentials
Email [chxxxxxx@gmail.com]:
Password: *************
Logged in as chxxxxxx@gmail.com

Deploy the App

Create An App Name

$ heroku create
Creating app... done, ⬢ dry-crag-62595
https://dry-crag-62595.herokuapp.com/ | https://git.heroku.com/dry-crag-62595.git

or

$ heroku create [app_name] 

[app_name]: the name of the app

Show The git remote Configuration

$ git remote -v
heroku  https://git.heroku.com/dry-crag-62595.git (fetch)
heroku  https://git.heroku.com/dry-crag-62595.git (push)
origin  http://github.com/chaoyee/php_crud_demo.git (fetch)
origin  http://github.com/chaoyee/php_crud_demo.git (push)

Deploy the App

$ git push heroku master
Enumerating objects: 300, done.
Counting objects: 100% (300/300), done.
Delta compression using up to 8 threads
Compressing objects: 100% (295/295), done.
Writing objects: 100% (300/300), 1.03 MiB | 10.37 MiB/s, done.
Total 300 (delta 93), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> PHP app detected
remote: -----> Bootstrapping...
remote: -----> Installing platform packages...
remote: NOTICE: No runtime required in composer.lock; using PHP ^7.0.0
remote: - nginx (1.8.1)
remote: - php (7.2.11)
remote: - apache (2.4.34)
remote: -----> Installing dependencies...
remote: Composer version 1.7.2 2018-08-16 16:57:12
remote: -----> Preparing runtime environment...
remote: NOTICE: No Procfile, using 'web: heroku-php-apache2'.
remote: -----> Checking for additional extensions to install...
remote: -----> Discovering process types
remote: Procfile declares types -> web
remote:
remote: -----> Compressing...
remote: Done: 16.2M
remote: -----> Launching...
remote: Released v3
remote: https://dry-crag-62595.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/dry-crag-62595.git
* [new branch] master -> master

View Logs

If there is any error, we can view the log for more information.

$ heroku logs --tail

2018-11-05T08:24:32.207801+00:00 app[api]: Release v1 created by user chaoyee22@gmail.com
2018-11-05T08:24:32.313450+00:00 app[api]: Enable Logplex by user chaoyee22@gmail.com
2018-11-05T08:24:32.207801+00:00 app[api]: Initial release by user chaoyee22@gmail.com
2018-11-05T08:29:59.153108+00:00 heroku[web.1]: State changed from starting to up
:
:

Define A Procfile

A Procfile is a text file in the root directory of the application which defines process types and explicitly declares what command should be executed to start the application.

Procfile:

web: heroku-php-apache2

Change Apps Name

Since Heroku generates a random name for the app, we can change it if needed.

$ heroku apps:rename [newname]
$ git remote rm heroku
$ git remote add heroku https://git.heroku.com/[newname].git

[newname]: the new name of the app.

Create ClearDB (MySQL)

ClearDB is a database service based on MySQL Server for Heroku.

$ heroku addons:create cleardb:ignite

Creating cleardb:ignite on ⬢ php-crud-demo... free
Created cleardb-animated-20025 as CLEARDB_DATABASE_URL
Use heroku addons:docs cleardb to view documentation

Get the database url:

$ heroku config | grep CLEAR_DATABASE_URL

=== php-crud-demo Config Vars

CLEARDB_DATABASE_URL: mysql://bf4e1f86266e0e:xxxxxxxx@[us-cdbr-iron-east-01.cleardb.net/heroku_340c60cc91508db?reconnect=true

The format of CLEARDB_DATABASE_URL is:
CLEARDB_DATABASE_URL =>
mysql://[username}:[password]@[host]/[database name]?reconnect=true

Login to MySQL Server

$ mysql -u bf4e1f86266e0e -h us-cdbr-iron-east-01.cleardb.net -p
password: ******
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 114469329
Server version: 5.5.56-log MySQL Community Server (GPL)
 
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

Now, the MySQL Server is installed.

Create Tables and Insert Test data

Using Sequel Pro, MySQL Workbench, phpMyAdmin or other applications to execute sql script and create tables and insert test data.

Adding following PHP code to database configuration (ex. config.php) in the Application in order to connect to MySQL server.

<?php  
$url = parse_url(getenv("CLEARDB_DATABASE_URL"));  
define('_DBHOST', $url["host"]);  
define('_DBUSER', $url["user"]);  
define('_DBPASSWD', $url["pass"]);  
define('_DBNAME', substr($url["path"], 1));

$mysqli = new mysqli( _DBHOST, _DBUSER, _DBPASSWD, _DBNAME);
?>

Deploy Application to Heroku

$ git add .
$ git commit -m ‘add db connection’
$ git push heroku master

Open App at Heroku

$ heroku open

Now, the app starts up in the browser from Heroku service.
Here is the demo app php-crud-demo.

Wednesday, October 31, 2018

How to Post Codebase on GitHub without Revealing Database Login and Password Parameters in PHP

How to Add Constants in Larvel 5

It’s quite simple.

Inside configuration file congif.php:

<?php 
  include("secret.php");
  $password = PASSWORD;  //defined in secret.php
  $username = USERNAME;
?>

Inside secret.php

<?php
  define('PASSWORD', 'example_password');    
  define('USERNAME', 'example_username') ;   
?>

Inside .gitignore, just add:

path/secret.php

path: the path to secret.php

Therefore, secret.php will not be uploaded to GitHub and keep these secret parameters safe!

Tuesday, October 16, 2018

Do Not Use Cookies as The Way We Use Variables

How to Add Constants in Larvel 5

Considering the code as follows:

<?php
  setcookie("test", "1", time() + 3600);  // set cookie
  echo $_COOKIE["test"];
?>

The result shows ‘undefined index’ after execution:

Notice: Undefined index: test in /xxx/index.php on line 2

Why is this happened? Has cookie not been set?
No, it is because the browser hasn’t sent a HTTP request to the server, so the browser hasn’t got the request cookie yet.

According to the document rfc6252 from Internet Engineering Task Force (IETF), it explains how cookies work at the introduction:

Using the Set-Cookie header field, an HTTP server can pass name/value pairs and associated metadata (called cookies) to a user agent. When the user agent makes subsequent requests to the server, the user agent uses the metadata and other information to determine whether to return the name/value pairs in the Cookie header.

Hmm~~, what does that mean exactly?

Let’s open the Chrome Developer Tools and show you how cookies works.

I wrote three php programs as follows:

  1. set_cookie.php: to set cookie ‘test’ and value as 1.
<?php
  setcookie("test", "1", time() + 3600);
  echo $_COOKIE["test"];
?>
  1. show_cookie.php: show the value of cookie ‘test’.
<?php
  echo $_COOKIE["test"];
?>
  1. delete_cookie.php: delete the cookie 'test.
<?php
  setcookie("test", "", time() - 3600);
?>

Check the cookies in Chrome Devtools

  1. Now, let’s start to run set_cookie.php and see what will happen through Chrome devtools. In Chrome devtools windows, there is a Response Cookie ‘test’ as 1 shown in the ‘Cookies windows’. The cookie ‘test’ is not shown at the side of ‘Request Cookies’ meaning that the browser hasn’t received cookie data from server yet. So, it shows ‘undefined index’ message in the browser as expected.

run set_cookie.php
set_cookie

  1. Next, let’s run show_cookie.php to send a HTTP request to the server and show the cookie ‘test’. It shows cookie ‘test’ and value as 1 at the side of ‘Request Cookies’. As expected, the browser shows ‘1’, the value of cookie ‘test’.

run show_cookie.php
show_cookie

  1. let’s run delete_cookie.php to delete the cookie ‘test’. It shows a ‘delete’ value at the side of ‘Response Cookies’. The cookie ‘test’ and value 1 is still at the side of ‘Request Cookies’.

delete_cookie.php
delete_cookie

  1. Let’s run show_message.php again to send a HTTP request to the server. It also send the response cookies to the server and delete the cookie ‘test’. The cookie ‘test’ has disappeared at both sides of the ‘Cookies windows’. Therefore, it shows ‘undefined index’ in the browser again.

show_cookie again
show_cookie again

Use cookies for storing data while variables for calculation.

As shown above, the behavior of cookies are different from variables. We can not use cookies just as the way we use variables.

Do not make the calculation according to cookies values if a HTTP request hasn’t been sent to the server. Using variables to do so to make sure the correct calculation.

Friday, October 12, 2018

Four Ways to Show Message Bar After Redirecting to Another Page in PHP

How to Add Constants in Larvel 5

There are four ways to show a message bar up front of the web page when needed in PHP. As shown below, the main function of the message bar is to notify users a warning message.

Message Bar

Four ways to build up a message bar are as follows:

1. Passing message by assigning a smarty variable.

index.php

<?php    
         :
$msg = 'Please login!';
         :
$smarty->assign('msg', $msg);    
// redirect to index.html
$smarty->display('index.html'); 
  
?> 

index.html

{if (isset($msg)}
  {$msg}
{/if}

It works very good except one situation: program redirects to another page and exits the original one before Smarty variable has been assigned.

Considering a situation below:

<?php
         :
if !login() {
  $msg = 'Please login!';
  header("location:login.php");
  exit;
}
         :
$smarty->assign('msg', $msg);    
// redirect to index.html
$smarty->display('index.html'); 
?>

Normally, we put $smarty->assign('msg', $msg); at the end of index.php file. It will not work in the above example since a header() command redirects to the login page and exits index.php. $msg will not be assigned to a Smarty variable.

2. Query string parameters

ex.
shopping_cart.html

<a href="index.php?msg=Cart is empty!">Empty Cart</a>  

index.php

$msg = isset($_REQUEST['msg']) ? 
  filter_var($_REQUEST['msg'], 
  FILTER_SANITIZE_MAGIC_QUOTES) : '';
echo $msg;

It shows a long line of words in the url windows of the browser. I really don’t like it. It is not a good way to do it.

ex.
index.php

      :
setcookie('msg', 'Hello! New user!', time() + 365*86400);
      :
function show_message() {
  $msg = $_COOKIE['msg'];
  setcookie('msg', '', time() - 3600);
  return $msg;
} 

index.html

{if isset($smarty.cookies.msg)}
  {show_message()}
{/if}  

It seems to be a good solution, However, it resulted in some unexpected error while using cookie method. It was not stable when I tested it. The browser could not render the correct page. I recommend not to use it.

4. Using Session

ex.
index.php

<?php
session_start();
       :
       :
write_message('Hello! New user!');
header("location:{$_SERVER['HTTP_REFERER']}");
  
function write_message($msg = '') {
  $_SESSION['msg'] = $msg;
}

function show_message() {
  $msg = $_SESSION['msg'];
  unset($_SESSION['msg']);
  return $msg;
}
?> 

index.html

{if isset($smarty.session.msg)}
  <div class="alert alert-danger alert-dismissible show" role="alert">
    {show_message()}
    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
{/if} 

The session method is the most recommended method to show a message bar at the redirected page. It’s quite easy, simple and no restriction at all. You can insert write_message('xxxxx') anywhere in code and it will show up in the redirected page. The only one drawback to criticize is that it consumes server’s resources since session runs on the server.

Tuesday, September 25, 2018

Few Notes about TCPDF - An Open Source PHP class for generating PDF documents

Few Notes about TCPDF - An Open Source PHP class for generating PDF documents

TCPDF is an open source PHP class for generating PDF documents. It is easy to install and setup as well as many options available. There are few things worth to be noticed in my experience of usage. Here are some:

1. Installation

To install TCPDF class is easy.

  1. Download all files from TCPDF’s github.
  2. Create a directory class under the main directory of the Site.
  3. Create a directory class/tcpdf.
  4. Copy all files to class/tcpdf.
  5. Add a line of code in the beginning of the php file:
    require_once "class/tcpdf/tcpdf.php";
  6. Have fun!

2. Traditional Chinese support

The default setting of TCPDF does not support Traditional Chinese character because it lacks of fonts in Traditional Chinese. We have to add the font files manually.

  1. Download font file ‘Droid Sans Fallback’ and ‘msungstdlight’.
  2. Add two font files to class/tcpdf/fonts.
  3. Open config/tcpdf_config.php and change two settings:
    define ('PDF_FONT_NAME_MAIN', 'helvetica');
       to
    define ('PDF_FONT_NAME_MAIN', 'msungstdlight');
    
    define ('PDF_FONT_NAME_DATA', 'helvetica');
    	to
    define ('PDF_FONT_NAME_DATA', 'msungstdlight');
    

p.s Here explains how to generate TrueTypeUnicode font files from DroidSansFallback.ttf font file.

3. A bug fixed while using PHP 7.2

When using PHP 7.2, TCPDF version 6.2.12 shows the error message:

Deprecated: The each() function is deprecated. 
This message will be suppressed on further calls in /Users/xxx/Sites/mini_shop/class/tcpdf/tcpdf.php on line 16544
  
TCPDF ERROR: Some data has already been output, 
can't send PDF file

Since each() function is deprecated after PHP version 7.2, the code must be modified in order to fit the new version. Fortunately, somebody has posted the solution. It works again just to replace three lines of code in tcpdf.php as follows:

-  while (list($key, $val) = each($prop)) {
+  foreach($prop as $key => $val) {
-  while (list($id, $name) = each($attr_array[1])) {
+  foreach($attr_array[1] as $id => $name) {
-  while (list($id, $name) = each($style_array[1])) {
+  foreach($style_array[1] as $id => $name) {

Replace each() function with foreach() function, and that’s it!

Sunday, September 23, 2018

A Simple CRUD App in PHP

A Simple CRUD App in PHP
The “CRUD” means Create, Read, Update, Delete and is the most frequent functions used in daily operation. Here shows a simple CRUD app in PHP for reference. Let’s follow the methods explained in the article of my blog “Building PHP Web Apps Without Framework” and start to build a product list web site.

Seven Basic Operations

There are seven operations need to identified. They are:
  1. list_products: get and show all products.
  2. show_product: get product data for a specific prod_id.
  3. new_product: get a new form to enter product data.
  4. create_product: create a product and save to database.
  5. edit_product: get and edit product data for a specific prod_id.
  6. update_product update product data of a specific prod_id to database.
  7. delete_product delete product for a specific prod_id.
The operations 3 and 4 are consecutive steps, which mean when a user creates a product by finishing product data entry (operation 3), the system save product data to database at once (operation 4).
Likewise, operation 5 and 6 have the same situation. The system gets and shows the product data on the screen (operation 5), then it saves the data back to database while data has been edited by a user (operation 6).

The Flow Control in “index.php”

Here shows the flow control in “index.php” which variable “$op” decides the program flow.
switch ($op) {
  case 'show_product':
    show_product($prod_id);
    break;
  case 'new_product':
    new_product();
    break;
  case 'create_product':
    $prod_id = create_product();
    header("Location:index.php?op=show_product&prod_id={$prod_id}");
    exit;
    break;
  case 'edit_product':
    edit_product($prod_id);
    break;
  case 'update_product':
    update_product($prod_id);
    header("Location:index.php?op=show_product&prod_id={$prod_id}");
    exit;
    break;
  case 'delete_product':
    delete_products($prod_id);
    header("Location:index.php");
    exit;
    break;
  default:
    list_products($keyword);
    break;
}