Перейти к содержимому
Поиск
Php Разработка

PHP: полный мануал с примерами, функциями и ООП

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

Александр НекрасовИзменено:
Практический мануал PHP: от переменных и функций к объектной модели интернет-магазина
PHP 8.5.11468 глав6256 карточек справочника
Дерево руководства

Глава 402 · С первых объектов и простейшего сохранения изображения

Gmagick: установка, окружение и первый работающий маршрут

От первого PNG до диагностики CLI/web, доступных форматов, файла шрифта и понятных статусов импорта.

Для чего Gmagick и из чего состоит обработка

Gmagick связывает PHP с библиотекой GraphicsMagick: позволяет создавать изображения, изменять их и читать метаданные. Это отдельное PHP-расширение, не другое имя Imagick. Установка команды gm в системе сама по себе не создаёт класс Gmagick в PHP. Вводный маршрут: сначала реальный PNG, затем установка/диагностика того PHP, который исполняет ваш код, затем работа с форматами и ресурсами.

Что участвует в выполнении
  1. Ваш PHP-код вызывает класс Gmagick.
  2. Загруженное расширение передаёт операцию библиотеке GraphicsMagick.
  3. Библиотека использует доступные кодировщики, шрифты и при необходимости внешние делегаты.
  4. На выходе появляется файл или объект ошибки; их проверяют отдельно.

PHP.net помечает Gmagick как экспериментальное расширение: интерфейс и поведение могут меняться. Это причина фиксировать рабочую среду и проверять свой маршрут. Официальное введение перечисляет более 88 основных форматов, включая DPX, GIF, JPEG, JPEG-2000, PNG, PDF, PNM и TIFF; число и названия не гарантируют поддержку каждого из них в вашей сборке. Здесь показаны настоящие результаты конкретных PNG/JPEG-маршрутов.

В книге три рабочих класса: Gmagick — изображение, GmagickDraw — команды рисования, GmagickPixel — цвет. Отдельно разобраны два класса исключений. Далее: константы и законченные рецепты.

Получить первый PNG четырьмя понятными действиями

Нужна основа будущего баннера: прямоугольный PNG выбранного цвета. Начнём без входной фотографии, шрифтов, собственных функций и обработки формы. Четыре строки ниже — само действие из исполняемой программы; после него появляется настоящий файл, а не только строка с размерами.

$image = new Gmagick();
$image->newImage(240, 160, '#245f7a');
$image->setImageFormat('PNG');
$image->writeImage(__DIR__ . '/first.png');

$image — переменная, в которой хранится объект изображения. new Gmagick() создаёт пустой объект; ещё никаких пикселей в нём нет. newImage(240,160,...) создаёт холст шириной 240 и высотой 160 пикселей; строка #245f7a задаёт цвет. Стрелка -> означает вызов метода этого объекта. setImageFormat выбирает PNG, writeImage записывает файл. __DIR__ означает каталог текущего скрипта, точка . склеивает его с именем файла. Это путь на диске сервера, а не адрес картинки для браузера. Чтобы просто получить холст, служебные измерения ниже не нужны.

Первый настоящий PNG: ровный синий холст 240 × 160, RGB 36,95,122. Файл можно открыть; это исходная поверхность для дальнейшего рисунка.
Первый настоящий PNG: ровный синий холст 240 × 160, RGB 36,95,122. Файл можно открыть; это исходная поверхность для дальнейшего рисунка.

Самостоятельный пример с входами и результатами

Получить первый PNG четырьмя понятными действиямиСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/gm104-foundation-fixture.php';
gmRestore();

$image = new Gmagick();
$image->newImage(240, 160, '#245f7a');
$image->setImageFormat('PNG');
$image->writeImage(__DIR__ . '/gm104-env-first-png-first.png');
$saved = new Gmagick(__DIR__ . '/gm104-env-first-png-first.png');

$checks=[
    'png_readable'=>$saved->getImageFormat()==='PNG',
    'size_240x160'=>$saved->getImageWidth()===240 && $saved->getImageHeight()===160,
    'chosen_rgb'=>gmRgb('gm104-env-first-png-first.png',120,80)===[36,95,122]
];
gmReport('gm104-env-first-png',["gmagick.newimage", "gmagick.setimageformat", "gmagick.writeimage", "gmagick.construct"],["gm104-env-first-png-first.png"],$checks,$errors??[],[]);
echo "first.png: PNG 240x160 RGB=36,95,122\n";
Ожидаемый результат
first.png: PNG 240x160 RGB=36,95,122

