(close) [php] Trotz if-anweisung (false) läuft es dennoch durch?

Shamane

DB-Crasher
ID: 86026
L
24 Juli 2006
909
50
Hi ho....
also ich verzweifle hier seit 2 Tagen an einem Code für einen Warenkorb.
Ausführung: Benutzer wählt ein Produkt und klickt auf "Kaufen", beim klick darauf wird auf eine andere Datei verlinkt welche die ID des zu kaufenden Produkts mit übernimmt.
z.B: von detail.php?id=10 AUF kaufen.php?id=10

So, nun ist es aber so, das wenn ich im Script prüfe ob der Artikel bereits im Warenkorb ist dennoch beide abfragen durchführt.. Ein Update für das Hinzufügen (bei nochmaligen klick) und die Insert anweisung, wenns halt noch nicht im Warenkorb ist.

Hier mal die DB-Struktur (warenkorb)
session|artikel_name|artikel_anzahl|artikel_preis|set_time
hvidvh6oh9s9fkfjgbls8tnmf214btsh|T-Shirt|1|9.99|1243275555

nun hier des Script/Datei (kaufen.php)
PHP:
<?php
include("inc/config.php");

/*
$_GET['id'] ist die übertragene ID des zu kaufenden Artikels/Produktes
*/

$sql = dbquery("SELECT * FROM shop_artikel WHERE script_id = '".$_GET['id']."' AND script_menge != '0' LIMIT 1");
if( mysql_num_rows($sql) == 1 )
{
  //Artikel vorhanden
  $row = mysql_fetch_array($sql);
    $artikel_preis = $row['script_price'];

  //Prüfen ob bereits im Warenkorb
  $sql_warenkorb = dbquery("SELECT * FROM `shop_warenkorb` WHERE `session` LIKE '".session_id()."' AND `artikel_name` LIKE '".$row['script_name']."' LIMIT 1");
  //Prüfen ob Artikel bereits im Warenkorb ist.
  if( mysql_num_rows($sql_warenkorb) == 0 )
  {
    //Einmal in den Warenkorb legen
    $addTo = dbquery("INSERT INTO `shop_warenkorb` (`session`,`artikel_name`,`artikel_anzahl`,`artikel_preis`,`set_time`) VALUES ('".session_id()."', '".$row['script_name']."', '1', '".$artikel_preis."', '".time()."')");
  }else{
    //Warenkorb - Artikel update - +1
    $addTo = dbquery("UPDATE shop_warenkorb SET artikel_anzahl = artikel_anzahl + 1 WHERE session = '".session_id()."' AND artikel_name = '".$row['script_name']."' LIMIT 1");
  }

  if( $addTo == true )
  {
    $_SESSION['warenkorb'] = true;
    $meldung['artikelname'] = '1x '.$row['script_name'];
    $meldung['produkt_id'] = $_GET['id'];
    $Cboxen = cBox($row['script_name'].' wurde in den Warenkorb gelegt', tpl_read('c_produkt_bestellen',$meldung));
  }else{
    /* Warenkorb eintrag war fehlerhaft */
    $meldung['code'] = 'Warenkorb';
    $meldung['beschreibung'] = 'Der gewünschte Artikel konnte aus einem Unbekannten grund nicht in den Warenkorb gelegt werden.';
    $Cboxen = cBox('Artikel wurde nicht im Warenkorb abgelegt', tpl_read('c_fehlerseite',$meldung));
  }

}else{
  //Produkt ID fehlerhaft
  $Cboxen = cBox('Fehlerhafte Artikel-ID', tpl_read('c_no_produkt_details'));
  $Nboxen = nBox_zufallsprodukt().nBox_newprodukt();
}
template($Cboxen,$Nboxen); 
?>
Interessant wird es erst ab "//Prüfen ob bereits im Warenkorb", alles andere ist nur für die vollständigkeit mit angegeben.

