php एक पृष्ठभूमि प्रक्रिया निष्पादित करता है


259

मुझे एक उपयोगकर्ता कार्रवाई पर एक निर्देशिका प्रतिलिपि निष्पादित करने की आवश्यकता है, लेकिन निर्देशिकाएं काफी बड़ी हैं, इसलिए मैं उपयोगकर्ता के बिना इस तरह की कार्रवाई करने में सक्षम होना चाहूंगा कि प्रतिलिपि को पूरा करने में लगने वाले समय के बारे में पता हो।

किसी भी सुझाव को सराहा जाएगा।


3
यह stackoverflow.com/questions/5367261/… खिड़कियों के नीचे यह करने के लिए कैसे समझाता है
shealtiel

जवाबों:


365

यह मानते हुए कि यह लिनक्स मशीन पर चल रहा है, मैंने हमेशा इसे इस तरह संभाला है:

exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile));

यह कमांड लॉन्च करता $cmdहै $outputfile, प्रोसेस आउटपुट को रीडायरेक्ट करता है और प्रोसेस आईडी को लिखता है $pidfile

इससे आप आसानी से देख सकते हैं कि प्रक्रिया क्या कर रही है और यदि यह अभी भी चल रही है।

function isRunning($pid){
    try{
        $result = shell_exec(sprintf("ps %d", $pid));
        if( count(preg_split("/\n/", $result)) > 2){
            return true;
        }
    }catch(Exception $e){}

    return false;
}

2
क्या sudo सेटअप को पासवर्ड के लिए संकेत दिए बिना चलाया जाता है? उपयोगकर्ता इनपुट के लिए आवश्यक कोई भी आदेश काम नहीं करने वाले हैं।
मार्क बैजक

17
यह stackoverflow.com/questions/5367261/… खिड़कियों के नीचे एक ही करने के लिए कैसे बताता है
shealtiel

13
मैंने इसका उपयोग किया, लेकिन इसे थोड़ा अद्यतन किया तो मुझे PID को फ़ाइल में लिखना नहीं पड़ा। इसलिए मैं इस प्रारूप का उपयोग करता हूं: <code> exec (sprintf ("$ s> $ s 2> & 1 & echo $ 1", $ cmd, $ outputfile), $ pidArr); </ code> परिणामी प्रक्रिया PID $ pidArr में है [0]
Kaiesh

3
@ केक: यह "$ प्रतिध्वनि" होना चाहिए!
ब्रूनोबग

8
कैयश ने '%' के बजाय '$' का एंकर बनाया। सही संस्करण: निष्पादन (स्प्रिंटफ़ ("% s>% s 2> & 1 & गूंज $!", $ Cmd, $ outputfile), $ pidArr)
यूरी गोर

23

जो भी भाषा (php / bash / perl / etc) में सर्वर-साइड स्क्रिप्ट के रूप में प्रक्रिया लिखें, वह आसान है और फिर इसे प्रक्रिया नियंत्रण कार्यों से अपनी php स्क्रिप्ट में कॉल करें।

फ़ंक्शन संभवत: यह पता लगाता है कि यदि मानक io का उपयोग आउटपुट स्ट्रीम के रूप में किया जाता है और यदि ऐसा है तो वह रिटर्न वैल्यू सेट करेगा।

proc_close( proc_open( "./command --foo=1 &", array(), $foo ) );

मैंने कमांड लाइन से "स्लीप 25s" का उपयोग कमांड के रूप में जल्दी से किया और यह एक आकर्षण की तरह काम किया।

( उत्तर यहां मिला )


3
यह एकमात्र तरीका है जो मुझे सेंटो पर काम करने के लिए मिल सकता है। धन्यवाद!
1948 में

धन्यवाद ! PHP और BASH की असंगति है। यदि आप एक नया सिस्टम चलाते हैं तो यह सिस्टम () या एक्जीक्यूट () का उपयोग करके बैकग्राउंड में लॉन्च करने में विफल होगा। यदि आप रीडायरेक्ट करते हैं तो फ़ाइल डिस्क्रिप्टर अटक जाते हैं। आपका तरीका काम कर गया। एक अन्य विकल्प PHP के लिए एक पुराने बैश बाइनरी का उपयोग करना है, लेकिन यह पागल है
जॉन

