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

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

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

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

Глава 385 · После объектов, файлов и глубины изображения

Imagick: encipherImage, decipherImage и восстановление пикселей после PNG

Разобрать существующую обфускацию: настоящий lossless roundtrip, неправильная фраза, открытые метаданные и потеря глубины без ложных обещаний безопасности.

Увидеть неузнаваемый растр и восстановить его после настоящего чтения файла

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

Исходник → настоящий cipher-растр → точное восстановление после lossless PNG8 save/read; все панели натуральные 400 × 320
Исходник → настоящий cipher-растр → точное восстановление после lossless PNG8 save/read; все панели натуральные 400 × 320

У результата восстановились все 384 000 компонентов: 400 × 320 пикселей по три RGB-канала. Это точное совпадение измеренных значений, а не только похожий вид картинки. Исходные белая основа и непрозрачный RGB8 подготовлены явно. Заголовок файла и метаданные не скрыты: даже у шумного cipher-файла остаются публичные comment=PUBLIC DEMO ORDER 42 и demo:ticket=PUBLIC-42.

$cipher = clone $source;
$ok = $cipher->encipherImage('public-demo-passphrase-2026-only');
$restored = clone $cipher;
$done = $restored->decipherImage('public-demo-passphrase-2026-only');

$source — объект с изображением. clone создаёт отдельную рабочую копию; -> вызывает её метод. В круглых скобках передаётся один аргумент: строка в кавычках. Фраза здесь публичная и в обоих вызовах одинаковая. $ok и $done получают bool true, не новое изображение; пиксели меняются внутри соответствующего объекта. Точка с запятой завершает команду. Переменные, объекты и clone разобраны отдельно. Следующая самостоятельная программа добавляет отсутствующий в этом коротком фрагменте важный шаг: запись и повторное открытие PNG.

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

Видны исходник, действительно преобразованные пиксели и точное восстановление после записи cipher-data.png и повторного чтения. Все 384 000 компонентов RGB совпали; открытые comment и demo:ticket в cipher-файле читаются.

Сохранить неузнаваемый растр и восстановить его после настоящего чтения файлаПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/image-cipher-fixture.php';
icRestore();
$source=icSource(); $before=icHash($source);
$phrase=IC_DEMO_PHRASE;
$cipher=clone $source;
$enc=$cipher->encipherImage($phrase);
icSavePNG($cipher,'cipher-data.png',8);
$loaded=new Imagick(__DIR__.'/cipher-data.png');
$restored=clone $loaded;
$dec=$restored->decipherImage($phrase);
icFirstProof($source,$cipher,$loaded,$restored,$enc,$dec,$before);
echo "image-cipher-first.png\nsource-preview8.png\ncipher-view8.png\nrestored-view8.png\ncipher-data.png\nmetrics.json\nencipher=true decipher=true lossless-save=1 restored-exact=1 public-metadata=1\n";

Видны исходник, действительно преобразованные пиксели и точное восстановление после записи cipher-data.png и повторного чтения. Все 384 000 компонентов RGB совпали; открытые comment и demo:ticket в cipher-файле читаются. Самостоятельный архив: example.php, два точных PNG-входа в base64 и image-cipher-fixture.php. Сохраните файлы рядом и выполните php example.php. Проверено PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16 без HDRI с Cipher, PNG и JPEG. Фраза public-demo-passphrase-2026-only публична и служит только воспроизводимой демонстрации. icRestore восстанавливает входы с проверкой SHA, icSource открывает подготовленный непрозрачный RGB8 и добавляет только публичные свойства. Вызовы изучаемых методов находятся в основном коде. icSavePNG пишет настоящий файл данных, icView — отдельный PNG8-просмотр; обзорные просмотры не используются для decipher.

Ожидаемый вывод проверенной программы
image-cipher-first.png
source-preview8.png
cipher-view8.png
restored-view8.png
cipher-data.png
metrics.json
encipher=true decipher=true lossless-save=1 restored-exact=1 public-metadata=1

Различить пиксельный поток, формат файла, глубину и открытые метаданные

Cipher-пиксели и восстановленный растр — реальные данные; PNG-контейнер и открытые свойства остаются вне этого преобразования
Cipher-пиксели и восстановленный растр — реальные данные; PNG-контейнер и открытые свойства остаются вне этого преобразования
Часть процессаЧто сохраняется или меняется
$sourceНормализованный непрозрачный RGB8-исходник; оригинал остаётся отдельным объектом.
$cipherРабочий поток пикселей меняется. Изображение по-прежнему имеет размер, depth, заголовок и читаемые свойства.
cipher-data.pngНастоящий lossless-файл, из которого программа заново прочитала тот же cipher-поток.
$restoredКопия прочитанного файла. decipherImage изменяет её; затем сравниваются все компоненты с эталоном.
PNG8-просмотрОтдельная иллюстрация. Если исходные cipher-данные 16-битные, такой просмотр теряет необходимые биты и не годится для восстановления.

Модель напоминает обратимое перемешивание содержимого ячеек внутри узнаваемой упаковки. Это ограниченная аналогия: реальные операции работают с потоком пиксельных байтов и AES-CTR, а не просто переставляют цветные квадраты. Ширина, высота, каналы и глубина определяют представление данных. Один и тот же passphrase в этой реализации не создаёт случайно новый nonce; повтор на том же входе дал тот же cipher. Поэтому шумный вид сам по себе не доказывает стойкость или аутентичность.

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

При диагностике полезны представление RGB, глубина каналов и потери сжатия. Начальный пример ограничен opaque RGB; результат не переносится автоматически на произвольный RGBA, CMYK, палитру, изменённый размер или другую реализацию AES.

Запустить короткий encipher и отдельно восстановить известный cipher-вход

Короткий encipher сохраняет реальный cipher; независимый decipher читает заранее подготовленный cipher-файл и возвращает исходный рисунок
Короткий encipher сохраняет реальный cipher; независимый decipher читает заранее подготовленный cipher-файл и возвращает исходный рисунок

Для первого короткого примера вход уже готов. icRestore декодирует два точных PNG из base64 и проверяет SHA; icSource открывает собственный RGB8 и добавляет только публичные свойства. Никаких сетевых данных, секретных ключей или чужих фотографий нет. Один изучаемый вызов меняет рабочую копию; затем отдельная запись сохраняет настоящие пиксели, а повторное чтение проверяет их сохранность.

Одним вызовом преобразовать пиксели и сохранить настоящий PNG

encipherImage вернул true и изменил пиксели рабочей копии. В настоящем encipher-data.png они сохранились точно после повторного чтения. Размер холста, формат изображения и открытые метаданные не стали скрытым файловым контейнером.

Одним вызовом преобразовать пиксели и сохранить настоящий PNGПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/image-cipher-fixture.php';
icRestore();
$source=icSource(); $before=icHash($source);
$phrase=IC_DEMO_PHRASE;
$cipher=clone $source;
$ok=$cipher->encipherImage($phrase);
icSavePNG($cipher,'encipher-data.png',8);
$loaded=new Imagick(__DIR__.'/encipher-data.png');
icEncipherProof($source,$cipher,$loaded,$ok,$before);
echo "image-cipher-encipher.png\nencipher-source8.png\nencipher-data.png\nmetrics.json\nencipher=true pixels-changed=1 saved-cipher-exact=1 source-unchanged=1\n";

encipherImage вернул true и изменил пиксели рабочей копии. В настоящем encipher-data.png они сохранились точно после повторного чтения. Размер холста, формат изображения и открытые метаданные не стали скрытым файловым контейнером. Самостоятельный архив: example.php, два точных PNG-входа в base64 и image-cipher-fixture.php. Сохраните файлы рядом и выполните php example.php. Проверено PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16 без HDRI с Cipher, PNG и JPEG. Фраза public-demo-passphrase-2026-only публична и служит только воспроизводимой демонстрации. icRestore восстанавливает входы с проверкой SHA, icSource открывает подготовленный непрозрачный RGB8 и добавляет только публичные свойства. Вызовы изучаемых методов находятся в основном коде. icSavePNG пишет настоящий файл данных, icView — отдельный PNG8-просмотр; обзорные просмотры не используются для decipher.

Ожидаемый вывод проверенной программы
image-cipher-encipher.png
encipher-source8.png
encipher-data.png
metrics.json
encipher=true pixels-changed=1 saved-cipher-exact=1 source-unchanged=1
$ok = $restored->decipherImage($phrase);

