Bir bağlantıyı nasıl erken kapatırım?


99

Oldukça uzun bir süreci başlatacak bir AJAX çağrısı (JQuery aracılığıyla) yapmaya çalışıyorum. Komut dosyasının yalnızca işlemin başladığını belirten bir yanıt göndermesini istiyorum, ancak JQuery, PHP betiği çalışması bitene kadar yanıtı döndürmeyecek.

Bunu bir "kapat" başlığıyla (aşağıda) ve ayrıca çıktı tamponlamasıyla denedim; hiçbiri işe yaramıyor gibi görünüyor. Tahmin var mı? yoksa bu JQuery'de yapmam gereken bir şey mi?

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

?>

çıktı tamponunuzu ob_flush () ile temizlediniz ve çalışmadı mı?
Vinko Vrsalovic

Yanıtlar:


87

Aşağıdaki PHP kılavuz sayfası (kullanıcı notları dahil), PHP betiğini sonlandırmadan tarayıcıya olan TCP bağlantısının nasıl kapatılacağına dair birçok talimat önerir:

Sözde yakın bir başlık göndermekten biraz daha fazlasını gerektiriyor.


OP daha sonra onaylar: evet, bu hile yaptı: buraya kopyalanan 71172 numaralı (Kasım 2006) kullanıcı notunu işaret ederek :

Php betiğinizi çalışır durumda tutarken kullanıcıların tarayıcı bağlantısını kapatmak, [PHP] 4.1'den beri, davranışının register_shutdown_function()kullanıcıların bağlantısını otomatik olarak kapatmayacak şekilde değiştirildiği zamandan beri bir sorundur .

sts at mail dot xubion dot hu Orijinal çözümü yayınladı:

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

Hangi yerine kadar para cezası işleri phpinfo()için echo('text I want user to see');bu durumda başlıklar gönderilen asla!

Çözüm, başlık bilgilerinizi göndermeden önce çıktı arabelleğini açıkça kapatmak ve arabelleği temizlemektir. Misal:

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

Bunu anlamaya çalışmak için 3 saat harcadım, umarım birine yardımcı olur :)

Test edilen yer:

  • IE 7.5730.11
  • Mozilla Firefox 1.81

Daha sonra, Temmuz 2010'da ilgili bir cevapta Arctic Fire daha sonra takipleri olan iki kullanıcı notunu yukarıdakine bağladı:



1
Yazar ve @ Timbo White, İçeriğin boyutunu bilmeden bağlantıyı erken kapatmak mümkün müdür? IE, kapanıştan önce içerik yakalamak zorunda kalmadan.
skibulk

3
Bilgisayar korsanları ve berbat web tarayıcıları, bağlantıyı kapatan HTTP başlığını görmezden gelebilir ve çıktının geri kalanını alabilir. Bundan sonra olanın hassas olmadığından emin olun. belki bir ob_start (); her şeyi bastırmak için: p
hanshenrik

3
Fastcgi_finish_request () ekleniyor; Yukarıdakiler çalışmadığında bağlantıyı başarıyla kapattığı söyleniyor. Ancak benim durumumda betiğimin yürütülmeye devam etmesini engelledi, bu yüzden dikkatli kullanın.
Eric Dubé

@RichardSmith Çünkü Connection: closeüstbilgi yığındaki diğer yazılımlar tarafından üzerine yazılabilir, örneğin, bir CGI durumunda ters proxy (bu davranışı nginx ile gözlemledim). Bu konuda @hanshenrik'in cevabına bakın. Genelde Connection: closemüşteri tarafında yürütülür ve bu soruya cevap olarak düşünülmemelidir. Bağlantı sunucu tarafından kapatılmalıdır .
7heo.tk

56

Bu 2 başlığı göndermek gerekiyor:

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

Çıktınızın boyutunu bilmeniz gerektiğinden, çıktınızı arabelleğe almanız ve ardından tarayıcıya boşaltmanız gerekir:

// 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 ********/

Ayrıca, web sunucunuz çıktıda otomatik gzip sıkıştırması kullanıyorsa (örn. Mod_deflate ile Apache), çıktının gerçek boyutu değiştiğinden ve İçerik Uzunluğu artık doğru olmadığından bu işe yaramaz. Belirli betiğin gzip sıkıştırmasını devre dışı bırakın.

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


