Mehrfach-Funktionsaufruf ?!
gepostet vor 18 Jahre, 6 Monate von Kelturio
Hallo Leutz,
und zwar habe ich zur Zeit ein kleines Problemchen, welches mit dem Aktualisieren Button des Browsers zusammen hängt.
Und zwar habe ich bei meinem Game z.B. Gebäude, die der User bauen kann.
So erfolgt das Problem:
Der User betritt die Seite, auf der er Gebäude bauen kann. Nun klickt dieser auf einen Ausbauen Button.
Die Überprüfung, ob der User den Ausbauen-Button geklickt hat lautet:
if (isset(Button)) dann rufe mir die Baufunktion auf;
Deren Aufruf beinhaltet die logische Folge, dass der Bau des Gebäudes startet und somit der Countdown der Bauzeit startet.
Klickt der User nun auf diesen Aktualisierenbutton des Browsers, so führt es komischerweise wieder die Funktion Bau aus und die Ressourcen werden also wieder erneut abgezogen, der Countdown startet neu etc.
Klickt der User aber nicht auf den Aktualisierenbutton des Browsers, sondern lediglich erneut auf den Link Gebäude (aktualisiert die Page praktisch über diesen Link) dann funktioniert alles wie es sein sollte.
Es funktioniert auch alles wie es sein sollte, wenn der User zwischendurch z.b. die Seite Forschung besucht hat, dann wieder auf die Gebäudeseite geht und dann erst den Aktualisierenbutton benutzt - dann geht auch alles normal.
Wieso wird die Funktion erneut aufgerufen, wenn man den Aktualisierenbutton des Browsers klickt, solange man zwischendurch keine andere Seite besucht hat ? Wie kann ich das unterbinden ?
gepostet vor 18 Jahre, 6 Monate von Kaiser Nero
Das Problem was du hast ist, dass wenn man die Seite aktualisiert alle per , etc gesendeten Daten erneut gesendet werden. (also auch der Auftrag das Gebäude zu bauen)
Frag einfach in deiner Funktion ab, oban dieser Stelle schon ein Gebäude steht oder gebaut wird und gib, falls dies so ist (dein Beispiel, wo es neu gestartet wird) einfach nur den "normalen Kram" aus (Gebäudeinfo / Restzeit / etc) und überspring den teil mit dem Abziehen der Ressourcen etc.
Ich hoffe ich konnte dir helfen.
mfg
gepostet vor 18 Jahre, 6 Monate von abuzeus
Problem:Du sendest mit dem Aktualisierungsbutton die kompeltte http-Anfrage neu, inklusve POST und GET Variablen.
Dein Script prüft nun, ob "Button" gesetzt ist, und genau das ist es ja, weil diese Variable ja mitgeschickt wird. Dein Script stösst nun den Gebäudebau an, und ab gehts.
Klickt er auf "Gebäude", dann wird kein "Button" oder sonstwas mitgesendet und dein Script stösst den Ausbau nicht an. Da dir das nicht aufgefallen ist, ist die Variable vermutlich per POSt übertragen worden.
Lösungsansatz: Prüfe vor jeder Aktion, ob sie im Kontext der aktuellen Spielsituation auch sinnvoll und erlaubt ist, also hier, ob schon gebaut wird. Das solltest du generell immer machen, weil sich so auch Rohstoffe erschummeln lassen oder das Spiel aus dem Kontext bringen lässt (also inkonsistente Daten).
Theoretisch reicht nicht einmal dass, weil sich Anfragen auch überschneiden können (das eine Script hat die Situation noch nicht in der DB verändert, das andere fragt sie ab und geht von falschen äusseren Umständen aus; tritt zB beim schnellen F5 drücken auf oder wenn zwei User gleiche Daten anfordern) aber ein Schutz dagegen ist etwas schwerer.
edit: zu langsam ;-)
gepostet vor 18 Jahre, 6 Monate von Kampfhoernchen
Die Daten werden dann einfach nochmal abgeschickt (Opera benutzt hier einen Cache).
Der Bau darf nicht nochmal angestoßen werden, etwa so:
if(<<>>)
echo "Es wrd schon gebaut";
else
<<< bauen >>>>
gepostet vor 18 Jahre, 6 Monate von BLUESCREEN
Wird der Baubefehl per POST übergeben?
edit: Zu viele Tabs offen...
gepostet vor 18 Jahre, 6 Monate von Kelturio
Ok, vielen Dank. Ihr konntet mir alle schnell, leicht und effektiv helfen.
Thx. ^^
gepostet vor 18 Jahre, 6 Monate von blum
Die eleganteste Methode Formulare zu verarbeiten ist sowieso dafür eine eigene datei zu verwenden.
Beispiel:
Startseite: index.php
in der post.php machst du dann alle abfragen/updates. danach leitest du den benutzer mit header('Location: index.php') wieder zurück.
damit umgehst du das problem mit dem refresh und hast deinen code auch sauberer getrennt.
gepostet vor 18 Jahre, 6 Monate von Kelturio
Hmm, also ich habe es jetzt erst einmal mit dieser Abfrage gelöst, die abfragt, ob bereits was im Bau ist. Der bau startet nun nicht mehr neu etc., also alles ok, aber es ist ein weiterer Schönheitsfehler aufgetreten.
Und zwar startet es bei der Aktualisierung über den Aktualisierenbutton des Browsers nun nicht mehr den Bau neu, aber es wird mit nun immer eine Meldung vom IE angezeigt, dass eine Aktualisierung ohne ein erneutes senden der Daten nicht möglich sei. Dann muss man auf Wiederholen klicken und man wird dann erst zum Spiel zurück geleitet.
Wie kann man das sauberer lösen ?
gepostet vor 18 Jahre, 6 Monate von TheUndeadable
Dies geschieht, wenn der letzte Request ein POST war. Eigentlich auch in anderen Browsern.
Du kannst dies lösen, in dem du am Ende deiner Verarbeitung den Browser auf die Seite selbst umleitest:
if ( $_REQUEST [ 'baue' ] )
{
// hier dein baukram
header ( 'Location: ?evtl Parameter hier' );
die;
}
gepostet vor 18 Jahre, 6 Monate von blum
Original von Kelturio
Hmm, also ich habe es jetzt erst einmal mit dieser Abfrage gelöst, die abfragt, ob bereits was im Bau ist. Der bau startet nun nicht mehr neu etc., also alles ok, aber es ist ein weiterer Schönheitsfehler aufgetreten.
Und zwar startet es bei der Aktualisierung über den Aktualisierenbutton des Browsers nun nicht mehr den Bau neu, aber es wird mit nun immer eine Meldung vom IE angezeigt, dass eine Aktualisierung ohne ein erneutes senden der Daten nicht möglich sei. Dann muss man auf Wiederholen klicken und man wird dann erst zum Spiel zurück geleitet.
Wie kann man das sauberer lösen ?
hab dir die lösung doch genau über deinem post hingeschrieben
gepostet vor 18 Jahre, 6 Monate von BLUESCREEN
Original von blum
Die eleganteste Methode Formulare zu verarbeiten ist sowieso dafür eine eigene datei zu verwenden.
(...)
danach leitest du den benutzer mit header('Location: index.php') wieder zurück.
Das finde ich hässlich, weil man dem User so nicht einfach eine Meldung wie "Gebäude wird gebaut." oder so anzeigen kann.
Das könnte man natürlich auch mit getrennten Dateien realisieren, wäre aber umständlich...
gepostet vor 18 Jahre, 6 Monate von blum
Original von BLUESCREEN
Original von blum
Die eleganteste Methode Formulare zu verarbeiten ist sowieso dafür eine eigene datei zu verwenden.
(...)
danach leitest du den benutzer mit header('Location: index.php') wieder zurück.
Das finde ich hässlich, weil man dem User so nicht einfach eine Meldung wie "Gebäude wird gebaut." oder so anzeigen kann.
Das könnte man natürlich auch mit getrennten Dateien realisieren, wäre aber umständlich...
doch mit session
gepostet vor 18 Jahre, 6 Monate von Kelturio
Original von TheUndeadable
Dies geschieht, wenn der letzte Request ein POST war. Eigentlich auch in anderen Browsern.
Du kannst dies lösen, in dem du am Ende deiner Verarbeitung den Browser auf die Seite selbst umleitest:
if ( $_REQUEST [ 'baue' ] )
{
// hier dein baukram
header ( 'Location: ?evtl Parameter hier' );
die;
}
Habe es nun so gelöst, aber nun zeigt es mir folgenden PHP Fehler an und danach kommt wieder die Explorer Meldung.
Warning: Cannot modify header information - headers already sent by
gepostet vor 18 Jahre, 6 Monate von TheUndeadable
hehe, vorher darfst du natürlich noch nichts ausgegeben haben oder du bufferst deine Ausgabe vorher mit ob_start.
gepostet vor 18 Jahre, 6 Monate von Kaiser Nero
Du benutzt wahrscheinlich:
session_start();
?>
Diesen Befehl musst du ausführen bevor du
.
.
.
machst.
Also.. du machst am besten folgendes:
Du machst in den Seiten wo du es benötigst das ganze am Anfang bevor du irgendwas anders machst:
session_start();
?>
...
...
Hoffe es hilft dir weiter..
mfg
gepostet vor 18 Jahre, 6 Monate von Kelturio
Original von TheUndeadable
hehe, vorher darfst du natürlich noch nichts ausgegeben haben oder du bufferst deine Ausgabe vorher mit ob_start.
Was darf ich noch nicht ausgegeben haben ?
@ Kaiser Nero:
So habe ich es schon von Anfang an gemacht.
gepostet vor 18 Jahre, 6 Monate von Sarge
kein einziges zeichen das das dokument anfängt.
Sobald du ein echo o.ä. hast wurden dem Browser schon die headers gesendet und alles was nun kommt würde er als dokument interpretieren.
gepostet vor 18 Jahre, 6 Monate von Kelturio
Ok, aber wie kann ich es sonst lösen ? Denn die Abfrage muss da in mitten des Quelltextes bleiben.
gepostet vor 18 Jahre, 6 Monate von blum
kelturio, ich rate Dir erstmal php zu lernen, bevor Du Dich an ein Browerspiel wagst.
gepostet vor 18 Jahre, 6 Monate von Kelturio
Wieso rätst du mir gleich wieder PHP zu lernen, wenn ich mal was nicht weiß ?
Man kann ja nicht alles wissen und deshalb frage ich euch hier mal um Hilfe.
Wie gesagt startet es meinen Bau etc. nicht mehr von vorne und zieht mir erneut Ress ab - nur die dumme Browsermeldung da muss noch weg. Dann funzt bis jetzt alles einwandfrei.
gepostet vor 18 Jahre, 6 Monate von Sarge
Wie TheUndeadable schon gesagt hat eine alternative ohne groß den code ändern zu müssen wäre nicht direkt auszugeben sondern die gesamte ausgabe zuerst zu buffern und dann in einem rausjagen.
gepostet vor 18 Jahre, 6 Monate von Kapsonfire
du kannst auch den aktualisierungsbutton in einer anderen form auf die selbe datei legen xD
dürfte es auch keine probleme geben
gepostet vor 18 Jahre, 6 Monate von abuzeus
gepostet vor 18 Jahre, 6 Monate von Kapsonfire
was soll das jetzt?
gepostet vor 18 Jahre, 6 Monate von Kelturio
Damit ist der Aktualisierungsbutton des Browsers gemeint und nicht ein selbst gemachter Button, Browser-Games World.
Das mit der Buffer Lösung klingt irgendwie recht kompliziert. Ich habe gelesen, dass man die dann nur wieder mit ob_end_flush() oder so ausgeben kann. Oder wie ?
Geht es nicht noch anders ?
gepostet vor 18 Jahre, 6 Monate von Kampfhoernchen
Ne, am Ende des Scripts wird alles ausgeworfen. Nur wenn du zwischendurch "auswerfen" willst, musst du die flush()-Funktion benutzen.
gepostet vor 18 Jahre, 6 Monate von abuzeus
Ist das weiter schlimm ?
Du solltest dir klar machen, dass Anzeige am Browser und Ausgaben die du im Code machst zwei Paar Schuhe sind.
Wenn du ob_start() rufst, werden deine komplettten Ausgaben, von Headern abgesehen, im Puffer gespeichert und erst wenn du ob_end_flush() aufrufst, wird der Kram zum Browser gesendet. Im Prinzip ist es im Script sowieso egal, in welcher Reihenfolge du Berechnungen machst, solange deine Ausgaben in der richtigen Reihenfolge stehen. Es bietet sich sogar an, zuerst alle Berechnungen, Datenbankabfragen usw. zu machen und am Ende in einem Rutsch alles auszugeben, das trennt Dinge, die nicht zusammengehören (Logik und Design) und vereinfacht die Codewartung.
Ich vermute aufgrund deiner Postings, dass die meisten deiner Probleme daher rühren, dass dir nicht ganz klar ist, was genau passiert und wie Abläufe zeitlich und logisch zusammenhängen. Bemühe dich darum, das zu verstehen und ich glaube dass du dann einen guten Schritt weiter gemacht hast.
Gruss, abu
gepostet vor 18 Jahre, 6 Monate von Sarge
Ich find den Buffer generell unschön.
Anders gehts nur das du deine headerausgabe wie gesagt vor deiner ersten Ausgabe ziehst. Sollte normalerweise keine Probleme verursachen.. du musst es einfach nur machen
gepostet vor 18 Jahre, 6 Monate von FateF8
spontan dachte ich an "onreload", aber das gibt's so ja leider nicht
aber, ggf. kannst du über ein "onload" ein javascript aufrufen, das z.b. die zuladen adresse, mit der letzten adresse in der history vergleicht und entsprechend handelt, also z.b. auf eine andere seite verweist, die den user auf den "reload" aufmerksam macht aber keine daten weiterverarbeite.
gruss
FateF8
gepostet vor 18 Jahre, 6 Monate von Kelturio
@ Kampfhoernchen:
Ach so, also brauche ich da nur ganz oben z.B. unter den include-Befehlen "ob_start();" hinschreiben und das müsste es auch schon gewesen sein, soweit ich das verstanden habe. Oder ?
@ abuzeus:
Ich werde mich bemühen in die Dinge einen tieferen Einblick zu bekommen.
@ Sarge:
Mein header befindet sich doch schon ganz oben, also vor der ersten Ausgabe.
Ganz am Anfang steht eben solches PHP Zeug wie DB-Connection und es werden paar Sachen aus der DB ausgelesen und neu berechnet, aber es wird nix mit echo etc. ausgegeben.
Danach kommt mein -Teil.
Oder verstehe ich dich da falsch ?
gepostet vor 18 Jahre, 6 Monate von Amun Ra
if ( isset($_POST['bauen']) ) {
if ( wird_gerade_gebaut() == 0 ) {
bauen();
} else {
nicht_bauen();
}
}
bauen() vermerkt in irgendeiner Form das gebaut wird.
wird_gerade_gebaut() fragt ab, ob gerade gebaut wird.
gepostet vor 18 Jahre, 6 Monate von Kelturio
@ Amun Ra:
So habe ich es doch auch schon, oder ? :
if (wird_gerade_gebaut == 0) {
if (isset ($_REQUEST["Ausbauen1"])) Bau ();
}
gepostet vor 18 Jahre, 5 Monate von Sarge
Warning: Cannot modify header information - headers already sent by ...
sagt recht eindeutig das du schon eine Ausgabe getätigt hast bevor du zu deinem header(); kamst... wo und was genau kann ich leider in meiner Kristallkugel nicht sehen.. vllt lohnt es sich in dem by xyz teil nachzuschauen *wink mit dem zaunpfahl*
gepostet vor 18 Jahre, 5 Monate von mifritscher
dann mach halt statt der location an der stelle irgendwie ne Text rein "Es wird doch schon gebaut" oder sowas
Aber mal allgemein: so wie sich das anhört scheinst du nicht konsequent zu überprüfen, ob der Auftrag zur Zeit überaupt sinnvoll ist. Denk dran, User sind immer ganz doll böse
Also sei auf alles gefasst, selbst wenn du es im html-code deaktiviert hast oder es gar nicht angezeigt wird könnte trotzdem ein entsprechender Auftrag kommen...
gepostet vor 18 Jahre, 5 Monate von Kelturio
@ Sarge:
Stimmt, da habe ich was übersehen.
Also mein Dokument is praktisch so aufgebaut:
- paar Java Scripts et.
- paar Tabellen
- z.B. Ressourcentabelle
- Gebäudetabelle
- weitere Tabellen
Dort, wo ich rot markiert habe befindet sich diese Abfrage ob was gebaut wird etc. und der Headerverweis. Da aber oben schon die Ress ausgelesen und angezeigt werden, fand doch schon eine Anzeige statt.
Wie kann ich das besser machen, damit es mit dem Browser klappt ?
gepostet vor 18 Jahre, 5 Monate von mifritscher
wie schon gesagt, haue einfach ne Art echo "Es wird schon was anderes gebaut"; statt dem header rein
gepostet vor 18 Jahre, 5 Monate von Kelturio
@ mifritscher:
Lese mal eine Seite vor dieser hier.
SOwas habe ich nämlich schon probiert, aber wenn ich dann auf den Aktualisierenbutton des Browsers klicke, erscheint trotzdem diese Meldung vom Browser, welche ich erwähnt hatte.
gepostet vor 18 Jahre, 5 Monate von FateF8
hmm, es mag nicht falsch sein, so wie du deine datei aufgebaut hast, aber "besser" ist, erst alle berechnungen etc. durchzuführen und zum schluss alles ausgeben
in vars speichern ?>
in vars speichern?>
- paar Java Scripts et.
- paar Tabellen
- z.B. Ressourcentabelle
- Ausgabe der php-vars (an entsprechender stelle)
- Gebäudetabelle
- weitere Tabellen
dadurch vermeidest du "ungewollte" ausgaben an nicht überschaubaren stellen
du kannst dann auch über ein und die selbe datei mit hilfe von if-clauses auf verschiedene html-ausgaben verweisen
als beispiel könntest du, wenn die prüfung in php auf reload true ist dann auf die entsprechende meldung als html-ausgabe verweisen
gruss
FateF8
gepostet vor 18 Jahre, 5 Monate von knalli
Original von Kelturio
@ Sarge:
Stimmt, da habe ich was übersehen.
Also mein Dokument is praktisch so aufgebaut:
- paar Java Scripts et.
- paar Tabellen
- z.B. Ressourcentabelle
- Gebäudetabelle
- weitere Tabellen
Dort, wo ich rot markiert habe befindet sich diese Abfrage ob was gebaut wird etc. und der Headerverweis. Da aber oben schon die Ress ausgelesen und angezeigt werden, fand doch schon eine Anzeige statt.
Wie kann ich das besser machen, damit es mit dem Browser klappt ?
Headerverweise nach einer Ausgabe geht nicht.. merke: Trenne Code und Output, dann wird auch immer alles gutt!.
Also bei dir:
+ ggf Header ?>
...
...
Das würde dir auf die schnell deutlich mehr bringen..
edit: herrlich, heute sind wir wieder im editierwahn "da war einer schneller"
gepostet vor 18 Jahre, 5 Monate von Kelturio
Ok, also erst alle Berechnungen und diese in Variablen speichern, dann an entsprechender Stelle einfach die Variablen ausgeben, okay.
Da muss ich erstmal viel umschreiben in meiner Datei. ^^
Ich poste dann wieder hier, ob es klappt.
gepostet vor 18 Jahre, 5 Monate von BLUESCREEN
Original von blum
Original von BLUESCREEN
Original von blum
Die eleganteste Methode Formulare zu verarbeiten ist sowieso dafür eine eigene datei zu verwenden.
(...)
danach leitest du den benutzer mit header('Location: index.php') wieder zurück.
Das finde ich hässlich, weil man dem User so nicht einfach eine Meldung wie "Gebäude wird gebaut." oder so anzeigen kann.
Das könnte man natürlich auch mit getrennten Dateien realisieren, wäre aber umständlich...
doch mit session
Wie gesagt: Umständlich, da es nicht reicht, nur eine Statusmeldung zu speichern, sondern es beliebig viele sein müssen. Und um diese wieder unterscheiden zu können müssen die alle eine ID kriegen, die dann bei der Location-Angabe übergeben wird. Außerdem muss man dann natürlich noch darauf achten, dass gespeicherte, aber nie abgerufene Meldungen nicht die Sessiondaten zumüllen.
Ansonsten hat man das Problem, dass Meldungen verloren gehen oder z.B. im falschen Tab angezeigt werden.
edit: Das sollten jetzt genug Offtopic-Posts von mir sein ^^
gepostet vor 18 Jahre, 5 Monate von blum
naja wenn man sowas macht, dann lebt die meldung in der session genau einen seitenaufruf lang. danach brauch ich die meldung ja nicht mehr.
echo $_SESSION['message'] ? $_SESSION['message'] : '';
$_SESSION['message'] = false;
gepostet vor 18 Jahre, 5 Monate von BLUESCREEN
Original von blum
naja wenn man sowas macht, dann lebt die meldung in der session genau einen seitenaufruf lang. danach brauch ich die meldung ja nicht mehr.
echo $_SESSION['message'] ? $_SESSION['message'] : '';
$_SESSION['message'] = false;
Wenn du das so machst wird die Meldung unter Umständen bereits überschrieben bevor sie angezeigt wurde.
Ein Beispiel, was passieren könnte: Eine Seite, die eine Meldung in die Session schreibt wird zweimal parallel aufgerufen (User benutzt Tabbed Browsing). Die erste Instanz des Skriptes schreibt ihre Meldung und die zweite überschreibt diese Meldung.
Dann werden parallel zwei Seiten aufgerufen, die Meldungen anzeigen sollen. Dabei zeigt die erste die Meldung des zweiten Skriptes an und die zweite überhaupt keine mehr.