標籤

bat (52) 作品 (38) python (21) shell (17) windows (11) 虛擬機 (11) php (10) CPP (6) KMS (6) 程式設計 (6) docker (5) 使用教學 (5) xoops (4) 公文 (4) Apache2 (3) Excel (3) juniper (3) 資料庫 (3) mysql (2) 免動手 (2) 資料結構 (2) 軟體廣播 (2) 電腦維修 (2) Android Studio (1) Apple IPAD管理 (1) Arduino (1) CSS (1) LAMP (1) NAS (1) Ubuntu (1) VHD (1) Windows Server (1) 原因 (1) 程式應用 (1) 程式積木 (1) 編輯器 (1) 雲端硬碟 (1)

2021年2月21日 星期日

在docker-nginx-php-mysql開發環境,建立一個簡單的 PHP REST API (二)

 前篇:在docker-nginx-php-mysql開發環境,建立一個簡單的 PHP REST API (一)

        自從完成在docker-nginx-php-mysql開發環境,建立一個簡單的 PHP REST API (一),開始對PHP REST API 有初步了解。希望能夠再進一步實作,因此以How To Create A Simple REST API in PHP? Step By Step Guide!為範本,進行實作。
        首先建立開發環境,以docker來做。使用資料依據為

一、shell檔案快速完成

檔名:DockerEnvInstall.sh
檔案內容:
#!/bin/bash
yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
yum install -y yum-utils
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
yum install docker-ce docker-ce-cli containerd.io
systemctl start docker
curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose version
yum install git
mkdir test01
cd test01
git clone https://github.com/mark2470mark/docker-nginx-php-mysql.git
cd ~/test01/docker-nginx-php-mysql
docker-compose up -d
docker-compose ps

重開機後,需要啟動docker,才能執行docker-compose up -d 等指令。
$sudo systemctl start docker

二、設定DockerEnvInstall.sh為可執行

$sudo chmod 755 DockerEnvInstall.sh
$sudo sh DockerEnvInstall.sh
此時的開發環境

三、建立資料庫

1.瀏覽器網址打上 http://IP:8080,進入phpmyadmin

 (1)建立資料庫 api_db

(2)建立資料表categories

複製SQL語法如下:
CREATE TABLE IF NOT EXISTS `categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(256) NOT NULL,
  `description` text NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=19 ;

(3) 在資料表categories填入資料

複製SQL語法如下:
INSERT INTO `categories` (`id`, `name`, `description`, `created`, `modified`) VALUES
(1, 'Fashion', 'Category for anything related to fashion.', '2014-06-01 00:35:07', '2014-05-30 17:34:33'),
(2, 'Electronics', 'Gadgets, drones and more.', '2014-06-01 00:35:07', '2014-05-30 17:34:33'),
(3, 'Motors', 'Motor sports and more', '2014-06-01 00:35:07', '2014-05-30 17:34:54'),
(5, 'Movies', 'Movie products.', '0000-00-00 00:00:00', '2016-01-08 13:27:26'),
(6, 'Books', 'Kindle books, audio books and more.', '0000-00-00 00:00:00', '2016-01-08 13:27:47'),
(13, 'Sports', 'Drop into new winter gear.', '2016-01-09 02:24:24', '2016-01-09 01:24:24');

(4)建立資料表product

複製SQL語法如下:
CREATE TABLE IF NOT EXISTS `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  `description` text NOT NULL,
  `price` decimal(10,0) NOT NULL,
  `category_id` int(11) NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=65 ;

(5) 在資料表product填入資料

複製SQL語法如下:
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'),
(26, 'Another product', 'Awesome product!', '555', 2, '2014-11-22 19:07:34', '2014-11-21 20:07:34'),
(28, 'Wallet', 'You can absolutely use this one!', '799', 6, '2014-12-04 21:12:03', '2014-12-03 22:12:03'),
(31, 'Amanda Waller Shirt', 'New awesome shirt!', '333', 1, '2014-12-13 00:52:54', '2014-12-12 01:52:54'),
(42, 'Nike Shoes for Men', 'Nike Shoes', '12999', 3, '2015-12-12 06:47:08', '2015-12-12 05:47:08'),
(48, 'Bristol Shoes', 'Awesome shoes.', '999', 5, '2016-01-08 06:36:37', '2016-01-08 05:36:37'),
(60, 'Rolex Watch', 'Luxury watch.', '25000', 1, '2016-01-11 15:46:02', '2016-01-11 14:46:02');

2.建立database.php

由於在docker-nginx-php-mysql開發環境中,
在原本docker-nginx-php-mysql/docker-compose.yml,

