Фоновое выполнение скрипта на PHP без crontab
Озадачили меня тут написать демона на PHP. Т.е. скрипт, который будет заданное количество раз в заданное количество часов в случайное время (всегда случайное) выполнять определенные действия, и все это без использования cron’a.
До этого никогда не заморачивался, а тут после постановки задачи, начал было думать что так нельзя, что php скрипт надо вызывать браузером…ну задача то поставлена, надо выполнять.
Первая мысль — отключить ограничение времени выполнения скрипта. Запрещено хостером.
Вторая мысль — яваскриптом повторять аякс-запрос периодически (да хоть раз в секунду). — нельзя (требование заказчика).
Выяснилось, собственно, что и браузер открыт не должен быть, и крон нельзя использовать, и работать скрипт должен независимо от пользователя, бесконечно долго. Естественно, он должен минимум грузить систему.
1. Пачка сигарет, ночь, гугл, доки, книги, мануалы….
goto 1…
На выходе получаю:
Задача_1:
Реализовать генератор времен выполнения скрипта, исходя из заданных количества раз и количества часов. Хранить где-то эти времена.
Задача_2:
Работать после закрытия браузера
Задача_3:
Не вылетать после окончания ограничения времени выполнения скрипта
Задача_4:
Выполнять в нужное время какие-то действия.
Итак…
Пишем в конфиге исходные данные:
Далее пишем функцию, которая поможет нам сгенерировать времена запуска.
В ней мы генерируем случайное число от 0 до количества секунд в исходном интервале.
Далее сгенерируем и запишем в сессию массив времен запуска. Предварительно отсортируем массив по возрастанию, чтобы сначала шло раннее время (машину времени я еще не успел создать).
Теперь надо заставить скрипт работать, не обращая внимания на максимальное время выполнения, установленное сервером.
Принцип таков:
1) Определяем время начала работы скрипта;
2) Определяем установленное ограничение на время выполнения.
3) Запускаем цикл, внутри которого считаем текущее время и вычисляем общее время работы скрипта, сверяем текущее время со значениями в массиве времен запуска, и если совпадение есть, выполняем заданные действия (у меня они в файле exec.php). Для запуска файлов используем сокеты.
4) Повторяем цикл пока время работы скрипта не приблизится к максимально разрешенному. Я поставил — пока до максимального времени не останется 5 секунд.
Итак… считаем начальные данные по времени:
Собственно, цикл. Комментарии в коде.
Ну и, если разрешенное время подходит к концу, то завершаем цикл и благополучно запускаем этот же скрипт другие процессом (в 5 секунд точно уложимся)
Собственно, готово.
Далее у меня много заморочек было в выполнении тех самых действий — там надо было робота написать для поиска ссылок по заданным ссылкам.
Когда дописал все, озадачился полезным применением…Использовать его можно как службу. Он может следить за чем-то в сети и уведомлять Вас, например, по почте. И не надо никаких cron’ов.
Скрипт можно еще оптимизировать — доработкой не занимался.
Кстати, вот от чего я не смог оторваться — браузер все же придется открыть, чтобы изначально запустить скрипт.
Фоновые PHP-процессы в Linux

