php - لماذا لا يجب استخدام وظائف mysql_ * في فب؟


ما هي الأسباب التقنية لماذا لا ينبغي للمرء استخدام وظائف mysql_* ؟ (مثل mysql_query() ، mysql_connect() أو mysql_real_escape_string()

لماذا يجب علي استخدام شيء آخر حتى لو كانوا يعملون على موقعي؟

إذا لم يعملوا على موقعي، لماذا أحصل على أخطاء مثل تحذير: mysql_connect (): لا يوجد ملف أو دليل من هذا القبيل ؟



Answers



ملحق الخلية:

  • ليس تحت التطوير النشط
  • يتم إهمالها رسميا اعتبارا من فب 5.5 (صدر يونيو 2013).
  • تمت إزالتها بالكامل اعتبارا من فب 7.0 (صدر في ديسمبر 2015)
    • وهذا يعني أنه اعتبارا من 31 ديسمبر 2018 أنها لن تكون موجودة في أي نسخة معتمدة من فب. حاليا يحصل فقط التحديثات الأمنية .
  • يفتقر إلى واجهة و
  • لا يدعم:
    • استعلامات غير محظورة وغير متزامنة
    • البيانات المعدة أو الاستعلامات المعلمة
    • الإجراءات المخزنة
    • بيانات متعددة
    • المعاملات
    • طريقة "مصادقة كلمة المرور" الجديدة (على افتراضيا في الخلية 5.6؛ مطلوب في 5.7)
    • جميع وظائف في الخلية 5.1

نظرا لأنه يتم إهمالها، فإن استخدامها يجعل رمزك أقل إثباتا في المستقبل.

عدم وجود دعم للبيانات المعدة أهمية خاصة لأنها توفر طريقة أكثر وضوحا وأقل عرضة للخطأ الهروب واقتباس البيانات الخارجية من يدويا الهروب منه مع دعوة وظيفة منفصلة.

راجع المقارنة بين ملحقات سكل .




فب يقدم ثلاث واجهات برمجة تطبيقات مختلفة للاتصال ميسكل. هذه هي mysqli (إزالتها اعتبارا من فب 7)، mysqli ، و PDO الامتدادات.

وظائف mysql_* المستخدمة لتكون شعبية جدا، ولكن لم يتم تشجيع استخدامها بعد الآن. يناقش فريق التوثيق حالة أمن قاعدة البيانات، وتثقيف المستخدمين بالابتعاد عن امتداد إكست / ميسكل المستخدم عادة هو جزء من هذا (راجع php.internals: ديبريكاتينغ إكست / ميسكل ).

وقد اتخذ فريق المطور فب في وقت لاحق قرار توليد أخطاء E_DEPRECATED عندما يتصل المستخدمون ميسكل، سواء من خلال mysql_connect() ، mysql_pconnect() أو وظيفة الاتصال الضمني التي بنيت في mysql_pconnect() .

ext/mysql تم إهمالها رسميا اعتبارا من فب 5.5 وتم إزالتها اعتبارا من فب 7 .

انظر المربع الأحمر؟

عندما تذهب في أي صفحة دليل وظيفة mysql_* ، ترى مربع أحمر، موضحا أنه لا ينبغي أن تستخدم بعد الآن.

لماذا ا

الانتقال بعيدا عن ext/mysql ميسكل ليس فقط حول الأمن، ولكن أيضا عن وجود إمكانية الوصول إلى كافة الميزات من قاعدة بيانات ميسكل.

ext/mysql ميسكل بنيت ل ميسكل 3.23 وحصلت فقط عدد قليل جدا من الإضافات منذ ذلك الحين في حين أن معظمهم الحفاظ على التوافق مع هذا الإصدار القديم الذي يجعل رمز أصعب قليلا للحفاظ على. الميزات المفقودة التي لا يدعمها ext/mysql ما يلي: ( من دليل فب ).

سبب عدم استخدام mysql_* وظيفة :

  • ليس قيد التطوير النشط
  • تمت الإزالة اعتبارا من فب 7
  • يفتقر إلى واجهة و
  • لا يدعم الاستعلامات غير المتزامنة، غير المتزامنة
  • لا يدعم البيانات المعدة أو الاستعلامات المعلمة
  • لا يدعم الإجراءات المخزنة
  • لا يدعم بيانات متعددة
  • لا يدعم المعاملات
  • لا يدعم جميع الوظائف في الخلية 5.1

نقلا عن النقطة المذكورة من جواب كوينتين

عدم وجود دعم للبيانات المعدة أهمية خاصة لأنها توفر طريقة أكثر وضوحا وأقل عرضة للخطأ الهروب واقتباس البيانات الخارجية من يدويا الهروب منه مع دعوة وظيفة منفصلة.

راجع المقارنة بين ملحقات سكل .

قم بإلغاء تحذيرات الإھمال

بينما يتم تحويل التعليمات البرمجية إلى MySQLi / PDO ، يمكن قمع الأخطاء E_DEPRECATED عن طريق تعيين error_reporting في php.ini لاستبعاد E_DEPRECATED:

error_reporting = E_ALL ^ E_DEPRECATED

لاحظ أن هذا سوف يخفي أيضا تحذيرات الإهمال الأخرى ، والتي، ومع ذلك، قد تكون لأشياء أخرى غير الخلية. ( من دليل فب )

المادة بدو مقابل ميسكلي: الذي يجب عليك استخدام؟ من قبل ديجان مارجانوفيتش سوف تساعدك على اختيار.

وأفضل طريقة PDO ، وأنا الآن كتابة PDO تعليمي بسيط.

A بدو بسيطة وقصيرة تعليمي

السؤال الأول في ذهني كان: ما هو "PDO`؟

A. " بدو - كائنات بيانات فب - هي طبقة وصول قاعدة بيانات توفر طريقة موحدة للوصول إلى قواعد بيانات متعددة."

الاتصال ب ميسكل

مع وظيفة mysql_* أو يمكننا أن نقول أنها الطريقة القديمة (مهملة في فب 5.5 وما فوق)

$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);

مع PDO : كل ​​ما عليك القيام به هو إنشاء كائن PDO جديد. يقبل منشئ المعلمات لتحديد مصدر قاعدة البيانات منشئ PDO الغالب يأخذ أربعة المعلمات التي هي DSN (اسم مصدر البيانات) واسم username اختياريا، password .

هنا أعتقد أنك مألوفة مع كل ما عدا DSN . وهذا جديد في PDO . و DSN هو في الأساس سلسلة من الخيارات التي تخبر PDO التي السائق لاستخدامها، وتفاصيل الاتصال. لمزيد من المرجع، تحقق بدو ميسكل دسن .

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');

ملاحظة: يمكنك أيضا استخدام charset=UTF-8 ، ولكن أحيانا يسبب خطأ، لذلك فمن الأفضل استخدام utf8 .

إذا كان هناك أي خطأ في الاتصال، فإنه سيتم رمي كائن PDOException التي يمكن تخزينها مؤقتا للتعامل مع Exception أكثر من ذلك.

قراءة جيدة : كونكتيونس أند كونكتيون ماناجيمنت ¶

يمكنك أيضا تمرير في العديد من خيارات برنامج التشغيل كمصفوفة للمعلمة الرابعة. أوصي تمرير المعلمة الذي يضع PDO في وضع الاستثناء. لأن بعض برامج تشغيل PDO لا تدعم البيانات المعدة محليا، لذلك PDO يؤدي مضاهاة إعداد. كما أنه يتيح لك تمكين هذه المحاكاة يدويا. لاستخدام البيانات المعدة من جانب الخادم الأصلي، يجب تعيينها بشكل false .

والآخر هو لإيقاف مضاهاة إعداد الذي يتم تمكينه في برنامج تشغيل MySQL افتراضيا، ولكن إعداد مضاهاة يجب إيقاف لاستخدام PDO بأمان.