Минимальный decipher не должен незаметно создавать свой вход тем же вызовом encipher. Поэтому второй архив включает подлинный encoded-rgb8.png, полученный из этого рисунка той же версией и публичной фразой при отдельной подготовке. Объект $cipher читается из него; $restored — независимый clone. Метод получает строку и изменяет пиксели копии. После этого сравнение с известным источником доказывает восстановление именно этого рисунка.

Восстановить отдельный заранее подготовленный cipher-вход

Короткий decipher работает с настоящим encoded-rgb8.png, созданным заранее той же версией и публичной фразой. Он не повторяет encipher в этой программе. Рабочая копия восстановилась точно, fixture и эталон сохранены.

Восстановить отдельный заранее подготовленный cipher-входПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/image-cipher-fixture.php';
icRestore();
$source=icSource(); $before=icHash($source);
$phrase=IC_DEMO_PHRASE;
$cipher=new Imagick(__DIR__.'/encoded-rgb8.png');
$cipherBefore=icHash($cipher);
$restored=clone $cipher;
$ok=$restored->decipherImage($phrase);
icDecipherProof($source,$cipher,$restored,$ok,$before,$cipherBefore);
echo "image-cipher-decipher.png\ndecipher-input8.png\nmetrics.json\ndecipher=true restored-exact=1 cipher-input-unchanged=1 source-unchanged=1\n";

Короткий decipher работает с настоящим encoded-rgb8.png, созданным заранее той же версией и публичной фразой. Он не повторяет encipher в этой программе. Рабочая копия восстановилась точно, fixture и эталон сохранены. Самостоятельный архив: example.php, два точных PNG-входа в base64 и image-cipher-fixture.php. Сохраните файлы рядом и выполните php example.php. Проверено PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16 без HDRI с Cipher, PNG и JPEG. Фраза public-demo-passphrase-2026-only публична и служит только воспроизводимой демонстрации. icRestore восстанавливает входы с проверкой SHA, icSource открывает подготовленный непрозрачный RGB8 и добавляет только публичные свойства. Вызовы изучаемых методов находятся в основном коде. icSavePNG пишет настоящий файл данных, icView — отдельный PNG8-просмотр; обзорные просмотры не используются для decipher.

Ожидаемый вывод проверенной программы
image-cipher-decipher.png
decipher-input8.png
metrics.json
decipher=true restored-exact=1 cipher-input-unchanged=1 source-unchanged=1

Сравнение RGB-хэша отличается от сравнения файлов по SHA. Новый PNG может иметь другой набор текстовых chunks и время записи, оставаясь теми же пикселями. icHash сравнивает массив RGB через PIXEL_SHORT: каждое значение нормализовано в диапазон 0..65535, даже если входной файл 8-битный. Отдельные file SHA проверяют точность входных fixtures и связывают созданные артефакты; они не подменяют проверку восстановленных пикселей.

Разобрать неправильную фразу, потери формата, глубину и собственную политику входа

Верный PNG восстанавливается; неверная фраза, JPEG90 и потеря глубины дают true без правильных пикселей; PNG16 отдельно сохраняет 16-битный поток
Верный PNG восстанавливается; неверная фраза, JPEG90 и потеря глубины дают true без правильных пикселей; PNG16 отдельно сохраняет 16-битный поток

При разборе сбоя задайте конкретный вопрос: неправильная фраза, испорченный формат или потерянные биты? Программа ниже сравнивает эти случаи на одном источнике. Она сохраняет настоящий 16-битный cipher в PNG16 и отдельно намеренно портит его, записав как PNG8. Файлы данных не заменяются иллюстрациями. Последняя часть показывает собственную политику входа и реальные ошибки пустых объектов.

Найти причину невосстановления: фраза, JPEG, глубина или неподходящая проверка

Правильный lossless-вход восстановился; неверная фраза, JPEG и потеря глубины дали true без правильного результата. PNG16 сохранил 16-битный cipher и восстановил источник. Собственная политика отклонила пустую/NUL-фразу, а API отдельно продемонстрировал принятие пустой строки. Две ошибки пустого объекта пойманы.

Найти причину невосстановления: фраза, JPEG, глубина или неподходящая проверкаПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/image-cipher-fixture.php';
icRestore();
$source=icSource(); $before=icHash($source);
$phrase=IC_DEMO_PHRASE;
$cipher=new Imagick(__DIR__.'/encoded-rgb8.png');$cipherBefore=icHash($cipher);
$good=clone $cipher;$goodReturn=$good->decipherImage($phrase);
$wrong=clone $cipher;$wrongReturn=$wrong->decipherImage('different-public-demo-phrase');
$jpeg=clone $cipher;$jpeg->setImageFormat('jpeg');$jpeg->setImageCompressionQuality(90);
$jpeg->writeImage(__DIR__.'/encoded-lossy.jpg');
$jpeg=new Imagick(__DIR__.'/encoded-lossy.jpg');$jpegReturn=$jpeg->decipherImage($phrase);
$source16=clone $source;$source16->setImageDepth(16);
$cipher16=clone $source16;$enc16=$cipher16->encipherImage($phrase);
icSavePNG($cipher16,'workflow-cipher16.png',16);
icSavePNG($cipher16,'workflow-cipher16-lost8.png',8);
$read16=new Imagick(__DIR__.'/workflow-cipher16.png');$saved16Hash=icHash($read16);
$readLost8=new Imagick(__DIR__.'/workflow-cipher16-lost8.png');
$dec16=$read16->decipherImage($phrase);$decLost8=$readLost8->decipherImage($phrase);
$stripped=clone $cipher;$stripped->stripImage();$strippedMetadata=icMetadata($stripped);
$stripReturn=$stripped->decipherImage($phrase);
$emptyPhrase=clone $source;$emptyEnc=$emptyPhrase->encipherImage('');$emptyHash=icHash($emptyPhrase);
$emptyDec=$emptyPhrase->decipherImage('');
$policyRejected=[];
foreach(['',"demo\0suffix"] as $badPhrase){
    try{icPhrase($badPhrase);$policyRejected[]=false;}catch(InvalidArgumentException $error){$policyRejected[]=true;}
}
$acceptedPhrase=icPhrase($phrase);
$again=clone $source;$againReturn=$again->encipherImage($acceptedPhrase);
$errors=[];
foreach(['encipher_empty'=>fn()=>(new Imagick())->encipherImage($phrase),
    'decipher_empty'=>fn()=>(new Imagick())->decipherImage($phrase)] as $name=>$call){
    try{$call();$errors[$name]=['class'=>'not caught','message'=>''];}
    catch(Throwable $error){$errors[$name]=['class'=>get_class($error),'message'=>$error->getMessage()];}
}
icView($good,'workflow-correct8.png');icView($wrong,'workflow-wrong8.png');
icView($jpeg,'workflow-jpeg8.png');icView($readLost8,'workflow-depth-loss8.png');
icView($read16,'workflow-png16-restored8.png');
$rects=icCompare([$good,$wrong,$jpeg,$readLost8],'image-cipher-workflow.png');
$wrongError=icError($source,$wrong);$jpegError=icError($source,$jpeg);$depthError=icError($source,$readLost8);
icDiagnostic('image-cipher-workflow',['executed_apis'=>['encipherImage','decipherImage'],
    'correct'=>['return'=>$goodReturn,'restored_exact'=>icHash($good)===$before,'error'=>icError($source,$good)],
    'wrong_phrase'=>['return'=>$wrongReturn,'restored_exact'=>icHash($wrong)===$before,'error'=>$wrongError],
    'jpeg90'=>['return'=>$jpegReturn,'restored_exact'=>icHash($jpeg)===$before,'error'=>$jpegError],
    'depth16'=>['encipher_return'=>$enc16,'cipher_RGB16_sha256'=>icHash($cipher16),'saved_RGB16_sha256'=>$saved16Hash,
        'decipher16_return'=>$dec16,'restored16_exact'=>icHash($read16)===$before,'error16'=>icError($source,$read16),
        'forced8_return'=>$decLost8,'forced8_restored_exact'=>icHash($readLost8)===$before,'forced8_error'=>$depthError],
    'strip'=>['properties_before_decode'=>$strippedMetadata,'return'=>$stripReturn,'restored_exact'=>icHash($stripped)===$before],
    'empty_phrase'=>['encipher_return'=>$emptyEnc,'cipher_changed'=>$emptyHash!==$before,'decipher_return'=>$emptyDec,'restored_exact'=>icHash($emptyPhrase)===$before],
    'application_policy_rejected'=>$policyRejected,'deterministic_cipher'=>icHash($again)===$cipherBefore,
    'errors'=>$errors,'public_metadata'=>icMetadata($cipher),'source_unchanged'=>icHash($source)===$before,'cipher_input_unchanged'=>icHash($cipher)===$cipherBefore,'panel_geometry'=>$rects,
    'checks'=>['correct_returns_true_and_restores'=>$goodReturn===true&&icHash($good)===$before,
        'wrong_phrase_true_is_not_authentication'=>$wrongReturn===true&&$wrongError['max']>0,
        'JPEG_true_does_not_restore'=>$jpegReturn===true&&$jpegError['max']>0,
        'PNG16_preserves_cipher_and_restores'=>$enc16===true&&$saved16Hash===icHash($cipher16)&&$dec16===true&&icHash($read16)===$before,
        'forced_PNG8_loses_16bit_cipher'=>$decLost8===true&&$depthError['max']>0,
        'strip_is_not_remove_all_properties'=>$strippedMetadata['comment']===false&&$strippedMetadata['ticket']==='PUBLIC-42'&&$strippedMetadata['cipher_mode']==='CTR',
        'stripped_pixels_still_restore'=>$stripReturn===true&&icHash($stripped)===$before,
        'API_accepts_empty_phrase'=>$emptyEnc===true&&$emptyHash!==$before&&$emptyDec===true&&icHash($emptyPhrase)===$before,
        'own_policy_rejects_empty_and_NUL'=>$policyRejected===[true,true],
        'same_phrase_reuses_cipher'=>$againReturn===true&&icHash($again)===$cipherBefore,
        'two_empty_object_errors'=>array_column($errors,'class')===['ImagickException','ImagickException'],
        'originals_preserved'=>icHash($source)===$before&&icHash($cipher)===$cipherBefore]]);
