前篇:在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;
}
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
步驟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."));
}
?>
// 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)
沒有留言:
張貼留言