Kodokon kodokon.com

الملفات: القراءة، والكتابة، والرفع، وJSON

اقرأ الملفات واكتب إليها، وسجِّل الأحداث، واقبل الملفات المرفوعة بأمان، وخزِّن بياناتك بصيغة JSON.

10 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

لا تتطلب قراءة ملف سوى دالة واحدة: تُرجِع file_get_contents() المحتوى كاملًا على شكل سلسلة نصية، وتقسّمه file() إلى مصفوفة من الأسطر. وقبل القراءة، تحقّق من إمكانية الوصول باستخدام is_readable(): فمسار معطوب سيُرجِع false مع تحذير.

PHP
<?php

declare(strict_types=1);

$path = __DIR__ . '/notes.txt';

if (!is_readable($path)) {
    exit("File not found or unreadable.");
}

$content = (string) file_get_contents($path);
echo nl2br(htmlspecialchars($content, ENT_QUOTES));

$lines = file(
    $path,
    FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES
);
echo count($lines) . " non-empty line(s)";
قراءة الملف نفسه كاملًا، ثم سطرًا سطرًا.

للكتابة، تستبدل file_put_contents() المحتوى كاملًا افتراضيًا. وثمة رايتان تغيّران الأمور: تضيف FILE_APPEND إلى النهاية بدلًا من الكتابة فوق المحتوى، وتضع LOCK_EX قفلًا حصريًا حتى لا يخلط طلبان متزامنان عمليتَي الكتابة الخاصتين بهما. تلك هي وصفة سجل تطبيقي بسيط.

PHP
<?php

declare(strict_types=1);

$logFile = __DIR__ . '/app.log';

$line = sprintf(
    "[%s] New order from %s\n",
    date('Y-m-d H:i:s'),
    'alice@example.com'
);

file_put_contents(
    $logFile,
    $line,
    FILE_APPEND | LOCK_EX
);

echo "Event logged.";
سجل تطبيقي موثوق في أسطر قليلة.

يستحق رفع الملفات عناية خاصة. يجب أن يعلن النموذج enctype="multipart/form-data"، ثم تصف PHP الملف المستقبَل في $_FILES. تحقّق من كل شيء: رمز الخطأ، والحجم، والنوع الحقيقي الذي يكشفه finfo - ولا تعتمد أبدًا على الامتداد أو على النوع الذي يعلنه المتصفح. وأخيرًا، يجب ألّا ينقل الملف المؤقت إلا move_uploaded_file().

PHP
<?php

declare(strict_types=1);

$maxSize = 2 * 1024 * 1024;
$file = $_FILES['avatar'] ?? null;

if ($file === null || $file['error'] !== UPLOAD_ERR_OK) {
    exit("No valid file received.");
}

if ($file['size'] > $maxSize) {
    exit("File too large (2 MB max).");
}

$info = new finfo(FILEINFO_MIME_TYPE);
$mime = $info->file($file['tmp_name']);
$allowed = ['image/jpeg' => 'jpg', 'image/png' => 'png'];

if (!isset($allowed[$mime])) {
    exit("Format not allowed.");
}

$name = bin2hex(random_bytes(8));
$target = __DIR__ . '/uploads/' . $name
    . '.' . $allowed[$mime];

move_uploaded_file($file['tmp_name'], $target);
echo "Image saved.";
upload.php: الحجم، والنوع الحقيقي، واسم الملف تحت السيطرة.

إن صيغة JSON هي الجسر الطبيعي بين PHP وبقية العالم: تُسَلسِل json_encode() مصفوفةً، وتفعل json_decode() العكس. مرِّر true كوسيط ثانٍ للحصول على مصفوفات ترابطية، ومرِّر الراية JSON_THROW_ON_ERROR لتحويل JSON المُشوَّه إلى استثناء واضح بدلًا من null صامت.

PHP
<?php

declare(strict_types=1);

$path = __DIR__ . '/tasks.json';

$json = is_readable($path)
    ? (string) file_get_contents($path)
    : '[]';

$tasks = json_decode(
    $json,
    true,
    512,
    JSON_THROW_ON_ERROR
);

$tasks[] = [
    'title' => 'Review the lesson',
    'done' => false,
];

file_put_contents(
    $path,
    json_encode(
        $tasks,
        JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
    ),
    LOCK_EX
);

echo count($tasks) . " task(s) saved";
مخزن بيانات مصغّر: قراءة، وتعديل، وإعادة كتابة.

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. ماذا تفعل الراية FILE_APPEND المُمرَّرة إلى file_put_contents()؟
    • تضيف المحتوى إلى نهاية الملف بدلًا من الكتابة فوقه
    • تنشئ المجلد الأصل إذا لم يكن موجودًا
    • تقفل الملف أثناء الكتابة
  2. لماذا يجب ألّا تعتمد على $_FILES['avatar']['type'] للتحقق من ملف مرفوع؟
    • هذا المفتاح موجود على بعض الخوادم فقط
    • يعمل مع الصور فقط
    • تُرسَل هذه القيمة من المتصفح ويمكن تزييفها؛ يجب أن تكتشف النوع الحقيقي باستخدام finfo
  3. ما الذي يغيّره الوسيط الثاني true في json_decode($json, true)؟
    • يُطلق فك الترميز استثناءً عند حدوث خطأ
    • تصبح كائنات JSON مصفوفات PHP ترابطية بدلًا من كائنات stdClass
    • تُحوَّل المفاتيح إلى أحرف كبيرة