Kapitel 10
warenkorb.php – Warenkorb anzeigen
Hier passiert das interessantere PDO-Konstrukt: eine dynamische IN-Query. Weil man in Prepared Statements keine Arrays als Parameter binden kann, muss man die Fragezeichen manuell bauen.
Der Code
warenkorb.php
<?php
require_once('db.php');
session_start();
$warenkorb = $_SESSION['warenkorb'] ?? [];
$produkte_im_korb = [];
$gesamtsumme = 0;
// produktdaten aus db holen (falls warenkorb nicht leer)
if (!empty($warenkorb)) {
// liste von ids
$ids = array_keys($warenkorb);
// für jede id ein ? erzeugen und mit komma verbinden: "?,?,?"
// grund: prepared statements akzeptieren keine arrays als parameter,
// jedes element braucht sein eigenes ?
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$stmt = $conn->prepare("SELECT id, name, price, picture
FROM products
WHERE id IN ($placeholders)");
$stmt->execute($ids);
$produkte = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($produkte as $produkt) {
$menge = $warenkorb[$produkt['id']];
$zwischensumme = $produkt['price'] * $menge;
$gesamtsumme += $zwischensumme;
$produkte_im_korb[] = [
'id' => $produkt['id'],
'name' => $produkt['name'],
'price' => $produkt['price'],
'picture' => $produkt['picture'],
'menge' => $menge,
'zwischensumme' => $zwischensumme,
];
}
}
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Warenkorb</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<?php include('navbar.php'); ?>
<h1>Warenkorb</h1>
<?php if (empty($produkte_im_korb)): ?>
<p>Dein Warenkorb ist leer.</p>
<a href="index.php">Zurück zur Übersicht</a>
<?php else: ?>
<table border="1" cellpadding="8">
<tr>
<th>Produkt</th><th>Preis</th><th>Menge</th>
<th>Zwischensumme</th><th>Aktion</th>
</tr>
<?php foreach ($produkte_im_korb as $item): ?>
<tr>
<td><?= htmlspecialchars($item['name'], ENT_QUOTES, 'UTF-8') ?></td>
<td><?= number_format($item['price'], 2, ',', '.') ?> €</td>
<td><?= (int)$item['menge'] ?></td>
<td><?= number_format($item['zwischensumme'], 2, ',', '.') ?> €</td>
<td>
<form action="cart_remove.php" method="POST" style="display:inline;">
<input type="hidden" name="produkt_id" value="<?= (int)$item['id'] ?>">
<button type="submit">Entfernen</button>
</form>
</td>
</tr>
<?php endforeach; ?>
<tr>
<td colspan="3"><strong>Gesamtsumme:</strong></td>
<td colspan="2"><strong><?= number_format($gesamtsumme, 2, ',', '.') ?> €</strong></td>
</tr>
</table>
<br>
<a href="index.php">Weiter einkaufen</a>
<a href="checkout.php">Zur Kasse</a>
<?php endif; ?>
</body>
</html>
Der Kern: dynamische IN-Query erklärt
Wenn im Warenkorb z.B. die Produkt-IDs 3, 7 und 12 stecken, will man SELECT ... WHERE id IN (3, 7, 12). Naiver Ansatz:
// FALSCH – SQL Injection!
$sql = "SELECT ... WHERE id IN (" . implode(',', $ids) . ")";
$conn->query($sql);
Warum falsch? Weil $ids aus der Session kommt, und wer weiß was da drin steht – wenn irgendwo im Code mal eine unbedachte User-Eingabe reingerät, ist die Query offen.
Richtige Lösung: für jede ID ein ? erzeugen, dann mit den Werten binden.
// bei 3 ids: "?,?,?"
$placeholders = implode(',', array_fill(0, count($ids), '?'));
// eingebaut in query
$stmt = $conn->prepare("SELECT ... WHERE id IN ($placeholders)");
$stmt->execute($ids); // ids als array übergeben
- array_fill(0, count($ids), '?') – erzeugt ein Array mit so vielen
'?'-Einträgen wie IDs. - implode(',', ...) – klebt sie mit Komma zusammen.
- execute($ids) – die Werte werden gebunden, sind garantiert safe.
Prüfer-Frage-Alarm: das ist ein Lieblings-Thema. Sei bereit zu erklären, warum ein simples
implode(',', $ids) in der Query gefährlich ist und warum die array_fill-Variante sicher ist.Zwei Schleifen absichtlich getrennt: erst DB-Ergebnisse holen, dann in einer zweiten Schleife das Anzeige-Array bauen (mit Zwischensumme). Getrennte Verantwortung – DB-Aggregation im PHP, nicht in SQL.