echo "image-cipher-workflow.png\nworkflow-correct8.png\nworkflow-wrong8.png\nworkflow-jpeg8.png\nworkflow-depth-loss8.png\nworkflow-png16-restored8.png\nworkflow-cipher16.png\nworkflow-cipher16-lost8.png\nencoded-lossy.jpg\nmetrics.json\ncorrect=exact wrong=true-but-invalid JPEG=true-but-invalid PNG16=exact forced8=invalid policy-rejections=2 errors=2\n";

Правильный lossless-вход восстановился; неверная фраза, JPEG и потеря глубины дали true без правильного результата. PNG16 сохранил 16-битный cipher и восстановил источник. Собственная политика отклонила пустую/NUL-фразу, а API отдельно продемонстрировал принятие пустой строки. Две ошибки пустого объекта пойманы. Самостоятельный архив: example.php, два точных PNG-входа в base64 и image-cipher-fixture.php. Сохраните файлы рядом и выполните php example.php. Проверено PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16 без HDRI с Cipher, PNG и JPEG. Фраза public-demo-passphrase-2026-only публична и служит только воспроизводимой демонстрации. icRestore восстанавливает входы с проверкой SHA, icSource открывает подготовленный непрозрачный RGB8 и добавляет только публичные свойства. Вызовы изучаемых методов находятся в основном коде. icSavePNG пишет настоящий файл данных, icView — отдельный PNG8-просмотр; обзорные просмотры не используются для decipher.

Ожидаемый вывод проверенной программы
image-cipher-workflow.png
workflow-correct8.png
workflow-wrong8.png
workflow-jpeg8.png
workflow-depth-loss8.png
workflow-png16-restored8.png
workflow-cipher16.png
workflow-cipher16-lost8.png
encoded-lossy.jpg
metrics.json
correct=exact wrong=true-but-invalid JPEG=true-but-invalid PNG16=exact forced8=invalid policy-rejections=2 errors=2
ПроверкаРеальный результат
PNG8, правильная фразаtrue и точное восстановление; max=0 для всех 384 000 компонентов.
Неверная публичная фразаtrue, но восстановление неверно; RMSE≈35161.67 в единицах PIXEL_SHORT.
Cipher сохранён как JPEG90true после decipher, но результат неверен; RMSE≈12256.55.
Настоящий 16-битный cipher сохранён как PNG16Те же cipher-компоненты после чтения; восстановление точное.
Тот же 16-битный cipher принудительно сохранён как PNG8true без верного восстановления; RMSE≈35206.00.
Пустой Imagick у любого из методовImagickException: Can not process empty Imagick object.

Указанные RMSE измерены по RGB через PIXEL_SHORT непосредственно в объектах. Они не являются процентами качества и не вычисляются из уменьшенных скриншотов. Просмотры PNG8 кодируются отдельно; у 16-битного результата они специально служат только показу. Имена workflow-cipher16.png и workflow-cipher16-lost8.png обозначают разные реальные файлы данных; превращение второго обратно в 16-битный PNG потерянные биты не восстановит.

stripImage здесь удалил comment, но оставил demo:ticket и cipher:* свойства. Поэтому нельзя объявлять вызов универсальным удалением всех пользовательских полей. В свойствах перед decipher по-прежнему виден CTR; восстановление после strip осталось точным. Это не проверка подлинности по метаданным: конкретный Core пересчитывает поток и не сверяет аутентификационный тег. Фраза, повреждённые данные или неправильное представление могут дать true и неправильный рисунок.

Пустая фраза в этом API тоже дала true у обоих методов, изменила cipher-пиксели и позволила восстановление. icPhrase явно запрещает пустую строку и NUL только как нашу политику приложения; такой запрет не приписывается официальной сигнатуре. NUL важен потому, что точный внутренний C-путь использует строку с нулевым завершением. Не превращайте этот частный guard в заявление о безопасности всего механизма. Здесь функция просто возвращает допустимую демонстрационную строку или выбрасывает InvalidArgumentException; функции и исключения объясняются отдельно.

Сохранить полный официальный базис и воспроизвести конкретную версию

Полный официальный базис

Imagick::encipherImage(string $passphrase): bool

Официальная доступность: PECL imagick 2 начиная с 2.3.0 и PECL imagick 3, связанный ImageMagick не ниже 6.3.9. Оба метода действуют в нашей Imagick 3.8.1 с IM7 и не помечены deprecated. Исходные записи целиком сохранены ниже, включая взаимные ссылки; официальных программных примеров и отдельного раздела ошибок на этих двух страницах нет.

encipherImage принимает обязательную строку passphrase и преобразует обычные пиксели в cipher-пиксели текущего изображения. Возвращает true при успехе. Прежнее содержимое нужно восстанавливать paired-методом decipherImage. Результат остаётся изображением с обычным заголовком, геометрией и читаемыми метаданными, а не произвольным зашифрованным бинарным файлом.

Строка PHP — содержимое фразы, а не путь к файлу. Это отличие от CLI-примеров ImageMagick с -encipher passphrase.txt. Передача имени файла PHP-методу не прочитает этот файл как фразу. Сам метод меняет объект; bool не содержит пиксели и не является именем выходного файла. Для сохранения требуется отдельная операция записи, для сохранения исходника — отдельный clone.

В точном wrapper требуется непустое текущее изображение; оба вызова на пустом Imagick выбросили ImagickException с Can not process empty Imagick object. При выключенной compile-time поддержке Cipher Core выдаёт CipherSupportNotEnabled, хотя имена методов могут существовать. При этом пустая строка passphrase в данной реализации допускается и roundtrip выполняется. Наш запрет пустой/NUL-строки — явно дополнительная политика приложения, не объявление такого ограничения в официальном API.

Exact IM7.1.1-46 использует AES-CTR над экспортированными пиксельными байтами; nonce детерминирован, независимой проверки аутентичности нет. Current official guide относит этот механизм только к обычной обфускации. Не используйте его как обещание конфиденциальности документов, защищённое хранилище или проверку целостности. Полнофайловое шифрование с аутентификацией — другая задача, разобранная в соответствующих уроках Sodium и OpenSSL.