22

आप इसे अपने कमांड में जोड़ने की कोशिश करना चाह सकते हैं

>/dev/null 2>/dev/null &

जैसे।

shell_exec('service named reload >/dev/null 2>/dev/null &');

मैं मतलब> / dev / बातिल 2> / dev / बातिल और
WLF

यह मेरे लिए काम है, और मैं सर्वर साइट पर मेकफाइल का उपयोग करूँगा, धन्यवाद! (उदा। मेक, रिस्टार्ट)
चू-सियांग लाई

यह स्वीकृत उत्तर की तुलना में बहुत सरल है! (जब तक आपको कुछ और जटिल की आवश्यकता नहीं है, जैसे कि यदि प्रक्रिया अभी भी चल रही है, तो जाँच करें।)
बीन

18

मैं विंडोज पर इस कार्यक्षमता के परीक्षण के लिए एक बहुत ही सरल उदाहरण जोड़ना चाहूंगा:

निम्नलिखित दो फाइलें बनाएं और उन्हें वेब निर्देशिका में सहेजें:

foreground.php:

<?php

ini_set("display_errors",1);
error_reporting(E_ALL);

echo "<pre>loading page</pre>";

function run_background_process()
{
    file_put_contents("testprocesses.php","foreground start time = " . time() . "\n");
    echo "<pre>  foreground start time = " . time() . "</pre>";

    // output from the command must be redirected to a file or another output stream 
    // http://ca.php.net/manual/en/function.exec.php

    exec("php background.php > testoutput.php 2>&1 & echo $!", $output);

    echo "<pre>  foreground end time = " . time() . "</pre>";
    file_put_contents("testprocesses.php","foreground end time = " . time() . "\n", FILE_APPEND);
    return $output;
}

echo "<pre>calling run_background_process</pre>";

$output = run_background_process();

echo "<pre>output = "; print_r($output); echo "</pre>";
echo "<pre>end of page</pre>";
?>

background.php:

<?
file_put_contents("testprocesses.php","background start time = " . time() . "\n", FILE_APPEND);
sleep(10);
file_put_contents("testprocesses.php","background end time = " . time() . "\n", FILE_APPEND);
?>

IUSR को उस निर्देशिका को लिखने की अनुमति दें जिसमें आपने उपरोक्त फाइलें बनाई थीं

READ और EXECUTE C: \ Windows \ System32 \ cmd.exe अनुमति दें

वेब ब्राउज़र से अग्रभूमि मारो

निम्नलिखित ब्राउज़र w / मौजूदा टाइमस्टैम्प और आउटपुट संसाधन में स्थानीय संसाधन # के लिए प्रस्तुत किया जाना चाहिए:

loading page
calling run_background_process
  foreground start time = 1266003600
  foreground end time = 1266003600
output = Array
(
    [0] => 15010
)
end of page

आपको उसी निर्देशिका में testoutput.php देखना चाहिए, क्योंकि उपरोक्त फाइलें बचाई गई थीं, और यह खाली होनी चाहिए

आपको एक ही निर्देशिका में testprocesses.php देखना चाहिए क्योंकि उपरोक्त फाइलें बचाई गई थीं, और इसमें निम्नलिखित पाठ w / वर्तमान टाइमस्टैम्प शामिल होना चाहिए:

foreground start time = 1266003600
foreground end time = 1266003600
background start time = 1266003600
background end time = 1266003610

10

यदि आपको PHP पृष्ठ के बिना पृष्ठभूमि में कुछ करने की आवश्यकता है, तो इसके पूरा होने की प्रतीक्षा में, आप एक और (पृष्ठभूमि) PHP स्क्रिप्ट का उपयोग कर सकते हैं जो कि wget कमांड के साथ "आह्वान" है। यह पृष्ठभूमि PHP स्क्रिप्ट विशेष रूप से आपके सिस्टम पर किसी भी अन्य PHP स्क्रिप्ट के रूप में, विशेषाधिकारों के साथ निष्पादित की जाएगी।