Скачайте архив, распакуйте в отдельный каталог и выполните php example.php с Gmagick. Короткий фрагмент выше показывает само действие. Полный пример добавляет служебный gm104-foundation-fixture.php: он восстанавливает вложенные входы с SHA256, сохраняет PNG/JPEG и измерения metrics.json. Эти проверки нужны для воспроизводимости урока, а не для каждого обычного вызова API. Результаты и дополнительные JSON появятся после запуска. Вход workshop.ppm имеет собственный генератор make-input.py; где нужен DejaVuSans.ttf, вложены шрифт и лицензия.

Измените цвет на #d25b2d или ширину на 300 и откройте сохранённый файл. Размеры и фон должны измениться соответственно. Проверочная программа поставляется отдельно с подробной квитанцией; она исполняет те же четыре операции и затем перечитывает PNG.

Связанные основы: переменная, класс, объект и ->, массив и ключ, try/catch.

Как выбрать PHP и его конфигурацию

Сначала определите целевой процесс: PHP из терминала, PHP-FPM сайта, Apache-модуль или конкретный PHP хостинг-панели. У них могут быть разные версии, ini и каталоги расширений. Настройка именно одного процесса не включает расширение автоматически во всех остальных. После изменения конфигурации перезапускают соответствующий сервис/рабочие процессы, а новый CLI-процесс перечитывает свою конфигурацию при запуске.

php -v
php --ini
php -m

Это команды терминала, не строки PHP. Они показывают версию, найденные ini и список модулей выбранного php из PATH. При нескольких установках вызывайте нужный исполняемый файл по полному пути. В полном примере runtime-report ниже те же различия записываются средствами самого PHP. Сопоставьте состояние с браузерным PHP в закрытом тестовом окружении; CLI-прогон не является HTTP-проверкой вашего сайта.

Требования и реальная совместимость версий

Нужны совместимые PHP, расширение gmagick и библиотека GraphicsMagick. Официальная страница Requirements всё ещё содержит рекомендацию «1.4+» и упоминание старых версий до 1.2.6; это исторический текст, который нельзя превращать в обязательное требование установить несуществующую для вашего маршрута ветку. Карточка пакета PECL задаёт требования по выпускам: с Gmagick 2.0.0RC1 — GraphicsMagick 1.3.17+ и PHP 7.0.1+; с 2.0.5RC1 — GraphicsMagick 1.3.20+ и PHP 7.0.1+. Для старой ветки PHP выше 5.1.3, но ниже 7.0.1 там указан 1.1.7RC3; это справочная совместимость старого ПО, не рекомендация разворачивать его сейчас.

Эти нижние границы не доказывают, что старый исходный пакет без изменений соберётся с любой новой PHP. Наши примеры выполняются на PHP 8.3.6, Gmagick 2.0.6RC1 и GraphicsMagick 1.3.42 Q16 из изолированной совместимой сборки. Официальная история GraphicsMagick продолжает ветку 1.3; для установки выбирайте поддерживаемую сборку своей платформы и проверяйте её зависимости. Q16 обозначает Quantum-глубину каналов библиотеки, а не обязательную 16-битную глубину каждого выходного PNG.

ЗависимостьЧто нужно подтвердить
PHP + расширениеСовпадение версии/ABI, архитектуры и режима сборки; extension_loaded и наличие класса в целевом процессе.
GraphicsMagickВерсия связанной библиотеки через Gmagick::getVersion, доступность её динамических зависимостей.
ФорматСписок возможностей плюс реальная запись/чтение именно нужного формата.
ШрифтыДоступный настроенный шрифт либо читаемый лицензированный файл, переданный setFont.
ФайлыПуть, существование входа, права пользователя PHP и фактическая возможность записи результата.

Как установить и подтвердить загрузку расширения

