«إنشاء مجلد إذا لم يكن موجودًا»: كيف لا تعيد اختراع العجلة في 2025
\n\nهل سبق لك أن كتبت سكريبتًا لحفظ الملفات وفجأة ظهر لك خطأ Warning: mkdir(): No such file or directory؟ إذا كان الأمر كذلك، فأنت لست وحدك. سؤال «إنشاء مجلد إذا لم يكن موجودًا» حصد آلاف المشاهدات على Stack Overflow، وهذا ليس بدون سبب. قد يبدو الأمر بسيطًا، لكن في الواقع، المبتدئين (وحتى المحترفين) غالبًا ما يتعثرون في مطبات مثل صلاحيات الوصول، الإنشاء المتكرر، وحالات السباق (race conditions).
في هذه المقالة، سنستعرض أفضل ممارسات PHP لإنشاء المجلدات لعام 2025. ستتعلم كيفية استخدام mkdir() بشكل صحيح، وتجنب الأخطاء الشائعة، وكتابة كود موثوق لا يتعطل في أسوأ الأوقات. هيا بنا!
لماذا سؤال «إنشاء مجلد إذا لم يكن موجودًا» شائع جدًا؟
\n\nكل مشروع ويب تقريبًا يتعامل مع الملفات بطريقة أو بأخرى: رفع الصور الرمزية، إنشاء التقارير، التخزين المؤقت، السجلات. وفي كل مرة تحتاج للتأكد من أن المجلد الهدف موجود. إذا لم يكن موجودًا، سيظهر خطأ في السكريبت، وسيرى المستخدم رسالة «500 Internal Server Error»، وستضطر للبحث عن الخلل في الثالثة صباحًا.
\n\nالمشكلة أن دالة PHP mkdir() لا تنشئ المجلد تلقائيًا إذا كان المجلد الأب غير موجود. العديد من المطورين يكتبون شيئًا كهذا:
if (!file_exists($path)) {\n mkdir($path);\n}\n\n\nوهذا يعمل… حتى يحدث حالة سباق (race condition). إذا حاول سكريبتان في نفس الوقت التحقق من وجود المجلد ومحاولة إنشائه، سيفشل أحدهما بخطأ. في 2025، مع تزايد الأحمال على المواقع، تصبح هذه الأخطاء حرجة.
\n\nدالة mkdir() في PHP: تحليل شامل
\n\nدعنا نسترجع التوقيع (signature):
\n\nmkdir(string $directory, int $permissions = 0777, bool $recursive = false, resource $context = ?): bool\n\n\n- \n
- $directory — المسار إلى المجلد المراد إنشاؤه. \n
- $permissions — صلاحيات الوصول (الافتراضي 0777، لكن يتم تطبيق قناع umask). \n
- $recursive — إذا كان
true، ينشئ جميع المجلدات الأب المفقودة. \n - $context — سياق التدفق (نادر الاستخدام). \n
السر الأكبر هو المعامل $recursive. معظم المشاكل تُحل باستخدامه. لكن دعنا نأخذ الأمور بالترتيب.
الطريقة البسيطة: is_dir() + mkdir()
\n\nالطريقة الأكثر وضوحًا وصحة للتحقق من وجود مجلد هي استخدام is_dir() بدلاً من file_exists(). لماذا؟ لأن file_exists() ستعيد true حتى لو كان هناك ملف بنفس الاسم، مما يؤدي إلى خطأ.
$dir = '/path/to/upload';\n\nif (!is_dir($dir)) {\n mkdir($dir, 0755, true);\n}\n\n\nهنا نقوم بـ:
\n- \n
- التحقق من أن المجلد غير موجود وليس ملفًا. \n
- إنشاء المجلد بصلاحيات 0755 (المالك لديه كل الصلاحيات، والباقون قراءة وتنفيذ). \n
- استخدام
trueللإنشاء المتكرر — إذا كان المجلد الأب/path/toغير موجود، سيتم إنشاؤه أيضًا. \n
هذه الطريقة تغطي 90% من الحالات. لكن ماذا لو حاول طلبان تنفيذ هذا الكود في نفس الوقت؟
\n\nالحماية من حالة السباق (Race Condition)
\n\nفي الأنظمة عالية التحميل، قد يحاول سكريبتان إنشاء المجلد في نفس الوقت. لتجنب الخطأ، استخدم @ (إخفاء الأخطاء) أو الأفضل، تحقق من نتيجة mkdir():
$dir = '/path/to/cache';\n\nif (!is_dir($dir)) {\n // نحاول الإنشاء. إذا كان المجلد قد أُنشئ بواسطة عملية أخرى، فلا مشكلة\n if (!mkdir($dir, 0755, true) && !is_dir($dir)) {\n throw new \\RuntimeException('فشل إنشاء المجلد: ' . $dir);\n }\n}\n