11 von 16

Warenkorb · Kapitel 11 von 16

PHP · MySQL · HTML/CSS – Schritt für Schritt

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.

16 Kapitel · ein Projekt

Der Codeinander Lernpfad

DEEN in Vorbereitung

Grundlagen

01GrundlagenIntro & Setup 02GrundlagenDatenbank-Schema 03Grundlagendb.php – Verbindung

Auth

04Authregister.php 05Authlogin.php 06Authlogout.php

Shop

07Shopnavbar.php 08Shopindex.php – Liste 09Shopproductdetail.php

Warenkorb

10Warenkorbcart_add.php 11Warenkorbwarenkorb.php 12Warenkorbcart_remove.php

Admin

13Adminstatistiken.php + Admin 14Admincheckout.php + Rechnung

Referenz

15ReferenzSQL-Cheatsheet 16Referenzzertifizierung-Checkliste