erken bağlantısını kapatmak

12 Cevap php

Ben oldukça uzun bir süreci başlatmaktır (JQuery) bir AJAX arama yapmak için çalışılıyor. Ben komut sadece sürecinin başladığını belirten bir yanıt göndermek istiyorum, ama PHP komut dosyası çalıştıran yapılır kadar JQuery yanıt dönmeyecektir.

Ben bu denedim a (aşağıda) başlık "kapatmak", ve aynı zamanda çıkış tamponlama ile; ne iş gibi görünüyor. Herhangi bir tahmin? ya bu ben JQuery yapmak gereken bir şeydir?

<?php

echo( "We'll email you as soon as this is done." );

header( "Connection: Close" );

// do some stuff that will take a while

mail( 'dude@thatplace.com', "okay I'm done", 'Yup, all done.' );

?>

12 Cevap

Aşağıdaki PHP kılavuzu sayfası (dahil kullanıcı notları) PHP komut dosyası biten olmadan tarayıcı TCP bağlantısını kapatmak için nasıl birden talimatları göstermektedir:

Sözde yakın bir başlık gönderirken biraz daha fazla gerektirir.


OP sonra doğruluyor: yup, this did the trick: pointing to user-note #71172 (Nov 2006) burada kopyalanan:

Php betik çalışmaya korurken kullanıcıların tarayıcı bağlantıyı kapatmadan otomatik olarak kullanıcıların bağlantısını kapatmak olmaz böylece davranış register_shutdown_function() modifiye edilmiştir [PHP] 4,1, beri bir sorun olmuştur.

posta nokta xubion de STS hu orijinal bir çözüm Yayınlanan nokta:

<?php
header("Connection: close");
ob_start();
phpinfo();
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush();
flush();
sleep(13);
error_log("do something in the background");
?>

Eğer phpinfo() echo('text I want user to see'); başlıkları gönderilen asla bu durumda yerine kadar Hangi çalışıyor!

Çözelti açıkça tamponu kapatır ve önce başlık bilgilerini gönderme tampon temizlemek için. Örnek:

<?php
ob_end_clean();
header("Connection: close");
ignore_user_abort(true); // just to be safe
ob_start();
echo('Text the user will see');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // Strange behaviour, will not work
flush(); // Unless both are called !
// Do processing here 
sleep(30);
echo('Text user will never see');
?>

Bu bir anlamaya çalışıyorum sadece harcanan 3 saat, o birisi yardımcı olur umarım :)

: Test edilmiştir

  • IE 7.5730.11
  • Mozilla Firefox 1.81

Daha sonra Temmuz 2010 yılında bir related answer Arctic Fire sonra yukarıdaki birine-up takip edilen iki başka kullanıcı notları bağlantılı:

Bu 2 başlıkları göndermek için gerekli:

Connection: close
Content-Length: n (n = size of output in bytes )

Eğer çıkış boyutunu bilmek gerekir çünkü, size çıkış tampon gerekir, sonra tarayıcıya yıkayın:

// buffer all upcoming output
ob_start();
echo "We'll email you as soon as this is done.";

// get the size of the output
$size = ob_get_length();

// send headers to tell the browser to close the connection
header("Content-Length: $size");
header('Connection: close');

// flush all output
ob_end_flush();
ob_flush();
flush();

// if you're using sessions, this prevents subsequent requests
// from hanging while the background process executes
if (session_id()) session_write_close();

/******** background process starts here ********/

Web sunucusu çıkışı (mod_deflate ile yani Apache) otomatik gzip sıkıştırması kullanılarak ise çıkış gerçek boyutu değişti çünkü Ayrıca, bu işe yaramaz, ve Content-Length artık doğru değildir. Gzip sıkıştırma belli bir script devre dışı bırakın.

Daha fazla ayrıntı için, ziyaret http://www.zulius.com/how-to/close-browser-connection-continue-execution

Tam sürüm:

ignore_user_abort(true);//avoid apache to kill the php running
ob_start();//start buffer output

echo "show something to user";
session_write_close();//close session file on server side to avoid blocking other requests