16
Sunucunuz çıktıyı sıkıştırırsa, bu şekilde devre dışı bırakabilirsiniz header("Content-Encoding: none\r\n");apache onu sıkıştırmaz.
GDmac

1
@GDmac teşekkür ederim! Bunu bir süre çalıştıramadım, ancak sıkıştırmayı devre dışı bırakmak hile yaptı.
Reactgular

ob_flush()Gerekli değildir ve aslında bir uyarı neden olur failed to flush buffer. Onu çıkardım ve bu harika çalıştı.
Levi

2
Ben bulundu ob_flush()çizgi oldu gerekli.
Deebster

21

fastcgi_end_request()Fonksiyonu kullanmak için Fast-CGI'yi PHP-FPM ile kullanabilirsiniz . Bu şekilde, yanıt istemciye zaten gönderilmişken bazı işlemler yapmaya devam edebilirsiniz.

Bunu PHP kılavuzunda bulabilirsiniz: FastCGI Process Manager (FPM) ; Ancak bu işlev özellikle kılavuzda daha fazla belgelenmemiştir. PHP-FPM'den alıntı : PHP FastCGI Process Manager Wiki :


fastcgi_finish_request ()

Kapsam: php işlevi

Kategori: Optimizasyon

Bu özellik, bazı php sorgularının uygulanmasını hızlandırmanızı sağlar. Komut dosyası yürütme sürecinde sunucu yanıtını etkilemeyen eylemler olduğunda hızlanma mümkündür. Örneğin, oturumun memcached'e kaydedilmesi, sayfa oluşturulduktan ve bir web sunucusuna geçtikten sonra gerçekleşebilir. fastcgi_finish_request()yanıt çıktısını durduran bir php özelliğidir. Web sunucusu anında istemciye "yavaşça ve ne yazık ki" yanıt aktarmaya başlar ve php aynı zamanda bir sorgu bağlamında oturumu kaydetme, indirilen videoyu dönüştürme, her türlü işleme gibi birçok yararlı şey yapabilir. istatistik vb.

fastcgi_finish_request() kapatma işlevini çalıştırmayı başlatabilir.


Not: fastcgi_finish_request() sahip bir cilvesi aramaları için flush, printya da echoerken senaryoyu sonlandırır.

Bu sorunu önlemek için, görüşmeden ignore_user_abort(true)hemen önce veya sonra fastcgi_finish_requestarayabilirsiniz:

ignore_user_abort(true);
fastcgi_finish_request();

3
BU GERÇEK CEVAP!
Kirill Titov

2
php-fpm kullanıyorsanız - sadece bu işlevi kullanın - başlıkları ve diğer her şeyi unutun. Bana çok zaman kazandırdı!
Ross

17

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

hangi anlamda tamamlandı? Hangi problem kabul edilen cevaplar komut dosyasını tamamlamanızı gerektiriyordu (hangisi?) Ve konfigürasyon farklarınızdan hangisi bunu gerekli kıldı?
hakre

4
bu satır: başlık ("İçerik Kodlaması: yok"); -> çok önemli.
Bobby Tablolar

2
Teşekkürler, bu sayfadaki tek çalışan çözüm budur. Bu cevap olarak onaylanmalıdır.

6

Daha iyi bir çözüm, bir arka plan sürecini çatallamaktır. Unix / linux üzerinde oldukça basittir:

<?php
echo "We'll email you as soon as this is done.";
system("php somestuff.php dude@thatplace.com >/dev/null &");
?>

Daha iyi örnekler için bu soruya bakmalısınız:

PHP bir arka plan işlemi yürütür


4

Bir Linux sunucunuz ve kök erişiminiz olduğunu varsayarsak, bunu deneyin. Bulduğum en basit çözüm bu.

Aşağıdaki dosyalar için yeni bir dizin oluşturun ve ona tam izinler verin. (Daha sonra daha güvenli hale getirebiliriz.)

mkdir test
chmod -R 777 test
cd test

Bunu adlı bir dosyaya koyun bgping.

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

Not &. Geçerli işlem echo komutuna ilerlerken ping komutu arka planda çalışacaktır. Yaklaşık 15 saniye sürecek olan 15 kez www.google.com'a ping atacaktır.

Çalıştırılabilir hale getirin.

chmod 777 bgping

Bunu adlı bir dosyaya koyun 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";

?>