Nun jedenfalls wird beim Aufrufen des Scriptes... einmal der Artikel (wenn nicht vorhanden in die Datenbank eingetragen und gleich sofort im nachhinein das Update ausgeführt. Was zur folge hat, das nicht nur ein Artikel sondern gleich 2x die Artikelmenge im Warenkorb sind.

Nun meine frage ist einfach nur, warum wird hier die IF anweisung übersprungen?
Also, nachdem ich die Datei durch aufzählen der Script- bzw. Dateidurchläufe durchläufe mitgeloggt habe, kann ich mit sicherheit sagen, das die Datei wirklich nur einmal ausgeführt wird.

Bitte helft mir...
Hab es zwar schon anders gelöst (per timestamp verschachtelungen) aber das ist auf dauer etwas umständlich und nicht sinn der sache das doch am ende irgendwas schief läuft.

Serverinformationen:
php-version: 5.2.9 (run on apache2)
mysql-version: 5.0.45

Edit: achso, ich nutze .htaccess um SEO Optimierte Urls zu erzeugen, aber daran wird es bestimmt nicht liegen?!
 
Zuletzt bearbeitet:
Die funktion dbquery() gibt mysql_query() zurück..

Also ist das gleiche wie als wenn ich mysql_query aufrufe halt nur mit SQL-Injektion ^^

In diesem fall wäre die Rückgabe bei Update und Insert befehlen true

Wenn ich zb inner halb der If abfrage einmal im Insert-bereich und Updatebereich ein Counter beifüge.. wird immer nur der Counter gezählt welcher innerhalb des Befehls steht.

Sprich..
PHP:
if( mysql_num_rows($sql_warenkorb) == 0 )
  {
    //Einmal in den Warenkorb legen
    $count_in++;
    $addTo = dbquery("INSERT INTO `shop_warenkorb` (`session`,`artikel_name`,`artikel_anzahl`,`artikel_preis`,`set_time`) VALUES ('".session_id()."', '".$row['script_name']."', '1', '".$artikel_preis."', '".time()."')");
  }else{
    //Warenkorb - Artikel update - +1
    $count_up++;
    $addTo = dbquery("UPDATE shop_warenkorb SET artikel_anzahl = artikel_anzahl + 1 WHERE session = '".session_id()."' AND artikel_name = '".$row['script_name']."' LIMIT 1");
  }

echo $count_in.' | '.$count_up;

Gibt immer nur halt count_IN ODER count_UP (werte) aus.
Aber dennoch wird das Update beim eintragen irgendwie mit ausgeführt, warum auch immer, ich hab am ende in der artikel_anzahl 2 stehen wenn ich über den Link von details.php auf kaufen.php gehe.

Anders ist es wieder wenn ich kaufen.php offen lasse, die Browsersession lösche (neueID) und dann die seite aktuallisiere dann ist die artikel_anzahl auf 1.

zu den ganzen oben genannten Problem kommt leider noch erschwerend hinzu, das selbst das nur Update (irgendwie) doppelt ausgeführt wird. Sprich, wenn der Artikel bereits im Warenkorb drin ist.. zb. Anzahl 1x
Und ich halt nochmal auf Kaufen klicke damit nocheinmal der selbe artikel hinzuaddiert wird, dann wird nicht nur +1 gerechnet sondern irgendwie gleich in zweierschritten.
update TAB set anzahl = anzahl + 1
Das ist aber auch nur Sporadisch.

Hatte mir schonmal das cacheverhalten von php selbst angeschaut und auch deaktiviert gehabt, was aber zu keiner ergebnissänderung führte...
realpath_cache_ttl = 120
realpath_cache_size = 16K
(seit php5 vorhanden)

Also, das es an meinem Browser liegt glaub ich eigentlich eher auch kaum, weil ich schon immer mit recht vielen If abfragen programmiere und das hier das erstemal ist das ich solch probleme habe.

Edit: hab es auch schon mit normalen mysql_query() anfragen probiert, aber ist das gleiche...
 
Hab ich doch gesagt..
die ausgabe ist TRUE
das ist für diesen fall insert und Update (wenn erfolgreich) immer so.
 
versuch es doch mal so

PHP:
        // Eintragum 1 erhöhen.
        $query = "UPDATE shop_warenkorb SET artikel_anzahl = artikel_anzahl + 1 WHERE session = '".session_id()."' AND artikel_name = '".$row['script_name']."'";
        $result = @mysql_query($query);
 
        // Noch kein Eintrag?
        if (mysql_affected_rows() == 0) {
            $sql_insert = "INSERT INTO `shop_warenkorb` (`session`,`artikel_name`,`artikel_anzahl`,`artikel_preis`,`set_time`) VALUES ('".session_id()."', '".$row['script_name']."', '1', '".$artikel_preis."', '".time()."')";
            @mysql_query($sql_insert);
        }
 
pHx,
hab es probiert.. es wurde nur noch schlimmer... ^^ anstatt eins einzutragen trägt er nicht nicht nur 2 ein sondern gleich 3 ^^
hmm ebend nochmal getestet, dann waren es nur noch 2 ^^ Naja ist halt auch wieder Sporadisch 3 oder 2 ... ^^ rofl ich verzweifle ^^

Wie gesagt.. komme über über die Seite details.php auf kaufen.php so trägt der 2x ein bzw update.

bin ich schon auf kaufen.php und entferne nur die session aus dem browser und entferne die einträge aus dem warenkorb manuell und aktuallisiere dann die kaufen.php, dann funktioniert es, er trägt es nur einmal ein.
 
versuch es doch mal so

... oder gleich eine Lösung mit ON DUPLICATE KEY UPDATE ;)

