خادم Apache والمنافذ وتوجيه الطلبات
كيف يصل الطلب إلى الملف الصحيح؟ وما المنافذ؟ ⏱ نحو 30 دقيقة.
- تشرح دور برنامج خادم الويب ومفهوم المنفذ.
- تحل مشكلة تعارض المنافذ في
XAMPPبتغيير إعدادApache. - تتتبع تحويل الرابط إلى ملف، وتقرأ $
_SERVER. - تبني موجّهًا بسيطًا يرد بالرمز المناسب، وتعرف دور .
htaccess.
١ما خادم الويب؟
كلمة «خادم» تُطلق على شيئين: الجهاز نفسه (حاسب يعمل طوال الوقت)، وبرنامج خادم الويب الذي يعمل عليه ويستقبل طلبات HTTP. أشهر برامج خادم الويب:
| البرنامج | ملاحظة |
|---|---|
| Apache | الأقدم والأكثر انتشارًا مع PHP، وهو الذي في XAMPP. يُضبط بملف httpd.conf وملفات .htaccess. |
| Nginx | سريع وخفيف، شائع في الخوادم الكبيرة. يمرّر طلبات PHP إلى برنامج اسمه PHP-FPM. |
| LiteSpeed | شائع في الاستضافات المشتركة، ويفهم ملفات .htaccess مثل Apache. |
دور خادم الويب: يستمع للطلبات، ويحدد الملف المطلوب. فإن كان ملفًّا ثابتًا (صورة، CSS، HTML) أرسله كما هو. وإن كان .php سلّمه لـ PHP، ثم أرسل الناتج.
٢المنافذ: باب لكل خدمة
الجهاز الواحد قد يشغّل خدمات كثيرة: خادم ويب، وقاعدة بيانات، وبريد. فكيف يعرف أي طلب لأي خدمة؟ بـالمنفذ Port: رقم من 0 إلى 65535، وكل خدمة «تستمع» على رقم.
| المنفذ | الخدمة |
|---|---|
80 | HTTP: خادم الويب (الافتراضي، لا يُكتب في الرابط) |
443 | HTTPS: خادم الويب المشفّر |
3306 | MySQL / MariaDB: قاعدة البيانات |
8080 | منفذ بديل شائع للتطوير |
الرابط http://localhost/ يعني ضمنيًّا http://localhost:80/. فإن غيّرت منفذ Apache إلى 8080 صار الرابط http://localhost:8080/. والسطر المسؤول في ملف إعداد Apache:
# C:\xampp\apache\conf\httpd.confListen 80ServerName localhost:80DocumentRoot "C:/xampp/htdocs"DirectoryIndex index.php index.html
٣من الرابط إلى الملف
يحوّل Apache مسار الرابط إلى مسار ملف داخل DocumentRoot:
| الرابط | الملف على القرص |
|---|---|
http://localhost/ | htdocs/index.php (الملف الافتراضي من DirectoryIndex) |
http://localhost/132/hello.php | htdocs/132/hello.php |
http://localhost/img/logo.png | htdocs/img/logo.png يُرسل كما هو |
http://localhost/nothing.php | لا يوجد ← 404 Not Found |
ويعطيك PHP معلومات الطلب والخادم في المصفوفة $_SERVER:
<?php$keys = ['REQUEST_METHOD', 'REQUEST_URI', 'SCRIPT_NAME', 'QUERY_STRING', 'HTTP_HOST', 'SERVER_PORT'];foreach ($keys as $k) { echo str_pad($k, 15) . " = " . ($_SERVER[$k] ?? '') . "\n";}
٤الموجّه: ملف واحد لكل الصفحات
بدل أن يكون لكل صفحة ملف منفصل يكرر القائمة والتذييل، نستخدم موجّهًا Router: ملف واحد يستقبل كل الطلبات، ويقرر ماذا يعرض حسب الطلب. هذا أساس كل أطر العمل الحديثة (Laravel وغيرها). وإن لم يجد الصفحة رد بالرمز 404 عبر http_response_code():
<?php// index.php: موجّه واحد لكل صفحات الموقع$page = $_GET['page'] ?? 'home'; $pages = [ 'home' => ['الرئيسية', 'مرحبًا بك في متجر الواحة.'], 'about' => ['من نحن', 'متجر سعودي للقهوة والتمور منذ 2020.'], 'contact' => ['تواصل معنا', 'واتساب: 0550000000'],]; if (!isset($pages[$page])) { http_response_code(404); $title = 'غير موجودة'; $body = 'الصفحة المطلوبة غير موجودة.';} else { [$title, $body] = $pages[$page];}?><nav> <a href="?page=home">الرئيسية</a> | <a href="?page=about">من نحن</a> | <a href="?page=contact">تواصل</a></nav><h1><?= $title ?></h1><p><?= $body ?></p>
٥روابط أجمل: .htaccess وإعادة الكتابة
الرابط /index.php?page=about يعمل، لكن /about أجمل وأسهل للحفظ ولمحركات البحث. في Apache يحوّل الملف .htaccess (يوضع في مجلد الموقع) الرابط الجميل إلى الموجّه داخليًّا، دون أن يرى المستخدم ذلك:
# .htaccessRewriteEngine On# إن لم يكن الطلب ملفًّا أو مجلدًا موجودًا فعلًا…RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-d# …فأرسله إلى index.php مع المسارRewriteRule ^(.*)$ index.php?page=$1 [QSA,L]
وبهذا يصل الطلب GET /about إلى index.php وفيه $_GET['page'] = 'about'. يحتاج ذلك تفعيل الوحدة mod_rewrite (مفعّلة في XAMPP افتراضيًّا).
٦الملفات التي لا يجب أن تُطلب
كل ملف داخل htdocs يمكن نظريًّا طلبه من الرابط. لذلك:
- ملفات الإعداد التي فيها كلمات مرور قاعدة البيانات توضع خارج جذر الموقع إن أمكن، أو تُمنع بـ .
htaccess. - ملفات
PHPلا تُكشف لأنApacheيشغّلها ولا يرسلها. لكن نسخة احتياطية مثلconfig.php.bakتُرسل نصًّا كما هي! - امنع عرض محتويات المجلدات:
Options -Indexesفي .htaccess.
# منع الوصول إلى ملفات الإعداد والنسخ الاحتياطية<FilesMatch "\.(env|ini|log|bak|sql)$"> Require all denied</FilesMatch>Options -Indexes
توقّع وتحقّق
المنفذ الافتراضي لـ HTTP هو:
Apache يشغّل على المنفذ 8080. الرابط الصحيح:
أي سطر يجعل الرد برمز 404؟
ما فائدة ملف .htaccess في المثال؟
RewriteRule.الخلاصة
- خادم الويب
(Apache)يستقبل الطلبات: يرسل الملفات الثابتة، ويسلّم ملفات .phpلـPHP. - المنفذ رقم الخدمة: 80 لـ
HTTP، و443 لـHTTPS، و3306 لـMySQL. - الإعداد في
httpd.conf: ListenوDocumentRootوDirectoryIndex. - الموجّه ملف واحد يقرر ماذا يعرض، ويرد بـ
http_response_code(404)لغير الموجود. - .
htaccessيحوّل الروابط الجميلة إلى الموجّه، ويمنع الوصول للملفات الحساسة.
تحدٍّ برمجي: موجّه لموقع الكلية
متوسطاكتب موجّهًا في index.php لموقع قسم البرمجة. يعرض الصفحة حسب المعامل page، ويرد بـ 404 للصفحات غير الموجودة.
- الصفحات:
homeوعنوانها «قسم البرمجة»، وcoursesوعنوانها «المقررات»، وstaffوعنوانها «المدربون». - اعرض العنوان في
<h1>. إن لم يُرسل page فاعرض home. - لصفحة غير موجودة: رمز الحالة 404 و
<h1>404 - الصفحة غير موجودة</h1>.
👀 اعرض الاستجابة المطلوبة
GET /index.phpGET /index.php?page=coursesGET /index.php?page=staffGET /index.php?page=jobs
- الكود يعمل بلا أخطاء أو تحذيرات
- بلا page ← قسم البرمجة
page=courses← المقرراتpage=staff← المدربونpage=jobs← رمز الحالة 404page=jobs← رسالة 404- الصفحات الموجودة برمز 200
💡 تلميح 1
isset($titles[$page]).💡 تلميح 2
حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
<?php$page = $_GET['page'] ?? 'home';$titles = [ 'home' => 'قسم البرمجة', 'courses' => 'المقررات', 'staff' => 'المدربون',];if (isset($titles[$page])) { echo "<h1>{$titles[$page]}</h1>";} else { http_response_code(404); echo "<h1>404 - الصفحة غير موجودة</h1>";}