انتقل إلى محتوى الدرس
الدرس 54
دورة PHP

مجاري الملفات وأوضاع fopen والتحريك بـ fseek و ftell وقفل الملفات في PHPPHP File Streams Modes Seeking with fseek ftell and Locking

تحكم في مؤشر القراءة والكتابة بدقة عبر أوضاع fopen ودوال ftell وfseek وrewind، وامنع تضارب الكتابة المتزامنة بقفل الملفات flock.
أقسام الدرس
6
الأمثلة
6
اللغة
العربية
تاريخ النشر
غير محدد
المشاهدات
0
محتوى الدرس
في هذا الدرس 6تصفّح المواضيع

تربط الدالة fopen() ملفاً أو مجرى بيانات بمؤشر قراءة وكتابة، وتحدد عبر رمز الوضع ما إذا كان مسموحاً بالقراءة أو التعديل أو المسح أو الإنشاء.

  • استخدم الوضع "r" للقراءة فقط من البايت 0، أو الوضع "r+" للقراءة والكتابة فوق البايتات الحالية دون مسح محتوى الملف مسبقاً.
  • استخدم الوضع "w" فقط عندما تريد عن قصد تفريغ محتوى الملف القديم بالكامل إلى 0 بايت فور فتحه.
  • استخدم الوضع "a" للإلحاق الآمن في نهاية الملف، أو الوضع "x" لإنشاء ملف جديد تماماً مع رفض الفتح إذا كان موجوداً مسبقاً.

فتح المجرى php://memory بالوضع "r+" يسمح بكتابة 17 بايت، ثم إعادة المؤشر للبايت 0 وقراءة أول 6 بايتات.

مخطط توضيحي: محاكي أوضاع فتح الملفات وحركة المؤشر التفاعلي (fopen / fseek / flock)
PHP
<?php
$fp = fopen('php://memory', 'r+');
fwrite($fp, "ID:100|STATUS:NEW");
rewind($fp);
$firstChunk = fread($fp, 6);
echo "Mode r+ read: $firstChunk\n";
fclose($fp);

عند معالجة ملفات السجلات الضخمة، تتيح القراءة المتدفقة سطراً بسطر عبر fgets() الحفاظ على استهلاك الذاكرة ثابتاً ومنخفضاً.

  • تقرأ الدالة fgets($fp) البايتات من موقع المؤشر الحالي حتى محرف السطر الجديد \n التالي أو نهاية الملف.
  • فحص الشرط ($line = fgets($fp)) !== false داخل حلقة while هو الأسلوب الأدق للمرور على جميع الأسطر حتى النهاية.
  • تتحقق الدالة feof($fp) مما إذا كان مؤشر الملف قد وصل إلى علامة نهاية الملف (EOF) بعد انتهاء القراءة.

تقرأ حلقة while ثلاثة أسطر بالتتابع عبر fgets()، وتؤكد feof($fp) وصول المؤشر إلى نهاية المجرى.

PHP
<?php
$fp = fopen('php://memory', 'r+');
fwrite($fp, "INFO: Boot\nWARN: Disk\nINFO: Ready\n");
rewind($fp);
$count = 0;
while (($line = fgets($fp)) !== false) {
    $count++;
}
echo "Lines: $count | EOF: " . (feof($fp) ? 'yes' : 'no') . "\n";
fclose($fp);

يحتفظ كل مجرى ملف مفتوح بمؤشر داخلي لموقع البايت، وتُرجع الدالة ftell() رقم ذلك البايت الحالي بدقة بدءاً من الصفر.

  • فور فتح الملف بالوضع "r" أو "w"، تُرجع الدالة ftell($fp) القيمة 0.
  • كل استدعاء للدوال fread() أو fgets() أو fwrite() يُحرّك المؤشر الداخلي بمقدار عدد البايتات التي تمت معالجتها.
  • يتيح حفظ الرقم الصحيح الناتج عن ftell() وضع علامة مرجعية لموقع محدد داخل ملف كبير للعودة إليه لاحقاً.

كتابة 10 أحرف تحرك المؤشر إلى البايت 10؛ وإعادة المؤشر للبداية ثم قراءة 4 بايتات تجعل ftell($fp) عند البايت 4.

PHP
<?php
$fp = fopen('php://memory', 'r+');
fwrite($fp, "ABCDEFGHIJ");
$afterWrite = ftell($fp);
rewind($fp);
fread($fp, 4);
$afterRead = ftell($fp);
echo "Write offset: $afterWrite | Read offset: $afterRead\n";
fclose($fp);

تعتمد عمليات الوصول العشوائي في الملفات على الدالة fseek() للقفز المباشر إلى أي إزاحة بالبايت، وعلى rewind() لإعادة المؤشر إلى نقطة الصفر.

  • تضع fseek($fp, $offset, SEEK_SET) المؤشر عند $offset بايت من بداية الملف (وهو الوضع الافتراضي).
  • يحرك الثابت SEEK_CUR المؤشر نسبةً إلى موقعه الحالي، بينما يحركه SEEK_END نسبةً إلى نهاية الملف (غالباً بقيم سالبة).
  • تُعد rewind($fp) اختصاراً مباشراً للأمر fseek($fp, 0, SEEK_SET) كما أنها تمسح علامة الوصول لنهاية الملف.