यहां विंडोज पर एक उदाहरण दिया गया है जिसमें gnuwin32 पैकेज के wget का उपयोग किया गया है।

एक एक्जम्पल के रूप में बैकग्राउंड कोड (फाइल टेस्ट-प्रोक- bg.php) ...

sleep(5);   // some delay
file_put_contents('test.txt', date('Y-m-d/H:i:s.u')); // writes time in a file

अग्रभूमि स्क्रिप्ट, एक आह्वान ...

$proc_command = "wget.exe http://localhost/test-proc-bg.php -q -O - -b";
$proc = popen($proc_command, "r");
pclose($proc);

इसके ठीक से काम करने के लिए आपको पोपेन / पिलोज़ का उपयोग करना चाहिए।

Wget विकल्प:

-q    keeps wget quiet.
-O -  outputs to stdout.
-b    works on background

7

यहाँ PHP में एक पृष्ठभूमि प्रक्रिया शुरू करने के लिए एक समारोह है। अंत में एक बनाया जो वास्तव में विंडोज पर काम करता है, बहुत सारे पढ़ने और विभिन्न दृष्टिकोणों और मापदंडों का परीक्षण करने के बाद।

function LaunchBackgroundProcess($command){
  // Run command Asynchroniously (in a separate thread)
  if(PHP_OS=='WINNT' || PHP_OS=='WIN32' || PHP_OS=='Windows'){
    // Windows
    $command = 'start "" '. $command;
  } else {
    // Linux/UNIX
    $command = $command .' /dev/null &';
  }
  $handle = popen($command, 'r');
  if($handle!==false){
    pclose($handle);
    return true;
  } else {
    return false;
  }
}

नोट 1: खिड़कियों पर, /Bजैसा कि कहीं और सुझाया गया है, पैरामीटर का उपयोग न करें । यह उसी कंसोल विंडो को startकमांड के रूप में चलाने के लिए प्रक्रिया को बाध्य करता है, जिसके परिणामस्वरूप प्रक्रिया को सिंक्रोनस रूप से संसाधित किया जाता है। प्रक्रिया को एक अलग थ्रेड (अतुल्यकालिक) में चलाने के लिए, उपयोग न करें/B

नोट 2: खाली डबल कोट्स start ""आवश्यक होने के बाद यदि कमांड एक उद्धृत पथ है। startकमांड पहले उद्धृत पैरामीटर को विंडो शीर्षक के रूप में व्याख्या करता है।


6

वैसे मुझे उपयोग करने के लिए थोड़ा तेज और आसान संस्करण मिला

shell_exec('screen -dmS $name_of_screen $command'); 

और यह काम करता है।


@ Alpha.Dev मैंने इसे linux पर परीक्षण किया है केवल मुझे नहीं पता कि यह किसी अन्य sytem पर काम करने वाला है।
Morfidon

4

क्या आप एक अलग प्रक्रिया को कांटा करने की व्यवस्था कर सकते हैं, और फिर अपनी कॉपी को पृष्ठभूमि में चला सकते हैं? जब से मैंने कोई PHP किया है तब से यह एक समय हो गया है, लेकिन फ़ंक्शन pcntl-fork आशाजनक लग रहा है।


यह प्रश्न का उत्तर प्रदान नहीं करता है। किसी लेखक से स्पष्टीकरण मांगने या उसका अनुरोध करने के लिए, उनके पोस्ट के नीचे एक टिप्पणी छोड़ दें।
रिजिराज १२

13
धन्यवाद - टिप्पणियाँ '08 में मौजूद नहीं थीं, लेकिन मैं इसे ध्यान में रखूंगा :)
मैट शेपर्ड

4

अपने प्रोग्राम को पृष्ठभूमि में चलाने के लिए इस फ़ंक्शन का उपयोग करें। यह क्रॉस-प्लेटफॉर्म और पूरी तरह से अनुकूलन योग्य है।