Официальное имя расширения — gmagick. PHP.net отсылает к установке PECL-расширений и странице пакета с исходниками, выпусками, сопровождающими и CHANGELOG. На текущей странице общего установщика PECL уже рекомендован заменяющий его PIE; это не подтверждает, что любой старый релиз Gmagick доступен через конкретную команду PIE. Выбирайте доступный поддерживаемый способ именно для своей версии PHP. Наш проверочный runtime использует пакетную совместимую сборку, а не обещает заново собрать старый upstream на любой ОС.

Путь установкиПоследовательность
Пакет платформы/хостинг-панельНайти gmagick для выбранной версии PHP, проверить зависимости и совместимость; установить в это окружение, включить модуль в нужном SAPI, перезапустить соответствующий сервис, выполнить первый PNG.
Сборка исходников UnixПодготовить инструменты и development-файлы PHP/GraphicsMagick; выполнить phpize выбранного PHP, configure с соответствующим php-config, make и установку; затем подключить модуль и проверить загрузку. Это схема сборки, не выполненная этим уроком универсальная команда.
Windows DLLНужен совместимый php_gmagick.dll и его библиотечные зависимости. Сопоставляются версия PHP, x86/x64, TS/NTS, debug и ABI/компилятор. DLL другой PHP не становится совместимой после переименования. При отсутствии подходящего бинарного выпуска требуется поддерживаемая сборка, а не произвольная старая DLL.
; php.ini выбранного процесса, после установки совместимого модуля
extension=gmagick

Строка extension только загружает уже установленный модуль; не скачивает его и не устанавливает GraphicsMagick. При загрузке могут обнаружиться отсутствующие системные библиотеки или несовместимый ABI. Это startup-ошибка PHP ещё до вашего try/catch, поэтому начинайте с вывода запуска и конфигурации. На странице PECL 2.0.6RC1 имеет состояние beta: сообщение установщика о preferred state stable не означает, что класс уже установлен. Не подменяйте gmagick на imagick в ini — это разные расширения. Не удаляйте рабочее другое расширение ради этого урока: диагностику можно выполнять в отдельном PHP-окружении.

После включения проверьте отчёт целевого процесса, затем первый настоящий PNG. Примеры с данными и шрифтом распаковываются в отдельный рабочий каталог; полный example.php восстанавливает только свои вложенные входы и сохраняет результаты рядом с собой.

Отличить PHP в терминале от PHP сайта по отчёту

В браузере Gmagick работает, а тесты из терминала сообщают Class not found. Часто запущены разные PHP или загружены разные ini. Сначала получим факты об одном процессе: как он запущен, какой исполняемый файл и конфигурацию использует, есть ли расширение и с какой библиотекой оно связано. Результат здесь — полезный JSON-отчёт, изображение для этой задачи не требуется.

echo PHP_SAPI, "\n";
var_dump(php_ini_loaded_file());
var_dump(extension_loaded('gmagick'));
var_dump(class_exists('Gmagick', false));

PHP_SAPI — режим выполнения: например cli для терминала, fpm-fcgi для PHP-FPM, cli-server для встроенного сервера. php_ini_loaded_file возвращает путь либо false, когда основной ini не загружен. extension_loaded отвечает true/false об этом процессе; class_exists проверяет класс без запуска автозагрузки благодаря второму аргументу false. В нашем изолированном CLI запуске используется -n: отсутствие ini ожидаемо, а расширение подключается параметром -d. Это не инструкция отключать конфигурацию рабочего сайта. Полная программа сохраняет PHP_BINARY, дополнительные ini и версии в runtime.json. Она проверена в CLI; работа вашего FPM этим не подтверждается.

Ожидаемый продукт — runtime.json и строки результата ниже. Его значения берутся из реально выполняющегося процесса; здесь не создаётся изображение, потому что задача — сравнить окружения.

Самостоятельный пример с входами и результатами

Отличить PHP в терминале от PHP сайта по отчётуСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/gm104-foundation-fixture.php';
gmRestore();