تقفز fseek($fp, 11, SEEK_SET) مباشرة إلى البايت 11 لقراءة "9841"، ثم تعود للبايت 0 لقراءة "2026".

مخطط تدفق التنفيذ العملي لقسم تحريك المؤشر وإعادته للبداية بـ fseek و rewind في لغة PHP
PHP
<?php
$fp = fopen('php://memory', 'r+');
fwrite($fp, "2026-ORDER-9841");
fseek($fp, 11, SEEK_SET);
$orderId = fread($fp, 4);
fseek($fp, 0, SEEK_SET);
$year = fread($fp, 4);
echo "Year: $year | Order: $orderId\n";
fclose($fp);

عندما تحاول عدة طلبات ويب الكتابة في الملف نفسه في آنٍ واحد، تمنع الدالة flock() تداخل البيانات وتلف الأسطر عبر أقفال نظام التشغيل.

  • مرّر الثابت LOCK_SH للحصول على قفل مشترك للقراءة المتزامنة، أو LOCK_EX للحصول على قفل حصري قبل أي كتابة.
  • إذا فتحت ملفاً بالوضع "r+" أو "c" لاستبدال محتواه بأمان تحت القفل، استدعِ ftruncate($fp, 0) فقط بعد نجاح flock($fp, LOCK_EX).
  • استدعِ دائماً fflush($fp) قبل فك القفل عبر flock($fp, LOCK_UN) لضمان تفريغ البايتات المؤقتة للقرص أثناء سريان القفل.

الفتح بالوضع "c+" يتجنب مسح الملف قبل الحصول على القفل؛ وفور نجاح LOCK_EX يتم تصفير الملف والكتابة وتفريغ المجرى ثم فك القفل.

PHP
<?php
$tmp = sys_get_temp_dir() . '/ct_counter.txt';
$fp = fopen($tmp, 'c+');
if (flock($fp, LOCK_EX)) {
    ftruncate($fp, 0);
    fwrite($fp, "VISITS=42");
    fflush($fp);
    flock($fp, LOCK_UN);
}
fclose($fp);
echo file_get_contents($tmp) . "\n";
unlink($tmp);

اختيار وضع الفتح الصحيح في fopen() يحمي البيانات الحالية من المسح غير المقصود ويمنح السكريبت تحكماً دقيقاً بالمؤشر.

  • فضّل الوضع "c+" على "w+" عند دمج تصفير الملف مع flock() حتى لا ترى العمليات المنتظرة ملفاً ممسوحاً قبل القفل.
  • استخدم الوضع "a" لسجلات الأحداث والأخطاء لأن نظام التشغيل يفرض إلحاق كل كتابة في نهاية الملف بغض النظر عن fseek().
  • اربط دائماً كل استدعاء fopen() بالدالة fclose($fp) لتحرير مقابض الملفات في نظام التشغيل فوراً.

تفحص الدالة stream_get_meta_data($fp) وضع المجرى النشط، وتقرأ stream_get_contents($fp) كامل البايتات المتبقية من موقع المؤشر.

الوضعالقراءة / الكتابةموقع المؤشر الابتدائيإذا كان الملف موجوداً / مفقوداً
"r" / "r+"Read / Read+WriteByte 0 (Start)Keeps content / Fails (false)
"w" / "w+"Write / Read+WriteByte 0 (Start)Truncates to 0 / Creates file
"a" / "a+"Append / Read+AppendEOF (End of file)Keeps content / Creates file
"x" / "c+"Create / Safe R+WByte 0 (Start)x fails if exists / c+ keeps content

PHP
<?php
$fp = fopen('php://temp', 'w+');
fwrite($fp, "STREAM_OK");
rewind($fp);
$meta = stream_get_meta_data($fp);
$content = stream_get_contents($fp);
echo $meta['mode'] . " -> " . $content . "\n";
fclose($fp);
خلاصة المعرفة ومحطة الانتقال

ملخص الدرس

حصاد الدرس

مراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي

ماذا تعلّمت في هذا الدرس؟

اختيار وضع الفتح الصحيح في fopen() يحمي البيانات الحالية من المسح غير المقصود ويمنح السكريبت تحكماً دقيقاً بالمؤشر. فضّل الوضع "c+" على "w+" عند دمج تصفير الملف مع flock() حتى لا ترى العمليات المنتظرة ملفاً ممسوحاً قبل القفل. استخدم الوضع "a" لسجلات الأحداث والأخطاء لأن نظام التشغيل يفرض إلحاق كل كتابة في نهاية الملف بغض النظر عن fseek(). اربط دائماً كل استدعاء fopen() بالدالة fclose($fp) لتحرير مقابض الملفات في نظام التشغيل فوراً.

