Принимаем данные в PHP: формы, файлы, JSON и внешние запросы

Раздел: Веб-разработка на PHP -> Отправка данных

Общие принципы отправки данных в PHP

При разработке веб-приложений на PHP одной из ключевых задач является получение данных от клиента. Данные могут приходить различными способами: через HTML-формы, AJAX-запросы, загрузку файлов или напрямую через URL. Каждый метод имеет свои особенности, ограничения и случаи применения. В этой статье разбираются основные подходы к приёму данных в PHP, даются рабочие примеры и предупреждается о типичных ошибках.

Основной и наиболее эффективный способ: обработка POST-данных с валидацией

Для большинства веб-форм, где требуется передача конфиденциальной или объёмной информации, используется метод POST. Данные передаются в теле HTTP-запроса и не отображаются в URL. В PHP они становятся доступны через суперглобальный массив $_POST.

<?php
// Файл handler.php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name = trim($_POST['name'] ?? '');
    $email = filter_var($_POST['email'] ?? '', FILTER_VALIDATE_EMAIL);
    
    $errors = [];
    if (empty($name)) {
        $errors[] = 'Поле имени обязательно';
    }
    if ($email === false) {
        $errors[] = 'Некорректный email';
    }
    
    if (empty($errors)) {
        // сохранение или отправка данных
        $message = 'Данные приняты: ' . htmlspecialchars($name) . ', ' . htmlspecialchars($email);
    } else {
        $message = implode('<br>', $errors);
    }
}
?>
<!DOCTYPE html>
<html>
<form method="post" action="">
    Имя: <input type="text" name="name"><br>
    Email: <input type="email" name="email"><br>
    <button type="submit">Отправить</button>
</form>
</html>

Пояснения: метод формы POST скрывает данные от прямого просмотра в адресной строке. Для безопасного вывода используется htmlspecialchars, чтобы предотвратить XSS-атаки. Валидация через filter_var проверяет корректность email до обработки.

Типичные проблемы и их решения:

  • Проблема: Пустой массив $_POST при отправке формы. Решение: убедиться, что форма имеет атрибут method="post" и поле name у каждого элемента.
  • Проблема: Специальные символы в выводе. Решение: применять htmlspecialchars() или использовать подготовленные запросы для базы данных.
  • Проблема: Длинные строки или отсутствие ограничений. Решение: настроить директивы post_max_size и max_input_vars в php.ini.

Как передать данные через URL (GET-запросы)?

Метод GET используется для идемпотентных запросов, когда данные не меняют состояние сервера (например, поиск, фильтры). Данные передаются в строке запроса и видны в URL. В PHP доступны через $_GET.

<!-- Форма с method="get" -->
<form method="get" action="search.php">
    <input type="text" name="q" placeholder="Поиск...">
    <button type="submit">Искать</button>
</form>

<?php
// search.php
if (isset($_GET['q'])) {
    $query = trim($_GET['q']);
    // проверка на пустую строку
    if ($query !== '') {
        echo 'Вы ищете: ' . htmlspecialchars($query);
    }
}
?>

Важно: GET не подходит для паролей или больших объёмов данных (ограничение длины URL обычно 2048 символов). Также не стоит передавать чувствительную информацию – она остаётся в истории браузера и логах сервера.

Как загрузить файл на сервер в PHP?

Загрузка файлов выполняется через форму с enctype="multipart/form-data" и методом POST. Файлы доступны в массиве $_FILES.

<form method="post" enctype="multipart/form-data">
    Выберите изображение:
    <input type="file" name="avatar">
    <button type="submit">Загрузить</button>
</form>

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['avatar'])) {
    $file = $_FILES['avatar'];
    // проверка ошибок
    if ($file['error'] === UPLOAD_ERR_OK) {
        $allowed = ['image/jpeg', 'image/png'];
        if (in_array($file['type'], $allowed) && $file['size'] < 2 * 1024 * 1024) {
            $dest = 'uploads/' . basename($file['name']);
            if (move_uploaded_file($file['tmp_name'], $dest)) {
                echo 'Файл сохранён: ' . $dest;
            }
        } else {
            echo 'Недопустимый тип или размер файла';
        }
    } else {
        echo 'Ошибка загрузки: код ' . $file['error'];
    }
}
?>

