PHP — один из самых распространенных языков программирования. Созданный для написания небольших домашних страничек, он постепенно вырос и теперь используется миллионами веб-сайтов. Однако веб-сайтами дело не ограничивается — его можно использовать практически в любых приложениях, благо есть интерактивный, CGI и FastCGI режимы.
Режим CGI я и хочу описать. Его плюсы в относительной простоте и возможности передачи скриптам различных данных (в том числе бинарных). Минус у него лишь один — скорость работы, из-за многократных запусков приложения. Впрочем, минус этот исправляется с помощью более нового протокола FastCGI.
Для начала определим, что же такое Common Gateway Interface (CGI). На деле это всего лишь запуск приложения с определенными переменными окружения. Так как это все-таки веб-технология, то и переменные будут тесно связаны с протоколом HTTP. Заглянем в RFC 3875 и посмотрим, какие переменные окружения нужны для CGI/1.1:
Для POST и PUT запросов данные запроса передаются в стандартный ввод приложения.
Тем не менее, для запуска php-cgi все эти переменные лишь желательны, но необязательны. Обязательная переменная окружения есть только одна, да и то не указанная в RFC — SCRIPT_FILENAME. В ней должен содержаться путь к PHP-скрипту в файловой системе, например "/home/some-user/htdocs/test.php". Для запуска PHP-скрипта через CGI в своем приложении вам достаточно лишь указать ее и запустить php-cgi (не «php», а именно «php-cgi»!), перенаправив его стандартные ввод и вывод.
Если вы не пишите свой веб-сервер, вам нужно обрезать выводимые PHP заголовки. Перехватывая вывод, ждите, пока не появится первая пустая строка (просто два переноса строки подряд — "\n\n") и используйте только то, что после нее.
PHP в режиме CGI желательно использовать только тогда, когда нужно не особо активно работать со скриптами, передавая им какие-либо данные или переменные. Если нужна активная работа — лучше использовать FastCGI, а если же не нужно ничего передавать скрипту — то проще будет запустить интерпретатор PHP, передав ему в качестве аргумента путь к скрипту.
И чтобы не быть голословным, небольшой пример работы (Windows, C#):
Режим CGI я и хочу описать. Его плюсы в относительной простоте и возможности передачи скриптам различных данных (в том числе бинарных). Минус у него лишь один — скорость работы, из-за многократных запусков приложения. Впрочем, минус этот исправляется с помощью более нового протокола FastCGI.
Для начала определим, что же такое Common Gateway Interface (CGI). На деле это всего лишь запуск приложения с определенными переменными окружения. Так как это все-таки веб-технология, то и переменные будут тесно связаны с протоколом HTTP. Заглянем в RFC 3875 и посмотрим, какие переменные окружения нужны для CGI/1.1:
- AUTH_TYPE — тип HTTP-авторизации (basic, digest или др.) Может быть пустым.
- CONTENT_LENGTH — длина передаваемых в POST или PUT запросе данных. Обычно берется из заголовка Content-Length запроса.
- CONTENT_TYPE — тип передаваемых в POST или PUT запросе данных. Обычно берется из заголовка Content-Type запроса.
- GATEWAY_INTERFACE — используемая версия CGI. Обычно «CGI/1.1».
- PATH_INFO — часть пути после пути к CGI-приложению, но до переменных запроса. Например, для запроса "/somewhere/cgiapp.exe/test/?qwerty=123" это будет "/test/".
- PATH_TRANSLATED — то же самое, что и PATH_INFO, но спроецированное на файловую систему. Например, "./htdocs/test/".
- QUERY_STRING — переменные запроса (без вопросительного знака). Например, «qwerty=123».
- REMOTE_ADDR — IP-адрес удаленного пользователя.
- REMOTE_HOST — доменное имя удаленного пользователя. Обычно равно REMOTE_ADDR.
- REMOTE_IDENT — идентификационные данные пользователя согласно RFC 1314. Используется редко.
- REMOTE_USER — имя удаленного пользователя, прошедшего HTTP-авторизацию.
- REQUEST_METHOD — тип запроса (GET, POST, PUT и т. п.)
- SCRIPT_NAME — часть запроса с путем к CGI-приложению. Например, "/somewhere/cgiapp.exe".
- SERVER_NAME — название сервера (имя хоста или доменное имя).
- SERVER_PORT — порт, на котором запущен сервер.
- SERVER_PROTOCOL — протокол, используемый сервером. Обычно «HTTP/1.1».
- SERVER_SOFTWARE — версия сервера. Например, «MyServer 1.0».
Для POST и PUT запросов данные запроса передаются в стандартный ввод приложения.
Тем не менее, для запуска php-cgi все эти переменные лишь желательны, но необязательны. Обязательная переменная окружения есть только одна, да и то не указанная в RFC — SCRIPT_FILENAME. В ней должен содержаться путь к PHP-скрипту в файловой системе, например "/home/some-user/htdocs/test.php". Для запуска PHP-скрипта через CGI в своем приложении вам достаточно лишь указать ее и запустить php-cgi (не «php», а именно «php-cgi»!), перенаправив его стандартные ввод и вывод.
Если вы не пишите свой веб-сервер, вам нужно обрезать выводимые PHP заголовки. Перехватывая вывод, ждите, пока не появится первая пустая строка (просто два переноса строки подряд — "\n\n") и используйте только то, что после нее.
PHP в режиме CGI желательно использовать только тогда, когда нужно не особо активно работать со скриптами, передавая им какие-либо данные или переменные. Если нужна активная работа — лучше использовать FastCGI, а если же не нужно ничего передавать скрипту — то проще будет запустить интерпретатор PHP, передав ему в качестве аргумента путь к скрипту.
И чтобы не быть голословным, небольшой пример работы (Windows, C#):
using System;
using System.Diagnostics;
namespace PhpApp
{
class Program
{
static void Main(string[] args)
{
Process php = new Process();
// Путь к php-cgi
php.StartInfo.FileName = "c:\\php\\php-cgi.exe";
// Через ShellExecute запускать нельзя - нужно перенаправить выходной поток
php.StartInfo.UseShellExecute = false;
// Указываем, что нужно перенаправить выходной поток
php.StartInfo.RedirectStandardOutput = true;
// Добавляем обработчик для принятия данных из выходного потока приложения
php.OutputDataReceived += new DataReceivedEventHandler(php_OutputDataReceived);
// Устанавливаем единственную обязательную для php-cgi переменную окружения
php.StartInfo.EnvironmentVariables.Add("SCRIPT_FILENAME", "test.php");
// Запускаем приложение
php.Start();
// Начинам читать данные из его выходного потока
php.BeginOutputReadLine();
// Ждем, пока php-cgi завершит работу
php.WaitForExit();
// Закрываем его окончательно
php.Close();
// Ожидаем нажатия клавиши
Console.ReadKey();
}
static void php_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
// Если нет принятых данных (такое бывает), выходим из процедуры
if (e.Data == null)
return;
// Выводим строку на экран
Console.WriteLine(e.Data);
}
}
}