[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Консольные интерактивные приложения на PHP
Balancer
Периодически возникает задача сделать интерактивное приложение под PHP. Обычно делается всё тупо и некрасиво — echo/fgets. Есть, понятно, и готовые библиотеки на этот счёт, но там, в общем-то, всё также некрасиво.

Следующая мысль — сделать что-то на ncurses. Но придётся делать целую прослойку для стандартных элементов интерфейса и взаимодействия их с приложением. Тоже долгая история. Но на её пути родилась такая цепочка. Для языка разметки форм хорошо бы задействовать тот же HTML → Надо писать хотя бы примитивный парсер форм → Хорошо бы для этого задействовать уже имеющиеся консольные браузеры → Консольный браузер итак может показывать HTML-страницы, выданные скриптом и отсылать запросы в него же, при этом в PHP5.4 появился неплохой встроенный Web-сервер.

И, вот, основная идея готова. Скрипт запускает web-сервер, потом — консольный браузер с запросом к этому серверу. Работаем привычно, как с любым Web-приложением, когда завершаем работу и выходим из браузера, сервер убивается. Получается удобно, красиво (для консоли) и без велосипедостроения.

А вот на практической реализации уткнулся в проблемы.

Хочется иметь автономный запускающий скрипт. С состоящим из двух частей — никаких проблем. Например, bash-запускалка и php-роутер, который проинициирует систему. Но удобно, когда скрипт один. Соответственно, в голову приходит два варианта:

— Комбинированный скрип, запускающийся как bash, продолжающийся как php. Ну, грубо говоря (концепт):

#!/bin/bash
#<?php /*

php -S localhost:12345 $0 &> /dev/null &
sleep 0.2 # Пауза, чтобы сервер успел стартовать
lynx http://localhost:12345 # запуск браузера
killall php # закрытие сервера
exit
*/

// Тут пошёл PHP-код роутера

echo "Run!";


Этот вариант прекрасно работает, но, увы, мусорит на экран двумя хэшами. Я так и не поборол пока эту проблему.

Следующий вариант более «полноценный». Всё засунуть целиком в нормальный PHP-скрипт, из него запустить фоновым процессом php с web-сервером, запустить браузер, после выхода из последнего — всё за собой подчистить. Тут вылезла другая проблема. Единственный способ запустить браузер интерактивно, который я нашёл — это pcntl_exec(). Во всех остальных случаях он тупо ждёт ввода, ничего не выводя на экран, пока его не прибить (пробовал lynx, links, w3m).

Кроме того, возникали постоянные проблемы с работой фонового web-сервера, пока не засунул его запуск в pcntl_fork(). Текущий вариант такой:

#!/usr/bin/env php
<?php

$self = $_SERVER['SCRIPT_NAME'];
if(empty($_SERVER['HTTP_HOST']))
{
// Это часть-запускалка
if($child = pcntl_fork())
{
// Мы запустили дочерний процесс. Тут — работает основной процесс
usleep(300000); // Чтобы сервер запустился
// Запуск браузера

pcntl_exec("/usr/bin/lynx", array("http://localhost:58671/"));
// Убиваем процесс сервера
posix_kill($child, 15);
}
else
{
// Это — дочерний процесс
// Запуск сервера в фоновом режиме

pcntl_exec("/usr/bin/php", array("-S", "localhost:58671", $self));
}

exit();
}

// Часть web--сервера
// Тут — роутер



Тут вылезла другая проблема. Всё отлично работает, пока не сделаешь выход. После выхода из браузера php-скрипт вываливается, не доходя до выполнения убийства web-сервера. Если после pcntl_exec("/usr/bin/lynx") поставить логгирование в файл, то оно никогда не вызывается. Соответственно, после выхода из браузера мы оказываемся в консоли, но у нас в фоне остаётся запущенный web-сервер.

Есть у кого-нибудь мысли, как решить первую или вторую проблемы?
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.