Работа с изображениями в PHP: все способы вывода и обработки

Раздел: Разработка сайтов -> Медиа и изображения

Основные методы работы с изображениями в PHP

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

// image.php
$filename = __DIR__ . '/uploads/' . basename($_GET['file']);
if (!file_exists($filename)) {
    http_response_code(404);
    exit('Изображение не найдено');
}
$mime = mime_content_type($filename);
header('Content-Type: ' . $mime);
header('Content-Length: ' . filesize($filename));
header('Cache-Control: public, max-age=86400');
readfile($filename);

Page img php (изображение на php)

В этом примере скрипт принимает имя файла через GET-параметр, проверяет его существование, устанавливает правильный MIME-тип и размер, включает кеширование и выводит содержимое. Использование basename предотвращает directory traversal.

Типичная ошибка: если после readfile или до заголовков происходит вывод любого текста (включая пробелы), то заголовки не отправляются. Решение - убедиться, что перед header() нет вывода, использовать ob_start() и ob_end_clean() при необходимости.

Другая проблема: изображение не отображается, если MIME-тип определён неверно. Проверяйте mime_content_type или задавайте явный тип по расширению.

Цель и случаи использования: защита прямых ссылок, контроль доступа, логирование скачиваний, динамическая обработка (например, изменение размера).

Как вывести изображение из базы данных?

Изображения можно хранить в BLOB-поле MySQL. При запросе PHP читает данные из БД и выводит их с заголовком Content-Type, полученным из другого поля или заданным вручную.

// Пример для MySQLi
$stmt = $db->prepare('SELECT mime, data FROM images WHERE id = ?');
$stmt->bind_param('i', $id);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($mime, $data);
$stmt->fetch();
header('Content-Type: ' . $mime);
echo $data;

Проблема: изображение может быть слишком большим для хранения в БД и медленно выводиться. Решение - хранить в БД только метаданные, а файлы - на диске.

Ошибка: не указан MIME-тип - браузер может не распознать формат. Храните mime вместе с данными.

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

Как изменить размер изображения на лету?

Библиотека GD или Imagick позволяет ресайзить изображение перед выводом. Пример с GD:

$src = imagecreatefromjpeg('photo.jpg');
$width = imagesx($src);
$height = imagesy($src);
$new_w = 200;
$new_h = intval($height * $new_w / $width);
$thumb = imagecreatetruecolor($new_w, $new_h);
imagecopyresampled($thumb, $src, 0,0,0,0, $new_w, $new_h, $width, $height);
header('Content-Type: image/jpeg');
imagejpeg($thumb, null, 90);
imagedestroy($src);
imagedestroy($thumb);

Ошибка: если параметры ширины и высоты не пропорциональны, изображение искажается. Сохраняйте пропорции, как в примере.

Проблема: при частых запросах создание миниатюр нагружает сервер. Используйте кеширование сгенерированных файлов.

Цель: отображение миниатюр, адаптивных вариантов для разных устройств.

Как защитить изображения от прямого доступа?

Скрипт вывода проверяет сессию, куки или права пользователя перед чтением файла.

session_start();
if (!isset($_SESSION['user_id'])) {
    http_response_code(403);
    exit('Доступ запрещён');
}
$filename = '/private/'.$fileName;
header('Content-Type: image/jpeg');
readfile($filename);

Ошибка: если файл физически доступен по URL (например, в public_html), защита не сработает. Храните файлы вне document root.

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

Цель: платный контент, изображения только для авторизованных пользователей.

Как создать изображение с текстом?

GD позволяет наносить текст на изображение. Полезно для создания капчи, сертификатов, водяных знаков.

$im = imagecreatetruecolor(400, 100);
$bg = imagecolorallocate($im, 255, 255, 255);
$textcolor = imagecolorallocate($im, 0, 0, 0);
imagefilledrectangle($im, 0, 0, 400, 100, $bg);
$font = 'arial.ttf';
imagettftext($im, 20, 0, 50, 60, $textcolor, $font, 'Привет, мир!');
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);

Ошибка: если шрифт не найден, функция вернёт false. Укажите абсолютный путь к файлу шрифта.

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

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

Расширенные примеры работы с изображениями в PHP

1. Скрипт вывода с кешированием (ETag и Last-Modified)

