Топ ошибок начинающих PHP разработчиков и как их избежать

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Почему PHP так коварен для новичков?

PHP остается одним из самых популярных языков для веб-разработки, но его низкий порог входа часто приводит к формированию плохих привычек. Начинающие разработчики, вдохновленные простотой синтаксиса, часто забывают о безопасности, производительности и современных стандартах. В этой статье мы разберем топ ошибок начинающих PHP разработчиков, которые могут превратить ваш код в кошмар для поддержки и уязвимость для атак.

Мы не будем просто перечислять проблемы — вы увидите примеры кода на PHP с ошибками и их исправленные версии. Это поможет вам сразу применять правильные практики.

1. Игнорирование безопасности: SQL-инъекции и XSS

Самая критичная ошибка — доверие пользовательским данным. Начинающие часто вставляют переменные прямо в SQL-запросы или выводят их на страницу без фильтрации.

Ошибка: Конкатенация в SQL запросах

Классический пример уязвимости:

// НЕПРАВИЛЬНО: уязвимость для SQL-инъекции
$id = $_GET['id'];
$query = "SELECT * FROM users WHERE id = $id";
$result = mysqli_query($link, $query);

Злоумышленник может передать ?id=1 OR 1=1 и получить все данные из таблицы.

Решение: Подготовленные запросы (PDO)

Используйте PDO или mysqli с подготовленными выражениями:

// ПРАВИЛЬНО: PDO с подготовленным запросом
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(['id' => $_GET['id']]);
$result = $stmt->fetchAll();

Ошибка: Вывод данных без экранирования (XSS)

Если вы выводите данные из базы или $_GET напрямую, вы рискуете получить XSS-атаку:

// НЕПРАВИЛЬНО: XSS уязвимость
echo "Привет, " . $_GET['name'];

Решение: htmlspecialchars

Всегда экранируйте вывод:

// ПРАВИЛЬНО: экранирование HTML
echo "Привет, " . htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');

2. Использование устаревших конструкций и функций

Многие учебники 10-летней давности учат использовать mysql_* функции или короткие теги. Это не только небезопасно, но и может не работать на современных хостингах.

Ошибка: mysql_* функции

// НЕПРАВИЛЬНО: устаревшее расширение
$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('test', $link);

Это расширение удалено из PHP 7, и код просто упадет с ошибкой.

Решение: Переход на PDO или MySQLi

// ПРАВИЛЬНО: PDO - современный и безопасный подход
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');

Ошибка: Короткие теги
// НЕПРАВИЛЬНО: может быть отключено в php.ini
<? echo "Hello"; ?>

Решение: Только полные теги

// ПРАВИЛЬНО: всегда используйте <?php
<?php echo "Hello"; ?>

3. Плохая работа с формами и данными

Начинающие разработчики часто забывают проверять, была ли форма отправлена, и используют $_REQUEST вместо конкретных суперглобальных массивов.

Ошибка: Отсутствие проверки метода отправки

// НЕПРАВИЛЬНО: код выполняется даже при GET запросе
$name = $_POST['name'];
// ... обработка

Решение: Проверка REQUEST_METHOD

// ПРАВИЛЬНО: проверяем, что форма отправлена
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name = $_POST['name'] ?? '';
    // ... валидация и обработка
}

Ошибка: Использование $_REQUEST

Суперглобальный массив $_REQUEST объединяет GET, POST и COOKIE. Это опасно, так как злоумышленник может переопределить POST-данные через URL:

// НЕПРАВИЛЬНО: небезопасно
$action = $_REQUEST['action'];

Решение: Явное указание источника

// ПРАВИЛЬНО: используем конкретный массив
$action = $_POST['action'] ?? 'default';

4. Пренебрежение структурированием кода

Когда весь код написан в одном файле index.php — это прямой путь к "спагетти-коду", который невозможно поддерживать.

Ошибка: Вся логика в одном файле

// НЕПРАВИЛЬНО: смешиваем HTML, SQL и логику
<?php
$conn = mysqli_connect(...);
$result = mysqli_query($conn, "SELECT * FROM posts");
while($row = mysqli_fetch_assoc($result)) {
    echo "<h2>" . $row['title'] . "</h2>";
    echo "<p>" . $row['content'] . "</p>";
}
?>

Решение: Разделение логики и представления

Используйте простой MVC-подход или хотя бы разделите код на функции и шаблоны:

// ПРАВИЛЬНО: выносим логику в функции
function getPosts($pdo) {
    $stmt = $pdo->query("SELECT * FROM posts");
    return $stmt->fetchAll();
}

$posts = getPosts($pdo);
// В шаблоне (например, template.php):
// <?php foreach ($posts as $post): ?>
//   <h2><?= htmlspecialchars($post['title']) ?></h2>
//   <p><?=                

Блоги

Рекомендаций по книгам