Статьи

PHP в командной строке — часть 1 статьи

Параметры разбора

Хотя на первый взгляд может показаться, что написать функцию для разбора опций не так уж и сложно, но зачем вам это? PEAR :: Console_Getopt предоставляет готовое решение и решает проблемы с $argv vs. $_SERVER['argv'] вы видели ранее.

Обратите внимание, что версия Console_Getopt я здесь использовал, была 1.2. См. Начало работы с PEAR, если вам интересно, как его установить. Имейте в Console_Getopt что удаление Console_Getopt — плохая идея, поскольку от этого зависит сам менеджер пакетов. Если вам нужно обновить свою версию, используйте:

$ pear upgrade Console_Getopt-stable

PEAR :: Console_Getopt предоставляет три открытых метода, каждый из которых вызывается статически:

1. array Console_Getopt::readPHPArgv()

Массив, возвращаемый из readPHPArgv() совпадает с массивом $argv , но Console_Getopt обеспечивает лучшую защиту от различных версий PHP. Если он не может получить доступ к аргументам командной строки (например, если они недоступны, например, в двоичном файле CGI, где register_argc_argv=Off ), он возвращает объект ошибки PEAR.

2. array Console_Getopt::getOpt(array argv, [string short_opts], [array long_opts])

Метод getOpt() принимает массив аргументов командной строки и анализирует их в массив опций и аргументов. Он ожидает, что первым элементом argv будет имя исполняемого скрипта, и он предназначен для использования при выполнении следующих типов скриптов:

$ php some_script.php

Строка ‘ short_opts ‘ определяет короткие опции, которые может предоставить пользователь, за которыми следуют символы, которые идентифицируют данные опции. Это позволяет использовать два специальных маркера в строке:
« : » указывает, что за предыдущей буквой должно следовать «значение», а « :: » говорит, что за предыдущей опцией может следовать значение. Проще всего это увидеть на примере.

Если $short_opts = 'lt' , возможны следующие командные строки (от getOpt()) ошибок не будет:

$ php some_script.php -lt $ php some_script.php -tl $ php some_script.php -l -t $ php some_script.php -t -l $ php some_script.php -l $ php some_script.php -t -t -l -l $ php some_script.php -t $ php some_script.php

Установка $short_opts = 'lt:' означает, что за параметром ‘t’ должен следовать хотя бы один символ (не пробел), который будет его значением. Посмотрите на этот пример:

$ php some_script.php -ltv

Здесь 't' = 'v' .

$ php some_script.php -tvalue -l

Теперь 't' = 'value' .

$ php some_script.php -tl

Здесь 't' = 'l' (l не является опцией в этом случае).

Наконец, установка $short_opts = 'lt::' означает, что ‘t’ может иметь необязательное значение (все, что следует за ним, до следующего пробела). Обратите внимание, что я могу разместить дополнительные параметры после двоеточий в строке коротких параметров. Например, 'lt:o::B' .

Это может показаться немного загадочным, но указание такой короткой строки опций является довольно стандартным для многих языков, используемых в UNIX, от C до Python. Как только вы привыкнете к этому, этот метод предоставляет полезный механизм для получения максимальной отдачи от аргументов командной строки с минимальными усилиями.

long_opts указываются аналогично short_opts, но вместо строки используется массив; также маркер « : » заменяется знаком « = чтобы определить, когда следует указывать значения. Чтобы разрешить длинные опции ‘ --user=harryf --pass=secret ‘, мне понадобится такой массив:

$long_opts = array ( 'user=', 'pass=', );

В этом случае оба параметра 'user' и 'pass' требуют значения. Если я опускаю знак равенства, никакое значение не допускается, а использование « == » позволяет пользователю указать необязательное значение.

Массив, возвращаемый из getOpt() всегда имеет два элемента в своем первом порядке; первый содержит параметры командной строки, а второй содержит аргументы. Мы рассмотрим структуру более подробно в данный момент.

Последний метод, предоставленный Console_Getopt :

3. array Console_Getopt::getOpt2(array argv, [string short_opts], [array long_opts])

Этот метод почти такой же, как getOpt() , за исключением того, что он ожидает, что первый элемент в массиве argv будет реальным аргументом, а не именем исполняемого скрипта. Другими словами, вы использовали бы его при выполнении сценария, такого как:

$ some_script.php -tl

Вот простой пример PEAR :: Console_Getopt в действии:

<?php // Include PEAR::Console_Getopt require_once 'Console/Getopt.php';

// Определяем коды выхода для ошибок
DEFINE ( ​​’NO_ARGS’, 10);
DEFINE ( ​​’INVALID_OPTION’, 11);

// Чтение входящих аргументов — так же, как $ argv
$ args = Console_Getopt :: readPHPArgv ();

// Убедитесь, что мы их получили (для двоичных файлов без CLI)
if (PEAR :: isError ($ args)) {
FWRITE (STDERR, $ args-> GetMessage () «п».);
Выход (NO_ARGS);
}

// Короткие опции
$ short_opts = ‘lt:’;

// Длинные опции
$ long_opts = array (
‘Пользователь =’,
‘Проходят =’,
);

// Преобразовать аргументы в опции — проверить первый аргумент
if (realpath ($ _ SERVER [‘argv’] [0]) == __FILE__) {
$ options = Console_Getopt :: getOpt ($ args, $ short_opts, $ long_opts);
} еще {
$ options = Console_Getopt :: getOpt2 ($ args, $ short_opts, $ long_opts);
}