$engine = new Gmagick();
$report = [
    'php_version' => PHP_VERSION,
    'sapi' => PHP_SAPI,
    'php_binary' => PHP_BINARY,
    'loaded_ini' => php_ini_loaded_file() ?: null,
    'scanned_ini' => php_ini_scanned_files() ?: null,
    'extension_loaded' => extension_loaded('gmagick'),
    'extension_version' => phpversion('gmagick'),
    'class_available' => class_exists('Gmagick', false),
    'graphicsmagick' => Gmagick::getVersion(),
    'quantum_depth' => $engine->getQuantumDepth(),
    'scope' => 'This report describes only the PHP process that executed it.'
];
gmJson('gm104-env-runtime-report-runtime.json', $report);

$checks=[
    'extension_loaded'=>$report['extension_loaded']===true,
    'class_available'=>$report['class_available']===true,
    'sapi_recorded'=>is_string($report['sapi']) && $report['sapi']!=='',
    'linked_library_recorded'=>isset($report['graphicsmagick']['versionString'])
];
gmReport('gm104-env-runtime-report',["gmagick.getversion", "gmagick.getquantumdepth"],[],$checks,$errors??[],$report);
echo "runtime.json: PHP binary, SAPI, ini, extension and linked-library versions recorded\nScope=current-process; web-PHP-not-assumed\n";
Ожидаемый результат
runtime.json: PHP binary, SAPI, ini, extension and linked-library versions recorded
Scope=current-process; web-PHP-not-assumed

Скачайте архив, распакуйте в отдельный каталог и выполните php example.php с Gmagick. Короткий фрагмент выше показывает само действие. Полный пример добавляет служебный gm104-foundation-fixture.php: он восстанавливает вложенные входы с SHA256, сохраняет PNG/JPEG и измерения metrics.json. Эти проверки нужны для воспроизводимости урока, а не для каждого обычного вызова API. Результаты и дополнительные JSON появятся после запуска. Вход workshop.ppm имеет собственный генератор make-input.py; где нужен DejaVuSans.ttf, вложены шрифт и лицензия.

Сравните этот отчёт с тем же диагностическим фрагментом в защищённом тестовом окружении сайта: SAPI, версия PHP, путь ini и наличие расширения должны объяснить различие. Не публикуйте постоянный phpinfo или полный отчёт о сервере. Если расширение есть, но ошибка называет Helper\Gmagick, отдельно проверьте пространство имён: new \Gmagick() обращается к глобальному классу.

Связанные основы: переменная, класс, объект и ->, массив и ключ, try/catch.

Из реальной задачи разработчика

How to add Gmagick class(Load library) to Codeception?. В Apache класс работает, а в Codeception/CLI не находится; в ошибке иногда появляется Helper\Gmagick. Показываем отдельный отчёт текущего PHP: SAPI, бинарный файл, ini, наличие расширения. Затем отделяем конфигурацию CLI/web от правила пространств имён; глобальное имя не устанавливает отсутствующее расширение.

Проверить формат настоящей записью и повторным чтением

Приложению нужно сохранять схему в PNG и JPEG. Наличие названия в queryFormats ещё не доказывает, что конкретный ввод читается и результат записывается: часть форматов использует внешние зависимости и ограничения. Проверим интересующий маршрут целиком: собственный PPM → файл нужного формата → повторное чтение размеров и пикселей.

$image = new Gmagick(__DIR__ . '/workshop.ppm');
$image->setImageFormat('JPEG');
$image->setCompressionQuality(82);
$image->writeImage(__DIR__ . '/card.jpg');

PPM workshop.ppm находится в архиве в base64 и восстанавливается полным example.php; для короткого фрагмента он уже должен лежать рядом со скриптом. Расширение имени .jpg само по себе не является настройкой кодировщика: формат задан явно. Число 82 — настройка JPEG-качества, а не обещание сохранить 82% исходного размера. PNG проверяется на равенство всех RGB; от JPEG равенство пикселей не требуется. В этой сборке queryFormats игнорирует переданный pattern и возвращает весь список, поэтому полный код запрашивает * и проверяет точное имя через in_array. Сохранённые JPEG и PNG действительно открываются; успешный список других форматов не выдаётся за их испытание.

PNG: собственная схема сохраняет исходные RGB без потерь.
PNG: собственная схема сохраняет исходные RGB без потерь.
JPEG quality 82: тот же сюжет и размер; файл действительно JPEG. Возле цветных границ возможны изменения из-за сжатия.
JPEG quality 82: тот же сюжет и размер; файл действительно JPEG. Возле цветных границ возможны изменения из-за сжатия.

