الجلسات
خيارات session_start()
يمكننا تمرير مصفوفة من خيارات الملف php.ini المعتمدة على الجلسة (session) إلى الدالة session_start
، مثال:
<?php if (version_compare(PHP_VERSION, '7.0.0') >= 0) { // php >= 7 session_start([ 'cache_limiter' => 'private', 'read_and_close' => true, ]); } else { // php < 7 session_start(); } ?>
تقدّم أيضًا هذه الميزة إعداد php.ini
جديد يسمى lazy_write
قيمته الافتراضية true
ويعني أن بيانات الجلسة يُعاد كتابتها فقط إذا تغيرت.
قفل الجلسة
تكتب PHP بيانات الجلسة في ملف موجود على الخادم، عندما يُرسَل طلب لبدء الجلسة باستخدام session_start()
إلى سكربت PHP تقفل PHP ملف الجلسة لمنع/انتظار طلبات أخرى قادمة لنفس session_id
للمتابعة وبسبب ذلك ستبقى الطلبات الأخرى عالقة عند session_start()
حتى يُلغى قفل ملف الجلسة.
يبقى ملف الجلسة مقفلًا حتى ينتهي السكربت أو تُغلق الجلسة يدويًا، لتجنب هذه الحالة أي تجنب منع تعطيل عدة طلبات يمكننا أن نبدأ الجلسة ونغلقها مما سيحرر القفل من ملف الجلسة ويسمح بمتابعة الطلبات الباقية.
// php < 7.0 // بدء الجلسة session_start(); // كتابة بيانات في ملف الجلسة $_SESSION['id'] = 123; // عندها يُقفل ملف الجلسة لذا تتعطل الطلبات // إغلاق الجلسة وتحرير القفل session_write_close();
قد تتساءل الآن كيف ستُقرأ قيم الجلسة إذا كانت الجلسة مغلقة؟ تبقى الجلسة متاحة حتى بعد إغلاقها لذا بإمكاننا قراءة بياناتها.
echo $_SESSION['id']; // 123
يتوفر بدءًا من الإصدار php 7.0 خيارات الجلسة read_only
وread_write
وlazy_write
لذا من الممكن ألا نستخدم session_write_close()
.
معالجة بيانات الجلسة
إنّ المتغير $_SESSION
عبارة عن مصفوفة وبإمكانك استعادتها أو معالجتها مثل أي مصفوفة عادية.
<?php // بدء الجلسة session_start(); // تخزين قيمة في الجلسة $_SESSION['id'] = 342; // استخدام تقليدي لقيم جلسة ربما قد ضُبطت في جلسة سابقة if(!isset($_SESSION["login"])) { echo "Please login first"; exit; } // login يمكننا الآن أن نستخدم $user = $_SESSION["login"]; // PHP 7 في Null الحصول على قيمة من بيانات الجلسة أو القيمة الافتراضية باستخدام عامل تجميع $name = $_SESSION['name'] ?? 'Anonymous';
لاحظ أنّه إذا خزّنت كائن في الجلسة فيمكنك استعادته بأمان إذا كان لديك محمّل تلقائي للصنف أو إذا كنت قد حمّلت الصنف مسبقًا، وإلا سيخرج الكائن كالنوع __PHP_Incomplete_Class
مما قد يسبب الأعطال لاحقًا.
تحذير: يمكن أن تتعرض بيانات الجلسة لهجوم اختطاف الجلسة (session hijacking) وهذا موضّح في كتاب أمن PHP المتقدم: من مبادئ أمن التطبيق إلى تنفيذ حماية xss - الفصل السابع: منع هجوم اختطاف الجلسة لذا يُنصح بعدم تخزين أي معلومات شخصية في المصفوفة $_SESSION
وخاصةً أرقام بطاقات الائتمان والمعرّفات الحكومية وكلمات المرور إنما يمكن تخزين المعلومات الأقل خطرًا مثل الأسماء وعناوين البريد الإلكتروني وأرقام الهاتف وغيرها مما يسمح للمخترق بانتحال شخصية مستخدم شرعي. كقاعدة عامة استخدم الجلسة لتخزين المعلومات الشخصية قليلة الأهمية.
تدمير كامل الجلسة
يمكنك استخدام الدالة session_destroy()
لتدمير الجلسة، بفرض لدينا الجلسة التالية:
Array([firstname] => Jon, [id] => 123)
ابدأ الجلسة أولًا بعدها يمكنك حذف كل القيم الموجودة في المتغير ذي النطاق العام العالي SESSION
، إذا أهملت هذا الحذف فإنّ كل المتغيرات العامة المخزنة في المتغير SESSION
ستبقى موجودة حتى لو دُمِّرت الجلسة.
session_start(); $_SESSION = array(); // إذا كنت ترغب في تدمير الجلسة يجب حذف ملف ارتباط الجلسة أيضًا // الشيفرة التالية ستُدمر الجلسة وليس فقط بياناتها if (ini_get("session.use_cookies")) { $params = session_get_cookie_params(); setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"] ); } // يمكنك الآن تدمير الجلسة session_destroy();
إنّ استخدام session_destroy()
مختلف عن استخدام $_SESSION = array();
التي ستزيل كل القيم الموجودة في المتغير ذي النطاق العام العالي SESSION
ولن تدمر نسخة الجلسة المخزّنة الفعلية.
ملاحظة: نستخدم $_SESSION = array();
بدلًا من session_unset()
لأنّ توثيق PHP ينص على أنّ استخدام session_unset()
فقط للشيفرة القديمة المهملة التي لا تستخدم $_SESSION
.
بدء جلسة آمنة دون أخطاء
يواجه العديد من المطورين هذه المشكلة عند عملهم على مشاريع كبيرة خاصةً إذا كانوا يعملوا على إضافات أو مكونات لنظام إدارة محتوى مثلًا، عندها فإنّ الحل لبدء جلسة آمنة يكون أولًا في التحقق من أنّ إصدار PHP يغطي كل الإصدارات ثمّ التحقق من بداية الجلسة. إذا لم توجد الجلسة عندها يمكن بدء الجلسة بأمان وإذا وجدت الجلسة لا يحدث أي شيء.
if (version_compare(PHP_VERSION, '7.0.0') >= 0) { if(session_status() == PHP_SESSION_NONE) { session_start(array( 'cache_limiter' => 'private', 'read_and_close' => true, )); } } else if (version_compare(PHP_VERSION, '5.4.0') >= 0) { if (session_status() == PHP_SESSION_NONE) { session_start(); } } else { if(session_id() == '') { session_start(); } }
يمكن أن يساعدك هذا كثيرًا لتجنب خطأ session_start
.
اسم الجلسة
التحقق من إنشاء ملفات تعريف ارتباط الجلسة
اسم الجلسة هو الاسم الذي يستخدمه ملف تعريف الارتباط (cookie) لتخزين الجلسات، يمكنك أن تستخدم هذا لتفحص فيما إذا اُنشئت ملفات تعريف الارتباط لجلسة ما:
if(isset($_COOKIE[session_name()])) { session_start(); }
لاحظ أنّ هذه الطريقة لا تفيد بشكلٍ عام إلا إذا كنت لا تريد إنشاء ملفات تعريف الارتباط دون ضرورة.
تغيير اسم الجلسة
يمكنك استدعاء الدالة session_name()
لتغيير اسم الجلسة.
// ضبط اسم الجلسة session_name('newname'); // بدء الجلسة session_start();
إذا لم يُمرَّر وسيط إلى الدالة session_name()
سيُرجع اسم الجلسة الحالي، يجب أن يحتوي الاسم على محارف أبْجَعَددية فقط وأن يكون قصيرًا ووصفيًا (للمستخدمين الذين مكّنوا تحذيرات ملفات تعريف الارتباط)، لا يمكن أن يحتوي الاسم على أرقام فقط إنما يجب وجود حرف واحد على الأقل وإلا سيُنشأ معرّف جلسة جديد في كل مرة.
ملفات تعريف الارتباط
تأخذ الدالة setcookie()
المعاملات التالية:
المعامل | التفاصيل |
name |
اسم ملف تعريف الارتباط وهو المفتاح الذي يمكنك استخدامه لاستعادة قيمة من المتغير $_COOKIE ذو النطاق العام العالي وهذا المعامل الإلزامي الوحيد
|
value | القيمة التي تريد تخزينها في ملف تعريف الارتباط، هذه البيانات يمكن أن يصل إليها المتصفح لذا لا تحفظ أي بيانات حساسة |
expire | طابع يونكس زمني (Unix timestamp) يمثّل وقت انتهاء ملف تعريف الارتباط، إذا ضُبط إلى الصفر فستنتهي مدة ملف تعريف الارتباط مع نهاية الجلسة وإذا ضُبط إلى وقت أصغر من الوقت الحالي فستنتهي مدة الملف مباشرةً |
path | نطاق ملف تعريف الارتباط، إذا عُيّنت قيمته / سيكون ملف تعريف الارتباط متوفرًا على كامل المجال وإذا عُيّنت قيمته /مسار معين/ فسيكون الملف متوفرًا في هذا المسار ومساراته الفرعية. قيمته الافتراضية هي مسار ملف تعريف الارتباط الحالي |
domain | النطاق أو النطاق الفرعي المتوفر عليه ملف تعريف الارتباط، إذا ضُبط إلى النطاق stackoverflow.com فإنّ الملف سيكون متوفرًا في هذا النطاق ونطاقاته الفرعية وإذا ضُبط إلى النطاق الفرعي meta.stackoverflow.com فإنّ الملف سيكون متوفرًا في هذا النطاق الفرعي والنطاقات الفرعية منه |
secure | إذا ضُبط إلى القيمة TRUE فسيُضبط ملف تعريف الارتباط فقط إذا وُجد اتصال HTTPS آمن بين الخادم والعميل |
httponly | يحدد فيما إذا كان ملف تعريف الارتباط يجب أن يتوفر عبر بروتوكول HTTP/S ويجب ألا يتوفر للغات البرمجة من جهة العميل مثل جافاسكربت، وهذا الخيار متوفر من الإصدار 5.2 ومابعده |
ملف تعريف ارتباط HTTP هو جزء بيانات صغير يُرسل من موقع ما ويُخزَّن على حاسوب المستخدم من قبل متصفح ويب العميل أثناء تصفح المستخدم لمواقع الإنترنت.
تعديل ملف تعريف الارتباط
يمكن أن تُعدَّل قيمة ملف تعريف الارتباط (cookie) بإعادة ضبط الملف، بفرض لدينا ملف تعريف ارتباط باسم "user":
setcookie("user", "John", time() + 86400, "/");
ملفات تعريف الارتباط هي جزء من ترويسة HTTP، لذا يجب أن تُستدعى setcookie()
قبل أن يُرسل أي خرج إلى المتصفح.
تأكد عند تعديل ملف الارتباط أنّ المعاملات path
وdomain
للدالة setcookie()
تطابق ملف تعريف الارتباط الموجود وإلا سيُنشأ ملف جديد.
سيُشفَّر قسم القيمة من ملف تعريف الارتباط تلقائيًا عند إرساله وعندما يُستقبل سيُفك تشفيره ويُسند إلى متغير بنفس اسم الملف.
ضبط ملف تعريف الارتباط
يُضبط ملف تعريف الارتباط باستخدام الدالة setcookie()
، وبما أنّ ملفات تعريف الارتباط جزء من ترويسة HTTP فيجب أن تُضبط قبل إرسال أي خرج إلى المتصفح، مثال:
setcookie("user", "Tom", time() + 86400, "/");
الوصف:
-
أنشئ ملف تعريف ارتباط بالاسم
user
-
قيمة الملف
Tom
(معامل اختياري) - ستنتهي صلاحية هذا الملف بعد يوم واحد (86400 ثانية) (معامل اختياري)
-
يتوفر الملف على كامل الموقع
/
(معامل اختياري) - يُرسل الملف عبر HTTPS فقط (معامل اختياري)
- لا يمكن للغات البرمجة من جهة العميل مثل جافاسكربت الوصول لهذا الملف (معامل اختياري)
يمكن الوصول لملف تعريف الارتباط المُنشأ أو المُعدَّل في الطلبات اللاحقة فقط (عند تطابق المسار والمجال) لأنّ المتغير ذو النطاق العام العالي $_COOKIE
لا يُملأ بالبيانات الجديدة مباشرةً.
التحقق من ضبط ملف تعريف ارتباط
يمكن استخدام الدالة isset()
للمتغير ذو النطاق العام العالي $_COOKIE
للتحقق من ضبط ملف تعريف ارتباط.
// PHP <7.0 if (isset($_COOKIE['user'])) { // ضُبط ملف تعريف الارتباط echo 'User is ' . $_COOKIE['user']; else { // لم يُضبط ملف تعريف الارتباط echo 'User is not logged in'; } // PHP 7.0+ echo 'User is ' . $_COOKIE['user'] ?? 'User is not logged in';
حذف ملف تعريف ارتباط
يمكنك ضبط الختم الزمني لصلاحية ملف تعريف الارتباط إلى وقت ما في الماضي ليُحذف هذا الملف:
setcookie('user', '', time() - 3600, '/');
تأكد عند حذف ملف تعريف ارتباط من توافق المعاملات path
وdomain
للدالة setcookie()
مع معلومات الملف الذي تريد حذفه وإلا سيُنشأ ملف تعريف ارتباط جديد تنتهي صلاحيته مباشرةً.
ومن الجيّد أيضًا أن تلغي قيمة المتغير $_COOKIE
في حال كانت الصفحة الحالية تستخدمه:
unset($_COOKIE['user']);
استعادة ملف تعريف ارتباط
استعادة وعرض ملف تعريف ارتباط اسمه User
يمكن أن نستعيد قيمة ملف تعريف ارتباط باستخدام المتغير العام $_COOKIE
، فمثلًا إذا كان لدينا ملف تعريف ارتباط اسمه user
نستعيده بالشكل التالي:
echo $_COOKIE['user'];
عميل بروتوكول SOAP (Simple Object Access Protocol)
المعاملات التي تأخذها الدالة SoapClient
هي:
المعامل | تفاصيل |
$wsdl
|
رابط WSDL (اختصار إلى Web Services Description Language أو NULL إذا كنا نستخدم النمط non-WSDL |
$options
|
مصفوفة خيارات للصنف SoapClient. يتطلب النمط Non-WSDL ضبط كل من location و uri، وكل الخيارات الأخرى اختيارية |
النمط WSDL
ننشئ كائنًا جديدًا من الصنف SoapClient
ونمرر رابط ملف WSDL ومصفوفة خيارات اختيارية.
// WSDL إنشاء كائن عميل جديد باستخدام رابط $soap = new SoapClient('https://example.com/soap.wsdl', [ // هذه المصفوفة وقيمها اختيارية 'soap_version' => SOAP_1_2, 'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP, 'cache_wsdl' => WSDL_CACHE_BOTH, # تساعد هذه الخيارات في تنقيح الأخطاء 'trace' => TRUE, 'exceptions' => TRUE ]);
ثم نستخدم الكائن $soap
لاستدعاء توابع SOAP.
$result = $soap->requestData(['a', 'b', 'c']);
النمط Non-WSDL
يشبه هذا النمط النمط السابق إلا أننا نمرر NULL
مكان ملف WSDL ويجب أن نتأكد من ضبط الخيارات location
وuri
.
$soap = new SoapClient(NULL, [ 'location' => 'https://example.com/soap/endpoint', 'uri' => 'namespace' ]);
خرائط الصنف (Classmaps)
يمكنك عند إنشاء عميل SOAP أن تضبط المفتاح classmap
في مصفوفة الإعدادات، يعرّف هذا المفتاح الأنواع المعرفة في WSDL والتي يجب أن تُربط إلى الأصناف الفعلية بدلًا من الصنف الافتراضي StdClass
، وعندها تحصل على استكمال تلقائي للحقول واستدعاءات التوابع على هذه الأصناف بدلًا من الاضطرار إلى تخمين الحقول المضبوطة للصنف StdClass
الاعتيادي.
class MyAddress { public $country; public $city; public $full_name; public $postal_code; // or zip_code public $house_number; } class MyBook { public $name; public $author; // SOAP بإضافة دوال مفيدة إلى الكائنات المُعادة من عمليات classmap يسمح لنا public function getShortDescription() { return "{$this->name}, written by {$this->author}"; } } $soap_client = new SoapClient($link_to_wsdl, [ // Other parameters "classmap" => [ // يعيد الصنف كسلسلة نصية ::class "Address" => MyAddress::class, "Book" => MyBook::class, ] ]);
بعد ضبط خريطة الصنف، عندما تجري عملية معينة تعيد النوع Address
أو Book
فإنّ SoapClient
ينشئ نسخة من ذلك الصنف ويملأ الحقول بالبيانات ويعيده عند استدعاء العملية.
بفرض لدينا التابع getAddress(1234)
يعيد كائن Address
وفقًا للمعرّف (ID) الموجود في قاعدة البيانات والتابع getBook(1234)
يعيد كائن Book
وفقًا للمعرّف (ID) الموجود في قاعدة البيانات.
$address = $soap_client->getAddress(1234); // (1) echo $address->country; $book = $soap_client->getBook(124); // (2) echo $book->getShortDescription(); // (3) $author = $soap_client->getAuthor(1234); // (4) echo $author->name;
في الموضع (1) أصبح المتغير $address
من النوع MyAddress
وذلك حسب classmap
. في الموضع (2) لا يمكننا استخدام دوال أخرى معرفة في الصنف MyBook
. في الموضع (3) أي نوع معرف في WSDL غير معرف في classmap
سيصبح كائن StdClass
عادي. في الموضع (4) لا يوجد خريطة صنف للنوع Author
لذا فإنّ $author
هو StdClass
عادي، أي لا يزال بإمكاننا الوصول للحقول لكن دون استكمال تلقائي ولا دوال مخصصة لتعريف الكائنات.
تتبع طلب ورد SOAP
قد نحتاج أحيانًا لتتبع ما الذي يُرسل ويُستقبل في طلب SOAP، تعيد التوابع التالية صيغة XML الموجودة في الطلب والرد:
SoapClient::__getLastRequest() SoapClient::__getLastRequestHeaders() SoapClient::__getLastResponse() SoapClient::__getLastResponseHeaders()
لنفرض مثلًا أنه لدينا الثابت ENVIRONMENT
وعندما تُضبط قيمته لتكون DEVELOPMENT
فإننا نريد طباعة كل المعلومات إذا رمى استدعاء التابع getAddress
خطأً، يمكن أن يكون الحل كالتالي:
try { $address = $soap_client->getAddress(1234); } catch (SoapFault $e) { if (ENVIRONMENT === 'DEVELOPMENT') { var_dump( $soap_client->__getLastRequestHeaders() $soap_client->__getLastRequest(), $soap_client->__getLastResponseHeaders(), $soap_client->__getLastResponse() ); } ... }
خادم SOAP أساسي
function test($x) { return $x; } $server = new SoapServer(null, array('uri' => "http://test-uri/")); $server->addFunction("test"); $server->handle();
استخدام مكتبة cURL
المعامل | تفاصيل |
curl_init | يهيئ جلسة cURL |
url | الرابط الذي سيُستخدم في طلب cURL |
curl_setopt | يضبط خيارًا لنقل cURL |
ch |
مُعالج cURL (يعيد قيمة من curl_init() )
|
option | خيارات CURLOPT_XXX التي تريد ضبطها، يمكنك الاطلاع على لائحة الخيارات من هنا والقيم المقبولة |
value | القيمة التي ستُضبط على معالِج cURL للخيار المُعطى |
curl_exec | يؤدي جلسة cURL |
ch | مُعالج cURL (يعيد قيمة من curl_init()) |
curl_close | يغلق جلسة cURL |
ch | مُعالج cURL (يعيد قيمة من curl_init()) |
الاستخدام الأساسي (طلبات GET)
تعد cURL
أداة لنقل البيانات بصياغة رابط (URL)، وتدعم HTTP
وFTP
وSCP
والعديد من البروتوكولات الأخرى (بدءًا من الإصدار 7.19.4). تذكر أنّك تحتاج إلى تنصيب وتمكين إضافة cURL
لاستخدامها.
// (1) if(!extension_loaded("curl")) { die("cURL extension not loaded! Quit Now."); } // بدء السكربت // (2) $curl = curl_init(); // ضبط الرابط والخيارات الأخرى curl_setopt($curl, CURLOPT_URL, "http://www.example.com"); // تنفيذ وتمرير النتيجة إلى المتصفح curl_exec($curl); // cURL إغلاق مورد curl_close($curl);
في الموضع (1) سكربت بسيط يفحص إن كانت إضافة cURL
محمّلة أم لا. في الموضع (2) إنشاء مورد cURL
جديد و$curl
هو معالج المورد.
طلبات POST
يمكنك استخدام cURL
إذا أردت محاكاة إجراء نموذج HTML يستخدم الطريقة POST
:
// في مصفوفة POST بيانات $post = [ 'a' => 'apple', 'b' => 'banana' ]; // POST جديد مع رابط إلى cURL ننشئ مورد $ch = curl_init('http://www.example.com'); // ليقرأ الخرج CURLOPT_RETURNTRANSFER نضبط المعامل curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // POST نمرر بيانات curl_setopt($ch, CURLOPT_POSTFIELDS, $post); // $response ننفذ الطلب ونحصل على الخرج في المتغير $response = curl_exec($ch); // نغلق الاتصال curl_close($ch);
استخدام ملفات تعريف الارتباط
يمكن لمكتبة cURL
أن تحافظ على ملفات تعريف الارتباط المستقبَلة في الردود للاستخدام مع الطلبات اللاحقة، نحقق هذا بسطر شيفرة واحد من أجل ملف تعريف ارتباط جلسة بسيط في الذاكرة:
curl_setopt($ch, CURLOPT_COOKIEFILE, "");
في الحالات التي يكون مطلوب فيها الحفاظ على ملفات تعريف الارتباط بعدأن يُدمَّر مُعالِج cURL
يمكنك وصف ملف لتخزينها:
curl_setopt($ch, CURLOPT_COOKIEJAR, "/tmp/cookies.txt");
وعندما تحتاج استخدامها ثانيةً تمررها كملف تعريف ارتباط:
curl_setopt($ch, CURLOPT_COOKIEFILE, "/tmp/cookies.txt");
ومع ذلك تذكر أنّك لا تحتاج هاتين الخطوتين إذا لم تكن تريد حمل ملفات تعريف الارتباط بين معالجات cURL
المختلفة، إذ أنّ ما تحتاجه في معظم الحالات هو ضبط CURLOPT_COOKIEFILE
إلى سلسلة فارغة.
يمكن أن تستخدم معالجة ملف تعريف الارتباط لاستعادة موارد من موقع إنترنت يتطلب تسجيل دخول مثلًا، يكون هذا الإجراء من خطوتين عادةً، الأولى إرسال البيانات بالطريقة POST
إلى صفحة تسجيل الدخول:
<?php // cURL إنشاء معالج $ch = curl_init(); // (curl_init() ضبط الرابط (أو يمكن تمريره إلى curl_setopt($ch, CURLOPT_URL, "https://www.example.com/login.php"); // POST لتكون HTTP ضبط طريقة curl_setopt($ch, CURLOPT_POST, true); // يمكّن ضبط هذا الخيار إلى سلسلة فارغة معالجة ملف تعريف الارتباط لكنه لا يحمّله من ملف curl_setopt($ch, CURLOPT_COOKIEFILE, ""); // ضبط القيم التي نريد إرسالها curl_setopt($ch, CURLOPT_POSTFIELDS, array( "username"=>"joe_bloggs", "password"=>"$up3r_$3cr3t", )); // إعادة جسم الرد curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // إرسال الطلب $result = curl_exec($ch);
الخطوة الثانية (بعد انتهاء فحص الخطأ القياسي) عادةً هي رد GET
بسيط، الشيء المهم هو إعادة استخدام معالِج cURL
الموجود للطلب الثاني، يضمن هذا أنّ ملفات إعادة الارتباط من الرد الأول ستُضمَّن تلقائيًا في الطلب الثاني.
لن نستدعي curl_init()
في الشيفرة التالية:
// تغيير الرابط curl_setopt($ch, CURLOPT_URL, "https://www.example.com/show_me_the_foo.php"); // GET تغيير الطريقة إلى curl_setopt($ch, CURLOPT_HTTPGET, true); // إرسال الطلب $result = curl_exec($ch); // cURL النهاية مع curl_close($ch); // $result تستطيع هنا إضافة الشيفرة التي تريدها لمعالجة
الشيفرة السابقة هي مجرد مثال عن معالجة ملف تعريف ارتباط ?أما في التطبيقات العملية تكون الأمور أكثر تعقيدًا، يجب أن تنفّذ عادةً طلب GET
أولي لصفحة تسجيل الدخول لتسحب مفتاح تسجيل الدخول الذي تحتاج تضمينه في طلب POST
. قد تعطّل بعض المواقع عميل cURL
المعتمد على سلسلة نصية لوكيل المستخدم مما يتطلب منك تغييرها.
استخدام multi_curl لإرسال عدة طلبات POST
قد نحتاج أحيانًا إجراء عدة طلبات POST
لنقطة نهائية (endpoint) واحدة أو أكثر، يمكننا استخدام multi_curl
للتعامل مع هذه الحالة.
ننشئ في البداية عدد الطلبات الذي نحتاجه بنفس طريقة المثال البسيط السابق ونضعها في مصفوفة، نستخدم curl_multi_init
ونضيف معالِج لكل منها.
نستخدم في المثال التالي نقطتين نهائيتين:
// POST مصفوفة بيانات لإرسالها بالطريقة $request_contents = array(); // مصفوفة روابط $urls = array(); // cURL مصفوفة معالجات $chs = array(); //الأول $request_contents محتوى المصفوفة $request_contents[] = [ 'a' => 'apple', 'b' => 'banana' ]; // الثاني $request_contents محتوى المصفوفة $request_contents[] = [ 'a' => 'fish', 'b' => 'shrimp' ]; // ضبط الروابط $urls[] = 'http://www.example.com'; $urls[] = 'http://www.example2.com'; // multi_curl وإضافتهم إلى cURL إنشاء مصفوفة من معالجات $mh = curl_multi_init(); foreach ($urls as $key => $url) { $chs[$key] = curl_init($url); curl_setopt($chs[$key], CURLOPT_RETURNTRANSFER, true); curl_setopt($chs[$key], CURLOPT_POST, true); curl_setopt($chs[$key], CURLOPT_POSTFIELDS, $request_contents[$key]); curl_multi_add_handle($mh, $chs[$key]); }
بعدها نستخدم curl_multi_exec
لإرسال الطلبات:
// تنفيذ الطلبات $running = null; do { curl_multi_exec($mh, $running); } // الحصول على الردود foreach(array_keys($chs) as $key){ $error = curl_error($chs[$key]); $last_effective_URL = curl_getinfo($chs[$key], CURLINFO_EFFECTIVE_URL); $time = curl_getinfo($chs[$key], CURLINFO_TOTAL_TIME); $response = curl_multi_getcontent($chs[$key]); // get results if (!empty($error)) { echo "The request $key return a error: $error" . "\n"; } else { echo "The request to '$last_effective_URL' returned '$response' in $time seconds." . "\n"; } curl_multi_remove_handle($mh, $chs[$key]); } // إغلاق المعالِج الحالي curl_multi_close($mh);
يمكن أن يعيد هذا المثال التالي:
- يعيد الطلب إلى 'http://www.example.com' القيمة 'fruits' في ثانيتين.
- يعيد الطلب إلى 'http://www.example2.com' القيمة 'seafood' في 5 ثواني.
إرسال بيانات متعددة الأبعاد وعدة ملفات في طلب واحد باستخدام cURL
بفرض لدينا نموذج كما في الصورة، ونريد إرسال البيانات إلى خادم الويب الخاص بنا عبر AJAX
ومن هناك إلى سكربت يُنفَّذ على خادم خارجي.
لدينا مدخلات عادية وحقل متعدد الخيارات وحقل إرفاق ملف حيث يمكننا تحميل عدة ملفات.
بفرض نجاح طلب AJAX POST
نحصل على البيانات التالية في الموقع:
// print_r($_POST) Array ( [first_name] => John [last_name] => Doe [activities] => Array ( [0] => soccer [1] => hiking ) )
وتبدو الملفات كما يلي:
// print_r($_FILES) Array ( [upload] => Array ( [name] => Array ( [0] => my_photo.jpg [1] => my_life.pdf ) [type] => Array ( [0] => image/jpg [1] => application/pdf ) [tmp_name] => Array ( [0] => /tmp/phpW5spji [1] => /tmp/phpWgnUeY ) [error] => Array ( [0] => 0 [1] => 0 ) [size] => Array ( [0] => 647548 [1] => 643223 ) ) )
نريد الآن إرسال هذه البيانات والملفات إلى خادم خارجي باستخدام cURL
مع الصنف CurlFile
، وبما أنّ cURL
تقبل مصفوفة بسيطة فقط وليس مصفوفة متعددة الأبعاد فيجب أن نستخدم مصفوفة $_POST
أولًا.
نستخدم هذه الدالة مثلًا للقيام بذلك مما يعطيك الخرج:
// print_r($new_post_array) Array ( [first_name] => John [last_name] => Doe [activities[0]] => soccer [activities[1]] => hiking )
الخطوة التالية هي إنشاء كائنات CurlFile
للملفات المحمّلة باستخدام الحلقة التالية:
$files = array(); foreach ($_FILES["upload"]["error"] as $key => $error) { if ($error == UPLOAD_ERR_OK) { $files["upload[$key]"] = curl_file_create( $_FILES['upload']['tmp_name'][$key], $_FILES['upload']['type'][$key], $_FILES['upload']['name'][$key] ); } }
الدالة curl_file_create
مساعدة للصنف CurlFile
وتنشئ كائنات CurlFile
، نحفظ هذه الكائنات في المصفوفة $files
مع مفاتيح بالأسماء "upload[0]" و"upload[1]" لملفينا.
نحتاج الآن لجمع المصفوفة المعدَّلة مع مصفوفة الملفات ونحفظها في $data
:
$data = $new_post_array + $files;
الخطوة الأخيرة هي إرسال طلب cURL
:
$ch = curl_init(); curl_setopt_array($ch, array( CURLOPT_POST => 1, CURLOPT_URL => "https://api.externalserver.com/upload.php", CURLOPT_RETURNTRANSFER => 1, CURLINFO_HEADER_OUT => 1, CURLOPT_POSTFIELDS => $data )); $result = curl_exec($ch); curl_close ($ch);
بما أنّ $data
هي مصفوفة بسيطة (مسطّحة) فإنّ cURL
ترسل هذا الطلب بالطريقة POST
مع نوع المحتوى multipart/form-data
ويمكنك الحصول على المعلومات والملفات المرسلة مع $_POST
و$_FILES
في الملف upload.php
على الخادم الخارجي كما تفعل عادةً.
إنشاء وإرسال طلب مع طريقة مخصصة
تدعم cURL
افتراضيًا طلبات GET
وPOST
ومن الممكن أيضًا إرسال طلبات بطرق مخصصة مثل DELETE
أوPUT
أوPATCH
(أو حتى طرق غير معيارية) باستخدام المعامل CURLOPT_CUSTOMREQUEST
.
// DELETE إنشاء طلب $method = 'DELETE'; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); $content = curl_exec($ch); curl_close($ch);
ترويسات HTTP المخصصة Get وSet في PHP
إرسال ترويسة الطلب
$uri = 'http://localhost/http.php'; $ch = curl_init($uri); curl_setopt_array($ch, array( CURLOPT_HTTPHEADER => array('X-User: admin', 'X-Authorization: 123456'), CURLOPT_RETURNTRANSFER =>true, CURLOPT_VERBOSE => 1 )); $out = curl_exec($ch); curl_close($ch); // طباعة خرج الرد echo $out;
قراءة الترويسة المخصصة
print_r(apache_request_headers());
الخرج:
Array ( [Host] => localhost [Accept] => */* [X-User] => admin [X-Authorization] => 123456 [Content-Length] => 9 [Content-Type] => application/x-www-form-urlencoded )
يمكننا أيضًا إرسال الترويسة باستخدام الصياغة التالية:
curl --header "X-MyHeader: 123" www.google.com
ترجمة -وبتصرف- للفصول [SOAP Client - SOAP Server - Using cURL in PHP - Sessions - Cookies] من كتاب PHP Notes for Professionals book
اقرأ أيضًا
- المقال التالي: فضاء الأسماء (namespaces) في PHP
- المقال السابق: السلسلة Serialization في PHP
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.