Cara menggunakan php proc_get_status

Cara menggunakan php proc_get_status


Saya perlu menjalankan salinan direktori pada tindakan pengguna, tetapi direktori cukup besar, jadi saya ingin dapat melakukan tindakan seperti itu tanpa pengguna menyadari waktu yang dibutuhkan untuk menyalin selesai.

Setiap saran akan sangat dihargai.


Jawaban:


Dengan asumsi ini berjalan pada mesin Linux, saya selalu menanganinya seperti ini:

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

Ini meluncurkan perintah $cmd, mengarahkan output perintah ke $outputfile, dan menulis id proses $pidfile.

Itu memungkinkan Anda memantau dengan mudah apa yang sedang dilakukan dan apakah prosesnya masih berjalan.

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;
}







Tulis proses sebagai skrip sisi-server dalam bahasa apa pun (php / bash / perl / dll) yang berguna dan kemudian panggil dari fungsi kontrol proses di skrip php Anda.

Fungsi ini mungkin mendeteksi jika standar io digunakan sebagai aliran output dan jika itu kemudian yang akan menetapkan nilai kembali .. jika tidak maka itu berakhir

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

Saya menguji ini dengan cepat dari baris perintah menggunakan "sleep 25s" sebagai perintah dan itu bekerja seperti pesona.

( Jawaban ditemukan di sini )




Anda mungkin ingin mencoba menambahkan ini ke perintah Anda

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

misalnya.

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





Saya hanya ingin menambahkan contoh yang sangat sederhana untuk menguji fungsi ini pada Windows:

Buat dua file berikut dan simpan ke direktori web:

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);
?>

Berikan izin IUSR untuk menulis ke direktori tempat Anda membuat file di atas

Berikan izin IUSR untuk MEMBACA dan LAKUKAN C: \ Windows \ System32 \ cmd.exe

Tekan foreground.php dari peramban web

Berikut ini harus diterjemahkan ke browser dengan cap waktu saat ini dan sumber daya lokal # dalam array keluaran:

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

Anda akan melihat testoutput.php di direktori yang sama dengan file di atas disimpan, dan itu harus kosong

Anda akan melihat testprocesses.php di direktori yang sama dengan file di atas disimpan, dan itu harus berisi teks berikut dengan cap waktu saat ini:

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


Jika Anda hanya perlu melakukan sesuatu di latar belakang tanpa halaman PHP menunggu untuk menyelesaikannya, Anda dapat menggunakan skrip PHP lain (latar belakang) yang "dipanggil" dengan perintah wget. Skrip PHP latar belakang ini akan dieksekusi dengan hak istimewa, tentu saja, seperti skrip PHP lainnya di sistem Anda.

Berikut adalah contoh di Windows menggunakan wget dari paket gnuwin32.

Kode latar belakang (file test-proc-bg.php) sebagai contoh ...

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

Skrip latar depan, yang memohon ...

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

Anda harus menggunakan popen / pclose agar ini berfungsi dengan baik.

Opsi wget:

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


Berikut adalah fungsi untuk meluncurkan proses latar belakang di PHP. Akhirnya dibuat satu yang benar-benar berfungsi pada Windows juga, setelah banyak membaca dan menguji berbagai pendekatan dan parameter.

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;
  }
}

Catatan 1: Di windows, jangan gunakan /Bparameter seperti yang disarankan di tempat lain. Ini memaksa proses untuk menjalankan jendela konsol yang sama dengan startperintah itu sendiri, sehingga proses diproses secara serempak. Untuk menjalankan proses di utas terpisah (asinkron), jangan gunakan /B.

Catatan 2: Kutipan ganda kosong setelah start ""diperlukan jika perintahnya adalah path yang dikutip. startperintah menafsirkan parameter yang dikutip pertama sebagai judul jendela.


Yah saya menemukan versi yang sedikit lebih cepat dan lebih mudah digunakan

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

dan itu berhasil.



Bisakah Anda mengatur untuk memotong proses yang terpisah, dan kemudian menjalankan salinan Anda di latar belakang? Sudah lama sejak saya melakukan PHP, tetapi fungsi pcntl-fork terlihat menjanjikan.




Gunakan fungsi ini untuk menjalankan program Anda di latar belakang. Ini lintas platform dan sepenuhnya dapat disesuaikan.

<?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;
}

Perhatikan bahwa setelah perintah dimulai, secara default fungsi ini menutup stdin dan stdout dari proses yang berjalan. Anda dapat mengarahkan proses output ke beberapa file melalui argumen $ redirectStdout dan $ redirectStderr.