Этот скрипт позволяет клиенту кешировать изображение и не загружать его повторно, если оно не изменилось.

Пример
$filename = __DIR__ . '/images/picture.jpg';
if (!file_exists($filename)) {
    http_response_code(404);
    exit;
}
$lastModified = filemtime($filename);
$etag = md5_file($filename);
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastModified) . ' GMT');
header('ETag: "' . $etag . '"');
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
    $ifMod = $_SERVER['HTTP_IF_MODIFIED_SINCE'] ?? '';
    $ifNone = $_SERVER['HTTP_IF_NONE_MATCH'] ?? '';
    if (strtotime($ifMod) >= $lastModified || $ifNone === '"'.$etag.'"') {
        http_response_code(304);
        exit;
    }
}
$mime = mime_content_type($filename);
header('Content-Type: ' . $mime);
header('Content-Length: ' . filesize($filename));
readfile($filename);
Браузер получит код 304 Not Modified и использует закешированную версию.

2. Обработка загрузки изображения с созданием миниатюры

Загрузка файла на сервер с проверкой типа, размера и последующей генерацией миниатюры.

Пример
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['image'])) {
    $file = $_FILES['image'];
    $allowed = ['image/jpeg', 'image/png', 'image/gif'];
    if (!in_array($file['type'], $allowed)) {
        die('Недопустимый тип файла');
    }
    if ($file['size'] > 5 * 1024 * 1024) {
        die('Файл слишком большой');
    }
    $uploadPath = __DIR__ . '/uploads/' . basename($file['name']);
    move_uploaded_file($file['tmp_name'], $uploadPath);
    // Создание миниатюры 150x150
    $thumb = imagecreatetruecolor(150, 150);
    $src = imagecreatefromjpeg($uploadPath);
    imagecopyresampled($thumb, $src, 0,0,0,0, 150, 150, imagesx($src), imagesy($src));
    $thumbPath = __DIR__ . '/thumbs/thumb_' . $file['name'];
    imagejpeg($thumb, $thumbPath, 80);
    imagedestroy($src);
    imagedestroy($thumb);
    echo 'Изображение загружено и миниатюра создана';
}
На сервере появятся оригинал в uploads/ и миниатюра в thumbs/

3. Наложение водяного знака с прозрачностью

Добавление полупрозрачного логотипа в нижний правый угол изображения.

Пример
$src = imagecreatefromjpeg('photo.jpg');
$watermark = imagecreatefrompng('logo.png');
$srcW = imagesx($src);
$srcH = imagesy($src);
$wmW = imagesx($watermark);
$wmH = imagesy($watermark);
$dstX = $srcW - $wmW - 10;
$dstY = $srcH - $wmH - 10;
imagecopy($src, $watermark, $dstX, $dstY, 0, 0, $wmW, $wmH);
header('Content-Type: image/jpeg');
imagejpeg($src, null, 90);
imagedestroy($src);
imagedestroy($watermark);
На выходном изображении в правом нижнем углу отобразится логотип.

4. Генерация изображения-заглушки (placeholder) с текстом

Создание простого изображения с заданными размерами и текстом, например, для тестовых макетов.

Пример
function createPlaceholder($width, $height, $text) {
    $im = imagecreatetruecolor($width, $height);
    $bg = imagecolorallocate($im, 200, 200, 200);
    $textColor = imagecolorallocate($im, 50, 50, 50);
    imagefilledrectangle($im, 0, 0, $width, $height, $bg);
    $fontSize = max(12, min($width, $height) / 10);
    $fontFile = __DIR__ . '/fonts/arial.ttf';
    $bbox = imagettfbbox($fontSize, 0, $fontFile, $text);
    $textWidth = $bbox[2] - $bbox[0];
    $textHeight = $bbox[1] - $bbox[7];
    $x = ($width - $textWidth) / 2;
    $y = ($height + $textHeight) / 2;
    imagettftext($im, $fontSize, 0, $x, $y, $textColor, $fontFile, $text);
    header('Content-Type: image/png');
    imagepng($im);
    imagedestroy($im);
}
// Пример вызова
createPlaceholder(400, 300, '300 x 400');
Браузер отобразит серый прямоугольник с текстом "300 x 400" по центру.

Изображение на PHP - comments

En
Page img php (php)