وسوف أشرح في وقت لاحق لماذا يجب أن يتم إيقاف إعداد مضاهاة. للعثور على سبب يرجى مراجعة هذا المنصب .

هو فقط صالحة للاستعمال إذا كنت تستخدم نسخة قديمة من MySQL التي لا أوصى.

في ما يلي مثال على كيفية إجراء ذلك:

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8', 
              'username', 
              'password',
              array(PDO::ATTR_EMULATE_PREPARES => false,
              PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

يمكننا تعيين سمات بعد البناء بدو؟

نعم ، يمكننا أيضا تعيين بعض السمات بعد بناء بدو مع الأسلوب setAttribute :

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8', 
              'username', 
              'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

معالجة الأخطاء

معالجة الأخطاء أسهل بكثير في PDO من mysql_* .

وهناك ممارسة شائعة عند استخدام mysql_* هي:

//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));

OR die() ليست وسيلة جيدة للتعامل مع الخطأ لأننا لا نستطيع التعامل مع الشيء في die . وسوف تنتهي فقط السيناريو فجأة ثم صدى الخطأ إلى الشاشة التي عادة لا تريد أن تظهر للمستخدمين النهائيين، والسماح للقراصنة دموية اكتشاف المخطط الخاص بك. بدلا من ذلك، يمكن غالبا استخدام قيم عودة وظائف mysql_* بالاقتران مع mysql_error () لمعالجة الأخطاء.

تقدم PDO حل أفضل: الاستثناءات. أي شيء نقوم به مع PDO يجب أن تكون ملفوفة في try - كتلة catch . يمكننا فرض PDO في واحد من ثلاثة أوضاع خطأ عن طريق تعيين السمة وضع الخطأ. هناك ثلاث طرق لمعالجة الأخطاء أدناه.

  • PDO::ERRMODE_SILENT . انها مجرد وضع رموز الخطأ ويعمل إلى حد كبير نفس mysql_* حيث يجب التحقق من كل نتيجة ثم ننظر في $db->errorInfo(); للحصول على تفاصيل الخطأ.
  • PDO::ERRMODE_WARNING ارفع E_WARNING . (تحذيرات وقت التشغيل (أخطاء غير مميتة) لا يتم إيقاف تنفيذ النص البرمجي.)
  • PDO::ERRMODE_EXCEPTION : استثناءات رمي. وهو يمثل خطأ أثارته شركة تنمية نفط عمان. يجب عدم رمي PDOException من التعليمات البرمجية الخاصة بك. راجع الاستثناءات للحصول على مزيد من المعلومات حول الاستثناءات في فب. وهو يعمل كثيرا مثل or die(mysql_error()); ، عندما لا يتم القبض عليه. ولكن على عكس or die() ، PDOException يمكن القبض والتعامل معها بأمان إذا اخترت القيام بذلك.

قراءة جيدة :

مثل:

$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

ويمكنك التفاف عليه في try - catch ، مثل أدناه:

try {
    //Connect as appropriate as above
    $db->query('hi'); //Invalid query!
} 
catch (PDOException $ex) {
    echo "An Error occured!"; //User friendly message/message you want to show to user
    some_logging_function($ex->getMessage());
}

لم يكن لديك للتعامل مع try - catch الآن. يمكنك قبض عليه في أي وقت مناسب، ولكن أوصي بشدة لك لاستخدام try - catch . كما قد يكون من المنطقي أن يتم التقاطها خارج الدالة التي تستدعي PDO :

function data_fun($db) {
    $stmt = $db->query("SELECT * FROM table");
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

//Then later
try {
    data_fun($db);
}
catch(PDOException $ex) {
    //Here you can handle error and show message/perform action you want.
}

أيضا، يمكنك التعامل معها من قبل or die() أو يمكننا أن نقول مثل mysql_* ، لكنها ستكون متنوعة حقا. يمكنك إخفاء رسائل الخطأ الخطيرة في الإنتاج عن طريق تحويل display_errors off ومجرد قراءة سجل الخطأ الخاص بك.

الآن، بعد قراءة كل الأشياء أعلاه، ربما كنت أفكر: ما هيك هو أنه عندما أريد فقط أن أبدأ يميل بسيطة SELECT ، INSERT ، UPDATE ، أو DELETE البيانات؟ لا تقلق، وهنا نذهب:

تحديد البيانات

لذلك ما تقومون به في mysql_* هو:

<?php
$result = mysql_query('SELECT * from table') or die(mysql_error());

$num_rows = mysql_num_rows($result);

while($row = mysql_fetch_assoc($result)) {
    echo $row['field1'];
}

الآن في PDO ، يمكنك القيام بذلك مثل:

<?php
$stmt = $db->query('SELECT * FROM table');

while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo $row['field1'];
}

أو

<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

//Use $results

ملاحظة : إذا كنت تستخدم الطريقة التالية ( query() )، تقوم هذه الطريقة بإرجاع كائن PDOStatement . حتى إذا كنت ترغب في جلب النتيجة، واستخدامه مثل أعلاه.

<?php
foreach($db->query('SELECT * FROM table') as $row) {
    echo $row['field1'];
}

في بيانات بدو، يتم الحصول عليها عن طريق ->fetch() ، طريقة التعامل مع البيان الخاص بك. قبل استدعاء الجلب، فإن أفضل نهج أن يقول بدو كيف تريد أن يتم جلب البيانات. في القسم أدناه أشرح ذلك.

جلب وسائط

لاحظ استخدام PDO::FETCH_ASSOC في fetch() و fetchAll() رمز أعلاه. هذا يخبر PDO عن إعادة الصفوف كمصفوفة ارتباطية مع أسماء الحقول كمفاتيح. هناك العديد من وسائط جلب أخرى جدا والتي سوف أشرح واحدا تلو الآخر.

أولا وقبل كل شيء، وأنا شرح كيفية تحديد وضع جلب:

 $stmt->fetch(PDO::FETCH_ASSOC)

في ما سبق، لقد تم استخدام fetch() . تستطيع ايضا استخذام:

الآن جئت إلى جلب الوضع:

  • PDO::FETCH_ASSOC : يقوم بإرجاع صفيف مفهرس باسم العمود كما تم إرجاعه في مجموعة النتائج
  • PDO::FETCH_BOTH (افتراضي): بإرجاع صفيف مفهرس بواسطة كل من اسم العمود ورقم العمود المفهرس 0 كما تم إرجاعه في مجموعة النتائج

هناك المزيد من الخيارات! قراءة كل منهم في وثائق الجلب PDOStatement . .

الحصول على عدد الصفوف :

بدلا من استخدام mysql_num_rows للحصول على عدد الصفوف التي تم إرجاعها، يمكنك الحصول على PDOStatement و rowCount() ، مثل:

<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';

الحصول على آخر معرف تم إدراجه

<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();

إدراج وتحديث أو حذف العبارات

ما نقوم به في mysql_* وظيفة:

<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);

وفي بدو، يمكن القيام بهذا الشيء من خلال:

<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;

في الاستعلام أعلاه PDO::exec تنفيذ عبارة سكل وإرجاع عدد الصفوف المتأثرة.

سيتم تغطية إدراج وحذف في وقت لاحق.

تكون الطريقة المذكورة أعلاه مفيدة فقط عندما لا تستخدم متغير في الاستعلام. ولكن عندما تحتاج إلى استخدام متغير في الاستعلام، لا تحاول من أي وقت مضى مثل ما سبق وهناك لبيان أعدت أو بيان المعلمة هو.

البيانات المعدة

س: ما هو البيان المعد و لماذا أحتاجهم؟
أ . العبارة المعدة عبارة عن عبارة سكل سابقة التجميع يمكن تنفيذها عدة مرات عن طريق ارسال البيانات الى وحدة الخدمة فقط.

