2

EDITED

I've got an ajax call (using $.ajax()) which calls the following php script.

for ($i=0;$i<40;$i++) {
    echo " ";
    flush();
    if (connection_aborted()) {
        log_message('error','CONNECTION IS ABORTED!!!!!');
        exit;
    }
    else {
        log_message('error','connection not aborted :(');
    }
    sleep(1);
}

This goes for 40 Seconds.

If I close the browser window which triggered the call, connection_aborted() still returns false, even if I sent explicitly a string and flushed the buffer!

Does anyone have an answer here please?

Florian Müller
  • 7,448
  • 25
  • 78
  • 120
  • This is "expected" behaviour, btw. http://www.php.net/manual/en/features.connection-handling.php - "it is only when the the server tries to *send* the buffer content that it will see that the connection is broken". (Emphasis mine). I don't think there's any more powerful function in (portable) PHP. – sourcejedi Jul 24 '12 at 10:10
  • So would it work if I put a `echo " ";` in front of every connection_closed()-check? – Florian Müller Jul 24 '12 at 10:52
  • I think you would at least need flush() as well. – sourcejedi Aug 08 '12 at 08:20
  • 1
    Moreover, if you have caching proxy in front of PHP like nginx, you will not see if connection is aborted in all cases. – Timur Aug 20 '12 at 21:28
  • I don't know that because the server is hosted at a common hoster, it's not mine. – Florian Müller Aug 20 '12 at 21:32
  • @Florian Check headers that are you receiving from server. You can do it sending `HEAD` request in console of your OS or just look at Firebug/Chrome Developer Tools/etc – Timur Aug 20 '12 at 21:37

1 Answers1

7

You will need to add "ignore_user_abort(true);" on top of the PHP script, and to call "ob_flush()" after echoing something from script (For why see PHP flush() man page). Working example (proof of concept):

<?php

ignore_user_abort(true);

function log_message($s, $ss) {
  $myFile = "log.txt";
  $fh = fopen($myFile, 'a') or die("can't open file");
  $stringData = $s . ": " . $ss . "\n";
  fwrite($fh, $stringData);
  fclose($fh);
}



for ($i=0;$i<5;$i++) {

    echo "<br>";
    //flush();
    ob_flush();

    if (connection_aborted()) {
        log_message('error1', connection_status());
        exit;
    }
    else {
        log_message('error2', connection_status());
    }

    sleep(1);
}

P.S. connection_status() returns 0 if connection is still active, and in case of closed one returns 1.

EDIT:

My bad. Call both flush() and ob_flush() (please read flush() man page, link above, and answers from this topic), or otherwise might not work, depending on server/php configuration. The following code was tested on WAMP with PHP 5.3.8 (works without calling flush()), and now on Ubuntu with PHP 5.3.10. where flush() call before ob_flush() is necessary.

Full code for testing:

index.html:

 <html>
  <head>
    <script src="http://code.jquery.com/jquery-1.8.0.min.js"></script>

    <script>

      $(document).ready(function() {

        $.ajax({
          url: "script.php",
          context: document.body
        }).done(function(data) { 
         alert(data);
        });

      })

    </script>

  </head>

  <body>
  </body>

</html>

script.php:

ignore_user_abort(true);

function log_message($type, $message, $file = 'log.txt') {
    $fh = fopen($file, 'a') or die("can't open file");

    $conn_status = connection_status();

    if($conn_status === CONNECTION_NORMAL) {
        $status = 'normal';
    } elseif($conn_status  === CONNECTION_ABORTED) {
         $status = 'aborted';
    } else {
        $status = 'timeout';
    }

    $aborted = connection_aborted() ? 'yes' : 'no';

    $data  = $type . ': ' . $message . "\n";
    $data .= 'Connection status: ' . $status . "\n";
    $data .= 'Aborted: ' . $aborted . "\n\n\n";

    fwrite($fh, $data);
    fclose($fh);
}



for ($i = 0; $i < 10; $i++) {

    echo "<br>";
    flush();
    ob_flush();

    if (connection_aborted()) {
        log_message('Error', 'Connection closed by user!');
        exit;
    }
    else {
        log_message('Info', 'Everything is fine. Move along...');
    }

    sleep(1);
}

After you call index.html page, and close tab or whole browser you should see in log.txt file next info:

Info: Everything is fine. Move along...
Connection status: normal
Aborted: no


Info: Everything is fine. Move along...
Connection status: normal
Aborted: no


Info: Everything is fine. Move along...
Connection status: normal
Aborted: no


Error: Connection closed by user!
Connection status: aborted
Aborted: yes
Community
  • 1
  • 1
Marko Jovanović
  • 2,647
  • 3
  • 27
  • 36
  • First of all, it is better to use `CONNECTION_xxx` constants. Furthermore, `connection_status()` can return 0, 1, 2 and even 3 as result of `CONNECTION_ABORTED|CONNECTION_TIMEOUT`. Manual: http://www.php.net/manual/en/features.connection-handling.php – Timur Aug 20 '12 at 22:40
  • Well, I did not call `ignore_user_abort()` because it seems this is a default setting of my provider. However, I did not try ob_flush(), I will ASAP. **EDIT:** Just tried ob_flush(), did not work either. – Florian Müller Aug 21 '12 at 00:02