Статьи

Воспользуйтесь преимуществами встроенного сервера PHP

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

Сервер пригоден и для других творческих целей. Например, вы можете распространять портативные веб-приложения на компакт-дисках или USB-накопителях или даже в качестве настольных приложений, все они созданы с помощью PHP без необходимости использования GTK или других графических библиотек.

Некоторые могут указать на то, что PHP — это язык, изначально предназначенный для использования в Интернете, в то время как другие языки, такие как Python и Ruby, этого не делают, поэтому для других имеет больше смысла предоставлять базовую серверную среду, чтобы помочь начать веб-разработку. Они будут утверждать, что PHP не нуждается во встроенном сервере. Кроме того, большинство систем сегодня поставляются с персональным веб-сервером, уже установленным или устанавливаемым с помощью нескольких команд или щелчков.

Действительно, в руководстве по PHP подчеркивается, что новый встроенный сервер предназначен только для разработки, и не рекомендуется использовать его в производстве. Для него нет специальных директив INI, за исключением одной (которая окрашивает вывод журналов, отправляемых на консоль), и общий тон документации выглядит так: «У нас тоже есть веб-сервер, перестаньте нас беспокоить».

Несмотря на это, сервер сделал это в версии 5.4, и я считаю, что он может быть ценным инструментом как для разработки, так и для тестирования. Например, на моей машине я использую предустановленный Apache OSX с пользовательской конфигурацией, которая соответствует моему стилю разработки, но иногда я хочу попробовать новое веб-приложение. Благодаря встроенному серверу PHP, я мог протестировать приложение прямо из моей директории download или temp, а затем переместить его в свою обычную среду, только если мне это действительно нужно.

Ну, сначала это не так просто, потому что многие приложения написаны для Apache и используют файлы .htaccess и mod_rewrite . Но я совершенно уверен, что кто-то там (возможно, один из вас, почему бы и нет?) Напишет и адаптирует эти функции, и я хотел бы быть первым, чтобы протестировать его.

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

Использование встроенного сервера

Для использования встроенного сервера вам потребуется установить PHP 5.4 или выше. Чтобы проверить вашу версию PHP, вызовите php -v в терминале. Затем вы можете определить, доступен ли сервер в вашей сборке, запустив php -h и отыскивая опции -S и -t , специфичные для сервера.

Вы можете протестировать сервер, создав основной файл index.php в текущем каталоге, который содержит вызов phpinfo() , а затем запустив сервер следующим образом:

  [ec2-user @ ip-10-229-67-156 ~] $ php -S <localhost или ваш общедоступный IP-адрес>: 8080
 PHP 5.4.0RC7 Development Server запущен в пт 26 февраля 18:49:29 2012
 Прослушивание <YourIP>: 8080
 Корнем документа является / home / ec2-user
 Нажмите Ctrl-C, чтобы выйти. 

Теперь в вашем браузере вы сможете увидеть контент, обслуживаемый встроенным сервером.

Новая строка журнала будет записана в окне консоли для каждого клиентского доступа:

  [Вс 26 февраля 18:55:30 2012] 80.180.55.37:36318 [200]: /
 [Вс 26 февраля 18:56:23 2012] 80.180.55.37:36584 [200]: / 

Возвращаясь к параметрам командной строки PHP, -S используется для указания адреса, к которому будет привязан сервер. Его значение может быть:

  • localhost — сервер доступен только на локальной машине
  • 0.0.0.0 — сервер доступен с любого интерфейса вашего компьютера, проводного или беспроводного
  • любой ваш публичный или частный IP-адрес — сервер доступен только по определенному адресу

-t позволяет вам указать серверу указать другой каталог для его корневого каталога. Например:

  [ec2-user @ ip-10-229-67-156 ~] $ php -S <localhost или ваш общедоступный IP-адрес>: 8090 -t / home / ec2-user / public 

Кроме того, вы также можете router.php имя определенного файла PHP, например, index.php или пользовательский файл router.php .

  [ec2-user @ ip-10-229-67-156 ~] $ php -S> localhost или ваш общедоступный IP-адрес>: 8080 -t / home / ec2-user / public public / index.php 

