11-bo‘lim
Fayllar bilan ishlash
O'qish va yozish, CSV, JSON, katta fayllarni qatorma-qator qayta ishlash va yo'l xavfsizligi.
Ushbu bo‘lim mundarijasi
Ma'lumotlar bazasi hamma narsa uchun kerak emas. Sozlamalar, jurnal, eksport, yuklangan fayllar - bularning hammasi oddiy fayllarda yashaydi.
O'qish va yozish #
// Har bir misol qat'iy turlar rejimida ishlaydi.
$ish = sys_get_temp_dir() . DIRECTORY_SEPARATOR . "php_darslik";
if (!is_dir($ish)) {
mkdir($ish, 0777, true);
}
$fayl = $ish . DIRECTORY_SEPARATOR . "eslatma.txt";
// Butun faylni bir marta yozish
file_put_contents($fayl, "Birinchi qator\n");
// Oxiriga qo'shish
file_put_contents($fayl, "Ikkinchi qator\n", FILE_APPEND);
file_put_contents($fayl, "Uchinchi qator\n", FILE_APPEND);
// Butun faylni o'qish
$matn = file_get_contents($fayl);
echo "file_get_contents:\n";
echo $matn;
echo "\n";
// Qatorlar massivi sifatida o'qish
$qatorlar = file($fayl, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
echo "file() bilan: " . count($qatorlar) . " qator\n";
foreach ($qatorlar as $i => $q) {
echo " [{$i}] {$q}\n";
}
echo "\n";
printf("Hajmi: %d bayt\n", filesize($fayl));
printf("Mavjudmi: %s\n", file_exists($fayl) ? "ha" : "yo'q");
printf("O'qish: %s\n", is_readable($fayl) ? "mumkin" : "mumkin emas");
printf("Yozish: %s\n", is_writable($fayl) ? "mumkin" : "mumkin emas");
unlink($fayl);
echo "\nO'chirilgandan keyin mavjudmi: " . (file_exists($fayl) ? "ha" : "yo'q") . "\n";
file_get_contents:
Birinchi qator
Ikkinchi qator
Uchinchi qator
file() bilan: 3 qator
[0] Birinchi qator
[1] Ikkinchi qator
[2] Uchinchi qator
Hajmi: 45 bayt
Mavjudmi: ha
O'qish: mumkin
Yozish: mumkin
O'chirilgandan keyin mavjudmi: yo'q
file_get_contents katta fayl uchun yaramaydifile_get_contents butun faylni xotiraga yuklaydi.
2 GB lik jurnal fayli uchun bu quyidagini anglatadi:
PHP Fatal error: Allowed memory size of 134217728 bytes
exhausted (tried to allocate 2147483648 bytes)
Fayl hajmi oldindan noma'lum bo'lsa, qatorma-qator o'qing:
$f = fopen($fayl, "r");
while (($qator = fgets($f)) !== false) {
// bir vaqtda faqat BITTA qator xotirada
}
fclose($f);
Qaysi biri qachon:
| Vaziyat | Usul |
|---|---|
| Kichik sozlama fayli | file_get_contents |
| JSON, XML (to'liq kerak) | file_get_contents |
| Jurnal, CSV, eksport | fgets tsikli |
| Hajmi noma'lum | fgets tsikli |
Quyidagi misolda aynan shu usulni qo'llaymiz.
Qatorma-qator qayta ishlash #
$jurnal = $ish . DIRECTORY_SEPARATOR . "server.log";
// Sinov uchun jurnal yaratamiz
$satrlar = [];
$darajalar = ["INFO", "WARN", "ERROR", "INFO", "INFO", "ERROR"];
for ($i = 1; $i <= 60; $i++) {
$daraja = $darajalar[$i % count($darajalar)];
$satrlar[] = sprintf("2024-09-%02d 10:%02d:00 %s xabar-%d", ($i % 28) + 1, $i % 60, $daraja, $i);
}
file_put_contents($jurnal, implode("\n", $satrlar) . "\n");
echo "Jurnal yaratildi: " . count($satrlar) . " qator, "
. filesize($jurnal) . " bayt\n\n";
// Qatorma-qator o'qib, statistika yig'amiz
$hisob = ["INFO" => 0, "WARN" => 0, "ERROR" => 0];
$xatolar = [];
$f = fopen($jurnal, "r");
if ($f === false) {
exit("Fayl ochilmadi\n");
}
while (($qator = fgets($f)) !== false) {
$qator = rtrim($qator, "\n");
foreach ($hisob as $daraja => $_) {
if (str_contains($qator, " {$daraja} ")) {
$hisob[$daraja]++;
if ($daraja === "ERROR" && count($xatolar) < 3) {
$xatolar[] = $qator;
}
break;
}
}
}
fclose($f);
echo "Darajalar bo'yicha:\n";
foreach ($hisob as $daraja => $soni) {
printf(" %-6s %3d %s\n", $daraja, $soni, str_repeat("#", $soni));
}
echo "\nBirinchi uchta xato:\n";
foreach ($xatolar as $x) {
echo " {$x}\n";
}
unlink($jurnal);
Jurnal yaratildi: 60 qator, 2051 bayt
Darajalar bo'yicha:
INFO 30 ##############################
WARN 10 ##########
ERROR 20 ####################
Birinchi uchta xato:
2024-09-03 10:02:00 ERROR xabar-2
2024-09-06 10:05:00 ERROR xabar-5
2024-09-09 10:08:00 ERROR xabar-8
CSV bilan ishlash #
$csv = $ish . DIRECTORY_SEPARATOR . "mahsulotlar.csv";
$malumot = [
["id", "nom", "narx", "soni"],
[1, "Klaviatura", 350000, 12],
[2, "Sichqoncha; simsiz", 120000, 40],
[3, 'Monitor 24"', 2400000, 5],
[4, "Quloqchin, katta", 89000, 0],
];
// Yozish - fputcsv qo'shtirnoq va vergulni O'ZI hal qiladi
$f = fopen($csv, "w");
foreach ($malumot as $qator) {
fputcsv($f, $qator, ",", '"', "\\");
}
fclose($f);
echo "Fayl mazmuni (xom):\n";
echo file_get_contents($csv);
echo "\nO'qish (fgetcsv):\n";
$f = fopen($csv, "r");
$sarlavha = fgetcsv($f, 0, ",", '"', "\\");
$qatorlar = [];
while (($q = fgetcsv($f, 0, ",", '"', "\\")) !== false) {
$qatorlar[] = array_combine($sarlavha, $q);
}
fclose($f);
printf(" %-3s %-20s %10s %6s\n", "ID", "NOM", "NARX", "SONI");
echo " " . str_repeat("-", 42) . "\n";
foreach ($qatorlar as $q) {
printf(" %-3s %-20s %10s %6s\n", $q["id"], $q["nom"], $q["narx"], $q["soni"]);
}
echo "\nOmborda bor mahsulotlar: ";
$bor = array_filter($qatorlar, static fn(array $q): bool => (int) $q["soni"] > 0);
echo count($bor) . " ta\n";
unlink($csv);
Fayl mazmuni (xom):
id,nom,narx,soni
1,Klaviatura,350000,12
2,"Sichqoncha; simsiz",120000,40
3,"Monitor 24""",2400000,5
4,"Quloqchin, katta",89000,0
O'qish (fgetcsv):
ID NOM NARX SONI
------------------------------------------
1 Klaviatura 350000 12
2 Sichqoncha; simsiz 120000 40
3 Monitor 24" 2400000 5
4 Quloqchin, katta 89000 0
Omborda bor mahsulotlar: 3 ta
explode(",") bilan o'qimangYuqoridagi ma'lumotga qarang: bitta nomda vergul, ikkinchisida nuqta-vergul, uchinchisida qo'shtirnoq bor.
explode(",", $qator) bularning hammasida buziladi.
fgetcsv esa CSV qoidalarini biladi:
| Qoida | Misol |
|---|---|
| Vergulli qiymat qo'shtirnoqqa olinadi | "Quloqchin, katta" |
| Ichidagi qo'shtirnoq ikkilanadi | "Monitor 24""" |
| Qator ichida yangi qator bo'lishi mumkin | Ko'p qatorli izoh |
Uchinchi qoida ayniqsa muhim: CSV maydonida \n
bo'lishi mumkin, ya'ni bitta yozuv bir necha faylda
qatorni egallashi mumkin. file() bilan o'qigan kod
buni hech qachon to'g'ri qayta ishlamaydi.
Excel uchun eksport qilayotgan bo'lsangiz yana ikki narsa:
// 1. UTF-8 BOM - aks holda Excel kirill/lotin harflarni buzadi
fwrite($f, "\xEF\xBB\xBF");
// 2. Rus/o'zbek Excel da ajratgich - nuqta-vergul
fputcsv($f, $qator, ";");
JSON bilan ishlash #
$json = $ish . DIRECTORY_SEPARATOR . "sozlama.json";
$sozlama = [
"sayt" => "Softromeda",
"til" => "uz",
"sahifa_hajmi" => 20,
"moduller" => ["darslik", "imtihon", "sertifikat"],
"pochta" => ["host" => "smtp.example.com", "port" => 587, "tls" => true],
];
// Yozish - o'qishga qulay shaklda
file_put_contents(
$json,
json_encode($sozlama, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
);
echo "Fayl mazmuni:\n";
echo file_get_contents($json) . "\n";
echo "\nO'qish:\n";
$xom = file_get_contents($json);
$qayta = json_decode($xom, true, 512, JSON_THROW_ON_ERROR);
printf(" sayt: %s\n", $qayta["sayt"]);
printf(" sahifa_hajmi: %d (turi: %s)\n", $qayta["sahifa_hajmi"],
get_debug_type($qayta["sahifa_hajmi"]));
printf(" moduller: %s\n", implode(", ", $qayta["moduller"]));
printf(" pochta porti: %d\n", $qayta["pochta"]["port"]);
echo "\nBuzuq JSON bilan nima bo'ladi:\n";
try {
json_decode("{buzuq}", true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $x) {
echo " JsonException: " . $x->getMessage() . "\n";
}
unlink($json);
Fayl mazmuni:
{
"sayt": "Softromeda",
"til": "uz",
"sahifa_hajmi": 20,
"moduller": [
"darslik",
"imtihon",
"sertifikat"
],
"pochta": {
"host": "smtp.example.com",
"port": 587,
"tls": true
}
}
O'qish:
sayt: Softromeda
sahifa_hajmi: 20 (turi: int)
moduller: darslik, imtihon, sertifikat
pochta porti: 587
Buzuq JSON bilan nima bo'ladi:
JsonException: Syntax error
json_decode ni JSON_THROW_ON_ERROR siz chaqirmangStandart holatda json_decode buzuq JSON uchun null
qaytaradi - hech qanday xato bermasdan.
Muammo shundaki, null haqiqiy javob ham bo'lishi
mumkin: json_decode("null") ham null qaytaradi.
Ya'ni bu kod ikki holatni ajrata olmaydi:
$m = json_decode($xom, true);
if ($m === null) {
// JSON buzuqmi yoki haqiqatan null mi?
}
Uch yechim bor, eng yaxshisi birinchisi:
| Usul | Izoh |
|---|---|
JSON_THROW_ON_ERROR | Istisno tashlaydi - eng aniq |
json_last_error() | Qo'shimcha chaqiruv kerak |
json_validate() | PHP 8.3+, faqat tekshiradi |
Yana ikki bayroq deyarli har doim kerak:
| Bayroq | Nima qiladi |
|---|---|
JSON_UNESCAPED_UNICODE | O'zbek harflari \uXXXX kodiga aylanmaydi |
JSON_UNESCAPED_SLASHES | URL dagi / \/ bo'lib ketmaydi |
Usiz "O'zbekiston" faylda o'qib bo'lmaydigan ko'rinishda
saqlanadi.
Xavfsiz yo'llar #
function xavfsizYol(string $asos, string $soralgan): ?string
{
// 1. Faqat fayl nomini olamiz - katalog qismini tashlaymiz
$nom = basename($soralgan);
// 2. Yashirin fayllarni rad etamiz
if ($nom === "" || str_starts_with($nom, ".")) {
return null;
}
// 3. To'liq yo'lni yasab, haqiqiy joyini aniqlaymiz
$toliq = realpath($asos . DIRECTORY_SEPARATOR . $nom);
if ($toliq === false) {
return null;
}
// 4. Natija ASOS katalog ichida ekanini tekshiramiz
$asosHaqiqiy = realpath($asos);
if ($asosHaqiqiy === false || !str_starts_with($toliq, $asosHaqiqiy)) {
return null;
}
return $toliq;
}
// Sinov fayllari
file_put_contents($ish . DIRECTORY_SEPARATOR . "hisobot.txt", "ma'lumot");
file_put_contents($ish . DIRECTORY_SEPARATOR . ".maxfiy", "yashirin");
$sinovlar = [
"hisobot.txt",
"../../../etc/passwd",
"..\\..\\windows\\win.ini",
".maxfiy",
"yoq-fayl.txt",
"",
];
printf("%-32s %s\n", "SO'RALGAN", "NATIJA");
echo str_repeat("-", 50) . "\n";
foreach ($sinovlar as $s) {
$natija = xavfsizYol($ish, $s);
printf("%-32s %s\n", "'{$s}'", $natija === null ? "RAD ETILDI" : "ruxsat: " . basename($natija));
}
unlink($ish . DIRECTORY_SEPARATOR . "hisobot.txt");
unlink($ish . DIRECTORY_SEPARATOR . ".maxfiy");
SO'RALGAN NATIJA
--------------------------------------------------
'hisobot.txt' ruxsat: hisobot.txt
'../../../etc/passwd' RAD ETILDI
'..\..\windows\win.ini' RAD ETILDI
'.maxfiy' RAD ETILDI
'yoq-fayl.txt' RAD ETILDI
'' RAD ETILDI
../ ketma-ketligi katalogdan yuqoriga chiqaradi.
Yetarlicha takrorlansa - fayl tizimining istalgan
joyiga:
/var/www/yuklamalar/../../../etc/passwd
= /etc/passwd
Yuqoridagi funksiya to'rt qatlamli himoya qo'yadi va har biri kerak:
| Qadam | Nimadan saqlaydi |
|---|---|
basename() | ../ va katalog yo'llaridan |
. tekshiruvi | .env, .git kabi yashirin fayllardan |
realpath() | Simvolik havolalar orqali chiqishdan |
| Prefiks tekshiruvi | Qolgan hamma holatdan |
Uchinchi qadam ko'pincha unutiladi: basename simvolik
havolani ko'rmaydi. Kimdir yuklamalar/ ichiga
/etc ga ishora qiluvchi havola qo'ysa, basename
o'tkazib yuboradi - realpath esa haqiqiy joyni
ochib beradi.
Eng yaxshi yechim esa - yo'l bilan umuman
ishlamaslik: fayllarni bazaga id bilan yozing va
foydalanuvchidan faqat id ni oling.
file_put_contentsbilan fayl yarating,FILE_APPENDbilan qo'shing.file()vafile_get_contentsnatijalarini solishtiring.- 1000 qatorli fayl yarating va uni
fgetsbilan o'qing. fputcsvbilan vergulli qiymat yozing va faylni oching.- Xuddi shu faylni
explode(",")bilan o'qib ko'ring - buzildimi? json_encodeniJSON_UNESCAPED_UNICODEsiz sinang.json_decodega buzuq JSON bering -nullqaytdimi?JSON_THROW_ON_ERRORqo'shing va istisnoni tuting.../../etc/passwdyo'linibasenamebilan tozalang.realpathva prefiks tekshiruvini qo'shib to'liq himoya yozing.
Xulosa #
file_get_contentsbutun faylni xotiraga yuklaydi - katta fayl uchun yaramaydi.- Hajmi noma'lum bo'lsa
fgetstsikli ishlating: xotirada bir vaqtda bitta qator. fopennatijasini har doim tekshiring vafcloseni unutmang.- CSV ni hech qachon
explode(",")bilan o'qimang -fgetcsvishlating. - CSV maydonida vergul, qo'shtirnoq va hatto yangi qator bo'lishi mumkin.
- Excel uchun UTF-8 BOM va
;ajratgichi kerak bo'lishi mumkin. json_decodegaJSON_THROW_ON_ERRORbering - aks holdanullikki ma'noli.json_encodegaJSON_UNESCAPED_UNICODEqo'shing, aks holda o'zbek harflari buziladi.- Foydalanuvchi bergan yo'lni hech qachon to'g'ridan-to'g'ri ishlatmang.
- Himoya to'rt qatlamli:
basename, yashirin fayl tekshiruvi,realpath, prefiks. - Eng yaxshisi - yo'l o'rniga
idbilan ishlash.
Keyingi bo'limda obyektga yo'naltirilgan dasturlash - sinflar va obyektlar bilan tanishamiz.
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.