سير العمل النموذجي من استخدام بيان أعدت كما يلي ( نقلت من ويكيبيديا ثلاثة 3 نقطة ):

  1. إعداد : يتم إنشاء قالب بيان من قبل التطبيق وإرسالها إلى نظام إدارة قاعدة البيانات (دبمس). وتترك بعض القيم غير محددة، تسمى المعلمات أو العناصر النائبة أو ربط المتغيرات (المسمى أدناه):

    INSERT INTO PRODUCT (name, price) VALUES (?, ?)

  2. يقوم دبمس بتحليل، ويقوم بتجميع، ويقوم بتحسين الاستعلام في قالب العبارة، ويقوم بتخزين النتيجة بدون تنفيذها.

  3. تنفيذ : في وقت لاحق، لوازم التطبيق (أو يربط) القيم للمعلمات، و دبمس ينفذ البيان (ربما يعود نتيجة). التطبيق قد تنفيذ البيان عدة مرات كما تريد مع قيم مختلفة. في هذا المثال، قد توفر "الخبز" للمعلمة الأولى و 1.00 للمعلمة الثانية.

يمكنك استخدام بيان تم إعداده من خلال تضمين العناصر النائبة في سكل الخاص بك. هناك أساسا ثلاثة منها دون النائبة (لا تحاول هذا مع متغير أعلاه) واحد، مع العناصر النائبة لم يكشف عن اسمه، واحد مع النائبة المسماة.

Q. حتى الآن، ما يسمى النائبة وكيف يمكنني استخدامها؟
أ . العناصر النائبة المسماة. استخدم أسماء وصفية مسبوقة بنقطتين، بدلا من علامات الاستفهام. نحن لا يهمني موقف / ترتيب القيمة في اسم مكان حامل:

 $stmt->bindParam(':bla', $bla);

bindParam(parameter,variable,data_type,length,driver_options)

يمكنك أيضا ربط باستخدام صفيف تنفيذ كذلك:

<?php
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

ميزة أخرى لطيفة للأصدقاء OOP هو أن النائبة اسمه لديهم القدرة على إدراج الكائنات مباشرة في قاعدة البيانات الخاصة بك، على افتراض خصائص تطابق الحقول المسماة. فمثلا:

class person {
    public $name;
    public $add;
    function __construct($a,$b) {
        $this->name = $a;
        $this->add = $b;
    }

}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);

Q. الآن، ما هي العناصر النائبة التي لم تذكر اسمها وكيف يمكنني استخدامها؟
أ. لنأخذ مثالا على ذلك:

<?php
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();

و

$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));

في ما سبق، يمكنك أن ترى تلك ? بدلا من الاسم كما هو الحال في حامل مكان الاسم. الآن في المثال الأول، نقوم بتخصيص متغيرات $stmt->bindValue(1, $name, PDO::PARAM_STR); النائبة المختلفة ( $stmt->bindValue(1, $name, PDO::PARAM_STR); ). ثم نقوم بتخصيص قيم لتلك العناصر النائبة وتنفيذ البيان. في المثال الثاني، يذهب عنصر الصفيف الأول إلى الأول ? والثانية إلى الثانية ? .

ملاحظة : في العناصر النائبة غير المسماة يجب أن نحرص على الترتيب الصحيح للعناصر في المصفوفة أننا تمرير إلى PDOStatement::execute() الأسلوب.

SELECT ، INSERT ، UPDATE ، DELETE الاستعلامات المعدة

  1. SELECT :

    $stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
    $stmt->execute(array(':name' => $name, ':id' => $id));
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
  2. INSERT :

    $stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
    $stmt->execute(array(':field1' => $field1, ':field2' => $field2));
    $affected_rows = $stmt->rowCount();
  3. DELETE :

    $stmt = $db->prepare("DELETE FROM table WHERE id=:id");
    $stmt->bindValue(':id', $id, PDO::PARAM_STR);
    $stmt->execute();
    $affected_rows = $stmt->rowCount();
  4. UPDATE :

    $stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
    $stmt->execute(array($name, $id));
    $affected_rows = $stmt->rowCount();

ملحوظة:

ومع ذلك PDO و / أو MySQLi ليست آمنة تماما. التحقق من الجواب هل أعدت شركة تنمية نفط عمان بيانات كافية لمنع حقن سكل؟ بواسطة إركماكسيل . أيضا، وأنا نقتبس بعض جزء من جوابه:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES GBK');
$stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1");
$stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));



أولا، دعونا نبدأ مع تعليق قياسي نعطي الجميع:

من فضلك، لا تستخدم mysql_* وظائف في التعليمات البرمجية الجديدة . ولم يعد يحتفظ بها ويتم إهمالها رسميا . انظر المربع الأحمر ؟ تعرف على البيانات المعدة بدلا من ذلك، واستخدام بدو أو ميسكلي - هذه المادة سوف تساعدك على أن تقرر أي. إذا اخترت بدو، وهنا هو تعليمي جيد .

دعونا نذهب من خلال هذا، الجملة من الجملة، وشرح:

  • وهي لم تعد قائمة، وهي مهملة رسميا

    وهذا يعني أن المجتمع فب إسقاط تدريجيا دعم لهذه الوظائف القديمة جدا. ومن المرجح أن لا وجود لها في المستقبل (الأخيرة) نسخة من فب! استمرار استخدام هذه الوظائف قد كسر التعليمات البرمجية الخاصة بك في (ليس ذلك) المستقبل البعيد.

    الجديد! - إكست / ميسكل هو الآن مهملة رسميا اعتبارا من فب 5.5!

    أحدث! تمت إزالة إكست / ميسكل في فب 7

  • بدلا من ذلك، يجب أن تتعلم من البيانات المعدة -

    mysql_* تمديد لا يدعم البيانات المعدة ، والذي هو (من بين أمور أخرى) مضاد مضادة فعالة جدا ضد حقن سكل . انها ثابتة ضعف خطير جدا في التطبيقات المعتمدة الخلية التي تسمح المهاجمين للوصول إلى النص الخاص بك وتنفيذ أي استفسار ممكن على قاعدة البيانات الخاصة بك.

    لمزيد من المعلومات، راجع كيف يمكن منع حقن سكل في فب؟

  • انظر المربع الأحمر؟

    عندما تذهب في أي صفحة دليل وظيفة mysql ، ترى مربع أحمر، موضحا أنه لا ينبغي أن تستخدم بعد الآن.

  • استخدام بدو أو ميسكلي

    هناك بدائل أفضل وأكثر قوة ومبنية بشكل جيد، بدو - كائن قاعدة بيانات فب ، والذي يقدم نهج أوب الكامل لتفاعل قاعدة البيانات، و ميسكلي ، وهو تحسين محددة الخلية.




سهولة الاستعمال

وقد سبق ذكر الأسباب التحليلية والتركيبية. بالنسبة للقادمين الجدد هناك حافز أكثر أهمية لوقف استخدام وظائف mysql_ المؤرخة.

واجهات برمجة التطبيقات المعاصرة لقاعدة البيانات هي أسهل استخداما.

انها في الغالب المعلمات ملزمة التي يمكن تبسيط التعليمات البرمجية. ومع الدروس الممتازة (كما رأينا أعلاه) فإن الانتقال إلى شركة تنمية نفط عمان ليس شاقا للغاية.

إلا أن إعادة كتابة قاعدة شفرة أكبر في آن واحد تستغرق وقتا. رايسون d'être لهذا البديل الوسيط:

ما يعادل pdo_ * وظائف بدلا من mysql_ *