Tarayıcınızda bgtest.php talebinde bulunduğunuzda, ping komutunun tamamlanması için yaklaşık 15 saniye beklemeden aşağıdaki yanıtı hızlı bir şekilde almalısınız.

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

result:0
end bgtest.php

Ping komutu şimdi sunucuda çalışıyor olmalıdır. Ping komutu yerine bir PHP betiği çalıştırabilirsiniz:

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

Bu yardımcı olur umarım!


4

İşte Timbo'nun gzip sıkıştırmasıyla çalışan kodunda yapılan bir değişiklik.

// 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 ********/

Sen bir tanrısın Bunu çözmek için 2 gündür çalışıyorum. Yerel geliştiricimde çalıştı, ancak ana bilgisayarda çalışmadı. Ben ıslatılmıştım. BENİ KURTARDIN. TEŞEKKÜR EDERİM!!!!
Chad Caldwell

3

Paylaşılan bir ana bilgisayardayım ve fastcgi_finish_requestkomut dosyalarından tamamen çıkacak şekilde ayarlandım. Ben de connection: closeçözümü sevmiyorum . Bunu kullanmak, sonraki istekler için ayrı bir bağlantıyı zorlar ve ek sunucu kaynaklarına mal olur. Transfer-Encoding: cunked Wikipedia Makalesini okudum ve 0\r\n\r\nbir cevabı sonlandırdığını öğrendim . Bunu tarayıcı sürümlerinde ve cihazlarda tam olarak test etmedim, ancak mevcut 4 tarayıcımın hepsinde çalışıyor.

// Disable automatic compression
// @ini_set('zlib.output_compression', 'Off');
// @ini_set('output_buffering', 'Off');
// @ini_set('output_handler', '');
// @apache_setenv('no-gzip', 1);

// Chunked Transfer-Encoding & Gzip Content-Encoding
function ob_chunked_gzhandler($buffer, $phase) {
    if (!headers_sent()) header('Transfer-Encoding: chunked');
    $buffer = ob_gzhandler($buffer, $phase);
    return dechex(strlen($buffer))."\r\n$buffer\r\n";
}

ob_start('ob_chunked_gzhandler');

// First Chunk
echo "Hello World";
ob_flush();

// Second Chunk
echo ", Grand World";
ob_flush();

ob_end_clean();

// Terminating Chunk
echo "\x30\r\n\r\n";
ob_flush();
flush();

// Post Processing should not be displayed
for($i=0; $i<10; $i++) {
    print("Post-Processing");
    sleep(1);
}

İyi cevabınız sayesinde, bağlantı kullanmanın ne kadar aptalca (ve gereksiz) olduğunu anladım: yakın. Sanırım bazıları sunucularının somun ve cıvatalarına aşina değil.
Justin

@Justin Bunu uzun zaman önce yazdım. Tekrar baktığımda, parçaları 4KB'ye doldurmanın gerekli olabileceğini not etmeliyim. Bazı sunucuların minimum seviyeye ulaşana kadar temizlenmeyeceğini hatırlıyorum.
skibulk

2

Çoklu okuma yapmayı deneyebilirsiniz.

işinizi parametre olarak yapmak için komut dosyasıyla birlikte php ikilisini çağıran ( shell_exec kullanarak ) bir sistem çağrısı yapan bir komut dosyası oluşturabilirsiniz . Ama bunun en güvenli yol olduğunu sanmıyorum. Belki php sürecini ve diğer şeyleri chroot ederek işleri daha da sıkılaştırabilirsiniz.

Alternatif olarak, phpclasslarda http://www.phpclasses.org/browse/package/3953.html bunu yapan bir sınıf vardır . Ama uygulamanın ayrıntılarını bilmiyorum


İşlemin bitmesini beklemek istemiyorsanız &, işlemi arka planda çalıştırmak için karakteri kullanın.
Liam

2

TL; DR Cevap:

ignore_user_abort(true); //Safety measure so that the user doesn't stop the script too early.

$content = 'Hello World!'; //The content that will be sent to the browser.

header('Content-Length: ' . strlen($content)); //The browser will close the connection when the size of the content reaches "Content-Length", in this case, immediately.

ob_start(); //Content past this point...

echo $content;

//...will be sent to the browser (the output buffer gets flushed) when this code executes.
ob_end_flush();
ob_flush();
flush();