В программирование бывает необходимость писать программы, которые должны работать непрерывно, причины тому могут быть: непрерывное отслеживание изменений на сайте, длительное выполнение какой-либо операции, веб-сокет сервер и другие. И для небольших программ язык PHP, как никогда подходит лучше всего. Здесь я попытаюсь описать возможные шаги, которые нужно предпринять чтобы написать свою программу работающую в среде Linux. Я предполагаю что Вы уже знакомы с Линукс и слова «консоль» и «ssh» Вас уже не пугают. Примеры команд будут запущены в среде Debian Linux 8.4, с PHP 7. Сам PHP 7 установлен как CLI.
Оглавление
Процесс в Linux
Запуская программу в Unix вы создаёте «процесс», т.е. процессор начинает выполнять инструкции программы. Чтобы не запутаться в названиях «программа» и «процесс» можно представить, что «программа» это некоторая бумага с текстом приказа, а «процесс» это робот который читает приказ и выполняет его. Вполне может быть что процесс может удалить программу, которая его запустила или что процесс запустил другие программы, т.е. вызвал другие процессы.
Запуская программу в Unix процессу присваиваются некоторые параметры, а именно:
— PID — уникальный номер процесса. С помощью PID можно отправить сигнал процессу, узнать о его состоянии. PID всегда уникален и предсказать этот номер не представляется возможным. Если выполнить в консоле команду то увидим ID процесса.
* Запуская программу в консоли я использую на конце символ «&», это я делаю для того чтобы после запуска в консоли можно было запускать другие программы, т.е. не быть заблокированным своим процессом.
— Имя — имя процесса формируется из имени программы и параметры его запуска. Т.е. если выполнить в консоли « php sleep.php & » процесс будет называться « php sleep.php » если же выполнить « /usr/local/bin/php sleep.php & », то процесс будет называться « /usr/local/bin/php sleep.php ». Но так бывает не всегда, при желании процесс может задать себе новое какое пожелает. Пример:
Вывод команды ps будет напоминать что-то вроде этого.
Я всё же рекомендую не использовать в имени процесса UTF-8 символы и спец символы, во избежания проблем с операционными системами Unix, без поддержки Unicode на уровне ядра.
— PPID — PID родительского процесса. У каждого процесса есть родитель, т.е. процесс который его запустил. У родительского процесса также может присутстовать родитель и так вверх по иерархии. На самом верху иерархии находится процесс « init » или « systemd », он является родоначальников всех процессов и его запускает само ядро Linux. У процесса всегда есть родитель, если родительский процесс закрывается все потомки родительского процесса «усыновляются» процессом « init » или « systemd ». Если вы запускаете программу через консоль, то родителем процесса будет консольная программа, вероятно « tcsh », « bash » или « zsh ». Посмотреть иерархию процессов можно так:
— UID — UID пользователя, который запустил процесс. После запуска процессу ещё присваивается владелец и группа (почти как у файла) и с правами этого пользователя процесс будет работать. К примеру если мы запустим программу от пользователя «user1» находящегося в группе «group1», то процесс сможет выполнять действия доступные пользователю «user1», и не сможет скажем зайти в папку «/root» или удалить файл, владелец которого является пользователь «user2».
— Аргументы программы — строки указанные в консоле при запуске программы после имени программы через пробел. Например если в консоли запустить программу: «php example.php a b -p1 —test=2», аргументами будут строки «a», «b», «-p1», «—test=2». В PHP аргументы программы можно найти в глобальном массиве $argv, а кол-во аргументов можно найти в глобальной переменной «$argc». Пример:
Закрытие процесса
В большинстве случаев процесс сам знает когда ему закончить работу, т.е. выполнил программу и завершился, но бывают случаи, когда процесс необходимо завершить принудительно. Для того чтобы обратиться к процесс нужно знать его PID или хотя бы имя процесса, чтобы по нему потом определить PID. После того как узнали PID процесса можно отправить сигнал закрытия, это делается командой « kill ». Пример:
Бывает такое что процесс не может завершиться, то тогда ему нужно отправить сигнал «принудительное закрытие», это делается командой « kill -9 PID ». Ещё процесс можно завершить по имени процесса, для этого используйте команду « killall ».
Если вы запустили программу и программа заблокировала консоль используйте сочетание клавиш « Ctrl + C » и программа завершится. Или если просто хотите вернуться консоль не закрывая программу, то нажмите « Ctrl + Z », а далее « bg ».
Программы Linux для работы с процессами
Программ для работы с процессами множество, я же расскажу о программах которые мне нравятся больше и популярные примеры их использования. Речь пойдёт о программах: ps , pgrep , kill , htop .
— ps — показывает запущенные процессы и сведения по ним. Примеры:
* — Если написать просто «ps -ef | grep «simple.php»», то отобразиться не только нужный нам процесс и сведения о самом нашем процессе «ps» и это может запутать.
— pgrep — ищет процесс по имени и возвращает PID процесса. В отличии от ps не возвращает PID самого себя, а только нужный нам. В большинстве случаев результат программы pgrep используется другими программами. Примеры:
— kill — отправить сигнал процессу. Не стоит пугаться названия этой программы, она не только завершает процесс, но и может отправить разные сигналы процессу. В основном используется чтобы принудительно закрыть процесс.
* Если процесс не настроен на «ловлю» этого сигнала процесс завершиться.
— htop — программа для мониторинга процессов в реальном времени. Программа позволяет узнать загруженность системы, а также узнать какие процессы используют большую часть процессорного времени или оперативной памяти. Удобно запускать в отдельном окне и заглядывать туда.
— pstree — показать дерево процессов. Можно посмотреть всю иерархию процессов или всех «предков» процесса.
Непрерывный процесс
Теперь нам нужно добиться того чтобы наш скрипт работал постоянно (а не выключался после запуска), для этого нам достаточно написать бесконечный цикл, к примеру вот так:
Если мы запустим этот скрипт, у нас действительно процесс будет запущен постоянно, но при этом мы получим почти 100% загрузку процессора, т.е. итерации цикла будут выполняться постоянно со 100% скоростью. Чтобы этого избежать нагрузку процессора, но при этом получать отклик необходимо по окончании каждой итерации цикла останавливать скрипт на некоторое количество времени. Для этого можно использовать функции « sleep » или « usleep », при « sleep » указывается время в секундах, а при «usleep» время в микросекундах, т.е. « sleep(2) = usleep(2000000) ». Переделаем наш скрипт:
Здесь «usleep» будет означать, время отклика ваше программы на внешние раздражители (сигналы, сокеты и прочее).Теперь вместо почти 100% загруженности получим почти 0% загруженность процессора при простаивании процесса. Вероятно программа, которая работает в фоне будет не просто выполняться в бесконечном цикле, а ждать поступления определённого события (сигналы, таймер, поступление данных на канал или сокет, изменения в файлах и прочее), здесь же скрипт предоставлен в качестве примера.
Отвязываемся от консоли
Мы научились запускать процессы в режиме ожидания, теперь необходимо чтобы процесс смог самостоятельно работать и не быть «привязанным к консоли». Запуская свои программы в консоли мы можем заметить пока программа выполняется, другие программы запускать в консоли не получается. Есть несколько способов запустить программу в фоновом режиме.
Первый способ:
Используйте символ « & » (Амперса́нд) после набора команды. Пример:
Консоли бывают разные (bash, tcsh, zsh и др.) и некоторые консоли (но не tcsh) при закрытии отправляют процессам специальный сигнал «SIGHUP», после чего программы завершают своё выполнение. Чтобы этого избежать используйте программу «nohup», она гарантирует что после закрытия консоли программы не закроются.
Второй способ:
После запуска программы нажмите сочетание клавиш « Ctrl + Z » и далее команду « bg ». Сочетаниями клавиш мы ставим процесс на «паузу» и командой « bg » «будим» процесс и он продолжает работать работать в фоне.
Третий способ:
Ещё один способ подразумевает что запущенный процесс (родительский процесс) «склонирует» себе подобный процесс (дочерний процесс) т.е. «форкнется» и завершиться. Родительский процесс завершиться, а дочерний процесс продолжит работу, к тому же он усыновляется процессом « init » и перестаёт быть зависимым от консоли. Я считаю этот способ более предпочтительным, т.к. нам теперь нет необходимости на конце писать символ « & » и следить не закроется ли он после закрытия консоли.
Одна программа — один процесс
Запуская нашу программу несколько раз мы будем постоянно «плодить» одинаковые процессы, нам же нужно чтобы программа порождала только один процесс. Чтобы программа запускалась только один раз, нужно чтобы она перед запуском опрашивала систему на поиск себе подобных процессов. Один из способов узнать запущенна ли уже программа это использовать «pid-файл», т.е. файл в котором записан PID запущенного процесса. Определить какой PID текущего процесса можно функцией posix_getpid . Создаётся pid-файл вот так:
Далее при каждом запуске программы, программа будет читать этот файл и на указанный PID будет отправлять сигнал, если ответ придёт утвердительный значит программа уже запущена и запуск повторный не потребуется, если же ответа нет значит можно запускаться. Проверить запущен ли процесс с определённым PID можно функцией « posix_kill », которая отправит сигнал процессу. В функции указать сигнал с номером « 0 ».
Теперь напишем программу, которая будет запускаться только один раз:
Программа запустилась только один раз.
PHP-программа как Unix скрипт
Чтобы запускать php-программу, как обычный Unix-скрипт (т.е. вместо « php script.php » писать « ./script.php »), необходимо в начале файла (перед « <?php ») программы написать путь к интерпритатору, который будет обрабатывать этот файл (в нашем случае это php ). Путь к интерпритатору будет начинаться с символов « #! ». Также нужно задать файлу права на выполнение к примеру 755 , что будет означать — разрешено запускать скрипт всем.
Теперь если запустить файл без указания интерпритатора, то программа запуститься через «/usr/bin/php», если запустить с указанием интерпритатора, то программа запустить через указнный в консоли интерпритатор. Пример:
Если же ваш скрипт будет использоваться в системах, где php может находиться в разных местах используйте такой путь к интерпритатору « #!/usr/bin/env php »
Как запустить php скрипт в фоновом режиме