header("Content-Encoding: none");//send header to avoid the browser side to take content as gzip format
header("Content-Length: ".ob_get_length());//send length header
header("Connection: close");//or redirect to some url: header('Location: http://www.google.com');
ob_end_flush();flush();//really send content, can't change the order:1.ob buffer to normal buffer, 2.normal buffer to output

//continue do something on server side
ob_start();
sleep(5);//the user won't wait for the 5 seconds
echo 'for diyism';//user can't see this
file_put_contents('/tmp/process.log', ob_get_contents());
ob_end_clean();

Eğer bir Linux sunucu ve root erişimi varsayarsak, bu deneyin. Ben bulduk basit bir çözümdür.

Aşağıdaki dosyalar için yeni bir dizin oluşturun ve bunu tüm izinleri verin. (Biz daha sonra daha güvenli hale getirebilirsiniz.)

mkdir test
chmod -R 777 test
cd test

Adlı bir dosyaya koymak bgping.

echo starting bgping
ping -c 15 www.google.com > dump.txt &
echo ending bgping

Note the &. The ping command will run in the background while the current process moves on to the echo command. It will ping www.google.com 15 times, which will take about 15 seconds.

Çalıştırılabilir hale.

chmod 777 bgping

Adlı bir dosyaya koymak bgtest.php.

<?php

echo "start bgtest.php\n";
exec('./bgping', $output, $result)."\n";
echo "output:".print_r($output,true)."\n";
echo "result:".print_r($result,true)."\n";
echo "end bgtest.php\n";

?>

When you request bgtest.php in your browser, you should get the following response quickly, without waiting about 15 seconds for the ping command to complete.

start bgtest.php
output:Array
(
    [0] => starting bgping
    [1] => ending bgping
)

result:0
end bgtest.php

Ping komutu artık sunucu üzerinde çalışan olmalıdır. Bunun yerine ping komutu, bir PHP komut dosyası çalıştırabilir:

php -n -f largejob.php > dump.txt &

Bu yardımcı olur umarım!

Sen fastcgi_end_request() fonksiyonu kullanmak için PHP-FPM'ye Hızlı CGI kullanabilirsiniz. Yanıtı zaten müşteriye gönderilen sırasında bu şekilde, bazı işlem yapmaya devam edebilirsiniz.

Burada PHP kılavuzunda bu bulmak: {[(0)];} Ama bu işlevi özellikle daha kılavuzda belgelenmiş değildir. İşte dan alıntıdır PHP-FPM: PHP FastCGI Process Manager Wiki:


fastcgi_finish_request()

Scope: php function Category: Optimization

Bu özellik, bazı php sorguları uygulanmasını hızlandırmak için olanak sağlar. Sunucu yanıtı etkilemez komut yürütme sürecinde eylemler olduğunda Hızlanma mümkündür. Sayfa oluşturulmuş ve bir web sunucusuna geçti sonra Örneğin, memcached yılında oturumu tasarruf oluşabilir. fastcgi_finish_request() tepki çıkışı durdurur bir php özelliktir. Web sunucu hemen istemciye "yavaş ve ne yazık ki" yanıtını aktarmaya başlar ve aynı zamanda php gibi, oturumu kaydetmeden indirilen video dönüştürme, her türlü taşıma gibi bir sorgu bağlamında, yararlı bir çok şey yapabilir istatistik vs

fastcgi_finish_request() kapatma işlevi yürüttükten çağırabilirsiniz.

Sen çoklu yapmak için deneyebilirsiniz.

Eğer parametre olarak işinizi yapmak için komut dosyası ile php ikilisini çağıran bir sistem çağrısı ({[) (0]} kullanarak) yapan bir komut dosyası kamçılamak olabilir. Ama bu en güvenli yol olduğunu sanmıyorum. Belki php süreci ve diğer şeyler chrooting tarafından eşyalarını thighten olabilir

Alternatif olarak, bunu phpclasses bir sınıf var http://www.phpclasses.org/browse/package/3953.html. Ama uygulama özelliklerini bilmiyorum

İşte gzip sıkıştırma ile çalışır Timbo koduyla bir değişiklik var.

// buffer all upcoming output
if(!ob_start("ob_gzhandler")){
    define('NO_GZ_BUFFER', true);
    ob_start();
}
echo "We'll email you as soon as this is done.";

