عندما يتجاوز PHP حدود الويب
\nتخيل موقفًا: تحتاج إلى كتابة خدمة خلفية (daemon) تراقب سجلات النظام، وتحللها، وترسل إشعارات إلى Telegram. أو ربما تحتاج إلى إنشاء جدولة مهام خاصة بك لا تعتمد على cron. أو ماذا لو أردت كتابة خادم ويب بسيط أو وكيل (proxy) خاص بك؟ معظم المطورين سيتجهون فورًا إلى Python أو Go أو C. ولكن ماذا لو أخبرتك أن PHP أيضًا قادرة على البرمجة النظامية؟ وبكفاءة عالية.
\nPHP ليست مجرد لغة لـ"مواقع WordPress". إصدار CLI (واجهة سطر الأوامر) الخاص بها هو أداة متكاملة للإدارة النظامية، والتعامل مع العمليات، والمقابس الشبكية، وحتى إنشاء الخدمات الخلفية. في هذا المقال، سنشرح كيفية استخدام PHP للبرمجة النظامية، وسنقدم أمثلة كود حقيقية تعمل على Linux.
\n\nالتحضير: ما تحتاج معرفته
\nأولاً، تأكد من تثبيت PHP مع دعم CLI والإضافات pcntl (إدارة العمليات)، posix (استدعاءات النظام)، و sockets (التعامل مع المقابس). في معظم توزيعات Linux، يمكنك فعل ذلك بأمر واحد:
sudo apt install php-cli php-pcntl php-posix php-sockets\nيمكنك التحقق من توفر الإضافات باستخدام php -m | grep -E 'pcntl|posix|sockets'. إذا كانت كلها موجودة، فلنبدأ.
التعامل مع العمليات: fork و exec
\nيتيح لك PHP إنشاء عمليات فرعية باستخدام الدالة pcntl_fork(). هذه آلية قوية لتنفيذ المهام بشكل متوازٍ. لنلقِ نظرة على مثال يقوم بتشغيل ثلاث عمليات فرعية، كل منها تؤدي مهمتها الخاصة.
<?php\n$workers = 3;\n$pids = [];\n\nfor ($i = 0; $i < $workers; $i++) {\n $pid = pcntl_fork();\n if ($pid == -1) {\n die("فشل إنشاء العملية");\n } elseif ($pid) {\n // العملية الأم: حفظ معرف العملية الفرعية\n $pids[] = $pid;\n echo "تم إنشاء عملية فرعية PID: $pid\\n";\n } else {\n // العملية الفرعية\n echo "العملية الفرعية " . getmypid() . " بدأت العمل\\n";\n sleep(rand(2, 5)); // محاكاة العمل\n echo "العملية الفرعية " . getmypid() . " انتهت\\n";\n exit(0);\n }\n}\n\n// العملية الأم تنتظر انتهاء جميع العمليات الفرعية\nforeach ($pids as $pid) {\n pcntl_waitpid($pid, $status);\n echo "العملية $pid انتهت بحالة $status\\n";\n}\n?>\nيوضح هذا الكود أساسيات تعدد المهام في PHP. يمكنك تشغيل مهام متوازية — تحليل السجلات، معالجة الملفات، تنفيذ طلبات الشبكة. في البرمجة النظامية، هذا الأسلوب لا غنى عنه عندما تحتاج إلى معالجة كميات كبيرة من البيانات دون حظر التيار الرئيسي.
\n\nتنفيذ الأوامر الخارجية
\nالدالة exec() ومتغيراتها (shell_exec()، system()) تسمح لك بتشغيل أي أوامر نظام. ولكن للبرمجة النظامية الحقيقية، من الأفضل استخدام proc_open() — فهي تمنحك تحكمًا كاملاً في الإدخال/الإخراج ومعرف العملية (PID).
<?php\n$descriptorspec = [\n 0 => ["pipe", "r"], // stdin\n 1 => ["pipe", "w"], // stdout\n 2 => ["pipe", "w"] // stderr\n];\n\n$process = proc_open('ping -c 4 8.8.8.8', $descriptorspec, $pipes);\n\nif (is_resource($process)) {\n // قراءة المخرجات\n $output = stream_get_contents($pipes[1]);\n fclose($pipes[1]);\n fclose($pipes[2]);\n proc_close($process);\n \n echo "نتيجة ping:\\n$output";\n}\n?>\nهذا الأسلوب يسمح بدمج PHP مع أي أدوات نظام — من ps إلى ffmpeg.
معالجة الإشارات: جعل الخدمة الخلفية مهذبة
\nأي خدمة خلفية جادة يجب أن تتعامل بشكل صحيح مع إشارات نظام التشغيل. PHP عبر إضافة pcntl تسمح باعتراض الإشارات (SIGTERM، SIGHUP، SIGUSR1 وغيرها). هذه مهارة أساسية