Полный официальный XML: описание, доступность, параметр, return и связанные методы
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<refentry xmlns="http://docbook.org/ns/docbook" xml:id="imagick.encipherimage">
 <refnamediv>
  <refname>Imagick::encipherImage</refname>
  <refpurpose>Enciphers an image</refpurpose>
 </refnamediv>

 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <modifier>public</modifier> <type>bool</type><methodname>Imagick::encipherImage</methodname>
   <methodparam><type>string</type><parameter>passphrase</parameter></methodparam>
  </methodsynopsis>

  <para>
   Converts plain pixels to enciphered pixels. The image is not readable
   until it has been deciphered using <function>Imagick::decipherImage</function>
   &imagick.method.available.0x639;
  </para>
 </refsect1>

 <refsect1 role="parameters">
  &reftitle.parameters;
  <para>
   <variablelist>
    <varlistentry>
     <term><parameter>passphrase</parameter></term>
     <listitem>
      <para>
       The passphrase
      </para>
     </listitem>
    </varlistentry>
   </variablelist>
  </para>

 </refsect1>
 <refsect1 role="returnvalues">
  &reftitle.returnvalues;
  <para>
   &imagick.return.success;
  </para>
 </refsect1>

 <refsect1 role="seealso">
  &reftitle.seealso;
  <para>
   <simplelist>
    <member><function>Imagick::decipherImage</function></member>
   </simplelist>
  </para>
 </refsect1>

</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->

Полный официальный базис

Imagick::decipherImage(string $passphrase): bool

Официальная доступность: PECL imagick 2 начиная с 2.3.0 и PECL imagick 3, связанный ImageMagick не ниже 6.3.9. Оба метода действуют в нашей Imagick 3.8.1 с IM7 и не помечены deprecated. Исходные записи целиком сохранены ниже, включая взаимные ссылки; официальных программных примеров и отдельного раздела ошибок на этих двух страницах нет.

decipherImage принимает обязательную строку passphrase; исходное изображение должно быть предварительно обработано encipherImage. Возвращает true при завершении операции. Для правильного восстановления нужны та же фраза и сохранённый соответствующий поток cipher-пикселей. Метод не распознаёт автоматически чужую схему AES, JPEG-повреждение или правильность пароля; неверная фраза в нашем запуске тоже вернула true.

Строка PHP — содержимое фразы, а не путь к файлу. Это отличие от CLI-примеров ImageMagick с -encipher passphrase.txt. Передача имени файла PHP-методу не прочитает этот файл как фразу. Сам метод меняет объект; bool не содержит пиксели и не является именем выходного файла. Для сохранения требуется отдельная операция записи, для сохранения исходника — отдельный clone.

В точном wrapper требуется непустое текущее изображение; оба вызова на пустом Imagick выбросили ImagickException с Can not process empty Imagick object. При выключенной compile-time поддержке Cipher Core выдаёт CipherSupportNotEnabled, хотя имена методов могут существовать. При этом пустая строка passphrase в данной реализации допускается и roundtrip выполняется. Наш запрет пустой/NUL-строки — явно дополнительная политика приложения, не объявление такого ограничения в официальном API.

Exact IM7.1.1-46 использует AES-CTR над экспортированными пиксельными байтами; nonce детерминирован, независимой проверки аутентичности нет. Current official guide относит этот механизм только к обычной обфускации. Не используйте его как обещание конфиденциальности документов, защищённое хранилище или проверку целостности. Полнофайловое шифрование с аутентификацией — другая задача, разобранная в соответствующих уроках Sodium и OpenSSL.

Полный официальный XML: описание, доступность, параметр, return и связанные методы
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<refentry xmlns="http://docbook.org/ns/docbook" xml:id="imagick.decipherimage">
 <refnamediv>
  <refname>Imagick::decipherImage</refname>
  <refpurpose>Deciphers an image</refpurpose>
 </refnamediv>

 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <modifier>public</modifier> <type>bool</type><methodname>Imagick::decipherImage</methodname>
   <methodparam><type>string</type><parameter>passphrase</parameter></methodparam>
  </methodsynopsis>

  <para>
   Deciphers image that has been enciphered before. The image must be enciphered
   using <function>Imagick::encipherImage</function>.
   &imagick.method.available.0x639;
  </para>
 </refsect1>

 <refsect1 role="parameters">
  &reftitle.parameters;
  <para>
   <variablelist>
    <varlistentry>
     <term><parameter>passphrase</parameter></term>
     <listitem>
      <para>
       The passphrase
      </para>
     </listitem>
    </varlistentry>
   </variablelist>
  </para>

 </refsect1>
 <refsect1 role="returnvalues">
  &reftitle.returnvalues;
  <para>
   &imagick.return.success;
  </para>
 </refsect1>

 <refsect1 role="seealso">
  &reftitle.seealso;
  <para>
   <simplelist>
    <member><function>Imagick::encipherImage</function></member>
   </simplelist>
  </para>
 </refsect1>

</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->

Для воспроизведения нужны PHP CLI, Imagick, ImageMagick с поддержкой Cipher, PNG и JPEG. Наши примеры действительно исполнялись в PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16 без HDRI. Наличие одноимённого метода или похожего шума не заменяет запуск. Если встретили старую систему, сначала сохраните её точные входные файлы и параметры; не запускайте JPEG, resize, alpha-преобразование или уменьшение depth над cipher как над обычной фотографией.

Полный исполняемый fixture, отдельно от коротких вызовов