باستخدام < pdo_mysql.php > يمكنك التبديل من وظائف mysql_ القديمة مع الحد الأدنى من الجهد . ويضيف pdo_ الوظيفة pdo_ التي تحل محل نظرائها mysql_ .

  1. ببساطة include_once( "pdo_mysql.php" ); في كل سيناريو استدعاء التي يجب أن تتفاعل مع قاعدة البيانات.

  2. قم بإزالة بادئة الدالة mysql_ كل مكان pdo_ ب pdo_ .

    • mysql_ pdo_ connect() يصبح pdo_ connect()
    • mysql_ pdo_ query() يصبح pdo_ query()
    • mysql_ num_rows() يصبح pdo_ num_rows()
    • mysql_ insert_id() يصبح pdo_ insert_id()
    • mysql_ fetch_array() يصبح pdo_ fetch_array()
    • mysql_ fetch_assoc() يصبح pdo_ fetch_assoc()
    • mysql_ real_escape_string() يصبح pdo_ real_escape_string()
    • وما إلى ذلك وهلم جرا...

  3. سوف تعمل التعليمات البرمجية على حد سواء ولا تزال تبدو في الغالب نفسها:

    include_once("pdo_mysql.php"); 
    
    pdo_connect("localhost", "usrABC", "pw1234567");
    pdo_select_db("test");
    
    $result = pdo_query("SELECT title, html FROM pages");  
    
    while ($row = pdo_fetch_assoc($result)) {
        print "$row[title] - $row[html]";
    }

إت voilà.
التعليمات البرمجية الخاصة بك تستخدم بدو.
الآن حان الوقت للاستفادة فعلا.

يمكن أن تكون المعلمات ملزمة سهلة الاستخدام

تحتاج فقط أبي أقل عمقا.

pdo_query() يضيف دعم pdo_query() جدا للمعلمات ملزمة. تحويل الرمز القديم واضح:

نقل المتغيرات الخاصة بك من سلسلة سكل.

  • قم pdo_query() كمعلمات وظيفة محددة بفواصل ل pdo_query() .
  • وضع علامات الاستفهام ? كما النائبة حيث المتغيرات كانت من قبل.
  • التخلص من ' يقتبس واحد أن القيم سلسلة متضمنة سابقا / المتغيرات.

تصبح الميزة أكثر وضوحا للرمز الأطول.

في كثير من الأحيان لا يتم استيفاء المتغيرات سلسلة فقط في سكل، ولكن متسلسلة مع المكالمات الهروب بينهما.

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title='" . pdo_real_escape_string($title) . "' OR id='".
   pdo_real_escape_string($title) . "' AND user <> '" .
   pdo_real_escape_string($root) . "' ORDER BY date")

مع ? النائبة تطبيق لم يكن لديك لعناء مع ذلك:

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root)

تذكر أن pdo_ * لا يزال يسمح إما أو .
فقط لا تهرب من متغير وربط ذلك في نفس الاستعلام.

  • يتم توفير ميزة العنصر النائب من قبل بدو حقيقية وراء ذلك.
  • وهكذا سمح أيضا :named قوائم النائب في وقت لاحق.

الأهم من ذلك يمكنك تمرير $ _REQUEST [] المتغيرات بأمان وراء أي استفسار. عندما تتطابق حقول <form> المقدمة مع بنية قاعدة البيانات، فإنها تكون أقصر من ذلك:

pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);

الكثير من البساطة. ولكن دعونا نعود إلى بعض النصائح أكثر إعادة كتابة والأسباب التقنية لماذا قد ترغب في التخلص من mysql_ والهروب.

إصلاح أو إزالة أي sanitize() أولدشول sanitize() وظيفة

بمجرد تحويل جميع المكالمات mysql_ إلى pdo_query مع معلمات ملزمة، إزالة كافة المكالمات pdo_real_escape_string زائدة عن الحاجة.

على وجه الخصوص يجب عليك إصلاح أي sanitize أو clean أو clean_data أو وظائف clean_data كما تم الإعلان عنها من قبل الدروس المؤرخة في شكل واحد أو آخر:

function sanitize($str) {
   return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}

معظم الخلل الصارخ هنا هو عدم وجود وثائق. والأهم من ذلك هو أن الترشيح كان في الترتيب الخطأ.

  • وكان الترتيب الصحيح: stripslashes الأعمق، ثم trim ، بعد ذلك strip_tags ، strip_tags سياق الإخراج، وفقط أخيرا _escape_string كما يجب تطبيقه مباشرة قبل إنتيرسبارسينغ سكل.

  • ولكن كخطوة أولى مجرد التخلص من دعوة _real_escape_string .

  • قد تضطر إلى الحفاظ على بقية sanitize() الخاص بك sanitize() وظيفة في الوقت الراهن إذا كان قاعدة البيانات وتدفق التطبيق يتوقع هتمل السياق السياق سلاسل. إضافة تعليق أنه ينطبق فقط هتمل الهروب من الآن فصاعدا.

  • يتم تفويض سلسلة / قيمة التعامل مع بدو والبيانات الخاصة بها المعلمة.

  • إذا كان هناك أي ذكر ل stripslashes() في وظيفة التعقيم الخاص بك، فإنه قد يشير إلى مستوى أعلى من الرقابة.

    مذكرة تاريخية على magic_quotes. تم إيقاف هذه الميزة بشكل صحيح. وغالبا ما يصور بشكل غير صحيح كما فشل ميزة الأمان . ولكن magic_quotes هي كما فشلت ميزة الأمان كما كرات التنس قد فشلت كمصدر التغذية. وهذا ببساطة لم يكن الغرض منها.

    تنفيذ الأصلي في PHP2 / في قدم ذلك صراحة مع مجرد " سيتم هروب تلقائيا نقلت مما يجعل من الاسهل لتمرير بيانات النموذج مباشرة إلى استفسارات مسكل ". ومن الجدير بالذكر أنه كان أسيدنتيالي آمنة للاستخدام مع مسكل ، وهذا دعم أسي فقط.
    ثم أعدت PHP3 / زيند magic_quotes ل ميسكل و ميسدوكومنتيد ذلك. ولكن في الأصل كان مجرد ميزة الراحة ، لا تنوي الأمن.

كيف تختلف البيانات المعدة

عند التدافع سلسلة المتغيرات في استعلامات سكل، فإنه لا مجرد الحصول على أكثر تعقيدا بالنسبة لك لمتابعة. كما أنه جهد غريب ل ميسكل لفصل التعليمات البرمجية والبيانات مرة أخرى.

حقن سكل ببساطة عندما ينزف البيانات في سياق التعليمات البرمجية . لا يمكن ملقم قاعدة البيانات في وقت لاحق بقعة حيث فب أصلا لصقها المتغيرات بنود الاستعلام المنتصف.

مع المعلمات ملزمة لك فصل التعليمات البرمجية سكل وقيم سياق سكل في التعليمات البرمجية فب الخاص بك. ولكن لا تحصل تعديلا مرة أخرى وراء الكواليس (باستثناء بدو :: EMULATE_PREPARES). تتلقى قاعدة البيانات الخاصة بك أوامر سكل غير المتغيرة وقيم متغير 1: 1.

في حين أن هذه الإجابة تؤكد أن عليك أن تهتم بمزايا القراءة من إسقاط mysql_ . في بعض الأحيان أيضا ميزة الأداء (تكرار إدخالات مع قيم مختلفة فقط) بسبب هذه البيانات المرئية والفنية / التعليمات البرمجية الفصل.

حذار أن المعلمة ملزمة لا يزال ليس حل وقفة واحدة سحرية ضد جميع حقن سكل. فإنه يعالج الاستخدام الأكثر شيوعا للبيانات / القيم. ولكن لا يمكن إدراج محددات اسم / جدول العمود في القائمة البيضاء، أو المساعدة في إنشاء بند ديناميكي، أو قوائم قيمة مصفوفة عادية.

