2011-03-30 125 views
1

我有一個PHP應用程序(使用LAMP堆棧),發送數千個應用程序。我很想停止強制發送電子郵件。顯然,我無法通過關閉瀏覽器來阻止senidng。如何停止PHP腳本?阻止電子郵件被髮送?

我應該殺死進程,還是有其他方法可以這樣做?我應該殺死哪個進程?可能有多個..?

PS:當然,應用程序的設計很糟糕......但這不是問題。

+0

如果您可以修改的源代碼,添加一個'file_exists()'檢查,將「取消」的文件,如果文件存在退出應用程序,可能是最徹底的方法。要停止該過程,只需在定義的目錄中創建該文件即可。 (當然還有其他幾種實現這種觸發器的方法。) – 2011-03-30 15:46:59

+0

如何發送電子郵件?有幾種方法可以在PHP中執行此操作。 – mpdonadio 2011-03-30 15:49:17

+0

@MOD> mail()函數是發送電子郵件的方式。 – Cedric 2011-03-30 16:35:42

回答

2

如果是你自己的(自寫的)應用程序,也許你應該添加一些功能,讓你暫停或暫停執行。

一個例子是每X次迭代,腳本檢查資源的命令。如果資源隊列中有命令,則按順序執行它們,將其刪除並繼續(如果適用)。

例如,平面文件或DB,您可以添加一個STOP-SUSPEND_EXECUTION命令。當腳本讀取該行或行時,它會暫停正常執行,但會繼續定期檢查資源。之後,如果讀取RESUME命令,則執行將從其停止的位置恢復,因爲它尚未離開迭代循環。

現在,您可以通過CLI或其他界面向隊列添加命令,應用程序將作出相應的響應。

你甚至可以看中它,添加時間戳來推遲命令執行。 PS:如果你正在執行羣發郵件等任務,也許你會考慮將這些腳本移動到命令行界面。我只根據你對「關閉瀏覽器」的評論提到這一點。


可以使用一些工作,但它有竅門。 run()以回調函數$job作爲參數。該函數表示您正在執行的任何批處理作業(羣發郵件等)以及作爲數據數組的單個迭代。在每次迭代中,$job作爲一組參數被賦予$data數組的下一個元素。

$data = array(
    array('name' => 'bob', 'email' => '[email protected]'), 
    array('name' => 'jim', 'email' => '[email protected]'), 
    array('name' => 'ann', 'email' => '[email protected]'), 
); 

$job = function($name, $email){ 
    // do something with $name 
    // and $email 
}; 

$batch->run($job, $data); 

你需要一些表(一個「拉MySQL工作臺):

CREATE SCHEMA IF NOT EXISTS `batchtest` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ; 
USE `batchtest` ; 

CREATE TABLE IF NOT EXISTS `batchtest`.`job` (
    `id` CHAR(24) NOT NULL , 
    `alias` VARCHAR(255) NOT NULL , 
    `status` INT NOT NULL DEFAULT 0 , 
    `timestamp` TIMESTAMP NOT NULL , 
    PRIMARY KEY (`id`)) 
ENGINE = InnoDB; 

CREATE TABLE IF NOT EXISTS `batchtest`.`queue` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 
    `job_id` CHAR(24) NOT NULL , 
    `action` VARCHAR(255) NOT NULL , 
    `params` TEXT NULL , 
    `timestamp` TIMESTAMP NOT NULL , 
    PRIMARY KEY (`id`)) 
ENGINE = InnoDB; 

每當你要暫停/恢復/中止任務,增加一行到queue表與job_idactionpause,resumeabort)並且作業會作出迴應。作業將自動從queue表中刪除已完成的命令。

這就是它的要義。

class BatchJob{ 

    const STATUS_STARTING = 0; 
    const STATUS_RUNNING = 1; 
    const STATUS_PAUSED  = 2; 
    const STATUS_ABORTED = 4; 
    const STATUS_COMPLETED = 5; 

    protected $_id   = null; 
    protected $_alias  = null; 
    protected $_pdo   = null; 
    protected $_pauseSleep = null; 
    protected $_status  = self::STATUS_STARTING; 
    protected $_jobTable = 'job'; 
    protected $_queueTable = 'queue'; 