//Flush here before getting content length if ob_gzhandler was used.
if(!defined('NO_GZ_BUFFER')){
    ob_end_flush();
}

// get the size of the output
$size = ob_get_length();

// send headers to tell the browser to close the connection
header("Content-Length: $size");
header('Connection: close');

// flush all output
ob_end_flush();
ob_flush();
flush();

// if you're using sessions, this prevents subsequent requests
// from hanging while the background process executes
if (session_id()) session_write_close();

/******** background process starts here ********/

Ok, so basically the way jQuery does the XHR request, even the ob_flush method will not work because you are unable to run a function on each onreadystatechange. jQuery checks the state, then chooses the proper actions to take (complete,error,success,timeout). And although I was unable to find a reference, I recall hearing that this does not work with all XHR implementations. A method that I believe should work for you is a cross between the ob_flush and forever-frame polling.

<?php
 function wrap($str)
 {
  return "<script>{$str}</script>";
 };

 ob_start(); // begin buffering output
 echo wrap("console.log('test1');");
 ob_flush(); // push current buffer
 flush(); // this flush actually pushed to the browser
 $t = time();
 while($t > (time() - 3)) {} // wait 3 seconds
 echo wrap("console.log('test2');");
?>

<html>
 <body>
  <iframe src="ob.php"></iframe>
 </body>
</html>

Tamponlar temizlendi gibi komut, satır içi yürütülür çünkü, yürütme olsun. Bu kullanışlı hale getirmek için, veri almak ve bu hareket için size ana komut kurulum tanımlanmış bir geri arama yöntemine console.log değiştirin. Umarım bu yardımcı olur. Şerefe, Morgan.

Alternatif bir çözüm, bir kuyruğa iş eklemek ve yeni işler için denetler ve onları çalıştıran bir cron komut dosyası yapmaktır.

Exec () ve ark web sunucusu tarafından işletilen PHP için devre dışı edildi, ama kabuk içinde çalıştırabilir - Ben paylaşılan bir bilgisayar tarafından dayatılan sınırları aşmak için son zamanlarda bu şekilde yapmak zorunda.

Flush () fonksiyonu işe yaramazsa. Sen gibi php.ini sonraki seçeneklerini ayarlamanız gerekir:

output_buffering = Off
zlib.output_compression = Off

Senin sorunun php bazı paralel programlama yaparak çözülebilir. Ben burada birkaç hafta önce onunla ilgili bir soru sordu: How can one use multi threading in PHP applications

Ve harika cevaplar aldım. Ben çok özel olarak bir sevdim. Ben bir çift kadar geldi benzer bir sorun ile başa çıkmak için zaten kullanılmış gibi aslında çok iyi sorununuzu çözebilir öğretici ; yazar bir referans to the Easy Parallel Processing in PHP (johnlim tarafından Eyl 2008) yapılan gün önce.

Joeri Sebrechts' answer yakındır, ama kesmek isteyen önce tamponlu olabilir varolan herhangi bir içeriği yok. Bu komut erken sonlandırmak için izin, ignore_user_abort düzgün aramıyor. diyism's answer iyi ama genel olarak geçerli değildir. Örneğin Bir kişi bu cevap ele gelmez fazla veya daha az çıktı tamponları olabilir, bu yüzden sadece sizin durumunuzda çalışmayabilir ve neden bilemezsiniz.

Bu fonksiyon (başlıkların henüz gönderilmemiş olan sürece) her zaman kesin sağlar ve şimdiye kadar üretilen ettik içeriğini korur. Ekstra işlem süresi varsayılan olarak sınırsızdır.

function disconnect_continue_processing($time_limit = null) {
    ignore_user_abort(true);
    session_write_close();
    set_time_limit((int) $time_limit);//defaults to no limit
    while (ob_get_level() > 1) {//only keep the last buffer if nested
        ob_end_flush();
    }
    $last_buffer = ob_get_level();
    $length = $last_buffer ? ob_get_length() : 0;
    header("Content-Length: $length");
    header('Connection: close');
    if ($last_buffer) {
        ob_end_flush();
    }
    flush();
}

Ekstra bellek gerekiyorsa da, bu işlevi çağırmadan önce ayrılamadı.