استخدام الهجين بدو

هذه pdo_* المجمع جعل أبي توقف الفجوة ودية الترميز. (انها الى حد كبير ما MYSQLI يمكن أن يكون لو لم يكن MYSQLI وظيفة التوقيع التوقيع). كما أنها تعرض بدو حقيقية في معظم الأحيان.
إعادة كتابة لا يجب أن تتوقف عند استخدام أسماء وظيفة pdo_ جديدة. هل يمكن نقل واحدا تلو الآخر كل pdo_query () إلى عادي $ pdo-> إعداد () -> تنفيذ () استدعاء.

فمن الأفضل أن تبدأ في تبسيط مرة أخرى. على سبيل المثال جلب النتائج المشتركة:

$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {

يمكن استبدال مع مجرد التكرار فوريش:

foreach ($result as $row) {

أو أفضل بعد استرجاع مجموعة كاملة وكاملة:

$result->fetchAll();

سوف تحصل على تحذيرات أكثر فائدة في معظم الحالات من بدو أو mysql_ عادة ما تقدم بعد الاستعلامات الفاشلة.

خيارات أخرى

لذلك هذا أمل تصور بعض الأسباب العملية ومسار وريثويل لإسقاط mysql_ .

مجرد التحول إلى بدو لا قطع تماما. pdo_query() هو أيضا مجرد الواجهة على ذلك.

إلا إذا كنت أيضا إدخال معلمة ملزمة أو يمكن الاستفادة من شيء آخر من أبي أجمل، انها تبديل لا طائل منه. آمل أن يتم تصويرها بسيطة بما فيه الكفاية لعدم زيادة تثبيط القادمين الجدد. (التعليم عادة ما يعمل أفضل من الحظر.)

في حين أنه مؤهل للحصول على أبسط شيء، التي يمكن-ربما-فئة العمل، فإنه لا يزال أيضا رمز تجريبي جدا. لقد كتبت للتو في نهاية الأسبوع. هناك الكثير من البدائل. مجرد جوجل ل فب قاعدة البيانات التجريد وتصفح قليلا. هناك دائما، وسوف يكون الكثير من المكتبات ممتازة لمثل هذه المهام.

إذا كنت ترغب في تبسيط تفاعل قاعدة البيانات الخاصة بك أبعد من ذلك، فإن مصممي الخرائط مثل باريس / إديورم يستحقون المحاولة. تماما مثل لا أحد يستخدم دوم لطيف في جافا سكريبت بعد الآن، لم يكن لديك لبابيسيت واجهة قاعدة بيانات الخام في الوقت الحاضر.




و mysql_ظائف هي:

  1. قديما - انهم لم يحتفظ أي أكثر
  2. لا تسمح لك لنقل بسهولة إلى الواجهة الخلفية قاعدة بيانات أخرى
  3. لا تدعم البيانات المعدة، وبالتالي
  4. تشجيع المبرمجين لاستخدام سلسلة لإنشاء الاستعلامات، مما يؤدي إلى الضعف حقن SQL



يتحدث عن التقنية الأسباب، هناك عدد قليل فقط، ومحددة للغاية ونادرا ما تستخدم. على الأرجح أنك لن تستخدم أي وقت مضى عليهم في حياتك.
قد يكون أنا جاهل جدا، ولكن لم يكن لي فرصة لاستخدامها أشياء مثل

  • غير حجب والاستعلامات غير متزامن
  • الإجراءات المخزنة العودة resultsets متعددة
  • تشفير (SSL)
  • ضغط

إذا كنت في حاجة إليها - هذه ليست أسباب فنية شك إلى الابتعاد عن تمديد الخلية نحو شيء أكثر عصرية وتبحث الحديث.

ومع ذلك، هناك أيضا بعض القضايا غير الفنية، التي يمكن أن تجعل تجربتك أصعب قليلا

  • وزيادة استخدام هذه الوظائف مع الإصدارات الحديثة PHP رفع إشعارات على مستوى مستنكر. انهم ببساطة يمكن إيقاف.
  • في المستقبل البعيد يمكن ربما إزالتها من PHP الافتراضي البناء. لا صفقة كبيرة جدا، كما سيتم نقل تحويلة mydsql إلى PECL وسوف كل هوستر نكون سعداء لcomplie PHP معها، لأنها لا تريد أن تفقد العملاء الذين كانوا يعملون منذ عشرات السنين المواقع.
  • مقاومة قوية من المجتمع ستاكوفيرفلوو. Еvery الوقت أذكر لكم هذه الوظائف صادقة، يمكنك أن قال أنهم تحت المحرمات صارمة.
  • كونه مستخدم العادي بى، وعلى الأرجح لديك فكرة استخدام هذه الوظائف هي من الأخطاء المعرضة للخطأ. فقط بسبب كل هذه الدروس والأدلة العديدة التي يعلمك بطريقة خاطئة. لا وظائف أنفسهم - لا بد لي من التأكيد على ذلك - ولكن الطريقة التي يتم استخدامها.

هذه المسألة الأخيرة هي المشكلة.
ولكن، برأيي، الحل المقترح ليس أفضل حالا سواء.
يبدو لي مثالية جدا حلم أن جميع هؤلاء المستخدمين PHP سوف تتعلم كيفية التعامل مع الاستفسارات SQL بشكل صحيح في وقت واحد. الأرجح أنها ستغير فقط mysql_ * لmysqli_ * ميكانيكيا، وترك النهج نفسه . خاصة لأن mysqli يجعل استخدام البيانات المعدة مؤلمة لا يصدق ومزعجة.
ناهيك عن أن الأم البيانات المعدة ليست كافية لحماية من حقن SQL، ولا mysqli ولا PDO يقدم حلا.

وهكذا، بدلا من محاربة هذا التمديد صادقة، كنت تفضل لمحاربة الممارسات الخاطئة وتثقيف الناس في الطرق الصحيحة.

أيضا، هناك بعض الأسباب كاذبة أو غير هامة، مثل

  • لا يدعم الإجراءات المخزنة (كنا باستخدام mysql_query("CALL my_proc");لالأعمار)
  • لا يدعم المعاملات (نفس النحو الوارد أعلاه)
  • لا يدعم القوائم متعددة (الذين في حاجة إليها؟)
  • لا قيد التطوير النشطة (ماذا في ذلك؟ أنها لا تؤثر لك بأي شكل من الأشكال العملية؟)
  • تفتقر إلى واجهة OO (لخلق واحدة هي مسألة لعدة ساعات)
  • لا يدعم تحضير بيانات أو Parametrized استعلامات

واحد الأخير هو نقطة مثيرة للاهتمام. وعلى الرغم من تحويلة الخلية لا تدعم الأم البيانات المعدة، فهي ليست المطلوبة للسلامة. يمكننا البيانات المعدة وهمية بسهولة باستخدام العناصر النائبة التعامل معها يدويا (تماما مثل PDO لا):

function paraQuery()
{
    $args  = func_get_args();
    $query = array_shift($args);
    $query = str_replace("%s","'%s'",$query); 

    foreach ($args as $key => $val)
    {
        $args[$key] = mysql_real_escape_string($val);
    }

    $query  = vsprintf($query, $args);
    $result = mysql_query($query);
    if (!$result)
    {
        throw new Exception(mysql_error()." [$query]");
    }
    return $result;
}

$query  = "SELECT * FROM table where a=%s AND b LIKE %s LIMIT %d";
$result = paraQuery($query, $a, "%$b%", $limit);

فويلا ، كل شيء معلمات وآمنة.

ولكن ما يرام، إذا كنت لا تحب مربع أحمر في الدليل، ومشكلة الاختيار الذي يطرح نفسه: mysqli أو شركة تنمية نفط عمان؟

حسنا، الجواب سيكون على النحو التالي:

  • إذا كنت تفهم ضرورة استخدام طبقة تجريد قاعدة البيانات ، وتبحث عن API لإنشاء واحد، mysqli هو اختيار جيد للغاية، كما أنه يدعم بالفعل العديد من الميزات ك محدد.
  • إذا، مثل غالبية النفايات من PHP الناس، كنت تستخدم API الخام يدعو الحق في رمز التطبيق (والذي هو في الأساس ممارسة خاطئة) - شركة تنمية نفط عمان هي الخيار الوحيد ، وهذا التمديد تتظاهر بأنها ليس فقط API وإنما هي شبه DAL، لا تزال غير مكتملة لكنه لم يقدم العديد من الميزات الهامة، مع اثنين منهم يجعل PDO المتميزة خطيرة من mysqli:

    • على عكس mysqli، يمكن PDO ربط النائبة من حيث القيمة ، الأمر الذي يجعل بنيت الاستفسارات الممكنة حيوي دون عدة شاشات من التعليمات البرمجية فوضوي للغاية.
    • على عكس mysqli، يمكن PDO دائما إرجاع نتيجة الاستعلام في مجموعة المعتادة بسيطة، في حين mysqli تستطيع ان تفعل ذلك فقط على المنشآت mysqlnd.

لذا، إذا كنت مستخدم العادي PHP وتريد أن تنقذ نفسك من نصف طن من الصداع عند استخدام بيانات معدة الأم، شركة تنمية نفط عمان - مرة أخرى - هو الخيار الوحيد.
ومع ذلك، PDO ليس عصا سحرية جدا، ولها انها المصاعب.
لذا، كتبت حلول لجميع المخاطر الشائعة والحالات المعقدة في العلامة PDO يكي

ومع ذلك، الجميع يتحدث ملحقات دائما في عداد المفقودين 2 الحقائق الهامة حول Mysqli وشركة تنمية نفط عمان:

  1. بيان معد سلفا ليست عصا سحرية . هناك معرفات الديناميكية التي لا يمكن أن تكون ملزمة باستخدام عبارات المعدة. هناك استفسار الديناميكية مع عدد غير معروف من المعلمات الأمر الذي يجعل الاستعلام بناء مهمة صعبة.

  2. يجب أن يبدو لا mysqli_ * ولا PDO وظائف في التعليمات البرمجية للتطبيق.
    يجب أن يكون هناك طبقة تجريد بينها وبين رمز التطبيق، والتي سوف تفعل كل مهمة قذرة من ملزم، حلقات، معالجة الأخطاء، الخ في الداخل، مما يجعل رمز التطبيق جافة ونظيفة. خاصة بالنسبة للحالات المعقدة مثل بناء الاستعلام الدينامية.

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

وفيما يلي بعض الأمثلة على أساس بلدي الطبقة safemysql لاظهار كيف يجب مثل فئة التجريد أن يكون:

$city_ids = array(1,2,3);
$cities   = $db->getCol("SELECT name FROM cities WHERE is IN(?a)", $city_ids);

قارن هذا سطر واحد واحد مع كمية من التعليمات البرمجية سوف تحتاج مع شركة تنمية نفط عمان .
ثم مقارنة مع مبلغ مجنون من التعليمات البرمجية سوف تحتاج مع Mysqli الخام إعداد البيانات. لاحظ أن معالجة الأخطاء، والتنميط، وقطع الأشجار الاستعلام بنيت بالفعل في وتشغيلها.

$insert = array('name' => 'John', 'surname' => "O'Hara");
$db->query("INSERT INTO users SET ?u", $insert);

قارن ذلك مع إدراج شركة تنمية نفط عمان المعتادة، عندما كل اسم حقل واحد يتكرر ستة الى عشرة مرات - في كل هذه العديد من اسمه النائبة، ربط وتعريفات الاستعلام.

مثال آخر:

$data = $db->getAll("SELECT * FROM goods ORDER BY ?n", $_GET['order']);

يمكنك من الصعب العثور على مثال لشركة تنمية نفط عمان للتعامل مع مثل هذه الحالات العملية.
وسيكون من الإطناب وعلى الأرجح غير آمنة.

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




وهناك أسباب كثيرة، ولكن ربما الأكثر أهمية هو أن تلك الوظائف تشجيع الممارسات برمجة آمنة لأنها لا تدعم البيانات المعدة. البيانات المعدة تساعد على منع هجمات حقن SQL.

عند استخدام mysql_*وظائف، وعليك أن تتذكر لتشغيل المعلمات الموفر المستخدم من خلال mysql_real_escape_string(). إذا كنت قد نسيت في مكان واحد فقط أو إذا كنت يحدث للهروب سوى جزء من الدخل، قد تكون قاعدة البيانات الخاصة بك تخضع للهجوم.

باستخدام البيانات المعدة في PDOأو mysqliسوف تجعل من ذلك أن هذا النوع من الاخطاء البرمجية أكثر صعوبة في القيام بها.




لأن (من بين أسباب أخرى) انها أصعب بكثير لضمان إدخال البيانات ومطهرة. إذا كنت تستخدم الاستفسارات parametrized، باعتبارها واحدة يفعل مع شركة تنمية نفط عمان أو mysqli يمكنك تجنب تماما المخاطر.

وكمثال على ذلك، يمكن لبعض واحد واستخدام "enhzflep)؛ انخفاض المستخدمين الطاولة" كاسم المستخدم. ووظائف القديمة تسمح المنفذة من عبارات متعددة في الاستعلام، لذلك شيء من هذا القبيل فتى سيئة يمكن حذف الجدول بأكمله.

إذا كان للمرء أن استخدام PDO من mysqli، فإن اسم المستخدم النهائيين الأمر "enhzflep)؛ انخفاض المستخدمين الطاولة"

انظر bobby-tables.com .




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

أولا، لا تتردد في إنشاء قاعدة البيانات هذه اختبار الخلية (لقد دعوت الإعدادية الألغام):

mysql> create table users(
    -> id int(2) primary key auto_increment,
    -> userid tinytext,
    -> pass tinytext);
Query OK, 0 rows affected (0.05 sec)

mysql> insert into users values(null, 'Fluffeh', 'mypass');
Query OK, 1 row affected (0.04 sec)

mysql> create user 'prepared'@'localhost' identified by 'example';
Query OK, 0 rows affected (0.01 sec)

mysql> grant all privileges on prep.* to 'prepared'@'localhost' with grant option;
Query OK, 0 rows affected (0.00 sec)

مع أن القيام به، ويمكن أن ننتقل إلى رمز PHP لدينا.

دعونا نفترض السيناريو التالي هو عملية التحقق من والمشرف على موقع على شبكة الانترنت (المبسطة ولكن العمل إذا قمت بنسخ واستخدامه للاختبار):

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }

    $database='prep';
    $link=mysql_connect('localhost', 'prepared', 'example');
    mysql_select_db($database) or die( "Unable to select database");

    $sql="select id, userid, pass from users where userid='$user' and pass='$pass'";
    //echo $sql."<br><br>";
    $result=mysql_query($sql);
    $isAdmin=false;
    while ($row = mysql_fetch_assoc($result)) {
        echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
        $isAdmin=true;
        // We have correctly matched the Username and Password
        // Lets give this person full access
    }
    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }
    mysql_close($link);

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