UNIQUE KEY auf die Session und den Script-Namen.

PHP:
<?php
include("inc/config.php");

/*
$_GET['id'] ist die übertragene ID des zu kaufenden Artikels/Produktes
*/
// ESCAPEN!
$sql = dbquery("SELECT * FROM shop_artikel WHERE script_id = '".$_GET['id']."' AND script_menge != 0 LIMIT 1");
if( mysql_num_rows($sql) == 1 )
{
  //Artikel vorhanden
  $row = mysql_fetch_assoc($sql); // _array ist RESOURCENVERSCHWENDUNG!
    $artikel_preis = $row['script_price'];
    // ESCAPEN nicht vergessen ;)
    $addTo = dbquery("INSERT INTO shop_warenkorb(session, artikel_name [..]) VALUES('" . session_id() . "', '" . $row['script_name'] . "', [...]) ON DUPLICATE KEY UPDATE artikel_anzahl = artikel_anzahl + 1");
  
  if( $addTo == true )
  {
    $_SESSION['warenkorb'] = true;
    $meldung['artikelname'] = '1x '.$row['script_name'];
    $meldung['produkt_id'] = $_GET['id'];
    $Cboxen = cBox($row['script_name'].' wurde in den Warenkorb gelegt', tpl_read('c_produkt_bestellen',$meldung));
  }else{
    /* Warenkorb eintrag war fehlerhaft */
    $meldung['code'] = 'Warenkorb';
    $meldung['beschreibung'] = 'Der gewünschte Artikel konnte aus einem Unbekannten grund nicht in den Warenkorb gelegt werden.';
    $Cboxen = cBox('Artikel wurde nicht im Warenkorb abgelegt', tpl_read('c_fehlerseite',$meldung));
  }

}else{
  //Produkt ID fehlerhaft
  $Cboxen = cBox('Fehlerhafte Artikel-ID', tpl_read('c_no_produkt_details'));
  $Nboxen = nBox_zufallsprodukt().nBox_newprodukt();
}
template($Cboxen,$Nboxen); 
?>

So in etwa. Ich habe noch einige Anmerkungen im Quellcode hinterlassen ;)

Greetz

paddya

Edit: session_start() machst du in der Config?
 
Zuletzt bearbeitet:
Danke Paddya,

leider ist das ebenfalls die gleiche wirklich wie alle anderen Methoden welche bereits genannt wurden.. und das problem besteht weiterhin...
Aber danke für den tip mit mysql_fetch_assoc() = wenn es nur einen datensatz betrifft ^^

Das mit Deinem Escapen hab ich nicht ganz verstanden..
Warum machst du hier kein Escape... "SELECT * FROM shop_artikel WHERE script_id = '".$_GET['id']."' AND script_menge != 0 LIMIT 1"

Benutzt:
PHP:
  $addTo = dbquery("INSERT INTO shop_warenkorb (session,artikel_name,artikel_anzahl,artikel_preis,set_time) VALUES('".session_id()."', '".$row['script_name']."', '1', '".$artikel_preis."', '".time()."') ON DUPLICATE KEY UPDATE artikel_anzahl = artikel_anzahl + 1");

Ja in der Config wird die session gestartet.. in der Config steht auch nichts weltbewegendes bis auf folgendes....
PHP:
session_name($cfg['session_name']);
session_start();

include( ROOT.DIR."/inc/function.php" );
dbconnect();
 
Das mit Deinem Escapen hab ich nicht ganz verstanden..
Warum machst du hier kein Escape... "SELECT * FROM shop_artikel WHERE script_id = '".$_GET['id']."' AND script_menge != 0 LIMIT 1"

Du sollst $_GET['id'] mit mysql_real_escape_string() escapen. Die 0 habe ich nicht in Anführungszeichen geschrieben, weil das kein String sondern ein Integer ist. Im MySQL-Strict-Mode würde das zu einem Fehler führen. Warum also nicht gleich richtig machen?

Benutzt:
PHP:
  $addTo = dbquery("INSERT INTO shop_warenkorb (session,artikel_name,artikel_anzahl,artikel_preis,set_time) VALUES('".session_id()."', '".$row['script_name']."', '1', '".$artikel_preis."', '".time()."') ON DUPLICATE KEY UPDATE artikel_anzahl = artikel_anzahl + 1");

UNIQUE KEY hast du über die Spalten session und artikel_name gelegt? Ansonsten wird das nicht gehen.

