خيارات الاستضافة وتكوين الخادم
الخطوة الأولى في النشر: اختر البيئة وجهّزها. ⏱ نحو 30 دقيقة.
- تقارن الاستضافة المشتركة و
VPSوالسحابية وتختار المناسبة. - تحدد معايير اختيار بيئة الاستضافة لتطبيق
PHP. - تضبط إعدادات
PHPللإنتاج، وتفحص جاهزية الخادم بصفحة مخصصة. - تفصل إعدادات التطوير عن الإنتاج بمتغيرات البيئة أو ملف إعداد خاص.
١من جهازك إلى الإنترنت
تطبيقك يعمل على localhost، أي على جهازك وحدك. لينفتح للناس يحتاج خادمًا متصلًا بالإنترنت طوال الوقت، بعنوان ثابت، وفيه Apache و PHP وقاعدة بيانات. ونادرًا ما تملك جهازًا كهذا، فتستأجره من شركة استضافة. والوحدات الأربع الأخيرة في المقرر هي رحلة النشر: اختيار البيئة ← النشر ← النطاق ← الاختبار.
٢أنواع الاستضافة
| النوع | الفكرة | تتحكم في | مناسب لـ |
|---|---|---|---|
| مشتركة Shared | خادم واحد يتشاركه مئات المواقع، ولوحة تحكم جاهزة (cPanel أو مثلها) فيها PHP و MySQL. | ملفاتك وقاعدتك وبعض إعدادات PHP فقط | المواقع الصغيرة، والمشاريع الطلابية، وأول نشر |
| خادم افتراضي خاص VPS | جزء محجوز من خادم كبير يعمل كأنه جهاز مستقل، بنظام Linux تديره أنت. | كل شيء: النظام وApache وPHP والجدار الناري | التطبيقات المتوسطة، ومن يحتاج إعدادات خاصة |
منصات سحابية Cloud / PaaS | ترفع الكود (أو حاوية Docker) والمنصة تشغّله وتوسّعه تلقائيًّا حسب الضغط. | الكود والإعدادات، والمنصة تدير الخوادم | التطبيقات الكبيرة والمتغيرة الضغط |
| مشتركة | VPS | سحابية | |
|---|---|---|---|
| سهولة البدء | الأسهل | تحتاج خبرة Linux | متوسطة |
| التحكم | محدود | كامل | واسع عبر إعدادات المنصة |
| مسؤولية الأمان والتحديثات | على الشركة غالبًا | عليك أنت | مشتركة |
| التكلفة | الأقل (وفيها مجاني) | متوسطة | حسب الاستخدام |
لمشروع المقرر تكفي استضافة مشتركة. مثال مجاني للتدريب: InfinityFree؛ تذكر صفحته الرسمية (في وقت كتابة الدرس) أنها تقدم PHP 8.4 وقواعد MySQL/MariaDB ونطاقًا فرعيًّا مجانيًّا وشهادة SSL مجانية ورفعًا بـ FTP أو مدير الملفات ودعمًا لـ .htaccess، بلا بطاقة ائتمان، مع شرط حد أدنى من الزيارات شهريًّا ليبقى الموقع فعالًا. العروض المجانية تتغير، فراجع شروطها الحالية قبل الاعتماد عليها، ولا تضع عليها بيانات حقيقية حساسة.
٣كيف تختار؟
- متطلبات التطبيق: إصدار PHP (8.1 فأحدث لمشروعنا)، والإضافات (pdo_mysql و mbstring)، وقاعدة البيانات.
- الحجم والضغط المتوقع: كم زائرًا في اليوم؟ كم حجم الملفات والقاعدة؟
- مكان الخادم: الأقرب لمستخدميك أسرع. وبعض البيانات (الحكومية والصحية) تشترط الأنظمة السعودية حفظها داخل المملكة.
- الدعم والنسخ الاحتياطي: هل تأخذ الشركة نسخًا احتياطية؟ هل يوجد دعم فني؟
- HTTPS والنطاق: شهادة SSL مجانية؟ هل تربط نطاقك الخاص؟
٤تكوين PHP للإنتاج
إعدادات XAMPP مصممة للتطوير: تعرض الأخطاء وتسمح بكل شيء. على الخادم الحقيقي نغيّر إعدادات php.ini (أو من لوحة التحكم، أو بـ ini_set في أول التطبيق):
| الإعداد | التطوير | الإنتاج | لماذا؟ |
|---|---|---|---|
display_errors | On | Off | لا تكشف المسارات والتفاصيل للزوار. |
log_errors | On | On | الأخطاء تُسجَّل في ملف للمطوّر. |
date.timezone | — | Asia/Riyadh | التواريخ والأوقات بتوقيت المملكة. |
upload_max_filesize | 40M | حسب الحاجة (مثلًا 5M) | حد حجم الملف المرفوع. |
session.cookie_secure | Off | On | كوكي الجلسة عبر HTTPS فقط. |
expose_php | On | Off | لا تعلن إصدار PHP في الترويسة X-Powered-By. |
و phpinfo() تعرض كل الإعدادات والإضافات المفعّلة؛ مفيدة للتحقق، لكن احذف صفحتها فورًا بعد الاستخدام لأنها تكشف الكثير. والأفضل صفحة فحص مخصصة لا تكشف إلا ما يلزم:
<?php// health.php: فحص جاهزية الخادم قبل النشر وبعدهheader('Content-Type: application/json; charset=utf-8'); $checks = [ 'php_8_1_or_newer' => version_compare(PHP_VERSION, '8.1', '>='), 'pdo' => extension_loaded('pdo'), 'mbstring' => extension_loaded('mbstring'), 'json' => extension_loaded('json'), 'display_errors_off' => !ini_get('display_errors'), 'timezone_riyadh' => date_default_timezone_get() === 'Asia/Riyadh',];$ok = !in_array(false, $checks, true);http_response_code($ok ? 200 : 500);echo json_encode(['ok' => $ok, 'php' => PHP_VERSION, 'checks' => $checks], JSON_PRETTY_PRINT);
في المختبر display_errors مفعّل لأنه بيئة تعلّم، فيفشل فحصه ويرد الفحص بـ 500. وهذا بالضبط ما نريد أن تكشفه الصفحة قبل نشر حقيقي.
٥الإعدادات حسب البيئة
التطبيق نفسه يعمل في بيئتين: التطوير على جهازك، والإنتاج على الخادم. بيانات الاتصال بالقاعدة مختلفة، وعرض الأخطاء مختلف. لا نعدّل الكود عند كل نشر؛ بل نقرأ البيئة من متغير، ونختار الإعدادات:
<?php// config.php$env = getenv('APP_ENV') ?: 'development'; $config = [ 'development' => [ 'db_dsn' => 'mysql:host=localhost;dbname=app;charset=utf8mb4', 'db_user' => 'root', 'db_pass' => '', 'debug' => true, ], 'production' => [ 'db_dsn' => getenv('DB_DSN'), // من لوحة الاستضافة، لا من الكود 'db_user' => getenv('DB_USER'), 'db_pass' => getenv('DB_PASS'), 'debug' => false, ],][$env]; ini_set('display_errors', $config['debug'] ? '1' : '0');date_default_timezone_set('Asia/Riyadh');return $config;
توقّع وتحقّق
موقع طلابي صغير لأول نشر. الأنسب غالبًا:
في VPS، من مسؤول عن تحديثات النظام والأمان؟
display_errors على الخادم الحقيقي:
log_errors On.صفحة phpinfo() بعد التحقق من الإعدادات:
الخلاصة
- مشتركة: الأسهل والأرخص.
VPS: تحكم كامل ومسؤولية كاملة. سحابية: توسّع تلقائي. - اختر حسب: إصدار
PHPوالإضافات، والضغط، والمكان، والدعم، وHTTPS. - الإنتاج:
display_errors Off، وlog_errors On، وAsia/Riyadh، وcookie_secure On. - صفحة فحص مخصصة بدل
phpinfo، واحذفphpinfoبعد استخدامها. - الإعدادات حسب البيئة، والأسرار خارج الكود.
تحدٍّ برمجي: صفحة جاهزية الخادم
متوسطقبل رفع التطبيق، نريد صفحة ready.php تفحص الخادم الجديد وترد JSON.
- الفحوص:
php(الإصدار 8.1 فأحدث)، وextensions(الإضافات pdo و mbstring و json و session كلها مفعّلة)، وuploads_writable(مجلد uploads موجود أو تنشئه، وقابل للكتابة). - الرد:
{"ok":true,"checks":{"php":true,"extensions":true,"uploads_writable":true},"missing":[]}و missing قائمة الإضافات الناقصة. - الرمز 200 إن نجح الكل، وإلا 503 Service Unavailable.
👀 اعرض الاستجابة المطلوبة
GET /ready.php
- الكود يعمل بلا أخطاء أو تحذيرات
- الرد JSON بالشكل المطلوب تمامًا
- الكل ناجح ← 200
- تستخدم version_compare و extension_loaded و is_writable
💡 تلميح 1
version_compare(PHP_VERSION, '8.1', '>=')💡 تلميح 2
array_values(array_filter($required, fn($e) => !extension_loaded($e)))حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
<?phpheader('Content-Type: application/json; charset=utf-8'); $required = ['pdo', 'mbstring', 'json', 'session'];$missing = array_values(array_filter($required, fn($e) => !extension_loaded($e))); $dir = __DIR__ . '/uploads';if (!is_dir($dir)) { mkdir($dir, 0755, true);}$checks = [ 'php' => version_compare(PHP_VERSION, '8.1', '>='), 'extensions' => count($missing) === 0, 'uploads_writable' => is_writable($dir),];$ok = !in_array(false, $checks, true);http_response_code($ok ? 200 : 503);echo json_encode(['ok' => $ok, 'checks' => $checks, 'missing' => $missing]);