يبدو شرعي بما فيه الكفاية لأول وهلة.

يجب على المستخدم إدخال المستخدم وكلمة السر، والحق؟

رائعة، لا يدخل في ما يلي:

user: bob
pass: somePass

وتقديمه.

الإخراج هو كما يلي:

You could not be verified. Please try again...

ممتاز! العمل كما هو متوقع، يتيح الآن محاولة اسم المستخدم وكلمة المرور الفعلي:

user: Fluffeh
pass: mypass

رائعة حقا!مرحبا-الأطفال دون سن الخامسة كل جولة، رمز التحقق المسير بشكل صحيح. انها مثالية!

حسنا، ليس حقا.دعونا نقول المستخدم هو شخص صغير ذكي. دعونا نقول الشخص هو أنا.

أدخل في ما يلي:

user: bob
pass: n' or 1=1 or 'm=m

والناتج هو:

The check passed. We have a verified admin!

مبروك، أنت سمحت لي فقط لإدخال مدراء المحمية فائقة القسم فقط معي ندخل اسم المستخدم وكلمة مرور كاذبة كاذبة. على محمل الجد، إذا كنت لا تصدقني، إنشاء قاعدة بيانات مع رمز I المقدمة، وتشغيل هذا الرمز PHP - الذي حقا لا يبدو للوهلة التحقق من اسم المستخدم وكلمة المرور بدلا بشكل جيد.