Когда проект растет, появляются ресурсоемкие задачи обработки данных. Например, разбор xlsx (эксель) прайса для обновления цен, или ресайз большой фотографии. Случаи могут быть самыми разнообразными, когда мы не хотим, чтобы пользователь ждал, пока наш скрипт отработает.
В данном посте расскажу, как можно запускать фоновое выполнение PHP скриптов. Следует отметить, что без использования VPS (Virtual Private Server), то есть на обычном шаред хостинге, такой способ не сработает. Строго говоря, диспетчер создавался под Linux, хотя не исключена корректная работа и на FreeBSD. Даже скорее всего будет работать тоже.
В самом диспетчере ничего сложного нет, он скорее имеет больше заморочек по администрированию. Давайте сначала разберем, из чего он состоит со стороны ОС, какие используются команды:
ps -C php -o pid=,command=
Здесь мы запрашиваем список процессов с именем php. Остальные параметры влияют на отображение результатов, т.е. мы хотим видеть pid, и непосредственно полную команду, включая параметры. Пример вывода этой команды:
12769 php /path/to/1.php /path/to/price.xlsx
Таким образом, мы проверяем, запущена ли уже такая задача, и если запущена, то по умолчанию повторный запуск не производится. Если все же требуется параллельно запустить еще один экземпляр с точно такими же параметрами, можно это указать явным способом.
php -d max_execution_time=300 –f /pathto/1.php /pathto/price.xlsx > /dev/null 2>&1 & echo $!
Здесь мы запускаем php, причем указываем максимальное время выполнения в 300 секунд, чтобы наши фоновые процессы не превратились в бесконечные. Простая мера предосторожности, не более. Далее идет путь к скрипту, потом параметры, если есть необходимость. Перенаправляем вывод вместо stdout в «черную дыру», 2>&1 означает, что мы так же направляем вывод ошибок туда же. Кстати, можно перенаправить в файл через >>, в целях дебаггинга. Но советую отлаживать скрипты перед тем как их щапускать в фоне. Самое главное, последняя часть: & уходим в background и echo $! Как раз выводим (возвращаем) PID только что созданного процесса.
Это все, теперь сам код диспетчера и пример использования:
Допустим у нас есть php скрипт, который принимает в параметрах путь до файла, читает его и складывает содержимое в другой файл. Причем делает это очень долго (заменим на sleep )
А вот, как запускать его в фоновом режиме:
Метод launch может принимать 3 параметра. Первый это путь к файлу-скрипту со всеми параметрами; второй – максимальное время выполнения (по умолчанию 300 секунд) и третий разрешено ли запускать копии, то есть точно такие же процессы с идентичными параметрами.
Обратите внимание, в переменную $pid мы вернули идентификатор процесса. Его можно где-нибудь сохранить, например, в куках пользователя, и при следующем открытии страницы узнать, закончилось ли выполнение задачи. Для этого метод isRunning
php execute a background process
I need to execute a directory copy upon a user action, but the directories are quite large, so I would like to be able to perform such an action without the user being aware of the time it takes for the copy to complete.
Any suggestions would be much appreciated.
22 Answers 22
Assuming this is running on a Linux machine, I’ve always handled it like this:
This launches the command $cmd , redirects the command output to $outputfile , and writes the process id to $pidfile .
That lets you easily monitor what the process is doing and if it’s still running.
Write the process as a server-side script in whatever language (php/bash/perl/etc) is handy and then call it from the process control functions in your php script.
The function probably detects if standard io is used as the output stream and if it is then that will set the return value..if not then it ends
I tested this quickly from the command line using «sleep 25s» as the command and it worked like a charm.
You might want to try to append this to your command
![]()
![]()
I’d just like to add a very simple example for testing this functionality on Windows:
Create the following two files and save them to a web directory:
Give IUSR permission to write to the directory in which you created the above files
Give IUSR permission to READ and EXECUTE C:\Windows\System32\cmd.exe
Hit foreground.php from a web browser
The following should be rendered to the browser w/the current timestamps and local resource # in the output array:
You should see testoutput.php in the same directory as the above files were saved, and it should be empty
You should see testprocesses.php in the same directory as the above files were saved, and it should contain the following text w/the current timestamps:
If you need to just do something in background without the PHP page waiting for it to complete, you could use another (background) PHP script that is «invoked» with wget command. This background PHP script will be executed with privileges, of course, as any other PHP script on your system.
Here is an example on Windows using wget from gnuwin32 packages.
The background code (file test-proc-bg.php) as an exmple .
The foreground script, the one invoking .
You must use the popen/pclose for this to work properly.
The wget options:
Well i found a bit faster and easier version to use
Here is a function to launch a background process in PHP. Finally created one that actually works on Windows too, after a lot of reading and testing different approaches and parameters.
Note 1: On windows, do not use /B parameter as suggested elsewhere. It forces process to run the same console window as start command itself, resulting in the process being processed synchronously. To run the process in a separate thread (asynchronously), do not use /B .
Note 2: The empty double quotes after start «» are required if the command is a quoted path. start command interprets the first quoted parameter as window title.