Επικοινωνία με την υποστήριξη

Απαντάμε μέσω e-mail, συνήθως μέσα σε δύο ημέρες.

Το Google reCAPTCHA ελέγχει αυτή την υποβολή για κατάχρηση· δεδομένα αποστέλλονται στην Google. Το script φορτώνεται μόνο όταν ανοίξει αυτή η φόρμα.

← Όλα τα άρθρα

Ο έλεγχος που είναι πάντα αληθής

Υπάρχουν 23 εντολές UPDATE στον κώδικα αυτής της υπηρεσίας. Ακριβώς μία από αυτές ελέγχει αν άλλαξε κάτι. Ο έλεγχος αυτός είναι:

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

rowCount() επιστρέφει 0 όταν δεν ταίριαξε καμία γραμμή. Το μηδέν είναι μεγαλύτερο ή ίσο του μηδενός. Ο έλεγχος περνά ό,τι κι αν συμβεί.

23 εντολές UPDATE, μία από αυτές κοιτάζει το αποτέλεσμα rowCount() >= 0 — περνά ακόμη κι όταν δεν ταίριαξε τίποτα rowCount() > 0 σε ολόκληρο τον κώδικα: 0 φορές μετρητές με γραμμή στον πίνακα που ενημερώνει: 4 από 2.218 τίποτα δεν είναι χαλασμένο σήμερα — για λόγο που δεν είναι αυτή η γραμμή

Σε τι χρησιμεύει η εντολή

Αποθηκεύει ένα πλαίσιο επιλογής: αν ο κάτοχος ενός μετρητή θέλει εβδομαδιαία σύνοψη με e-mail. Η διεύθυνση βρίσκεται σε ξεχωριστό πίνακα, και μια γραμμή εμφανίζεται εκεί μόνο αφού κάποιος πατήσει τον σύνδεσμο επιβεβαίωσης σε ένα μήνυμα που ο ίδιος ζήτησε. Τέσσερις μετρητές έχουν τέτοια γραμμή. Ενεργοί είναι 2.218.

Έτσι, για το 99,8% των μετρητών το UPDATE δεν ταιριάζει με τίποτα. Το endpoint απαντά success: true και η ρύθμιση δεν αποθηκεύεται, γιατί δεν υπάρχει πού να αποθηκευτεί.

Το σχόλιο από πάνω είναι σωστό

Τρεις γραμμές πιο πάνω, στην ίδια συνάρτηση:

«Μόνο όπου υπάρχει επιβεβαιωμένη διαδρομή επιστροφής. Χωρίς αυτήν δεν υπάρχει διεύθυνση στην οποία θα μπορούσε να σταλεί η εβδομαδιαία αναφορά — και το πλαίσιο επιλογής θα είχε υποσχεθεί κάτι που δεν συμβαίνει.»

Αυτό είναι απολύτως σωστό. Κάποιος σκέφτηκε αυτή την περίπτωση, την κατάλαβε και κατέγραψε το σκεπτικό. Έπειτα η γραμμή από κάτω χρησιμοποίησε το >= εκεί όπου το σκεπτικό απαιτούσε >.

Αξίζει να το δει κανείς κατάματα, γιατί η συνηθισμένη εξήγηση — δεν το σκέφτηκε κανείς — είναι διαθέσιμη και λανθασμένη. Η σκέψη βρίσκεται μέσα στο αρχείο. Αυτό που απέτυχε είναι ένας χαρακτήρας, σε ένα σημείο όπου η λάθος και η σωστή εκδοχή φαίνονται πανομοιότυπες με μια ματιά και συμπεριφέρονται πανομοιότυπα σε κάθε δοκιμή όπου υπάρχει γραμμή προς ενημέρωση.

Κανείς δεν εξαπατάται

Ακολουθεί το μέρος που θα ήταν εύκολο να παραλειφθεί, και η παράλειψή του θα έκανε αυτό το άρθρο πιο δραματικό και λιγότερο αληθινό.

Η σελίδα δεν εμφανίζει αυτό το πλαίσιο επιλογής αν δεν υπάρχει η γραμμή. Μία οθόνη πιο πέρα, στον κώδικα που σχεδιάζει το πλαίσιο ρυθμίσεων του κατόχου, γίνεται πρώτα ερώτημα στον ίδιο πίνακα, και ολόκληρο το τμήμα παραλείπεται όταν το ερώτημα επιστρέψει κενό. Έτσι ένας κάτοχος μετρητή χωρίς επιβεβαιωμένη διεύθυνση δεν βλέπει ποτέ το στοιχείο ελέγχου, δεν το πατά ποτέ και δεν λαμβάνει ποτέ την ψευδή επιβεβαίωση.

