9-bo‘lim
Validatsiya va tozalash
filter_var, qayta ishlatiladigan tekshiruv qatlami, xato xabarlari va tozalash bilan tekshirish orasidagi farq.
Ushbu bo‘lim mundarijasi
Validatsiya - bu "yomon belgilarni o'chirish" emas. Validatsiya - "bu qiymat men kutgan narsami?" degan savolga javob berish.
Farqi katta va bu bo'lim aynan shu haqda.
Tekshirish va tozalash - ikki boshqa ish #
// Har bir misol qat'iy turlar rejimida ishlaydi.
$kirishlar = [
"[email protected]",
"husanboy@example",
" [email protected] ",
"<script>alert(1)</script>@example.com",
"",
];
printf("%-42s %-10s %s\n", "KIRISH", "TEKSHIR", "TOZALANGAN");
echo str_repeat("-", 74) . "\n";
foreach ($kirishlar as $k) {
$tekshir = filter_var(trim($k), FILTER_VALIDATE_EMAIL);
$toza = filter_var($k, FILTER_SANITIZE_EMAIL);
printf(
"%-42s %-10s %s\n",
mb_strlen($k) > 40 ? mb_substr($k, 0, 37) . "..." : "'{$k}'",
$tekshir === false ? "RAD" : "OK",
$toza === "" ? "(bo'sh)" : $toza
);
}
KIRISH TEKSHIR TOZALANGAN
--------------------------------------------------------------------------
'[email protected]' OK [email protected]
'husanboy@example' RAD husanboy@example
' [email protected] ' OK [email protected]
'<script>alert(1)</script>@example.com' RAD [email protected]
'' RAD (bo'sh)
Jadvalning oxirgi ustuniga qarang. FILTER_SANITIZE_EMAIL
<script> dan ba'zi belgilarni olib tashladi va
"tozalangan" qiymat qaytardi - lekin bu qiymat hali
ham email emas.
Farqni tushunish muhim:
| Validatsiya | Tozalash | |
|---|---|---|
| Savol | "To'g'rimi?" | "Xavfsiz qilaylik" |
| Javob | true / false | O'zgartirilgan qiymat |
| Xato holatda | Rad etadi | Jimgina o'zgartiradi |
| Foydalanuvchiga | Xato xabari | Hech narsa |
Tozalash xavfli, chunki u muammoni yashiradi. Foydalanuvchi noto'g'ri email yozdi - siz uni jimgina "tuzatdingiz" va bazaga yozdingiz. Endi xat hech qachon yetib bormaydi va hech kim sababini bilmaydi.
Amaliy qoida:
| Bosqich | Nima qilinadi |
|---|---|
| Qabul qilish | Validatsiya - noto'g'ri bo'lsa rad et |
| Saqlash | Qiymatni o'zgartirmasdan yozish |
| Chiqarish | Ekranlash (htmlspecialchars) |
Diqqat: FILTER_SANITIZE_* filtrlarining ko'pi PHP 8.1
dan boshlab eskirgan deb belgilangan. Ularni
ishlatmang.
filter_var imkoniyatlari #
$sinovlar = [
["42", FILTER_VALIDATE_INT, "butun son"],
["3.14", FILTER_VALIDATE_FLOAT, "kasr son"],
["true", FILTER_VALIDATE_BOOL, "mantiqiy"],
["yes", FILTER_VALIDATE_BOOL, "mantiqiy"],
["ha", FILTER_VALIDATE_BOOL, "mantiqiy"],
["[email protected]", FILTER_VALIDATE_EMAIL, "email"],
["https://softromeda.uz", FILTER_VALIDATE_URL, "URL"],
["softromeda.uz", FILTER_VALIDATE_URL, "URL"],
["192.168.1.1", FILTER_VALIDATE_IP, "IP manzil"],
["999.1.1.1", FILTER_VALIDATE_IP, "IP manzil"],
];
printf("%-24s %-12s %s\n", "QIYMAT", "TUR", "NATIJA");
echo str_repeat("-", 56) . "\n";
foreach ($sinovlar as [$qiymat, $filtr, $nom]) {
$natija = filter_var($qiymat, $filtr, FILTER_NULL_ON_FAILURE);
printf(
"%-24s %-12s %s\n",
"'{$qiymat}'",
$nom,
$natija === null ? "rad etildi" : var_export($natija, true)
);
}
QIYMAT TUR NATIJA
--------------------------------------------------------
'42' butun son 42
'3.14' kasr son 3.14
'true' mantiqiy true
'yes' mantiqiy true
'ha' mantiqiy rad etildi
'[email protected]' email '[email protected]'
'https://softromeda.uz' URL 'https://softromeda.uz'
'softromeda.uz' URL rad etildi
'192.168.1.1' IP manzil '192.168.1.1'
'999.1.1.1' IP manzil rad etildi
FILTER_VALIDATE_BOOL ni alohida eslab qolingBoshqa filtrlar xato holatda false qaytaradi. Lekin
FILTER_VALIDATE_BOOL uchun false - bu haqiqiy
javob bo'lishi mumkin.
Shuning uchun u uchun FILTER_NULL_ON_FAILURE
bayrog'i majburiy:
$q = filter_var($x, FILTER_VALIDATE_BOOL, FILTER_NULL_ON_FAILURE);
if ($q === null) { /* yaroqsiz */ }
Qanday qiymatlarni qabul qiladi:
true deb qabul qilinadi | false deb qabul qilinadi |
|---|---|
"1", "true", "on", "yes" | "0", "false", "off", "no", "" |
Yuqoridagi jadvalda "ha" rad etildi - chunki
filter_var ingliz tilidagi so'zlarni biladi, o'zbekcha
emas. Bu kutilgan xatti-harakat: forma qiymatlari
odatda 1/0 bo'ladi, ko'rinadigan matn esa alohida.
Diapazon tekshirish ham mumkin:
filter_var($x, FILTER_VALIDATE_INT, [
"options" => ["min_range" => 1, "max_range" => 100],
]);
Qayta ishlatiladigan tekshiruv qatlami #
final class Tekshiruv
{
private array $xatolar = [];
public function __construct(private readonly array $malumot) {}
public function majburiy(string $maydon, string $xabar): self
{
$q = trim((string) ($this->malumot[$maydon] ?? ""));
if ($q === "") {
$this->xatoQosh($maydon, $xabar);
}
return $this;
}
public function uzunlik(string $maydon, int $eng_kam, int $eng_kop, string $xabar): self
{
$q = trim((string) ($this->malumot[$maydon] ?? ""));
$n = mb_strlen($q);
if ($q !== "" && ($n < $eng_kam || $n > $eng_kop)) {
$this->xatoQosh($maydon, $xabar);
}
return $this;
}
public function email(string $maydon, string $xabar): self
{
$q = trim((string) ($this->malumot[$maydon] ?? ""));
if ($q !== "" && !filter_var($q, FILTER_VALIDATE_EMAIL)) {
$this->xatoQosh($maydon, $xabar);
}
return $this;
}
public function royxatdan(string $maydon, array $ruxsat, string $xabar): self
{
$q = $this->malumot[$maydon] ?? null;
if ($q !== null && !in_array($q, $ruxsat, true)) {
$this->xatoQosh($maydon, $xabar);
}
return $this;
}
private function xatoQosh(string $maydon, string $xabar): void
{
$this->xatolar[$maydon] ??= $xabar;
}
public function toqrimi(): bool
{
return $this->xatolar === [];
}
public function xatolar(): array
{
return $this->xatolar;
}
}
// --- Ishlatish ---
$formalar = [
"to'g'ri" => [
"ism" => "Husanboy", "email" => "[email protected]",
"xabar" => "Assalomu alaykum, savolim bor edi.", "mavzu" => "savol",
],
"xatoli" => [
"ism" => "H", "email" => "notogri-email",
"xabar" => "qisqa", "mavzu" => "boshqa",
],
];
foreach ($formalar as $nom => $malumot) {
$t = (new Tekshiruv($malumot))
->majburiy("ism", "Ism kiritilishi shart.")
->uzunlik("ism", 2, 50, "Ism 2-50 belgi bo'lsin.")
->majburiy("email", "Email kiritilishi shart.")
->email("email", "Email manzili noto'g'ri.")
->uzunlik("xabar", 10, 1000, "Xabar kamida 10 belgi bo'lsin.")
->royxatdan("mavzu", ["savol", "taklif", "shikoyat"], "Mavzu tanlanmagan.");
echo "Forma: {$nom}\n";
if ($t->toqrimi()) {
echo " hammasi joyida\n";
} else {
foreach ($t->xatolar() as $maydon => $xabar) {
printf(" %-8s %s\n", $maydon, $xabar);
}
}
echo "\n";
}
Forma: to'g'ri
hammasi joyida
Forma: xatoli
ism Ism 2-50 belgi bo'lsin.
email Email manzili noto'g'ri.
xabar Xabar kamida 10 belgi bo'lsin.
mavzu Mavzu tanlanmagan.
Har bir usul $this qaytaradi - shuning uchun ularni
zanjir qilib yozish mumkin:
(new Tekshiruv($_POST))
->majburiy("ism", "...")
->email("email", "...")
->toqrimi();
Bu ravon interfeys (fluent interface) deb ataladi va PHP olamida keng tarqalgan - Laravel, Symfony va ko'p kutubxona shu naqshni ishlatadi.
Ikki muhim qaror bu sinfda qilingan:
1. Har maydon uchun faqat BIRINCHI xato saqlanadi.
$this->xatolar[$maydon] ??= $xabar; qatori shuni
qiladi. Sabab: foydalanuvchiga bir maydon uchun uchta
xato ko'rsatish foydasiz.
2. Bo'sh qiymat faqat majburiy da tekshiriladi.
Boshqa usullar bo'sh qiymatni o'tkazib yuboradi
($q !== "" sharti). Aks holda ixtiyoriy maydon
to'ldirilmasa ham "email noto'g'ri" deb yozilardi.
Bu ikki detal amaliyotda juda ko'p vaqt tejaydi.
Muntazam ifodalar bilan tekshirish #
$naqshlar = [
"telefon" => '/^\+998[0-9]{9}$/',
"parol" => '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/',
"slug" => '/^[a-z0-9]+(?:-[a-z0-9]+)*$/',
"sana" => '/^\d{4}-\d{2}-\d{2}$/',
];
$sinovlar = [
"telefon" => ["+998901234567", "998901234567", "+99890123456"],
"parol" => ["Parol123", "parol123", "Pa1"],
"slug" => ["zamonaviy-php", "Zamonaviy-PHP", "ikki--tire"],
"sana" => ["2024-09-01", "2024-9-1", "01.09.2024"],
];
foreach ($sinovlar as $tur => $qiymatlar) {
echo "{$tur}:\n";
foreach ($qiymatlar as $q) {
$mos = preg_match($naqshlar[$tur], $q) === 1;
printf(" %-18s %s\n", "'{$q}'", $mos ? "OK" : "rad etildi");
}
echo "\n";
}
telefon:
'+998901234567' OK
'998901234567' rad etildi
'+99890123456' rad etildi
parol:
'Parol123' OK
'parol123' rad etildi
'Pa1' rad etildi
slug:
'zamonaviy-php' OK
'Zamonaviy-PHP' rad etildi
'ikki--tire' rad etildi
sana:
'2024-09-01' OK
'2024-9-1' rad etildi
'01.09.2024' rad etildi
Yuqoridagi sana naqshi 2024-09-01 ni qabul qiladi.
Lekin u 2024-13-45 ni ham qabul qiladi - chunki naqsh
faqat shaklni tekshiradi, mazmunni emas.
To'g'ri usul:
$sana = DateTimeImmutable::createFromFormat("Y-m-d", $kiritilgan);
$xatolar = DateTimeImmutable::getLastErrors();
$toqri = $sana !== false
&& $xatolar["warning_count"] === 0
&& $xatolar["error_count"] === 0;
getLastErrors() ni tekshirish shart, chunki
createFromFormat 2024-02-31 ni jimgina 2024-03-02
ga aylantiradi va obyekt qaytaradi.
Xuddi shu tamoyil boshqa joyda ham amal qiladi:
| Tekshiruv | To'g'ri vosita |
|---|---|
FILTER_VALIDATE_EMAIL | |
| URL | FILTER_VALIDATE_URL |
| IP | FILTER_VALIDATE_IP |
| Sana | DateTimeImmutable |
| JSON | json_validate() (PHP 8.3) yoki json_decode |
Muntazam ifoda faqat maxsus shakllar uchun - telefon raqami, mahsulot kodi, slug kabi.
Va e'tibor bering: naqsh ^ bilan boshlanib $ bilan
tugashi shart. Usiz preg_match satrning istalgan
joyidan mos kelishni qidiradi.
Fayl yuklashni tekshirish #
function faylniTekshir(array $fayl, array $ruxsat, int $engKopBayt): ?string
{
if (($fayl["error"] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
return match ($fayl["error"]) {
UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE => "Fayl juda katta.",
UPLOAD_ERR_PARTIAL => "Fayl to'liq yuklanmadi.",
UPLOAD_ERR_NO_FILE => "Fayl tanlanmagan.",
default => "Yuklashda xatolik.",
};
}
if ($fayl["size"] > $engKopBayt) {
return "Fayl hajmi " . round($engKopBayt / 1024 / 1024, 1) . " MB dan oshmasin.";
}
// MUHIM: kengaytmaga emas, HAQIQIY turga qaraymiz
$finfo = new finfo(FILEINFO_MIME_TYPE);
$turi = $finfo->file($fayl["tmp_name"]);
if (!in_array($turi, $ruxsat, true)) {
return "Bu turdagi fayl qabul qilinmaydi.";
}
return null; // xato yo'q
}
// Ishlatish
$xato = faylniTekshir(
$_FILES["rasm"] ?? [],
["image/jpeg", "image/png", "image/webp"],
2 * 1024 * 1024
);
zararli.php faylini rasm.jpg deb nomlash - bir
soniyalik ish. Shuning uchun tekshiruv fayl
mazmuniga asoslanishi kerak.
Yuqoridagi kodda finfo aynan shuni qiladi: u faylning
birinchi baytlarini o'qib, haqiqiy turini aniqlaydi.
Fayl yuklashda to'rt qoida:
| Qoida | Sabab |
|---|---|
finfo bilan turni tekshiring | Kengaytma yolg'on bo'lishi mumkin |
| Nomni o'zingiz yarating | ../../ yo'li bilan chiqib ketishdan saqlaydi |
| Veb papkadan tashqarida saqlang | Yuklangan fayl bajarilmasin |
move_uploaded_file() ishlating | U faylning haqiqatan yuklanganini tekshiradi |
Ikkinchi qoida uchun:
$kengaytma = match ($turi) {
"image/jpeg" => "jpg",
"image/png" => "png",
"image/webp" => "webp",
};
$yangiNom = bin2hex(random_bytes(16)) . "." . $kengaytma;
Foydalanuvchi bergan nomni umuman ishlatmang.
FILTER_VALIDATE_EMAILvaFILTER_SANITIZE_EMAILni bir xil kirishda solishtiring.- Tozalash nima uchun muammoni yashirishini tushuntiring.
FILTER_VALIDATE_BOOLniFILTER_NULL_ON_FAILUREsiz sinang.- Diapazon bilan butun sonni tekshiring (
min_range,max_range). - Zanjirli
Tekshiruvsinfini yozing va ikki formada sinang. - Bir maydonga ikki xato qo'shing - qaysi biri saqlanadi?
- Ixtiyoriy maydonni bo'sh qoldiring - noto'g'ri xato chiqdimi?
- Telefon raqami uchun muntazam ifoda yozing.
^va$ni olib tashlab natijani ko'ring.DateTimeImmutable::createFromFormatga2024-02-31bering.
Xulosa #
- Validatsiya - "to'g'rimi?" degan savol; tozalash - qiymatni jimgina o'zgartirish.
- Tozalash muammoni yashiradi - noto'g'ri email bazaga tushadi va xat yetib bormaydi.
FILTER_SANITIZE_*filtrlarining ko'pi PHP 8.1 dan eskirgan - ishlatmang.FILTER_VALIDATE_BOOLuchunFILTER_NULL_ON_FAILUREmajburiy.- Uch bosqich: qabul qilishda validatsiya, saqlashda parametrlash, chiqarishda ekranlash.
- Kiritish paytida
htmlspecialcharsqilmang - u bazadagi ma'lumotni buzadi. - Zanjirli tekshiruv sinfida har maydon uchun birinchi xatoni saqlang.
- Bo'sh qiymatni faqat
majburiytekshiruvida rad eting. - Muntazam ifoda faqat shaklni tekshiradi - sana uchun
DateTimeImmutableishlating. - Naqsh
^bilan boshlanib$bilan tugasin. - Fayl yuklashda kengaytmaga emas,
finfobilan haqiqiy turga qarang. - Yuklangan fayl nomini o'zingiz yarating va veb papkadan tashqarida saqlang.
Keyingi bo'limda sessiyalar va cookie - foydalanuvchini so'rovlar orasida eslab qolishni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.