<?php
function startBackgroundProcess(
    $command,
    $stdin = null,
    $redirectStdout = null,
    $redirectStderr = null,
    $cwd = null,
    $env = null,
    $other_options = null
) {
    $descriptorspec = array(
        1 => is_string($redirectStdout) ? array('file', $redirectStdout, 'w') : array('pipe', 'w'),
        2 => is_string($redirectStderr) ? array('file', $redirectStderr, 'w') : array('pipe', 'w'),
    );
    if (is_string($stdin)) {
        $descriptorspec[0] = array('pipe', 'r');
    }
    $proc = proc_open($command, $descriptorspec, $pipes, $cwd, $env, $other_options);
    if (!is_resource($proc)) {
        throw new \Exception("Failed to start background process by command: $command");
    }
    if (is_string($stdin)) {
        fwrite($pipes[0], $stdin);
        fclose($pipes[0]);
    }
    if (!is_string($redirectStdout)) {
        fclose($pipes[1]);
    }
    if (!is_string($redirectStderr)) {
        fclose($pipes[2]);
    }
    return $proc;
}

ध्यान दें कि कमांड शुरू होने के बाद, डिफ़ॉल्ट रूप से यह फ़ंक्शन रनिंग प्रक्रिया की गति और गति को बंद कर देता है। आप $ redirectStdout और $ redirectStderr तर्कों के माध्यम से कुछ फ़ाइल में प्रोसेस आउटपुट को रीडायरेक्ट कर सकते हैं।

विंडोज उपयोगकर्ताओं के लिए ध्यान दें:
आप nulनिम्नलिखित तरीके से stdout / stderr को पुनर्निर्देशित नहीं कर सकते हैं :

startBackgroundProcess('ping yandex.com', null, 'nul', 'nul');

हालाँकि, आप ऐसा कर सकते हैं:

startBackgroundProcess('ping yandex.com >nul 2>&1');

* निक्स उपयोगकर्ताओं के लिए नोट्स:

1) यदि आप वास्तविक पीआईडी ​​प्राप्त करना चाहते हैं, तो निष्पादन शेल कमांड का उपयोग करें:

$proc = startBackgroundProcess('exec ping yandex.com -c 15', null, '/dev/null', '/dev/null');
print_r(proc_get_status($proc));

2) यदि आप अपने प्रोग्राम के इनपुट में कुछ डेटा पास करना चाहते हैं, तो $ stdin तर्क का उपयोग करें:

startBackgroundProcess('cat > input.txt', "Hello world!\n");

3

आप रेसक्यू की तरह एक कतार प्रणाली की कोशिश कर सकते हैं । फिर आप एक नौकरी उत्पन्न कर सकते हैं, जो सूचना को संसाधित करता है और "प्रसंस्करण" छवि के साथ काफी तेजी से वापसी करता है। इस दृष्टिकोण के साथ आप यह नहीं जान पाएंगे कि यह कब समाप्त हो गया है।

यह समाधान बड़े पैमाने पर अनुप्रयोगों के लिए अभिप्रेत है, जहाँ आप नहीं चाहते कि आपके सामने की मशीनें भारी उठाने का काम करें, इसलिए वे उपयोगकर्ता अनुरोधों को संसाधित कर सकते हैं। इसलिए यह फ़ाइलों और फ़ोल्डरों जैसे भौतिक डेटा के साथ काम कर सकता है या नहीं कर सकता है, लेकिन अधिक जटिल तर्क या अन्य अतुल्यकालिक कार्यों (यानी नए पंजीकरण मेल) के प्रसंस्करण के लिए यह बहुत अच्छा है और बहुत ही स्केलेबल है।


2

विंडोज और लिनक्स दोनों के लिए एक कार्य समाधान। My github पेज पर और अधिक जानकारी प्राप्त करें ।

