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