اذهب إلى المحتوى

الجلسات وملفات تعريف الارتباط ومكتبة cURL في PHP


سارة محمد2

الجلسات

خيارات 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

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...