تطور WordPress من منصة التدوين إلى نظام CMS متكامل ، في وقت واحد يحولها إلى إطار قوي للمطورين لبناء المشاريع والتطبيقات المعلقة عليها.

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

واحدة من الأحجار الكريمة المخفية في WordPress التي تسمح للمطورين بإجراء عمليات مع نظام الملفات المحلي بطريقة آمنة وقوية هي واجهة برمجة تطبيقات WordPress Filesystem. تقوم بإزالة وظائف معالجة الملفات إلى مجموعة من الطرق المطلوبة بشكل شائع حتى يمكن استخدامها بشكل آمن في بيئات الاستضافة المختلفة.

نطاق المشكلة

قد يكون هناك عدة أسباب للرغبة في كتابة الملفات المحلية في الكود:

  • تسجيل الأحداث أو العمليات المنجزة
  • تبادل البيانات مع الأنظمة التي لا تدعم WordPress
  • دعم

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

  1. الأمان. هناك خطر من ملكية ملف غير صحيحة عند كتابة الملفات المحلية مع رمز (بواسطة خادم الويب). تنشأ هذه المشكلة في بيئات الاستضافة المشتركة سيئة التكوين وقد تؤدي إلى فقدان التحكم في الملفات.
  2. التوافق. نظرًا لتنوع شركات الاستضافة هناك ، يكون تكوين خادم المستخدم المحدد غير معروف للمطور. وبالتالي ، لا يمكن للمطور التأكد من أن الأذونات المطلوبة لعملية الكتابة قابلة للتحقيق من قِبل مستخدم المكوِّن الإضافي أو السمة.

إذا كان المكوِّن الإضافي لـ WordPress أو الموضوع الذي يحتاج إلى كتابة الملفات المحلية مخصصًا للإصدار العام ، فيجب على المطور دائمًا أن يضع هذه المشكلات في اعتبارك. والخبر السار هو أن WordPress نفسها لديها بالفعل أداة لمعالجة هذه المشاكل: واجهة برمجة تطبيقات النظام.

مقدمة عن واجهة برمجة تطبيقات WordPress Filesystem

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

المنطق وراء API بسيط للغاية. يحاول كتابة الملفات المحلية مباشرة وفي حالة ملكية ملف غير صحيح فإنه التبديل إلى أسلوب آخر المستندة إلى FTP. اعتمادا على مكتبات PHP المتاحة ، تجد طريقة مناسبة لإعداد اتصال FTP (عبر مآخذ التمديد ، أو الإفراط في SSH). بشكل عام ، الخطوات التالية مطلوبة للعمل مع الملفات المحلية:

الخطوة 1. اكتشاف طريقة الاتصال المتوفرة

يستخدم WordPress get_filesystem_method لاكتشاف توفر الطرق التالية (من أعلى أولوية إلى أقل) Direct ، SSH2 ، FTP PHP Extension ، FTP Sockets.

الخطوة 2. الحصول على بيانات الاعتماد المطلوبة للطريقة المكتشفة

إذا كان النقل المكتشف يحتاج إلى بيانات اعتماد من مستخدم ، فإن WordPress يستخدم الدالة request_filesystem_credentials لعرض نموذج طلب. تحتوي الدالة على عدد من المعلمات التي تسمح لها بالاحتفاظ بالبيانات بين عمليات إرسال النماذج ، واطلب بيانات الاعتماد عدة مرات في حالة فشل الاتصال ، واستهداف دليل معين داخل تثبيت WordPress:

request_filesystem_credentials($form_post, $type, $error, $context, $extra_fields);

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

عندما لا يتم توفير بيانات الاتصال المطلوبة بواسطة الطريقة المختارة ، تقوم الدالة بطباعة النموذج لطلبها:

Conneciton information

بعد أول طلب يخزّن WordPress اسم مضيف FTP واسم المستخدم في قاعدة البيانات للاستخدام في المستقبل ، لكنه لا يخزن كلمة المرور. بدلاً من ذلك ، يمكن تحديد بيانات اعتماد FTP في ملف wp-config.php باستخدام الثوابت التالية:

  • FTP_HOST - اسم المضيف للخادم المطلوب الاتصال به
  • FTP_USER - اسم المستخدم للاتصال به
  • FTP_PASS - كلمة المرور للاتصال بها
  • FTP_PUBKEY - المسار إلى المفتاح العام لاستخدامه في اتصال SSH2
  • FTP_PRIKEY - المسار إلى المفتاح الخاص لاستخدامه في اتصال SSH2

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