Самостоятельный пример с входами и результатами

Проверить формат настоящей записью и повторным чтениемСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/gm104-foundation-fixture.php';
gmRestore();

$source = new Gmagick(__DIR__ . '/workshop.ppm');
$formats = array_map('strtoupper', $source->queryFormats('*'));
if (!in_array('PNG', $formats, true) || !in_array('JPEG', $formats, true)) {
    throw new RuntimeException('This example needs PNG and JPEG in the configured build');
}
gmPng($source, 'gm104-env-format-roundtrip-lossless.png');
$jpeg = clone $source;
$jpeg->setImageFormat('JPEG');
$jpeg->setCompressionQuality(82);
$jpeg->writeImage(__DIR__ . '/gm104-env-format-roundtrip-compressed.jpg');
$openedPng = new Gmagick(__DIR__ . '/gm104-env-format-roundtrip-lossless.png');
$openedJpeg = new Gmagick(__DIR__ . '/gm104-env-format-roundtrip-compressed.jpg');
$receipt = ['listed'=>['PNG'=>in_array('PNG',$formats,true),'JPEG'=>in_array('JPEG',$formats,true)],
    'png'=>gmInspect('gm104-env-format-roundtrip-lossless.png'), 'jpeg'=>gmInspect('gm104-env-format-roundtrip-compressed.jpg'),
    'png_pixel_signature_matches'=>$source->getImageSignature()===$openedPng->getImageSignature()];
gmJson('gm104-env-format-roundtrip-formats.json', $receipt);

$checks=[
    'png_roundtrip'=>$openedPng->getImageFormat()==='PNG' && $openedPng->getImageWidth()===240 && $openedPng->getImageHeight()===160,
    'jpeg_roundtrip'=>$openedJpeg->getImageFormat()==='JPEG' && $openedJpeg->getImageWidth()===240 && $openedJpeg->getImageHeight()===160,
    'lossless_pixels'=>$receipt['png_pixel_signature_matches']===true
];
gmReport('gm104-env-format-roundtrip',["gmagick.queryformats", "gmagick.setimageformat", "gmagick.setcompressionquality", "gmagick.writeimage", "gmagick.construct"],["gm104-env-format-roundtrip-lossless.png", "gm104-env-format-roundtrip-compressed.jpg"],$checks,$errors??[],$receipt);
echo "formats: PNG=written-and-read JPEG=written-and-read\nBoth=240x160 PNG-RGB=unchanged formats.json=written\n";
Ожидаемый результат
formats: PNG=written-and-read JPEG=written-and-read
Both=240x160 PNG-RGB=unchanged formats.json=written

Скачайте архив, распакуйте в отдельный каталог и выполните php example.php с Gmagick. Короткий фрагмент выше показывает само действие. Полный пример добавляет служебный gm104-foundation-fixture.php: он восстанавливает вложенные входы с SHA256, сохраняет PNG/JPEG и измерения metrics.json. Эти проверки нужны для воспроизводимости урока, а не для каждого обычного вызова API. Результаты и дополнительные JSON появятся после запуска. Вход workshop.ppm имеет собственный генератор make-input.py; где нужен DejaVuSans.ttf, вложены шрифт и лицензия.

Если PNG получился, а PDF не читается, не переустанавливайте всё расширение вслепую. Проверьте поддержку конкретного формата, его внешние зависимости и само содержимое файла; затем сделайте такой же небольшой реальный roundtrip. Здесь проверены только показанные PNG/JPEG, не произвольный PDF.

Полный контракт и отдельный пример фильтрации списка — Gmagick::queryFormats.

Связанные основы: переменная, класс, объект и ->, массив и ключ, try/catch.

Нарисовать подпись проверенным файлом шрифта

Для карточки нужна надпись. На одном сервере указанное имя шрифта существует, на другом — нет. Системный queryFonts и конкретный файл TTF отвечают на разные вопросы. В архив вложен лицензированный DejaVuSans.ttf: его содержимое проверяется по SHA256, а setFont получает полный путь к нему. Получаем настоящую подпись, даже если системный каталог имён пуст.

