Введение: зачем вам REST API на PHP?
REST API (Representational State Transfer) — это архитектурный стиль, который позволяет разным приложениям общаться друг с другом через HTTP. Сегодня без API не обходится ни один современный веб-сервис: мобильные приложения, SPA-фронтенды, интеграции с платежными системами — всё это требует быстрого и понятного интерфейса для обмена данными.
PHP остаётся одним из самых популярных языков для бэкенда. Вы можете написать полноценный REST API на чистом PHP без громоздких фреймворков — это займёт у вас не больше 30 минут. В этой статье мы разберём практический пример с CRUD-операциями (создание, чтение, обновление, удаление) для управления списком задач (To-Do).
1. Подготовка окружения и структура проекта
Для работы вам понадобится:
- Локальный сервер (Open Server, XAMPP, MAMP или встроенный PHP-сервер)
- PHP версии 7.4 или выше
- Редактор кода (VS Code, PhpStorm)
Создайте корневую папку rest-api-php и внутри неё файлы:
rest-api-php/
├── index.php (точка входа, маршрутизатор)
├── config.php (настройки базы данных)
├── api/
│ ├── tasks.php (CRUD для задач)
│ └── helpers.php (вспомогательные функции)
└── .htaccess (перенаправление запросов на index.php)
1.1. Настройка .htaccess для красивых URL
Чтобы все запросы направлялись в единую точку входа, создайте файл .htaccess в корне:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
Если используете встроенный сервер PHP, просто запустите его из папки проекта: php -S localhost:8000.
2. Создание маршрутизатора и базового API
Откройте index.php — это наш главный обработчик. Он будет анализировать HTTP-метод и URI вызывать нужные функции.
2.1. index.php — точка входа
<?php
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
require_once 'config.php';
require_once 'api/helpers.php';
$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = rtrim($uri, '/');
// Простая маршрутизация
if ($uri === '/api/tasks') {
require_once 'api/tasks.php';
handleTasks($method);
} elseif (preg_match('/^\/api\/tasks\/(\d+)$/', $uri, $matches)) {
require_once 'api/tasks.php';
handleTask($method, (int)$matches[1]);
} else {
sendResponse(['error' => 'Endpoint not found'], 404);
}
?>
Мы обрабатываем два маршрута: /api/tasks (список/создание) и /api/tasks/{id} (конкретная задача).
2.2. helpers.php — вспомогательные функции
<?php
function sendResponse($data, $status = 200) {
http_response_code($status);
echo json_encode($data, JSON_UNESCAPED_UNICODE);
exit;
}
function getJsonInput() {
$input = file_get_contents('php://input');
return json_decode($input, true) ?? [];
}
?>
3. Работа с базой данных и CRUD-операции
Создадим простую таблицу tasks в MySQL:
CREATE TABLE tasks (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
status ENUM('pending', 'completed') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Файл config.php:
<?php
$host = 'localhost';
$dbname = 'rest_api_db';
$username = 'root';
$password = '';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
sendResponse(['error' => 'Database connection failed: ' . $e->getMessage()], 500);
}
?>
3.1. tasks.php — основная логика API
Здесь мы реализуем все CRUD-операции. Функция handleTasks отвечает за GET (список) и POST (создание), а handleTask — за GET/{id}, PUT (обновление) и DELETE.
<?php
function handleTasks($method) {
global $pdo;
if ($method === 'GET') {
$stmt = $pdo->query("SELECT * FROM tasks ORDER BY created_at DESC");
$tasks = $stmt->fetchAll(PDO::FETCH_ASSOC);
sendResponse($tasks);
}
elseif ($method === 'POST') {
$data = getJsonInput();
if (empty($data['title'])) {
sendResponse(['error' => 'Title is required'], 400);
}
$stmt = $pdo->prepare("INSERT INTO tasks (title) VALUES (:title)");
$stmt->execute(['title' => $data['title']]);
$id = $pdo->lastInsertId();
sendResponse(['id' => $id, 'message' => 'Task created'], 201);
}
else {
sendResponse(['error' => 'Method not allowed'], 405);
}
}
function handleTask($method, $id) {
global $pdo;
if ($method === 'GET') {
$stmt = $pdo->prepare("SELECT * FROM tasks WHERE id = :id");
$stmt->execute(['id' => $id]);
$task = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$task) {
sendResponse(['error' => 'Task not found'], 404);
}
sendResponse($task);
}
elseif ($method === 'PUT') {
$data = getJsonInput();
$fields = [];
$params = ['id' => $id];
if (isset($data['title'])) {
$fields[] = 'title = :title';
$params['title'] = $data['title'];
}
if (isset($data['status'])) {
$fields[] = 'status = :status';
$params['status'] = $data['status'];
}
if (empty($fields)) {
sendResponse(['error' => 'No fields