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 9 po 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)

  1. Poproś o kraj – Dodaj selektor kraju w formularzach rejestracyjnych i przekaż ten region do parsera.
  2. Pokaż formatowanie na żywo – Użyj formatowania typu „AsYouType”, aby użytkownicy widzieli poprawny wzorzec podczas pisania.
  3. 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.
  4. Zapisuj tylko ciąg E.164 – Przechowuj w bazie danych znormalizowany numer z prefiksem +.
  5. 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_number przy rejestracji na żywo; sprawdza to, czy numer jest zgodny z regionalnymi zasadami.
  • Używaj is_possible_number podczas 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ę.