Типичные ошибки: превышение лимита upload_max_filesize или post_max_size; отсутствие папки назначения; выполнение кода до проверки ошибок. Решение: всегда проверять $file['error'] и настраивать php.ini.

Как принимать JSON-данные (например, от REST API)?

Когда данные приходят в формате JSON (через Content-Type: application/json), PHP не заполняет $_POST. Нужно читать сырой поток php://input.

<?php
// Чтение JSON из тела запроса
$json = file_get_contents('php://input');
// Преобразование в массив
$data = json_decode($json, true);

if (json_last_error() === JSON_ERROR_NONE && is_array($data)) {
    $name = $data['name'] ?? 'Не указано';
    echo 'Имя: ' . htmlspecialchars($name);
} else {
    http_response_code(400);
    echo 'Некорректный JSON';
}
?>
<!-- Пример отправки через fetch -->
<script>
fetch('/api.php', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({name: 'Иван', age: 30})
});
</script>

Проблема: часто забывают указать корректный заголовок Content-Type на клиенте – тогда php://input может быть пустым. Решение: на сервере проверять не только JSON, но и наличие данных.

Как обработать AJAX-запросы (XMLHttpRequest, fetch)?

Для динамических веб-приложений данные отправляются асинхронно. Серверная часть остаётся той же: в зависимости от Content-Type данные попадают в $_POST (для form-data) или в php://input (для JSON).

<?php
// ajax_handler.php
header('Content-Type: application/json');
$input = json_decode(file_get_contents('php://input'), true);
if ($input && isset($input['action'])) {
    $response = ['status' => 'ok', 'message' => 'Действие: ' . $input['action']];
} else {
    $response = ['status' => 'error', 'message' => 'Неверные данные'];
}
echo json_encode($response);
?>
<script>
fetch('ajax_handler.php', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({action: 'save'})
}).then(r => r.json()).then(console.log);
</script>
Частая ошибка: не отправлять заголовок Content-Type при использовании fetch – PHP не поймёт, как обработать данные. Решение: явно указывать Content-Type.

Как отправить данные из PHP на внешний сервер (cURL)?

Иногда требуется передать данные на другой веб-сервер (например, платёжный шлюз). Для этого используется библиотека cURL.

<?php
$ch = curl_init('https://api.example.com/submit');
$payload = json_encode(['key' => 'value']);
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
    echo 'Ошибка cURL: ' . curl_error($ch);
} else {
    echo 'HTTP код: ' . $httpCode . ', ответ: ' . $response;
}
curl_close($ch);
?>

Цель: интеграция с внешними API. Проблемы: неверные SSL-сертификаты (решение: CURLOPT_SSL_VERIFYPEER = false для тестирования, но не для продакшена), таймауты, некорректные заголовки.

Расширенные примеры отправки данных в PHP

Пример 1. Форма регистрации с валидацией и сохранением в файл

Пример
<!DOCTYPE html>
<html>
<body>
<form method="post" enctype="multipart/form-data">
    <label>Логин: <input type="text" name="login" required></label><br>
    <label>Пароль: <input type="password" name="pass" required></label><br>
    <label>Аватар: <input type="file" name="avatar" accept="image/*"></label><br>
    <label>Подписка на рассылку: <input type="checkbox" name="subscribe" value="yes"></label><br>
    <button type="submit">Зарегистрироваться</button>
</form>

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $login = trim($_POST['login'] ?? '');
    $pass = $_POST['pass'] ?? '';
    $subscribe = isset($_POST['subscribe']) ? 'да' : 'нет';
    
    $errors = [];
    if (strlen($login) < 3) $errors[] = 'Логин должен содержать минимум 3 символа';
    if (strlen($pass) < 6) $errors[] = 'Пароль должен быть не менее 6 символов';
    
    $avatarPath = '';
    if (isset($_FILES['avatar']) && $_FILES['avatar']['error'] === UPLOAD_ERR_OK) {
        $file = $_FILES['avatar'];
        $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
        $allowed = ['jpg', 'jpeg', 'png', 'gif'];
        if (in_array(strtolower($ext), $allowed) && $file['size'] < 2*1024*1024) {
            $avatarPath = 'uploads/avatar_' . uniqid() . '.' . $ext;
            move_uploaded_file($file['tmp_name'], $avatarPath);
        } else {
            $errors[] = 'Недопустимый формат или размер аватара';
        }
    }
    
    if (empty($errors)) {
        $record = [
            'login' => $login,
            'pass_hash' => password_hash($pass, PASSWORD_DEFAULT),
            'avatar' => $avatarPath,
            'subscribe' => $subscribe,
            'time' => date('Y-m-d H:i:s')
        ];
        file_put_contents('users.json', json_encode($record, JSON_PRETTY_PRINT) . PHP_EOL, FILE_APPEND | LOCK_EX);
        echo 'Регистрация успешна';
    } else {
        echo '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>';
    }
}
?>
</body>
</html>
Результат (при успехе): строка 'Регистрация успешна' и запись в файл users.json. При ошибке – список ошибок.

