Взаимодействие веб-интерфейса с базой данных: полный стек

Раздел: Веб-разработка -> Интеграция фронтенда и бэкенда

Основные подходы к интеграции фронтенда и бэкенда

Как получать данные с сервера динамически, без обновления страницы?

Современный способ - использование Fetch API на стороне клиента и PHP с PDO и JSON на сервере. Этот подход обеспечивает асинхронное взаимодействие, разделение логики и безопасность через подготовленные запросы.

Пример: получение списка пользователей из базы MySQL.


// PHP: get_users.php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'user', 'pass');
$stmt = $pdo->query('SELECT id, name FROM users');
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
header('Content-Type: application/json');
echo json_encode($users);
  

Web php mysql (веб php mysql)


// JavaScript
fetch('get_users.php')
  .then(response => {
    if (!response.ok) throw new Error('Ошибка ' + response.status);
    return response.json();
  })
  .then(data => {
    // отображение данных
  })
  .catch(error => console.error(error));
  

Css javascript php mysql (css javascript php mysql)

Пояснение

PHP-скрипт устанавливает заголовок Content-Type: application/json, чтобы браузер понимал формат. PDO использует подготовленные запросы для предотвращения SQL-инъекций. Fetch возвращает Promise, обработка .then и .catch.

Типичные ошибки и их решение

  • Забыли указать header('Content-Type: application/json') - браузер может неправильно интерпретировать ответ, особенно при использовании XMLHttpRequest.
  • Не проверяется response.ok - при ошибках сервера (404, 500) промис fetch не переходит в reject, нужно проверять вручную.
  • SQL-инъекции при конкатенации строк в запросе - используйте подготовленные запросы.
  • Проблемы с кодировкой - в DSN добавьте charset=utf8;mb4 для эмодзи.

Как отправить данные формы асинхронно и сохранить их в базе?

Отправка POST запроса с JSON-телом.


// add_user.php
$input = json_decode(file_get_contents('php://input'), true);
$stmt = $pdo->prepare('INSERT INTO users (name) VALUES (:name)');
$stmt->execute(['name' => $input['name']]);
echo json_encode(['success' => true, 'id' => $pdo->lastInsertId()]);
  

Html php mysql (html php mysql)


// JavaScript
fetch('add_user.php', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({name: 'John'})
});
  

Html css php mysql (html css php mysql)

Частая ошибка: не указан заголовок Content-Type или указан неправильно (например, application/x-www-form-urlencoded), тогда PHP не сможет прочитать json_decode. Используйте ключ 'Content-Type': 'application/json'.

Вариант 1: Синхронная отправка формы (традиционный POST)

Этот метод используется, когда не требуется асинхронность: форма отправляется, браузер перезагружает страницу с ответом сервера.



Html css javascript php mysql (html css javascript php mysql)


// save.php
$name = $_POST['name'] ?? '';
$stmt = $pdo->prepare('INSERT INTO users (name) VALUES (?)');
$stmt->execute([$name]);
header('Location: success.php'); // редирект
  

Php mysql javascripts (php mysql и javascript)

Цель использования

Подходит для простых форм обратной связи, регистрации, где не требуется динамическое обновление страницы.

Проблемы: потеря состояния страницы, большая нагрузка на сервер при каждом действии, отсутствие обратной связи об ошибке без редиректа.

Вариант 2: XMLHttpRequest (XHR) без библиотек

Исторический способ асинхронных запросов. Используется для совместимости со старыми браузерами.


var xhr = new XMLHttpRequest();
xhr.open('GET', 'data.php');
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status === 200) {
    var data = JSON.parse(xhr.responseText);
    // обработка
  }
};
xhr.send();
  

Php mysql javascript html5 (php mysql javascript html5)

Проблемы: необходимость вручную отслеживать состояния, нет поддержки Promise, сложнее обработка ошибок.

Ошибка: забыли xhr.send() или не проверили readyState. Решение: использовать onload вместо onreadystatechange.

Вариант 3: Использование jQuery для AJAX

Упрощает синтаксис, но требует подключения библиотеки.


$.ajax({
  url: 'data.php',
  type: 'GET',
  dataType: 'json',
  success: function(data) {
    // работа с data
  },
  error: function(jqXHR, textStatus, errorThrown) {
    console.error(errorThrown);
  }
});
  

Цель: быстрая разработка при уже подключенном jQuery.

Недостатки: зависимость от сторонней библиотеки, увеличение размера страницы, современные браузеры поддерживают fetch.

Вариант 4: Отправка файлов через FormData

Позволяет загружать файлы на сервер асинхронно без обновления страницы.


const formData = new FormData();
formData.append('file', fileInput.files[0]);
fetch('upload.php', {
  method: 'POST',
  body: formData
})
.then(response => response.json())
.then(result => { console.log(result); });
  

// upload.php
$uploadDir = 'uploads/';
$fileName = basename($_FILES['file']['name']);
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadDir . $fileName)) {
  echo json_encode(['file' => $fileName]);
} else {
  http_response_code(500);
  echo json_encode(['error' => 'Ошибка загрузки']);
}
  

Проблемы: ограничение размера файла в php.ini (upload_max_filesize, post_max_size), проверка типа файла, безопасность (разрешать только определённые расширения).

Расширенные примеры интеграции

Пример 1. Полное CRUD приложение 'Список задач'

Серверный API (api.php) с роутингом:

Пример