if(session_id())
{
    session_write_close(); //Closes writing to the output buffer.
}

//Anything past this point will be ran without involving the browser.

İşlev Cevabı:

ignore_user_abort(true);

function sendAndAbort($content)
{
    header('Content-Length: ' . strlen($content));

    ob_start();

    echo $content;

    ob_end_flush();
    ob_flush();
    flush();
}

sendAndAbort('Hello World!');

//Anything past this point will be ran without involving the browser.

1

Probleminiz php'de bazı paralel programlama yapılarak çözülebilir. Birkaç hafta önce burada bununla ilgili bir soru sordum: PHP uygulamalarında çoklu iş parçacığı nasıl kullanılabilir?

Ve harika cevaplar aldım. Özellikle birini çok beğendim. Yazar PHP'de Easy Parallel Processing (Eylül 2008; johnlim tarafından) öğreticisine atıfta bulundu, bu da probleminizi gerçekten çok iyi çözebilir, çünkü onu birkaç gün önce benzer bir problemle başa çıkmak için zaten kullanmıştım.


1

Joeri Sebrechts'in yanıtı yakın, ancak bağlantıyı kesmeden önce arabelleğe alınabilecek mevcut içeriği yok ediyor. ignore_user_abortDüzgün bir şekilde çağırmaz , betiğin vaktinden önce sonlanmasına izin verir. diyizmin cevabı iyidir, ancak genel olarak uygulanabilir değildir. Örneğin, bir kişi bu cevabın ele almadığı daha fazla veya daha az çıktı tamponuna sahip olabilir, bu nedenle sizin durumunuzda işe yaramayabilir ve nedenini bilemezsiniz.

Bu işlev, istediğiniz zaman (başlıklar henüz gönderilmemişse) bağlantıyı kesmenize izin verir ve şimdiye kadar oluşturduğunuz içeriği 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 belleğe de ihtiyacınız varsa, bu işlevi çağırmadan önce onu ayırın.


1

Mod_fcgid kullanıcıları için not (lütfen kendi sorumluluğunuzda kullanın).

Hızlı Çözüm

Joeri Sebrechts'in kabul edilen yanıtı gerçekten işlevseldir. Ancak mod_fcgid kullanırsanız , bu çözümün kendi kendine çalışmadığını görebilirsiniz. Diğer bir deyişle, flush işlevi çağrıldığında, istemciye olan bağlantı kapanmaz.

FcgidOutputBufferSizeYapılandırma parametresi mod_fcgid suçlu olabilir. Bu ipucunu şurada buldum:

  1. Travers Carter'ın bu yanıtı ve
  2. Seumas Mackinnon'un bu blog yazısı .

Yukarıdakileri okuduktan sonra, hızlı bir çözümün satırı eklemek olacağı sonucuna varabilirsiniz (sondaki "Örnek Sanal Konak" bölümüne bakın):

FcgidOutputBufferSize 0

Apache yapılandırma dosyanızda (örn. httpd.conf), FCGI yapılandırma dosyanızda (örn. fcgid.conf) veya sanal ana bilgisayar dosyanızda (örn. httpd-vhosts.conf).

Yukarıdaki (1) 'de, "OutputBufferSize" adlı bir değişkenden bahsedilmektedir. Bu, FcgidOutputBufferSize(2) ' de bahsedilenin eski adıdır ( mod_fcgid için Apache web sayfasındaki yükseltme notlarına bakın ).

Ayrıntılar ve İkinci Bir Çözüm

Yukarıdaki çözüm, mod_fcgid tarafından ya tüm sunucu ya da belirli bir sanal konak için gerçekleştirilen arabelleğe almayı devre dışı bırakır . Bu, web siteniz için bir performans düşüşüne neden olabilir. Öte yandan, PHP kendi başına arabelleğe alma işlemini gerçekleştirdiği için durum pek de doğru olmayabilir.

Mod_fcgid'in arabelleğini devre dışı bırakmak istemiyorsanız , başka bir çözüm daha var ... bu arabelleği boşaltmaya zorlayabilirsiniz .

Aşağıdaki kod, Joeri Sebrechts tarafından önerilen çözüme dayanarak bunu yapar:

<?php
    ob_end_clean();
    header("Connection: close");
    ignore_user_abort(true); // just to be safe
    ob_start();
    echo('Text the user will see');

    echo(str_repeat(' ', 65537)); // [+] Line added: Fill up mod_fcgi's buffer.

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