Пример 2. Приём нескольких одинаковых полей (массив) через POST

Пример
<!-- Форма с массивом -->
<form method="post">
    <input type="text" name="phones[]" placeholder="Телефон 1"><br>
    <input type="text" name="phones[]" placeholder="Телефон 2"><br>
    <input type="text" name="phones[]" placeholder="Телефон 3"><br>
    <button type="submit">Отправить</button>
</form>

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['phones'])) {
    $phones = array_map('trim', $_POST['phones']);
    $phones = array_filter($phones); // удаляем пустые
    echo 'Переданы номера: ' . implode(', ', array_map('htmlspecialchars', $phones));
}
?>

Пример 3. Отправка данных методом GET с несколькими параметрами и экранированием URL

Пример
<?php
// Генерация ссылки с параметрами
$base = 'https://site.com/search.php?';
$params = [
    'q' => 'php отправка',
    'page' => 2,
    'lang' => 'ru'
];
$url = $base . http_build_query($params);
echo 'Ссылка: <a href="' . htmlspecialchars($url) . '">перейти</a>';
// Результат: https://site.com/search.php?q=php+%D0%BE%D1%82%D0%BF%D1%80%D0%B0%D0%B2%D0%BA%D0%B0&page=2&lang=ru
?>

Пример 4. Загрузка нескольких файлов с именами в массиве

Пример
<form method="post" enctype="multipart/form-data">
    <input type="file" name="images[]" multiple>
    <button type="submit">Загрузить</button>
</form>

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_FILES['images'])) {
    $files = $_FILES['images'];
    $count = count($files['name']);
    for ($i = 0; $i < $count; $i++) {
        if ($files['error'][$i] === UPLOAD_ERR_OK) {
            $dest = 'uploads/' . basename($files['name'][$i]);
            move_uploaded_file($files['tmp_name'][$i], $dest);
            echo 'Файл ' . $files['name'][$i] . ' загружен как ' . $dest . '<br>';
        }
    }
}
?>

Пример 5. Отправка данных из PHP с помощью file_get_contents (stream context)

Пример
<?php
$data = ['username' => 'admin', 'password' => 'secret'];
$options = [
    'http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
        'content' => http_build_query($data)
    ]
];
$context = stream_context_create($options);
$result = file_get_contents('https://example.com/login', false, $context);
if ($result !== false) {
    echo 'Ответ сервера: ' . $result;
} else {
    echo 'Ошибка запроса';
}
?>
Результат: тело ответа от удалённого сервера.

Пример 6. Обработка PUT/DELETE запросов (REST)

Пример
<?php
$method = $_SERVER['REQUEST_METHOD'];
if ($method === 'PUT') {
    $data = json_decode(file_get_contents('php://input'), true);
    echo 'PUT данные: ' . print_r($data, true);
} elseif ($method === 'DELETE') {
    parse_str(file_get_contents('php://input'), $data);
    echo 'DELETE: ' . $data['id'];
} else {
    http_response_code(405);
}
?>

Пример 7. Отправка формы с токеном CSRF

Пример
<?php
session_start();
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) {
        die('CSRF атака!');
    }
    // дальнейшая обработка
    echo 'Данные приняты';
}
?>
<form method="post">
    <input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
    <button type="submit">Отправить</button>
</form>
При совпадении токена – 'Данные приняты'. При несовпадении – ошибка 'CSRF атака!'.

Отправка данных в PHP - comments

En
Send php (php)