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

Дерево руководства
Глава 400 · После объектов, файлов и базовой обработки изображений
Imagick: старый getImageSize, байты файла и точный лимит экспорта
Не спутать getImageSize с getimagesize, понять ноль после crop и записать ровно те байты PNG, которые прошли проверку.
Разобраться, что означают размеры собственной этикетки
Сервис принимает картинку этикетки и должен показать её размеры, а после обработки — уложить отправляемый файл в лимит байтов. В старом коде найден getImageSize, рядом в примере — getimagesize. Названия похожи, но задачи разные. Начнём с собственной этикетки: она имеет 400×320 пикселей и занимает 1682 байта. Затем вырежем часть и запишем ровно те байты, которые прошли проверку.

Пиксели задают сетку картинки: 400 столбцов и 320 строк, всего 128000 позиций. Байты — длина закодированного файла, который хранится на диске или передаётся. Сжатие, формат и дополнительные данные влияют на файл; одна только площадь картинки не сообщает его длину. Расход памяти декодированного Imagick тоже не равен этим 1682 байтам.
$image = new Imagick(__DIR__ . "/label.png");
$bytes = $image->getImageLength();
echo $bytes . " bytes"; // 1682 bytesnew Imagick читает файл в объект $image. Стрелка -> вызывает его метод, пустые скобки означают отсутствие аргументов. Знак = сохраняет возвращённое целое число в $bytes. Точка соединяет число с поясняющим текстом, echo выводит результат. В новом коде используем getImageLength; старое getImageSize ниже вызывается отдельно для сравнения и документирования миграции.
Чтобы запустить короткий фрагмент, нужен файл label.png. В каждом полном архиве он включён как label.png.b64: example.php автоматически восстановит обычный PNG рядом. Это собственная учебная картинка. В первом полном примере старый и новый методы действительно вызываются и сверяются с файловой системой; чтение getimagesize отдельно показывает геометрию.
Сравнить старое имя, текущее имя и реальные байты файла
Исходный label.png занимает 1682 байта и имеет геометрию 400×320. Оба метода Imagick вернули 1682; PHP getimagesize вернул массив со стороной 400 и стороной 320. Старый метод действительно доступен и вызван в этой сборке, хотя документация рекомендует getImageLength.
<?php
declare(strict_types=1);
require __DIR__ . '/size-fixture.php';
szRestore();
$source = new Imagick(__DIR__ . '/label.png');
$sourceBefore = szState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/label.png');
if (!method_exists($source, 'getImageSize')) {
throw new RuntimeException('This historical comparison requires getImageSize');
}
$oldBytes = $source->getImageSize();
$currentBytes = $source->getImageLength();
$dimensions = getimagesize(__DIR__ . '/label.png');
clearstatcache(true, __DIR__ . '/label.png');
$diskBytes = filesize(__DIR__ . '/label.png');
$file = szFile('label.png');
$view = szView($source);
$images = ['source'=>szImage($view,'first-source8.png')];
$rects = szCompare([$view],'image-size-first.png');
szDiagnostic('image-size-first',['getImageSize','getImageLength'],[
'legacy_bytes'=>$oldBytes,'current_bytes'=>$currentBytes,'disk_bytes'=>$diskBytes,'php_getimagesize'=>$dimensions,'file'=>$file,'units'=>['bytes'=>1682,'width_pixels'=>400,'height_pixels'=>320,'pixel_count'=>128000],
'images'=>$images,'panel_keys'=>['source'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>szState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>szState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/label.png')===$sourceHash,
'checks'=>['legacy_current_agree'=>$oldBytes===$currentBytes,'getters_match_disk'=>$currentBytes===$diskBytes,'known_input_bytes'=>$diskBytes===1682,'geometry_is_separate'=>$dimensions[0]===400&&$dimensions[1]===320,'method_returns_int'=>is_int($oldBytes)]
]);
echo "image-size-first.png\nfirst-source8.png\nmetrics.json\ngetImageSize=1682 getImageLength=1682 filesize=1682 geometry=400x320\n";
Исходный label.png занимает 1682 байта и имеет геометрию 400×320. Оба метода Imagick вернули 1682; PHP getimagesize вернул массив со стороной 400 и стороной 320. Старый метод действительно доступен и вызван в этой сборке, хотя документация рекомендует getImageLength. Архив содержит example.php, label.png.b64 и size-fixture.php. Распакуйте рядом и выполните php example.php; обычный label.png восстановится автоматически. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Значения байтов относятся к этому исходнику и кодерам.
Ожидаемый вывод настоящего запуска
image-size-first.png
first-source8.png
metrics.json
getImageSize=1682 getImageLength=1682 filesize=1682 geometry=400x320
Одинаковое число 1682 от обоих методов означает, что смена имени не меняет единицу измерения. deprecated — рекомендация отказаться от старого API, а не обещание его немедленного отсутствия. Для собственного нового обработчика берите getImageLength. Эта глава дополняет его существующее объяснение исторической карточкой и сценарием проверки одного готового blob.
Отделить одинаковую геометрию от разных файлов

Допустим, интерфейс показывает «400×320» и разработчик пытается вычислить по этой записи допустимость файла. Сделаем контроль: запишем тот же рисунок как JPEG. Геометрия останется прежней, но кодер создаст другой набор байтов. Проверка лимита по одной ширине и высоте поэтому не решает задачу.
$dimensions = getimagesize(__DIR__ . "/label.png");
echo $dimensions[0] . "x" . $dimensions[1]; // 400x320
$bytes = filesize(__DIR__ . "/label.png");
echo $bytes; // 1682getimagesize — обычная функция PHP, вызываемая без ->. Она получает строку пути и возвращает массив; квадратные скобки выбирают элемент. [0] — ширина, [1] — высота. У filesize другой результат: число байтов файла или false при ошибке. После изменения файла PHP может использовать кэш сведений, поэтому наши измерения вызывают clearstatcache(true, $path) перед повторной проверкой.
Полный пример создаёт JPEG quality 80 и записывает полученную бинарную строку целиком. Затем новый Imagick читает фактический JPEG: getImageLength сверяется с filesize и strlen той строки, которая действительно записывалась. Картинки на доске взяты из декодирования двух реальных файлов, а не нарисованы заново.
Увидеть разные размеры файлов с одной геометрией
Сохранён label-q80.jpg: та же геометрия 400×320, но 11950 байт вместо 1682 у исходного PNG. На этом рисунке с плоскими областями PNG компактнее; универсального правила для любых фотографий нет. Проверены настоящие байты и отличающиеся декодированные пиксели.
<?php
declare(strict_types=1);
require __DIR__ . '/size-fixture.php';
szRestore();
$source = new Imagick(__DIR__ . '/label.png');
$sourceBefore = szState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/label.png');
$pngFile = szFile('label.png');
$jpeg = clone $source;
$jpeg->setImageFormat('jpeg');
$jpeg->setImageCompressionQuality(80);
$blob = $jpeg->getImageBlob();
$jpegFile = szWriteBlob($blob, 'label-q80.jpg');
$jpegRead = new Imagick(__DIR__ . '/label-q80.jpg');
$currentBytes = $jpegRead->getImageLength();
$views = [szView($source),szView($jpegRead)];
$images = ['png'=>szImage($views[0],'formats-png8.png'),'jpeg'=>szImage($views[1],'formats-jpeg8.png')];
$rects = szCompare($views,'image-size-formats.png');
szDiagnostic('image-size-formats',['getImageBlob','getImageLength'],[
'png_file'=>$pngFile,'jpeg_file'=>$jpegFile,'encoded_bytes'=>strlen($blob),'current_bytes'=>$currentBytes,'blob_sha256'=>hash('sha256',$blob),'jpeg_quality'=>80,
'images'=>$images,'panel_keys'=>['png','jpeg'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>szState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>szState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/label.png')===$sourceHash,
'checks'=>['same_geometry'=>$pngFile['geometry']===$jpegFile['geometry'],'different_bytes'=>$pngFile['bytes']!==$jpegFile['bytes'],'actual_fixture_sizes'=>$pngFile['bytes']===1682&&$jpegFile['bytes']===11950,'blob_matches_file'=>strlen($blob)===$jpegFile['bytes']&&hash('sha256',$blob)===$jpegFile['sha256'],'current_matches_file'=>$currentBytes===$jpegFile['bytes'],'jpeg_pixels_differ'=>$pngFile['state']['RGB16_sha256']!==$jpegFile['state']['RGB16_sha256']]
]);
echo "image-size-formats.png\nformats-png8.png\nformats-jpeg8.png\nlabel-q80.jpg\nmetrics.json\nsame-geometry=400x320 PNG=1682 JPEG80=11950 bytes decoded-pixels=different\n";
Сохранён label-q80.jpg: та же геометрия 400×320, но 11950 байт вместо 1682 у исходного PNG. На этом рисунке с плоскими областями PNG компактнее; универсального правила для любых фотографий нет. Проверены настоящие байты и отличающиеся декодированные пиксели. Архив содержит example.php, label.png.b64 и size-fixture.php. Распакуйте рядом и выполните php example.php; обычный label.png восстановится автоматически. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Значения байтов относятся к этому исходнику и кодерам.
Ожидаемый вывод настоящего запуска
image-size-formats.png
formats-png8.png
formats-jpeg8.png
label-q80.jpg
metrics.json
same-geometry=400x320 PNG=1682 JPEG80=11950 bytes decoded-pixels=different
Для этой этикетки с плоскими заливками, прямоугольниками и тонкими линиями PNG оказался существенно компактнее JPEG. Это свойство данного рисунка и настроек. Для фотографии результат может быть другим. JPEG также изменил декодированные пиксели, хотя геометрия осталась 400×320; равенство размеров не означает равенство цвета или качества.
| Нужно узнать | Что измеряем |
|---|---|
| Ширину и высоту файла | getimagesize($path) или геометрию прочитанного Imagick |
| Байты существующего файла | filesize($path), с обработкой false и учётом кэша |
| Байты конкретного полученного blob | strlen($blob): длина бинарной строки в байтах |
| Текущую известную длину в Imagick | getImageLength; историческое имя getImageSize |
| Память обработки | Отдельные измерения и лимиты; длина PNG/JPEG её не определяет |
Для подписи можно разделить байты на 1024 и получить KiB; исходные сравнения удобнее вести в целых байтах. Уточняйте единицу лимита: 1000 байт и 1 KiB=1024 байта не одно и то же. Наша следующая проверка намеренно задаёт ровно 1000 байт. О формате и качестве подробнее в главе о сжатии.
Понять нулевую длину после crop и измерить готовый blob

Теперь нужен только верхний левый фрагмент этикетки: 200×160 пикселей, начиная с точки x=20, y=20. Сначала меняем копию растра в памяти. Это ещё не означает, что библиотека уже сформировала новый файл. В нашем реальном запуске сразу после crop оба getter вернули 0, хотя у объекта уже есть непустое изображение 200×160.
$part = clone $image;
$part->cropImage(200, 160, 20, 20);
$part->setImagePage(0, 0, 0, 0);
echo $part->getImageLength(); // В этом запуске: 0
$part->setImageFormat("png");
$blob = $part->getImageBlob();
echo strlen($blob); // Байты именно полученной строкиclone оставляет исходник отдельным. Аргументы cropImage — ширина, высота и начало фрагмента; setImagePage сбрасывает сведения о виртуальном холсте после обрезки. Полный пример дополнительно задаёт RGB8 и параметры PNG, поэтому его закодированный фрагмент имеет конкретные 662 байта. Порядок действий важнее этого числа: сначала кодирование, затем измерение его результата.
Blob — бинарная строка с полным закодированным изображением. Она может содержать нулевые байты; strlen считает все байты строки. Это не mb_strlen и не количество видимых символов. После получения $blob мы записываем именно эту переменную через file_put_contents, чтобы не подменить проверенный результат новым кодированием.
Измерить вырезанную часть только после кодирования
Копия вырезана до 200×160; оба getter до кодирования вернули 0. После getImageBlob получены 662 байта, и именно эта строка записана в label-cropped.png. Исходный label.png не изменился. На иллюстрации фрагмент показан без увеличения по центру серого холста.
<?php
declare(strict_types=1);
require __DIR__ . '/size-fixture.php';
szRestore();
$source = new Imagick(__DIR__ . '/label.png');
$sourceBefore = szState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/label.png');
$cropped = clone $source;
$cropped->cropImage(200,160,20,20);
$cropped->setImagePage(0,0,0,0);
$beforeEncoding = [
'state'=>szState($cropped),
'legacy_bytes'=>$cropped->getImageSize(),
'current_bytes'=>$cropped->getImageLength(),
];
$blob = szPNG($cropped);
$afterEncoding = [
'state'=>szState($cropped),
'legacy_bytes'=>$cropped->getImageSize(),
'current_bytes'=>$cropped->getImageLength(),
];
$saved = szWriteBlob($blob,'label-cropped.png');
$read = new Imagick(__DIR__.'/label-cropped.png');
$errors = [
'empty_legacy'=>szTry(fn()=>(new Imagick())->getImageSize()),
'empty_current'=>szTry(fn()=>(new Imagick())->getImageLength()),
'missing_input'=>szTry(fn()=>new Imagick(__DIR__.'/missing.png')),
];
$views = [szView($source),szView($read)];
$images = ['source'=>szImage($views[0],'memory-source8.png'),'crop'=>szImage($views[1],'memory-crop8.png')];
$rects = szCompare($views,'image-size-memory.png');
szDiagnostic('image-size-memory',['getImageSize','getImageLength','cropImage','getImageBlob'],[
'crop'=>['width'=>200,'height'=>160,'x'=>20,'y'=>20],'before_encoding'=>$beforeEncoding,'after_encoding'=>$afterEncoding,'blob_bytes'=>strlen($blob),'blob_sha256'=>hash('sha256',$blob),'saved'=>$saved,'readback'=>szState($read),'errors'=>$errors,'crop_display'=>['x'=>100,'y'=>80,'width'=>200,'height'=>160,'scale'=>1],
'images'=>$images,'panel_keys'=>['source','crop'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>szState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>szState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/label.png')===$sourceHash,
'checks'=>['geometry_changed_before_encoding'=>$beforeEncoding['state']['geometry']===[200,160],'both_before_zero'=>$beforeEncoding['legacy_bytes']===0&&$beforeEncoding['current_bytes']===0,'both_after_actual'=>$afterEncoding['legacy_bytes']===662&&$afterEncoding['current_bytes']===662,'same_encoded_bytes'=>strlen($blob)===$saved['bytes']&&hash('sha256',$blob)===$saved['sha256'],'crop_pixels_roundtrip'=>$afterEncoding['state']['RGB16_sha256']===szHash($read),'empty_legacy_caught'=>($errors['empty_legacy']['error']['class']??null)==='ImagickException','empty_current_caught'=>($errors['empty_current']['error']['class']??null)==='ImagickException','missing_caught'=>($errors['missing_input']['error']['class']??null)==='ImagickException']
]);
echo "image-size-memory.png\nmemory-source8.png\nmemory-crop8.png\nlabel-cropped.png\nmetrics.json\ncrop=200x160 before-encoding=0 after-encoding=662 written=662 source=unchanged\n";
Копия вырезана до 200×160; оба getter до кодирования вернули 0. После getImageBlob получены 662 байта, и именно эта строка записана в label-cropped.png. Исходный label.png не изменился. На иллюстрации фрагмент показан без увеличения по центру серого холста. Архив содержит example.php, label.png.b64 и size-fixture.php. Распакуйте рядом и выполните php example.php; обычный label.png восстановится автоматически. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Значения байтов относятся к этому исходнику и кодерам.
Ожидаемый вывод настоящего запуска
image-size-memory.png
memory-source8.png
memory-crop8.png
label-cropped.png
metrics.json
crop=200x160 before-encoding=0 after-encoding=662 written=662 source=unchanged
Откройте label-cropped.png: его настоящая геометрия 200×160, а не 400×320. Серые поля существуют лишь у иллюстрации на странице. Исходный label.png сохранил 400×320 и 1682 байта. После кодирования обе длины в изменённом объекте стали 662; в файле также ровно 662 байта, а SHA256 совпал с хешем blob.
Не превращайте это наблюдение в правило «после любой операции getter всегда нулевой» или «он всегда хранит старое число». Значение зависит от состояния потока, операции и версии. Надёжная проверка именно отправляемого содержимого измеряет уже полученные байты. Повторный вызов getImageBlob — новая операция кодирования; если нужно сохранить точную последовательность байтов, храните строку, которую уже проверили.
Три ошибки перехвачены отдельно: оба getter на пустом Imagick и открытие отсутствующего файла. Они не смешиваются с допустимым нулём длины после crop. Подробности геометрии: холст, обрезка и виртуальная страница. Об ошибках чтения и записи: операции с файлами изображений.
Проверить предел и сохранить ровно принятые байты

Соберём маленькую функцию экспорта: она получает подготовленное изображение, лимит в байтах и имя результата. Требование простое: закодировать один раз, измерить строку, при превышении вернуть понятный отказ, иначе записать ровно эту строку. Подбор качества JPEG уже разобран в главе о превью и размере файла; здесь новая задача — связать решение с конкретными байтами, не менять их между проверкой и записью.
$blob = $image->getImageBlob();
$bytes = strlen($blob);
if ($bytes > $maxBytes) {
return ["accepted" => false, "bytes" => $bytes];
}
file_put_contents($path, $blob);Это короткая схема функции после задания формата и параметров PNG. if выбирает ветку по сравнению; return возвращает вызывающему коду массив решения и завершает функцию. Полный вариант ниже работает с копией, задаёт PNG RGB8, проверяет запись и хеш. Для каждого кандидата основное кодирование выполняется один раз; изображения для страницы создаются отдельно и не участвуют в решении о лимите.
Проверить лимит и записать ровно проверенные байты
При лимите 1000 байт полный PNG на 1682 байта отклонён, а фрагмент на 662 байта записан в label-part.png. label-rejected.png не создаётся. В label-export.json сохранены оба решения и контрольные суммы, связывающие принятый blob с реальным файлом.
<?php
declare(strict_types=1);
require __DIR__ . '/size-fixture.php';
szRestore();
$source = new Imagick(__DIR__ . '/label.png');
$sourceBefore = szState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/label.png');
function exportPNGUnderLimit(Imagick $image, int $maxBytes, string $filename): array
{
if ($maxBytes < 1) {
throw new InvalidArgumentException('Positive byte limit required');
}
$copy = clone $image;
$blob = szPNG($copy);
$bytes = strlen($blob);
if ($bytes > $maxBytes) {
return ['accepted'=>false,'bytes'=>$bytes,'limit'=>$maxBytes,
'filename'=>$filename,'reason'=>'encoded-file-too-large'];
}
$saved = szWriteBlob($blob, $filename);
$read = new Imagick(__DIR__ . '/' . $filename);
return ['accepted'=>true,'bytes'=>$bytes,'limit'=>$maxBytes,
'filename'=>$filename,'blob_sha256'=>hash('sha256',$blob),
'saved'=>$saved,'current_bytes'=>$read->getImageLength()];
}
$crop = clone $source;
$crop->cropImage(200,160,20,20);
$crop->setImagePage(0,0,0,0);
$rejected = exportPNGUnderLimit($source,1000,'label-rejected.png');
$accepted = exportPNGUnderLimit($crop,1000,'label-part.png');
$manifest = ['source'=>'label.png','source_sha256'=>$sourceHash,'limit_bytes'=>1000,
'rejected'=>$rejected,'accepted'=>$accepted,
'policy'=>'Encode each candidate once; write the same checked bytes only when accepted'];
file_put_contents(__DIR__.'/label-export.json',json_encode(
$manifest,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR
) . "\n");
$readManifest = json_decode((string)file_get_contents(__DIR__.'/label-export.json'),true,512,JSON_THROW_ON_ERROR);
$output = new Imagick(__DIR__.'/label-part.png');
$views = [szView($source),szView($output)];
$images = ['rejected'=>szImage($views[0],'workflow-rejected8.png'),'accepted'=>szImage($views[1],'workflow-accepted8.png')];
$rects = szCompare($views,'image-size-workflow.png');
szDiagnostic('image-size-workflow',['cropImage','getImageBlob','getImageLength'],[
'rejected'=>$rejected,'accepted'=>$accepted,'manifest'=>$readManifest,'manifest_sha256'=>hash_file('sha256',__DIR__.'/label-export.json'),'rejected_output_exists'=>is_file(__DIR__.'/label-rejected.png'),'readback'=>szState($output),'crop_display'=>['x'=>100,'y'=>80,'width'=>200,'height'=>160,'scale'=>1],
'images'=>$images,'panel_keys'=>['rejected','accepted'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>szState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>szState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/label.png')===$sourceHash,
'checks'=>['large_rejected'=>$rejected['accepted']===false&&$rejected['bytes']===1682,'rejected_not_written'=>!is_file(__DIR__.'/label-rejected.png'),'crop_accepted'=>$accepted['accepted']===true&&$accepted['bytes']===662,'limit_respected'=>$accepted['saved']['bytes']<=1000,'same_blob_written'=>$accepted['blob_sha256']===$accepted['saved']['sha256'],'modern_getter_matches'=>$accepted['current_bytes']===$accepted['saved']['bytes'],'manifest_file_bound'=>$readManifest['accepted']['saved']['sha256']===hash_file('sha256',__DIR__.'/label-part.png'),'manifest_source_bound'=>$readManifest['source_sha256']===hash_file('sha256',__DIR__.'/label.png')]
]);
echo "image-size-workflow.png\nworkflow-rejected8.png\nworkflow-accepted8.png\nlabel-part.png\nlabel-export.json\nmetrics.json\nlimit=1000 rejected=1682 accepted=662 exact-blob=saved rejected-file=absent\n";
При лимите 1000 байт полный PNG на 1682 байта отклонён, а фрагмент на 662 байта записан в label-part.png. label-rejected.png не создаётся. В label-export.json сохранены оба решения и контрольные суммы, связывающие принятый blob с реальным файлом. Архив содержит example.php, label.png.b64 и size-fixture.php. Распакуйте рядом и выполните php example.php; обычный label.png восстановится автоматически. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Значения байтов относятся к этому исходнику и кодерам.
Ожидаемый вывод настоящего запуска
image-size-workflow.png
workflow-rejected8.png
workflow-accepted8.png
label-part.png
label-export.json
metrics.json
limit=1000 rejected=1682 accepted=662 exact-blob=saved rejected-file=absent
Получится label-part.png на 662 байта и label-export.json. Для полной этикетки зафиксирован отказ: 1682 больше 1000, поэтому label-rejected.png в новой папке примера не создаётся. Функция не пытается молча обрезать картинку или ухудшать качество: фрагмент подготовлен вызывающим кодом заранее, а полный вариант остаётся исходником. Читатель видит причину каждого решения.
JSON можно открыть текстовым редактором: в нём лимит, результат проверки двух кандидатов, имя принятого файла и его SHA256. Контрольная сумма связывает проверенный blob с файлом и помогает обнаружить случайную подмену; она не является подписью автора. Функция проверяет полноту записи, но этот учебный пример не реализует атомарную публикацию при параллельных запросах. При отказе он также не удаляет чей-либо старый файл с тем же именем.
В этом запуске нет HTTP-отправки и нет обработки пользовательской загрузки: работа идёт с собственным файлом. В реальной форме массив $_FILES не является ни путём, ни Imagick. После проверки error используют tmp_name как путь к временному файлу; size относится к принятой загрузке, а не к будущему преобразованному результату. Эти шаги и допустимые типы разобраны в главе о загрузках. getimagesize не следует использовать как самостоятельное доказательство безопасности файла.
Заданный предел касается байтов самого изображения. Multipart-обёртка HTTP или base64 добавят свои данные; если внешний сервис ограничивает весь запрос, учитывайте его формат отдельно. Получение blob требует памяти и времени кодера; небольшой размер сжатого файла не означает маленький растр. Для крупных входов нужны пределы геометрии и ресурсов до дорогой обработки. Не кодируйте картинку повторно ради каждой строки отчёта.
Полный контракт getImageSize, границы и миграция имени
Imagick::getImageSize: полный контракт старого имени
Imagick::getImageSize(): intgetImageSize не принимает аргументов и возвращает int — длину текущего изображения в байтах. Это полный смысл короткой официальной страницы: в ней нет примера и отдельного раздела ошибок. Метод помечен deprecated с Imagick 3.4.4; официально рекомендуемая замена — getImageLength. Доступность из официального каталога: PECL imagick 2, PECL imagick 3.
| Вопрос | Ответ |
|---|---|
| Что передать? | Ничего: пустые круглые скобки. Изображение уже должно находиться в объекте Imagick. |
| Что возвращается? | Одно целое число байтов текущего file/blob, а не массив ширины и высоты. |
| Меняет ли вызов картинку? | Это чтение сведений. Он не масштабирует растр и не кодирует будущий экспорт только ради ответа. |
| Какое имя использовать в новом коде? | getImageLength; полная текущая карточка уже есть в главе о превью и размере файла. |
| Означает deprecated, что метод отсутствует? | Нет. В нашей Imagick 3.8.1 с ImageMagick 7.1.1-46 getImageSize доступен и реально выполнен. В будущем или другой сборке доступность проверяют отдельно. |
$legacyBytes = $image->getImageSize(); // Историческое имя.
$bytes = $image->getImageLength(); // Текущее рекомендуемое имя.В исследованном wrapper Imagick 3.8.1 ветка getImageSize для ImageMagick 7 вызывает MagickGetImageLength, как и нынешний метод. Ветка для ImageMagick 6 использует старый MagickGetImageSize; она здесь не запускалась. MagickGetImageLength обращается к GetBlobSize: значение связано с состоянием файла или потока, а не с оценкой будущего сжатого результата. Ноль после изменения растра не доказывает, что готовый файл будет пустым.
Реальный запуск текущей сборки дал ImagickException для getImageSize и getImageLength на пустом Imagick, а также при попытке открыть отсутствующий PNG. Успешный старый вызов не выдал предупреждения в нашей пробе; это наблюдение сборки, которое не отменяет пометку deprecated в документации. Ошибки не подавляются @. Код обработчика должен различать отсутствие метода, отсутствие изображения и сбой чтения файла; основы исключений разобраны отдельно.
Не путайте этот метод со свободной функцией PHP getimagesize($path). Она принимает путь и возвращает массив сведений о геометрии и типе либо false при невозможности определить их; элементы 0 и 1 — ширина и высота. Она не отвечает на вопрос о числе байтов. Для существующего файла используется filesize, для уже полученной бинарной строки — strlen. Подробная текущая карточка: getImageLength и реальный размер сохранённого файла.
Запуск и упражнения с ответами
Распакуйте example.php, label.png.b64 и size-fixture.php рядом и запустите php example.php. Проверенная среда: PHP 8.5.11, Imagick 3.8.1, ImageMagick 7.1.1-46 Q16 на Windows. В первом и третьем примерах реально вызывается deprecated getImageSize для сравнения. Второй и четвёртый используют текущий API без лишнего вызова старого метода. Среда ImageMagick 6 не запускалась.
Упражнение 1: у PNG и JPEG одинаковые 400×320, можно ли принять оба по одному измерению байтов? Нет: они занимают 1682 и 11950 байт. Упражнение 2: getter вернул 0 после crop; означает ли это пустое изображение? Нет: у нас это непустые 200×160 до кодирования, затем PNG на 662 байта. Упражнение 3: что записать после успешного сравнения strlen($blob) с лимитом? Тот же $blob, чтобы записанные байты соответствовали решению. Упражнение 4: заменяет ли getimagesize метод getImageSize? Нет: первая функция возвращает массив геометрии по пути, второй метод — число байтов текущего состояния объекта. Упражнение 5: что делать, если требуется сохранить полную этикетку, а она не проходит лимит? Вернуть понятный отказ или согласованно выбрать другой экспорт; обрезка меняет содержание и не является универсальным способом сжатия.
Вспомогательный PHP из каждого архива
<?php
declare(strict_types=1);
function szRestore():void {
$hashes=json_decode('{"label.png":"e6fba16c63ce2c38269669d47d5263eb455133f747e4ba08cb9be261ea5055f1"}',true,512,JSON_THROW_ON_ERROR);
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('Input missing or changed');}
if(!method_exists(Imagick::class,'getImageLength'))throw new RuntimeException('This example requires getImageLength');
}
function szHash(Imagick $im,string $map='RGB'):string{return hash('sha256',json_encode($im->exportImagePixels(0,0,$im->getImageWidth(),$im->getImageHeight(),$map,Imagick::PIXEL_SHORT),JSON_THROW_ON_ERROR));}
function szState(Imagick $im):array{return ['geometry'=>[$im->getImageWidth(),$im->getImageHeight()],'format'=>$im->getImageFormat(),'RGB16_sha256'=>szHash($im)];}
function szPNG(Imagick $im):string {$im->setImageFormat('png');$im->setImageDepth(8);$im->setOption('png:bit-depth','8');$im->setOption('png:color-type','2');$im->setOption('png:exclude-chunk','all');return $im->getImageBlob();}
function szFile(string $name):array {
$path=__DIR__.'/'.$name;clearstatcache(true,$path);$bytes=filesize($path);$dimensions=getimagesize($path);
if($bytes===false||$dimensions===false)throw new RuntimeException('Cannot inspect output');
return ['filename'=>$name,'sha256'=>hash_file('sha256',$path),'bytes'=>$bytes,'geometry'=>[$dimensions[0],$dimensions[1]],'mime'=>$dimensions['mime'],'state'=>szState(new Imagick($path))];
}
function szWriteBlob(string $blob,string $name):array {
$written=file_put_contents(__DIR__.'/'.$name,$blob);
if($written===false||$written!==strlen($blob))throw new RuntimeException('Incomplete write');
$file=szFile($name);if($file['sha256']!==hash('sha256',$blob))throw new RuntimeException('Written bytes differ');return $file;
}
function szView(Imagick $im):Imagick {
$view=new Imagick();$view->newImage(400,320,'#dce4e6','png');$x=intdiv(400-$im->getImageWidth(),2);$y=intdiv(320-$im->getImageHeight(),2);
$view->compositeImage($im,Imagick::COMPOSITE_COPY,$x,$y);return $view;
}
function szImage(Imagick $im,string $name):array {
$copy=clone $im;$blob=szPNG($copy);$saved=szWriteBlob($blob,$name);$read=new Imagick(__DIR__.'/'.$name);
return ['geometry'=>[$im->getImageWidth(),$im->getImageHeight()],'RGB16_sha256'=>szHash($im),'RGBA16_sha256'=>szHash($im,'RGBA'),'encoded_png'=>['filename'=>$name,'RGB16_sha256'=>szHash($read),'RGBA16_sha256'=>szHash($read,'RGBA')],'display_basis'=>'Actual readback, natural size centered on gray canvas; no scaling'];
}
function szCompare(array $images,string $name):array {$view=new Imagick();$view->newImage(400*count($images),320,'white','png');$rects=[];foreach($images as $i=>$im){$view->compositeImage($im,Imagick::COMPOSITE_COPY,400*$i,0);$rects[]=['x'=>400*$i,'y'=>0,'width'=>400,'height'=>320];}$copy=clone $view;szWriteBlob(szPNG($copy),$name);return $rects;}
function szTry(callable $fn):array{try{$v=$fn();return ['type'=>get_debug_type($v),'value'=>$v];}catch(Throwable $e){return ['error'=>['class'=>get_class($e),'message'=>$e->getMessage()]];}}
function szDiagnostic(string $id,array $methods,array $data):void {
$target=in_array('getImageSize',$methods,true);
$doc=['schema'=>'aen-legacy-image-size-program-diagnostics-v1','example_id'=>$id,'runtime'=>['php'=>PHP_VERSION,'imagick'=>phpversion('imagick'),'imagemagick'=>Imagick::getVersion()],'legacy_available'=>method_exists(Imagick::class,'getImageSize'),'legacy_executed'=>$target,'target_method_executed'=>$target,'legacy_runtime_executed'=>false,'current_runtime_executed'=>true,'current_available'=>method_exists(Imagick::class,'getImageLength'),'invoked_methods'=>$methods,'executed_api'=>$target?'getImageSize':'getImageLength']+$data;
if(file_put_contents(__DIR__.'/metrics.json',json_encode($doc,JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR)."\n")===false)throw new RuntimeException('Cannot save metrics');
}
szRestore восстанавливает собственный вход; szPNG явно кодирует PNG RGB8; szWriteBlob записывает уже полученную строку и проверяет фактические байты; szFile читает файл для независимой геометрии и хеша пикселей. szView размещает изображение в натуральном размере на отдельном холсте просмотра, не меняя экспорт. Основные getter и решение о лимите видны непосредственно в программах.
Вопросы разработчиков, задающие практические ситуации
Обсуждения используются как источники реальных затруднений. Наши программы и объяснения написаны заново; нормативные свойства проверены по PHP.net и исходникам, поведение примеров — настоящим запуском.
Imagick knowing the image size? (file size): Нужен размер после изменения изображения, но непонятно, требуется ли промежуточный файл. Измеряем strlen готового blob в памяти; затем записываем именно эту строку и сверяем фактические байты.
what does PHP.getimagesize actually return: Название getimagesize создаёт путаницу между одним числом и массивом сведений. Разбираем элементы 0/1, путь как аргумент, отличие свободной PHP-функции от метода Imagick и от filesize.
imagick getImageLength not working after crop image: После crop требуется отправить фрагмент в ограничение байтов, но известная длина сбрасывается. Реально вырезаем 200×160, наблюдаем 0 до кодирования и 662 после него, сохраняем ту же проверенную бинарную строку.
How to get JPG file length in bytes AFTER resizing and compressing the image with Imagick in PHP?: После изменения геометрии и JPEG-quality getter возвращает 0, а нужен предел размера миниатюры. Показываем отдельные стадии растра и кодирования; размер решения берём из единожды полученного blob, не прогнозируем по getter.
Imagick causing images to become larger: Повторное чтение и кодирование увеличивает полученный файл, хотя существенной правки не было. Отделяем исходные байты от нового экспорта; не обещаем сохранение размера между кодерами и не кодируем снова после решения о лимите.
Accessing info about file uploaded in PHP and modifying with GD: Массив $_FILES передают в функции, ожидающие путь или декодированное изображение. Объясняем различие массива загрузки, tmp_name, текущего объекта и выходного blob; полный HTTP-сценарий оставляем связанному разделу uploads.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
Imagick::getImageSizeРазличить байты, геометрию и ещё не закодированный результат
PECL imagick 2, PECL imagick 3 · imagick
Imagick::getImageSize(): intImagick::getImageSize: полный контракт старого имени
Imagick::getImageSize(): intgetImageSize не принимает аргументов и возвращает int — длину текущего изображения в байтах. Это полный смысл короткой официальной страницы: в ней нет примера и отдельного раздела ошибок. Метод помечен deprecated с Imagick 3.4.4; официально рекомендуемая замена — getImageLength. Доступность из официального каталога: PECL imagick 2, PECL imagick 3.
| Вопрос | Ответ |
|---|---|
| Что передать? | Ничего: пустые круглые скобки. Изображение уже должно находиться в объекте Imagick. |
| Что возвращается? | Одно целое число байтов текущего file/blob, а не массив ширины и высоты. |
| Меняет ли вызов картинку? | Это чтение сведений. Он не масштабирует растр и не кодирует будущий экспорт только ради ответа. |
| Какое имя использовать в новом коде? | getImageLength; полная текущая карточка уже есть в главе о превью и размере файла. |
| Означает deprecated, что метод отсутствует? | Нет. В нашей Imagick 3.8.1 с ImageMagick 7.1.1-46 getImageSize доступен и реально выполнен. В будущем или другой сборке доступность проверяют отдельно. |
$legacyBytes = $image->getImageSize(); // Историческое имя.
$bytes = $image->getImageLength(); // Текущее рекомендуемое имя.В исследованном wrapper Imagick 3.8.1 ветка getImageSize для ImageMagick 7 вызывает MagickGetImageLength, как и нынешний метод. Ветка для ImageMagick 6 использует старый MagickGetImageSize; она здесь не запускалась. MagickGetImageLength обращается к GetBlobSize: значение связано с состоянием файла или потока, а не с оценкой будущего сжатого результата. Ноль после изменения растра не доказывает, что готовый файл будет пустым.
Реальный запуск текущей сборки дал ImagickException для getImageSize и getImageLength на пустом Imagick, а также при попытке открыть отсутствующий PNG. Успешный старый вызов не выдал предупреждения в нашей пробе; это наблюдение сборки, которое не отменяет пометку deprecated в документации. Ошибки не подавляются @. Код обработчика должен различать отсутствие метода, отсутствие изображения и сбой чтения файла; основы исключений разобраны отдельно.
Не путайте этот метод со свободной функцией PHP getimagesize($path). Она принимает путь и возвращает массив сведений о геометрии и типе либо false при невозможности определить их; элементы 0 и 1 — ширина и высота. Она не отвечает на вопрос о числе байтов. Для существующего файла используется filesize, для уже полученной бинарной строки — strlen. Подробная текущая карточка: getImageLength и реальный размер сохранённого файла.
Сравнить старое имя, текущее имя и реальные байты файла
Исходный label.png занимает 1682 байта и имеет геометрию 400×320. Оба метода Imagick вернули 1682; PHP getimagesize вернул массив со стороной 400 и стороной 320. Старый метод действительно доступен и вызван в этой сборке, хотя документация рекомендует getImageLength.
<?php
declare(strict_types=1);
require __DIR__ . '/size-fixture.php';
szRestore();
$source = new Imagick(__DIR__ . '/label.png');
$sourceBefore = szState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/label.png');
if (!method_exists($source, 'getImageSize')) {
throw new RuntimeException('This historical comparison requires getImageSize');
}
$oldBytes = $source->getImageSize();
$currentBytes = $source->getImageLength();
$dimensions = getimagesize(__DIR__ . '/label.png');
clearstatcache(true, __DIR__ . '/label.png');
$diskBytes = filesize(__DIR__ . '/label.png');
$file = szFile('label.png');
$view = szView($source);
$images = ['source'=>szImage($view,'first-source8.png')];
$rects = szCompare([$view],'image-size-first.png');
szDiagnostic('image-size-first',['getImageSize','getImageLength'],[
'legacy_bytes'=>$oldBytes,'current_bytes'=>$currentBytes,'disk_bytes'=>$diskBytes,'php_getimagesize'=>$dimensions,'file'=>$file,'units'=>['bytes'=>1682,'width_pixels'=>400,'height_pixels'=>320,'pixel_count'=>128000],
'images'=>$images,'panel_keys'=>['source'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>szState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>szState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/label.png')===$sourceHash,
'checks'=>['legacy_current_agree'=>$oldBytes===$currentBytes,'getters_match_disk'=>$currentBytes===$diskBytes,'known_input_bytes'=>$diskBytes===1682,'geometry_is_separate'=>$dimensions[0]===400&&$dimensions[1]===320,'method_returns_int'=>is_int($oldBytes)]
]);
echo "image-size-first.png\nfirst-source8.png\nmetrics.json\ngetImageSize=1682 getImageLength=1682 filesize=1682 geometry=400x320\n";
Исходный label.png занимает 1682 байта и имеет геометрию 400×320. Оба метода Imagick вернули 1682; PHP getimagesize вернул массив со стороной 400 и стороной 320. Старый метод действительно доступен и вызван в этой сборке, хотя документация рекомендует getImageLength. Архив содержит example.php, label.png.b64 и size-fixture.php. Распакуйте рядом и выполните php example.php; обычный label.png восстановится автоматически. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Значения байтов относятся к этому исходнику и кодерам.
Ожидаемый вывод настоящего запуска
image-size-first.png
first-source8.png
metrics.json
getImageSize=1682 getImageLength=1682 filesize=1682 geometry=400x320
Измерить вырезанную часть только после кодирования
Копия вырезана до 200×160; оба getter до кодирования вернули 0. После getImageBlob получены 662 байта, и именно эта строка записана в label-cropped.png. Исходный label.png не изменился. На иллюстрации фрагмент показан без увеличения по центру серого холста.
<?php
declare(strict_types=1);
require __DIR__ . '/size-fixture.php';
szRestore();
$source = new Imagick(__DIR__ . '/label.png');
$sourceBefore = szState($source);
$sourceHash = hash_file('sha256', __DIR__ . '/label.png');
$cropped = clone $source;
$cropped->cropImage(200,160,20,20);
$cropped->setImagePage(0,0,0,0);
$beforeEncoding = [
'state'=>szState($cropped),
'legacy_bytes'=>$cropped->getImageSize(),
'current_bytes'=>$cropped->getImageLength(),
];
$blob = szPNG($cropped);
$afterEncoding = [
'state'=>szState($cropped),
'legacy_bytes'=>$cropped->getImageSize(),
'current_bytes'=>$cropped->getImageLength(),
];
$saved = szWriteBlob($blob,'label-cropped.png');
$read = new Imagick(__DIR__.'/label-cropped.png');
$errors = [
'empty_legacy'=>szTry(fn()=>(new Imagick())->getImageSize()),
'empty_current'=>szTry(fn()=>(new Imagick())->getImageLength()),
'missing_input'=>szTry(fn()=>new Imagick(__DIR__.'/missing.png')),
];
$views = [szView($source),szView($read)];
$images = ['source'=>szImage($views[0],'memory-source8.png'),'crop'=>szImage($views[1],'memory-crop8.png')];
$rects = szCompare($views,'image-size-memory.png');
szDiagnostic('image-size-memory',['getImageSize','getImageLength','cropImage','getImageBlob'],[
'crop'=>['width'=>200,'height'=>160,'x'=>20,'y'=>20],'before_encoding'=>$beforeEncoding,'after_encoding'=>$afterEncoding,'blob_bytes'=>strlen($blob),'blob_sha256'=>hash('sha256',$blob),'saved'=>$saved,'readback'=>szState($read),'errors'=>$errors,'crop_display'=>['x'=>100,'y'=>80,'width'=>200,'height'=>160,'scale'=>1],
'images'=>$images,'panel_keys'=>['source','crop'],'panel_geometry'=>$rects,'source_before'=>$sourceBefore,'source_after'=>szState($source),'source_sha256'=>$sourceHash,'source_unchanged'=>szState($source)===$sourceBefore&&hash_file('sha256',__DIR__.'/label.png')===$sourceHash,
'checks'=>['geometry_changed_before_encoding'=>$beforeEncoding['state']['geometry']===[200,160],'both_before_zero'=>$beforeEncoding['legacy_bytes']===0&&$beforeEncoding['current_bytes']===0,'both_after_actual'=>$afterEncoding['legacy_bytes']===662&&$afterEncoding['current_bytes']===662,'same_encoded_bytes'=>strlen($blob)===$saved['bytes']&&hash('sha256',$blob)===$saved['sha256'],'crop_pixels_roundtrip'=>$afterEncoding['state']['RGB16_sha256']===szHash($read),'empty_legacy_caught'=>($errors['empty_legacy']['error']['class']??null)==='ImagickException','empty_current_caught'=>($errors['empty_current']['error']['class']??null)==='ImagickException','missing_caught'=>($errors['missing_input']['error']['class']??null)==='ImagickException']
]);
echo "image-size-memory.png\nmemory-source8.png\nmemory-crop8.png\nlabel-cropped.png\nmetrics.json\ncrop=200x160 before-encoding=0 after-encoding=662 written=662 source=unchanged\n";
Копия вырезана до 200×160; оба getter до кодирования вернули 0. После getImageBlob получены 662 байта, и именно эта строка записана в label-cropped.png. Исходный label.png не изменился. На иллюстрации фрагмент показан без увеличения по центру серого холста. Архив содержит example.php, label.png.b64 и size-fixture.php. Распакуйте рядом и выполните php example.php; обычный label.png восстановится автоматически. Проверенная среда: PHP 8.5.11 / Imagick 3.8.1 / ImageMagick 7.1.1-46 Q16, Windows. Значения байтов относятся к этому исходнику и кодерам.
Ожидаемый вывод настоящего запуска
image-size-memory.png
memory-source8.png
memory-crop8.png
label-cropped.png
metrics.json
crop=200x160 before-encoding=0 after-encoding=662 written=662 source=unchanged
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