الخطوة 3. قم بتهيئة فصل WordPress Filesystem والاتصال بنظام الملفات

إن قلب WordPress Filesystem API هو وظيفة WP_Filesystem. يقوم بتحميل وتهيئة فئة النقل المناسبة ، يخزن مثيل تم الحصول عليه في كائن wp_filesystem $ عالمي للاستخدام الإضافي ، ويحاول الاتصال بنظام الملفات باستخدام بيانات الاعتماد المتوفرة:

WP_Filesystem($args, $context);

الخطوة 4. استخدم أساليب WordPress Filesystem لتنفيذ عمليات القراءة / الكتابة

يحتوي كائن wp_filesystem $ تهيئة بشكل صحيح على مجموعة من الطرق للاتصال مع نظام الملفات المحلي الذي يمكن استخدامه دون أي مزيد من القلق حول نوع الاتصال. على وجه الخصوص ، هناك اتباع الأساليب الشائعة الاستخدام:

  • get_contents - يقرأ الملف في سلسلة
  • put_contents - يكتب سلسلة إلى ملف
  • mkdir - يخلق الدليل
  • mdir - يزيل الدليل
  • wp_content_dir - يقوم بإرجاع المسار على نظام الملفات المحلي إلى مجلد wp-content
  • wp_plugins_dir - يقوم بإرجاع المسار على نظام الملفات المحلي إلى مجلد plugins
  • wp_themes_dir - إرجاع المسار على نظام الملفات المحلي إلى مجلد السمات

وضع كل ذلك معا ، دعونا نأتي بمثال يؤدي الخطوات المذكورة أعلاه في وضع بسيط - سنكتب بعض النص المقدم في textarea إلى ملف .txt عادي.

لاحظ أن هذا المثال هو لأغراض العرض التوضيحي ، في حالة واقعية لا تقوم بتخزين بيانات نصية بسيطة في ملف txt. ، سيكون حلاً أكثر قوة لتخزينه في قاعدة البيانات بدلاً من ذلك.

واجهة برمجة تطبيقات WordPress Filesystem قيد التنفيذ

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

أولاً ، لنقم بإنشاء صفحة العرض التوضيحي لعرض النموذج الخاص بنا ضمن القائمة "أدوات":

