2012-02-23 34 views
7

के साथ मैं एक टाइमआउट के साथ एक PHP प्रक्रिया चलाने के लिए एक रास्ता तलाश रहा हूँ। वर्तमान में मैं बस exec() का उपयोग कर रहा हूं, लेकिन यह टाइमआउट विकल्प प्रदान नहीं करता है।execout() टाइमआउट

मैंने जो भी कोशिश की वह proc_open() का उपयोग कर प्रक्रिया खोल रहा है और परिणामस्वरूप पाइप पर stream_set_timeout() का उपयोग कर रहा है, लेकिन यह भी काम नहीं करता है।

तो, क्या टाइमआउट के साथ कमांड चलाने के लिए कोई तरीका है (एक PHP कमांड सटीक होना)?

(वैसे, मैं भी इस प्रक्रिया की वापसी कोड को पुनः प्राप्त करने की जरूरत है।): (पी एस यह ऐसे मामलों में जहां max_execution_time सीमा में विफल रहता है के लिए है, इसलिए कि सुझाव देने के लिए कोई जरूरत नहीं।)

+0

शुरू टाइमर। असीमित पाश में प्रक्रिया डालें, टाइमर की जांच करें, आवश्यक होने पर टाइम-आउट करें। –

उत्तर

2

आप fork() सकता है और फिर exec() एक प्रक्रिया में और wait() दूसरे में गैर-अवरोधन। टाइमआउट और kill() अन्य प्रक्रिया को ट्रैक करें, यदि यह समय पर समाप्त नहीं होता है।

+1

क्या आप यहां pcntl_ फ़ंक्शंस का जिक्र कर रहे हैं? – NikiC

+0

@NikiC: हाँ, मुझे लगता है कि उन्हें PHP में क्या कहा जाता है। – Florian

5

मैं php.net पर यह है कि मुझे लगता है कि पाया आप क्या चाहते हैं

<?php 
function PsExecute($command, $timeout = 60, $sleep = 2) { 
    // First, execute the process, get the process ID 

    $pid = PsExec($command); 

    if($pid === false) 
     return false; 

    $cur = 0; 
    // Second, loop for $timeout seconds checking if process is running 
    while($cur < $timeout) { 
     sleep($sleep); 
     $cur += $sleep; 
     // If process is no longer running, return true; 

     echo "\n ---- $cur ------ \n"; 

     if(!PsExists($pid)) 
      return true; // Process must have exited, success! 
    } 

    // If process is still running after timeout, kill the process and return false 
    PsKill($pid); 
    return false; 
} 

function PsExec($commandJob) { 

    $command = $commandJob.' > /dev/null 2>&1 & echo $!'; 
    exec($command ,$op); 
    $pid = (int)$op[0]; 

    if($pid!="") return $pid; 

    return false; 
} 

function PsExists($pid) { 

    exec("ps ax | grep $pid 2>&1", $output); 

    while(list(,$row) = each($output)) { 

      $row_array = explode(" ", $row); 
      $check_pid = $row_array[0]; 

      if($pid == $check_pid) { 
        return true; 
      } 

    } 

    return false; 
} 

function PsKill($pid) { 
    exec("kill -9 $pid", $output); 
} 
?> 
+1

यह एक उचित दृष्टिकोण की तरह दिखता है, लेकिन इस मामले में कोई रिटर्न कोड कैसे प्राप्त कर सकता है? – NikiC

15

कर सकते हैं मैं इस विषय पर एक सा खोज की है और निष्कर्ष पर पहुंचा है कि कुछ मामले में (आप लिनक्स उपयोग कर रहे हैं) आप 'टाइमआउट' कमांड का उपयोग कर सकते हैं। यह बहुत लचीला

Usage: timeout [OPTION] DURATION COMMAND [ARG]... 
    or: timeout [OPTION] 
मेरी विशेष मामले में

मैं PHP से स्फिंक्स इंडेक्सर को चलाने के लिए कोशिश कर रहा हूँ है, थोड़े प्रवास डेटा स्क्रिप्ट इसलिए मैं अपने स्फिंक्स दस्तावेजों

exec("timeout {$time} indexer --rotate --all", $output); 

तो मैं करने जा रहा हूँ पुन: अनुक्रमणिका करने की जरूरत है आउटपुट का विश्लेषण करें और इसे एक और प्रयास देने का फैसला करें, या अपवाद फेंक दें और मेरी स्क्रिप्ट छोड़ दें।

+0

बढ़िया काम :) –

1

(अस्वीकरण: मुझे आश्चर्य हुआ कि इसके लिए कोई अच्छा समाधान नहीं मिला, फिर मैंने प्रो प्रलेखन को ब्राउज़ किया और इसे बहुत सीधे आगे पाया। तो यहां एक सरल प्रो उत्तर है, जो मूल कार्यों का उपयोग ऐसे तरीके से करता है जो लगातार परिणाम प्रदान करता है । तुम भी अभी भी प्रवेश के प्रयोजनों के लिए उत्पादन पकड़ कर सकते हैं।)

