2013-04-12 50 views
1

從我的Apache服務器的PHP頁面,我用跑的線路像一些命令:使用exec()時真的守護一個命令?

exec("{$command} >> /tmp/test.log 2>&1 & echo -n \$!"); 

你可以看到的參數here一個交代。

但我不明白:如果我重新啓動或停止我的apache服務器,我的命令也死了。

[email protected]:/sx/temp# ps ax | grep 0ff | grep -v grep 
15957 ?  S  0:38 /usr/bin/php /sx/site_web_php/fr_FR/app/console task:exec /sx/temp/task_inventaire/ 0ff79bf690dcfdf788fff26c259882e2d07426df 10800 
[email protected]:/sx/temp# /etc/init.d/apache2 restart 
Restarting web server: apache2 ... waiting .. 
[email protected]:/sx/temp# ps ax | grep 0ff | grep -v grep 
[email protected]:/sx/temp# 

一些研究之後,我瞭解父母的pid一些事情,但使用&我的命令行裏,我想我是真的脫離我的孩子的過程,從他的父母。

我使用apache2與libapache2-mod-php5和apache2-mpm-prefork。

我怎樣才能真正將我的子程序從apache中分離出來?

編輯

您可以複製它在Linux/Mac上這樣說:

一)創建一個包含executed_script.php文件:

<?php 
sleep(10); 

B)創建一個execute_from_http。 php文件包含:

<?php 
exec("php executed_script.php > /tmp/test.log 2>&1 & echo -n \$!"); 

c)運行http://localhost/path/execute_from_http.php

終端上d),運行命令:

ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep 

如果運行期間execute_from_http.php腳本的10秒的命令,你會得到輸出:

[email protected]:/var/www/xxx/$ ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep 
    1 5257 5245 5245 ?   -1 S  33 0:00 php executed_script.php 
* Restarting web server apache2 
... waiting ...done. 
[email protected]:/var/www/xxx/$ 

正如您所看到的,ps命令只輸出一次,這告訴您執行的腳本在apache重新啓動時死亡。

回答

1

首先注意到,在您的示例「&」僅僅是一個布爾值,並且concats的命令呼應。如果你想在背景啓動命令,這意味着高管將立即返回,使用&在命令行的末尾:

exec("{$command} >> /tmp/test.log 2>&1 & echo -n \$! &"); 

如果你想運行的過程中Apache在後完成後,您就必須使用守護進程pcntl_fork()

這裏來處理一個例子:

$pid = pcntl_fork(); 

switch($pid) { 
    case -1 : die ('Error while forking'); 

    case 0: // daemon code 
     posix_setsid(); // create new process group 
     exec("{$command} >> /tmp/test.log 2>&1 & echo -n \$!"); 
     break; 
    default: 
     echo 'daemon started'; 
     break; 

} 

現在,在處理exec返回值及其輸出的起始PHP腳本中沒有代碼。所以當前進程可以在exec完成之前完成。在此之後,工作進程將歸屬於init。你


也可以看看PEAR包System_Daemon。這可以幫助守護一個腳本。

+0

已經與高管的進程化的過程,是不是? –

+0

不,它不是。通過exec啓動的進程仍然屬於Apache進程組 – hek2mgl

+0

我最近幾天有同樣的要求,併成功地使用'pcntl_fork()'。我不知道爲什麼,但沒有明確創建新進程組的事件 – hek2mgl

2

的「在」法

我找到了一個工作解決方案,但我不知道這是確定的,如果我們講的性能和安全性。它使用at命令,這是一種只能工作一次的cron。

相反的:

exec("php executed_script.php > /dev/null 2>&1 & echo -n \$!"); 

用途:

exec("echo 'php executed_script.php > /dev/null 2>&1' | at now -M"); 

的關鍵是executed_script.php將通過外部守護進程(ATD)中運行,所以executed_script.php將是atd,而不是一個孩子apache的。

[email protected]:/var/www/xxx$ ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep 
7032 7033 973 973 ?   -1 SN  33 0:00   \_ php executed_script.php 
* Restarting web server apache2 
... waiting ...done. 
7032 7033 973 973 ?   -1 SN  33 0:00   \_ php executed_script.php 
[email protected]:/var/www/xxx$ ps ax | grep 973 
973 ?  Ss  0:00 atd 

注意幾件事情:

  • 您無法訪問您的RAN的應用程序的PID,如果你喜歡$!我以前的代碼段,你會得到的at的PID。
  • 您需要刪除www-data這是在默認情況下/etc/at.deny(它可能是那裏的原因,所以要小心)
  • 我對性能產生嚴重的懷疑:我認爲at寫上由atd讀取一個文件進行通信

叉/ setsid方法

正如@ hek2mgl在自己的回答中寫道,我們可以使用一個pcntl_fork(),但是這並不是那麼簡單。首先,你不能運行pcntl_fork()背後的Apache,因爲如果我們看一下PHP手冊,Introduction of the Process Control,我們可以看到:

過程控制不應該在Web服務器環境 中啓用和意外結果可能發生,如果在Web服務器環境中使用任何過程控制功能 。

當分叉時,你會得到父進程在內存中的兩個確切副本。而且由於Apache背後的PHP是作爲模塊運行的,所以在PHP執行結束時(甚至在die()之後),您會回到apache的模塊包裝器,並且無法控制發生了什麼。

因此,這裏是一箇中間指令的情況下,將守護進程的執行:

1)來自於Apache的運行中間指令,將創建您的守護進程的命令:

$command = escapeshellarg("php executed_script.php"); 
exec("php run_as_daemon.php {$command} >> /dev/null 2>&1 &"); 

2)中間命令叉並使用posix_setsid確實分離您的命令。

<?php 

if (!isset($argv[1])) 
{ 
    exit; 
} 
$command = $argv[1]; 

$pid = pcntl_fork(); 
if ($pid < 0) // error 
    exit; 
else if ($pid) // parent 
    exit; 
else // child 
{ 
    $sid = posix_setsid(); // creates a daemon 

    if ($sid < 0) 
     exit; 

    exec("{$command} >> /dev/null 2>&1 &"); 
} 

3)你執行的命令,當然,不改變:

<?php 
sleep(10); 

結果:

[email protected]:/var/www/xxx/$ wget -qO- http://localhost/xxx/execute_from_http.php && sleep 1 && ps axjf | grep execute | grep -v grep ; sudo /etc/init.d/apache2 restart ; ps axjf | grep execute | grep -v grep 
    1 19958 19956 19956 ?   -1 S  33 0:00 php executed_script.php 
* Restarting web server apache2 ......done. 
    1 19958 19956 19956 ?   -1 S  33 0:00 php executed_script.php