Eklenen kod satırının esasen yaptığı şey mod_fcgi'nin tamponunu doldurmak ve böylece onu temizlemeye zorlamaktır. "65537" sayısı FcgidOutputBufferSize, Apache web sayfasında karşılık gelen yönerge için belirtildiği gibi değişkenin varsayılan değeri "65536 " olduğu için seçildi . Bu nedenle, ortamınızda başka bir değer ayarlanmışsa bu değeri buna göre ayarlamanız gerekebilir.

Ortamım

  • WampServer 2.5
  • Apache 2.4.9
  • PHP 5.5.19 VC11, x86, İş Parçacığı Güvenli Değil
  • mod_fcgid / 2.3.9
  • Windows 7 Profesyonel x64

Örnek Sanal Konak

<VirtualHost *:80>
    DocumentRoot "d:/wamp/www/example"
    ServerName example.local

    FcgidOutputBufferSize 0

    <Directory "d:/wamp/www/example">
        Require all granted
    </Directory>
</VirtualHost>

Birçok çözüm denedim. Mod_fcgid ile benim için çalışan tek çözüm budur.
Tsounabe

1

bu benim için çalıştı

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

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

//send length header
header("Content-Length: ".ob_get_length());
header("Connection: close");
//really send content, can't change the order:
//1.ob buffer to normal buffer,
//2.normal buffer to output
ob_end_flush();
flush();
//continue do something on server side
ob_start();
//replace it with the background task
sleep(20);

0

Tamam, temelde jQuery'nin XHR isteğini yerine getirme şekli, ob_flush yöntemi bile çalışmayacaktır çünkü her onreadystatechange'de bir işlev çalıştıramazsınız. jQuery durumu kontrol eder, ardından yapılacak uygun eylemleri seçer (tamamlama, hata, başarı, zaman aşımı). Bir referans bulamasam da, bunun tüm XHR uygulamalarında çalışmadığını duyduğumu hatırlıyorum. Sizin için çalışması gerektiğine inandığım bir yöntem ob_flush ve forever-frame sorgulama arasında bir çaprazlamadır.

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

Ve komut dosyaları satır içi olarak yürütüldüğü için, tamponlar temizlendiğinde, çalıştırılırsınız. Bunu kullanışlı hale getirmek için, console.log'u, verileri almak ve buna göre hareket etmek için ana komut dosyası kurulumunuzda tanımlanan bir geri arama yöntemine değiştirin. Bu yardımcı olur umarım. Şerefe, Morgan.


0

Alternatif bir çözüm, işi bir kuyruğa eklemek ve yeni işleri kontrol eden ve çalıştıran bir cron betiği oluşturmaktır.

Son zamanlarda paylaşılan bir ana bilgisayar tarafından empoze edilen sınırları aşmak için bunu bu şekilde yapmak zorunda kaldım - exec () ve diğerleri, web sunucusu tarafından çalıştırılan PHP için devre dışı bırakıldı, ancak bir kabuk betiğinde çalışabilirdi.


0

Eğer flush()fonksiyon çalışmaz. Php.ini içinde sonraki seçenekleri şu şekilde ayarlamalısınız :

output_buffering = Off  
zlib.output_compression = Off  

0

Son Çalışma Çözümü

    // client can see outputs if any
    ignore_user_abort(true);
    ob_start();
    echo "success";
    $buffer_size = ob_get_length();
    session_write_close();
    header("Content-Encoding: none");
    header("Content-Length: $buffer_size");
    header("Connection: close");
    ob_end_flush();
    ob_flush();
    flush();

    sleep(2);
    ob_start();
    // client cannot see the result of code below

0

Bu iş parçacığından birçok farklı çözümü denedikten sonra (hiçbiri benim için çalışmadıktan sonra), resmi PHP.net sayfasında çözüm buldum:

function sendResponse($response) {
    ob_end_clean();
    header("Connection: close\r\n");
    header("Content-Encoding: none\r\n");
    ignore_user_abort(true);
    ob_start();

    echo $response; // Actual response that will be sent to the user

    $size = ob_get_length();
    header("Content-Length: $size");
    ob_end_flush();
    flush();
    if (ob_get_contents()) {
        ob_end_clean();
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.