कार्यों के proc लाइन proc_terminate (process-handler) है, जो proc_get_status (process-handler) "चल" कुंजी हो रही के साथ संयुक्त, आप नींद के साथ पाश एक साथ एक तुल्यकालिक कार्यकारी कॉल करने के लिए है, जबकि कर सकते हैं समय समाप्त।

तो मूल रूप से:

$ps = popen('cmd'); 
$timeout = 5; //5 seconds 
$starttime = time(); 
while(time() < $starttime + $timeout) //until the current time is greater than our start time, plus the timeout 
{ 
    $status = proc_get_status($ps); 
    if($status['running']) 
     sleep(1); 
    else 
     return true; //command completed :) 
} 

proc_terminate($ps); 
return false; //command timed out :(
+0

लेकिन मैनुअल कहता है proc_get_status और proc_terminate केवल proc_open द्वारा लौटा संसाधन के साथ काम करता है, पॉप नहीं? –

1

जब यह एक PHP स्क्रिप्ट से कहा जाता है timeout {$time} command समाधान ठीक से काम नहीं करता है। मेरे मामले में, एक गलत सर्वर पर एक ssh कमांड के साथ (आरएसए कुंजी नहीं मिली, और सर्वर पासवर्ड मांगता है), परिभाषित टाइमआउट के बाद प्रक्रिया अभी भी जिंदा है।

हालांकि मैं एक समारोह है कि यहाँ ठीक काम करता है पाया है:

http://blog.dubbelboer.com/2012/08/24/execute-with-timeout.html

सी & पी:

/** 
* Execute a command and return it's output. Either wait until the command exits or the timeout has expired. 
* 
* @param string $cmd  Command to execute. 
* @param number $timeout Timeout in seconds. 
* @return string Output of the command. 
* @throws \Exception 
*/ 
function exec_timeout($cmd, $timeout) { 
    // File descriptors passed to the process. 
    $descriptors = array(
    0 => array('pipe', 'r'), // stdin 
    1 => array('pipe', 'w'), // stdout 
    2 => array('pipe', 'w') // stderr 
); 

    // Start the process. 
    $process = proc_open('exec ' . $cmd, $descriptors, $pipes); 

    if (!is_resource($process)) { 
    throw new \Exception('Could not execute process'); 
    } 

    // Set the stdout stream to none-blocking. 
    stream_set_blocking($pipes[1], 0); 

    // Turn the timeout into microseconds. 
    $timeout = $timeout * 1000000; 

    // Output buffer. 
    $buffer = ''; 

    // While we have time to wait. 
    while ($timeout > 0) { 
    $start = microtime(true); 

    // Wait until we have output or the timer expired. 
    $read = array($pipes[1]); 
    $other = array(); 
    stream_select($read, $other, $other, 0, $timeout); 

    // Get the status of the process. 
    // Do this before we read from the stream, 
    // this way we can't lose the last bit of output if the process dies between these  functions. 
    $status = proc_get_status($process); 

    // Read the contents from the buffer. 
    // This function will always return immediately as the stream is none-blocking. 
    $buffer .= stream_get_contents($pipes[1]); 

    if (!$status['running']) { 
     // Break from this loop if the process exited before the timeout. 
     break; 
    } 

    // Subtract the number of microseconds that we waited. 
    $timeout -= (microtime(true) - $start) * 1000000; 
    } 

    // Check if there were any errors. 
    $errors = stream_get_contents($pipes[2]); 

    if (!empty($errors)) { 
    throw new \Exception($errors); 
    } 

    // Kill the process in case the timeout expired and it's still running. 
    // If the process already exited this won't do anything. 
    proc_terminate($process, 9); 

    // Close all streams. 
    fclose($pipes[0]); 
    fclose($pipes[1]); 
    fclose($pipes[2]); 

    proc_close($process); 

    return $buffer; 
} 
0

मैं एक ही समस्या यह है कि मैं सभी उत्तर ऊपर की कोशिश की है का सामना करना पड़ रहा , लेकिन विंडोज सर्वर इनमें से किसी के साथ काम नहीं कर सकता है, शायद यह मेरी मूर्खता है।

खिड़कियों के लिए मेरा अंतिम काम कर समाधान एक बैच फ़ाइल निष्पादित हो रहा है,

timeout.bat

::param 1 is timeout seconds, param 2 is executable 
echo "running %2 with timeout %1" 
start %2 
set time=0 

:check 
tasklist /FI "IMAGENAME eq %2" 2>NUL | find /I /N "%2">NUL 
::time limit exceed 
if "%time%"=="%1" goto kill 
::program is running 
if "%ERRORLEVEL%"=="0" (ping 127.0.0.1 -n 2 >nul & set /a time=%time%+1 & goto check) else (goto end) 

:kill 
echo "terminate" 
taskkill /im %2 /f 

:end 
echo "end" 

php आदेश

exec("timeout.bat {$time} your_program.exe"); 
संबंधित मुद्दे