مشاركة

هل كان هذا الدرس مفيدًا؟

جارٍ تحميل الآراء…

ابنِ لغتك البرمجية

المصطلحات4

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 Streams, fseek & flock مؤشرات الملفات fseek و flock
تحكم في مؤشر القراءة والكتابة بدقة عبر أوضاع fopen ودوال ftell وfseek وrewind، وامنع تضارب الكتابة المتزامنة بقفل الملفات flock.
للمراجعة
02 Understanding fopen Read Write Modes أوضاع فتح الملفات r و r+ و w و a و x في fopen
المفهوم الأساسي لقسم أوضاع فتح الملفات r و r+ و w و a و x في fopen في لغة PHP الحديثة.
للمراجعة
03 Line-by-Line Streaming with fgets and feof القراءة المتدفقة سطراً بسطر عبر fgets و feof
الصياغة البرمجية والتطبيق العملي المباشر لقسم القراءة المتدفقة سطراً بسطر عبر fgets و feof.
للمراجعة
04 Reading Pointer Offset with ftell معرفة موقع المؤشر الحالي بالبايت عبر ftell
قواعد التحقق وأفضل الممارسات القياسية الخاصة بقسم معرفة موقع المؤشر الحالي بالبايت عبر ftell.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

حروف قليلة. معنى كامل.

الاختصارات4

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 PHP PHP
PHP: Hypertext Preprocessor
لغة البرمجة النصية على جانب الخادم لبناء تطبيقات الويب الديناميكية وواجهات البرمجة.
للمراجعة
02 CLI CLI
Command-Line Interface
واجهة سطر الأوامر التي تتيح تشغيل ملفات PHP مباشرة عبر الطرفية.
للمراجعة
03 FPM FPM
FastCGI Process Manager
مدير عمليات FastCGI عالي الأداء لمعالجة طلبات خادم الويب في PHP.
للمراجعة
04 HTML HTML
HyperText Markup Language
لغة الترميز القياسية التي يولدها محرك PHP ويرسلها إلى متصفح العميل بعد التنفيذ.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

من الفهم للتطبيق

مهامك قبل الاختبار

خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.

0/2مهام منجزة
  1. أنشئ ملف PHP محلياً ونفّذ المثال البرمجي المشروح في قسم أوضاع فتح الملفات r و r+ و w و a و x في fopen للتحقق من المخرجات.

  2. بدّل بين الحالات الثلاث في المحاكي التفاعلي ضمن قسم القراءة المتدفقة سطراً بسطر عبر fgets و feof وقارن مخرجات التنفيذ.

تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.

مساحة التحدي

اختبر فهمك.
ووصلها للإتقان.

كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.

8أسئلة 1أنواع تحديات 100%هدف الإتقان
تصحيح تلقائي. فرص بلا حدود.

أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.

الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.

لمحة عن التحدي8 أسئلة تنتظرك
01

أي وضع في fopen() يفتح ملفاً موجوداً للقراءة والكتابة معاً عند البايت 0 دون مسح محتوياته؟

يفتح الوضع "r+" الملف للقراءة والكتابة من البداية مع الحفاظ على محتواه الحالي.

02

ماذا تُرجع الدالة ftell($fp) عند استدعائها على مجرى ملف نشط؟

تُرجع ftell() الرقم الصحيح لموقع المؤشر الحالي بالبايت.

03

ما القيمة الرقمية التي تُرجعها الدالة fseek($fp, 20, SEEK_SET) عند نجاح تحريك المؤشر؟

تتبع fseek() معيار لغة C بإرجاع 0 عند النجاح و-1 عند الفشل.

04

أي ثابت في دالة flock() يطلب قفلاً حصرياً للكتابة على مؤشر الملف؟

يحجز LOCK_EX قفلاً حصرياً للكتابة يمنع التداخل المتزامن.

05

لماذا يجب فتح الملف بالوضع "c+" بدلاً من "w+" عند استخدام flock($fp, LOCK_EX) لاستبدال محتواه؟

يفتح الوضع "c+" الملف دون مسحه، مما يتيح استدعاء ftruncate($fp, 0) بأمان بعد نجاح القفل الحصري.

06

أي ثابت في دالة fseek() يحرك مؤشر الملف نسبةً إلى موقعه الحالي؟

يضيف الثابت SEEK_CUR الإزاحة إلى موقع المؤشر الحالي.

07

ماذا تفعل الدالة fopen("report.txt", "x") إذا كان الملف report.txt موجوداً مسبقاً على القرص؟

يضمن وضع الإنشاء الحصري "x" عدم الكتابة فوق أي ملف موجود مسبقاً.

08

لماذا يُفضّل استخدام fgets($fp) بدلاً من file_get_contents() عند قراءة ملف سجلات بحجم 2 جيجابايت؟

القراءة المتدفقة سطراً بسطر تحمي الخادم من تجاوز حد الذاكرة memory_limit.