<?php
declare(strict_types=1);
const IC_DEMO_PHRASE='public-demo-passphrase-2026-only';
function icRestore():void {
    $hashes=['source-rgb8.png'=>'b6af02ed97020582a27e993a1565de41e23ea97ff7be11ac132d68204d56d483','encoded-rgb8.png'=>'ea4628f5c5a2a42a75728c94865023f82aea2fb5e33f823a1eb1e3f656a5de2a'];
    foreach($hashes as $name=>$hash){
        $raw=base64_decode((string)file_get_contents(__DIR__.'/'.$name.'.b64'),true);
        if($raw===false||hash('sha256',$raw)!==$hash||file_put_contents(__DIR__.'/'.$name,$raw)===false){throw new RuntimeException('Known demonstration input missing or changed');}
    }
}
function icSource():Imagick {
    $image=new Imagick(__DIR__.'/source-rgb8.png');
    $image->setImageProperty('comment','PUBLIC DEMO ORDER 42');$image->setImageProperty('demo:ticket','PUBLIC-42');return $image;
}
function icPixels(Imagick $image):array {return $image->exportImagePixels(0,0,400,320,'RGB',Imagick::PIXEL_SHORT);}
function icHash(Imagick $image):string {return hash('sha256',json_encode(icPixels($image),JSON_THROW_ON_ERROR));}
function icError(Imagick $a,Imagick $b):array {
    $x=icPixels($a);$y=icPixels($b);$max=0;$sum=0.0;$changed=0;
    foreach($x as $i=>$v){$d=abs($v-$y[$i]);$max=max($max,$d);$sum+=$d*$d;$changed+=(int)($d!==0);}
    return ['max'=>$max,'RMSE'=>sqrt($sum/count($x)),'changed_components'=>$changed,'components'=>count($x)];
}
function icMetadata(Imagick $image):array {
    return ['comment'=>$image->getImageProperty('comment'),'ticket'=>$image->getImageProperty('demo:ticket'),
        'cipher_type'=>$image->getImageProperty('cipher:type'),'cipher_mode'=>$image->getImageProperty('cipher:mode'),
        'cipher_nonce'=>$image->getImageProperty('cipher:nonce'),'width'=>$image->getImageWidth(),'height'=>$image->getImageHeight(),
        'depth'=>$image->getImageDepth(),'alpha'=>$image->getImageAlphaChannel()];
}
function icSavePNG(Imagick $image,string $name,int $depth):void {
    $copy=clone $image;$copy->setImageFormat('png');$copy->setImageDepth($depth);
    $copy->setOption('png:bit-depth',(string)$depth);$copy->setOption('png:color-type','2');
    if(!$copy->writeImage(__DIR__.'/'.$name)){throw new RuntimeException('PNG write failed');}
}
function icView(Imagick $image,string $name):void {
    $copy=clone $image;$copy->stripImage();$copy->setOption('png:exclude-chunk','all');icSavePNG($copy,$name,8);
}
function icCompare(array $images,string $name):array {
    $board=new Imagick();$board->newImage(400*count($images),320,'white');$rects=[];
    foreach($images as $i=>$image){
        if($image->getImageWidth()!==400||$image->getImageHeight()!==320){throw new RuntimeException('Expected natural 400x320 panel');}
        $raw=clone $image;$raw->stripImage();$board->compositeImage($raw,Imagick::COMPOSITE_OVER,400*$i,0);
        $rects[]=['x'=>400*$i,'y'=>0,'width'=>400,'height'=>320];
    }
    icView($board,$name);return $rects;
}
function icPhrase(string $phrase):string {
    if($phrase===''||str_contains($phrase,"\0")){throw new InvalidArgumentException('Demo policy requires a nonempty phrase without NUL');}
    return $phrase;
}
function icDiagnostic(string $id,array $data):void {
    $doc=['schema'=>'aen-image-cipher-program-diagnostics-v1','example_id'=>$id,
        'runtime'=>['php'=>PHP_VERSION,'imagick'=>phpversion('imagick'),'image_magick'=>Imagick::getVersion()]]+$data;
    if(file_put_contents(__DIR__.'/metrics.json',json_encode($doc,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR)."\n")===false){throw new RuntimeException('Diagnostic write failed');}
}
function icFirstProof(Imagick $source,Imagick $cipher,Imagick $loaded,Imagick $restored,bool $enc,bool $dec,string $before):void {
    icView($source,'source-preview8.png');icView($cipher,'cipher-view8.png');icView($restored,'restored-view8.png');
    $rects=icCompare([$source,$cipher,$restored],'image-cipher-first.png');$error=icError($source,$restored);$meta=icMetadata($loaded);
    icDiagnostic('image-cipher-first',['executed_apis'=>['encipherImage','decipherImage'],'encipher_return'=>$enc,'decipher_return'=>$dec,
        'source_RGB16_sha256'=>icHash($source),'cipher_RGB16_sha256'=>icHash($cipher),'file_RGB16_sha256'=>icHash($loaded),
        'cipher_survives_save'=>icHash($loaded)===icHash($cipher),'restored_exact'=>icHash($restored)===$before,'restored_error'=>$error,
        'public_metadata'=>$meta,'source_unchanged'=>icHash($source)===$before,'panel_geometry'=>$rects,
        'checks'=>['encipher_true'=>$enc===true,'decipher_true'=>$dec===true,'cipher_changes_pixels'=>icHash($cipher)!==$before,
            'lossless_file_keeps_cipher'=>icHash($loaded)===icHash($cipher),'source_restored_exactly'=>$error['max']===0,
            'comment_still_public'=>$meta['comment']==='PUBLIC DEMO ORDER 42','ticket_still_public'=>$meta['ticket']==='PUBLIC-42',
            'source_preserved'=>icHash($source)===$before]]);
}
function icEncipherProof(Imagick $source,Imagick $cipher,Imagick $loaded,bool $ok,string $before):void {
    icView($source,'encipher-source8.png');icView($cipher,'image-cipher-encipher.png');
    icDiagnostic('image-cipher-encipher-minimal',['executed_api'=>'encipherImage','encipher_return'=>$ok,
        'source_RGB16_sha256'=>$before,'cipher_RGB16_sha256'=>icHash($cipher),'file_RGB16_sha256'=>icHash($loaded),
        'metadata'=>icMetadata($loaded),'source_unchanged'=>icHash($source)===$before,
        'checks'=>['encipher_true'=>$ok===true,'pixels_changed'=>icHash($cipher)!==$before,'lossless_file_keeps_cipher'=>icHash($loaded)===icHash($cipher),
            'known_cipher'=>icHash($cipher)==='e8d282f8db735d0e4ef7fc91539b062eef67da78e3cc4128e2dbf4956db993cc','source_preserved'=>icHash($source)===$before]]);
}
function icDecipherProof(Imagick $source,Imagick $cipher,Imagick $restored,bool $ok,string $before,string $cipherBefore):void {
    icView($cipher,'decipher-input8.png');icView($restored,'image-cipher-decipher.png');$error=icError($source,$restored);
    icDiagnostic('image-cipher-decipher-minimal',['executed_api'=>'decipherImage','decipher_return'=>$ok,
        'cipher_RGB16_sha256'=>$cipherBefore,'restored_RGB16_sha256'=>icHash($restored),'restored_exact'=>icHash($restored)===$before,
        'restored_error'=>$error,'metadata_after_decode'=>icMetadata($restored),'cipher_unchanged'=>icHash($cipher)===$cipherBefore,'source_unchanged'=>icHash($source)===$before,
        'checks'=>['decipher_true'=>$ok===true,'exact_source_restored'=>$error['max']===0,'cipher_fixture_preserved'=>icHash($cipher)===$cipherBefore,
            'source_preserved'=>icHash($source)===$before]]);
}

Helper не скрывает encipher/decipher: оба изучаемых вызова находятся в main-программах. icRestore проверяет байты двух fixtures; icSavePNG пишет данные на отдельной копии с явной глубиной и TrueColor PNG. icView делает отдельное PNG8-представление; icCompare собирает натуральные панели 400 × 320. icHash и icError измеряют полный RGB через PIXEL_SHORT, icDiagnostic сохраняет JSON. Сначала понятный вызов, затем явно названная аппаратура сохранения и проверки — это разные части примера.

Упражнение: заменить в первом примере только decipher-фразу на different-public-demo-phrase и предсказать отдельно return и сравнение пикселей. Решение: в проверенной реализации return останется true, совпадение с эталоном исчезнет. Следующее упражнение — сохранить cipher16 с 16-битной глубиной и затем только его просмотровую копию с 8-битной; для восстановления читать настоящий 16-битный файл. Для защищённого шифрования полного файла изучайте Sodium и OpenSSL; это отдельные контракты, а не взаимозаменяемые названия для decipherImage.

Функции и методы этой темы

Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.

Imagick::encipherImageПонять существующую обфускацию пикселей и проверить настоящий lossless roundtrip

PECL imagick 2 >= 2.3.0, PECL imagick 3 · imagick

Imagick::encipherImage(string $passphrase): bool

Полный официальный базис

Imagick::encipherImage(string $passphrase): bool

Официальная доступность: PECL imagick 2 начиная с 2.3.0 и PECL imagick 3, связанный ImageMagick не ниже 6.3.9. Оба метода действуют в нашей Imagick 3.8.1 с IM7 и не помечены deprecated. Исходные записи целиком сохранены ниже, включая взаимные ссылки; официальных программных примеров и отдельного раздела ошибок на этих двух страницах нет.

encipherImage принимает обязательную строку passphrase и преобразует обычные пиксели в cipher-пиксели текущего изображения. Возвращает true при успехе. Прежнее содержимое нужно восстанавливать paired-методом decipherImage. Результат остаётся изображением с обычным заголовком, геометрией и читаемыми метаданными, а не произвольным зашифрованным бинарным файлом.

Строка PHP — содержимое фразы, а не путь к файлу. Это отличие от CLI-примеров ImageMagick с -encipher passphrase.txt. Передача имени файла PHP-методу не прочитает этот файл как фразу. Сам метод меняет объект; bool не содержит пиксели и не является именем выходного файла. Для сохранения требуется отдельная операция записи, для сохранения исходника — отдельный clone.

В точном wrapper требуется непустое текущее изображение; оба вызова на пустом Imagick выбросили ImagickException с Can not process empty Imagick object. При выключенной compile-time поддержке Cipher Core выдаёт CipherSupportNotEnabled, хотя имена методов могут существовать. При этом пустая строка passphrase в данной реализации допускается и roundtrip выполняется. Наш запрет пустой/NUL-строки — явно дополнительная политика приложения, не объявление такого ограничения в официальном API.

Exact IM7.1.1-46 использует AES-CTR над экспортированными пиксельными байтами; nonce детерминирован, независимой проверки аутентичности нет. Current official guide относит этот механизм только к обычной обфускации. Не используйте его как обещание конфиденциальности документов, защищённое хранилище или проверку целостности. Полнофайловое шифрование с аутентификацией — другая задача, разобранная в соответствующих уроках Sodium и OpenSSL.

Полный официальный XML: описание, доступность, параметр, return и связанные методы
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<refentry xmlns="http://docbook.org/ns/docbook" xml:id="imagick.encipherimage">
 <refnamediv>
  <refname>Imagick::encipherImage</refname>
  <refpurpose>Enciphers an image</refpurpose>
 </refnamediv>

 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <modifier>public</modifier> <type>bool</type><methodname>Imagick::encipherImage</methodname>
   <methodparam><type>string</type><parameter>passphrase</parameter></methodparam>
  </methodsynopsis>

  <para>
   Converts plain pixels to enciphered pixels. The image is not readable
   until it has been deciphered using <function>Imagick::decipherImage</function>
   &imagick.method.available.0x639;
  </para>
 </refsect1>

 <refsect1 role="parameters">
  &reftitle.parameters;
  <para>
   <variablelist>
    <varlistentry>
     <term><parameter>passphrase</parameter></term>
     <listitem>
      <para>
       The passphrase
      </para>
     </listitem>
    </varlistentry>
   </variablelist>
  </para>

 </refsect1>
 <refsect1 role="returnvalues">
  &reftitle.returnvalues;
  <para>
   &imagick.return.success;
  </para>
 </refsect1>

 <refsect1 role="seealso">
  &reftitle.seealso;
  <para>
   <simplelist>
    <member><function>Imagick::decipherImage</function></member>
   </simplelist>
  </para>
 </refsect1>

