В общем, такая ситуация - нужно из интерфейса запустить скрипт (например через exec() или system()), который будет производить расчеты а в это время часть интерфейса будет недоступна, но состояние работы скрипта должно как-то выводится полльзователю. Я такого раньше не реализовывал, поэтому идея такая: 1)Запускаем скрипт через system (только как потом перенаправить пользователя на главную страницу, ведь этот вызов, вроде как, блокирующий) 2)Сделать запись в бд, что идет работа и часть интерфейса показываться не будет (смотрим в бд, если есть запись о том что работа идет, то не показываем некоторые меню) 3)Но как от скрипта получать результаты в реальном времени? Например, чтобы аяксом каждые 30 секунд производились запросы к скрипту и он возвращал какие-то данные (но так не получится, потому что скрипт работать будет, значит нужен какой-то промежуточный?)
технология скорборда. запустили сценарий, придумали произвольную строку, вернули её клиенту и перенаправили клиента к другой странице - где он статус будет смотреть, запрашивая с этой произвольной. продолжительная программа на определенных этапах записывает данные в оговоренное место. скрипт статуса читает данные из этого оговоренного места и показывает пользователю в дружелюбном формате. оговоренное место может быть обычным текстовым файлом, бинарным файлом, пхп-файлом, таблица в субд, таблица в ноускуэль решении вроде рэдиса или мемкеша.
Спасибо. Я хотел бы уточнить некоторые детали. Если скрипт обращается к БД, то есть смысл через какой-то промежуток к ней обращаться. То есть, скрипт сделал какой-то процент от работы и записал в БД - сделал столько-то процентов. Так? Да и как собственно перенаправление клиента сделать чтобы процесс работал в фоне, например запущенный через system. Или можно каким-то другим образом это сделать?
Можно не буквально system запускать (такую возможность лучше вообще закрыть), а выкладывать каким-то образом "задание". Думай об этом как об обработке очереди. Один процесс пихает задания в очередь, другой обрабатывает. Если оставаться в рамках PHP, обработчиком может быть скрипт, запускаемый кроном или какой-нибудь phpdaemon.
Мне нужно запустить обработку сразу же, как пользователь загрузит файл. Нуи потом результат как-то отображать.
напрмер страница start.php Код (PHP): <?php // создаем айдишник сессии $session_id = md5(microtime(true)); // стартуем с ним нашу прогу // амперсанд отстёгивает новый процесс от текущего, чтоб не ждать завершения exec("/usr/bin/php /path/to/program.php {$session_id} &"); // редиректим юзера к сценарию статуса header("Location: /status.php?session_id={$session_id}"); exit; ?> страница status.php Код (PHP): <?php // проверяем наличие идентификатора сессии if (!isset($_GET['session_id'])) { // ой потерялся die('session_id required'); } // формируем имя файла $sb_file = '/tmp/program-session-' . $_GET['session_id'] . '.php'; // проверяем наличие if (!file_exists($sb_file)) { // еще одна потеря die('session not found'); } // загружаем $sb = include $sb_file; // показываем страницу ?><!DOCTYPE html> <html> <head> <title>Program status. Session: <?=$_GET['session_id']?></title> <meta http-equiv="refresh" content="5"> </head> <body><h1>Program</h1> <p><strong>launched</strong> <?=$sb['launched']?></p> <p><strong>progress</strong> <?=$sb['progress']?>%</p> </body></html> программа program.php Код (PHP): <?php // проверим передан ли аргумент сессии if (empty($argv[1])) { // ах echo "session_id required"; exit 1; } // наше время запуска $launched = date('Y-m-d H:i:s'); // наш файл $sb_file = '/tmp/program-session-' . $argv[1] . '.php'; // наш длинный цикл for ($i = 0; $i <= 100; $i++) { // кладем текущее состояние в файл file_put_contents($sb_file, sprintf('<?php return %s', var_export(['launched' => $launched, 'progress' => $i], true))); // спим секунду-другую sleep(rand(1, 5)); } // спасибо ?>
А можно ли как-то узнать, нормально ли вызов произошел или при старте программы, например ошибки были?
все можно. перенаправление ввода, статусы, сигналы, форки. мы в разделе для новичков, запрашиваемая информация для очень подготовленного ума. изначальная задача была как проследить за выполнением долгого скрипта - вот те минимальное рабочее решение. тупо покажет от нуля до сотни. ты с ним разобрался?
Ну почти. Свой скрипт у меня получилось запустить, правда не совсем как хотелось бы. Код (PHP): $cmd = "start /B \"php test.php > C:\\users\\alex\\desktop\\123.txt\""; pclose(popen($cmd,'w')); Во-первых вывод в файл не перенаправляется, а во-вторых я хз как узнать запустился ли скрипт или какие ошибки посыпались. Подсказка от модератора: Любой код или текст конфигурации пишите между тегом [code=php] и [/code]. Используйте отступы в коде для форматирования текста. Это помогает быстрее понять вас, увеличивает шанс на получение ответа. Что выделять? Например: PHP, HTML, CSS, JavaScript, SQL, XML, .htaccess, ini, регулярные выражения, код шаблонизаторов, любая другая разметка, результаты array/object dump и т. д.
может быть полный путь? может странная конструкция открытия-закрытия процесса? и где перенаправление вывода ошибок?
Путь к рнр у меня в системных переменных. Все отрабатывает, только в файл не перенаправляется. И по popen тоже определить, нормально ли запуск произошел, нельзя.
а почему попен а не экзек или систем или пасфру? есть вообще понимание как работать с ресурсом открытым попен-ом? а вывод ошибок можно отправить в файл или в другой поток. у тебя же стандартный вывод заворачивается в файл - вот таким же раком и другие дескрипторы перехватываются: 2>&1 - вывод ошибок в стандартный вывод 2>/path/to/file - вывод ошибок в файл или другую программу
Попеном я хотел определять удачно ли завершился вызов или нет. Но он false не возращает даже если файл запускаемый не существует. И какая конкретно причина фейла тоже не узнать. Так тоже не работает: Код (PHP): $cmd = "start php test.php 2>&1 1> C:\\users\\alex\\desktop\\123.txt"; //комманда pclose(popen($cmd,'w'));
для определения удачности есть статус. рэтвал. для определения ошибок существует стандартный поток ошибок. стдэрр. дескриптор два. попеном открывается ресурс с которым ты потом интерактивно общаешься. в стдин пишешь из стдаута читаешь. в стдэре ждешь предупреждения. в третьем и далее дескрипторах ждешь что-то еще если ты их открыл и ими пользуешься.
Я понимаю, но можно простой пример, который запустит процесс фоном и в случае неудачи запуска (отсутсует пхп файл, например) сделает вывод какой-нибудь? Я разные способы пробовал, но либо процесс начинает висеть и не идет в фон, либо не выводятся ошибки.
хватит оверквотить. Код (PHP): exec('/usr/bin/php /path/to/file.php 2>/tmp/stderr.log >/tmp/stdout.log &'); с виндой как-нибудь сам.
Вот, если кому в будущем пригодится, рабочее решение: http://stackoverflow.com/questions/13289595/starting-a-wind ... et-its-pid. Спасибо всем кто отписал!