В избранное    Домой   

Суббота,  20 Apr 2024 г., 06:34
Не медлит Господь исполнением обетования, как некоторые почитают то медлением; но долготерпит нас, не желая, чтобы кто погиб, но чтобы все пришли к покаянию. /2-е Петра (гл.3 ст.9)/

 Логин:  

 Пароль: 




Анонсы:
=== Дата: 31/08/2011     Автор: Крис Ньюман ===

PHP. Урок 18 Выполнение программ на Web-сервере

Урок 18. Выполнение программ на Web-сервере

В этом уроке вы узнаете, как с помощью PHP выполнить программы на Web-сервере и обработать полученный вывод.

Выполнение локальных программ

PHP позволяет вызывать внешние программы, которые находятся на Web-сервере, несколькими способами.

Функция passthru

Вызвать локальную команду и получить результат на экране можно с помощью функции passthru. Инструкция, которая передается в аргументе, выполняется на Web-сервере, и весь полученный вывод отправляется браузеру.

Ниже приводится простой пример, который работает как на Unix/Linux, так и на Windows-системах:

passthru(“hosthame”);

C помощью команды hostname можно узнать название сервера. Команда hostname выполняется на локальной системе, и результат выводится на экран.

Второй необязательный аргумент passthru позволяет определить код выхода из команды. Так можно узнать результат выполнения операции. Обычно все команды при удачном завершении возвращают ноль. Код возврата может понадобиться, если команда может возвращать разные значения.

Вывод команды. Только стандартный поток вывода отображается в окне браузера. Поэтому для того, чтобы увидеть сообщения об ошибках, нужно перенаправить поток ошибок stderr в стандартный поток вывода.
На серверах под управлением Unix это выполняется с помощью вызова функции passthru(“cmd 2>&1”) в оболочке Bourne.

Наиболее часто при ненулевом результате получаем значение 1 для неспецифических ошибок и 127,если такой команды не обнаружено. Другие коды ошибок для каждой отдельной программы нужно искать в документации. В следующем примере вызывается команда hostname, и в зависимости от результата выполняется действие:

passthru(“hostname”, $return);
switch ($return) {
    case 0: echo “Команда выполнена успешно”;
        break;
    case 127: echo “Команда не обнаружена”;
        break;
    default: echo “Команда не выполнена. Код возврата $return”;
}

Применение апострофа