function run_process($cmd,$outputFile = '/dev/null', $append = false){
                    $pid=0;
                if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
                        $cmd = 'wmic process call create "'.$cmd.'" | find "ProcessId"';
                        $handle = popen("start /B ". $cmd, "r");
                        $read = fread($handle, 200); //Read the output 
                        $pid=substr($read,strpos($read,'=')+1);
                        $pid=substr($pid,0,strpos($pid,';') );
                        $pid = (int)$pid;
                        pclose($handle); //Close
                }else{
                    $pid = (int)shell_exec(sprintf('%s %s %s 2>&1 & echo $!', $cmd, ($append) ? '>>' : '>', $outputFile));
                }
                    return $pid;
            }
            function is_process_running($pid){
                if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
                        //tasklist /FI "PID eq 6480"
                    $result = shell_exec('tasklist /FI "PID eq '.$pid.'"' );
                    if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
                        return true;
                    }
                }else{
                    $result = shell_exec(sprintf('ps %d 2>&1', $pid));
                    if (count(preg_split("/\n/", $result)) > 2 && !preg_match('/ERROR: Process ID out of range/', $result)) {
                        return true;
                    }
                }
                return false;
            }
            function stop_process($pid){
                    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
                            $result = shell_exec('taskkill /PID '.$pid );
                        if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
                            return true;
                        }
                    }else{
                            $result = shell_exec(sprintf('kill %d 2>&1', $pid));
                        if (!preg_match('/No such process/', $result)) {
                            return true;
                        }
                    }
            }

2

इस उत्तर के लिए धन्यवाद : पृष्ठभूमि प्रक्रिया को चलाने के लिए एक आदर्श उपकरण सिम्फनी प्रोसेस घटक होगा , जो proc_*कार्यों पर आधारित है, लेकिन इसका उपयोग करना बहुत आसान है। अधिक जानकारी के लिए इसके प्रलेखन देखें ।


1

एक पृष्ठभूमि प्रक्रिया शुरू करने के बजाय, एक ट्रिगर फ़ाइल बनाने और क्रॉन या ऑटोसेयर्स जैसे अनुसूचक होने के कारण क्या समय-समय पर एक स्क्रिप्ट को निष्पादित किया जाता है जो ट्रिगर फ़ाइलों पर दिखता है और कार्य करता है? ट्रिगर में निर्देश या यहां तक ​​कि कच्चे कमांड (बेहतर अभी तक, बस इसे एक शेल स्क्रिप्ट बना सकते हैं) हो सकते हैं।



1

मैं बहुत उपयोग कर रहा हूं fast_cgi_finish_request()

एक क्लोजर और register_shutdown_function () के साथ संयोजन में

$message ='job executed';
$backgroundJob = function() use ($message) {
     //do some work here
    echo $message;
}

फिर शटडाउन से पहले निष्पादित होने के लिए इस क्लोजर को पंजीकृत करें।

register_shutdown_function($backgroundJob);

अंत में जब ग्राहक को प्रतिक्रिया भेजी गई तो आप ग्राहक से कनेक्शन बंद कर सकते हैं और PHP प्रक्रिया के साथ काम करना जारी रख सकते हैं:

fast_cgi_finish_request();

बंद को निष्पादित किया जाएगा fast_cgi_finish_request के बाद।