</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->

Одним вызовом преобразовать пиксели и сохранить настоящий PNG

encipherImage вернул true и изменил пиксели рабочей копии. В настоящем encipher-data.png они сохранились точно после повторного чтения. Размер холста, формат изображения и открытые метаданные не стали скрытым файловым контейнером.

Одним вызовом преобразовать пиксели и сохранить настоящий PNGПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/image-cipher-fixture.php';
icRestore();
$source=icSource(); $before=icHash($source);
$phrase=IC_DEMO_PHRASE;
$cipher=clone $source;
$ok=$cipher->encipherImage($phrase);
icSavePNG($cipher,'encipher-data.png',8);
$loaded=new Imagick(__DIR__.'/encipher-data.png');
icEncipherProof($source,$cipher,$loaded,$ok,$before);
echo "image-cipher-encipher.png\nencipher-source8.png\nencipher-data.png\nmetrics.json\nencipher=true pixels-changed=1 saved-cipher-exact=1 source-unchanged=1\n";

encipherImage вернул true и изменил пиксели рабочей копии. В настоящем encipher-data.png они сохранились точно после повторного чтения. Размер холста, формат изображения и открытые метаданные не стали скрытым файловым контейнером. Самостоятельный архив: example.php, два точных PNG-входа в base64 и image-cipher-fixture.php. Сохраните файлы рядом и выполните php example.php. Проверено PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16 без HDRI с Cipher, PNG и JPEG. Фраза public-demo-passphrase-2026-only публична и служит только воспроизводимой демонстрации. icRestore восстанавливает входы с проверкой SHA, icSource открывает подготовленный непрозрачный RGB8 и добавляет только публичные свойства. Вызовы изучаемых методов находятся в основном коде. icSavePNG пишет настоящий файл данных, icView — отдельный PNG8-просмотр; обзорные просмотры не используются для decipher.

Ожидаемый вывод проверенной программы
image-cipher-encipher.png
encipher-source8.png
encipher-data.png
metrics.json
encipher=true pixels-changed=1 saved-cipher-exact=1 source-unchanged=1

Найти причину невосстановления: фраза, JPEG, глубина или неподходящая проверка

Правильный lossless-вход восстановился; неверная фраза, JPEG и потеря глубины дали true без правильного результата. PNG16 сохранил 16-битный cipher и восстановил источник. Собственная политика отклонила пустую/NUL-фразу, а API отдельно продемонстрировал принятие пустой строки. Две ошибки пустого объекта пойманы.

Найти причину невосстановления: фраза, JPEG, глубина или неподходящая проверкаПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/image-cipher-fixture.php';
icRestore();
$source=icSource(); $before=icHash($source);
$phrase=IC_DEMO_PHRASE;
$cipher=new Imagick(__DIR__.'/encoded-rgb8.png');$cipherBefore=icHash($cipher);
$good=clone $cipher;$goodReturn=$good->decipherImage($phrase);
$wrong=clone $cipher;$wrongReturn=$wrong->decipherImage('different-public-demo-phrase');
$jpeg=clone $cipher;$jpeg->setImageFormat('jpeg');$jpeg->setImageCompressionQuality(90);
$jpeg->writeImage(__DIR__.'/encoded-lossy.jpg');
$jpeg=new Imagick(__DIR__.'/encoded-lossy.jpg');$jpegReturn=$jpeg->decipherImage($phrase);
$source16=clone $source;$source16->setImageDepth(16);
$cipher16=clone $source16;$enc16=$cipher16->encipherImage($phrase);
icSavePNG($cipher16,'workflow-cipher16.png',16);
icSavePNG($cipher16,'workflow-cipher16-lost8.png',8);
$read16=new Imagick(__DIR__.'/workflow-cipher16.png');$saved16Hash=icHash($read16);
$readLost8=new Imagick(__DIR__.'/workflow-cipher16-lost8.png');
$dec16=$read16->decipherImage($phrase);$decLost8=$readLost8->decipherImage($phrase);
$stripped=clone $cipher;$stripped->stripImage();$strippedMetadata=icMetadata($stripped);
$stripReturn=$stripped->decipherImage($phrase);
$emptyPhrase=clone $source;$emptyEnc=$emptyPhrase->encipherImage('');$emptyHash=icHash($emptyPhrase);
$emptyDec=$emptyPhrase->decipherImage('');
$policyRejected=[];
foreach(['',"demo\0suffix"] as $badPhrase){
    try{icPhrase($badPhrase);$policyRejected[]=false;}catch(InvalidArgumentException $error){$policyRejected[]=true;}
}
$acceptedPhrase=icPhrase($phrase);
$again=clone $source;$againReturn=$again->encipherImage($acceptedPhrase);
$errors=[];
foreach(['encipher_empty'=>fn()=>(new Imagick())->encipherImage($phrase),
    'decipher_empty'=>fn()=>(new Imagick())->decipherImage($phrase)] as $name=>$call){
    try{$call();$errors[$name]=['class'=>'not caught','message'=>''];}
    catch(Throwable $error){$errors[$name]=['class'=>get_class($error),'message'=>$error->getMessage()];}
}
icView($good,'workflow-correct8.png');icView($wrong,'workflow-wrong8.png');
icView($jpeg,'workflow-jpeg8.png');icView($readLost8,'workflow-depth-loss8.png');
icView($read16,'workflow-png16-restored8.png');
$rects=icCompare([$good,$wrong,$jpeg,$readLost8],'image-cipher-workflow.png');
$wrongError=icError($source,$wrong);$jpegError=icError($source,$jpeg);$depthError=icError($source,$readLost8);
icDiagnostic('image-cipher-workflow',['executed_apis'=>['encipherImage','decipherImage'],
    'correct'=>['return'=>$goodReturn,'restored_exact'=>icHash($good)===$before,'error'=>icError($source,$good)],
    'wrong_phrase'=>['return'=>$wrongReturn,'restored_exact'=>icHash($wrong)===$before,'error'=>$wrongError],
    'jpeg90'=>['return'=>$jpegReturn,'restored_exact'=>icHash($jpeg)===$before,'error'=>$jpegError],
    'depth16'=>['encipher_return'=>$enc16,'cipher_RGB16_sha256'=>icHash($cipher16),'saved_RGB16_sha256'=>$saved16Hash,
        'decipher16_return'=>$dec16,'restored16_exact'=>icHash($read16)===$before,'error16'=>icError($source,$read16),
        'forced8_return'=>$decLost8,'forced8_restored_exact'=>icHash($readLost8)===$before,'forced8_error'=>$depthError],
    'strip'=>['properties_before_decode'=>$strippedMetadata,'return'=>$stripReturn,'restored_exact'=>icHash($stripped)===$before],
    'empty_phrase'=>['encipher_return'=>$emptyEnc,'cipher_changed'=>$emptyHash!==$before,'decipher_return'=>$emptyDec,'restored_exact'=>icHash($emptyPhrase)===$before],
    'application_policy_rejected'=>$policyRejected,'deterministic_cipher'=>icHash($again)===$cipherBefore,
    'errors'=>$errors,'public_metadata'=>icMetadata($cipher),'source_unchanged'=>icHash($source)===$before,'cipher_input_unchanged'=>icHash($cipher)===$cipherBefore,'panel_geometry'=>$rects,
    'checks'=>['correct_returns_true_and_restores'=>$goodReturn===true&&icHash($good)===$before,
        'wrong_phrase_true_is_not_authentication'=>$wrongReturn===true&&$wrongError['max']>0,
        'JPEG_true_does_not_restore'=>$jpegReturn===true&&$jpegError['max']>0,
        'PNG16_preserves_cipher_and_restores'=>$enc16===true&&$saved16Hash===icHash($cipher16)&&$dec16===true&&icHash($read16)===$before,
        'forced_PNG8_loses_16bit_cipher'=>$decLost8===true&&$depthError['max']>0,
        'strip_is_not_remove_all_properties'=>$strippedMetadata['comment']===false&&$strippedMetadata['ticket']==='PUBLIC-42'&&$strippedMetadata['cipher_mode']==='CTR',
        'stripped_pixels_still_restore'=>$stripReturn===true&&icHash($stripped)===$before,
        'API_accepts_empty_phrase'=>$emptyEnc===true&&$emptyHash!==$before&&$emptyDec===true&&icHash($emptyPhrase)===$before,
        'own_policy_rejects_empty_and_NUL'=>$policyRejected===[true,true],
        'same_phrase_reuses_cipher'=>$againReturn===true&&icHash($again)===$cipherBefore,
        'two_empty_object_errors'=>array_column($errors,'class')===['ImagickException','ImagickException'],
        'originals_preserved'=>icHash($source)===$before&&icHash($cipher)===$cipherBefore]]);