(1)在web/public/,建立資料夾api

$ sudo mkdir api
$ cd api/ 

(2)在web/public/api/,建立資料夾config


$ mkdir config
$ cd config/

(3)建立database.php


$ pico database.php
檔案名稱:database.php
檔案內容:
<?php
class Database{
  
    // specify your own database credentials
    private $host = "mysql";
    private $db_name = "api_db";
    private $username = "root";
    private $password = "a123456";
    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);
            $this->conn->exec("set names utf8");
        }catch(PDOException $exception){
            echo "Connection error: " . $exception->getMessage();
        }
  
        return $this->conn;
    }
}
?>

(4)在web/public/建立TestDatabaseConn.php,測試資料庫是否正確連線

檔案名稱:TestDatabaseConn.php
檔案內容:
<?php
$test01 = include 'api/config/database.php';
echo $test01."<br>";
$database = new database;
print_r($database->getConnection());
?>
測試結果

3.建立product.php

(1)在web/public/api/,建立資料夾objects


$cd ..
$cd web/public/api
$mkdir objects

(2)在web/public/api/objects,建立product.php


$cd product
$pico product.php
檔案名稱:product.php
檔案內容:
<?php
class Product{
  
    // database connection and table name
    private $conn;
    private $table_name = "products";
  
    // object properties
    public $id;
    public $name;
    public $description;
    public $price;
    public $category_id;
    public $category_name;
    public $created;
  
    // constructor with $db as database connection
    public function __construct($db){
        $this->conn = $db;
    }

   // read products
   function read(){
  
       // select all 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
                 ORDER BY p.created DESC";
  
       // prepare query statement
       $stmt = $this->conn->prepare($query);
  
       // execute query
       $stmt->execute();
  
       return $stmt;
   }
// create product
function create(){
  
    // query to insert record
    $query = "INSERT INTO" . $this->table_name . "
                     SET name=:name, price=:price, description=:description, category_id=:category_id, 
                             created=:created";
  
    // prepare query
    $stmt = $this->conn->prepare($query);
  
    // sanitize
    $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->created=htmlspecialchars(strip_tags($this->created));
  
    // 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->created);
  
    // execute query
    if($stmt->execute()){
        return true;
    }
    return false;
}
// used when filling up the update product form
function readOne(){
  
    // query to read single record
    $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.id = ?
        LIMIT 0,1";
  
    // prepare query statement
    $stmt = $this->conn->prepare( $query );
  
    // bind id of product to be updated
    $stmt->bindParam(1, $this->id);
  
    // execute query
    $stmt->execute();
  
    // get retrieved row
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
  
    // set values to object properties
    $this->name = $row['name'];
    $this->price = $row['price'];
    $this->description = $row['description'];
    $this->category_id = $row['category_id'];
    $this->category_name = $row['category_name'];
}
// update the product
function update(){

    // update query
    $query = "UPDATE" . $this->table_name . "
              SET name = :name,
                      price = :price,
                      description = :description,
                      category_id = :category_id
              WHERE id = :id";

    // prepare query statement
    $stmt = $this->conn->prepare($query);

    // sanitize
    $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 new 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(':id', $this->id);

    // execute the query
    if($stmt->execute()){
        return true;
    }

    return false;
}

}
?>

4.建立read.php

(1)在web/public/api/,建立資料夾product


$cd ..
$mkdir product 

(2)在web/public/api/product/,建立read.php


$cd product
$pico read.php
檔案名稱:read.php
檔案內容:
<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
  
// include database and object files
include_once '../config/database.php';
include_once '../objects/product.php';
  
// instantiate database and product object
$database = new Database();
$db = $database->getConnection();
  
// initialize object
$product = new Product($db);
  
// query products
$stmt = $product->read();
$num = $stmt->rowCount();
  
// check if more than 0 record found
if($num>0){
  
    // products array
    $products_arr=array();
    $products_arr["records"]=array();
  
    // 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['name'] to
        // just $name only
        extract($row);
  
        $product_item=array(
            "id" => $id,
            "name" => $name,
            "description" => html_entity_decode($description),
            "price" => $price,
            "category_id" => $category_id,
            "category_name" => $category_name
        );
  
        array_push($products_arr["records"], $product_item);
    }
  
    // set response code - 200 OK
    http_response_code(200);
  
    // show products data in json format
    echo json_encode($products_arr);
else {
  
    // set response code - 404 Not found
    http_response_code(404);
  
    // tell the user no products found
    echo json_encode(
        array("message" => "No products found.")
    );
}
?>

