- Những sai lầm phổ biến khi validate số điện thoại
- Định dạng số điện thoại Việt Nam hiện nay (2026)
- Danh sách đầu số di động Việt Nam cập nhật 2026
- Chiến lược xử lý đúng
- Hàm validate số điện thoại Việt Nam (PHP — cập nhật 2026)
- Phiên bản JavaScript/TypeScript (Frontend)
- Vì sao không dùng regex một phát cho xong
- Ví dụ sử dụng thực tế
- Nên lưu số điện thoại theo format nào
- Bonus: Hàm chuẩn hóa + format hiển thị
- Kết luận
Những sai lầm phổ biến khi validate số điện thoại
- Chỉ kiểm tra độ dài 10 hoặc 11 số
- Dùng regex quá đơn giản
- Không chuẩn hóa
+84và0 - Không cập nhật đầu số mới
- Bỏ qua số cố định (landline) và số máy bàn mới
- Không kiểm tra đầu số đã bị thu hồi hay chưa
Kết quả: số rác vẫn lọt, số thật thì bị loại. Cả hai đều dở.
Định dạng số điện thoại Việt Nam hiện nay (2026)
Một số điện thoại di động Việt Nam hợp lệ có đặc điểm:
- Bắt đầu bằng
0hoặc+84 - Sau khi chuẩn hóa: 10 chữ số
- Đầu số thuộc nhà mạng hợp lệ và đang hoạt động
Ví dụ hợp lệ:
0912345678+849123456780912 345 678+84 912 345 678
Danh sách đầu số di động Việt Nam cập nhật 2026
| Nhà mạng | Đầu số | Ghi chú |
|---|---|---|
| Viettel | 032–039, 096–099 | Thị phần lớn nhất, đầu số 03x là chuẩn mới |
| MobiFone | 070–079, 089–090, 093 | Đầu số 07x chuyển đổi từ 11 số (2018) |
| VinaPhone | 081–088, 091–094 | Đầu số 08x chuyển đổi từ 11 số (2018) |
| Vietnamobile | 052–059 | Đầu số 05x chuyển đổi từ 11 số |
| Gmobile | 059 | Đã sáp nhập, một số đầu số chuyển nhượng |
| Reddi (Mobicast) | 055 | Mạng di động ảo (MVNO) mới |
| iTel (Indochina Telecom) | 087 | Mạng di động ảo (MVNO) |
| Wintel (Viettel + VNPT) | 092 | Mạng di động ảo (MVNO) |
Lưu ý: Từ năm 2018, VNPT và Bộ TT&TT đã chuyển đổi toàn bộ thuê bao 11 số về 10 số. Các đầu số 012x, 016x, 018x, 019x đã ngừng hoạt động.
Chiến lược xử lý đúng
- Chuẩn hóa chuỗi đầu vào — loại bỏ khoảng trắng, dấu chấm, gạch ngang, ngoặc
- Đưa về một format thống nhất (khuyến nghị
0xxxxxxxxx) - Kiểm tra chỉ chứa chữ số sau khi chuẩn hóa
- Kiểm tra độ dài chuẩn 10 số
- Kiểm tra đầu số hợp lệ theo danh sách nhà mạng cập nhật
Hàm validate số điện thoại Việt Nam (PHP — cập nhật 2026)
<?php
function validate_vietnam_phone(string $phone): bool
{
// 1. Loại bỏ khoảng trắng, dấu chấm, dấu gạch, ngoặc
$phone = trim($phone);
$phone = preg_replace('/[\s\.\-\(\)]/', '', $phone);
// 2. Chuẩn hóa +84 về 0
if (str_starts_with($phone, '+84')) {
$phone = '0' . substr($phone, 3);
}
// 3. Chỉ cho phép chữ số
if (!ctype_digit($phone)) {
return false;
}
// 4. Độ dài chuẩn (10 số)
if (strlen($phone) !== 10) {
return false;
}
// 5. Danh sách đầu số di động Việt Nam (cập nhật 2026)
$validPrefixes = [
// Viettel
'032','033','034','035','036','037','038','039',
'096','097','098','099',
// MobiFone
'070','076','077','078','079',
'089','090','093',
// VinaPhone
'081','082','083','084','085','086','088',
'091','092','093','094',
// Vietnamobile
'052','053','054','055','056','057','058','059',
// Gmobile
'059',
// MVNO
'055', // Reddi
'087', // iTel
'092', // Wintel
];
$prefix = substr($phone, 0, 3);
return in_array($prefix, $validPrefixes, true);
}
Phiên bản JavaScript/TypeScript (Frontend)
<script>
function validateVietnamPhone(phone) {
// 1. Chuẩn hóa
let cleaned = phone.trim().replace(/[\s\.\-\(\)]/g, '');
// 2. +84 → 0
if (cleaned.startsWith('+84')) {
cleaned = '0' + cleaned.slice(3);
}
// 3. Chỉ số
if (!/^\d+$/.test(cleaned)) return false;
// 4. Độ dài
if (cleaned.length !== 10) return false;
// 5. Đầu số hợp lệ (2026)
const validPrefixes = [
'032','033','034','035','036','037','038','039',
'096','097','098','099',
'070','076','077','078','079','089','090','093',
'081','082','083','084','085','086','088','091','092','093','094',
'052','053','054','055','056','057','058','059',
'087'
];
return validPrefixes.includes(cleaned.slice(0, 3));
}
</script>Vì sao không dùng regex một phát cho xong
Regex có thể gộp tất cả vào một dòng, nhưng:
- Khó đọc, khó bảo trì
- Đầu số đổi là sửa mệt nghỉ
- Không tái sử dụng logic chuẩn hóa cho các phần khác (format, lưu DB)
- Khó viết unit test riêng từng bước
Tách từng bước như trên giúp:
- Dễ debug — biết chính xác bước nào fail
- Dễ mở rộng — thêm đầu số mới chỉ cần sửa 1 mảng
- Dễ viết test — test từng hàm nhỏ riêng biệt
- Không cần đọc regex mà đoán ý đồ tác giả
Ví dụ sử dụng thực tế
<?php
$phone = $_POST['phone'] ?? '';
if (!validate_vietnam_phone($phone)) {
http_response_code(400);
die(json_encode(['error' => 'Số điện thoại không hợp lệ']));
}
// Chuẩn hóa trước khi lưu
$normalized = normalize_vietnam_phone($phone); // trả về 0xxxxxxxxx
// An tâm lưu database
save_to_db($normalized);
Nên lưu số điện thoại theo format nào
Khuyến nghị:
- Lưu dạng
0xxxxxxxxx— dễ đọc, dễ hiển thị, phổ biến ở VN - Hoặc chuẩn E.164:
+84xxxxxxxxx— nếu làm hệ thống đa quốc gia, gửi SMS qua API quốc tế
Quan trọng nhất: chỉ lưu một format duy nhất. Đừng để mỗi bản ghi một kiểu. Nếu cần hiển thị đẹp, format lúc render — đừng format lúc lưu.
Bonus: Hàm chuẩn hóa + format hiển thị
<?php
function normalize_vietnam_phone(string $phone): string
{
$phone = preg_replace('/[\s\.\-\(\)]/', '', trim($phone));
if (str_starts_with($phone, '+84')) {
$phone = '0' . substr($phone, 3);
}
return $phone;
}
function format_vietnam_phone(string $phone): string
{
// Giả sử đã chuẩn hóa dạng 0xxxxxxxxx
if (strlen($phone) === 10) {
return substr($phone, 0, 4) . ' ' . substr($phone, 4, 3) . ' ' . substr($phone, 7, 3);
}
return $phone;
}
// Ví dụ:
// Input: +84 912 345 678
// Normalize: 0912345678
// Format: 0912 345 678
Kết luận
Validate số điện thoại không khó, cái khó là làm cho đúng và bền. Một hàm rõ ràng, từng bước, cập nhật đầu số đầy đủ sẽ giúp backend sạch dữ liệu, frontend đỡ chửi, và bạn đỡ phải viết script dọn rác sau này.
Nhập bừa là bản năng người dùng, xử lý gọn là trách nhiệm của backend!

Bình luận