9-bo‘lim

Validatsiya va tozalash

filter_var, qayta ishlatiladigan tekshiruv qatlami, xato xabarlari va tozalash bilan tekshirish orasidagi farq.

🕑 12 daqiqa o‘qish 📄 840 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Tekshirish va tozalash - ikki boshqa ish
  2. filter_var imkoniyatlari
  3. Qayta ishlatiladigan tekshiruv qatlami
  4. Muntazam ifodalar bilan tekshirish
  5. Fayl yuklashni tekshirish
  6. Xulosa

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 #

PHP
// Har bir misol qat'iy turlar rejimida ishlaydi.
PHP
$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
    );
}
Natija
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)
Tozalash - validatsiya emas

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:

ValidatsiyaTozalash
Savol"To'g'rimi?""Xavfsiz qilaylik"
Javobtrue / falseO'zgartirilgan qiymat
Xato holatdaRad etadiJimgina o'zgartiradi
FoydalanuvchigaXato xabariHech 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:

BosqichNima qilinadi
Qabul qilishValidatsiya - noto'g'ri bo'lsa rad et
SaqlashQiymatni o'zgartirmasdan yozish
ChiqarishEkranlash (htmlspecialchars)

Diqqat: FILTER_SANITIZE_* filtrlarining ko'pi PHP 8.1 dan boshlab eskirgan deb belgilangan. Ularni ishlatmang.

filter_var imkoniyatlari #

PHP
$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)
    );
}
Natija
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 qoling

Boshqa 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:

PHP
$q = filter_var($x, FILTER_VALIDATE_BOOL, FILTER_NULL_ON_FAILURE);
if ($q === null) { /* yaroqsiz */ }

Qanday qiymatlarni qabul qiladi:

true deb qabul qilinadifalse 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:

PHP
filter_var($x, FILTER_VALIDATE_INT, [
    "options" => ["min_range" => 1, "max_range" => 100],
]);

Qayta ishlatiladigan tekshiruv qatlami #

PHP
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";
}
Natija
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.
Zanjirli interfeys nima uchun qulay

Har bir usul $this qaytaradi - shuning uchun ularni zanjir qilib yozish mumkin:

PHP
(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.

Ma'lumot uchta nazoratdan o'tadi 1. QABUL QILISHDA - VALIDATSIYA "Bu qiymat men kutgan narsami?" Yo'q bo'lsa - RAD ETING va xato xabarini bering. filter_var, mb_strlen, in_array($x, $ruxsat, true) 2. SAQLASHDA - PARAMETRLASH Qiymatni O'ZGARTIRMANG. SQL ga qo'shmang - parametr sifatida uzating. $stmt->execute([$ism, $email]); 3. CHIQARISHDA - EKRANLASH Qayerga chiqayotganiga qarab ekranlang: HTML, URL yoki JSON. htmlspecialchars($x, ENT_QUOTES, "UTF-8") Eng keng tarqalgan xato: bir bosqichni boshqasi bilan almashtirish Kiritishda htmlspecialchars qilish - bazaga &amp; yozadi va ma'lumotni BUZADI. Ekranlash faqat CHIQARISH paytida, o'sha joyga mos usulda qilinadi.
Har bosqichning o'z vazifasi bor - ularni almashtirmang

Muntazam ifodalar bilan tekshirish #

PHP
$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";
}
Natija
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
Sanani muntazam ifoda bilan to'liq tekshirib bo'lmaydi

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:

PHP
$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:

TekshiruvTo'g'ri vosita
EmailFILTER_VALIDATE_EMAIL
URLFILTER_VALIDATE_URL
IPFILTER_VALIDATE_IP
SanaDateTimeImmutable
JSONjson_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 #

PHP
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
);
Fayl kengaytmasiga hech qachon ishonmang

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:

QoidaSabab
finfo bilan turni tekshiringKengaytma yolg'on bo'lishi mumkin
Nomni o'zingiz yarating../../ yo'li bilan chiqib ketishdan saqlaydi
Veb papkadan tashqarida saqlangYuklangan fayl bajarilmasin
move_uploaded_file() ishlatingU faylning haqiqatan yuklanganini tekshiradi

Ikkinchi qoida uchun:

PHP
$kengaytma = match ($turi) {
    "image/jpeg" => "jpg",
    "image/png"  => "png",
    "image/webp" => "webp",
};
$yangiNom = bin2hex(random_bytes(16)) . "." . $kengaytma;

Foydalanuvchi bergan nomni umuman ishlatmang.

Amaliy topshiriq
  1. FILTER_VALIDATE_EMAIL va FILTER_SANITIZE_EMAIL ni bir xil kirishda solishtiring.
  2. Tozalash nima uchun muammoni yashirishini tushuntiring.
  3. FILTER_VALIDATE_BOOL ni FILTER_NULL_ON_FAILURE siz sinang.
  4. Diapazon bilan butun sonni tekshiring (min_range, max_range).
  5. Zanjirli Tekshiruv sinfini yozing va ikki formada sinang.
  6. Bir maydonga ikki xato qo'shing - qaysi biri saqlanadi?
  7. Ixtiyoriy maydonni bo'sh qoldiring - noto'g'ri xato chiqdimi?
  8. Telefon raqami uchun muntazam ifoda yozing.
  9. ^ va $ ni olib tashlab natijani ko'ring.
  10. DateTimeImmutable::createFromFormat ga 2024-02-31 bering.

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_BOOL uchun FILTER_NULL_ON_FAILURE majburiy.
  • Uch bosqich: qabul qilishda validatsiya, saqlashda parametrlash, chiqarishda ekranlash.
  • Kiritish paytida htmlspecialchars qilmang - u bazadagi ma'lumotni buzadi.
  • Zanjirli tekshiruv sinfida har maydon uchun birinchi xatoni saqlang.
  • Bo'sh qiymatni faqat majburiy tekshiruvida rad eting.
  • Muntazam ifoda faqat shaklni tekshiradi - sana uchun DateTimeImmutable ishlating.
  • Naqsh ^ bilan boshlanib $ bilan tugasin.
  • Fayl yuklashda kengaytmaga emas, finfo bilan 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.

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.