Błąd logowania wynikający z niespójnego przechowywania numerów telefonów ujawnił lukę. Konto jednego użytkownika zostało zablokowane, ponieważ w bazie danych ten sam niemiecki numer mobilny figurował w dwóch formach – 0171 5550134 w jednym wierszu i +49 171 5550134 w drugim – przez co system traktował je jako osobne wpisy. Skutek: kod OTP nigdy nie dotarł, a przycisk „wyślij kod” stał się loterią.
Dlaczego numery telefonów są trudniejsze niż daty
Programiści często ufają wyrażeniom regularnym (regex), aby okiełznać wprowadzanie numerów telefonów. To zaufanie pryska w momencie, gdy numer przekracza granicę lub zmienia się plan krajowy. Daty podążają za przewidywalnym kalendarzem; numery telefonów mutują wraz z operatorami, regulacjami i konwencjami kulturowymi.
Ukryty koszt surowych ciągów znaków
Przechowywanie numeru telefonu jako zwykłego ciągu znaków wydaje się bezpieczne – dopóki dwie reprezentacje nie wskażą na tę samą linię. Systemy OTP, które zapytują bazę danych o „konkretny” numer, kończą wysyłając kod do duplikatu, który nigdy nie dotrze do użytkownika.
Problem pogłębia się, gdy numery znajdują się w polach numerycznych. Kolumna typu BIGINT usuwa znak + oraz wszelkie wiodące zera, zmieniając +49 171 5550134 w 491715550134. Bez znaku plusa odtworzenie oryginalnego formatu staje się zgadywaniem.
Standard E.164
Międzynarodowy plan numeracji telefonów, E.164, definiuje pojedynczą, przenośną reprezentację:
- Zaczyna się od
+ - Następnie kod kraju (1–3 cyfry)
- Następnie numer abonenta
- Łącznie nie więcej niż 15 cyfr
- Brak spacji, kropek czy myślników
E.164 nie gwarantuje, że numer jest aktywny; gwarantuje jedynie, że ciąg znaków jest zgodny z poprawnym wzorcem strukturalnym. Traktuj go jako kontrakt formatu, a nie wyrocznię dostępności.
Typowe pułapki, których regex nie naprawi
- Przechowywanie numeryczne – BIGINT odrzuca
+i wiodące zera. Zamiast tego użyj kolumny tekstowej (TEXT lub VARCHAR). - Sztywne wyrażenia regularne – Plany krajowe się zmieniają. Meksyk zrezygnował ze swojego prefiksu trunkowego w 2019 roku; Argentyna wymaga obecnie cyfry
9po kodzie kraju dla linii komórkowych. Statyczny wzorzec szybko staje się przestarzały. - Ślepe usuwanie zer – Włoskie numery stacjonarne zachowują wiodące zero, niemieckie nie. Zasada „usuń wszystkie wiodące zera” uszkodzi włoskie dane, pozostawiając niemieckie numery bez zmian.
- Zakładanie, że format oznacza możliwość doręczenia – libphonenumber waliduje strukturę, ale nie potrafi stwierdzić, czy telefon jest włączony lub czy numer został przeniesiony.
Budowanie niezawodnego potoku danych (pipeline)
- Poproś o kraj – Dodaj selektor kraju w formularzach rejestracyjnych i przekaż ten region do parsera.
- Pokaż formatowanie na żywo – Użyj formatowania typu „AsYouType”, aby użytkownicy widzieli poprawny wzorzec podczas pisania.
- Waliduj przy utracie fokusu (on blur) – Uruchamiaj walidację po tym, jak użytkownik opuści pole, a nie przy każdym naciśnięciu klawisza; zmniejsza to tarcie.
- Zapisuj tylko ciąg E.164 – Przechowuj w bazie danych znormalizowany numer z prefiksem
+. - Formatuj na brzegu (na interfejsie) – Przywracaj czytelny dla człowieka układ dopiero w UI lub szablonach e-mail.
Podczas migracji danych legacy zachowaj wiersze, które nie przechodzą walidacji. Przeanalizuj każdy istniejący wpis do nowej kolumny, oznacz błędy i wygeneruj raport. Ciche usuwanie danych tworzy zgłoszenia do wsparcia, które później zamieniają się w kosztowne poprawki.
Szybka lista kontrolna dla programistów
- Przechowuj numery jako TEXT/VARCHAR w formacie E.164.
- Używaj biblioteki libphonenumber od Google; radzi sobie ona z chaotyczną rzeczywistością globalnych planów numeracji.
- Podaj domyślny region dla użytkowników, którzy pomijają kod kraju.
- Wywołuj
is_valid_numberprzy rejestracji na żywo; sprawdza to, czy numer jest zgodny z regionalnymi zasadami. - Używaj
is_possible_numberpodczas czyszczenia masowych danych; wyłapuje ona ewidentnie błędne wpisy bez odrzucania przypadków granicznych.
Prawidłowa obsługa numerów telefonów to nie jest dodatek typu „nice-to-have”; to wymóg konieczny dla każdego systemu polegającego na niezawodnym kontakcie z użytkownikiem. Poprzez normalizację do standardu E.164 i delegowanie parsowania do sprawdzonej biblioteki, programiści eliminują całą klasę błędów, które po cichu niszczą zaufanie i przychody. Traktuj numery telefonów jako dane ustrukturyzowane, a nie tekst swobodnego formatu, i pozwól standardom wykonać najcięższą pracę.