Вывод такого скрипта маршрутизатора будет проанализирован и выполнен сервером. Вот основной пример:

 <?php $extensions = array("php", "jpg", "jpeg", "gif", "css"); $path = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH); $ext = pathinfo($path, PATHINFO_EXTENSION); if (in_array($ext, $extensions)) { // let the server handle the request as-is return false; } echo "<p>Welcome to PHP</p>"; 

Если скрипт возвращает значение false, запрошенный URI будет обработан сервером, который выводит запрошенный ресурс как есть или как ошибка 404. Если скрипт возвращает что-то еще, то результат передается клиенту.

Хотя такой подход дает нам больше контроля, есть несколько вещей, о которых вы должны знать. Во-первых, сервер PHP возвращает только минимальный набор заголовков HTTP:

  Подключение: закрыто
 Тип контента: текст / HTML
 Ведущий: aws-dev-01.vtardia.com
 X-Powered-By: PHP / 5.4.0RC7 

Сравните это с набором типичных HTTP-заголовков, возвращаемых Apache:

  Accept-Ranges: байты
 Подключение: Keep-Alive
 Длина контента: 631
 Тип контента: текст / HTML
 Дата: сб, 04 фев 2012 18:24:42 GMT
 Этаг: "bbb99-277-4ace8c5470a40"
 Keep-Alive: тайм-аут = 15, максимум = 100
 Дата последнего изменения: ср, 14 сен 2011 15:54:09 GMT
 Сервер: Apache / 2.2.21 (Unix) DAV / 2 

Если ваше приложение использует заголовки сервера, они должны быть согласованными как в среде разработки / тестирования (встроенный сервер), так и в производственной среде (Apache / IIS / Nginx).

Во-вторых, PHP-сервер имеет другой SAPI (Server API), поэтому вы выполняете маршрутизацию условно независимо от того, подается ли index.php со встроенного сервера или с рабочего сервера. php_sapi_name() вернет «cli-server», когда вы используете встроенный сервер.

 <?php if (php_sapi_name() == "cli-server") { // running under built-in server so // route static assets and return false $extensions = array("php", "jpg", "jpeg", "gif", "css"); $path = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH); $ext = pathinfo($path, PATHINFO_EXTENSION); if (in_array($ext, $extensions)) { return false; } } 

Существует одна специальная директива INI для встроенного сервера; директива cli_server.color включает вывод cli_server.color журнала в вывод консоли. Создайте пустой текстовый файл с именем cli-server.ini и вставьте эту строку:

  cli_server.color = on 

Вы можете создать уникальную конфигурационную среду для вашего сервера в вашем новом пользовательском INI-файле, и любые не указанные директивы примут значение по умолчанию. Здесь мы только что cli_server.color directive .

Убейте ранее запущенный процесс и запустите его снова, но на этот раз используйте -c чтобы указать новый файл.

  [ec2-user @ ip-10-229-67-156 ~] $ php -S <localhost или ваш общедоступный IP-адрес>: 8080 -c cli-server.ini 

Если ваш терминал поддерживает цвет, вы должны увидеть цветные выходные строки. 200 статусов показаны зеленым цветом, оранжевый используется для 404 статусов, и вы увидите красный для ошибок внутри запрошенного скрипта.

Создание собственного сервера

Теперь, когда вы знаете все, что нужно знать о встроенном веб-сервере в PHP, давайте использовать эти знания, чтобы сделать что-то крутое. Давайте запрограммируем пользовательский портативный сервер!

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

Каталог library содержит код приложения, public каталог будет нашим корневым документом и будет содержать index.php и некоторые примеры статических файлов. Основное внимание в этом руководстве будет уделено каталогу server , поэтому приложение будет состоять из простого скрипта HelloWorld и некоторого статического содержимого (изображения и файла CSS).

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

  [ec2-user @ ip-10-229-67-156 myapp] $ ./start.sh 

Давайте начнем исследовать стартовый скрипт, который является простым скриптом оболочки:
[ракушка]#! / Бен / Баш

INIFILE = «$ (PWD) /server/server.ini»
DOCROOT = «$ (PWD) / общественности»
Роутер = «$ (PWD) /server/router.php»
HOST = 0.0.0.0
PORT = 8080

PHP = $ (какой php)
если [$? ! = 0]; тогда
echo «Невозможно найти PHP»
выход 1
фи

$ PHP -S $ HOST: $ PORT -c $ INIFILE -t $ DOCROOT $ ROUTER [/ shell]
Линии сразу после #! Шебанг это настраиваемые параметры. Я предполагаю, что скрипт запускается из каталога приложения, поэтому пути INIFILE , DOCROOT и ROUTER рассчитываются оттуда с помощью pwd . Затем путь к PHP определяется с помощью вывода команды which . Если PHP не найден в $PATH пользователя, с помощью которого команда возвращает ненулевое значение, и сценарий завершится с ошибкой.

Подход здесь работает достаточно хорошо, но, возможно, вам придется быть более надежным в зависимости от ваших потребностей. Альтернативный подход заключается в предоставлении пользователю возможности переопределить любой из определенных параметров из командной строки, например:
[shell] если [! -z $ INIFILE]; тогда
INIFILE = «$ (PWD) /server/server.ini»
Fi [/ оболочка]
Продолжая, каталог errors содержит файлы для сообщений об ошибках HTTP. Вот пример сообщения 403; хотя я использовал только HTML, скрипт будет включен с помощью include в маршрутизаторе, чтобы вы могли добавить любой PHP, какой захотите.

 <!doctype html>  <html lang="en"> <head>  <meta charset="utf-8"> <title>403</title>  </head> <body> <h1>403: Forbidden</h1> <p>Sorry, the requested resource is not accessible.</p> </body>  </html> 

И еще есть файл router.php который выполняет всю работу. Цель этого файла — захватить и обработать все запросы и передать их на сервер, только если они являются существующими файлами. Все страницы ошибок управляются изнутри, включая шаблоны.

 <?php // Set timezone date_default_timezone_set("UTC"); // Directory that contains error pages define("ERRORS", dirname(__FILE__) . "/errors"); // Default index file define("DIRECTORY_INDEX", "index.php"); // Optional array of authorized client IPs for a bit of security $config["hostsAllowed"] = array(); function logAccess($status = 200) { file_put_contents("php://stdout", sprintf("[%s] %s:%s [%s]: %sn", date("DM j H:i:s Y"), $_SERVER["REMOTE_ADDR"], $_SERVER["REMOTE_PORT"], $status, $_SERVER["REQUEST_URI"])); } // Parse allowed host list if (!empty($config['hostsAllowed'])) { if (!in_array($_SERVER['REMOTE_ADDR'], $config['hostsAllowed'])) { logAccess(403); http_response_code(403); include ERRORS . '/403.php'; exit; } } // if requesting a directory then serve the default index $path = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH); $ext = pathinfo($path, PATHINFO_EXTENSION); if (empty($ext)) { $path = rtrim($path, "/") . "/" . DIRECTORY_INDEX; } // If the file exists then return false and let the server handle it if (file_exists($_SERVER["DOCUMENT_ROOT"] . $path)) { return false; } // default behavior logAccess(404); http_response_code(404); include ERRORS . "/404.php"; 

В первых строках я определяю некоторые глобальные настройки, такие как индексный файл каталога и каталог шаблонов ошибок. Параметр date_default_timezone_set() должен совпадать с параметром вашей системы, иначе у вас будет несоответствие между записями журнала скрипта и сервером. Я также добавил необязательный список разрешенных клиентских IP-адресов для повышения безопасности.

Функция logAccess() необходима, потому что, когда скрипт маршрутизатора заботится о запросе, журнал по умолчанию сервера обходит. Эта функция принимает только параметр кода состояния и форматирует выходные данные в соответствии с данными сервера.

Нашей первой задачей синтаксического анализа является проверка безопасности: если список хостов определен выше, а клиент отсутствует в этом списке, мы выдаем сообщение об ошибке и закрываем скрипт. Нам нужно вывести код состояния, отличный от 200, в случае ошибки, и функция header() не будет работать в этом контексте, поэтому правильная функция — новый http_response_code() .

Если клиенту разрешено идти дальше, следующее, что мы делаем, это извлекаем запрошенный путь и его расширение. Если расширение пусто, пользователь запрашивает каталог, поэтому мы строим полный путь, используя файл индекса каталога по умолчанию.

Наконец, если запрошенный путь соответствует существующему файлу, скрипт возвращает false и позволяет серверу обработать его. Если нет, выполняется поведение по умолчанию, отображающее страницу ошибки 404.

Резюме

Вот и все. Как видите, сервер PHP прост и довольно прост в использовании. Наш пользовательский быстрый сервер очень прост, код может быть оптимизирован и инкапсулирован в более сложный и полнофункциональный класс. Как обычно, вы можете скачать исходный код с GitHub для игры. Удачного кодирования!

Изображение через Евгений Кузьменок / Shutterstock