ignore_user_abort

Školení, která pořádám

Dopsal jsem knihu

Často potřebujeme zajistit, aby se posloupnost operací vykonala buď celá nebo aby se nevykonala vůbec. Pokud se jedná výhradně o databázové operace, dají se k tomu použít transakce, v obecném případě je ale situace obtížnější. Vzhledem k tomu, že uživatel může vykonávání skriptu kdykoliv jednoduše ukončit zastavením načítání stránky (v prohlížečích k tomu obvykle slouží klávesa Esc a ikona na liště), nejedná se zdaleka o problém pouze teoretický. Operacemi, které chceme vykonat vždy spolu, je např. uložení objednávky a odeslání notifikace o jejím vzniku e-mailem. Pokud se objednávka jenom uloží a nepošle se o ní notifikace, může to znamenat ušlý zisk a naštvaného klienta, opačný případ je ještě horší.

K zabránění zastavení skriptu uživatelem slouží funkce ignore_user_abort. Nepokrývá pochopitelně např. násilné ukončení skriptu příkazem kill, ani v případě přerušení operací nevrátí již provedené změny, ale proti největšímu riziku obranu poskytuje.

<?php
// zde bude příprava dat pro vložení
ignore_user_abort(true); // zakázání přerušení skriptu uživatelem
mysql_query("INSERT INTO objednavky (" . implode(", ", array_keys($set)) . ") VALUES (" . implode(", ", $set) . ")");
$root = "http://$_SERVER[SERVER_NAME]" . substr($_SERVER["PHP_SELF"], 0, strrpos($_SERVER["PHP_SELF"], "/"));
mail($notify_email, "Nova objednavka", "$root/admin/objednavky_1.php?select=" . mysql_insert_id());
?>

Jakýkoliv výstup poslaný po zastavení přenášení stránky se samozřejmě zahodí.

Jakub Vrána, Výuka, 6.3.2006, diskuse: 15 (nové: 0)

Diskuse

lukas:

To jsem ani nevedel, ze uzivatel muze ukoncit skript... skvely clanek...
# 6.3.2006 03:07:04 reagovat

SQi:

Já zas myslel, že tomu nejde zabránit:-0
# 6.3.2006 13:03:49 reagovat

johno:

Takéto prasárne by som najradšej defaultne vypol. Viete si živo predstaviť kedy sa to dá využiť v kladnom slova zmysle?
# 6.3.2006 10:01:19 reagovat

ikona Jakub Vrána:

Nevím, jakou prasárnu máš na mysli, ale smysl funkce ignore_user_abort() je popsán v článku, takže bych řekl, že ti bude vadit výchozí chování "při zastavení požadavku se skript ukončí". To ve většině případů dává dobrý smysl - pokud už uživatel o výstup skriptu nemá zájem, je zbytečné plýtvat procesorovým časem na jeho další běh.
# 6.3.2006 11:02:14 reagovat

ikona llook:

Já bych zase řekl, že ingorováním uživatelského přerušení tam, kde to není potřeba, lze nadělat mnohem méně škody, než naopak.
Málokterá stránka, u které přerušení nevadí, využívá tolik systémových zdrojů, aby se povolením přerušení něco získalo. Takže bych byl spíš pro to, aby naopak programátor PHP sděloval, že "zrovna tento skript se klidně stopnout může".
Čím víc PHP znám, na tím víc věcí mám odlišný názor než PHP Group...
# 6.3.2006 19:22:33 reagovat

johno:

Presne to som tým myslel.
# 6.3.2006 19:39:53 reagovat

Jakub Podhorský:

Jakube nedá se tohodle efektu docílit i uvedením ob_start() na začátku skriptu? (vím že je to prasárna a ta funkce k tomu neslouží, ale neudělá to podobný efekt?)
# 6.3.2006 13:12:07 reagovat

ikona Jakub Vrána:

Neřekl bych, ale můžeš to vyzkoušet.
# 6.3.2006 13:17:58 reagovat

24k:

Jakube trim(); :)
# 6.3.2006 22:25:53 reagovat

Tibor:

..tak toto by mi v zivote nenapadlo ze sa moze stat... Vdaka a rozsirenie obzorov...
# 6.3.2006 23:22:45 reagovat

ikona dgx:

OT: ignoruj uživatelův potrat?
# 7.3.2006 15:39:51 reagovat

ikona spaze:

Já bych jen doplnil connection_status() a "When a PHP script is running normally the NORMAL state, is active. If the remote client disconnects the ABORTED state flag is turned on. A remote client disconnect is usually caused by the user hitting his STOP button. If the PHP-imposed time limit (see set_time_limit()) is hit, the TIMEOUT state flag is turned on."
# 8.3.2006 01:32:45 reagovat

paranoiq:

s pomocí connection_status() lze i ušetřit nějaký ten výkon ztracený povolením ignore_user_abort. v případě že se již user odpojil není třeba vytvářet výstup. pouze doděláte co je třeba (uložení dat do db apod.) a ukončíte script.
# 13.3.2006 12:08:09 reagovat

Honza Odvárko:

Jenom doplním, že podle mého testování, jakmile jednou zavoláte ignore_user_abort(true), už to nelze odvolat voláním ignore_user_abort(false)
# 3.8.2007 20:04:04 reagovat

nedik:

no, tak jsem to vyzkoušel a nefunguje mi to, že když dám stop v prohlížeči, tak se zastaví skript. Skript si prostě běží dál, ať udělám, co udělám. Můžu klidně zavřít prohlížeč, a skript to nijak neovlivní. Tak opravdu nechápu, o čem je vlastně tady řeč.
# 11.7.2008 00:43:49 reagovat

Vložit příspěvek

Používejte diakritiku. Nelze používat HTML značky, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

© 2005-2010 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.