5.建立create.php

(1)在web/public/api/product/,建立create.php

檔案名稱:create.php
檔案內容:
<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
  
// get database connection
include_once '../config/database.php';
  
// instantiate product object
include_once '../objects/product.php';
  
$database = new Database();
$db = $database->getConnection();
  
$product = new Product($db);
  
// get posted data
$data = json_decode(file_get_contents("php://input"));
  
// make sure data is not empty
if(
    !empty($data->name) &&
    !empty($data->price) &&
    !empty($data->description) &&
    !empty($data->category_id)
){
  
    // set product property values
    $product->name = $data->name;
    $product->price = $data->price;
    $product->description = $data->description;
    $product->category_id = $data->category_id;
    $product->created = date('Y-m-d H:i:s');
  
    // create the product
    if($product->create()){
  
        // set response code - 201 created
        http_response_code(201);
  
        // tell the user
        echo json_encode(array("message" => "Product was created."));
    }
  
    // if unable to create the product, tell the user
    else{
  
        // set response code - 503 service unavailable
        http_response_code(503);
  
        // tell the user
        echo json_encode(array("message" => "Unable to create product."));
    }
}
  
// tell the user data is incomplete
else{
  
    // set response code - 400 bad request
    http_response_code(400);
  
    // tell the user
    echo json_encode(array("message" => "Unable to create product. Data is incomplete."));
}
?>

6.使用postman來測試寫好的API

Chrome 擴充功能版 : 下載連結
如下圖:
                              
步驟1.點選POST
步驟2.輸入網址:http://IP/api/product/create.php
以目前作者測試的網址為http://192.168.111.140/api/product/create.php
步驟3.點選Body
步驟4.點選raw
步驟5.輸入的JSON如下:
{
    "name" : "Amazing Pillow 2.0",
    "price" : "199",
    "description" : "The best pillow for amazing programmers.",
    "category_id" : 2,
    "created" : "2018-06-01 00:35:07"
}
步驟6.點選Send
就會得到步驟7.JSON
{
    "message": "Product was created."
}
就會出現
{"records":[{"id":"1","name":"Amazing Pillow 2.0","description":"The best pillow for amazing programmers.","price":"199","category_id":"2","category_name":"Electronics"}]}

7.建立read_one.php

(1)在web/api/product/,建立read_one.php

檔案名稱:read_one.php
檔案內容:
<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: access");
header("Access-Control-Allow-Methods: GET");
header("Access-Control-Allow-Credentials: true");
header('Content-Type: application/json');
  
// include database and object files
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 ID property of record to read
$product->id = isset($_GET['id']) ? $_GET['id'] : die();
  
// read the details of product to be edited
$product->readOne();
  
 if($product->name!=null) {
    // create array
    $product_arr = array(
        "id" =>  $product->id,
        "name" => $product->name,
        "description" => $product->description,
        "price" => $product->price,
        "category_id" => $product->category_id,
        "category_name" => $product->category_name 
     );
  
    // set response code - 200 OK
    http_response_code(200);
  
    // make it json format
    echo json_encode($product_arr);
} else {
    // set response code - 404 Not found
    http_response_code(404);
  
    // tell the user product does not exist
    echo json_encode(array("message" => "Product does not exist."));
}
?>

(2)使用postman來測試寫好的API

8.建立update.php

(1)在web/api/product/,建立update.php

檔案名稱:update.php
檔案內容:
<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
 
// include database and object files
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);
 
// get id of product to be edited
$data = json_decode(file_get_contents("php://input"));
 
// set ID property of product to be edited
$product->id = $data->id;
 
// set product property values
$product->name = $data->name;
$product->price = $data->price;
$product->description = $data->description;
$product->category_id = $data->category_id;
 
// update the product
if($product->update()){
 
    // set response code - 200 ok
    http_response_code(200);
 
    // tell the user
    echo json_encode(array("message" => "Product was updated."));
}
 
// if unable to update the product, tell the user
else{
 
    // set response code - 503 service unavailable
    http_response_code(503);
 
    // tell the user
    echo json_encode(array("message" => "Unable to update product."));
}
?>

 
(2)
 

沒有留言:

張貼留言

只要點兩下,傳統右鍵選單改回Win11右鍵選單

系列文章: 1. 只要點兩下,就能將Win11 右鍵選單 回復 傳統右鍵選單 2. 只要點兩下,傳統右鍵選單改回Win11右鍵選單 上一篇提到只要點兩下,就能將Win11選單回到傳統選單。但是有沒有方法能夠回到Win11選單呢?                    ...