لماذا mysql_* في PHP هو شر: تحليل كامل مع أمثلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

قصة خطأ واحد: لماذا mysql_* هو من الماضي

\n\n

تخيل: أنت تكتب موقعًا على PHP، وتتصل بقاعدة بيانات MySQL وتستخدم الدالة المألوفة من الجامعة mysql_query(). كل شيء يعمل، الموقع يعيش، المستخدمون سعداء. ولكن في يوم من الأيام تلاحظ تحذيرًا غريبًا في السجلات: «Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future». هذا ليس مجرد تذمر من المفسر - إنه علم أحمر لا يمكن تجاهله.

\n\n

على Stack Overflow، جمع سؤال «Why shouldn't I use mysql_* functions in PHP?» آلاف المشاهدات ومئات التعليقات. وهذا ليس من قبيل الصدفة. في هذه المقالة، سنحلل لماذا أصبحت دوال mysql_* (mysql_connect, mysql_query, mysql_fetch_array وغيرها) العدو رقم واحد لمطوري PHP، وسنعرض بأمثلة كود حقيقية ما الذي يجب استبدالها به، وسنقدم خطة ترحيل خطوة بخطوة.

\n\n

ما هي mysql_* ولماذا تمت إزالتها؟

\n\n

ظهر إضافة mysql_* (MySQL الأصلي) في PHP 2.0 في عام 1997 البعيد. كانت بسيطة وبديهية: استدعاء mysql_connect()، تنفيذ استعلام عبر mysql_query()، الحصول على النتيجة. ولكن لهذه البساطة كان جانب مظلم.

\n\n

ابتداءً من PHP 5.5.0، تم وضع علامة قديمة (deprecated) على جميع دوال mysql_*، وفي PHP 7.0 تم حذفها بالكامل. إذا حاولت استخدام mysql_connect() على PHP 7+، ستحصل على خطأ فادح: Call to undefined function mysql_connect(). السبب ليس نزوة من مطوري PHP، بل مشاكل أساسية في الأمان والهندسة المعمارية.

\n\n

ثلاثة أسباب رئيسية للتخلي عن mysql_*

\n\n
    \n
  • حقن SQL بدون حماية - الدوال لا تدعم الاستعلامات المحضرة (prepared statements)، مما يجعل التعقيم اليدوي إلزاميًا، ولكنه خطوة غالبًا ما تُنسى.
  • \n
  • هندسة معمارية قديمة - لا يوجد دعم للأسلوب الكائني، والإجراءات المخزنة، والاستعلامات المتعددة، والمعاملات.
  • \n
  • غياب التطوير - لم يتم تحديث الإضافة لسنوات، بينما تغير MySQL (على سبيل المثال، ظهرت أنواع بيانات جديدة، وترميزات، وآليات مصادقة).
  • \n
\n\n

مثال حي: كيف تقتل mysql_* موقعك

\n\n

دعنا نلقي نظرة على الكود الكلاسيكي الذي لا يزال موجودًا في الكتب المدرسية القديمة والمنتديات:

\n\n
<?php\n// كود قديم - لا تستخدمه!\n$link = mysql_connect('localhost', 'root', 'password');\nmysql_select_db('users_db', $link);\n\n$user_input = $_GET['username']; // المستخدم يدخل: ' OR 1=1 --\n$query = "SELECT * FROM users WHERE username = '$user_input'";\n$result = mysql_query($query, $link);\n\nwhile ($row = mysql_fetch_assoc($result)) {\n    echo "مرحبًا، " . $row['username'] . "<br>";\n}\n?>
\n\n

ما المشكلة؟ إذا قام المهاجم بإدخال القيمة ' OR 1=1 -- في المعامل username، سيتحول الاستعلام إلى:

\n\n
SELECT * FROM users WHERE username = '' OR 1=1 --
\n\n

الشرطة المزدوجة -- ستعلق باقي الاستعلام، والشرط 1=1 صحيح دائمًا. ونتيجة لذلك، ستحصل على جميع المستخدمين في قاعدة البيانات، بما في ذلك كلمات المرور والبريد الإلكتروني والمعلومات السرية الأخرى. هذه ليست نظرية - هذا ثغرة حقيقية تخترق آلاف المواقع كل يوم.

\n\n

بالطبع، يمكن استخدام mysql_real_escape_string()، ولكن:

\n
    \n
  • غالبًا ما ينسى المطورون استدعاءها.
  • \n
  • لا تحمي من جميع أنواع الهجمات (مثل الهجمات باستخدام الترميزات).
  • \n
  • يصبح الكود قذرًا ويصعب قراءته.
  • \n
\n\n

ما الذي يجب استبدال mysql_* به: طريقتان حديثتان

\n\n

في PHP الحديثة، هناك إضافتان جديرتان بالثقة للعمل مع MySQL: mysqli (MySQL Improved) و PDO (PHP Data Objects). كلاهما يدعمان

المدونات

توصيات الكتب