PHP构建RESTful API完整教程:从入门到实战部署 | Web服务开发

2025-08-26 0 804

一、RESTful API概述与设计原则

RESTful API是一种基于REST架构风格的Web服务接口,它使用HTTP协议定义了一组约束和原则,使Web服务更加简洁、可扩展和易于维护。

RESTful API核心原则:

  • 无状态性:每个请求包含所有必要信息,服务器不存储客户端状态
  • 统一接口:使用标准HTTP方法(GET、POST、PUT、DELETE等)
  • 资源导向:所有内容都是资源,通过URI标识
  • 可缓存性:响应应明确表明是否可缓存
  • 分层系统:客户端不需要知道是否直接连接到最终服务器

二、项目结构与数据库设计

项目目录结构:

api/
├── config/
│   └── database.php      # 数据库配置
├── controllers/
│   ├── ApiController.php # 基础控制器
│   └── ProductController.php # 产品控制器
├── models/
│   ├── Database.php      # 数据库连接
│   └── Product.php       # 产品模型
├── utils/
│   ├── Response.php      # 响应处理
│   └── JwtAuth.php       # JWT认证
└── index.php             # 入口文件
            

数据库设计(products表):

CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL,
    category_id INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
            

三、核心代码实现

1. 数据库配置与连接

创建config/database.php:

<?php
class Database {
    private $host = "localhost";
    private $db_name = "api_db";
    private $username = "root";
    private $password = "";
    public $conn;
    
    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");
            $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch(PDOException $exception) {
            echo "Connection error: " . $exception->getMessage();
        }
        
        return $this->conn;
    }
}
?>
            

2. 响应处理工具

创建utils/Response.php:

<?php
class Response {
    public static function send($data, $status = 200) {
        http_response_code($status);
        header('Content-Type: application/json');
        echo json_encode([
            'status' => $status,
            'data' => $data
        ]);
        exit;
    }
    
    public static function error($message, $status = 400) {
        http_response_code($status);
        header('Content-Type: application/json');
        echo json_encode([
            'status' => $status,
            'message' => $message
        ]);
        exit;
    }
}
?>
            

3. 产品模型

创建models/Product.php:

<?php
class Product {
    private $conn;
    private $table_name = "products";
    
    public $id;
    public $name;
    public $description;
    public $price;
    public $category_id;
    public $created_at;
    public $updated_at;
    
    public function __construct($db) {
        $this->conn = $db;
    }
    
    // 获取所有产品
    public function read() {
        $query = "SELECT * FROM " . $this->table_name . " ORDER BY created_at DESC";
        $stmt = $this->conn->prepare($query);
        $stmt->execute();
        
        return $stmt;
    }
    
    // 获取单个产品
    public function readOne() {
        $query = "SELECT * FROM " . $this->table_name . " WHERE id = ? LIMIT 0,1";
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(1, $this->id);
        $stmt->execute();
        
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if($row) {
            $this->name = $row['name'];
            $this->description = $row['description'];
            $this->price = $row['price'];
            $this->category_id = $row['category_id'];
            $this->created_at = $row['created_at'];
            $this->updated_at = $row['updated_at'];
            return true;
        }
        
        return false;
    }
    
    // 创建产品
    public function create() {
        $query = "INSERT INTO " . $this->table_name . " 
                 SET name=:name, description=:description, price=:price, category_id=:category_id";
        
        $stmt = $this->conn->prepare($query);
        
        // 清理数据
        $this->name = htmlspecialchars(strip_tags($this->name));
        $this->description = htmlspecialchars(strip_tags($this->description));
        $this->price = htmlspecialchars(strip_tags($this->price));
        $this->category_id = htmlspecialchars(strip_tags($this->category_id));
        
        // 绑定参数
        $stmt->bindParam(":name", $this->name);
        $stmt->bindParam(":description", $this->description);
        $stmt->bindParam(":price", $this->price);
        $stmt->bindParam(":category_id", $this->category_id);
        
        if($stmt->execute()) {
            return true;
        }
        
        return false;
    }
    
    // 更新产品
    public function update() {
        $query = "UPDATE " . $this->table_name . " 
                 SET name=:name, description=:description, price=:price, category_id=:category_id 
                 WHERE id=:id";
        
        $stmt = $this->conn->prepare($query);
        
        // 清理数据
        $this->name = htmlspecialchars(strip_tags($this->name));
        $this->description = htmlspecialchars(strip_tags($this->description));
        $this->price = htmlspecialchars(strip_tags($this->price));
        $this->category_id = htmlspecialchars(strip_tags($this->category_id));
        $this->id = htmlspecialchars(strip_tags($this->id));
        
        // 绑定参数
        $stmt->bindParam(":name", $this->name);
        $stmt->bindParam(":description", $this->description);
        $stmt->bindParam(":price", $this->price);
        $stmt->bindParam(":category_id", $this->category_id);
        $stmt->bindParam(":id", $this->id);
        
        if($stmt->execute()) {
            return true;
        }
        
        return false;
    }
    