Catatan untuk pengguna windows:
Anda tidak dapat mengalihkan stdout / stderr ke nuldengan cara berikut:

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

Namun, Anda dapat melakukan ini:

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

Catatan untuk * nix pengguna:

1) Gunakan perintah exec shell jika Anda ingin mendapatkan PID aktual:

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

2) Gunakan argumen $ stdin jika Anda ingin meneruskan beberapa data ke input program Anda:

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


Anda dapat mencoba sistem antrian seperti Resque . Anda kemudian dapat menghasilkan pekerjaan, yang memproses informasi dan kembali dengan cepat dengan gambar "pemrosesan". Dengan pendekatan ini Anda tidak akan tahu kapan itu selesai.

Solusi ini ditujukan untuk aplikasi berskala lebih besar, di mana Anda tidak ingin alat berat depan Anda melakukan pengangkatan berat, sehingga mereka dapat memproses permintaan pengguna. Karena itu mungkin atau mungkin tidak bekerja dengan data fisik seperti file dan folder, tetapi untuk memproses logika yang lebih rumit atau tugas asinkron lainnya (yaitu email pendaftaran baru) itu bagus untuk dimiliki dan sangat scalable.


Solusi yang berfungsi untuk Windows dan Linux. Temukan lebih banyak di halaman github saya .

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;
                        }
                    }
            }



Alih-alih memulai proses latar belakang, bagaimana dengan membuat file pemicu dan memiliki penjadwal seperti cron atau autosys secara berkala menjalankan skrip yang mencari dan bertindak pada file pemicu? Pemicu bisa berisi instruksi atau bahkan perintah mentah (lebih baik lagi, buat saja skrip shell).



Saya banyak menggunakan fast_cgi_finish_request()

Dalam kombinasi dengan penutupan dan register_shutdown_function ()

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

Kemudian daftarkan penutupan ini untuk dieksekusi sebelum shutdown.

register_shutdown_function($backgroundJob);

Akhirnya ketika respons dikirim ke klien Anda dapat menutup koneksi ke klien dan terus bekerja dengan proses PHP:

fast_cgi_finish_request();

Penutupan akan dieksekusi setelah fast_cgi_finish_request.

$ Message tidak akan terlihat kapan saja. Dan Anda dapat mendaftarkan penutupan sebanyak yang Anda inginkan, tetapi berhati-hatilah dengan waktu eksekusi skrip. Ini hanya akan berfungsi jika PHP dijalankan sebagai modul Fast CGI (benarkah itu ?!)


Scripting PHP tidak seperti bahasa berkembang aplikasi desktop lainnya. Dalam bahasa aplikasi desktop kita dapat mengatur thread daemon untuk menjalankan proses latar belakang tetapi dalam PHP proses terjadi ketika pengguna meminta halaman. Namun dimungkinkan untuk mengatur pekerjaan latar belakang menggunakan fungsionalitas tugas cron server yang dijalankan oleh skrip php.


Bagi kita yang menggunakan Windows , lihat ini:

Referensi: http://php.net/manual/en/function.exec.php#43917

Saya juga bergulat dengan mendapatkan program untuk berjalan di latar belakang di Windows sementara skrip terus dijalankan. Metode ini tidak seperti solusi lain yang memungkinkan Anda untuk memulai program yang diminimalkan, dimaksimalkan, atau tanpa jendela sama sekali. Solusi llbra @ phpbrasil bekerja tetapi terkadang menghasilkan jendela yang tidak diinginkan di desktop ketika Anda benar-benar ingin tugas tersebut dijalankan secara tersembunyi.

mulai Notepad.exe diminimalkan di latar belakang:

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

mulai perintah shell tidak terlihat di latar belakang:

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

mulailah MSPaint dimaksimalkan dan tunggu sampai Anda menutupnya sebelum melanjutkan skrip:

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

Untuk info lebih lanjut tentang metode Run (), buka: http://msdn.microsoft.com/library/en-us/script56/html/wsMthRun.asp

URL yang diedit:

Buka https://technet.microsoft.com/en-us/library/ee156605.aspx sebagai gantinya karena tautan di atas tidak ada lagi.







Saya tahu ini adalah postingan berusia 100 tahun, tetapi bagaimanapun, saya pikir itu mungkin berguna bagi seseorang. Anda dapat meletakkan gambar yang tidak terlihat di suatu halaman di halaman yang menunjuk ke url yang perlu dijalankan di latar belakang, seperti ini:

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