В мире разработки часто возникает потребность в работе с командной строкой — будь то выполнение системных команд, обработка их вывода или работа с различными кодировками. Столкнувшись с такими задачами, программисты часто начинают искать готовые решения, чтобы сэкономить время и избежать повторения однотипного кода.
Именно для таких случаев была разработана библиотека PhpFluentConsole — простое и гибкое решение для работы с командной строкой, с поддержкой кодировок и множеством полезных фич для работы с выводом команд.
Зачем нужна эта библиотека?
PhpFluentConsole не заменяет существующие библиотеки, а выступает как легковесная основа для гибкого построения CLI-запросов. Её цель — упростить интеграцию системных команд без необходимости изучать объёмную документацию или вникать в сложный API.
Основная цель библиотеки — упрощение и автоматизация выполнения команд, а также обработка вывода, что делает её удобной для разработчиков, которые хотят создавать свои собственные решения на основе этой библиотеки.
Преимущества использования
Гибкость и удобство:
Библиотека поддерживает текучий интерфейс для построения команд, что делает код максимально читаемым и лаконичным.
Пример:
$cli = new ConsoleRunner() ->setCommand('echo') ->addKey('Hello, World!')
Поддержка кодировок:
Для работы с кириллицей и другими символами, библиотека включает поддержку различных кодировок, таких как CP866, UTF-8, CP1251, и других. Это особенно важно при работе в windows-среде, где часто возникают проблемы с выводом текста в стандартных кодировках, что так же может затруднить обработку вывода с помощью регулярных выражений.
Пример:
$cli = new ConsoleRunner() ->setCommand('dir') ->encoding('866')
Обработка ошибок и кодов возврата:
Библиотека позволяет получать код возврата после выполнения команды и искать ошибки в выводе с помощью регулярных выражений. Это важно, если вам нужно удостовериться, что команда завершилась успешно или отловить ошибку в выводе.
Пример:
if (!$cli->run()) { echo "Ошибка выполнения команды!" . $cli->getReturnCode(); }
Поиск совпадений по паттернам:
Вы можете искать совпадения в выводе команды, используя регулярные выражения. Это полезно, если нужно извлечь конкретную информацию из вывода команд, например, лог-файлов или диагностики системы.
Пример:
if ($cli->run()) { $matches = $cli->getMatches('/Error/'); print_r($matches); }
Стандартный вывод:
Если нам просто нужно получить массив строк.
Пример:
if ($cli->run()) { print_r($cli->getOutput()); }
Установка
composer require mikhailovlab/php-fluent-console
Описание методов
Устанавливает команду для выполнения.
public function setCommand(string $cmd): self
Добавляет аргумент или часть команды.
public function addKey(string $key): self
Устанавливает кодировку для вывода. Например, '866' для отображения кириллицы в Windows.
public function encoding(?string $encoding = null): self
Устанавливает флаг, что нужно выполнить обратную конвертацию кодировки. Метод полезен для возврата вывода в исходной кодировке для работы с cmd.
public function decoding(): self
Возвращает текущую команду.
public function getCommand(): string
Выполняет команду и возвращает true, если код возврата равен 0.
public function run(): bool
Возвращает вывод после выполнения команды.
public function getOutput(): array
Возвращает код возврата выполнения команды.
public function getReturnCode(): int
Проверяет вывод на наличие ошибки по регулярному выражению.
public function hasError(string $pattern): bool
Возвращает все строки вывода, совпавшие с регулярным выражением.
public function getMatches(string|array $patterns): array
Примеры
Проверять функционал будем на примере фреймворка Laravel 11, но так же можно использовать любой другой, это непринципиально:
Пример 1: Получаем IP адрес в операционной системе windows
$cli = new ConsoleRunner() ->setCommand('ipconfig') ->addKey('/all') ->encoding('866'); //ожидаем вывод с кириллицей if ($cli->run()) { dd($cli->getOutput()); }
Вывод:
array:59 [▼ // app\Http\Controllers\TestController.php:21 0 => "" 1 => "Настройка протокола IP для Windows" 2 => "" 3 => " Имя компьютера . . . . . . . . . : DESKTOP-HRTB4N9" 4 => " Основной DNS-суффикс . . . . . . :" 5 => " Тип узла. . . . . . . . . . . . . : Гибридный" 6 => " IP-маршрутизация включена . . . . : Нет" 7 => " WINS-прокси включен . . . . . . . : Нет" 8 => " Порядок просмотра суффиксов DNS . : lan" 9 => "" 10 => "Адаптер Ethernet Ethernet 2:" ...
Кириллица отображается корректно, можно двигаться дальше.
Пример 2: Получаем список контейнеров с электронными подписями
$cli = new ConsoleRunner() ->setCommand('csptest') ->addKey('-keyset') ->addKey('-enum_cont') ->addKey('-verifycontext') ->addKey('-fqcn'); if ($cli->run()) { dd($cli->getMatches('#\\\\.*#')); } $pattern = '/\[ErrorCode:\s*(0x[0-9A-Fa-f]+)\]/'; dd('Error code: ' . $cli->getMatches($pattern)[0]);
Вывод:
array:1 [▼ // app\Http\Controllers\TestController.php:23 0 => "\\.\REGISTRY\d58fe6c13-d917-2a53-8e9c-8c4b8158220-test" ]
В принципе работает, но если мы собираемся разрабатывать свою библиотеку, такой подход может показаться избыточным.
Пример 3: Расширяем базовый класс
Мы можем наследоваться от базового класса ConsoleRunner и вместо указания методов через addKey, вызывать их динамически, используя магический метод __call. Как правило, в консольных утилитах мы можем получить список всех доступных методов и аргументов используя ключ -help и добавить их в массив, что бы исключить ошибки, т.к. при несовпадении будет выброшено исключение.
class customRunner extends ConsoleRunner { private $methods = [ 'keyset', 'enum_cont', 'verifycontext', 'fqcn' ]; public function __call(string $name, array $arguments): self { if (in_array($name, $this->methods)) { $this->addKey('-' . $name); if (!empty($arguments)) { foreach ($arguments as $arg) { $this->addKey((string) $arg); } } return $this; } throw new \BadMethodCallException("Method $name is not supported"); } } try{ $cli = new customRunner() ->setCommand('csptest') ->keyset() ->enum_cont() ->verifycontext() ->fqcn(); if ($cli->run()) { dd($cli->getMatches('#\\\\.*#')); } $pattern = '/\[ErrorCode:\s*(0x[0-9A-Fa-f]+)\]/'; dd('Error code: ' . $cli->getMatches($pattern)[0]); }catch (Exception $e){ dd($e->getMessage()); }
Вывод:
array:1 [▼ // app\Http\Controllers\TestController.php:23 0 => "\\.\REGISTRY\d58fe6c13-d917-2a53-8e9c-8c4b8158220-test" ]
Мы можем перенести логику и обработку вывода в отдельные методы, что бы сделать код еще более лаконичным.
try{ $containers = new customRunner() ->getContainers() ->run(); dd($containers); }catch (Exception $e){ dd($e->getMessage()); }
Таким образом мы можем наследоваться от базового класса и создавать свои классы-обертки, в которых будем описывать методы и обрабатывать вывод.
Заключение
PhpFluentConsole — это удобный и гибкий инструмент для работы с командной строкой. Он позволяет строить команды через простой и понятный интерфейс, поддерживает работу с кодировками, предоставляет возможности для обработки ошибок и извлечения данных из вывода команд. Библиотека является отличной основой для создания более сложных решений или даже для разработки других библиотек на её основе, таких как CryptoProBuilder, о которой я расскажу в следующей статье.
Если у вас есть вопросы или предложения по улучшению этой библиотеки, вы всегда можете обратиться к репозиторию на GitHub, где вы сможете внести свой вклад или создать issue для обсуждения новых возможностей.