// Проверьте правильность параметров
if (PEAR :: isError ($ options)) {
FWRITE (STDERR, $ options-> GetMessage () «п».);
Выход (INVALID_OPTION);
}

print_r ($ вариантов);
?>

Если мы вызовем этот скрипт так:

$ php getopts.php -ltr --user=harryf --pass=secret arg1 arg2

Вывод из print_r () выглядит следующим образом:

Array ( [0] => Array ( [0] => Array ( [0] => l [1] => )

[1] => Массив
(
[0] => т
[1] => г
)

[2] => Массив
(
[0] => —user
[1] => гарриф
)

[3] => Массив
(
[0] => —pass
[1] => секрет
)

)

[1] => Массив
(
[0] => arg1
[1] => arg2
)

)

Массив параметров всегда содержит два элемента первого порядка, первый из которых содержит другой массив, представляющий каждый параметр командной строки. Второй элемент содержит массив аргументов . Если вы оглянетесь назад на то, как был вызван скрипт, вы сможете увидеть взаимосвязь.

Вы можете увидеть, как PEAR :: Console_Getopt может использоваться для анализа аргументов и параметров, используемых утилитой UNIX ‘ls’, при выполнении следующим образом:

$ ls -ltr --width=80 /home/harryf/scripts/

Если вы проанализировали приведенную выше командную строку с Console_Getopt , у вас будет массив параметров, таких как:

Array ( [0] => Array ( [0] => Array ( [0] => l [1] => )

[1] => Массив
(
[0] => т
[1] =>
)

[2] => Массив
(
[0] => г
[1] =>
)

[3] => Массив
(
[0] => — ширина
[1] => 80
)
)

[1] => Массив
(
[0] => / home / harryf / scripts /
)

)

Теперь вы можете повторно реализовать ls в PHP, если у вас есть бесконечные часы в ваших руках.

Совместимость

Как я упоминал ранее в этой статье, можно использовать двоичный файл PHP CGI более или менее так же, как двоичный файл CLI, но требуется некоторая дополнительная «подстройка». Некоторые из этих изменений лучше всего вносить во время выполнения, добавив дополнительный скрипт PHP. Другие должны быть сделаны либо в самом php.ini, либо путем передачи дополнительных аргументов в бинарный файл PHP.

Начиная с настроек, которые вы можете изменить во время выполнения, вот скрипт, который устраняет большинство проблем для пользователей, работающих с двоичным файлом CGI или версиями CLI ниже 4.3.0:

<?php /** * Sets up CLI environment based on SAPI and PHP version */ if (version_compare(phpversion(), '4.3.0', '<') || php_sapi_name() == 'cgi') { // Handle output buffering @ob_end_flush(); ob_implicit_flush(TRUE);

// Настройки PHP ini
set_time_limit (0);
ini_set (‘track_errors’, TRUE);
ini_set (‘html_errors’, FALSE);
ini_set (‘magic_quotes_runtime’, FALSE);

// Определяем константы потока
define (‘STDIN’, fopen (‘php: // stdin’, ‘r’));
define (‘STDOUT’, fopen (‘php: // stdout’, ‘w’));
define (‘STDERR’, fopen (‘php: // stderr’, ‘w’));

// Закрыть потоки при завершении скрипта
register_shutdown_function (
create_function ( »,
«Fclose (STDIN); fclose (STDOUT); fclose (STDERR); вернуть истину; ‘)
);
}
?>

Имя файла: cli_compatibility.php

Включение этого кода в ваши сценарии решит большинство проблем, но некоторые дополнительные проблемы остаются.

Исполняемый файл CGI обычно отправляет заголовки HTTP при выполнении — даже из командной строки. Пользователи, вероятно, увидят вывод, подобный следующему, когда они выполнят сценарии командной строки, используя исполняемый файл CGI:

X-Powered-By: PHP/4.3.6 Content-type: text/html

Чтобы предотвратить это, PHP должен вызываться с опцией ‘-q’ для ‘quiet’. Например:

$ php -q some_script.php

К сожалению, это ложится бременем на пользователей. В UNIX вы можете обойти эту проблему, добавив параметр в SheBang в качестве скрипта и предложив пользователям выполнить его напрямую:

#!/usr/local/bin/php -q <?php // Code starts here

Другая проблема с исполняемым файлом CGI заключается в том, что он автоматически меняет текущий рабочий каталог на тот, в котором находится исполняемый скрипт. Представьте, что я использую простой скрипт, который содержит следующее:

<?php print getcwd()."n"; ?>

Имя файла: getcwd.php

Теперь я выполняю это так:

$ pwd /home/harryf $ php ./scripts/getcwd.php

Если я использую двоичный файл CLI, это покажет «/ home / harryf» — мой текущий каталог. Но если я использую двоичный файл CGI, я получаю «/ home / harryf / scripts» — каталог скриптов.

Я не знаю обходного пути, который мог бы решить эту проблему, поэтому, если это критично для вашего приложения, лучше всего заставить пользователей работать с двоичным файлом CLI. Измените начало сценария совместимости выше:

<?php if ( php_sapi_name() == 'cgi' ) { die ('Unsupported SAPI - please use the CLI binary'); } if ( version_compare(phpversion(), '4.3.0', '<') ) {

Заворачивать

На этом первая часть нашего тура по интерфейсу командной строки PHP завершена. Пока что у нас есть основы. В следующий раз я расскажу о выполнении внешних программ из PHP, рассмотрим некоторые пакеты, которые PEAR может предложить для улучшения вашего вывода, и рассмотрим некоторые (только для UNIX) расширения PHP обеспечивает для командной строки.

Перейти на страницу: 1 | 2 | 3