لذلك، في الجواب، وهذا هو السبب الذي يجري صرخ في و.

لذا، دعونا نلقي نظرة على ما حدث من خطأ، ولماذا أنا فقط حصلت على الدخول الى حسابك في سوبر المشرف فقط-الخفافيش الكهف. أخذت تخمين ويفترض أن كنت لا يجري حذرا مع المدخلات وببساطة سلموهم إلى قاعدة البيانات مباشرة. I شيدت المدخلات بطريقة تى اتش تى شأنها تغيير الاستعلام الذي تم تشغيلها بالفعل. لذا، ما كان من المفترض أن يكون، وماذا كان يجري في نهاية المطاف؟

select id, userid, pass from users where userid='$user' and pass='$pass'

هذا الاستعلام، ولكن عندما نستبدل المتغيرات مع المدخلات الفعلية التي كنا نحصل على ما يلي:

select id, userid, pass from users where userid='bob' and pass='n' or 1=1 or 'm=m'

انظر كيف شيدت بلادي "كلمة السر"، بحيث يكون أولا إغلاق اقتباس مفردة حول كلمة السر، ثم إدخال مقارنة جديدة تماما؟ بعد ذلك فقط من أجل السلامة، وأضفت آخر "السلسلة" بحيث الاقتباس واحد سوف تحصل مغلقة كما هو متوقع في رمز كان لدينا أصلا.

ومع ذلك، هذا ليس عن الناس في الصراخ لك الآن، وهذا هو حوالي تبين لكم كيف لجعل الرمز الخاص بك أكثر أمانا.

حسنا، لذلك ما حدث من خطأ وكيف يمكننا إصلاحه؟

هذا هو كلاسيكي هجوم حقن SQL. واحد من أبسط لهذه المسألة. على مقياس من ناقلات الهجوم، وهذا هو طفل مهاجمة دبابة - والفوز.

لذلك، كيف نحمي قسم الادارة المقدس الخاص بك وجعلها جميلة وآمنة؟ فإن أول شيء فعله أن يكون على التوقف عن استخدام تلك القديمة حقا وإهمال mysql_*الوظائف. وأنا أعلم، كنت اتبعت تعليمي وجدت على الانترنت ويعمل، ولكن من العمر، انها قديمة وفي غضون بضع دقائق، لقد كسرت الماضي فقط دون بقدر ما هو كسر العرق.

الآن، لديك خيارات أفضل من استخدام mysqli_ أو شركة تنمية نفط عمان . أنا شخصيا معجب كبير من شركة تنمية نفط عمان، ولذا فإنني سوف تستخدم شركة تنمية نفط عمان في الفترة المتبقية من هذا الجواب. هناك المؤيدة والمعارضة، ولكن شخصيا أجد أن المؤيدة تفوق بكثير يخدع. انها محمولة عبر محركات قاعدة بيانات متعددة - ما إذا كنت تستخدم الخلية أو أوراكل أو أي شيء حول الدموي - فقط عن طريق تغيير سلسلة الاتصال، فإنه لديه كل الميزات الفاخرة نريد الاستخدام وجميلة ونظيفة. أنا أحب نظيفة.

الآن، دعونا نلقي نظرة على هذا الرمز مرة أخرى، وهذه المرة مكتوبة باستخدام كائن PDO:

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }
    $isAdmin=false;

    $database='prep';
    $pdo=new PDO ('mysql:host=localhost;dbname=prep', 'prepared', 'example');
    $sql="select id, userid, pass from users where userid=:user and pass=:password";
    $myPDO = $pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
    if($myPDO->execute(array(':user' => $user, ':password' => $pass)))
    {
        while($row=$myPDO->fetch(PDO::FETCH_ASSOC))
        {
            echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
            $isAdmin=true;
            // We have correctly matched the Username and Password
            // Lets give this person full access
        }
    }

    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

الاختلافات الرئيسية هي أنه لا توجد المزيد من mysql_*الوظائف. انها فعلت كل عبر كائن PDO، ثانيا، أنه يستخدم بيان معد سلفا. الآن، ما هو بيان prepred تسأل؟ انها وسيلة لقول الأمام قاعدة بيانات لتشغيل استعلام، ما الاستعلام هو أننا ذاهبون إلى تشغيل. في هذه الحالة، فإننا نقول للقاعدة البيانات: "مرحبا، انا ذاهب لتشغيل حدد بيان الرغبة الهوية، والمستخدم وتمرير من المستخدمين الجدول حيث معرف المستخدم هو متغير والممر هو أيضا متغير".

ثم، في تنفيذ بيان، نعبر قاعدة البيانات صفيف مع جميع المتغيرات أنها تتوقع الآن.

وكانت النتائج رائعة. يتيح محاكمة اسم المستخدم وكلمة المرور تركيبات من قبل مرة أخرى:

user: bob
pass: somePass

لم يتم التحقق المستخدم. رائع.

كيف حول:

user: Fluffeh
pass: mypass

أوه، أنا فقط حصلت قليلا متحمس، لأنها عملت: تمرير الاختيار. لدينا المشرف التحقق!

الآن، دعونا نحاول البيانات أن الفصل ذكية ستدخل في محاولة لتجاوز نظام التحقق القليل لدينا:

user: bob
pass: n' or 1=1 or 'm=m

هذه المرة، نحصل على ما يلي:

You could not be verified. Please try again...

هذا هو السبب الذي يجري صرخ في حين نشر الأسئلة - انها لأن الناس يمكن أن يرى أن التعليمات البرمجية يمكن تجاوزه ويت حتى المحاولة. من فضلك، لا تستخدم هذا السؤال والإجابة لتحسين التعليمات البرمجية، لجعله أكثر أمنا واستخدام وظائف التي الحالي.

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




تمديد الخلية هي أقدم من ثلاثة وكان الطريق الأصلية التي تستخدم للمطورين للتواصل مع الخلية. ويجري الآن هذا التمديد إهمال لصالح الأخرى اثنين من البدائل بسبب التحسينات التي أدخلت في الإصدارات الأحدث من كلا PHP و MySQL.

  • MySQLi هو "تحسين" تمديد للعمل مع قواعد بيانات MySQL. ويستفيد من الميزات المتوفرة في إصدارات أحدث من خادم MySQL، يعرض على حد سواء وظيفة المنحى واجهة وجوه المنحى للمطور ويقوم عدد قليل من الأشياء أنيق الأخرى.

  • شركة تنمية نفط عمان يوفر API التي تعزز معظم الوظائف التي انتشرت سابقا عبر ملحقات الوصول إلى قاعدة البيانات الرئيسية، أي الخلية، الإنترنت، سكليتي، MSSQL، وما إلى ذلك واجهة تكشف أجسام رفيعة المستوى للمبرمج للعمل مع اتصالات قاعدة البيانات والاستفسارات و مجموعات النتائج، والسائقين على مستوى منخفض أداء الاتصال والتعامل مع مع خادم قاعدة البيانات الموارد. وهناك الكثير من النقاش والعمل يسير في شركة تنمية نفط عمان وانها تعتبر الطريقة المناسبة للعمل مع قواعد البيانات في التعليمات البرمجية الحديثة والمهنية.