// api.php
header('Content-Type: application/json');
$pdo = new PDO('mysql:host=localhost;dbname=todo;charset=utf8', 'user', 'pass');
$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$parts = explode('/', trim($uri, '/'));
$resource = $parts[0] ?? '';
$id = $parts[1] ?? null;

switch ($method) {
  case 'GET':
    if ($resource === 'tasks' && $id) {
      $stmt = $pdo->prepare('SELECT * FROM tasks WHERE id = ?');
      $stmt->execute([$id]);
      echo json_encode($stmt->fetch(PDO::FETCH_ASSOC));
    } elseif ($resource === 'tasks') {
      $stmt = $pdo->query('SELECT * FROM tasks ORDER BY created_at DESC');
      echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
    }
    break;
  case 'POST':
    $input = json_decode(file_get_contents('php://input'), true);
    $stmt = $pdo->prepare('INSERT INTO tasks (title, completed) VALUES (?, 0)');
    $stmt->execute([$input['title']]);
    echo json_encode(['id' => $pdo->lastInsertId()]);
    break;
  case 'PUT':
    $input = json_decode(file_get_contents('php://input'), true);
    $stmt = $pdo->prepare('UPDATE tasks SET completed = ? WHERE id = ?');
    $stmt->execute([$input['completed'], $id]);
    echo json_encode(['updated' => true]);
    break;
  case 'DELETE':
    $stmt = $pdo->prepare('DELETE FROM tasks WHERE id = ?');
    $stmt->execute([$id]);
    echo json_encode(['deleted' => true]);
    break;
  default:
    http_response_code(405);
    echo json_encode(['error' => 'Method not allowed']);
}

Клиентский JavaScript (используя async/await):

Пример

const API = '/api/tasks';
async function loadTasks() {
  const resp = await fetch(API);
  if (!resp.ok) throw new Error('Не удалось загрузить задачи');
  const tasks = await resp.json();
  renderTasks(tasks);
}
async function addTask(title) {
  const resp = await fetch(API, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({title})
  });
  return resp.json();
}
async function toggleTask(id, completed) {
  await fetch(`${API}/${id}`, {
    method: 'PUT',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({completed})
  });
}
async function deleteTask(id) {
  await fetch(`${API}/${id}`, { method: 'DELETE' });
}
// Использование
loadTasks();

Результат: при загрузке страницы список задач появляется без перезагрузки, добавление и удаление происходят мгновенно.

Пример взаимодействия: GET /api/tasks -> JSON [...], POST /api/tasks -> {"id":42}, PUT /api/tasks/42 -> {"updated":true}

Пример 2. Постраничная навигация с AJAX

PHP (tasks_page.php):

Пример

$page = $_GET['page'] ?? 1;
$limit = 10;
$offset = ($page - 1) * $limit;
$total = $pdo->query('SELECT COUNT(*) FROM tasks')->fetchColumn();
$stmt = $pdo->prepare('SELECT * FROM tasks LIMIT ? OFFSET ?');
$stmt->bindValue(1, $limit, PDO::PARAM_INT);
$stmt->bindValue(2, $offset, PDO::PARAM_INT);
$stmt->execute();
$tasks = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode(['tasks' => $tasks, 'total' => $total, 'page' => $page]);

JavaScript:

Пример

function loadPage(page) {
  fetch('/tasks?page=' + page)
    .then(resp => resp.json())
    .then(data => {
      // отрисовка data.tasks и обновление пагинации с data.total
    });
}
document.getElementById('pagination').addEventListener('click', (e) => {
  if (e.target.dataset.page) loadPage(e.target.dataset.page);
});

Результат: клик по странице подгружает новые данные без перезагрузки.

Пример 3. Аутентификация с использованием сессий

PHP (login.php):

Пример

session_start();
$data = json_decode(file_get_contents('php://input'), true);
$stmt = $pdo->prepare('SELECT * FROM users WHERE login = ? AND password = SHA2(?,256)');
$stmt->execute([$data['login'], $data['password']]);
$user = $stmt->fetch();
if ($user) {
  $_SESSION['user_id'] = $user['id'];
  echo json_encode(['success' => true]);
} else {
  http_response_code(401);
  echo json_encode(['error' => 'Неверные данные']);
}

JavaScript при отправке формы входа:

Пример

fetch('/login', {
  method: 'POST',
  credentials: 'include',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({login, password})
}).then(resp => {
  if (resp.ok) window.location.href = '/dashboard';
});

Защищённые запросы (например, /profile) проверяют сессию:

Пример

session_start();
if (!isset($_SESSION['user_id'])) {
  http_response_code(401);
  exit;
}
// остальная логика

Проблемы: необходимость настройки CORS для credentials, защита от CSRF с помощью токенов.

Пример 4. Обработка ошибок и отладка

На сервере используйте try-catch:

Пример

try {
  // ... PDO операции
} catch (PDOException $e) {
  http_response_code(500);
  echo json_encode(['error' => 'Ошибка базы данных']);
  // можно логировать $e->getMessage()
}

На клиенте:

Пример

fetch('/api/data')
  .then(response => {
    if (!response.ok) {
      return response.json().then(err => { throw new Error(err.error); });
    }
    return response.json();
  })
  .catch(error => {
    document.getElementById('error').textContent = error.message;
  });

Результат: пользователь видит понятное сообщение вместо непонятной ошибки.

HTML CSS JavaScript PHP MySQL - comments

En
Html css javascript php mysql (php)