Символ апострофа (`) позволяет быстро выполнить нужную команду на Web-сервере. Строка между апострофами выполняется, а на выходе получим результат, генерируемый системой.

Ниже приводится аналог примера с passthru для апострофов:

echo `hostname`;

Апострофы позволяют присвоить результат выполнения команды переменной, как показывается в примере ниже:

$hostname = `hostname`;

Символ апострофа можно использовать в любом месте сценария PHP. Он приостанавливает выполнение сценария и подставляет полученной значение в сценарий. В примере ниже показано, как результат выполнения команды на сервере подставляется в условие:

if (chop(`hostname`) == “hal9000”) {
    echo “Добрый вечер, Дмитрий”;
}

Результат выполнения hostname заканчивается переводом строки. Это нужно для нормального вывода в командной строке. Функция chop в примере выше удаляет все разделительные знаки для того, чтобы правильно сравнить значения.

Коды возврата. Апострофы не позволяют узнать коды возврата. Поэтому вместо них нужно использовать функцию exec. Она работает так же, как и passthru, но результат возвращает в виде строки. Второй необязательный параметр содержит код возврата.

Создание командной строки

Апострофам, функциям passthru и exec команды передаются в виде строки. Кроме того, строку с командами можно построить при помощи переменных и выражений.

В двойных кавычках символ доллара заменяется на соответствующую переменную, но в одинарных кавычках он трактуется как переменная оболочки.

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

`$cmd`;

В переменной $cmd может быть несколько системных команд. Если не нужно знать результат этих операций, такой вариант корректен.

Нужно помнить про закрывающую точку с запятой. Закрывающий апостроф завершает команду сервера, но не выражение PHP.

Окружение сервера

Теперь рассмотрим, каким образом PHP взаимодействует с окружением локального Web-сервера.

Определение платформы сервера

На каждой системе есть свой набор команд. Поэтому при написании сценария под различные платформы нужно знать, на какой из них происходит работа.

Константа PHP_OS содержит название операционной системы. Обычно нужно определить — Windows- или Unix-подобная система используется на сервере. Дело в том, что все Unix-подобные системы (включая Mac OS) очень похожи друг на друга.

Значение PHP_OS на Web-сервере под управление Windows может быть Windows, WINNT или WIN32. В будущем к этому списку могут прибавиться новые значения. Поэтому для проверки на Windows достаточно выполнить независимую от регистра проверку первых трех символов строки. В примере ниже показано, как это сделать:

if (strtoupper(substr(PHP_OS, 0, 3) ) == “WIN”) { … }

Darwin. Отметим, что новая версия Mac OS идентифицирует себя как Darwin. Поэтому нужно проверить начало строки PHP_OS на совпадение с WIN.

Переменные окружения

Суперглобальный массив $_ENV содержит все значения переменных окружения. Переменные окружения — это значения операционной системы. Они доступны для PHP из окружения, в котором работает Web-сервер.

Переменная окружения PATH содержит список путей, в которых нужно искать исполняемые программы. Все места проверяются по очереди, пока программа не будет найдена. В противном случае выводится сообщение об ошибке.

Определить текущее значение пути можно с помощью следующего выражения:

echo $_ENV[“PATH”];

В Unix/Linux-системе он может быть следующим:

/bin:/usr/bin:/usr/X11R6/bin:/home/chris/bin

Но на платформе Windows он выглядит примерно так:

C:\WINDOWS\system32;C:\WINDOWS

Нужно помнить, что формат исполняемых путей отличается для различных операционных систем. Unix/Linux-версия использует двоеточие для разделения позиций и косую черту для путей. В платформе Windows используется точка с запятой и обратная косая черта. Поэтому в PHP есть специальные константы — DIRECTORY_SEPARATOR и PATH_SEPARATOR, которые позволяют определить соответствующие значения.

Во многих случаях изменение значения PATH отличается для разных платформ. Например, если использовать правильное значение константы PATH_SEPARATOR, C:/WINDOWS не существует на платформе Linux. Но к нему можно добавить текущий или относительный каталог.

В следующем примере добавляется каталог bin относительно текущей позиции, к началу системного пути:

$newpath = getcwd() . DIRECTORY_SEPARATOR . “bin” . PATH_SEPARATOR . $_ENV[“PATH”];
putenv(“PATH=$newpath”);

Функции putenv нужно передать аргумент, в котором переменной окружения присваивается новое значение. Это временное изменение. Новое хранится только до окончания работы сценария.

Часовые пояса

Переменная окружения TZ содержит настройки часового пояса. Изменяя это значение, можно выводить время в другой точке мира. При этом не нужно знать смещение и выполнять арифметические операции.

Большинство главных городов различных регионов мира имеют легко запоминающиеся значения для TZ (например: Europe/London, US/Pacific). Можно задать значение относительно GMT или другое общее название часового пояса, например GMT-8 или EST.

На большинстве систем названия всех часовых поясов можно найти в /usr/share/zoneinfo.

Сценарий в листинге 18.1 показывает текущее время в различных точках мира.

Листинг 18.1. Использование переменной окружения TZ для изменения часового пользователя


<?php
$now = time();
$original_tz = $_ENV[“TZ”];

echo “Текущее время ” . date(“H:i:s”, $now) . “<br>”;

putenv (“TZ=US/Pacific”);
echo “Сейчас на американском западном побережье ” . date(“H:i:s”, $now) . “<br>”

putenv (“TZ=Europe/Paris”);
echo “Сейчас во Франции ” . date(“H:i:s”, $now) . “<br>”

putenv (“TZ=Australia/Sydney”);
echo “Сейчас в Сиднее ” . date(“H:i:s”, $now) . “<br>”

putenv (“TZ=Asia/Tokyo”);
echo “Сейчас в Токио ” . date(“H:i:s”, $now) . “<br>”

putenv(“TZ=$original_tz”);
?>

Отметим, что в начале листинга 18.1 сохраняется значение текущего часового пояса. Это позволяет восстановить его после всех изменений.

Сохранение времени. В начале листинга 18.1 значение временной метки записывается в $now. Поэтому все функции date получают одинаковое значение. Второй аргумент date можно опустить, но во время работы сценария может измениться системное время. Тогда на выходе будет странный результат.

Анализ безопасности

Размещать на сервере сценарии, которые могут выполнять серверные программы, плохое решение с точки зрения безопасности. До окончания этого урока будут рассмотрены способы безопасного выполнения программ.

Разделение обратной косой чертой команд оболочки

Рассмотрим сценарий в листинге 18.2. Он создает Web-интерфейс для команды finger.

Листинг 18.2. Вызов команды finger из Web-формы


<FORM ACTION=”finger.php” METHOD=”POST”>
<INPUT NAME=”username” SIZE=10>
<INPUT TYPE=”SUBMIT” VALUE=”Figer username”>
</FORM>
<?php
if ($_POST[“username”]) {
    $cmd = “finger {$_POST['username']}”;
    echo “<PRE>” . `$cmd` . “</PRE>”;
}
?>

Если запустить этот сценарий в браузере и ввести имя пользователя, результат выполнения finger будет выведен на экран.

Но если вместо имени ввести точку с запятой, а за ней - любую команду, например ;ls, команда finger выполнится без аргумента. А вслед за ней выполниться следующая команда. Аналогичный механизм реализуется с помощью других символов, в зависимости от платформы сервера.

Понятно, что это не очень хорошо. Некоторые могут подумать, что нельзя нанести существенный ущерб системе с помощью такого недочета. Но есть программы взлома, которые могут сделать довольно много, используя этот механизм. Например, с помощью команды wget или lynx на Web-сервере устанавливается и запускается на выполнение нужная программа. Это может быть rootkit, который позволяет находить различные уязвимости на сервере. Или сценарий, который запустит DOS-атаку на сервере и заберет на себя все ресурсы. Как бы то ни было, но лучше не давать анонимным пользователям такой доступ к серверу.

Функция escapeshellcmd позволяет предотвратить появление такой уязвимости. Все символы, кроме одного предназначенного, которые могут обмануть сценарий при выполнении программы, предваряются обратной косой чертой. Таким образом, нежелательные символы становятся аргументом команды.

Чтобы сделать безопасным листинг 18.2, нужно заменить выражение, которое создает $cmd, на следующий код:

$cmd = escapeshellcmd(“finger {$_POST['username']}”);

Теперь, если ввести ;ls в поле формы, выполниться команда finger \; ls. Команда попытается найти в системе пользователей с именем ; или ls.

Резюме

В этом уроке вы узнали, как обезопасить выполнение команд на Web-сервере из PHP и как работать с выводом, который они генерируют. В следующем уроке вы узнаете, как получить доступ к базе данных MySQL из PHP.


<<назад

Погода в Рудне
(Волгоградcкая обл.)

Подробнее >>


Курс валют
на 20 Апр 2024 г.
704 - Вьетнамских донгов
- 1