echo "image-cipher-workflow.png\nworkflow-correct8.png\nworkflow-wrong8.png\nworkflow-jpeg8.png\nworkflow-depth-loss8.png\nworkflow-png16-restored8.png\nworkflow-cipher16.png\nworkflow-cipher16-lost8.png\nencoded-lossy.jpg\nmetrics.json\ncorrect=exact wrong=true-but-invalid JPEG=true-but-invalid PNG16=exact forced8=invalid policy-rejections=2 errors=2\n";

Правильный lossless-вход восстановился; неверная фраза, JPEG и потеря глубины дали true без правильного результата. PNG16 сохранил 16-битный cipher и восстановил источник. Собственная политика отклонила пустую/NUL-фразу, а API отдельно продемонстрировал принятие пустой строки. Две ошибки пустого объекта пойманы. Самостоятельный архив: example.php, два точных PNG-входа в base64 и image-cipher-fixture.php. Сохраните файлы рядом и выполните php example.php. Проверено PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16 без HDRI с Cipher, PNG и JPEG. Фраза public-demo-passphrase-2026-only публична и служит только воспроизводимой демонстрации. icRestore восстанавливает входы с проверкой SHA, icSource открывает подготовленный непрозрачный RGB8 и добавляет только публичные свойства. Вызовы изучаемых методов находятся в основном коде. icSavePNG пишет настоящий файл данных, icView — отдельный PNG8-просмотр; обзорные просмотры не используются для decipher.

Ожидаемый вывод проверенной программы
image-cipher-workflow.png
workflow-correct8.png
workflow-wrong8.png
workflow-jpeg8.png
workflow-depth-loss8.png
workflow-png16-restored8.png
workflow-cipher16.png
workflow-cipher16-lost8.png
encoded-lossy.jpg
metrics.json
correct=exact wrong=true-but-invalid JPEG=true-but-invalid PNG16=exact forced8=invalid policy-rejections=2 errors=2
Imagick::decipherImageПонять существующую обфускацию пикселей и проверить настоящий lossless roundtrip

PECL imagick 2 >= 2.3.0, PECL imagick 3 · imagick

Imagick::decipherImage(string $passphrase): bool

Полный официальный базис

Imagick::decipherImage(string $passphrase): bool

Официальная доступность: PECL imagick 2 начиная с 2.3.0 и PECL imagick 3, связанный ImageMagick не ниже 6.3.9. Оба метода действуют в нашей Imagick 3.8.1 с IM7 и не помечены deprecated. Исходные записи целиком сохранены ниже, включая взаимные ссылки; официальных программных примеров и отдельного раздела ошибок на этих двух страницах нет.

decipherImage принимает обязательную строку passphrase; исходное изображение должно быть предварительно обработано encipherImage. Возвращает true при завершении операции. Для правильного восстановления нужны та же фраза и сохранённый соответствующий поток cipher-пикселей. Метод не распознаёт автоматически чужую схему AES, JPEG-повреждение или правильность пароля; неверная фраза в нашем запуске тоже вернула true.

Строка PHP — содержимое фразы, а не путь к файлу. Это отличие от CLI-примеров ImageMagick с -encipher passphrase.txt. Передача имени файла PHP-методу не прочитает этот файл как фразу. Сам метод меняет объект; bool не содержит пиксели и не является именем выходного файла. Для сохранения требуется отдельная операция записи, для сохранения исходника — отдельный clone.

В точном wrapper требуется непустое текущее изображение; оба вызова на пустом Imagick выбросили ImagickException с Can not process empty Imagick object. При выключенной compile-time поддержке Cipher Core выдаёт CipherSupportNotEnabled, хотя имена методов могут существовать. При этом пустая строка passphrase в данной реализации допускается и roundtrip выполняется. Наш запрет пустой/NUL-строки — явно дополнительная политика приложения, не объявление такого ограничения в официальном API.

Exact IM7.1.1-46 использует AES-CTR над экспортированными пиксельными байтами; nonce детерминирован, независимой проверки аутентичности нет. Current official guide относит этот механизм только к обычной обфускации. Не используйте его как обещание конфиденциальности документов, защищённое хранилище или проверку целостности. Полнофайловое шифрование с аутентификацией — другая задача, разобранная в соответствующих уроках Sodium и OpenSSL.

Полный официальный XML: описание, доступность, параметр, return и связанные методы
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<refentry xmlns="http://docbook.org/ns/docbook" xml:id="imagick.decipherimage">
 <refnamediv>
  <refname>Imagick::decipherImage</refname>
  <refpurpose>Deciphers an image</refpurpose>
 </refnamediv>

 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <modifier>public</modifier> <type>bool</type><methodname>Imagick::decipherImage</methodname>
   <methodparam><type>string</type><parameter>passphrase</parameter></methodparam>
  </methodsynopsis>

  <para>
   Deciphers image that has been enciphered before. The image must be enciphered
   using <function>Imagick::encipherImage</function>.
   &imagick.method.available.0x639;
  </para>
 </refsect1>

 <refsect1 role="parameters">
  &reftitle.parameters;
  <para>
   <variablelist>
    <varlistentry>
     <term><parameter>passphrase</parameter></term>
     <listitem>
      <para>
       The passphrase
      </para>
     </listitem>
    </varlistentry>
   </variablelist>
  </para>

 </refsect1>
 <refsect1 role="returnvalues">
  &reftitle.returnvalues;
  <para>
   &imagick.return.success;
  </para>
 </refsect1>

 <refsect1 role="seealso">
  &reftitle.seealso;
  <para>
   <simplelist>
    <member><function>Imagick::encipherImage</function></member>
   </simplelist>
  </para>
 </refsect1>

</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->

Восстановить отдельный заранее подготовленный cipher-вход

Короткий decipher работает с настоящим encoded-rgb8.png, созданным заранее той же версией и публичной фразой. Он не повторяет encipher в этой программе. Рабочая копия восстановилась точно, fixture и эталон сохранены.

Восстановить отдельный заранее подготовленный cipher-входПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/image-cipher-fixture.php';
icRestore();
$source=icSource(); $before=icHash($source);
$phrase=IC_DEMO_PHRASE;
$cipher=new Imagick(__DIR__.'/encoded-rgb8.png');
$cipherBefore=icHash($cipher);
$restored=clone $cipher;
$ok=$restored->decipherImage($phrase);
icDecipherProof($source,$cipher,$restored,$ok,$before,$cipherBefore);
echo "image-cipher-decipher.png\ndecipher-input8.png\nmetrics.json\ndecipher=true restored-exact=1 cipher-input-unchanged=1 source-unchanged=1\n";

Короткий decipher работает с настоящим encoded-rgb8.png, созданным заранее той же версией и публичной фразой. Он не повторяет encipher в этой программе. Рабочая копия восстановилась точно, fixture и эталон сохранены. Самостоятельный архив: example.php, два точных PNG-входа в base64 и image-cipher-fixture.php. Сохраните файлы рядом и выполните php example.php. Проверено PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16 без HDRI с Cipher, PNG и JPEG. Фраза public-demo-passphrase-2026-only публична и служит только воспроизводимой демонстрации. icRestore восстанавливает входы с проверкой SHA, icSource открывает подготовленный непрозрачный RGB8 и добавляет только публичные свойства. Вызовы изучаемых методов находятся в основном коде. icSavePNG пишет настоящий файл данных, icView — отдельный PNG8-просмотр; обзорные просмотры не используются для decipher.

Ожидаемый вывод проверенной программы
image-cipher-decipher.png
decipher-input8.png
metrics.json
decipher=true restored-exact=1 cipher-input-unchanged=1 source-unchanged=1

Найти причину невосстановления: фраза, JPEG, глубина или неподходящая проверка

