كل شيء بين MongoDB و PHP
المتطلبات
-
خادم MongoDB يعمل على منفذ والذي هو 27017 عادةً. (اكتب
mongod
في موجه الأوامر لتشغيل خادم mongod) -
لغة php مثبّتة إما باستخدام
cgi
أوfpm
مع إضافةMongoDB
(إضافة MongoDB لا توجد مع php بشكلٍ افتراضي). -
مكتبة المُنشئ (Composer) (mongodb/mongodb). نفّذ التعليمة
php composer.phar require "mongodb/mongodb=^1.0.0"
في المجلد الجذر للمشروع لتثبيت مكتبة MongoDB).
إذا تأكدت من المتطلبات يمكنك بعدها الانتقال للخطوة التالية:
-
التحقق من تثبيت php: نفّذ التعليمة
php -v
في موجه الأوامر إذا لم تكن متأكدًا من أنّها مثبّتة لديك وستُرجع مايشبه التالي:
PHP 7.0.6 (cli) (built: Apr 28 2016 14:12:14) ( ZTS ) Copyright (c) 1997-2016 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
-
التحقق من تثبيت MongoDB: وذلك بتنفيذ التعليمة
mongo --version
والتي ستُرجعMongoDB shell version: 3.2.6
. -
التحقق من تثبيت المُنشئ: وذلك بتنفيذ التعليمة
php composer.phar --version
التي ستُرجعComposer version 1.2-dev (3d09c17b489cd29a0c0b3b11e731987e7097797d) 2016-08-30 16:12:39
.
الاتصال من php إلى MongoDB
<?php // يجب أن يشير هذا المسار إلى المحمِّل التلقائي للمُنشئ من المكان حيث يجب أن تُحمَّل مكتبة MongoDB require 'vendor/autoload.php'; // استخدام اسم مستخدم وكلمة مرور مخصَّصَين try { $mongo = new MongoDB\Client('mongodb://username:password@localhost:27017'); print_r($mongo->listDatabases()); } catch (Exception $e) { echo $e->getMessage(); } // استخدام إعدادات افتراضية try { $mongo = new MongoDB\Client('mongodb://localhost:27017'); print_r($mongo->listDatabases()); } catch (Exception $e) { echo $e->getMessage(); }
ستتصل الشيفرة السابقة باستخدام مكتبة المُنشئ MongoDB (mongodb/mongodb)
المضمّنة بالشكل vendor/autoload.php
للاتصال بخادم MongoDB? الذي يعمل على المنفذ 27017. ستتصل إذا كان كل شيء صحيحًا وتعرض قائمة مصفوفة أما إذا حدث استثناء بالاتصال إلى خادم MongoDB? ستُطبع رسالة.
الإنشاء (الإضافة) في MongoDB
يستخدم MongoDB المجموعة (collection) بدلًا من الجداول كما هو الحال في SQL.
نستخدم في الشيفرة التالية الكائن $mongo
لاختيار قاعدة البيانات والمجموعة، إذا لم توجد قاعدة البيانات (demo في مثالنا) والمجموعة (beers في مثالنا) سينشئهما MongoDB تلقائيًا.
ونستخدم $collection
لإضافة ملف في MongoDB، يشبه الملف السطر في SQL، وكل ملف مُنشئ له معرِّف فريد.
<?php $collection = $mongo->demo->beers; $result = $collection->insertOne( [ 'name' => 'Hinterland', 'brewery' => 'BrewDog' ] ); echo "Inserted with Object ID '{$result->getInsertedId()}'";
استخدمنا في المثال الكائن $mongo
المستخدم سابقًا في شيفرة الاتصال من php إلى MongoDB، يستخدم MongoDB نوع تنسيق البيانات JSON
لذا سنستخدم في php المصفوفة لإضافة بيانات إلى MongoDB، ستحوّل مكتبة mongo من المصفوفة إلى JSON
وبالعكس، لكل ملف في MongoDB معرّف خاص به يمكننا الحصول عليه عند الإضافة باستخدام الشيفرة:
$result->getInsertedId();
القراءة (البحث) في MongoDB
نستخدم التابع find()
للاستعلام عن السجلات، ويكون المعامل مصفوفة تتضمن زوج قيمة مفتاح نريد إيجاده، تُرجَع النتيجة على شكل مصفوفة ونستخدم foreach
لفلترة المفاتيح المطلوبة.
$result = $collection->find( [ 'name' => 'Hinterland', 'brewery' => 'BrewDog' ] ); foreach ($result as $entry) { echo $entry['_id'], ': ', $entry['name'], "\n"; } ?>
مثال آخر للبحث عن عدة مستخدمين اسمهم "Mike":
$filter = ['name' => 'Mike']; $query = new \MongoDB\Driver\Query($filter); $cursor = $manager->executeQuery('database_name.collection_name', $query); foreach ($cursor as $doc) { var_dump($doc); }
ونستخدم التابع findOne()
للحصول على ملف واحد، مثال للبحث عن مستخدم واحد فقط له معرِّف محدد:
$options = ['limit' => 1]; $filter = ['_id' => new \MongoDB\BSON\ObjectID('578ff7c3648c940e008b457a')]; $query = new \MongoDB\Driver\Query($filter, $options); $cursor = $manager->executeQuery('database_name.collection_name', $query); $cursorArray = $cursor->toArray(); if(isset($cursorArray[0])) { var_dump($cursorArray[0]); }
الحذف في MongoDB
تعيد الشيفرة التالية 1 في حال تم الحذف بنجاح وتعيد 0 في حال الفشل.
<?php $result = $collection->drop( [ 'name' => 'Hinterland'] ); print_r($result->ok); ?>
يمكنك الاطلاع في التوثيق الرسمي من MongoDB على العديد من التوابع التي يمكن تطبيقها على $collection
.
الاتصال مع MongoDB وإجراء العمليات
إنشاء اتصال MongoDB يمكنك استخدامه للاستعلام منه لاحقًا:
$manager = new \MongoDB\Driver\Manager('mongodb://localhost:27017');
ستتعلم في المثال التالي كيفية الاستعلام باستخدام كائن الاتصال، تُغلق هذه الإضافة الاتصال بشكلٍ تلقائي لذا ليس من الضروري إغلاقه يدويًا.
إضافة ملف
مثال لإضافة ملف:
$document = [ 'name' => 'John', 'active' => true, 'info' => ['genre' => 'male', 'age' => 30] ]; $bulk = new \MongoDB\Driver\BulkWrite; $_id1 = $bulk->insert($document); $result = $manager->executeBulkWrite('database_name.collection_name', $bulk);
تحديث ملف
مثال لتحديث كل الملفات التي اسمها "John":
$filter = ['name' => 'John']; $document = ['name' => 'Mike']; $bulk = new \MongoDB\Driver\BulkWrite; $bulk->update( $filter, $document, ['multi' => true] ); $result = $manager->executeBulkWrite('database_name.collection_name', $bulk);
حذف ملف
مثال لحذف كل الملفات التي اسمها "Peter":
$bulk = new \MongoDB\Driver\BulkWrite; $filter = ['name' => 'Peter']; $bulk->delete($filter); $result = $manager->executeBulkWrite('database_name.collection_name', $bulk);
استخدام Redis مع PHP
الاتصال إلى كائن Redis
بفرض أنّ الخادم الافتراضي يعمل على المضيف المحلي مع المنفذ الافتراضي?، عندها يكون أمر الاتصال إلى خادم Redis هذا:
$redis = new Redis(); $redis->connect('127.0.0.1', 6379);
تثبيت PHP Redis
على نظام التشغيل أبونتو
نثبّت أولًا خادم Redis:
sudo apt install redis-server
ثم نثبّت وحدة PHP:
sudo apt install php-redis
ثم نعيد تشغيل خادم Apache:
sudo service apache2 restart
تنفيذ أوامر Redis في PHP
توفر وحدة Redis PHP
الوصول إلى نفس الأوامر كعميل Redis CLI
لذا يمكن استخدامها بشكلٍ مباشر. الصياغة كالتالي:
// إنشاء مفتاحين جديدين $redis->set('mykey-1', 123); $redis->set('mykey-2', 'abcd'); // الحصول على مفتاح واحد // 123 // الحصول على كل المفاتيح التي بدايتها 'my-key-' var_dump($redis->keys('mykey-*')); // '123', 'abcd'
الإضافة PDO في PHP
تسمح الإضافة PDO للمطورين بالاتصال بأنواع مختلفة كثيرة من قواعد البيانات وتنفيذ استعلامات مختلفة عليها بطريقة موحدة كائنية التوجه.
منع حقن SQL باستخدام استعلامات ذات وسائط
حقن SQL هو هجوم يسمح لمستخدم ضار بتعديل استعلام SQL بإضافة أوامر غير مرغوب بها إلى الاستعلام، مثلًا الاستعلام التالي معرَّض للخطر:
$sql = 'SELECT name, email, user_level FROM users WHERE userID = ' . $_GET['user']; $conn->query($sql);
تسمح هذه الشيفرة لأي مستخدم بالتعديل في قاعدة البيانات بشكلٍ أساسي كما يرغب، مثلًا بفرض لدينا سلسلة الاستعلام التالية:
page.php?user=0;%20TRUNCATE%20TABLE%20users;
تجعل هذه السلسلة الاستعلام يكون بالشكل:
SELECT name, email, user_level FROM users WHERE userID = 0; TRUNCATE TABLE users;
يعدّ هذا المثال مبالغًا فيه (معظم هجمات حقن SQL لا تهدف إلى حذف البيانات ولا تدعم معظم دوال تنفيذ استعلام PHP الاستعلام المتعدد)، هذا مثال على إمكانية جعل هجوم حقن SQL ممكنًا من خلال التجميع غير المتقن للاستعلام، لسوء الحظ فإنَّ مثل هذه الهجمات شائع جدًا وفعال بشكلٍ كبير بسبب المبرمجين الذين يفشلون في اتخاذ الاحتياطات المناسبة لحماية بياناتهم.
الحل المناسب لمنع حدوث حقن SQL هو تعليمات التحضير (prepared statements)، فنستخدم عنصرًا بديلًا (placeholder) بدلًا من دمج بيانات المستخدم بشكلٍ مباشر مع الاستعلام، ثم تُرسَل البيانات بشكلٍ منفصل وبالتالي لا توجد فرصة لمحرك SQL أن يحتار بخصوص بيانات المستخدم. ولاحظ أنّ إضافة PHP MySQLi
تدعم أيضًا تعليمات التحضير.
تدعم PDO نوعين من العناصر البديلة (لا يمكن استخدام العناصر البديلة لتسمية الأعمدة أو الجداول وإنما فقط للقيم):
1- العناصر البديلة المسماة، نقطتان (:) يتبعهما اسم واضح مثل (:user).
// استخدام العناصر البديلة المسماة $sql = 'SELECT name, email, user_level FROM users WHERE userID = :user'; $prep = $conn->prepare($sql); // مصفوفة ترابطية $prep->execute(['user' => $_GET['user']]); $result = $prep->fetchAll();
2- العناصر البديلة الموضعية التقليدية في SQL تُمثَّل بالعلامة ?
.
// استخدام العناصر البديلة الممثَّلة بعلامة الاستفهام $sql = 'SELECT name, user_level FROM users WHERE userID = ? AND user_level = ?'; $prep = $conn->prepare($sql); // مصفوفة مفهرسة $prep->execute([$_GET['user'], $_GET['user_level']]); $result = $prep->fetchAll();
يجب أن تعلم أنّه إذا احتجت إلى تغيير اسم عمود أو جدول بشكلٍ ديناميكي فإنّ هذه ممارسة سيئة وعلى مسؤوليتك الأمنية الخاصة، مع أنّه يمكنك القيام بذلك عن طريق دمج السلاسل النصية. إحدى الطرق لتحسين أمان مثل هذه الاستعلامات هي تعيين جدول فيه القيم المسموح بها ومقارنة القيمة التي تريدها للدمج مع هذا الجدول.
يجب أن تعلم أنّه من المهم ضبط ترميز محارف الاتصال ليكون DSN (Data Source Name) فقط، وإلا قد يكون تطبيقك معرّضًا لثغرة ضعيفة. إنّ ضبط ترميز المحارف ليكون DSN غير متاح في الإصدارات PDO السابقة للإصدار 5.3.6 لذا فالخيار الوحيد هو ضبط سمة الاتصال PDO::ATTR_EMULATE_PREPARES
لتكون false
مباشرةً بعد إنشائه.
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
ستؤدي هذه الشيفرة إلى استخدام PDO لتعليمات التحضير الأساسية الموجودة في DBMS
(Database Management Systems) بدلًا من محاكاتها فقط، وانتبه إلى أنّ PDO ستتراجع ببطء لمحاكاة التعليمات التي لا تستطيع MySQL
تحضيرها محليًّا، هذه العبارات موجودة في التوثيق.
اتصال PDO الأساسي والاسترجاع
بدءًا من الإصدار PHP 5.0 أصبحت PDO متاحة كطبقة وصول إلى قاعدة البيانات، وهي لا تعرف قاعدة البيانات، ستعمل الشيفرة في مثال الاتصال التالي لأي من قواعد البيانات المدعومة ببساطة عن طريق تغيير الترميز DSN.
// (1) $dsn = "mysql:host=localhost;dbname=testdb;charset=utf8"; // (2) $username = "user"; $password = "pass"; $db = new PDO($dsn, $username, $password); // ضبط PDO لرمي استثناء إذا أُدخِل استعلام غير صحيح $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // تحضير تعليمة التنفيذ مع عنصر بديل مفرد $query = "SELECT * FROM users WHERE class = ?"; $statement = $db->prepare($query); // إنشاء بعض المعاملات لملء العناصر البديلة وتنفيذ التعليمة $parameters = [ "221B" ]; $statement->execute($parameters); // التكرار على كل سجل كمصفوفة ترابطية while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { do_stuff($row); }
ننشئ في الموضع (1) مقبضًا لقاعدة البيانات ونستخدم MySQL
(اتصال باستخدام مقبس محلي) يوضّح الموضع (2) أنّه يمكنك استخدام MySQL
(اتصال عبر الشبكة، يمكنك تحديد المنفذ أيضًا إذا أردت) باستخدام الشيفرة:
$dsn = "mysql:host=127.0.0.1;port=3306;dbname=testdb;charset=utf8";
أو استخدام Postgres
:
$dsn = "pgsql:host=localhost;port=5432;dbname=testdb;";
أو حتى SQLite
:
$dsn = "sqlite:/path/to/database"
تنشئ الدالة prepare كائنًا من الصنف PDOStatement
من سلسلة الاستعلام، تجري عمليات تنفيذ الاستعلام واسترجاع النتائج على هذا الكائن المُرجَع. في حال الفشل إما تعيد الدالة false
أو ترمي استثناءً (بالاعتماد على كيفية ضبط إعدادات اتصال PDO).
عمليات قاعدة البيانات مع PDO
تضمن عمليات (transactions) قاعدة البيانات أنَّ مجموعة التغييرات على قاعدة البيانات ستصبح دائمة فقط إذا نجحت كل التعليمات، يمكن التقاط أي فشل في الاستعلام أو الشيفرة خلال عملية ما ثم يكون لديك خيار التراجع (roll back) عن التغييرات التي حاولت القيام بها. توفر PDO توابع بسيطة لعمليات البدء وحفظ التغييرات (committing) والتراجع.
$pdo = new PDO( $dsn, $username, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION) ); try { $statement = $pdo->prepare("UPDATE user SET name = :name"); $pdo->beginTransaction(); $statement->execute(["name"=>'Bob']); $statement->execute(["name"=>'Joe']); $pdo->commit(); } catch (\Exception $e) { if ($pdo->inTransaction()) { $pdo->rollback(); // إذا وصلنا إلى هنا فإنَّ التحديثين ليسا في قاعدة البيانات } throw $e; }
تكون أي تغييرات تُجرى على البيانات خلال العملية مرئية للاتصال النشط، ستُرجع تعليمات SELECT
التغييرات المُعدَّلة حتى لو لم تُحفظ في قاعدة البيانات بعد.
مثال عملي لاستخدام العمليات مع PDO
نعرض لك في الفقرة التالية مثال عملي من العالم الحقيقي حيث يضمن استخدام العمليات اتساق قاعدة البيانات.
تخيل بأنّك تبني عربة تسوق لموقع تجارة الكترونية وقررت أن تحتفظ بطلبات العملاء في جدولين من قاعدة البيانات، اسم الجدول الأول orders
يعبر عن الطلبات وحقوله هي order_id
، name
، address
، telephone
وcreated_at
، واسم الجدول الثاني orders_products
يحوي منتجات الطلبات وحقوله هي order_id
،product_id
وquantity
، أي يحتوي الجدول الأول على بيانات وصفية للطلب والجدول الثاني على المنتجات الفعلية التي طلبها العملاء.
إضافة طلب جديد إلى قاعدة البيانات
تحتاج لإضافة طلب جديد إلى قاعدة البيانات إلى أمرين، الأول هو إنشاء سجل جديد (INSERT) في الجدول orders
يحتوي على البيانات الوصفية للطلب (الاسم والعنوان وغير ذلك)، والثاني هو إنشاء سجل جديد في الجدول orders_products
لكل منتج من المنتجات الموجودة في قائمة الطلب. يمكنك القيام بذلك باستخدام الشيفرة التالية:
// إضافة البيانات الوصفية للطلب في قاعدة البيانات $preparedStatement = $db->prepare( 'INSERT INTO `orders` (`name`, `address`, `telephone`, `created_at`) VALUES (:name, :address, :telephone, :created_at)' ); $preparedStatement->execute([ 'name' => $name, 'address' => $address, 'telephone' => $telephone, 'created_at' => time(), ]); // الحصول على `order_id` المولَّد $orderId = $db->lastInsertId(); // بناء استعلام لإضافة منتجات الطلب $insertProductsQuery = 'INSERT INTO `orders_products` (`order_id`, `product_id`, `quantity`) VALUES'; $count = 0; foreach ( $products as $productId => $quantity ) { $insertProductsQuery .= ' (:order_id' . $count . ', :product_id' . $count . ', :quantity' . $count . ')'; $insertProductsParams['order_id' . $count] = $orderId; $insertProductsParams['product_id' . $count] = $productId; $insertProductsParams['quantity' . $count] = $quantity; ++$count; } // إضافة المنتجات المُضمَّنة في الطلب إلى قاعدة البيانات $preparedStatement = $db->prepare($insertProductsQuery); $preparedStatement->execute($insertProductsParams);
ستعمل هذه الشيفرة بشكلٍ رائع على إضافة طلب جديد إلى قاعدة البيانات حتى يحدث شيء ما غير متوقع ولسببٍ ما يفشل استعلام INSERT
الثاني وعندها سيكون لديك طلب جديد في الجدول orders
بدون وجود منتجات مرتبطة فيه من الجدول orders_products
. لحسن الحظ يمكن إصلاح هذا ببساطة بجعل الاستعلامين في عملية قاعدة بيانات واحدة.
إضافة طلب جديد إلى قاعدة البيانات مع عملية
كل ماعليك فعله لبدء عملية باستخدام PDO هو استدعاء التابع beginTransaction
قبل تنفيذ أي استعلامات على قاعدة البيانات، ثم تجري التغييرات التي تريدها بتنفيذ استعلامات INSERT
و/أو UPDATE
وفي النهاية تستدعي التابع commit
للكائن لجعل التغييرات دائمة، قبل استدعاء التابع commit
فإنّ كل التغييرات التي تجريها على بياناتك غير دائمة ويمكن التراجع عنها بسهولة باستدعاء التابع rollback
للكائن PDO.
نوضح في المثال التالي استخدام العمليات لإضافة طلب جديد في قاعدة البيانات مع ضمان اتساق البيانات في نفس الوقت، ستُرجع جميع التغييرات إذا فشل أحد الاستعلامين، نستخدم في هذا المثال MySQL
لكن يمكن تطبيقه على أي قاعدة بيانات تدعم العمليات.
$db = new PDO('mysql:host=' . $host . ';dbname=' . $dbname . ';charset=utf8', $username,$password); // تأكد من أنّ PDO سترمي استثناءً في حالة الخطأ لجعل عملية معالجة الخطأ أسهل $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); try { // بدءًا من هذه النقطة وحتى تُحفظ العملية يمكن التراجع عن كل تغيير في قاعدة البيانات $db->beginTransaction(); // إضافة البيانات الوصفية للطلب في قاعدة البيانات $preparedStatement = $db->prepare( 'INSERT INTO `orders` (`order_id`, `name`, `address`, `created_at`) VALUES (:name, :address, :telephone, :created_at)' ); $preparedStatement->execute([ 'name' => $name, 'address' => $address, 'telephone' => $telephone, 'created_at' => time(), ]); // الحصول على `order_id` المولَّد $orderId = $db->lastInsertId(); // بناء الاستعلام لإضافة منتجات الطلب $insertProductsQuery = 'INSERT INTO `orders_products` (`order_id`, `product_id`, `quantity`) VALUES'; $count = 0; foreach ( $products as $productId => $quantity ) { $insertProductsQuery .= ' (:order_id' . $count . ', :product_id' . $count . ', :quantity' . $count . ')'; $insertProductsParams['order_id' . $count] = $orderId; $insertProductsParams['product_id' . $count] = $productId; $insertProductsParams['quantity' . $count] = $quantity; ++$count; } // إضافة منتجات الطلب إلى قاعدة البيانات $preparedStatement = $db->prepare($insertProductsQuery); $preparedStatement->execute($insertProductsParams); // جعل تغييرات قاعدة البيانات دائمة $db->commit(); } catch ( PDOException $e ) { // فشل إضافة الطلب في قاعدة البيانات لذا نتراجع عن التغييرات $db->rollback(); throw $e; }
الاتصال بخادم MySQL/MariaDB باستخدام PDO
يوجد طريقتين للاتصال بخادم MySQL/MariaDB وفقًا للبنية التحتية.
الاتصال (TCP/IP) المعياري
$dsn = 'mysql:dbname=demo;host=server;port=3306;charset=utf8'; $connection = new \PDO($dsn, $username, $password); // رمي استثناءات عند حدوث خطأ SQL $connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); // منع محاكاة تعليمات التحضير $connection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
يجب أن تعطّل المحاكاة بشكلٍ واضح لأنّ PDO صممت لتكون متكاملة مع إصدارات خادم MySQL
الأقدم (التي لا تدعم تعليمات التحضير)، وإلا ستخسر فوائد منع الحقن (injection prevention) المضافة التي يوفرها عادةً استخدام تعليمات التحضير.
سلوك معالجة الخطأ الافتراضي هو حل وسط آخر، إذا لم يُعَدّ فلن تظهر PDO أي مؤشرات إلى أخطاء SQL
، يُنصح بضبطه إلى الإعداد "exception mode" (نمط الاستثناء) لأنّه يمنحك وظائف إضافية عند كتابة تعابير ثبات مجردة (مثلًا عندما يكون لديك استثناء عند انتهاك القيد UNIQUE
).
اتصال المقبس
$dsn = 'mysql:unix_socket=/tmp/mysql.sock;dbname=demo;charset=utf8'; $connection = new \PDO($dsn, $username, $password); // رمي استثناءات عند حدوث خطأ SQL $connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); // منع محاكاة تعليمات التحضير $connection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
في الأنظمة مثل unix
إذا كان اسم المضيف 'localhost' يتم الاتصال بالخادم عبر مقبس المجال (domain socket).
الحصول على عدد الأسطر المتأثرة بالاستعلام باستخدام PDO
نبدأ بالمتغير $db
والذي هو نسخة من الصنف PDO. نريد غالبًا بعد تنفيذ الاستعلام أن نحدد عدد الأسطر المتأثرة بهذا الاستعلام عندها نستخدم التابع rowCount()
من الصنف PDOStatement
.
$query = $db->query("DELETE FROM table WHERE name = 'John'"); $count = $query->rowCount(); echo "Deleted $count rows named John";
ملاحظة: يُستخدم هذا التابع لتحديد عدد الأسطر المتأثرة بتعليمات INSERT
وDELETE
وUPDATE
فقط، بالرغم من أنّ هذا التابع قد يعمل بشكلٍ صحيح مع تعليمات SELECT
أيضًا إلا أنّه غير متسق مع جميع قواعد البيانات.
PDO::lastInsertId()
يمكنك الحصول على قيمة المعرِّف (ID) المتزايدة تلقائيًا للسطر الذي أضفته إلى جدول قاعدة البيانات باستخدام التابع lastInsertId()
.
// فتح اتصال أساسي (MySQL) $host = 'localhost'; $database = 'foo'; $user = 'root' $password = ''; $dsn = "mysql:host=$host;dbname=$database;charset=utf8"; $pdo = new PDO($dsn, $user, $password); // إضافة سطر جديد في الجدول الافتراضي 'foo_user' $query = "INSERT INTO foo_user(pseudo, email) VALUES ('anonymous', 'anonymous@example.com')"; $query_success = $pdo->query($query); // استعادة المعرِّف للسطر الأخير المدخل $id = $pdo->lastInsertId(); // القيمة المعادة هي عدد صحيح
لدينا الكلمة المفتاحية RETURNING
في قواعد البيانات postgresql
وoracle
والتي تُرجع الأعمدة المحددة للأسطر المُدخلة/المعدّلة حاليًا. إليك مثال لإضافة سطر جديد واحد:
// فتح اتصال أساسي (PGSQL) $host = 'localhost'; $database = 'foo'; $user = 'root' $password = ''; $dsn = "pgsql:host=$host;dbname=$database;charset=utf8"; $pdo = new PDO($dsn, $user, $password); // إضافة سطر جديد في الجدول الافتراضي 'foo_user' $query = "INSERT INTO foo_user(pseudo, email) VALUES ('anonymous', 'anonymous@example.com') RETURNING id"; $statement = $pdo->query($query); // استعادة المعرِّف للسطر الأخير المدخل $id = $statement->fetchColumn();
استخدام الإضافة SQLSRV في PHP
استعادة رسائل الخطأ
من المهم جلب رسالة (أو رسائل) الخطأ المُرجعة من قِبل المُشغّل عند حدوث خطأ ما وذلك لمعرفة سبب المشكلة، الصيغة هي:
sqlsrv_errors([int $errorsOrWarnings]);
تُرجع هذه الشيفرة مصفوفة مع مفتاح ووصف.
المفتاح | الوصف |
---|---|
SQLSTATE | حالة خادم SQL/ مشغّل OBDC |
الشيفرة | SQL Server شيفرة خطأ |
الرسالة | وصف الخطأ |
من الشائع استخدام الدالة السابقة كالتالي:
$brokenQuery = "SELECT BadColumnName FROM Table_1"; $stmt = sqlsrv_query($conn, $brokenQuery); if ($stmt === false) { if (($errors = sqlsrv_errors()) != null) { foreach ($errors as $error) { echo "SQLSTATE: ".$error['SQLSTATE']."<br />"; echo "code: ".$error['code']."<br />"; echo "message: ".$error['message']."<br />"; } } }
جلب نتائج الاستعلام
يوجد 3 طرق أساسية لجلب النتائج من استعلام:
- sqlsrv_fetch_array()
تعيد هذه الدالة السطر التالي كمصفوفة.
$stmt = sqlsrv_query($conn, $query); while($row = sqlsrv_fetch_array($stmt)) { echo $row[0]; $var = $row["name"]; //... }
لهذه الدالة معامل ثاني اختياري لجلب أنواع مختلفة من المصفوفات، يمكن أن يكون SQLSRV_FETCH_ASSOC
أو SQLSRV_FETCH_NUMERIC
أو SQLSRV_FETCH_BOTH
(القيمة الافتراضية) ويعيد مصفوفة ترابطية، عددية، أو مصفوفة ترابطية وعددية على الترتيب.
- sqlsrv_fetch_object()
تعيد هذه الدالة السطر التالي ككائن.
$stmt = sqlsrv_query($conn, $query); while($obj = sqlsrv_fetch_object($stmt)) { // أسماء خاصيات الكائن هي أسماء حقول الاستعلام echo $obj->field; //... }
- sqlsrv_fetch()
تجعل هذه الدالة السطر التالي متاحًا للقراءة.
$stmt = sqlsrv_query($conn, $query); while(sqlsrv_fetch($stmt) === true) { // الحصول على الحقل الأول $foo = sqlsrv_get_field($stmt, 0); }
إنشاء اتصال
// اسم الخادم/النسخة، متضمنًا رقم منفذ اختياري (الافتراضي 1433) $dbServer = "localhost,1234"; // اسم قاعدة البيانات $dbName = "db001"; // اسم المستخدم $dbUser = "user"; // كلمة مرور قاعدة البيانات لهذا المستخدم $dbPassword = "password"; $connectionInfo = array( "Database" => $dbName, "UID" => $dbUser, "PWD" => $dbPassword ); $conn = sqlsrv_connect($dbServer, $connectionInfo);
للإضافة SQLSRV أيضًا مشغّل PDO. للاتصال باستخدام PDO:
$conn = new PDO("sqlsrv:Server=localhost,1234;Database=db001", $dbUser, $dbPassword);
كتابة استعلام بسيط
// إنشاء اتصال $conn = sqlsrv_connect($dbServer, $connectionInfo); $query = "SELECT * FROM [table]"; $stmt = sqlsrv_query($conn, $query);
ملاحظة: نستخدم الأقواس المربعة []
للهرب من الكلمة المحجوزة table
، وتعمل نفس عمل علامة الاقتباس المائلة ` في MySQL.
استدعاء إجراء مخزن (Stored Procedure)
لاستدعاء إجراء مخزن على الخادم:
// المعاملات '?' تتضمن معاملات خرج $query = "{call [dbo].[myStoredProcedure](?,?,?)}"; $params = array( array($name, SQLSRV_PARAM_IN), array($age, SQLSRV_PARAM_IN), // يجب أن يكون المتغير $count معرّف مسبقًا array($count, SQLSRV_PARAM_OUT, SQLSRV_PHPTYPE_INT) ); $result = sqlsrv_query($conn, $query, $params);
كتابة استعلام ذو معاملات
$conn = sqlsrv_connect($dbServer, $connectionInfo); $query = "SELECT * FROM [users] WHERE [name] = ? AND [password] = ?"; $params = array("joebloggs", "pa55w0rd"); $stmt = sqlsrv_query($conn, $query, $params);
إذا كنت تخطط لاستخدام نفس تعليمة الاستعلام أكثر من مرة مع معاملات مختلفة فيمكنك تحقيق ذلك باستخدام الدوال sqlsrv_prepare()
وsqlsrv_execute()
كما في الشيفرة التالية:
$cart = array( "apple" => 3, "banana" => 1, "chocolate" => 2 ); $query = "INSERT INTO [order_items]([item], [quantity]) VALUES(?,?)"; // المتغيرات هي معاملات يجب تمريرها بالمرجع $params = array(&$item, &$qty); $stmt = sqlsrv_prepare($conn, $query, $params); foreach($cart as $item => $qty){ if(sqlsrv_execute($stmt) === FALSE) { die(print_r(sqlsrv_errors(), true)); } }
ترجمة -وبتصرف- للفصول [PDO - Using MongoDB - mongo-php - Using Redis with PHP - Using SQLSRV] من كتاب PHP Notes for Professionals book
اقرأ أيضًا
- المقال التالي: كيفية إرسال بريد إلكتروني في PHP
- المقال السابق: إضافة PHP MySQLi ونظام إدارة قواعد البيانات SQLite3
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.