Ο χαλασμένος έλεγχος είναι προσβάσιμος μόνο αν κληθεί το endpoint απευθείας με έγκυρο token. Όποιος το κάνει αυτό παίρνει success: true και καμία αποθηκευμένη ρύθμιση. Είναι ένα πραγματικό ελάττωμα, αλλά περιορισμένο.

Γιατί αξίζει παρ' όλα αυτά να καταγραφεί

Η λειτουργία είναι ασφαλής χάρη σε μια δικλίδα που κανείς δεν κατέγραψε ως δικλίδα. Η γραμμή που υπάρχει για να την κάνει ασφαλή δεν την κάνει ασφαλή. Αυτό που την κάνει ασφαλή είναι μια συνθήκη εμφάνισης σε άλλη συνάρτηση, της οποίας το σχόλιο εξηγεί γιατί το πλαίσιο επιλογής είναι κρυφό — όχι ότι κάτι εξαρτάται από το να παραμείνει κρυφό.

Αν αφαιρεθεί ή αναδιαρθρωθεί αυτή η συνθήκη εμφάνισης — κάτι εύλογο κατά τον επανασχεδιασμό ενός πλαισίου ρυθμίσεων — το ελάττωμα γίνεται αμέσως ορατό, χωρίς τίποτα να συνδέει πουθενά τις δύο αλλαγές. Η ασφάλεια είναι πραγματική, και είναι τυχαία, και η τυχαία ασφάλεια είναι εκείνη που εξαφανίζεται κατά τη διάρκεια άσχετων εργασιών.

Ο ίδιος κώδικας το κάνει σωστά ένα αρχείο πιο δίπλα. Η αντίστοιχη συνάρτηση του webring ρωτά αν υπάρχει η γραμμή, επιστρέφει false όταν δεν υπάρχει και δεν εκτελεί καθόλου την ενημέρωση. Αυτός ο πίνακας έχει προς το παρόν μηδέν γραμμές, οπότε η συνάρτηση επιστρέφει false κάθε φορά που καλείται, κάτι που είναι η σωστή απάντηση.

Το γενικό μοτίβο

Μια εντολή UPDATE που δεν ταιριάζει με καμία γραμμή δεν είναι σφάλμα σε καμία βάση δεδομένων. Είναι μια επιτυχημένη εντολή που δεν έκανε τίποτα, και κάθε επίπεδο πάνω από αυτήν θα αναφέρει επιτυχία, εκτός αν κάτι ρωτήσει. Είκοσι δύο από τις εντολές εδώ δεν ρωτούν, και για τις περισσότερες αυτό είναι εντάξει: ενημερώνουν μια γραμμή για την οποία το αίτημα έχει ήδη αποδείξει ότι υπάρχει.

Εκείνη που χρειαζόταν να ρωτήσει ρώτησε με τρόπο που δεν μπορεί να αποτύχει. Το rowCount() >= 0 δεν είναι αδύναμος έλεγχος, είναι η απουσία ελέγχου μεταμφιεσμένη σε έλεγχο — και είναι χειρότερο από την έλλειψη ελέγχου, γιατί ο επόμενος που θα διαβάσει τη συνάρτηση βλέπει ότι ένα αποτέλεσμα εξετάζεται και σταματά να ψάχνει.

Η έκφραση rowCount() > 0 εμφανίζεται μηδέν φορές σε αυτόν τον κώδικα. Αυτός είναι ο αριθμός που έκανε ένα τυπογραφικό λάθος ενός χαρακτήρα άξιο για άρθρο: όχι ότι γράφτηκε λάθος μία φορά, αλλά ότι δεν υπήρχε πουθενά σωστό παράδειγμα με το οποίο να συγκριθεί.

Διορθώθηκε στις 28 Αυγούστου 2026. Το endpoint τώρα ρωτά αν υπάρχει η γραμμή πριν από την ενημέρωση, όπως έκανε ήδη η συνάρτηση του webring ένα αρχείο πιο δίπλα, και απαντά false όταν δεν υπάρχει. Η προφανής διόρθωση ενός χαρακτήρα — σύγκριση με το «μεγαλύτερο από μηδέν» — μετρήθηκε πρώτα και απορρίφθηκε: ο driver αναφέρει τις γραμμές που άλλαξαν και όχι αυτές που ταίριαξαν, οπότε αν το πλαίσιο επιλογής οριστεί στην τιμή που έχει ήδη δεν αλλάζει τίποτα, και εκείνη η εκδοχή θα είχε αναφέρει αποτυχία για μια λειτουργία που ήταν εντάξει. Και οι δύο εκδοχές είναι λάθος, σε αντίθετες κατευθύνσεις.

Διαφήμιση