$draw = new GmagickDraw();
$draw->setFont(__DIR__ . '/DejaVuSans.ttf');
$draw->setFontSize(24);
$draw->setFillColor(new GmagickPixel('#245f7a'));
$image->annotateImage($draw, 18, 88, 0, 'Ready to draw');

$image здесь — холст первого примера. GmagickDraw хранит настройки текста; GmagickPixel представляет выбранный цвет. Подробно эти роли разобраны в следующей главе. Пара 18,88 задаёт положение надписи, 0 — угол поворота. Для полного примера холст и шрифт создаются/восстанавливаются самостоятельно. Выход font.json содержит настроенные системные имена и фактически использованный файл. Пустой queryFonts не означает, что метод annotateImage обязательно не работает; отсутствие доступного TTF — уже другая причина.

Подпись Ready to draw, размер шрифта 24: использован вложенный DejaVuSans.ttf; пустой системный список не мешает явному файлу.
Подпись Ready to draw, размер шрифта 24: использован вложенный DejaVuSans.ttf; пустой системный список не мешает явному файлу.

Самостоятельный пример с входами и результатами

Нарисовать подпись проверенным файлом шрифтаСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/gm104-foundation-fixture.php';
gmRestore();

$image = gmCanvas();
$configuredNames = $image->queryFonts('*');
$fontFile = __DIR__ . '/DejaVuSans.ttf';
if (!is_file($fontFile) || !is_readable($fontFile)) {
    throw new RuntimeException('Bundled font file is unavailable');
}
$draw = new GmagickDraw();
$draw->setFont($fontFile);
$draw->setFontSize(24);
$draw->setFillColor(new GmagickPixel('#245f7a'));
$image->annotateImage($draw, 18, 88, 0, 'Ready to draw');
gmPng($image, 'gm104-env-font-preflight-label.png');
$receipt = ['configured_font_names'=>$configuredNames,'selected_file'=>basename($draw->getFont()),
    'font_sha256'=>hash_file('sha256',$fontFile),'result'=>'gm104-env-font-preflight-label.png'];
gmJson('gm104-env-font-preflight-font.json', $receipt);

$checks=[
    'font_list_is_array'=>is_array($configuredNames),
    'selected_file'=>basename($draw->getFont())==='DejaVuSans.ttf',
    'text_changed_pixels'=>$image->getImageColors()>1
];
gmReport('gm104-env-font-preflight',["gmagick.queryfonts", "gmagick.annotateimage", "gmagickdraw.setfont", "gmagickdraw.getfont", "gmagickdraw.setfontsize", "gmagickdraw.setfillcolor"],["gm104-env-font-preflight-label.png"],$checks,$errors??[],$receipt);
echo "font: file=DejaVuSans.ttf label=Ready to draw PNG=240x160\nConfigured-font-list=recorded file-hash=verified\n";
Ожидаемый результат
font: file=DejaVuSans.ttf label=Ready to draw PNG=240x160
Configured-font-list=recorded file-hash=verified

Скачайте архив, распакуйте в отдельный каталог и выполните php example.php с Gmagick. Короткий фрагмент выше показывает само действие. Полный пример добавляет служебный gm104-foundation-fixture.php: он восстанавливает вложенные входы с SHA256, сохраняет PNG/JPEG и измерения metrics.json. Эти проверки нужны для воспроизводимости урока, а не для каждого обычного вызова API. Результаты и дополнительные JSON появятся после запуска. Вход workshop.ppm имеет собственный генератор make-input.py; где нужен DejaVuSans.ttf, вложены шрифт и лицензия.

Замените путь к шрифту на несуществующий. В прикладном коде остановите задачу на проверке файла и сообщите, какой ресурс отсутствует. Не считайте отсутствие текста «успешным PNG»: для подписи важен видимый результат. При добавлении стороннего шрифта сохраните его лицензию вместе с источником.

Связанные основы: переменная, класс, объект и ->, массив и ключ, try/catch.

Записать результат относительно скрипта и обработать неверный каталог

Изображение читается, но готовое превью не находится или записывается не туда. Относительный путь зависит от рабочего каталога процесса; __DIR__ фиксирует место относительно PHP-файла. Успешно сохраним результат рядом со скриптом и отдельно намеренно передадим путь с отсутствующим каталогом, чтобы увидеть ошибку записи.

$input = __DIR__ . '/workshop.ppm';
$output = __DIR__ . '/preview.png';
$image = new Gmagick($input);
$image->thumbnailImage(120, 80, true);
$image->setImageFormat('PNG');
$image->writeImage($output);

Вход из архива должен быть восстановлен перед коротким фрагментом. thumbnailImage уменьшает до 120×80, true просит сохранить пропорции. Полная программа сначала проверяет существование и читаемость входа, а затем реально записывает PNG. writeImage не создаёт отсутствующую цепочку каталогов за вас. is_writable — предварительная подсказка, но не гарантия будущей записи; окончательный результат подтверждает сам вызов и повторное чтение файла. В этом сценарии не подставляется путь из пользовательского запроса: имена входа и выхода определены приложением.

Результат рядом со скриптом: превью 120 × 80. Ошибка отдельного отсутствующего каталога поймана; корректный файл сохранён.
Результат рядом со скриптом: превью 120 × 80. Ошибка отдельного отсутствующего каталога поймана; корректный файл сохранён.

Самостоятельный пример с входами и результатами

Записать результат относительно скрипта и обработать неверный каталогСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/gm104-foundation-fixture.php';
gmRestore();

$sourcePath = __DIR__ . '/workshop.ppm';
$outputPath = __DIR__ . '/gm104-env-output-paths-result.png';
if (!is_file($sourcePath) || !is_readable($sourcePath)) {
    throw new RuntimeException('Input file cannot be read');
}
$image = new Gmagick($sourcePath);
$image->thumbnailImage(120, 80, true);
$image->setImageFormat('PNG');
$image->writeImage($outputPath);

$errors = ['missing_directory'=>gmTry(fn()=>$image->writeImage(__DIR__.'/absent-output-104/result.png'))];
$receipt = ['input_basename'=>basename($sourcePath),'output_basename'=>basename($outputPath),
    'output_directory'=>__DIR__,'file_created'=>is_file($outputPath),
    'failed_target'=>'absent-output-104/result.png'];
gmJson('gm104-env-output-paths-paths.json',$receipt);

$checks=[
    'output_exists'=>$receipt['file_created']===true,
    'known_output_size'=>$image->getImageWidth()===120 && $image->getImageHeight()===80,
    'invalid_destination_caught'=>$errors['missing_directory']['ok']===false
];
gmReport('gm104-env-output-paths',["gmagick.construct", "gmagick.thumbnailimage", "gmagick.setimageformat", "gmagick.writeimage"],["gm104-env-output-paths-result.png"],$checks,$errors??[],$receipt);
echo "paths: valid-local-output=written missing-directory=caught\nResult=120x80 paths.json=written\n";
Ожидаемый результат
paths: valid-local-output=written missing-directory=caught
Result=120x80 paths.json=written

Скачайте архив, распакуйте в отдельный каталог и выполните php example.php с Gmagick. Короткий фрагмент выше показывает само действие. Полный пример добавляет служебный gm104-foundation-fixture.php: он восстанавливает вложенные входы с SHA256, сохраняет PNG/JPEG и измерения metrics.json. Эти проверки нужны для воспроизводимости урока, а не для каждого обычного вызова API. Результаты и дополнительные JSON появятся после запуска. Вход workshop.ppm имеет собственный генератор make-input.py; где нужен DejaVuSans.ttf, вложены шрифт и лицензия.

При переносе в отдельный каталог создайте его осознанно, проверьте владельца и права учётной записи PHP, затем повторите короткую запись. URL вида /uploads/preview.png и путь на диске — разные значения; HTML-тег img должен получать URL опубликованного файла, а Gmagick — путь или поддерживаемый источник.

Связанные основы: переменная, класс, объект и ->, массив и ключ, try/catch.

Из реальной задачи разработчика

how to install gmagick extension of php on windows vista. После установки на Windows класс уже создаётся, но относительный путь к изображению вызывает Unable to open file. Проверяем именно путь и доступность входа: __DIR__, существование файла, читаемость и фактическое чтение/запись. Наличие GmagickException вместо Class not found означает другую стадию диагностики. Gmagick не объявляется новой версией Imagick.

Продолжить пакетный импорт после одного плохого файла

Небольшая очередь обработки содержит три задания: исправную схему, отсутствующий файл и текст вместо изображения. Один плохой элемент не должен скрыть успешный результат остальных. Соберём статусы и сохраним превью только исправного входа. Это уже прикладной сценарий после первого знакомства с изображением и путями.

try {
    $image = new Gmagick(__DIR__ . '/workshop.ppm');
    echo 'Image opened';
} catch (GmagickException $error) {
    echo 'Cannot read image';
}

try ограничивает действие, которое может завершиться исключением; catch принимает объект ошибки указанного класса. Успешный путь не заходит в catch. Полная программа помещает этот блок внутрь foreach: имя задания связывается с его статусом в массиве $results. Для повреждённого входа никакой placeholder не выдаётся за успешно импортированную фотографию. Подробное сообщение библиотеки сохранено в локальной диагностике; публичный статус сформулирован самим приложением. Причина битого файла может включать сообщение о декодировщике/делегате, а не только слова «повреждённый файл».

Одна исправная схема импортирована в превью 120 × 80. Два других задания отклонены с понятным статусом; это не подменные изображения ошибки.
Одна исправная схема импортирована в превью 120 × 80. Два других задания отклонены с понятным статусом; это не подменные изображения ошибки.

Самостоятельный пример с входами и результатами

Продолжить пакетный импорт после одного плохого файлаСамостоятельный пример
<?php
declare(strict_types=1);
require __DIR__.'/gm104-foundation-fixture.php';
gmRestore();

file_put_contents(__DIR__.'/broken-input.dat', "This is text, not an image.\n");
$tasks = ['good'=>'workshop.ppm','missing'=>'missing-input-104.png','broken'=>'broken-input.dat'];
$results = [];
$errors = [];
foreach ($tasks as $name=>$filename) {
    try {
        $image = new Gmagick(__DIR__.'/'.$filename);
        $image->thumbnailImage(120,80,true);
        gmPng($image,'gm104-env-import-report-accepted.png');
        $results[$name] = ['status'=>'accepted','output'=>'gm104-env-import-report-accepted.png'];
    } catch (GmagickException $error) {
        $results[$name] = ['status'=>'rejected','reason'=>'Cannot read image'];
        $errors[$name] = ['ok'=>false,'class'=>get_class($error),'message'=>$error->getMessage()];
    }
}
gmJson('gm104-env-import-report-import.json',$results);

$checks=[
    'good_accepted'=>$results['good']['status']==='accepted',
    'missing_rejected'=>$results['missing']['status']==='rejected',
    'broken_rejected'=>$results['broken']['status']==='rejected',
    'three_task_receipts'=>count($results)===3
];
gmReport('gm104-env-import-report',["gmagick.construct", "gmagick.thumbnailimage", "gmagick.writeimage"],["gm104-env-import-report-accepted.png"],$checks,$errors??[],$results);
echo "import: accepted=1 rejected=2\nGood preview=120x80 missing/broken=reported import.json=written\n";
Ожидаемый результат
import: accepted=1 rejected=2
Good preview=120x80 missing/broken=reported import.json=written

Скачайте архив, распакуйте в отдельный каталог и выполните php example.php с Gmagick. Короткий фрагмент выше показывает само действие. Полный пример добавляет служебный gm104-foundation-fixture.php: он восстанавливает вложенные входы с SHA256, сохраняет PNG/JPEG и измерения metrics.json. Эти проверки нужны для воспроизводимости урока, а не для каждого обычного вызова API. Результаты и дополнительные JSON появятся после запуска. Вход workshop.ppm имеет собственный генератор make-input.py; где нужен DejaVuSans.ttf, вложены шрифт и лицензия.

Добавьте ещё один исправный вход и назначьте ему отдельное выходное имя, иначе несколько успешных заданий перезапишут одно accepted.png. Здесь намеренно только один успешный файл. Для настоящей очереди используйте идентификатор задания и храните связь между входом, выходом и статусом.

Связанные основы: переменная, класс, объект и ->, массив и ключ, try/catch.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.