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

Дерево руководства
Глава 402 · С первых объектов и простейшего сохранения изображения
Gmagick: установка, окружение и первый работающий маршрут
От первого PNG до диагностики CLI/web, доступных форматов, файла шрифта и понятных статусов импорта.
Для чего Gmagick и из чего состоит обработка
Gmagick связывает PHP с библиотекой GraphicsMagick: позволяет создавать изображения, изменять их и читать метаданные. Это отдельное PHP-расширение, не другое имя Imagick. Установка команды gm в системе сама по себе не создаёт класс Gmagick в PHP. Вводный маршрут: сначала реальный PNG, затем установка/диагностика того PHP, который исполняет ваш код, затем работа с форматами и ресурсами.
- Ваш PHP-код вызывает класс Gmagick.
- Загруженное расширение передаёт операцию библиотеке GraphicsMagick.
- Библиотека использует доступные кодировщики, шрифты и при необходимости внешние делегаты.
- На выходе появляется файл или объект ошибки; их проверяют отдельно.
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__ означает каталог текущего скрипта, точка . склеивает его с именем файла. Это путь на диске сервера, а не адрес картинки для браузера. Чтобы просто получить холст, служебные измерения ниже не нужны.

Самостоятельный пример с входами и результатами
<?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
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 действительно открываются; успешный список других форматов не выдаётся за их испытание.


Самостоятельный пример с входами и результатами
<?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 — уже другая причина.

Самостоятельный пример с входами и результатами
<?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 — предварительная подсказка, но не гарантия будущей записи; окончательный результат подтверждает сам вызов и повторное чтение файла. В этом сценарии не подставляется путь из пользовательского запроса: имена входа и выхода определены приложением.

Самостоятельный пример с входами и результатами
<?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 не выдаётся за успешно импортированную фотографию. Подробное сообщение библиотеки сохранено в локальной диагностике; публичный статус сформулирован самим приложением. Причина битого файла может включать сообщение о декодировщике/делегате, а не только слова «повреждённый файл».

Самостоятельный пример с входами и результатами
<?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. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