    // 删除产品
    public function delete() {
        $query = "DELETE FROM " . $this->table_name . " WHERE id = ?";
        $stmt = $this->conn->prepare($query);
        
        $this->id = htmlspecialchars(strip_tags($this->id));
        $stmt->bindParam(1, $this->id);
        
        if($stmt->execute()) {
            return true;
        }
        
        return false;
    }
}
?>
            

4. 产品控制器

创建controllers/ProductController.php:

<?php
class ProductController {
    private $db;
    private $product;
    
    public function __construct($db) {
        $this->db = $db;
        $this->product = new Product($db);
    }
    
    // 处理请求
    public function handleRequest($method, $id = null) {
        switch($method) {
            case 'GET':
                if($id) {
                    $this->getProduct($id);
                } else {
                    $this->getAllProducts();
                }
                break;
            case 'POST':
                $this->createProduct();
                break;
            case 'PUT':
                $this->updateProduct($id);
                break;
            case 'DELETE':
                $this->deleteProduct($id);
                break;
            default:
                Response::error('Method not allowed', 405);
                break;
        }
    }
    
    // 获取所有产品
    private function getAllProducts() {
        $stmt = $this->product->read();
        $num = $stmt->rowCount();
        
        if($num > 0) {
            $products_arr = array();
            $products_arr["records"] = array();
            
            while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                extract($row);
                $product_item = array(
                    "id" => $id,
                    "name" => $name,
                    "description" => html_entity_decode($description),
                    "price" => $price,
                    "category_id" => $category_id,
                    "created_at" => $created_at,
                    "updated_at" => $updated_at
                );
                
                array_push($products_arr["records"], $product_item);
            }
            
            Response::send($products_arr);
        } else {
            Response::send(array("message" => "No products found."));
        }
    }
    
    // 获取单个产品
    private function getProduct($id) {
        $this->product->id = $id;
        
        if($this->product->readOne()) {
            $product_arr = array(
                "id" => $this->product->id,
                "name" => $this->product->name,
                "description" => html_entity_decode($this->product->description),
                "price" => $this->product->price,
                "category_id" => $this->product->category_id,
                "created_at" => $this->product->created_at,
                "updated_at" => $this->product->updated_at
            );
            
            Response::send($product_arr);
        } else {
            Response::error("Product not found", 404);
        }
    }
    
    // 创建产品
    private function createProduct() {
        $data = json_decode(file_get_contents("php://input"));
        
        if(
            !empty($data->name) &&
            !empty($data->price) &&
            !empty($data->category_id)
        ) {
            $this->product->name = $data->name;
            $this->product->description = $data->description ?? '';
            $this->product->price = $data->price;
            $this->product->category_id = $data->category_id;
            
            if($this->product->create()) {
                Response::send(array("message" => "Product created."), 201);
            } else {
                Response::error("Unable to create product.");
            }
        } else {
            Response::error("Unable to create product. Data is incomplete.");
        }
    }
    
    // 更新产品
    private function updateProduct($id) {
        $data = json_decode(file_get_contents("php://input"));
        
        $this->product->id = $id;
        
        if($this->product->readOne()) {
            $this->product->name = $data->name ?? $this->product->name;
            $this->product->description = $data->description ?? $this->product->description;
            $this->product->price = $data->price ?? $this->product->price;
            $this->product->category_id = $data->category_id ?? $this->product->category_id;
            
            if($this->product->update()) {
                Response::send(array("message" => "Product updated."));
            } else {
                Response::error("Unable to update product.");
            }
        } else {
            Response::error("Product not found", 404);
        }
    }
    
    // 删除产品
    private function deleteProduct($id) {
        $this->product->id = $id;
        
        if($this->product->readOne()) {
            if($this->product->delete()) {
                Response::send(array("message" => "Product deleted."));
            } else {
                Response::error("Unable to delete product.");
            }
        } else {
            Response::error("Product not found", 404);
        }
    }
}
?>
            

5. 入口文件与路由

创建index.php:

<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");

// 引入必要文件
require_once 'config/database.php';
require_once 'models/Product.php';
require_once 'controllers/ProductController.php';
require_once 'utils/Response.php';

// 获取请求方法和参数
$method = $_SERVER['REQUEST_METHOD'];
$request_uri = $_SERVER['REQUEST_URI'];
$uri_segments = explode('/', trim($request_uri, '/'));

// 简单路由解析
$resource = $uri_segments[1] ?? '';
$id = $uri_segments[2] ?? null;

// 初始化数据库连接
$database = new Database();
$db = $database->getConnection();