Ja in der Config wird die session gestartet.. in der Config steht auch nichts weltbewegendes bis auf folgendes....
PHP:
session_name($cfg['session_name']);
session_start();

include( ROOT.DIR."/inc/function.php" );
dbconnect();

Evtl. wird irgendwie etwas doppelt inkludiert o.Ä. ändere mal alle Statements in include_once bzw. require_once. Evtl. hilft das bei der Fehlersuche ;)

Greetz

paddya
 
mysql_real_escape_string() wird bereits in der funktion dbquery() durchgeführt durch alle übergebenenen Variablen

paddya schrieb:
UNIQUE KEY hast du über die Spalten session und artikel_name gelegt?
Ja, habe ich... ebenfalls gemacht, vorher war nur ein index auf session drauf, welches ich zuvor entfernte.

paddya schrieb:
Evtl. wird irgendwie etwas doppelt inkludiert o.Ä. ändere mal alle Statements in include_once bzw. require_once. Evtl. hilft das bei der Fehlersuche
Jop, hab es schon so am laufen in der aktuellen version.. weil ich auch schon daran dachte (was aber eigentlich unmöglich ist, es wird nur die Config mit der funktions.php includiert ^^ und in der funktion selsbt sind reine funktionen welche wenn überhaupt nur SELECT anfragen beinhalten.
 
mysql_real_escape_string() wird bereits in der funktion dbquery() durchgeführt durch alle übergebenenen Variablen

Du übergibst an die Funktion nur ein Argument: das zusammengebaute SQL-Statement. Wendest du dadrauf jetzt mysql_real_escape an, werden Quotes escaped.

PHP:
mysql_real_escape_string("SELECT foo FROM bar WHERE text = 'Test'");

führt zu:

Code:
SELECT foo FROM bar WHERE text = \'Test\'

Das zieht einen MySQL-Error nach sich.

Greetz

paddya
 
Hmm das konnte ich bisher noch nicht feststellen, das sowas passierte ^^
PHP:
function dbquery($query)
{
	$args=func_get_args();
	$vargs=array();
	for($i=1;$i<func_num_args();$i++) {
		if(get_magic_quotes_gpc()) {
		$args[$i]=stripslashes($args[$i]);
		}
	$vargs[]=mysql_real_escape_string($args[$i]);
	}
	$query=vsprintf($query,$vargs);
	$res=mysql_query($query);
return($res);
}

Aber, das sql-injektion ist ja nun erstmal nebensache.. das hauptproblem besteht weiterhin :(
Naja, ich glaub das problem liegt wohl nicht unbedingt am script selbst, vielleicht liegt es ja auch am PHP oder sonst irgendwas, obwohl es php nicht sein dürfte, weil dann würden verschiedene andere seiten das selbe problem aufweisen ^^
 
Hmm das konnte ich bisher noch nicht feststellen, das sowas passierte ^^

Lass dir mal sicherheitshalber das endgültige SQL-Statement ausgeben, das dann ausgeführt wird.

Edit: Übrigens ist vsprintf() bei deinen Queries eh überflüssig, weil du immer nur ein Argument übergibst (das SQL-Statement) ;)

Greetz

paddya
 
Zum Hauptproblem...

habs nun anders gelöst, ohne eine weitere Datei zu benutzen.
Hab es nun einfach in die details.php mit rein gepackt und da funktioniert es ohne probleme... Wird immer nur eines übernommen.
Was nen misst hier aber auch..

edit: wenn ich anstatt nur das geht übergebe auch noch durch is_numeric($_GET['id']) es auf einen rein numerischen wert prüfe sollt es ja auch funktionieren ^^

Hab glaube den fehler gefunden.. es liegt doch an der htaccess datei..
Code:
    ### Rewrite Produkt Bestellen ###
    RewriteRule ^produkt_([0-9]+)_bestellen\.html$ produkt_bestellen.php?id=$1&in_warenkorb [L,QSA]
    RewriteRule ^produkt_([0-9]+)_bestellen\.php$ produkt_bestellen.php?id=$1&in_warenkorb [L,QSA]


EDIT-II: hmm nach nochmaligen Test's liegt es doch nicht an der htaccess, sondern eher daran, das von details.php nicht auf kaufen.php per GET verwiesen werden darf sondern nur per POST
Was ich wiederum absolut nicht verstehe warum des nicht per GET richtig funktioniert.
Aber egal. es Tut nun ^^


PS: Ich danke allen die sich hier beteiligt haben um das Problem zu lösen... auch wenn es nicht wirklich den erfolg hatte welches ich mir erhoffte, aber tut ja nun per POST
 
Zuletzt bearbeitet: