Support kontaktieren

Wir melden uns per E-Mail. Meist innerhalb von zwei Tagen.

Zum Schutz vor Missbrauch prüft Google reCAPTCHA diese Einsendung. Dabei werden Daten an Google übertragen. Das Skript wird erst geladen, wenn Sie dieses Formular öffnen.

← Alle Beiträge

Die Prüfung, die immer wahr ist

In diesem Dienst stehen 23 UPDATE-Anweisungen. Genau eine davon sieht nach, ob sie etwas geändert hat. Diese Prüfung lautet:

'success' => $n->rowCount() >= 0

rowCount() liefert 0, wenn keine Zeile passte. Null ist größer oder gleich null. Die Prüfung geht durch, was auch immer passiert.

23 UPDATE-Anweisungen, eine davon sieht auf das Ergebnis rowCount() >= 0 — geht durch, auch wenn nichts passte rowCount() > 0 im ganzen Code: 0 Mal Zähler mit einer Zeile in der Tabelle, die es ändert: 4 von 2.218 heute ist nichts kaputt — aus einem Grund, der nicht diese Zeile ist

Wofür die Anweisung da ist

Sie speichert einen Haken: ob der Besitzer eines Zählers eine Wochenübersicht per E-Mail möchte. Die Adresse steht in einer eigenen Tabelle, und eine Zeile entsteht dort erst, wenn jemand den Bestätigungsverweis in einer Mail angeklickt hat, um die er gebeten hat. Vier Zähler haben so eine Zeile. Aktive gibt es 2.218.

Für 99,8 % der Zähler trifft das UPDATE also nichts. Der Endpunkt antwortet success: true, und die Einstellung wird nicht gespeichert, weil es nichts gibt, worin man sie speichern könnte.

Der Kommentar darüber stimmt

Drei Zeilen höher, in derselben Funktion:

„Nur wo ein bestätigter Rückweg steht. Ohne ihn gibt es keine Adresse, an die der Brief gehen könnte — und der Haken hätte etwas versprochen, was nicht passiert."

Das ist genau richtig. Jemand hat über diesen Fall nachgedacht, ihn verstanden und die Überlegung aufgeschrieben. Dann hat die Zeile darunter >= benutzt, wo die Überlegung > verlangte.

Das lohnt einen geraden Blick, denn die übliche Erklärung — es hat keiner bedacht — steht bereit und ist falsch. Der Gedanke steht in der Datei. Gescheitert ist ein Zeichen, an einer Stelle, an der die falsche und die richtige Fassung auf den ersten Blick gleich aussehen und sich in jedem Test gleich verhalten, der eine Zeile zum Aktualisieren hat.

Niemand wird belogen

Jetzt der Teil, den man leicht weglassen könnte, und dessen Weglassen diesen Beitrag dramatischer und unwahrer machte.

Die Seite zeichnet diesen Haken gar nicht, wenn die Zeile fehlt. Einen Bildschirm weiter, in dem Code, der den Besitzerkasten baut, wird dieselbe Tabelle zuerst gefragt, und der ganze Block wird übersprungen, wenn die Abfrage leer zurückkommt. Ein Besitzer ohne bestätigte Adresse sieht die Schaltfläche also nie, klickt sie nie an und bekommt nie die falsche Bestätigung.

Die kaputte Prüfung ist nur erreichbar, wenn man den Endpunkt direkt mit einem gültigen Token aufruft. Wer das tut, bekommt success: true und keine gespeicherte Einstellung. Das ist ein echter Mangel, und ein schmaler.

Warum es trotzdem aufschreibenswert ist

Die Funktion ist sicher wegen eines Riegels, den niemand als Riegel aufgeschrieben hat. Die Zeile, die es sicher machen soll, macht es nicht sicher. Was es tut, ist eine Bedingung beim Zeichnen in einer anderen Funktion, deren Kommentar erklärt, warum der Haken versteckt wird — nicht, dass irgendetwas davon abhängt, dass er versteckt bleibt.

Entfernt oder verschiebt man diese Bedingung — eine vernünftige Sache beim Umbau eines Einstellungskastens — wird der Mangel sofort sichtbar, und nichts verbindet die beiden Änderungen miteinander. Die Sicherheit ist echt, sie ist zufällig, und zufällige Sicherheit ist die Sorte, die bei fremder Arbeit verschwindet.

Derselbe Code macht es eine Datei weiter richtig. Die entsprechende Funktion des Webrings fragt, ob die Zeile existiert, gibt falsch zurück, wenn nicht, und schickt das Update gar nicht erst ab. Diese Tabelle hat derzeit null Zeilen, die Funktion gibt also bei jedem Aufruf falsch zurück — und das ist die richtige Antwort.

Die allgemeine Form

Ein UPDATE, das keine Zeile trifft, ist in keiner Datenbank ein Fehler. Es ist eine erfolgreiche Anweisung, die nichts getan hat, und jede Schicht darüber meldet Erfolg, solange nicht jemand nachfragt. Zweiundzwanzig der Anweisungen hier fragen nicht nach, und bei den meisten ist das in Ordnung: sie aktualisieren eine Zeile, deren Existenz die Anfrage schon bewiesen hat.

Die eine, die nachfragen musste, hat auf eine Art nachgefragt, die nicht durchfallen kann. rowCount() >= 0 ist keine schwache Prüfung, es ist das Fehlen einer Prüfung im Kostüm einer — und das ist schlimmer als gar keine, denn der Nächste, der die Funktion liest, sieht ein geprüftes Ergebnis und hört auf hinzusehen.

Die Wendung rowCount() > 0 kommt in diesem Code null Mal vor. Das ist die Zahl, die aus einem Tippfehler etwas macht, das einen Beitrag wert ist: nicht, dass es einmal falsch geschrieben wurde, sondern dass es nirgends ein richtiges Vorkommen gab, an dem man es hätte messen können.

Behoben am 28. August 2026. Der Endpunkt fragt jetzt vor dem Schreiben, ob die Zeile existiert — so, wie es die Webring-Funktion eine Datei weiter schon immer tat — und antwortet sonst mit falsch. Der naheliegende Ein-Zeichen-Fix, stattdessen auf größer als null zu prüfen, wurde vorher gemessen und verworfen: der Treiber meldet die Zahl der geänderten Zeilen, nicht der getroffenen. Wer den Haken auf den Wert setzt, auf dem er schon steht, ändert nichts — und diese Fassung hätte einen Fehlschlag für einen Vorgang gemeldet, der in Ordnung war. Beide Fassungen sind falsch, nur in verschiedene Richtungen.

Anzeige