/*** Create Demo page (under Tools menu)***/add_action('admin_menu', 'filesystem_demo_page');function filesystem_demo_page() {add_submenu_page( 'tools.php', 'Filesystem API Demo page', 'Filesystem Demo', 'upload_files', 'filesystem_demo', 'filesystem_demo_screen' );}function filesystem_demo_screen() {$form_url = "tools.php?page=filesystem_demo";$output = $error = '';/*** write submitted text into file (if any)* or read the text from file - if there is no submission**/if(isset($_POST['demotext'])){//new submissionif(false === ($output = filesystem_demo_text_write($form_url))){return; //we are displaying credentials form - no need for further processing}  ELSEIF (is_wp_error ($ الانتاج)) {$error = $output->get_error_message();$output = '';}  } else {/ read from fileif (false === ($ output = filesystem_demo_text_read ($ form_url))) {return؛  // نحن نعرض بيانات الاعتماد لن تكون هناك حاجة لمزيد من المعالجة} elseif (is_wp_error ($ output)) {$error = $output->get_error_message();$output = '';}  } $ output = esc_textarea ($ output)؛  // الهروب للطباعة؟ 

صفحة Demo API لنظام الملفات

عند عرض صفحتنا (filesystem_demo_screen) ، نتحقق من توفر إرسال النص. إذا كان موجودًا ، فحاولنا كتابته في ملف test.txt ، وإلا فإننا نحاول العثور على هذا الملف في مجلد plugin وقراءة محتوياته ليتم تضمينها في textarea. وأخيرًا ، نطبع نموذجًا أساسيًا لإدخال النص. من أجل القراءة ، تم فصل عمليات الكتابة والقراءة هذه إلى وظائفها الخاصة.

Filesystem API demo

لتجنب تكرار خطوات التهيئة نفسها ، تم إنشاء المساعد المشترك. تستدعي request_filesystem_credentials أولاً للكشف عن طريقة الاتصال المتوفرة والحصول على بيانات الاعتماد. إذا كان ذلك ناجحاً فإنه يستدعي WP_Filesystem لبدء $ wp_filesystem مع البيانات المعطاة.

/*** Initialize Filesystem object** @param str $form_url - URL of the page to display request form* @param str $method - connection method* @param str $context - destination folder* @param array $fields - fileds of $_POST array that should be preserved between screens* @return bool/str - false on failure, stored text on success**/function filesystem_init($form_url, $method, $context, $fields = null) {global $wp_filesystem;/* first attempt to get credentials */if (false === ($creds = request_filesystem_credentials($form_url, $method, false, $context, $fields))) {/*** if we comes here - we don't have credentials* so the request for them is displaying* no need for further processing**/return false;}/* now we got some credentials - try to use them*/if (!WP_Filesystem($creds)) {/* incorrect connection data - ask for credentials again, now with error message */request_filesystem_credentials($form_url, $method, true, $context);return false;}return true; //filesystem object successfully initiated}

الكتابة لملف الكود تبدو كالتالي:

/*** Perform writing into file** @param str $form_url - URL of the page to display request form* @return bool/str - false on failure, stored text on success**/function filesystem_demo_text_write($form_url){global $wp_filesystem;check_admin_referer('filesystem_demo_screen');$demotext = sanitize_text_field($_POST['demotext']); //sanitize the input$form_fields = array('demotext'); //fields that should be preserved across screens$method = ''; //leave this empty to perform test for 'direct' writing$context = WP_PLUGIN_DIR . '/filesystem-demo'; //target folder$form_url = wp_nonce_url($form_url, 'filesystem_demo_screen'); //page url with nonce valueif(!filesystem_init($form_url, $method, $context, $form_fields))return false; //stop further processign when request form is displaying/** now $wp_filesystem could be used* get correct target file first**/$target_dir = $wp_filesystem->find_folder($context);$target_file = trailingslashit($target_dir).'test.txt';/* write into file */if(!$wp_filesystem->put_contents($target_file, $demotext, FS_CHMOD_FILE))return new WP_Error('writing_error', 'Error when writing file'); //return error objectreturn $demotext;}

في هذا الجزء حددنا بعض المعايير الضرورية:

  • $ demotext - النص المقدم للكتابة
  • $ form_fields - عنصر في صفيف $ _POST الذي يقوم بتخزين النص الخاص بنا ويجب حفظه
  • طريقة $ - طريقة النقل ، نتركها فارغة للكشف تلقائيا
  • السياق $ - مجلد الهدف (ملحق واحد)

بعد ذلك بدأنا الكائن wp_filesystem $ العالمي باستخدام وظيفة المساعد التي وصفتها سابقا. في حالة النجاح ، نكتشف المسار الصحيح للمجلد الهدف ونكتب النص المقدم إليه باستخدام طريقة put_contents لكائن wp_filesystem $.

يبدو رمز القراءة من الملف كما يلي:

/*** Read text from file** @param str $form_url - URL of the page where request form will be displayed* @return bool/str - false on failure, stored text on success**/function filesystem_demo_text_read($form_url){global $wp_filesystem;$demotext = '';$form_url = wp_nonce_url($form_url, 'filesystem_demo_screen');$method = ''; //leave this empty to perform test for 'direct' writing$context = WP_PLUGIN_DIR . '/filesystem-demo'; //target folderif(!filesystem_init($form_url, $method, $context))return false; //stop further processing when request forms displaying/** now $wp_filesystem could be used* get correct target file first**/$target_dir = $wp_filesystem->find_folder($context);$target_file = trailingslashit($target_dir).'test.txt';/* read the file */if($wp_filesystem->exists($target_file)){ //check for existence$demotext = $wp_filesystem->get_contents($target_file);if(!$demotext)return new WP_Error('reading_error', 'Error when reading file'); //return error object}return $demotext;}

تعمل هذه الوظيفة بنفس الطريقة الموضحة مسبقًا ، ولكنها تستخدم get_contents للقراءة من الملف الهدف.

استنتاج

عند العمل مع الملفات المحلية ، سيتواصل مطور WordPress أو مطور الإضافات مع مشكلات الأمان والتوافق ، مما يضع ضغوطًا هائلة على الفريق ويضيف ساعات طويلة إلى دورة حياة المشروع. بالاعتماد على واجهة برمجة التطبيقات لـ Filesystem ، يمكن أن تكون هذه المشاكل متدرجة جنبًا إلى جنب بطريقة فعالة. لذا في المرة القادمة التي تجد نفسك فيها تكتب fwrite في كود المساعد الخاص بك ، ضع هذا الخيار البديل الصحي.

تستطيع تحميل تجريبي من هذا الرمز هنا ، وتطويعه لاحتياجاتك.