/
githubmirror
/
symfony
Обзор
Документация
Войти
/
githubmirror
/
symfony
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
8.2
src/Symfony/Component/Console/Terminal/Image/ITerm2Protocol.php
104 строки
3 KB
Nicolas Grekas
[Console] Fix terminator handling in the image protocols
08 авг 2026, 12:24
08 авг 2026, 12:24
4a2185b
Код
Авторство
О чём код?
<?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Console\Terminal\Image; /** * Handles the iTerm2 Inline Images Protocol (OSC 1337). * * The iTerm2 protocol uses Operating System Command (OSC) sequences: * - Start: ESC ] 1337 ; File= (0x1B 0x5D 0x31 0x33 0x33 0x37 0x3B 0x46 0x69 0x6C 0x65 0x3D) * - End: BEL (0x07) or ESC \ (0x1B 0x5C) * * Format: ESC]1337;File=[arguments]:[base64 data]BEL * * @see https://iterm2.com/documentation-images.html * * @author Robin Chalas <robin.chalas@gmail.com> * * @internal */ final class ITerm2Protocol implements ImageProtocolInterface { public const OSC_START = "\x1b]1337;File="; public const BEL = "\x07"; public const ST = "\x1b\\"; public function detectPastedImage(string $data): bool { return str_contains($data, self::OSC_START); } public function decode(string $data): array { if (false === $start = strpos($data, self::OSC_START)) { return ['data' => '', 'format' => null]; } // OSC accepts either terminator, so the sequence ends at the first one of them $terminators = array_filter([strpos($data, self::BEL, $start), strpos($data, self::ST, $start)], \is_int(...)); if (!$terminators) { return ['data' => '', 'format' => null]; } $end = min($terminators); $content = substr($data, $start + \strlen(self::OSC_START), $end - $start - \strlen(self::OSC_START)); if (false === $colonPos = strpos($content, ':')) { return ['data' => '', 'format' => null]; } $payload = substr($content, $colonPos + 1); if (false === $decodedData = base64_decode($payload, true)) { return ['data' => '', 'format' => null]; } $format = $this->detectImageFormat($decodedData); return ['data' => $decodedData, 'format' => $format]; } public function encode(string $imageData, ?int $maxWidth = null): string { $arguments = [ 'inline=1', ]; if ($maxWidth) { $arguments[] = \sprintf('width=%d', $maxWidth); } $arguments[] = 'preserveAspectRatio=1'; $argumentString = implode(';', $arguments); $payload = base64_encode($imageData); return self::OSC_START.$argumentString.':'.$payload.self::BEL; } public function getName(): string { return 'iterm2'; } private function detectImageFormat(string $data): ?string { return match (true) { str_starts_with($data, "\x89PNG\r\n\x1a\n") => 'png', str_starts_with($data, "\xFF\xD8\xFF") => 'jpg', str_starts_with($data, 'GIF87a'), str_starts_with($data, 'GIF89a') => 'gif', str_starts_with($data, 'RIFF') && 'WEBP' === substr($data, 8, 4) => 'webp', default => null, }; } }