السلام عليكم
مع تنوع المواقع ولغات البرمجة ، وتنوع الاجهزة وبيئات التشغيل اللي تعمل عليها التطبيقات المختلفة، من مواقع ويب وبرامج ديسكتوب وبرامج للمحمول ، ظهرت الحاجة لوضع لغة مشتركة
أو بروتوكول للتواصل بين التطبيقات في مثل هذه الظروف المعقدة، فالتخاطب بين هذه البيئات امر ضروري جدًا، فمثلا مستخدمي الاجهزة المحمولة أو اللوحية يحتاجون للتواصل مع مواقع الانترنت، وهذا عادة ً يتم عن تطبيقات خاصة: مثل تطبيقات تويتر، الفيسبوك واليوتيوب.
لكن ما هي اللغة المشتركة او البروتوكول الذي يربط بين كل هذه المركبات ؟
في الحقيقة يوجد أكثر من بروتوكول ، لكن ما يخصنا في ال php هو بشكل اساسي بروتوكلين اساسيين:- soap
- xml-rpc
هذه البروتوكولات مستعملة للاتصال بين التطبيقات ولغات البرمجة المختلفة ، فجميع اللغات المعروفة لديها مكتبات للتعامل مع هذه البروتوكولات، وتستطيع فهم وتحليل المعلومات المرسلة ويمكن ايضًا ان ترسل معلومات تستطيع ان تفهمها التطبيقات الاخرى.
بشكل عام هذه التطبيقات تتّبع هندسة معينة وهي client\server أي انه يوجد برنامج يوفر الخدمة وهو السيرفر، مثلا موقع اليوتيوب الذي يوفر خدمة استضافة وعرض الفيديوهات، وهناك المستخدم او العميل والذي يطلب الخدمة من الخادم(طلب الفيديوهات للمشاهدة).
سوف نتكلم في هذا الموضوع عن بروتوكول xml-rpc ، وهو بروتوكول يقوم بارسال واستقبال الطلبات والمعلومات عن طريق ال xml،كما ان الطلب يجب ان يكون بصيغة او مبنى خاص، لكن لحسن الحظ لن تضطر لكتابة اي شيء بهذه اللغة
اذ ان ال php تحوي دوال خاصة بتحويل المصفوفة ل xml وبالعكس.
عندما نرسل طلب للسيرفر، يجب علينا ان نحدد اسم الدالة التي نريد طلبها، مثل دالة لتغيير الستاتوس في الفيسبوك، او احضار الرسائل او غيره..
ويجب علينا ايضًا ان ندخل في الطلب البارمترات المطلوبة مثل اسم العضو وكلمة المرور وغيره من المعلومات المطلوبة.
في البداية دعنا نتعرف على دوال ال xml-rpc في لغة ال php:
هذه قائمة بالدوال:
http://www.php.net/manual/en/ref.xmlrpc.php
أما اهم الدوال فهي:
xmlrpc_server_create
http://www.php.net/manual/en/functio...ver-create.php
تستعمل لانشاء سيرفر
تستخدم لتسجيل دالة
xmlrpc_server_register_method
http://www.php.net/manual/en/functio...ter-method.php
دوال لتحويل الطلب من وإلى صيغة xml
http://www.php.net/manual/en/functio...de-request.php
http://www.php.net/manual/en/functio...de-request.php
هكذا يتم بناء السيرفر:
كود PHP:
function greeting_func($method_name, $params, $app_data)
{
$name = $params[0];
$lname = $params[1];
return "Hello, $name $lname. How are you today?";
}
$xmlrpc_server = xmlrpc_server_create();
xmlrpc_server_register_method($xmlrpc_server, "greeting", "greeting_func");
$request_xml = $HTTP_RAW_POST_DATA;
$response = xmlrpc_server_call_method($xmlrpc_server, $request_xml, '');
print $response;
xmlrpc_server_destroy($xmlrpc_server);
يتم انشاء السيرفر لتلقي الطلبات من العميل
xmlrpc_server_create
ثم يتم تسجيل الدوال التي نرغب باتاحة استعمالها للعميل
وذلك عن طريق الدالة
xmlrpc_server_register_method
وهي هنا دالة greeting_func، اما اسمها الذي يطلبه العميل فهو greeting
اذ اننا لا نريد للعميل ان يعرف اسماء الدوال التي لدينا، لذا نعطيه اسم اخر ونربط الاسم
بالدالة.
بعد ذلك نقوم باستدعاء دالة نقوم بالتقاط الطلب المرسل من قبل العميل
xmlrpc_server_call_method
طبعًا هذه الدالة يتم استدعائها عند تلقي الطلب
طيب كيف يعمل العميل:
كود PHP:
<?php
$request = xmlrpc_encode_request("greeting", array('ahmad','sadiq'));
$context = stream_context_create(array('http' => array(
'method' => "POST",
'header' => "(anti-spam-(anti-spam-content-type:)) text/xml",
'content' => $request
)));
$file = file_get_contents("http://localhost/xml-rpc/rpc_server.php", false, $context);
$response = xmlrpc_decode($file);
if (is_array($response) && xmlrpc_is_fault($response)) {
trigger_error("xmlrpc: $response[faultString] ($response[faultCode])");
} else {
print_r($response);
}
?>
هذا الكود يقوم بارسال طلب post ، تمامًا مثل الforms العادية. لكنه هنا يرسل اسم الدالة التي نريد طلبها من السيرفر ، وايضًا البارمترات المطلوبة وهي الاسم واسم العائلة.
وهناك ايضًا الدالة xmlrpc_is_fault
والتي تحدد اذا ما كان هناك خطأ قد حصل بالسيرفر نتيجة لسوء استدعاء الدالة.
طبعًا الموضوع اصبح طويل قليلًا لذا سأحاول الاختصار...
حتى نفهم جيدًا مبدأ خدمات الانترنت سوف نقوم ببناء سيرفر xml-rpc هو عبارة عن مدونة بسيطة مرتبطة بقاعدة البيانات.
أما العميل او طالب الخدمة فهم كتّاب المدونة حيث سيسمح لهم بارسال المواضيع بعد تنسيقها من داخل برنامج الوورد أو برنامج windows live writer ، طبعًا هذا بعد ان يدخلوا اسم المستخدم وكلمة المرور للتحقق من عضوياتهم.
اذ ان هذه الخدمة متاحة عن طريق الوورد من هنا:

وهذا ما سيظهر لنا

ربما لاحظت ان الوورد يدعم رفع الصور كما هو ظاهر في الصورة...
طيب كيف سيتخاطب برنامج الوورد مع السكربت الذي لدينا، خصوصًا ان ميكروسوفت حتمًا لا تعرف شيئًا عنه، وكذلك نحن لا نعرف شيئًا عن برمجة الوورد الداخلية؟
الحل هو استخدام بروتوكول او لغة مشتركة بين تطبيقنا والوورد، بحيث يكون هناك دوال لانشاء\تعديل موضوع، وايضًا دوال لرفع الصور وخلافه.
اللغة المشتركة جاهزة ومعروفة وهي ال xml-rpc ، لكن كيف سيعرف الوورد اسماء الدوال التي
نستخدمها في موقعنا حتى يقوم باستدعائها وارسال المواضيع؟
الحل يكون ب api (وهو عبارة عن مجموعة كلاسات\دوال نعرف اسماءها) مشترك بيننا
وهنا سوف نستخدم api اسمه metaweblog
وهو عبارة عن مجموعة دوال خاصة بالمدونات وفيها الدوال التي نحتاجها بالضبط
وهذه هي الدوال التي فيها:
http://msdn.microsoft.com/en-us/library/bb259697.aspx
في الواقع يوجد اكثر من api
مثل
wordpress api
blogger api
وغيرها
لكن هنا سوف نستعمل مجموعة الدوال هذه، والتي يعرفها الوورد ويستطيع التفاعل معها.
الرجاء الانتباه ان هذه الدوال غير مبرمجة وانما هي الدوال التي يجب علينا برمجتها
والظاهر في الموقع اعلاه هو فقط اسماءها وما تأخذ من بارمترات وما تعيد
هذا هو الكلاس الذي نفذنا فيه هذا ال api
كود PHP:
<?php
require_once("includes/mySQLAdapter.php");
class rpc_handler
{
private $server;
private $data;
private $actions = array(
'metaWeblog.newPost'=>'newPost',
'metaWeblog.editPost'=>'editPost',
'metaWeblog.getPost'=>'getPost',
'metaWeblog.getCategories'=>'getCategories',
'metaWeblog.getRecentPosts'=>'getRecentPosts',
'metaWeblog.newMediaObject'=>'newMediaObject',
'blogger.getUsersBlogs'=>'getUsersBlogs',
'blogger.deletePost'=>'deletePost',
'blogger.getUserInfo'=>'getUserInfo'
);
function __construct($data){
$this->server = xmlrpc_server_create();
foreach ($this->actions as $k=>$v):
xmlrpc_server_register_method($this->server,$k,array($this,$v));
endforeach;
$this->data=$data;
}
public function handle($request)
{
return xmlrpc_server_call_method($this->server, $request, '');
}
public function destroy()
{
xmlrpc_server_destroy($this->server);
}
public function newPost($method_name, $params, $app_data)
{
$usr = $params[1];
$pwd = $params[2];
$blogid = $params[0];
$content = $params[3];
$publish = $params[4];
$auth = $this->data->authUser($usr,$pwd);
if (!$auth) return -1;
if (!is_array($content)) return -2;
return $this->data->addPost($content['title'],$content['description'],$auth);
}
public function editPost($method_name, $params, $app_data)
{
$usr = $params[1];
$pwd = $params[2];
$pid = $params[0];
$content = $params[3];
$publish = $params[4];
$auth = $this->data->authUser($usr,$pwd);
if (!$auth) return -1;
if (!is_array($content)) return -2;
return $this->data->editPost($pid,$content['title'],$content['description']);
}
public function getPost($method_name, $params, $app_data)
{
$pid = $params[0];
$usr = $params[1];
$pwd = $params[2];
$auth = $this->data->authUser($usr,$pwd);
if (!$auth) return -1;
$content = $this->data->getPost($pid);
return array('title'=>$content['title'],'description'=>$content['body']);
}
public function getCategories($method_name, $params, $app_data)
{
$usr = $params[1];
$pwd = $params[2];
$auth = $this->data->authUser($usr,$pwd);
if (!$auth) return -1;
$cat = $this->data->getCategories();
if (!$cat) return -3;
$all = array();
foreach ($cat as $c)
$feed['title']= $c;
$all[]=$feed;
return ($all);
}
public function getRecentPosts($method_name, $params, $app_data)
{
$usr = $params[1];
$pwd = $params[2];
$auth = $this->data->authUser($usr,$pwd);
if (!$auth) return -1;
$posts = $this->data->getRecentPosts();
if (!$posts) return -3;
$all = array();
foreach ($posts as $c)
$feed['title']= $c;
$all[]=$feed;
return ($all);
}
public function newMediaObject($method_name, $params, $app_data)
{
$usr = $params[1];
$pwd = $params[2];
$auth = $this->data->authUser($usr,$pwd);
if (!$auth) return -1;
$media = $params[3];
$name = basename($media['name']);
$ext = pathinfo($media['name'], PATHINFO_EXTENSION);
$bits = $media['bits'];
if (file_exists("uploads/".$name)) $name = uniqid().".".$ext;
$ifp = fopen( "uploads/".$name, "wb" );
@fwrite( $ifp, $bits->scalar);
fclose( $ifp );
return array("url"=>URL.'/uploads/'.$name);
}
public function getUsersBlogs($method_name, $params, $app_data)
{
$usr = $params[1];
$pwd = $params[2];
$auth = $this->data->authUser($usr,$pwd);
if (!$auth) return -1;
$response = array('url'=>URL,"blogid"=>"1","blogName"=>"ahmad");
return array($response);
}
public function deletePost($method_name, $params, $app_data)
{
$pid = $params[0];
$usr = $params[1];
$pwd = $params[2];
$auth = $this->data->authUser($usr,$pwd);
if (!$auth) return -1;
return $this->data->deletePost($pid);
}
public function getUserInfo($method_name, $params, $app_data)
{
$usr = $params[1];
$pwd = $params[2];
$auth = $this->data->authUser($usr,$pwd);
if (!$auth) return -1;
$data = $this->data->getUsersInfo($auth);
$response = array("nickname"=>$data->name,"userid"=>$data->id,'url'=>"http://google.com",
'email'=>$data->email);
return array($response);
}
}
الموضوع طال قليلًا لذلك اترك لكم البحث في الكود المرفق
وكفاية انني عرفتكم على هذا البروتوكول اذا لم تكونوا تعرفوه
طبعًا الملف المرفق فيه ملف كونفيج وملف لقواعد البيانات
قوموا بالتعديلات اللازمة
كذلك هناك ملف اسمه xml.rsd يستعمل للتعرف السريع على الاعدادت، ويعمل مع windows live writer ،بحيث تدخل للبرنامج عنوان الموقع الرئيسي فيقوم بالتعرف على مكان سيرفر ال xml-rpc، قوموا بالتعديل عليه ايضًا بتغيير الروابط التي فيه إلى الروابط الملائمة لتطبيقاتكم.
ويستخدم ملف ال xml.rsd عن طريق تضمينه بالصفحة الرئيسية للمدونة عن طريق التاغ:
كود PHP:
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://localhost/xml-rpc/rsd.xml" />
سلامات