Правильный lossless-вход восстановился; неверная фраза, JPEG и потеря глубины дали true без правильного результата. PNG16 сохранил 16-битный cipher и восстановил источник. Собственная политика отклонила пустую/NUL-фразу, а API отдельно продемонстрировал принятие пустой строки. Две ошибки пустого объекта пойманы.

Найти причину невосстановления: фраза, JPEG, глубина или неподходящая проверкаПример для указанного окружения
<?php
declare(strict_types=1);
require __DIR__.'/image-cipher-fixture.php';
icRestore();
$source=icSource(); $before=icHash($source);
$phrase=IC_DEMO_PHRASE;
$cipher=new Imagick(__DIR__.'/encoded-rgb8.png');$cipherBefore=icHash($cipher);
$good=clone $cipher;$goodReturn=$good->decipherImage($phrase);
$wrong=clone $cipher;$wrongReturn=$wrong->decipherImage('different-public-demo-phrase');
$jpeg=clone $cipher;$jpeg->setImageFormat('jpeg');$jpeg->setImageCompressionQuality(90);
$jpeg->writeImage(__DIR__.'/encoded-lossy.jpg');
$jpeg=new Imagick(__DIR__.'/encoded-lossy.jpg');$jpegReturn=$jpeg->decipherImage($phrase);
$source16=clone $source;$source16->setImageDepth(16);
$cipher16=clone $source16;$enc16=$cipher16->encipherImage($phrase);
icSavePNG($cipher16,'workflow-cipher16.png',16);
icSavePNG($cipher16,'workflow-cipher16-lost8.png',8);
$read16=new Imagick(__DIR__.'/workflow-cipher16.png');$saved16Hash=icHash($read16);
$readLost8=new Imagick(__DIR__.'/workflow-cipher16-lost8.png');
$dec16=$read16->decipherImage($phrase);$decLost8=$readLost8->decipherImage($phrase);
$stripped=clone $cipher;$stripped->stripImage();$strippedMetadata=icMetadata($stripped);
$stripReturn=$stripped->decipherImage($phrase);
$emptyPhrase=clone $source;$emptyEnc=$emptyPhrase->encipherImage('');$emptyHash=icHash($emptyPhrase);
$emptyDec=$emptyPhrase->decipherImage('');
$policyRejected=[];
foreach(['',"demo\0suffix"] as $badPhrase){
    try{icPhrase($badPhrase);$policyRejected[]=false;}catch(InvalidArgumentException $error){$policyRejected[]=true;}
}
$acceptedPhrase=icPhrase($phrase);
$again=clone $source;$againReturn=$again->encipherImage($acceptedPhrase);
$errors=[];
foreach(['encipher_empty'=>fn()=>(new Imagick())->encipherImage($phrase),
    'decipher_empty'=>fn()=>(new Imagick())->decipherImage($phrase)] as $name=>$call){
    try{$call();$errors[$name]=['class'=>'not caught','message'=>''];}
    catch(Throwable $error){$errors[$name]=['class'=>get_class($error),'message'=>$error->getMessage()];}
}
icView($good,'workflow-correct8.png');icView($wrong,'workflow-wrong8.png');
icView($jpeg,'workflow-jpeg8.png');icView($readLost8,'workflow-depth-loss8.png');
icView($read16,'workflow-png16-restored8.png');
$rects=icCompare([$good,$wrong,$jpeg,$readLost8],'image-cipher-workflow.png');
$wrongError=icError($source,$wrong);$jpegError=icError($source,$jpeg);$depthError=icError($source,$readLost8);
icDiagnostic('image-cipher-workflow',['executed_apis'=>['encipherImage','decipherImage'],
    'correct'=>['return'=>$goodReturn,'restored_exact'=>icHash($good)===$before,'error'=>icError($source,$good)],
    'wrong_phrase'=>['return'=>$wrongReturn,'restored_exact'=>icHash($wrong)===$before,'error'=>$wrongError],
    'jpeg90'=>['return'=>$jpegReturn,'restored_exact'=>icHash($jpeg)===$before,'error'=>$jpegError],
    'depth16'=>['encipher_return'=>$enc16,'cipher_RGB16_sha256'=>icHash($cipher16),'saved_RGB16_sha256'=>$saved16Hash,
        'decipher16_return'=>$dec16,'restored16_exact'=>icHash($read16)===$before,'error16'=>icError($source,$read16),
        'forced8_return'=>$decLost8,'forced8_restored_exact'=>icHash($readLost8)===$before,'forced8_error'=>$depthError],
    'strip'=>['properties_before_decode'=>$strippedMetadata,'return'=>$stripReturn,'restored_exact'=>icHash($stripped)===$before],
    'empty_phrase'=>['encipher_return'=>$emptyEnc,'cipher_changed'=>$emptyHash!==$before,'decipher_return'=>$emptyDec,'restored_exact'=>icHash($emptyPhrase)===$before],
    'application_policy_rejected'=>$policyRejected,'deterministic_cipher'=>icHash($again)===$cipherBefore,
    'errors'=>$errors,'public_metadata'=>icMetadata($cipher),'source_unchanged'=>icHash($source)===$before,'cipher_input_unchanged'=>icHash($cipher)===$cipherBefore,'panel_geometry'=>$rects,
    'checks'=>['correct_returns_true_and_restores'=>$goodReturn===true&&icHash($good)===$before,
        'wrong_phrase_true_is_not_authentication'=>$wrongReturn===true&&$wrongError['max']>0,
        'JPEG_true_does_not_restore'=>$jpegReturn===true&&$jpegError['max']>0,
        'PNG16_preserves_cipher_and_restores'=>$enc16===true&&$saved16Hash===icHash($cipher16)&&$dec16===true&&icHash($read16)===$before,
        'forced_PNG8_loses_16bit_cipher'=>$decLost8===true&&$depthError['max']>0,
        'strip_is_not_remove_all_properties'=>$strippedMetadata['comment']===false&&$strippedMetadata['ticket']==='PUBLIC-42'&&$strippedMetadata['cipher_mode']==='CTR',
        'stripped_pixels_still_restore'=>$stripReturn===true&&icHash($stripped)===$before,
        'API_accepts_empty_phrase'=>$emptyEnc===true&&$emptyHash!==$before&&$emptyDec===true&&icHash($emptyPhrase)===$before,
        'own_policy_rejects_empty_and_NUL'=>$policyRejected===[true,true],
        'same_phrase_reuses_cipher'=>$againReturn===true&&icHash($again)===$cipherBefore,
        'two_empty_object_errors'=>array_column($errors,'class')===['ImagickException','ImagickException'],
        'originals_preserved'=>icHash($source)===$before&&icHash($cipher)===$cipherBefore]]);
echo "image-cipher-workflow.png\nworkflow-correct8.png\nworkflow-wrong8.png\nworkflow-jpeg8.png\nworkflow-depth-loss8.png\nworkflow-png16-restored8.png\nworkflow-cipher16.png\nworkflow-cipher16-lost8.png\nencoded-lossy.jpg\nmetrics.json\ncorrect=exact wrong=true-but-invalid JPEG=true-but-invalid PNG16=exact forced8=invalid policy-rejections=2 errors=2\n";

Правильный lossless-вход восстановился; неверная фраза, JPEG и потеря глубины дали true без правильного результата. PNG16 сохранил 16-битный cipher и восстановил источник. Собственная политика отклонила пустую/NUL-фразу, а API отдельно продемонстрировал принятие пустой строки. Две ошибки пустого объекта пойманы. Самостоятельный архив: example.php, два точных PNG-входа в base64 и image-cipher-fixture.php. Сохраните файлы рядом и выполните php example.php. Проверено PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16 без HDRI с Cipher, PNG и JPEG. Фраза public-demo-passphrase-2026-only публична и служит только воспроизводимой демонстрации. icRestore восстанавливает входы с проверкой SHA, icSource открывает подготовленный непрозрачный RGB8 и добавляет только публичные свойства. Вызовы изучаемых методов находятся в основном коде. icSavePNG пишет настоящий файл данных, icView — отдельный PNG8-просмотр; обзорные просмотры не используются для decipher.

Ожидаемый вывод проверенной программы
image-cipher-workflow.png
workflow-correct8.png
workflow-wrong8.png
workflow-jpeg8.png
workflow-depth-loss8.png
workflow-png16-restored8.png
workflow-cipher16.png
workflow-cipher16-lost8.png
encoded-lossy.jpg
metrics.json
correct=exact wrong=true-but-invalid JPEG=true-but-invalid PNG16=exact forced8=invalid policy-rejections=2 errors=2
Источники и обсуждения

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

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

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

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