I think you should not rely on the connection_aborted () function: there are some user reports ( https://stackoverflow.com/a/16577/... , An alternative to the PHP connection_aborted () function , that it is unreliable. Also consider situations when a network timeout occurs.
I propose another idea, which, in my opinion, is more reliable. It is simple: send XML data to the client, and then wait a while for confirmation: the client sends another HTTP request with confirmation when the data was received. After this confirmation, you can complete the transaction. In case of timeout - rollback.
This idea requires minor changes in server php and client code.
Changed your PHP code (test1.php):
ob_end_clean(); header("Connection: close"); ignore_user_abort(true); ob_start(); echo $response->asXML(); $size = ob_get_length(); header("Content-Length: $size"); // *** added lines *** $serial = rand(); $memcache_obj = memcache_connect('localhost', 11211); $memcache_obj->set("test1.$serial", 0); header("X-test1-serial: $serial"); // *** ob_end_flush(); flush(); // *** changed code *** $ok = 0; $tmout = 10*1000; // timeout in milliseconds // wait until confirmation flag changes to 1 or timeout occurs while (!($ok = intval($memcache_obj->get("test1.$serial")))) { if (connection_aborted()) break; // then no wait if (($tmout = $tmout - 10) <= 0) break; usleep(10000); // wait 10 milliseconds } $memcache_obj->delete("test1.$serial"); if ($ok) { error_log('User informed'); // commit transaction } else { error_log('Timeout'); // rollback transaction }
Code that processes client confirmation (user_ack.php):
<?php header("Content-type: text/plain; charset=utf-8"); $serial = intval($_GET['serial']); $memcache_obj = memcache_connect('localhost', 11211); $memcache_obj->replace("test1.$serial", 1); echo $serial;
And finally, the client code (test1.html) to check:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>Test connection</title> <script type="text/javascript"> function user_ack(serial) { var httpReq = new XMLHttpRequest(); httpReq.open("GET", "user_ack.php?serial=" + encodeURIComponent(serial), true); httpReq.onreadystatechange = function () { if (httpReq.readyState == 4) { if (httpReq.status == 200) { </script> </head> <body> <p>XML from server:</p> <div id="xml"></div> <p>Confirmation serial: <span id="ack"></span></p> <p><input type="button" value="XML download test" onclick="get_xml();"/></p> </body> </html>
I use memcached to store the value of the confirmation flag for the connection between test1.php and user_ack.php. This value name must be unique for each connection, so I use $serial = rand(); to generate a name: "test1.$serial" . When the created confirmation flag has a value of 0. After confirmation of user_ack.php change the value to 1.
Since user_ack.php must be the name of the flag value, the client sends an acknowledgment with a $ serial value. The $ serial value is received by the form server in a custom HTTP header: X-test1-serial when receiving XML.
I use memcache for simplicity. The MySQL table used for this purpose can also be used.