    public function __construct($pdo, $alias){ 
     $this->_pdo  = $pdo; 
     $this->_alias = $alias; 
     $this->_id  = vsprintf('%04x%04x%04x%04x%04x%04x', array(
      mt_rand(0, 0xffff), 
      mt_rand(0, 0xffff), 
      mt_rand(0, 0xffff), 
      mt_rand(0, 0xffff), 
      mt_rand(0, 0xffff), 
      mt_rand(0, 0xffff), 
     )); 
     $this->output("Initializing job"); 
     $this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
     $statement = $this->_pdo->prepare("INSERT INTO {$this->_jobTable} (id, alias, status) VALUES (:id, :alias, :status)"); 
     $statement->execute(array(
      ':id'  => $this->_id, 
      ':alias' => $this->_alias, 
      ':status' => $this->_status, 
     )); 
    } 

    public function run($job, Array $data, $pauseSleep = 10){ 
     $this->_pauseSleep = $pauseSleep; 
     $iteration   = 0; 
     $this->updateStatus(self::STATUS_RUNNING); 

     while($this->_status != self::STATUS_ABORTED 
      &&$this->_status != self::STATUS_COMPLETED){ 

      $statement = $this->_pdo->prepare("SELECT id, action, params FROM {$this->_queueTable} WHERE job_id = :job_id"); 
      $statement->execute(array(
       ':job_id'  => $this->_id, 
      )); 

      foreach($statement->fetchAll() as $command){ 
       switch($command['action']){ 
        case 'resume': 
         $this->updateStatus(self::STATUS_RUNNING); 
         break; 
        case 'pause': 
         $this->updateStatus(self::STATUS_PAUSED); 
         break; 
        case 'abort': 
         $this->updateStatus(self::STATUS_ABORTED, true, false); 
         exit; 
         break; 
       } 
       $statement = $this->_pdo->prepare("DELETE FROM {$this->_queueTable} WHERE id = :id"); 
       $statement->execute(array(
        ':id' => $command['id'], 
       )); 
      } 

      if($this->_status == self::STATUS_PAUSED){ 
       sleep($this->_pauseSleep); 
       continue; 
      } 

      call_user_func_array($job, (Array) current($data)); 

      if(!next($data)){ 
       $this->updateStatus(self::STATUS_COMPLETED, true, false); 
      } 

     } 
    } 

    protected function output($string){ 
     echo ">>> [{$this->_alias}:{$this->_id}] [" . date('Y-m-d H:i:s') . "] {$string}" . PHP_EOL; 
    } 

    protected function updateStatus($status = null, $updateDatabase = true, $updateOutput = true){ 
     if(!is_null($status)){ 
      $this->_status = $status; 
     } 

     if($updateDatabase){ 
      $statement = $this->_pdo->prepare("UPDATE {$this->_jobTable} SET status = :status WHERE id = :id"); 
      $statement->execute(array(
       ':id'  => $this->_id, 
       ':status' => $this->_status, 
      )); 
     } 
     if($updateOutput){ 
      $reflection = new ReflectionClass(__CLASS__); 
      $statusCodes = array_flip($reflection->getConstants()); 
      $this->output("Job status change [{$statusCodes[$this->_status]}]"); 
     } 
    } 

    public function __destruct(){ 
     $this->updateStatus(); 
    } 

} 
0

httpd - 這將停止所有的Apache。

0

通常你會殺死Web服務器。如果你運行cgi exe,你可以殺死它。

0

你問的如何關閉一個瘋狂的php腳本?如果是這樣,你總是可以重新啓動Apache。如果我誤解了你的問題,我提前道歉。

1

如果你可以修改腳本,你可以插入這樣一行的腳本(最好是前mail()線)的主要週期:

if (connection_aborted()) 
    exit(); 

這將如果停止PHP腳本你關閉瀏覽器窗口。儘管這是默認行爲,但php經常無法立即停止腳本。

你可以在不知道腳本內部工作的情況下做到這一點,它比殺死Apache更好。

相關問題