أجد الإجابات أعلاه طويلة حقا، لذلك لتلخيص:

تمديد mysqli لديها عدد من المزايا والتحسينات الرئيسية على امتداد الخلية الوجود:

  • واجهة موجهة نحو الكائن
  • دعم البيانات المعدة
  • دعم البيانات المتعددة
  • دعم المعاملات
  • قدرات التصحيح المحسنة
  • دعم الخادم المضمنة

المصدر: نظرة عامة MySQLi

كما هو موضح في جاءت الإجابة أعلاه، بدائل الخلية هي mysqli و(كائنات PHP البيانات) شركة تنمية نفط عمان.

  • API يدعم من جانب الخادم تحضير بيانات: بدعم من MYSQLi وشركة تنمية نفط عمان
  • API يدعم العميل تحضير بيانات: المعتمدة فقط من قبل شركة تنمية نفط عمان
  • API يدعم الإجراءات المخزنة: كل MySQLi وشركة تنمية نفط عمان
  • API يدعم القوائم متعددة وجميع وظائف 4.1+ ماي - بدعم من MySQLi ومعظمهم أيضا من قبل شركة تنمية نفط عمان

وقدم كل من MySQLi وشركة تنمية نفط عمان حيث أدخلت في PHP 5.0، في حين أن الخلية قبل PHP3.0. وهناك نقطة هو أن نلاحظ أن الخلية يتم تضمينها في PHP5.x على الرغم من إهمال في الإصدارات الأحدث.




فمن الممكن لتحديد ما يقرب من جميع mysql_ * الوظائف باستخدام mysqli أو شركة تنمية نفط عمان. مجرد إدراجها على رأس تطبيق PHP القديم الخاص بك، وأنه سوف يعمل على PHP7. بلدي الحل هنا .

<?php

define('MYSQL_LINK', 'dbl');
$GLOBALS[MYSQL_LINK] = null;

function mysql_link($link=null) {
    return ($link === null) ? $GLOBALS[MYSQL_LINK] : $link;
}

function mysql_connect($host, $user, $pass) {
    $GLOBALS[MYSQL_LINK] = mysqli_connect($host, $user, $pass);
    return $GLOBALS[MYSQL_LINK];
}

function mysql_pconnect($host, $user, $pass) {
    return mysql_connect($host, $user, $pass);
}

function mysql_select_db($db, $link=null) {
    $link = mysql_link($link);
    return mysqli_select_db($link, $db);
}

function mysql_close($link=null) {
    $link = mysql_link($link);
    return mysqli_close($link);
}

function mysql_error($link=null) {
    $link = mysql_link($link);
    return mysqli_error($link);
}

function mysql_errno($link=null) {
    $link = mysql_link($link);
    return mysqli_errno($link);
}

function mysql_ping($link=null) {
    $link = mysql_link($link);
    return mysqli_ping($link);
}

function mysql_stat($link=null) {
    $link = mysql_link($link);
    return mysqli_stat($link);
}

function mysql_affected_rows($link=null) {
    $link = mysql_link($link);
    return mysqli_affected_rows($link);
}

function mysql_client_encoding($link=null) {
    $link = mysql_link($link);
    return mysqli_character_set_name($link);
}

function mysql_thread_id($link=null) {
    $link = mysql_link($link);
    return mysqli_thread_id($link);
}

function mysql_escape_string($string) {
    return mysql_real_escape_string($string);
}

function mysql_real_escape_string($string, $link=null) {
    $link = mysql_link($link);
    return mysqli_real_escape_string($link, $string);
}

function mysql_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql);
}

function mysql_unbuffered_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql, MYSQLI_USE_RESULT);
}

function mysql_set_charset($charset, $link=null){
    $link = mysql_link($link);
    return mysqli_set_charset($link, $charset);
}

function mysql_get_host_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_host_info($link);
}

function mysql_get_proto_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_proto_info($link);
}
function mysql_get_server_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_server_info($link);
}

function mysql_info($link=null) {
    $link = mysql_link($link);
    return mysqli_info($link);
}

function mysql_get_client_info() {
    $link = mysql_link();
    return mysqli_get_client_info($link);
}

function mysql_create_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "CREATE DATABASE `$db`");
}

function mysql_drop_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "DROP DATABASE `$db`");
}

function mysql_list_dbs($link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, "SHOW DATABASES");
}

function mysql_list_fields($db, $table, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    $table = str_replace('`', '', mysqli_real_escape_string($link, $table));
    return mysqli_query($link, "SHOW COLUMNS FROM `$db`.`$table`");
}

function mysql_list_tables($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "SHOW TABLES FROM `$db`");
}

function mysql_db_query($db, $sql, $link=null) {
    $link = mysql_link($link);
    mysqli_select_db($link, $db);
    return mysqli_query($link, $sql);
}

function mysql_fetch_row($qlink) {
    return mysqli_fetch_row($qlink);
}

function mysql_fetch_assoc($qlink) {
    return mysqli_fetch_assoc($qlink);
}

function mysql_fetch_array($qlink, $result=MYSQLI_BOTH) {
    return mysqli_fetch_array($qlink, $result);
}

function mysql_fetch_lengths($qlink) {
    return mysqli_fetch_lengths($qlink);
}

function mysql_insert_id($qlink) {
    return mysqli_insert_id($qlink);
}

function mysql_num_rows($qlink) {
    return mysqli_num_rows($qlink);
}

function mysql_num_fields($qlink) {
    return mysqli_num_fields($qlink);
}

function mysql_data_seek($qlink, $row) {
    return mysqli_data_seek($qlink, $row);
}

function mysql_field_seek($qlink, $offset) {
    return mysqli_field_seek($qlink, $offset);
}

function mysql_fetch_object($qlink, $class="stdClass", array $params=null) {
    return ($params === null)
        ? mysqli_fetch_object($qlink, $class)
        : mysqli_fetch_object($qlink, $class, $params);
}

function mysql_db_name($qlink, $row, $field='Database') {
    mysqli_data_seek($qlink, $row);
    $db = mysqli_fetch_assoc($qlink);
    return $db[$field];
}

function mysql_fetch_field($qlink, $offset=null) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    return mysqli_fetch_field($qlink);
}

function mysql_result($qlink, $offset, $field=0) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    $row = mysqli_fetch_array($qlink);
    return (!is_array($row) || !isset($row[$field]))
        ? false
        : $row[$field];
}

function mysql_field_len($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->length : false;
}

function mysql_field_name($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgname) ? $field->name : $field->orgname;
}

function mysql_field_table($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgtable) ? $field->table : $field->orgtable;
}

function mysql_field_type($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->type : false;
}

function mysql_free_result($qlink) {
    try {
        mysqli_free_result($qlink);
    } catch (Exception $e) {
        return false;
    }
    return true;
}



mysql_ * تم استهلاك ظائف (اعتبارا من فب 5.5 ) نظرا لحقيقة أن أفضل الوظائف والهياكل كود وضعت. والحقيقة أن وظيفة تم استهلاكها يعني أن أي جهد أكثر سيتم وضعها في تحسينها من حيث الأداء والأمان، وهو ما يعني أنه أقل دليل على المستقبل .

إذا كنت بحاجة إلى المزيد من الأسباب:

  • mysql_ * وظائف لا تدعم البيانات المعدة.
  • mysql_ * وظائف لا تدعم الربط من المعلمات.
  • mysql_ * وظائف تفتقر إلى وظائف لالبرمجة الشيئية.
  • والقائمة تطول ...