// 路由分发
switch($resource) {
    case 'products':
        $controller = new ProductController($db);
        $controller->handleRequest($method, $id);
        break;
    default:
        Response::error('Resource not found', 404);
        break;
}
?>
            

四、API测试与使用

1. 获取所有产品(GET)

curl -X GET http://localhost/api/products
            

2. 获取单个产品(GET)

curl -X GET http://localhost/api/products/1
            

3. 创建产品(POST)

curl -X POST http://localhost/api/products 
-H "Content-Type: application/json" 
-d '{
    "name": "iPhone 13",
    "description": "最新款iPhone",
    "price": 5999,
    "category_id": 1
}'
            

4. 更新产品(PUT)

curl -X PUT http://localhost/api/products/1 
-H "Content-Type: application/json" 
-d '{
    "name": "iPhone 13 Pro",
    "price": 7999
}'
            

5. 删除产品(DELETE)

curl -X DELETE http://localhost/api/products/1
            

五、高级功能扩展

1. JWT认证实现

创建utils/JwtAuth.php:

<?php
class JwtAuth {
    private $secret_key = "your_secret_key";
    
    public function generateToken($payload) {
        $header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
        $payload = json_encode($payload);
        
        $base64UrlHeader = $this->base64UrlEncode($header);
        $base64UrlPayload = $this->base64UrlEncode($payload);
        
        $signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, $this->secret_key, true);
        $base64UrlSignature = $this->base64UrlEncode($signature);
        
        return $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature;
    }
    
    public function validateToken($token) {
        $tokenParts = explode('.', $token);
        $header = base64_decode($tokenParts[0]);
        $payload = base64_decode($tokenParts[1]);
        $signatureProvided = $tokenParts[2];
        
        $base64UrlHeader = $this->base64UrlEncode($header);
        $base64UrlPayload = $this->base64UrlEncode($payload);
        $signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, $this->secret_key, true);
        $base64UrlSignature = $this->base64UrlEncode($signature);
        
        return ($base64UrlSignature === $signatureProvided);
    }
    
    private function base64UrlEncode($text) {
        return str_replace(
            ['+', '/', '='],
            ['-', '_', ''],
            base64_encode($text)
        );
    }
}
?>
            

2. 分页与过滤

在Product模型中添加分页方法:

public function readPaging($from_record_num, $records_per_page) {
    $query = "SELECT * FROM " . $this->table_name . " 
              ORDER BY created_at DESC 
              LIMIT ?, ?";
    
    $stmt = $this->conn->prepare($query);
    $stmt->bindParam(1, $from_record_num, PDO::PARAM_INT);
    $stmt->bindParam(2, $records_per_page, PDO::PARAM_INT);
    $stmt->execute();
    
    return $stmt;
}

public function count() {
    $query = "SELECT COUNT(*) as total_rows FROM " . $this->table_name;
    $stmt = $this->conn->prepare($query);
    $stmt->execute();
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    
    return $row['total_rows'];
}
            

六、部署与优化建议

部署注意事项:

  • 使用HTTPS确保数据传输安全
  • 配置适当的CORS策略
  • 使用环境变量管理敏感信息
  • 实施API速率限制防止滥用
  • 启用Gzip压缩减少响应大小

性能优化建议:

  • 使用OPcache加速PHP执行
  • 实施数据库查询缓存
  • 使用Redis或Memcached缓存频繁访问的数据
  • 对响应数据实施压缩
  • 使用CDN分发静态资源

安全性建议:

  • 验证和过滤所有输入数据
  • 使用预处理语句防止SQL注入
  • 实施适当的身份验证和授权机制
  • 定期更新依赖库和框架
  • 记录和监控API访问日志

七、总结

本教程详细介绍了如何使用PHP构建一个完整的RESTful API,涵盖了从数据库设计、模型创建、控制器实现到路由处理的全过程。通过这个示例,您可以学习到:

  • RESTful API的设计原则和最佳实践
  • 使用PDO进行安全的数据库操作
  • 实现标准的CRUD操作(创建、读取、更新、删除)
  • 处理HTTP请求和生成JSON响应
  • 扩展API功能(认证、分页、过滤等)

这个API可以作为各种前端应用(Web、移动应用等)的后端服务,提供了清晰的数据接口和完整的业务逻辑处理能力。您可以根据实际需求进一步扩展功能,如用户认证、文件上传、更复杂的查询功能等。

通过掌握这些技能,您将能够构建专业级的Web服务,为现代应用开发提供强大的后端支持。

PHP构建RESTful API完整教程:从入门到实战部署 | Web服务开发
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

淘吗网 php PHP构建RESTful API完整教程:从入门到实战部署 | Web服务开发 https://www.taomawang.com/server/php/976.html

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务