Seite läd nicht neu nach dem Einsatz von Sessions
Bereto
- php
Hallo ihr PHP-Gurus,
ich suche seit gut einem Monat eine Lösung für ein saudoofes Problem.
Ich habe einen Shop programmiert. Dieser hat logischerweise einen Warenkorb. Um die Stückzahl variabel zu machen (Artikel-Menge), habe ich bei der Warenkorb-Anzeige vor und hinter der Menge eien Kopf, der wenn ich diesen betätige die Stückzahl um eine erhöht oder verringert. Beispielsweise, grob und ohne Grafik so: / 3 /\
Die Seite ruft sich selbst wieder auf. Die Anzahl wird aus der Datenbank gelesen, und angezeigt. Alles hat funktioniert, bis ich auf die Idee gekommen bin Sessions einzusetzen. Früher habe ich "per post" die UserID übergeben, womit aus der DB nur die Artikel des Users angezeigt wurden. Funktioniert einwandfrei.
Jetzt wollte ich zwecks Sicherheit Sessions einsetzen, der ich die UserID übergebe. Prinzipell funktioniert es, d.h. in der datenbank werden alle veränderungen ordnungsgmäß ausgeführt, aber die sich selbst neu ladende Seite zeigt irwizige Inhalte an, manchmal werden bei mehreren Artikel die Stückzahlen gleizeitig geändert, dann läßt sich die Stückzahl nicht über 2 bringen usw...
Der Hammer ist, das im Mozilla jeder 2. Klick zum Erfolg führt. Also klick nix, klick erhöhung der Menge um eins, klick wieder nix usw.
:-/ Wer weiß hier Rat. Die typischen tricks ala
<meta http-equiv="expires" content="0">
<meta http-equiv="cache-control" content="no-cache">
haben keinen Erfolg.
Danke im Voraus.
Ich habe einen Shop programmiert. Dieser hat logischerweise einen Warenkorb. Um die Stückzahl variabel zu machen (Artikel-Menge), habe ich bei der Warenkorb-Anzeige vor und hinter der Menge eien Kopf, der wenn ich diesen betätige die Stückzahl um eine erhöht oder verringert.
Jetzt wollte ich zwecks Sicherheit Sessions einsetzen, der ich die UserID übergebe.
Was meinst Du damit? Hältst Du nur die Kundennummer in der Session und lässt den Warenkorb in einer Datenbank? Es ist sicherlich wenig sinnvoll, jetzt alles über den Haufen zu werfen, aber es wäre möglicherweise günstiger, sämtliche Sessiondaten in $_SESSION zu halten und nicht ein Stückchen hier (Session) und ein Stückchen dort (Warenkorb). Aber wie gesagt: Nur als Anregung.
Prinzipell funktioniert es, d.h. in der datenbank werden alle veränderungen ordnungsgmäß ausgeführt, aber die sich selbst neu ladende Seite zeigt irwizige Inhalte an, manchmal werden bei mehreren Artikel die Stückzahlen gleizeitig geändert, dann läßt sich die Stückzahl nicht über 2 bringen usw...
Du solltest nochmal versuchen, das Cacheverhalten zu ändern, zum einen mit unten genannter Methode und zum anderen, indem Du zur Sicherheit das Caching in den Browsereinstellungen abschaltest - nicht, daß da doch was mit Deinem Skript im Argen liegt (auch wenn es angesichts der korrekten Datenbank nicht wahrscheinlich ist) und Du an der falschen Stelle suchst. Ein Debug-Protokoll würde zusammen mit dem Zugriffsprotokoll des Servers auch helfen, genau nachzuvollziehen, was da eigentlich passiert.
<meta http-equiv="expires" content="0">
<meta http-equiv="cache-control" content="no-cache">haben keinen Erfolg.
Da Du PHP einsetzt, solltest Du auf die HTML-Krücke http-equiv verzichten und gleich das HTTP-Protokoll benutzen:
header("Cache-Control: no-cache");
Beachte bei Expires: bitte, daß es keine Zahl annimmt, sondern ein Datum, siehe http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21. Du kannst date("r",0) dazu benutzen.
Gruß,
soenk.e
Ich habe Tests gefahren, so mit 100 Seiten aufreufen etc. und bin zu dem Schluß gekommen, das die Datenbank schneller ist als die Session-Variable, besonders im Hinblick auf viele User (ich erwarte in diesem Projekt ca. 1000 Warenkorb-Vorgänge pro Tag).
Wäre nett wenn Du mal in die anderen Antwort schaust, dort habe ich mal den Quell-Code des Scrips gepostet. Vielleicht siehst Du ja einen Fehler?! Und Vielleicht hast Du noch einen Tipp auf Lager, falls ich mich irgendwo doof anstelle...
Danke.
Ich habe Tests gefahren, so mit 100 Seiten aufreufen etc. und bin zu dem Schluß gekommen, das die Datenbank schneller ist als die Session-Variable,
Nein, das ist unmöglich. Erstens führst Du in dem problematischen Skript überhaupt keine Änderung an $UserID durch und zweitens stehen alle externen Variablen mit Beginn des Skriptablaufs zur Verfügung.
Dein Skript scheint funktionsmäßig korrekt zu sein, es müßte sich also um ein Cache-Problem handeln. Versuche nochmal, die <meta>-Angaben wie beschrieben per header() auszugeben.
Davon unabhängig würde ich Dir wirklich ans Herz legen, den Warenkorb in die Session zu legen - Du ersparst Dir damit bestimmt die Hälfte vom Code, weil die ganzen voluminösen mysql-Geschichten wegfallen.
Der "elseif ($Steuerung = 'update')"-Block beispielsweise kann mit allen Eventualitäten auf folgende kurze Zeilen zusammenschrumpfen:
if (isset($_SESSION["artikel"][$MaterialID]))
if ($Art=="plus")
$_SESSION["artikel"][$MaterialID]++;
else
$_SESSION["artikel"][$MaterialID]--;
else
$_SESSION["artikel"][$MaterialID]=1;
Weiterhin solltest Du unbedingt:
register_globals ausschalten und die superglobals $_GET und $_SESSION verwenden, so wie Du es bereits mit $_POST machst. Mit register_globals versaust Du Dir den gesamten Namensraum und öffnest unter Umständen auch noch Sicherheitslöcher, weil man dem Skript gerade bei den URL-Parametern ohne Aufwand x-beliebige Variablen unterjubeln kann. Das ist auch der Grund, warum register_globals jetzt standardmäßig ausgeschaltet ist und diese superglobals eingeführt wurden.
Die Session startest Du besser mit session_start(). Damit entfällt die Registrierung jeder einzelnen Variable, weil Du einfach auf $_SESSION zugreifen kannst - jegliche Änderung darin wird beim Skriptende automatisch gespeichert.
Du solltest Daten, die nicht mit 110%-iger Sicherheit aus Zahlen bestehen, immer mit htmlentities() ausgeben. In Deinem Fall betrifft das insbesondere Hersteller- und Artikelname, aber durchaus auch andere Variablen.
Du solltest Dich eventuell mit mysql_escape_string() vertraut machen.
Deine URLs sind falsch. Das Zeichen & darf in HTML niemals alleine stehen, auch nicht in href-Attributen oder ähnlichem. Willst Du ein Und haben, benutze &. Oder konfiguriere Dein PHP so, daß es auch das Semikolon als Trennzeichen akzeptiert. Siehe auch http://validator.w3.org.
Gruß,
soenk.e
Ich habe Tests gefahren, so mit 100 Seiten aufreufen etc. und bin zu dem Schluß gekommen, das die Datenbank schneller ist als die Session-Variable,
Nein, das ist unmöglich. Erstens führst Du in dem problematischen Skript überhaupt keine Änderung an $UserID durch und zweitens stehen alle externen Variablen mit Beginn des Skriptablaufs zur Verfügung.
Dein Skript scheint funktionsmäßig korrekt zu sein, es müßte sich also um ein Cache-Problem handeln. Versuche nochmal, die <meta>-Angaben wie beschrieben per header() auszugeben.
Davon unabhängig würde ich Dir wirklich ans Herz legen, den Warenkorb in die Session zu legen - Du ersparst Dir damit bestimmt die Hälfte vom Code, weil die ganzen voluminösen mysql-Geschichten wegfallen.
____________________________________________________
Also ich habe mir die Dinge die Du schreibst reichlich durch den Kopf gehen lassen. (Ich bin kein Profi, mehr Autodidakt, komme aber zurecht...)
Auf die Idee, alles in die Session zu packen bin ich noch nicht gekommen. Da die Zeit drängt, werde ich es nach Fertigstellung des Projektes ausprobieren. Mir ist wichtig, dass ich auch mal in der DB nachschauen kann, was ab geht im Warenkorb der Leute. Mir ist klar, dass ich auch die Cookies befragen (editieren) könnte, aber, wie gesagt, erst wenn alles anderen läuft. Logischeweise ist das was im Ram liegt, schneller als jede DB-Abfrage, duDu hast also völlig Recht.
Das Hauptproblem habe ich heute übrigend lösen können: Ich habe auf meinem Testsystem den OMNIhttpd - Webserver laufen. Austausch gegen Apache, und alle Probleme sind weg!!! Es lag also am Webserver!
______________________________________________________________
Der "elseif ($Steuerung = 'update')"-Block beispielsweise kann mit allen Eventualitäten auf folgende kurze Zeilen zusammenschrumpfen:
if (isset($_SESSION["artikel"][$MaterialID]))
if ($Art=="plus")
$_SESSION["artikel"][$MaterialID]++;
else
$_SESSION["artikel"][$MaterialID]--;
else
$_SESSION["artikel"][$MaterialID]=1;Weiterhin solltest Du unbedingt:
_____________________________________________________________
Guter Ansatz, danke.
_____________________________________________________________
- register_globals ausschalten und die superglobals $_GET und $_SESSION verwenden, so wie Du es bereits mit $_POST machst. Mit register_globals versaust Du Dir den gesamten Namensraum und öffnest unter Umständen auch noch Sicherheitslöcher, weil man dem Skript gerade bei den URL-Parametern ohne Aufwand x-beliebige Variablen unterjubeln kann. Das ist auch der Grund, warum register_globals jetzt standardmäßig ausgeschaltet ist und diese superglobals eingeführt wurden.
___________________________________________________________
Die Session starte ich im Script beim Login, hier werden nurnoch die benötigten Variablen gelöscht.
___________________________________________________________
Die Session startest Du besser mit session_start(). Damit entfällt die Registrierung jeder einzelnen Variable, weil Du einfach auf $_SESSION zugreifen kannst - jegliche Änderung darin wird beim Skriptende automatisch gespeichert.
Du solltest Daten, die nicht mit 110%-iger Sicherheit aus Zahlen bestehen, immer mit htmlentities() ausgeben. In Deinem Fall betrifft das insbesondere Hersteller- und Artikelname, aber durchaus auch andere Variablen.
Du solltest Dich eventuell mit mysql_escape_string() vertraut machen.
________________________________________________________
Kannte beide Befehle noch nicht, werde sie mir reinziehen...
________________________________________________________
- Deine URLs sind falsch. Das Zeichen & darf in HTML niemals alleine stehen, auch nicht in href-Attributen oder ähnlichem. Willst Du ein Und haben, benutze &. Oder konfiguriere Dein PHP so, daß es auch das Semikolon als Trennzeichen akzeptiert. Siehe auch http://validator.w3.org.
_________________________________________________________
Hab ich geändert. Danke.
_________________________________________________________
Gruß,
soenk.e
_________________________________________________________
Letzte Frage: Ich streite mich immer ein bischen mit den wenigen, mir so bekannten (PHP-)Kumpels: Macht man am Ende der Seite die Verbindung zur Dantenbank aus Performance-Gründen lieber zu oder nicht, wenn ich die selbe DB auf der nächsten Seite wieder brauche? (Mysql_close($link))
Solong Danke erstmal.
Macht man am Ende der Seite die Verbindung zur Dantenbank aus Performance-Gründen lieber zu oder nicht, wenn ich die selbe DB auf der nächsten Seite wieder brauche? (Mysql_close($link))
Das ist bei PHP eigentlich ziemlich wurscht. Schließt Du die Verbindung nicht selbst, wird sie von PHP bei Skriptende automatisch beendet. Der Aufruf von mysql_close() kurz vor Ende ist also eher Kosmetik, aber legst Du wert auf ordentlichen Code, solltest Du es machen. Auf Ausführung oder Rechnerresourcen hat das in jedem Fall keinen merkbaren Einfluss.
Brauchst Du die Datenbank definitiv auf weiteren Seiten, kannst Du Dir mysql_pconnect() anschauen. Die damit geöffnete Verbindung bleibt bestehen, auch nach Ende des Skripts, und wird beim nächsten Mal vom Webserver (Webserver, nicht unbedingt von jenem Skript, das die Verbindung öffnete!) wieder genutzt.
Diese Vorgehensweise _kann_ die Leistung des Systems verbessern, _muß_ aber nicht. Sinnvoll ist die Anwendung sicherlich, wenn der Datenbankserver auf einem entfernten Rechner liegt, denn der Verbindungsaufbau über das Internet kann manchmal ein wenig dauern. Wahrscheinlich überhaupt nicht sinnvoll ist sie, wenn der Datenbankserver auf derselben Maschine läuft und über Dateisystemsockets (statt der aufwendigeren Netzwerksockets) mit dem Webserver/PHP/Skript kommuniziert.
Ich behaupte mal so ins Blaue hinein, daß Du keinerlei Unterschied merken wirst.
Beachte die Beschreibung zu mysql_pconnect() sowie die von dort erreichbare, ausführliche Unterseite zu dauerhaften Datenbankverbindungen in der PHP-Anleitung.
Gruß,
soenk.e
Hallo,
das klingt irgendwie recht seltsam, also wenn die DB Änderungen funktionieren, erkennst Du ja im Script wahrscheinlich den richtigen User, also funktioniert die Session. Du solltest mal überprüfen, ob der Rest vom Script logisch richtig ist, oder irgendeinen Programmierfehler enthält.
Ansonsten würde ich mal beim Browser den Cache (Platte + RAM) komplett deaktivieren, und austesten ob es dann geht, falls nicht, hast Du kein Cache Problem.
Wenn es ein Cache Problem ist, könnte es eventuell helfen, in die Zielurl des Knopfes noch eine Zufallszahl als Parameter einzucodieren, dann müsste der Browser in jedem Fall neu laden.
Gruss
Marko
Hallo,
danke erstmal für Eure shnelle Hilfe. Ich habe den IE auf "Seite immer neu laden gestellt, es ändert jedoch nicht am Verhalten des Systems. :-(
Der Quell-Code ist kein Geheimnis, des halb poste ich ihn einfach mal. Vielleicht seht Ihr etwas...
Nun denn:
--------------------------------------------------------------------
<?
session_register(UserID);
include ('../system/param/param.php');
?>
<html>
<head>
<meta http-equiv="Content-Language" content="de">
<meta http-equiv="expires" content="0">
<meta http-equiv="cache-control" content="no-cache">
<title>Warenkorb</title>
<link rel="stylesheet" type="text/css" href="../system/param/user.css">
</head>
<body>
<?
$Zeit = time();
#echo $Zeit; ## zum debugen
if($Steuerung == 'neu')
{
foreach($_POST as $key => $value)
{
#echo "$key : $value"; ## zum debugen
#echo "<br>"; ## zum debugen
$nAuswahl = similar_text($key,'MaterialID');
if ($nAuswahl != '10')
{
}
else
{
$MaterialID = substr(strrchr($key,'D'),1);
$menge_mat = '1';
$anfrage_count="SELECT Menge AS aktivaMenge FROM aktiva Where MaterialID = '$MaterialID' AND UserID = '$UserID';";
$ergebnis_count=mysql_query($anfrage_count) or die ("Fehlermeldung2=".mysql_error());
$row_count=mysql_fetch_array($ergebnis_count);
if (empty($row_count[aktivaMenge]))
{
$ins_aktiva="INSERT INTO aktiva VALUES ('$UserID','$Zeit','$MaterialID','$menge_mat','$value')";
if ($ergeb_ins_aktiva=mysql_query($ins_aktiva))
{echo "";}
else
{echo "Datensatz nicht in Aktiva eingefügt - Fehlermeldung3=".mysql_error();};
}
else
{
$upd_aktiva="UPDATE aktiva SET Menge = Menge + '$menge_mat' WHERE MaterialID = '$MaterialID' AND UserID = '$UserID';";
if ($ergeb_upd_aktiva=mysql_query($upd_aktiva))
{echo "";}
else
{echo "Mengenbetrag nicht um Menge in Aktiva erhöht - Fehlermeldung4=".mysql_error();};
}
}
}
}
elseif ($Steuerung = 'update')
{
if ($Art == 'plus')
{
$anfrage2="UPDATE aktiva SET Menge = (Menge + '1') WHERE MaterialID = '$MaterialID' AND UserID = '$UserID';";
if ($ergebnis2=mysql_query($anfrage2))
{echo "";}
else
{echo "Fehlermeldung Material plus=".mysql_error();};
}
else
{
$anfrage2="UPDATE aktiva SET Menge = (Menge - '1') WHERE MaterialID = '$MaterialID' AND UserID = '$UserID';";
if ($ergebnis2=mysql_query($anfrage2))
{echo "";}
else
{echo "Fehlermeldung Material minus=".mysql_error();};
}
}
#####################################################################################################
else
{}
################################ Jetzt zeigen wir den Inhalt der Aktiva Tabelle an ##################
$sp_anzeige="SELECT * FROM aktiva WHERE UserID = '$UserID'";
$ergebnis_sp_anzeige=mysql_query($sp_anzeige) or die ("Fehlermeldung5=".mysql_error());
$nums_sp_anzeige=mysql_num_rows($ergebnis_sp_anzeige);
if($nums_sp_anzeige == '0')
{
echo "<p><font size='3'><b>Es befinden sich keine Waren im Warenkorb!</b></font></p>";
}
else
{
?>
<p><font size=2>Folgendes haben Sie ausgewählt:</font></p>
<table border=0 cellpadding=2 width=600 class=table>
<tr height="30">
<td class=td_ueschri width="15%" align="center"><font size=2>Menge</font></td>
<td class=td_ueschri width="50%" align="center"><font size=2>Beschreibung</font></td>
<td class=td_ueschri width="15%" align="center"><font size=2>Preis in *</font></td>
<td class=td_ueschri width="20%" align="center"><font size=2>Gesamtpreis in *</font></td>
</tr>
<?
for ($l=0; $l < $nums_sp_anzeige; $l++)
{
$row_sp_anzeige=mysql_fetch_array($ergebnis_sp_anzeige);
$list_mat="SELECT Hersteller, Name FROM material WHERE MaterialID='$row_sp_anzeige[MaterialID]';";
$erg_list_mat=mysql_query($list_mat) or die ("Fehlermeldung6=".mysql_error());
$row_list_mat=mysql_fetch_array($erg_list_mat);
echo "<tr height='30'>";
echo "<td class=td_table width='15%' align='center'><font size=2><a href='user_warenkorb.php?Steuerung=update&MaterialID=$row_sp_anzeige[MaterialID]&Art=minus'><img border='0' src='../system/images/minus-pfeil.gif' align='absmiddle'></a><b> $row_sp_anzeige[Menge] </b><a href='user_warenkorb.php?Steuerung=update&MaterialID=$row_sp_anzeige[MaterialID]&Art=plus'><img border='0' src='../system/images/plus-pfeil.gif' align='absmiddle'></a></font></td>";
echo "<td class=td_table width='50%' align='center'><font size=1>$row_list_mat[Hersteller] $row_list_mat[Name]</font></td>";
echo "<td class=td_table width='15%' align='center'><font size=1>$row_sp_anzeige[Preis]</font></td>";
$Gesamt_Preis = $row_sp_anzeige[Menge] * $row_sp_anzeige[Preis];
$Gesamt_Preis = sprintf ("%1.2f", $Gesamt_Preis);
$Gesamt_Preis_Summe = $Gesamt_Preis_Summe + $Gesamt_Preis;
echo "<td class=td_table width='20%' align='center'><font size=1>$Gesamt_Preis</font></td>";
echo "</tr>";
}
$Gesamt_Preis_Summe = sprintf ("%1.2f", $Gesamt_Preis_Summe);
echo "<tr height='30'>
<td class=td_table width='100%' align='center' colspan='4' valign='middle' height='16'><p align='left'>
<table border='0' cellpadding='10' cellspacing='0' width='100%'>
<tr>
<td class=td_table width='50%' align='left' colspan='2'><p align='left'><font size=1><a href='user_warenkorb_loeschen.php?UserID=$UserID' target='_self'>Warenkorb löschen</a></font></p></td>
<td class=td_table width='50%' align='right' colspan='2'><p align='right'><font size=2>Gesamt - Bestellwert: $Gesamt_Preis_Summe </font></p></td>
</tr>
</table>
</td>
</tr>";
echo "</table>";
}
?>
<form action="user_order.php" method="post">
<table width="600">
<tr>
<td>Ich habe noch folgendes Anliegen:</td>
</tr>
<tr>
<td><textarea rows="3" cols="95" name="anliegen"></textarea></td>
</tr>
<tr>
<td><hr></td>
</tr>
</table>
<Input src='../system/images/bestellen.gif' name='bestellen' alt='Ware endgültig bestellen' type='image' value='submit'>
</form>
</body>
</html>
---------------------------------------------------------------
Thanks for help.
Hallo
...
session_register(UserID);
...
... <a href='user_warenkorb_loeschen.php?UserID=$UserID' target='_self'>Warenkorb löschen</a>
...
Du registrierst die UserID, du benutzt sie für Datenbankabfragen
(hier gelöscht), und du hängst sie als Parameter an den Link ran,
ich habe allerdings keine Stelle in deinem Quellcode gefunden,
wo die UserID erstellt wird.
Tschö, Auge