免费资源下载
基于PSR标准、Composer依赖管理和现代化PHP特性的企业级API开发完整指南
技术架构演进
本文将深入探讨PHP 8.x环境下如何构建符合PSR标准的现代化RESTful API,涵盖JWT认证、依赖注入、中间件管道、数据库抽象层等核心技术。不同于传统MVC架构,我们采用分层架构和领域驱动设计思想,打造高性能、可维护的API服务。
一、项目架构设计与环境配置
1.1 现代化项目目录结构
api-project/ ├── src/ │ ├── Application/ # 应用层 │ │ ├── Middleware/ # 中间件 │ │ ├── Exceptions/ # 应用异常 │ │ └── Actions/ # 业务动作 │ ├── Domain/ # 领域层 │ │ ├── Entities/ # 实体对象 │ │ ├── ValueObjects/ # 值对象 │ │ └── Services/ # 领域服务 │ ├── Infrastructure/ # 基础设施层 │ │ ├── Persistence/ # 数据持久化 │ │ ├── Auth/ # 认证授权 │ │ └── Cache/ # 缓存服务 │ └── Presentation/ # 表现层 │ ├── Controllers/ # 控制器 │ ├── Requests/ # 请求验证 │ └── Responses/ # 响应格式化 ├── config/ # 配置文件 ├── public/ # 公开目录 │ └── index.php # 入口文件 ├── tests/ # 测试目录 ├── vendor/ # Composer依赖 ├── .env.example # 环境变量示例 ├── composer.json # 依赖配置 └── README.md # 项目说明
1.2 Composer依赖配置
{
"name": "api-project/rest-api",
"type": "project",
"require": {
"php": "^8.1",
"ext-json": "*",
"ext-openssl": "*",
"firebase/php-jwt": "^6.3", # JWT令牌处理
"illuminate/database": "^9.0", # Laravel数据库组件
"illuminate/events": "^9.0", # 事件系统
"league/container": "^4.2", # 依赖注入容器
"league/route": "^6.0", # 路由组件
"monolog/monolog": "^2.8", # 日志记录
"nyholm/psr7": "^1.5", # PSR-7实现
"ramsey/uuid": "^4.0" # UUID生成
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"mockery/mockery": "^1.5"
},
"autoload": {
"psr-4": {
"App\": "src/"
}
}
}
二、核心组件实现
2.1 JWT认证服务实现
JWT令牌生成器
<?php
namespace AppInfrastructureAuth;
use FirebaseJWTJWT;
use FirebaseJWTKey;
use RamseyUuidUuid;
class JwtTokenService
{
private string $secretKey;
private int $expirationTime;
public function __construct(string $secretKey, int $expirationTime = 3600)
{
$this->secretKey = $secretKey;
$this->expirationTime = $expirationTime;
}
/**
* 生成访问令牌
*/
public function generateAccessToken(array $userData): string
{
$issuedAt = time();
$expireAt = $issuedAt + $this->expirationTime;
$payload = [
'iss' => 'api.yourdomain.com', // 签发者
'aud' => 'api.yourdomain.com', // 接收方
'iat' => $issuedAt, // 签发时间
'nbf' => $issuedAt, // 生效时间
'exp' => $expireAt, // 过期时间
'jti' => Uuid::uuid4()->toString(), // 唯一标识
'data' => [ // 用户数据
'user_id' => $userData['id'],
'email' => $userData['email'],
'roles' => $userData['roles'] ?? ['user']
]
];
return JWT::encode($payload, $this->secretKey, 'HS256');
}
/**
* 生成刷新令牌
*/
public function generateRefreshToken(): string
{
return bin2hex(random_bytes(32));
}
/**
* 验证并解码令牌
*/
public function validateToken(string $token): ?array
{
try {
$decoded = JWT::decode($token, new Key($this->secretKey, 'HS256'));
return (array) $decoded;
} catch (Exception $e) {
// 记录日志但不暴露具体错误信息
error_log('JWT验证失败: ' . $e->getMessage());
return null;
}
}
/**
* 刷新访问令牌
*/
public function refreshToken(string $oldToken): ?string
{
$decoded = $this->validateToken($oldToken);
if (!$decoded) {
return null;
}
// 检查令牌是否即将过期(最后5分钟)
$currentTime = time();
$tokenExpire = $decoded['exp'];
if (($tokenExpire - $currentTime) > 300) {
// 令牌还有超过5分钟有效期,无需刷新
return null;
}
// 生成新令牌
return $this->generateAccessToken($decoded['data']);
}
}
2.2 中间件管道实现
认证中间件
<?php
namespace AppApplicationMiddleware;
use PsrHttpMessageResponseInterface;
use PsrHttpMessageServerRequestInterface;
use PsrHttpServerMiddlewareInterface;
use PsrHttpServerRequestHandlerInterface;
use AppInfrastructureAuthJwtTokenService;
class AuthenticationMiddleware implements MiddlewareInterface
{
private JwtTokenService $jwtService;
public function __construct(JwtTokenService $jwtService)
{
$this->jwtService = $jwtService;
}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
// 获取Authorization头
$authHeader = $request->getHeaderLine('Authorization');
if (empty($authHeader) || !str_starts_with($authHeader, 'Bearer ')) {
return $this->createUnauthorizedResponse('缺少认证令牌');
}
// 提取JWT令牌
$token = substr($authHeader, 7);
// 验证令牌
$decoded = $this->jwtService->validateToken($token);
if (!$decoded) {
return $this->createUnauthorizedResponse('令牌无效或已过期');
}
// 将用户信息添加到请求属性中
$request = $request->withAttribute('user', $decoded['data']);
// 继续处理请求
return $handler->handle($request);
}
private function createUnauthorizedResponse(string $message): ResponseInterface
{
$response = new NyholmPsr7Response();
$response->getBody()->write(json_encode([
'error' => 'Unauthorized',
'message' => $message,
'code' => 401
]));
return $response
->withStatus(401)
->withHeader('Content-Type', 'application/json')
->withHeader('WWW-Authenticate', 'Bearer realm="API"');
}
}
速率限制中间件
<?php
namespace AppApplicationMiddleware;
use PsrHttpMessageResponseInterface;
use PsrHttpMessageServerRequestInterface;
use PsrHttpServerMiddlewareInterface;
use PsrHttpServerRequestHandlerInterface;
use AppInfrastructureCacheRateLimiter;
class RateLimitMiddleware implements MiddlewareInterface
{
private RateLimiter $rateLimiter;
private int $maxRequests;
private int $timeWindow;
public function __construct(
RateLimiter $rateLimiter,
int $maxRequests = 100,
int $timeWindow = 3600
) {
$this->rateLimiter = $rateLimiter;
$this->maxRequests = $maxRequests;
$this->timeWindow = $timeWindow;
}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$clientIp = $request->getServerParams()['REMOTE_ADDR'] ?? 'unknown';
$route = $request->getUri()->getPath();
$key = "rate_limit:{$clientIp}:{$route}";
if (!$this->rateLimiter->attempt($key, $this->maxRequests, $this->timeWindow)) {
return $this->createRateLimitResponse();
}
$response = $handler->handle($request);
// 添加速率限制头部信息
$remaining = $this->rateLimiter->remaining($key, $this->maxRequests);
$resetTime = $this->rateLimiter->resetTime($key, $this->timeWindow);
return $response
->withHeader('X-RateLimit-Limit', (string)$this->maxRequests)
->withHeader('X-RateLimit-Remaining', (string)$remaining)
->withHeader('X-RateLimit-Reset', (string)$resetTime);
}
private function createRateLimitResponse(): ResponseInterface
{
$response = new NyholmPsr7Response();
$response->getBody()->write(json_encode([
'error' => 'Too Many Requests',
'message' => '请求过于频繁,请稍后再试',
'code' => 429
]));
return $response
->withStatus(429)
->withHeader('Content-Type', 'application/json')
->withHeader('Retry-After', '3600');
}
}
三、RESTful API控制器实现
3.1 用户资源控制器
<?php
namespace AppPresentationControllers;
use PsrHttpMessageResponseInterface;
use PsrHttpMessageServerRequestInterface;
use AppApplicationActionsUserCreateUserAction;
use AppApplicationActionsUserGetUserAction;
use AppApplicationActionsUserUpdateUserAction;
use AppApplicationActionsUserDeleteUserAction;
use AppPresentationRequestsUserCreateRequest;
use AppPresentationRequestsUserUpdateRequest;
class UserController
{
private CreateUserAction $createUserAction;
private GetUserAction $getUserAction;
private UpdateUserAction $updateUserAction;
private DeleteUserAction $deleteUserAction;
public function __construct(
CreateUserAction $createUserAction,
GetUserAction $getUserAction,
UpdateUserAction $updateUserAction,
DeleteUserAction $deleteUserAction
) {
$this->createUserAction = $createUserAction;
$this->getUserAction = $getUserAction;
$this->updateUserAction = $updateUserAction;
$this->deleteUserAction = $deleteUserAction;
}
/**
* 创建用户 - POST /api/users
*/
public function store(ServerRequestInterface $request): ResponseInterface
{
// 验证请求数据
$validator = new UserCreateRequest($request);
if (!$validator->validate()) {
return $this->jsonResponse([
'errors' => $validator->errors(),
'message' => '验证失败'
], 422);
}
$data = $validator->validated();
try {
$user = $this->createUserAction->execute($data);
return $this->jsonResponse([
'data' => $user,
'message' => '用户创建成功'
], 201);
} catch (Exception $e) {
return $this->jsonResponse([
'error' => '创建失败',
'message' => $e->getMessage()
], 500);
}
}
/**
* 获取用户详情 - GET /api/users/{id}
*/
public function show(ServerRequestInterface $request, string $id): ResponseInterface
{
try {
$user = $this->getUserAction->execute($id);
if (!$user) {
return $this->jsonResponse([
'error' => '未找到用户',
'message' => '指定的用户不存在'
], 404);
}
return $this->jsonResponse([
'data' => $user
], 200);
} catch (Exception $e) {
return $this->jsonResponse([
'error' => '获取失败',
'message' => $e->getMessage()
], 500);
}
}
/**
* 更新用户 - PUT /api/users/{id}
*/
public function update(ServerRequestInterface $request, string $id): ResponseInterface
{
$validator = new UserUpdateRequest($request);
if (!$validator->validate()) {
return $this->jsonResponse([
'errors' => $validator->errors(),
'message' => '验证失败'
], 422);
}
$data = $validator->validated();
try {
$user = $this->updateUserAction->execute($id, $data);
return $this->jsonResponse([
'data' => $user,
'message' => '用户更新成功'
], 200);
} catch (Exception $e) {
return $this->jsonResponse([
'error' => '更新失败',
'message' => $e->getMessage()
], 500);
}
}
/**
* 删除用户 - DELETE /api/users/{id}
*/
public function destroy(ServerRequestInterface $request, string $id): ResponseInterface
{
try {
$this->deleteUserAction->execute($id);
return $this->jsonResponse([
'message' => '用户删除成功'
], 204);
} catch (Exception $e) {
return $this->jsonResponse([
'error' => '删除失败',
'message' => $e->getMessage()
], 500);
}
}
/**
* 统一的JSON响应方法
*/
private function jsonResponse(array $data, int $statusCode): ResponseInterface
{
$response = new NyholmPsr7Response();
$response->getBody()->write(json_encode($data, JSON_UNESCAPED_UNICODE));
return $response
->withStatus($statusCode)
->withHeader('Content-Type', 'application/json; charset=utf-8')
->withHeader('Cache-Control', 'no-store, no-cache, must-revalidate')
->withHeader('X-Content-Type-Options', 'nosniff');
}
}
四、性能优化与安全实践
4.1 数据库查询优化
// 使用查询构建器优化
$users = DB::table('users')
->select(['id', 'name', 'email', 'created_at'])
->where('status', 'active')
->when($request->has('role'), function ($query) use ($request) {
return $query->where('role', $request->input('role'));
})
->orderBy('created_at', 'desc')
->cursorPaginate(20); // 使用游标分页
// 预加载关联数据
$posts = Post::with(['author:id,name', 'tags:id,name'])
->whereHas('comments', function ($query) {
$query->where('approved', true);
})
->get();
4.2 缓存策略实现
class CachedUserRepository
{
private UserRepository $repository;
private CacheInterface $cache;
private int $ttl;
public function findById(string $id): ?User
{
$cacheKey = "user:{$id}";
return $this->cache->remember($cacheKey, $this->ttl,
function () use ($id) {
return $this->repository->findById($id);
}
);
}
public function invalidateCache(string $userId): void
{
$this->cache->delete("user:{$userId}");
$this->cache->delete('users:list');
}
}
4.3 安全防护措施
// SQL注入防护(使用参数绑定)
$users = DB::select(
'SELECT * FROM users WHERE email = ? AND status = ?',
[$email, 'active']
);
// XSS防护
$cleanInput = htmlspecialchars(
$input,
ENT_QUOTES | ENT_HTML5,
'UTF-8'
);
// CSRF令牌验证
if (!hash_equals($_SESSION['csrf_token'], $requestToken)) {
throw new Exception('CSRF令牌验证失败');
}
// 密码安全存储
$hashedPassword = password_hash(
$password,
PASSWORD_ARGON2ID,
['memory_cost' => 65536, 'time_cost' => 4]
);
五、部署与监控
5.1 Docker部署配置
# docker-compose.yml
version: '3.8'
services:
php-api:
build:
context: .
dockerfile: Dockerfile
container_name: php-rest-api
restart: unless-stopped
working_dir: /var/www/html
volumes:
- ./:/var/www/html
- ./docker/php/php.ini:/usr/local/etc/php/php.ini
environment:
- APP_ENV=production
- APP_DEBUG=false
- DB_HOST=mysql
- REDIS_HOST=redis
depends_on:
- mysql
- redis
networks:
- api-network
nginx:
image: nginx:1.21-alpine
container_name: api-nginx
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./:/var/www/html
- ./docker/nginx/conf.d:/etc/nginx/conf.d
depends_on:
- php-api
networks:
- api-network
mysql:
image: mysql:8.0
container_name: api-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql
- ./docker/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- api-network
redis:
image: redis:7-alpine
container_name: api-redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
- api-network
networks:
api-network:
driver: bridge
volumes:
mysql-data:
redis-data:
5.2 性能监控配置
✅ Prometheus指标
# HELP api_http_requests_total Total HTTP requests
# TYPE api_http_requests_total counter
api_http_requests_total{method="GET",endpoint="/api/users"} 1234
# HELP api_response_time_seconds API response time
# TYPE api_response_time_seconds histogram
api_response_time_seconds_bucket{le="0.1"} 1000
✅ 结构化日志
{
"timestamp": "2024-01-15T10:30:00Z",
"level": "INFO",
"message": "User authenticated",
"user_id": "12345",
"ip": "192.168.1.100",
"endpoint": "/api/auth/login",
"duration_ms": 45
}