$ संदेश कभी भी दिखाई नहीं देगा। और आप जितने चाहें उतने क्लोजर रजिस्टर कर सकते हैं, लेकिन स्क्रिप्ट के निष्पादन के समय का ध्यान रखें। यह तभी काम करेगा जब PHP तेज़ CGI मॉड्यूल के रूप में चल रहा हो (क्या यह सही था ?!


0

PHP स्क्रिप्टिंग अन्य डेस्कटॉप एप्लिकेशन डेवलपिंग लैंग्वेज की तरह नहीं है। डेस्कटॉप एप्लिकेशन भाषाओं में हम एक पृष्ठभूमि प्रक्रिया को चलाने के लिए डेमन थ्रेड्स सेट कर सकते हैं लेकिन PHP में एक पेज के लिए उपयोगकर्ता का अनुरोध करने पर एक प्रक्रिया उत्पन्न हो रही है। हालाँकि, सर्वर की क्रोन जॉब कार्यक्षमता का उपयोग करके एक बैकग्राउंड जॉब सेट करना संभव है जो php स्क्रिप्ट चलता है।


0

विंडोज का उपयोग करने वाले लोगों के लिए , इसे देखें:

संदर्भ: http://php.net/manual/en/function.exec.php#43917

मैं भी विंडोज में पृष्ठभूमि में चलाने के लिए एक कार्यक्रम प्राप्त करने के साथ कुश्ती करता हूं, जबकि स्क्रिप्ट निष्पादित करना जारी रखता है। अन्य समाधानों के विपरीत यह विधि आपको किसी भी कार्यक्रम को न्यूनतम, अधिकतम या बिना किसी खिड़की के शुरू करने की अनुमति देती है। llbra @ phpbrasil का समाधान काम करता है लेकिन यह कभी-कभी डेस्कटॉप पर एक अवांछित खिड़की का निर्माण करता है जब आप वास्तव में कार्य को छिपाना चाहते हैं।

Notepad.exe को पृष्ठभूमि में छोटा करें:

<?php 
$WshShell = new COM("WScript.Shell"); 
$oExec = $WshShell->Run("notepad.exe", 7, false); 
?> 

पृष्ठभूमि में एक शेल कमांड अदृश्य शुरू करें:

<?php 
$WshShell = new COM("WScript.Shell"); 
$oExec = $WshShell->Run("cmd /C dir /S %windir%", 0, false); 
?> 

MSPaint को प्रारंभ करें और स्क्रिप्ट जारी रखने से पहले इसे बंद करने के लिए प्रतीक्षा करें:

<?php 
$WshShell = new COM("WScript.Shell"); 
$oExec = $WshShell->Run("mspaint.exe", 3, true); 
?> 

रन पर अधिक जानकारी के लिए () विधि पर जाएं: http://msdn.microsoft.com/library/en-us/script56/html/wsMthRun.asp

संपादित URL:

इसके बजाय https://technet.microsoft.com/en-us/library/ee156605.aspx पर जाएं क्योंकि लिंक ऊपर मौजूद नहीं है।


1
इस कोड को चलाने के लिए क्या करना होगा? मुझे मिलता हैFatal error: Class 'COM' not found
अल्फ.डेव

MSDN से Ps लिंक टूटा हुआ है
Alph.Dev

@ Alph.Dev: एमएसडीएन डॉक्टर को अस्थायी रूप से हटा दिया गया लगता है। इसमें WScript.Shell का उपयोग करने के अधिक उदाहरण और स्पष्टीकरण शामिल थे।
जिमी इलेनॉला

@ Alph.Dev: वर्ग COM के लिए नहीं मिला, यह पूरी तरह से एक और बात है। Google पर देखें। आप इस php.net/manual/en/com.installation.php
जिमी इलेनॉला

@ Alph.Dev कृपया रन () फ़ंक्शन के लिए अद्यतन जानकारी के लिए Technet.microsoft.com/en-us/library/ee156605.aspx चेक करें () फ़ंक्शन
जिमी इलेनॉला

-12

मुझे पता है कि यह एक 100 साल पुरानी पोस्ट है, लेकिन वैसे भी, यह किसी के लिए उपयोगी हो सकता है। आप पृष्ठ पर कहीं एक अदृश्य छवि रख सकते हैं जो url की ओर इशारा करती है जिसे पृष्ठभूमि में चलाने की आवश्यकता है, जैसे:

<img src="run-in-background.php" border="0" alt="" width="1" height="1" />


12
वास्तव में बुरा समाधान। यदि उपयोगकर्ता पृष्ठ छोड़ देगा तो प्रक्रिया बाधित होगी।
सेर्गेई पी। उर्फ ​​अजुर

3
"अदृश्य छवि" और इसका लिंक पृष्ठ स्रोत कोड में उजागर किया गया है।
टोनी गिल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.