Autor | Zpráva | ||
---|---|---|---|
Pavel Dumbrovský Profil * |
#1 · Zasláno: 30. 8. 2009, 11:32:54
Zdravím,
udělal jsem si malej skriptít na pusunovaní pořadí fotoalb. Jednoduše kliknu že chci aby se jedno album posunulo o úroveň vejš, tak to tomu albu dá v databázi pořadí - 1 a albu který tam stálo předtím to dá pořadí + 1. Pro identifikaci konkrétního alba přitom beru proměnnou z adresy přes get. Jak ale zabránit tomu, když by uživatel aktualizoval stránku, aby se skript neprovedl znovu? |
||
Philber Profil |
#2 · Zasláno: 30. 8. 2009, 11:46:13
třeba po každém vykonání skriptu, nebo spíš při každém načtení stránky smazat proměnné v kterých se tato informace posílá
unset($promenna) |
||
AM_ Profil |
#3 · Zasláno: 30. 8. 2009, 11:48:07
Já to obvykle řeším tak, že data zasílám pouze skriptu, který je na serveru zpracuje (tedy upraví databázi) a následně se přes header("location: ...") přesměruje (zpět) na požadovanou stránku. Považuji to za logicky nejčistší, protože tím oddělíš požadavek na změnu databáze a požadavek na aktualizovanou stránku a při stisknutí F5 se požadavek na databázi znovu neprovede.
|
||
AM_ Profil |
#4 · Zasláno: 30. 8. 2009, 11:50:02
Philber
Při F5 se ale zašle nový požadavek (stejný jako ten předtím) a kód se spouští znovu se stejnými parametry, tak jaký smysl má mazat proměnné v PHP skriptu, který je v době stisknutí F5 dávno ukončený. |
||
Pavel Dumbrovský Profil |
#5 · Zasláno: 30. 8. 2009, 12:16:38
AM_
Jo, to je řešení, ale zvítězil starej dobrej javascript function run(url) { setTimeout("top.location.replace('" + url + "');",0); } a echo "\n<script>run('/admin/postalbum/');</script>\n"; Dík za radu. |
||
Pavel Dumbrovský Profil |
#6 · Zasláno: 30. 8. 2009, 12:17:58
I když mě tak napadá, kdyby byl někdo hodně rychlej a stihl dát F5 v průběhu skriptu, tak by se to teoreticky mohlo provést dvakrát, nebo ne? To platí i pro header..
|
||
Nox Profil |
#7 · Zasláno: 30. 8. 2009, 12:22:45
Pavel Dumbrovský
A zvítězi proč? Je to celkem krkolomné a nehezké, řešení od AM_ je mnohem lepší A bude fungovat i bez JS |
||
Pavel Dumbrovský Profil |
#8 · Zasláno: 30. 8. 2009, 14:21:22
Tak jsem zjistil, že po dvojkliku se to provede dvakrát, asi sem v rici..
|
||
imploder Profil |
#9 · Zasláno: 30. 8. 2009, 18:00:51 · Upravil/a: imploder
Pavel Dumbrovský
To, co radí AM_, je dobrá věc a u webových aplikací obvyklý postup. Když se vyvolá skript, co provádí nějakou akci, po provedení akce skript prohlížeč přesměruje na jinou URL, která žádnou akci nevyvolává a např. jen zobrazuj určitý pevně daný výsledek (takže při reloadu se nic nezmění a uživatel není zmaten). Pojmenujme si skript provádějící akci "akce.php" a skript, na který se pak přesměruje "vysledek.php". Pak to probíhá nějak takhle: 1. Uživatel klikne na tlačítko a prohlížeč pošle serveru požadavek na skript akce.php se zadanými parametry. Pak čeká na odpověď serveru. 2. Server přijme požadavek a začne vykonávat skript akce.php. Akce se provede a skript nakonec vygeneruje HTTP hlavičku* přesměrovávající na vysledek.php (s parametrem např. uspech=ano, který znamená, že se má objevit zpráva o úspěšném provedení akce). 3. Zatímco se akce prováděla, prohlížeč čekal. Jako první věc v odpovědi dostane přesměrovávací hlavičku. Vyžádá si tedy podle ní vysledek.php?uspech=ano. Od serveru mu dojde zpráva o úspěšném provedení akce a prohlížeč ji zobrazí. *) je to hlavička Location, v php se vygeneruje takhle: header('Location: '.'http://'.$_SERVER['SERVER_NAME'].dirname($_SERVER['PHP_SELF']).'/'."vysledek.php?uspech=ano"); „I když mě tak napadá, kdyby byl někdo hodně rychlej a stihl dát F5 v průběhu skriptu, tak by se to teoreticky mohlo provést dvakrát, nebo ne? To platí i pro header..“ To by se s tím řešením dít nemělo, správně by se akce.php vůbec v adresním řádku nemělo objevit. Prohlížeč čeká na první paket odpovědi a až pak začne překreslovat stránku (dřív nemá z čeho) - a jako první věc mu přijde přesměrovávací hlavička, takže se hned přesměruje. Aspoň tak by to mělo správně fungovat. „Tak jsem zjistil, že po dvojkliku se to provede dvakrát, asi sem v rici..“ Ano, někdy se stává, že požadavek se odešle, ale serveru trvá odpověď dlouho (protože např. skript se dlouho provádí nebo je špatné spojení). Netrpělivý uživatel (který má před sebou pořád původní stránku s formulářem a ve stavovém řádku něco jako "čekám na odpověď...") mezitím zmáčkne tlačítko znovu a tím odešle další, stejný požadavek a to spustí skript na serveru ještě jednou. Tímto způsobem na fórech občas dochází k tzv. double postu, tj. stejný příspěvek se vloží dvakrát. Ochrana proti tomu by byla jednoduchá - skript nedovolí uživateli vložil stejný příspěvek na stejné místo, jako poslední, který vložil. Nicméně např. PHPBB ani tohle nemá implementováno, takže se double posty na fórech objevují. V případě, že aplikace musí uživateli umožňovat provést úplně stejnou akci dvakrát po sobě (to je myslím i tvůj případ s posouváním), je potřeba vymyslet lepší ochranu. Můj návrh je takový: Když se vygeneruje formulář na ovládání toho posouvání, vloží se do něj jako skryté pole i náhodně vygenerovaný kód (můžeš použít PHP funkci uniqid). Po odeslání se společně s akcí uloží i ten kód, který s požadavkem přišel). Skript před provedením akce porovná kód přijatý v požadavku s tím uloženým - když budou stejné, akce se neprovede. Stejný kód jako uložený totiž znamená, že od předchozího spuštění skriptu nebyl formulář přegenerován (tj. uživatel podruhé klikl na to tlačítko). Když pak uživatel odešle ten formulář dvakrát (a pokaždé je odeslání úspěšné a skript se na serveru spustí, jenom odpovědi to nějak trvá), akce se provede jenom jednou. Šlo by místo toho javascriptem zabránit v odeslání při druhém kliknutí na tlačítko, ale to není dobré řešení, protože by: 1) znemožnilo odeslání i v případě, že se požadavek např. kvůli výpadku internetu u uživatele nepodařilo odeslat - tohle by uživatele 100% nasralo 2) vyžadovalo javascript |
||
Pavel Dumbrovský Profil |
#10 · Zasláno: 30. 8. 2009, 18:12:06
Díky za vyčerpávající odpověď. Nakonec stejně zůstávám u scriptu:
setTimeout("top.location.replace('" + url + "');",1000); Ještě jednou díky za rady! |
||
Časová prodleva: 15 let
|
0