MediaWiki
بنية تطبيقات المصادر المفتوحة (المجلد الثاني)MediaWiki
بنية تطبيقات المصادر المفتوحة (المجلد الثاني) MediaWiki
Sumana Harihareswara و Guillaume Paumier
إن استمتعت بهذه الكتب، فقد تستمتع أيضًا بـ التصميم البرمجي بالأمثلة في Python والتصميم البرمجي بالأمثلة في JavaScript.
من البداية، جرى تطوير MediaWiki تحديدًا ليكون برمجية ويكيبيديا. وقد عمل المطوّرون على تيسير إعادة الاستخدام من قِبل مستخدمين من خارج المشروع، لكن تأثير ويكيبيديا وانحيازها قد شكّلا معمارية MediaWiki طوال تاريخها.
ويكيبيديا إحدى أكبر عشرة مواقع على العالم، إذ تتلقّى حاليًا نحو 400 مليون زائر فريد شهريًا، وتسجّل أكثر من 100,000 إصابة في الثانية. ولا تعتمد ويكيبيديا على الإعلانات التجارية؛ إذ إن دعمها كله يأتي من مؤسسة غير ربحية هي مؤسسة ويكيميديا، التي تقوم على التبرعات بوصفه نموذج تمويلها الأساسي. وهذا يعني أن MediaWiki يجب ألّا يشغّل موقعًا من أكبر عشرة مواقع فحسب، بل أن يفعل ذلك أيضًا بميزانية ضئيلة. ولتحقيق هذه المطالب، اتّجه MediaWiki بدفّة صوب الأداء والتخزين المؤقت (caching) والتحسين. أما الميزات المكلفة التي يتعذّر تفعيلها على ويكيبيديا فتُعاد أو تُعطَّل عبر متغيّر إعدادات؛ فهناك توازن دائم بين الأداء والميزات.
لا يقتصر تأثير ويكيبيديا في معمارية MediaWiki على الأداء. فعلى خلاف أنظمة إدارة المحتوى (CMS) العامة، كُتب MediaWiki في الأصل لغاية محدَّدة جدًا: دعم مجتمع ينشئ المعرفة ويحرّرها على منصة مفتوحة، قابلة لإعادة الاستخدام بحرية. وهذا يعني، على سبيل المثال، أن MediaWiki لا يتضمّن الميزات المعتادة في أنظمة إدارة المحتوى المؤسسية، مثل سير عمل النشر أو قوائم التحكم في الوصول، لكنه يقدّم بدلًا منها مجموعة متنوّعة من الأدوات للتعامل مع البريد المزعج والتخريب.
لذلك، منذ البداية، أثّرَت احتياجات وتصرّفات مجتمع متطوّر باستمرار من المشاركين في ويكيبيديا في تطوير MediaWiki، والعكس أيضًا. وقد قُدّت معمارية MediaWiki مرارًا بمبادرات ابتدأها المجتمع أو طلبها، مثل إنشاء ويكيميديا كومنز أو ميزة التنقيحات المعلَّمة (Flagged Revisions). وأجرى المطوّرون تغييرات معمارية جوهرية لأن طريقة استخدام محرّري ويكيبيديا لـ MediaWiki جعلت ذلك ضروريًا.
كما كسب MediaWiki قاعدة مستخدمين خارجيين راسخة لأنه كان برمجية مفتوحة المصدر منذ البداية. فالمعيدون من خارج المشروع يعرفون أنه ما دام موقع بارز مثل ويكيبيديا يستخدم MediaWiki، فإن هذه البرمجية ستحظى بالصيانة والتحسين. وكان MediaWiki مركَّزًا حقًّا على مواقع ويكيميديا، لكن جرى بذل جهد لجعله أكثر شموليةً وقدرةً على تلبية احتياجات هؤلاء المستخدمين الخارجيين. فمثلًا، يأتي MediaWiki الآن مُزوَّدًا بمثبِّت ويب ممتاز، مما يجعل عملية التثبيت أقل إزعاجًا بكثير مما كانت حين كان يلزم تنفيذ كل شيء عبر سطر الأوامر وكانت البرمجية تحتوي على مسارات مكتوبة بشكل ثابت لويكيبيديا.
ومع ذلك، فإن MediaWiki هو برمجية ويكيبيديا ولا يزال كذلك، وهذا يظهر في كل مظاهر تاريخها ومعماريتها.
ينظَّم هذا الفصل على النحو التالي:
- نظرة تاريخية لمحة موجزة عن تاريخ MediaWiki، أو على نحو أدقّ عن تاريخه السابق لظهوره، وظروف نشوئه.
- قاعدة شيفرة MediaWiki وممارساتها يشرح اختيار PHP، وأهمية الشيفرة الآمنة وتنفيذها، وكيف يجري التعامل مع الإعدادات العامة.
- قاعدة البيانات وتخزين النصوص يتوغّل في نظام تخزين البيانات الموزّع، وكيف تطوّر بنيته لاستيعاب النمو.
- الطلبات والتخزين المؤقت والتسليم يتتبّع تنفيذ طلب ويب عبر مكوّنات MediaWiki التي يُنشّطها. ويتضمّن هذا القسم وصفًا لطبقات التخزين المؤقت المختلفة، ونظام تسليم الأصول (assets).
- اللغات يفصّل نظام التدويل والتعريب (i18n وl10n) واسع الانتشار، ولماذا يهم، وكيف نُفِّذ.
- المستخدمون يعرض كيفية تمثيل المستخدمين في البرمجية، وكيفية عمل صلاحيات المستخدم.
- المحتوى يفصّل كيفية هيكلة المحتوى وتنسيقه ومعالجته لتوليد HTML النهائي. ويتناول قسم فرعي كيفية تعامل MediaWiki مع ملفات الوسائط.
- تخصيص MediaWiki وتوسيعها يشرح كيفية استخدام JavaScript وCSS والإضافات والسمات لتخصيص ويكي، وكيف تغيّر مظهره وسلوكه. ويقدّم قسم فرعي واجهة برمجة ويب (API) الخاصة بالبرمجية، وهي قابلة للقراءة آليًا.
12.1. نظرة تاريخية
المرحلة الأولى: UseModWiki
أُطلق موقع ويكيبيديا في يناير 2001. وفي ذلك الحين كان في معظمه تجربةً لزيادة حجم المحتوى المُنتَج من أجل Nupedia، وهي موسوعة مجانية المحتوى لكنها محكَّم من قِبل الأقران، أنشأها Jimmy Wales. ولأنه كانت تجربة، كان ويكيبيديا مدعومًا في الأصل بـ UseModWiki، وهو محرّك ويكي موجود برخصة GPL ومكتوب بلغة Perl، يستخدم تسمية CamelCase ويخزّن جميع الصفحات في ملفات نصية منفصلة، دون أي سجل للتغييرات التي أُجريت عليها.
سرعان ما تبيّن أن CamelCase غير مناسب حقًّا لتسمية مقالات الموسوعة. وفي أواخر يناير 2001، أضاف Clifford Adams، وهو مطوّر UseModWiki ومشارك في ويكيبيديا، ميزة جديدة إلى UseModWiki هي الوصلات الحرّة؛ أي القدرة على الوصل إلى الصفحات عبر صياغة خاصة (قوسان مربعان)، بدلًا من الوصل التلقائي عبر CamelCase. وبعد أسابيع قليلة، رقّى ويكيبيديا إلى الإصدار الجديد من UseModWiki الداعم للوصلات الحرّة، وفعّلها.
ورغم أن هذه المرحلة الأولى لا تتعلق بـ MediaWiki في ذاتها، فإنها تقدّم بعض السياق وتبيّن أن ويكيبيديا بدأت تشكّل ميزات البرمجية التي تشغّلها قبل إنشاء MediaWiki أصلًا. كما أثّر UseModWiki في بعض ميزات MediaWiki؛ في لغة الترميز مثلًا. ويحتوي ويكيبيديا النُّسُوخية (Nostalgia Wikipedia) على نسخة كاملة من قاعدة بيانات ويكيبيديا من ديسمبر 2001، حين كان ويكيبيديا لا يزال يستخدم UseModWiki.
المرحلة الثانية: سكربت PHP
في عام 2001 لم يكن ويكيبيديا بعد موقعًا من أكبر عشرة مواقع؛ بل كان مشروعًا خافتًا يجلس في زاوية مظلمة من الإنترنت، مجهولًا لمعظم محركات البحث، ومستضافًا على خادم واحد. ومع ذلك، كان الأداء مسألة مثيرة للقلق بالفعل، ولا سيما لأن UseModWiki كان يخزّن محتواه في قاعدة بيانات من نوع الملفات المسطّحة. وفي ذلك الوقت كان محرّرو ويكيبيديا قلِقين من أن تغمرهم حركة المرور بعد تتبّع مقالات في نيويورك تايمز وSlashdot وWired.
لذلك، في صيف 2001، شرع Magnus Manske، وهو مشارك في ويكيبيديا وكان وقتها طالبًا جامعيًا، في العمل على محرّك ويكي مخصّص لويكيبيديا في وقت فراغه. وقد أراد تحسين أداء ويكيبيديا باستخدام تطبيق مدعوم بقاعدة بيانات، وتطوير ميزات خاصة بويكيبيديا لا يمكن تقديمها عبر محرّك ويكي «عام». وكُتب المحرّك الجديد بلغة PHP ومدعومًا بقاعدة بيانات MySQL، وسُمِّي ببساطة «سكربت PHP» أو «ويكي PHP» أو «برمجية ويكيبيديا» أو «المرحلة الثانية».
أصبح سكربت PHP متاحًا في أغسطس 2001، ومشاركًا على SourceForge في سبتمبر، ومختبَرًا حتى أواخر 2001. ولأن ويكيبيديا كان يعاني مشكلات أداء متكرّرة بسبب تزايد حركة المرور، انتقل ويكيبيديا باللغة الإنجليزية في النهاية من UseModWiki إلى سكربت PHP في يناير 2002. كما رقّت تدريجيًا إصدارات اللغات الأخرى التي أُنشئت عام 2001، وإن بقي بعضها مدعومًا بـ UseModWiki حتى عام 2004.
وبصفته برمجية PHP تستخدم قاعدة بيانات MySQL، كان سكربت PHP هو التكرار الأول لما سيصبح لاحقًا MediaWiki. فقد أدخل ميزات جوهرية كثيرة لا تزال مستخدمة حتى اليوم، مثل المساحات الاسمية (namespaces) لتنظيم المحتوى (بما في ذلك صفحات النقاش)، والسمات، والصفحات الخاصة (بما فيها تقارير الصيانة وقائمة المساهمات وقائمة مراقبة المستخدم).
المرحلة الثالثة: MediaWiki
رغم التحسينات التي جاء بها سكربت PHP والخلفية المعتمدة على قاعدة البيانات، ظلّ مزيج تزايد حركة المرور والميزات المكلفة والعتاد المحدود يستمرّ في التسبّب بمشكلات أداء في ويكيبيديا. وفي عام 2002، أعاد Lee Daniel Crocker كتابة الشيفرة من جديد، وسماء البرمجية الجديدة «المرحلة الثالثة» (http://article.gmane.org/gmane.science.linguistics.wikipedia.technical/2794). ولأن الموقع كان يواجه صعوبات متكرّرة، رأى Lee أنه «لم يبقَ وقت كافٍ للجلوس وتصميم معمارية سليمة وتطوير حل على النحو الصحيح»، ولذلك «اكتفى بإعادة تنظيم المعمارية القائمة من أجل أداء أفضل، وأجرى تعديلات متسرّعة على الشيفرة كلها». وأُضيفت ميزات التنميط (profiling) لتتبّع الدوال البطيئة.
احتفظت برمجية المرحلة الثالثة بالواجهة الأساسية نفسها، وصُمّمت لتبدو وتعمل أقرب ما يمكن إلى برمجية المرحلة الثانية. وأُضيفت كذلك ميزات جديدة قليلة، مثل نظام جديد لرفع الملفات، وفروق جنبًا إلى جنب لتغييرات المحتوى، والوصلات بين الويكيات (interwiki links).
أُضيفت ميزات أخرى خلال عام 2002، مثل صفحات صيانة جديدة، وخيار «التحرير بالنقر المزدوج». غير أن مشكلات الأداء عادت سريعًا. فمثلًا، في نوفمبر 2002، اضطرّ المديرون إلى تعطيل إحصاءات «عدد المشاهدات» و«الموقع» مؤقتًا، لأنها كانت تسبّب عمليتي كتابة في قاعدة البيانات عند كل مشاهدة للصفحة. وكان أيضًا يبدّلون الموقع أحيانًا إلى وضع القراءة فقط للحفاظ على الخدمة للقرّاء، ويعطّلون صفحات الصيانة المكلفة في أوقات الازدحام بسبب مشكلات قفل الجداول.
في مطلع عام 2003، ناقش المطوّرون ما إذا كان ينبغي لهم إعادة هندسة البرمجية وبناء معماريتها من الصفر قبل أن تفوق أعمال المعالجة العاجلة قدرتهم على ضبطها، أم الاستمرار في تعديل قاعدة الشيفرة القائمة وتحسينها. واختاروا الخيار الثاني، في المقام الأول لأن معظم المطوّرين كانوا راضين إلى حدٍّ كافٍ عن قاعدة الشيفرة، وواثقين بما يكفي من أن التحسينات التكرارية الإضافية ستكون كافية للتعامل مع نمو الموقع.
في يونيو 2003، أضاف المديرون خادمًا ثانيًا، وهو أول خادم لقاعدة البيانات منفصلًا عن خادم الويب. (وكانت الآلة الجديدة أيضًا خادم الويب لمواقع ويكيبيديا غير الإنجليزية.) وسيُخطَّط لموازنة الحمل (load balancing) بين الخادمين في وقت لاحق من ذلك العام. كما فعّل المديرون نظام تخزين مؤقت جديدًا للصفحات يستخدم نظام الملفات لتخزين الصفحات المعروضة والجاهزة للإخراج، من أجل المستخدمين مجهوليي الهوية.
يونيو 2003 هو أيضًا العام الذي أنشأ فيه Jimmy Wales مؤسسة ويكيميديا غير الربحية لدعم ويكيبيديا وإدارة بنيتها التحتية وعملها اليومي. وسُمِّيت «برمجية ويكيبيديا» رسميًا «MediaWiki» في يوليو، استنادًا إلى تلاعب لفظي (wordplay) على اسم مؤسسة ويكيميديا. وكان ما عُدّ في حينه مزحة ذكية سيحيّر أجيالًا من المستخدمين والمطوّرين.
أُضيفت ميزات جديدة في يوليو، مثل جدول المحتويات المُولَّد تلقائيًا والقدرة على تحرير أقسام الصفحات، وكلاهما لا يزال مستخدمًا حتى اليوم. وحدث أول إصدار تحت اسم «MediaWiki» في أغسطس 2003، منهيًا التطوّر الطويل لتطبيق كانت بنيته الكلية ستبقى مستقرة إلى حدٍّ كبير منذ ذلك الحين.
12.2. قاعدة شيفرة MediaWiki وممارساتها
PHP
اختيرت PHP عاملةً لبرمجية ويكيبيديا «المرحلة الثانية» في عام 2001؛ ومنذ ذلك الحين نما MediaWiki عضويًا ولا يزال يتطوّر. معظم مطوّري MediaWiki متطوعون يساهمون في وقت فراغهم، وكانت أعدادهم قليلة جدًا في السنوات الأولى. وقد تبدو بعض قرارات تصميم البرمجية أو ما أُغفل منها خاطئًا في الوقت الحاضر، لكن من الصعب لوم المؤسّسين على عدم تنفيذ تجريد (abstraction) تبيّن لاحقًا أنه بالغ الأهمية، حين كانت قاعدة الشيفرة الأصلية بالغة الصغر وكان الوقت اللازم لتطويرها قصيرًا جدًا.
على سبيل المثال، يستخدم MediaWiki أسماء أصناف (classes) بلا بادئة، ما قد يسبّب تعارضات عندما يضيف مطوّرو نواة PHP وPECL (PHP Extension Community Library) أصنافًا جديدة: فقد اضطرّ صنف Namespace في MediaWiki إلى تغيير اسمه إلى MWNamespace ليتوافق مع PHP 5.3. وكان الاستخدام المتّسق لبادئة لجميع الأصناف (مثل «MW») سيجعل دمج MediaWiki داخل تطبيق أو مكتبة أخرى أسهل.
ربما لم يكن الاعتماد على PHP أفضل خيار من حيث الأداء، إذ لم يستفد من التحسينات التي شهدتها بعض اللغات الديناميكية الأخرى. وكان استخدام Java سيكون أفضل كثيرًا من حيث الأداء، ويبسطّط توسيع التنفيذ في مهام الصيانة في الواجهة الخلفية. ومن جهة أخرى، فإن PHP شائعة جدًا، ما يسهّل استقطاب مطوّرين جدد.
رغم أن MediaWiki لا يزال يحتوي على شيفرة قديمة «قبيحة»، فإن تحسينات جوهرية أُجريت على مدى السنوات، وأُدخلت عناصر معمارية جديدة على MediaWiki طوال تاريخه. وتشمل ذلك أصناف Parser وSpecialPage وDatabase، وصنف Image وتسلسل FileRepo، وResourceLoader، وتسلسل Action. بدأ MediaWiki من دون أيٍّ منها، لكنها جميعًا تدعم ميزات قائمة منذ البداية. وكثير من المطوّرين يهتمّون في المقام الأول بتطوير الميزات، بينما تُترك المعمارية في المؤخّرة غالبًا، لتلحق بها في وقت لاحق عندما تصبح تكلفة العمل ضمن معمارية غير كافية واضحةً.
الأمان
ولأن MediaWiki هو المنصّة لمواقع بارزة مثل ويكيبيديا، فرض مطوّرو النواة ومراجعو الشيفرة قواعد أمنية صارمة. (انظر الدليل التفصيلي.) ولتسهيل كتابة شيفرة آمنة، يوفّر MediaWiki للمطوّرين أغلفة (wrappers) حول إخراج HTML واستعلامات قاعدة البيانات للتعامل مع التهريب (escaping). ولتنقية مدخلات المستخدم، يستخدم المطوّر صنف WebRequest الذي يحلّل البيانات الواردة في عنوان URL أو عبر نموذج مُرسَل بطريقة POST. فهو يزيل «الاقتباسات والشرطات السحرية» (magic quotes) والشرطات المائلة، ويجرّد مدخلات غير قانونية، ويوحّد تسلسلات Unicode. ويُتجنّب تزوير الطلبات عبر المواقع (CSRF) باستخدام الرموز (tokens)، ويُتجنّب البرمجة النصية عبر المواقع (XSS) بالتحقق من المدخلات وتهريب المخرجات، عادةً باستخدام دالة htmlspecialchars() في PHP. كما يوفّر MediaWiki (ويستخدم) منقِّح XHTML عبر صنف Sanitizer، ودوالّ قاعدة بيانات تمنع حقن SQL.
الإعدادات
يوفّر MediaWiki مئات إعدادات التهيئة، المخزَّنة في متغيّرات PHP عامة. تُضبط قيمها الافتراضية في DefaultSettings.php، ويمكن لمدير النظام تجاوزها بتحرير LocalSettings.php.
اعتمد MediaWiki في الماضي بشكل مفرط على المتغيّرات العامة، بما في ذلك الإعدادات ومعالجة السياق. وتسبّب المتغيّرات العامة في آثار أمنية خطيرة مع دالة register_globals في PHP (والتي لم يحتج MediaWiki إليها منذ الإصدار 1.2). كما يحدّ هذا النظام من إمكانات التجريد في الإعدادات، ويجعل تحسين عملية بدء التشغيل أصعب. وإلى ذلك، تتشارك مساحة أسماء الإعدادات مع المتغيّرات المستخدمة في التسجيل وكائن السياق، مما يوحي بتعارضات محتملة. ومن منظور المستخدم، جعلت متغيّرات الإعداد العامة MediaWiki يبدو صعب التهيئة والصيانة. وكان تطوير MediaWiki قصّة نقلٍ بطيء للسياق من المتغيّرات العامة إلى الكائنات. وتخزين سياق المعالجة في متغيّرات أعضاء الكائنات يتيح إعادة استخدام تلك الكائنات بطريقة أكثر مرونة بكثير.
12.3. قاعدة البيانات وتخزين النصوص
استخدم MediaWiki خلفية قاعدة بيانات علائقية منذ برمجية المرحلة الثانية. ونظام إدارة قواعد البيانات (DBMS) الافتراضي (والأفضل دعمًا) لـ MediaWiki هو MySQL، وهو النظام الذي تستخدمه جميع مواقع ويكيميديا، لكن لأنظمة DBMS أخرى (مثل PostgreSQL وOracle وSQLite) تطبيقات مدعومة من المجتمع. ويمكن لمدير النظام اختيار DBMS أثناء تثبيت MediaWiki، كما يوفّر MediaWiki كلاً من طبقة تجريد لقاعدة البيانات وطبقة تجريد للاستعلامات تُبسّطان الوصول إلى قاعدة البيانات للمطوّرين.
الشكل 12.1: مخطط قاعدة البيانات
يحتوي التخطيط الحالي على عشرات الجداول. وكثير منها يتعلق بمحتوى الويكي (مثل page وrevision وcategory وrecentchanges). وتشمل جداول أخرى بيانات عن المستخدمين (user وuser_groups)، وملفات الوسائط (image وfilearchive)، والتخزين المؤقت (objectcache وl10n_cache وquerycache)، والأدوات الداخلية (job لقائمة المهام)، وغيرها، كما يبيّن الشكل 12.2. (تتوفّر وثائق كاملة لتخطيط قاعدة البيانات في MediaWiki.) وتُستخدم الفهارس وجداول الملخّص على نطاق واسع في MediaWiki، لأن استعلامات SQL التي تفحص أعدادًا هائلة من الصفوف قد تكون باهظة الثمن، ولا سيما في مواقع ويكيميديا. وعادةً ما يُحذَّر من الاستعلامات غير المفهرَسة.
مرّت قاعدة البيانات بعشرات تغييرات المخطّط عبر السنين، كان أبرزها فصل تخزين النصوص عن تتبّع التنقيحات في MediaWiki 1.5.
الشكل 12.2: جداول المحتوى الرئيسة في MediaWiki 1.4 و1.5
في نموذج 1.4، كان المحتوى يُخزَّن في جدولين مهمّين، cur (يحوي نصّ وبيانات تنقيحة الصفحة الحالية الوصفية) وold (يحوي التنقيحات السابقة)؛ وكانت الصفحات المحذوفة تُحفظ في archive. وعندما يجري تحرير، تُنسَخ التنقيحة السابقة الحالية إلى جدول old، ويُحفظ التحرير الجديد في cur. وعندما تُعاد تسمية صفحة، كان يتعيّن تحديث عنوان الصفحة في البيانات الوصفية لجميع تنقيحات old، وهذه عملية قد تستغرق وقتًا طويلًا. وعندما تُحذف صفحة، كان يتعيّن نسخ مدخلاتها في جدولي cur وold إلى جدول archive قبل حذفها؛ وهذا يعني نقل نصّ جميع التنقيحات، وقد يكون بالغ الكبر ومن ثم يستغرق وقتًا.
في نموذج 1.5، فُصلت البيانات الوصفية للتنقيحات عن نصّ التنقيحات: استُبدل جدولا cur وold بالجداول page (البيانات الوصفية للصفحات) وrevision (البيانات الوصفية لجميع التنقيحات، القديمة أو الحالية) وtext (نصّ جميع التنقيحات، القديمة أو الحالية أو المحذوفة). الآن، عندما يجري تحرير، لم تعد البيانات الوصفية للتنقيحات بحاجة إلى النسخ بين الجداول: يكفي إدراج مدخل جديد وتحديث المؤشّر page_latest. وإلى ذلك، لم تعد البيانات الوصفية للتنقيحات تتضمّن عنوان الصفحة، بل مُعرّفها فقط: وهذا يُغني عن إعادة تسمية جميع التنقيحات عند إعادة تسمية الصفحة
يخزّن جدول revision البيانات الوصفية لكل تنقيحة، لكن ليس نصوصها؛ بل تحتوي على مُعرّف نصّي يشير إلى جدول text الذي يحوي النص الفعلي. وعندما تُحذف صفحة، يبقى نصّ جميع تنقيحاتها في ذلك الجدول ولا يحتاج إلى النقل إلى جدول آخر. ويتألف جدول text من ربط بين مُعرّفات وكُتَل نصّية؛ ويشير حقل flags إلى ما إذا كانت الكتلة النصية مضغوطة بـ gzip (لتوفير المساحة) أو أنها مجرّد مؤشّر إلى تخزين نصّي خارجي. تستخدم مواقع ويكيميديا عنقود تخزين خارجي مدعومًا بـ MySQL يضمّ كُتَلًا من بضع عشرات التنقيحات. وتُخزَّن التنقيحة الأولى من الكتلة كاملة، فيما تُخزَّن التنقيحات التالية للصفحة نفسها فروقًا نسبةً إلى التنقيحة السابقة؛ ثم تُضغط الكُتَل بـ gzip. ولأن التنقيحات مجموعة لكل صفحة، فإنها تميل إلى التشابه، فيكون الفروق نسبيًا صغيرًا ويعمل gzip بجودة عالية. وتقترب نسبة الضغط المحقَّقة في مواقع ويكيميديا من 98%.
على جانب العتاد، يحمل MediaWiki دعمًا مدمجًا لموازنة الحمل، أُضيف في وقت مبكّر عام 2004 في MediaWiki 1.2 (حين حصل ويكيبيديا على خادمه الثاني—وهو أمر بالغ الأهمية في حينه). ويصبح موازن الحمل، وهو شيفرة PHP في MediaWiki التي تقرّر أي خادم يتّصل به، اليوم جزءًا جوهريًا من البنية التحتية لويكيميديا، وهو ما يفسّر تأثيره في بعض قرارات الخوارزميات داخل الشيفرة. ويمكن لمدير النظام أن يحدّد في إعدادات MediaWiki أن هناك خادم قاعدة بيانات رئيسيًا وأي عدد من خوادم قواعد البيانات الفرعية؛ ويمكن إسناد وزن (weight) إلى كل خادم. وسيحوّل موازن الحمل كل عمليات الكتابة إلى الخادم الرئيسي، ويوزّع القراءة وفق الأوزان. كما يتتبّع تأخّر النسخ (replication lag) لكل خادم فرعي. وإذا تجاوز تأخّر النسخ في خادم فرعي 30 ثانية، فلن يتلقّى أي استعلامات قراءة حتى يلحق بالركب؛ وإذا تأخّر جميع الخوادم الفرعية أكثر من 30 ثانية، فس يضع MediaWiki نفسه تلقائيًا في وضع القراءة فقط.
يضمن «حامي التسلسل الزمني» (chronology protector) في MediaWiki ألا يسبّب تأخّر النسخ أبدًا ظهور صفحة للمستخدم تدّعي أن إجراءً نفّذه للتو لم يحدث بعد: فمثلًا، إذا أعاد مستخدم تسمية صفحة، فقد يظلّ مستخدم آخر يرى الاسم القديم، أما من أعاد التسمية فسيرى دائمًا الاسم الجديد، لأنه هو من قام بها. ويُتحقَّق من ذلك بتخزين موضع الخادم الرئيسي في جلسة المستخدم إذا كانت إحدى طلباته قد أنتجت استعلام كتابة. وفي المرة التالية التي يرسل فيها المستخدم طلب قراءة، يقرأ موازن الحمل هذا الموضع من الجلسة، ويحاول اختيار خادم فرعي بلغ موضع النسخ ذاك لخدمة الطلب. وإذا لم يتوفّر أيٌّ منها، فسينتظر حتى يتوفّر أحدها. وقد يبدو للمستخدمين الآخرين أن الإجراء لم يحدث بعد، لكن التسلسل الزمني يبقى متّسقًا لكل مستخدم.
12.4. الطلبات والتخزين المؤقت والتسليم
سير تنفيذ طلب ويب
يشكّل index.php نقطة الدخول الرئيسة لـ MediaWiki، ويتولّى معظم الطلبات التي تعالجها خوادم التطبيق (أي الطلبات التي لم تخدمها بنية التخزين المؤقت؛ انظر أدناه). وتُجري الشيفرة المنفَّذة من index.php فحوصًا أمنية، وتحمّل إعدادات التهيئة الافتراضية من includes/DefaultSettings.php، وتخمّن التهيئة عبر includes/Setup.php، ثم تطبّق إعدادات الموقع الواردة في LocalSettings.php. بعد ذلك تُنشئ كائن MediaWiki ($mediawiki)، وتُنشئ كائن Title ($wgTitle) بحسب معاملي العنوان والإجراء في الطلب.
يمكن أن يتلقّى index.php معاملات إجراءات متنوّعة في طلب العنوان؛ والإجراء الافتراضي هو view، الذي يعرض العرض المعتاد لمحتوى المقال. فمثلًا، يعرض الطلب https://en.wikipedia.org/w/index.php?title=Apple&action=view محتوى مقال «Apple» في ويكيبيديا الإنجليزية. (وعادةً ما تُنسَّق طلبات العرض على نحو أجمل عبر إعادة كتابة العنوان، في هذا المثال إلى https://en.wikipedia.org/wiki/Apple.) وتشمل الإجراءات الشائعة الأخرى edit (لفتح مقال للتحرير)، وsubmit (لمعاينة مقال أو حفظه)، وhistory (لعرض تاريخ مقال)، وwatch (لإضافة مقال إلى قائمة مراقبة المستخدم). أما الإجراءات الإدارية فتشمل delete (لحذف مقال) وprotect (لمنع تحرير مقال).
يُستدعى عندئذٍ MediaWiki::performRequest() للتعامل مع معظم طلبات العنوان. وهو يتحقّق من العناوين السيّئة وقيود القراءة وإعادة التوجيهات المحلية بين الويكيات وحلقات إعادة التوجيه، ويحدّد ما إذا كان الطلب لصفحة عادية أم لصفحة خاصة.
تُسلَّم طلبات الصفحات العادية إلى MediaWiki::initializeArticle() لإنشاء كائن Article للصفحة ($wgArticle)، ثم إلى MediaWiki::performAction() التي تتعامل مع الإجراءات «القياسية». وبمجرد اكتمال الإجراء، تُنهي MediaWiki::finalCleanup() الطلب عبر تثبيت معاملات قاعدة البيانات، وإخراج HTML، وإطلاق التحديثات المؤجَّلة عبر قائمة المهام. وتُثبِّت MediaWiki::restInPeace() التحديثات المؤجَّلة وتُغلق المهمة بسلاسة.
إذا كانت الصفحة المطلوبة صفحة خاصة (أي ليست صفحة محتوى ويكي عادية، بل صفحة خاصة متعلّقة بالبرمجية مثل Statistics)، فيُستدعى المسار SpecialPageFactory::executePath بدلًا من initializeArticle()؛ ثم يُستدعى سكربت PHP المقابل. ويمكن للصفحات الخاصة أن تقوم بمطلق أنواع السحر، ولكلٍّ منها غرض محدّد، عادةً مستقل عن أي مقال بعينه أو عن محتواه. وتشمل الصفحات الخاصة أنواعًا مختلفة من التقارير (التغييرات الأخيرة، والسجلات، والصفحات غير المصنَّفة) وأدوات إدارة الويكي (حظر المستخدمين، وتغيير حقوق المستخدمين)، وغيرها. ويعتمد سير التنفيذ فيها على وظيفتها.
تحتوي دوالّ كثيرة على شيفرة تنميط (profiling)، ما يجعل من الممكن تتبّع سير التنفيذ لأغراض التنقيح عند تفعيل التنميط. ويُجرى التنميط باستدعاء الدالتين wfProfileIn وwfProfileOut لبدء تنميط دالة وإيقافه على التوالي؛ وكلتا الدالتين تأخذ اسم الدالة معاملًا. وفي مواقع ويكيميديا، يجري التنميط لنسبة مئوية من جميع الطلبات، حفاظًا على الأداء. ويرسل MediaWiki حزم UDP إلى خادم مركزي يجمعها ويُنتج بيانات التنميط.
التخزين المؤقت
طوّر MediaWiki نفسه لأداء أفضل لأنه يلعب دورًا مركزيًا في مواقع ويكيميديا، لكنه كذلك جزء من منظومة تشغيلية أكبر أثّرت في معماريته. وقد فرضت بنية التخزين المؤقت في ويكيميديا، وهي مُهيكَلة في طبقات، قيودًا على MediaWiki؛ وتجاوز المطوّرون هذه القضايا، لا بمحاولة تشكيل بنية التخزين المؤقت المحسَّنة على نطاق واسع في ويكيميديا بما يلائم MediaWiki، بل بجعل MediaWiki أكثر مرونة بحيث يعمل داخل تلك البنية دون الإخلال بالأداء أو باحتياجات التخزين المؤقت. فمثلًا، يعرض MediaWiki افتراضيًا عنوان IP للمستخدم في الزاوية العليا اليمنى من الواجهة (للغات التي تُكتب من اليسار إلى اليمين) تذكيرًا بأن هذا هو ما يعرفه البرنامج به عندما لا يكون المستخدم مسجَّل الدخول. ويتيح متغيّر الإعداد $wgShowIPinHeader لمدير النظام تعطيل هذه الميزة، مما يجعل محتوى الصفحة مستقلًا عن المستخدم: عندئذٍ يمكن تقديم النسخة نفسها بالضبط من كل صفحة لجميع الزوّار مجهوليي الهوية.
يتكوّن المستوى الأول من التخزين المؤقت، وهو المستخدم في مواقع ويكيميديا، من وسائط تخزين مؤقت عكسي (reverse caching proxies) هي Squids، تعترض معظم الطلبات وتخدمها قبل أن تصل إلى خوادم تطبيق MediaWiki. وتحمل هذه الوسائط نسخًا ساكنة (static) من صفحات كاملة معروضة، تُقدَّم للقراءات البسيطة من المستخدمين غير المسجّلين في الموقع. ويدعم MediaWiki أصليًا Squid وVarnish، ويتكامل مع طبقة التخزين المؤقت هذه، مثلًا بإخطارها بأن تُفرِغ صفحة من الذاكرة المؤقتة عند تغيّرها. أما المستخدمون المسجّلون الدخول، والطلبات الأخرى التي لا يمكن أن تخدمها وسائط Squid، فتُوجَّه وسائط Squid الطلبات إلى خادم الويب (Apache).
يقع التخزين المؤقت من المستوى الثاني عند يعرض MediaWiki الصفحة ويجمعها من كائنات متعدّدة، كثير منها قابل للتخزين المؤقت لتقليل الاستدعاءات في المستقبل. وتشمل هذه الكائنات واجهة الصفحة (الشريط الجانبي والقوائم ونصوص الواجهة) والمحتوى نفسه بعد تحليله من نصّ الويكي. وقد كان مخزن الكائنات في الذاكرة متاحًا في MediaWiki منذ الإصدار 1.1 المبكّر (2003)، وهو مهمّ بصفة خاصة لتجنّب إعادة تحليل الصفحات الطويلة والمعقّدة.
كما يمكن تخزين بيانات جلسة الدخول في memcached، ما يتيح عمل الجلسات بشفافية عبر عدة خوادم ويب أمامية في إعداد لموازنة الحمل (تعتمد ويكيميديا اعتمادًا كبيرًا على موازنة الحمل باستخدام LVS مع PyBal).
منذ الإصدار 1.16، يستخدم MediaWiki مخزن كائنات مخصّصًا لنصوص واجهة المستخدم المعرَّبة؛ وقد أُضيف ذلك بعد ملاحظة أن جزءًا كبيرًا من الكائنات المخزَّنة في memcached كان رسائل واجهة معرَّبة إلى لغة المستخدم. ويعتمد النظام على جلب سريع للرسائل الفردية من قواعد بيانات ثابتة (CDB)، أي ملفات أزواج مفتاح-قيمة. وتُقلّل هذه القواعد من الحمل الزائد على الذاكرة ومن زمن بدء التشغيل في الحالة المعتادة؛ وهي تُستخدم أيضًا في ذاكرة التخزين المؤقت للوصلات بين الويكيات.
تتكوّن طبقة التخزين المؤقت الأخيرة من ذاكرة التخزين المؤقت لأوامر PHP البايتية (opcode cache)، وهي ممكّنة عادةً لتسريع تطبيقات PHP. وقد تكون عملية الترجمة (compilation) طويلة؛ ولتجنّب ترجمة سكربتات PHP إلى أوامر بايتية في كل مرة تُستدعى فيها، يمكن استخدام مُسرِّع PHP لتخزين الأوامر المترجَمة وتنفيذها مباشرةً من دون ترجمة. ويعمل MediaWiki «ببساطة» مع كثير من المُسرِّعات مثل APC وPHP accelerator وeAccelerator.
ولانحيازه إلى ويكيميديا، فإن MediaWiki مُحسَّن لهذه البنية الكاملة متعددة الطبقات والموزّعة. ومع ذلك، فهو يدعم أصليًا أيضًا إعدادات بديلة للمواقع الأصغر حجمًا. فمثلًا، يوفّر نظام تخزين مؤقت اختياريًا مبسّطًا بالملفات يخزّن مخرجات الصفحات المعروضة بالكامل، كما تفعل Squid. كما تتيح طبقة التخزين المؤقت التجريدية في MediaWiki تخزين الكائنات في عدة أماكن، منها نظام الملفات أو قاعدة البيانات أو ذاكرة التخزين المؤقت للأوامر البايتية.
ResourceLoader
كما في كثير من تطبيقات الويب، أصبحت واجهة MediaWiki أكثر تفاعلية واستجابةً على مر السنين، وذلك في معظمه بفضل استخدام JavaScript. فقد تطلّبت جهود قابلية الاستخدام التي انطلقت عام 2008، وكذلك المعالجة المتقدّمة للوسائط (مثل تحرير ملفات الفيديو عبر الإنترنت)، تحسينات مخصّصة في أداء الواجهة الأمامية.
ولتحسين تسليم أصول JavaScript وCSS، طُوِّر وحدة ResourceLoader لتحسين تسليم JS وCSS. وقد بدأ العمل عليها عام 2009 واكتمل عام 2011، وأصبحت ميزة أساسية في MediaWiki منذ الإصدار 1.17. ويعمل ResourceLoader بتحميل أصول JS وCSS عند الطلب، thereby تقليل زمن التحميل والتحليل عندما تكون الميزات غير مستخدمة، مثلًا في المتصفحات الأقدم. كما يضغط الشيفرة (minify)، ويجمّع الموارد لتقليل عدد الطلبات، ويمكنه تضمين الصور بصيغة data URIs. (ولمزيدٍ عن ResourceLoader، انظر الوثائق الرسمية، وعرض Low Hanging Fruit vs. Micro-optimization: Creative Techniques for Loading Web Pages Faster الذي قدّمه Trevor Parscal وRoan Kattouw في OSCON 2011.)
12.5. اللغات
السياق والمبرر
يعدّ جزء مركزي من المساهمة الفعّالة في المعرفة الحرّة ونشرها للجميع أن تُقدَّم بأكبر عدد ممكن من اللغات. ويتوفّر ويكيبيديا بأكثر من 280 لغة، وتمثّل مقالات الموسوعة بالإنجليزية أقل من 20% من جميع المقالات. ولأن ويكيبيديا ومواقعها الشقيقة موجودة بهذا العدد الكبير من اللغات، فإن الأمر لا يقتصر على تقديم المحتوى بلغة القرّاء الأم، بل يمتد أيضًا إلى توفير واجهة معرَّبة وأدوات إدخال وتحويل فعّالة، حتى يتمكن المشاركون من المساهمة بالمحتوى.
ولهذا السبب، فإن التعريب والعَلمَنة (l10n وi18n) مكوّنان مركزيان في MediaWiki. نظام العَلمَنة واسع الانتشار ويؤثّر في أجزاء كثيرة من البرمجية؛ وهو أيضًا من أكثر الأنظمة مرونةً وغنًى بالميزات. (وهناك دليل شامل للعَلمَنة والتعريب في MediaWiki.) ومن المعتاد تفضيل راحة المترجم على راحة المطوّر، لكن يُعتقد أن ذلك تكلفة مقبولة.
يطابق MediaWiki حاليًا أكثر من 350 لغة، بما فيها اللغات غير اللاتينية واللغات التي تُكتب من اليمين إلى اليسار (RTL)، وبمستويات إنجاز متفاوتة. ويمكن أن تكون الواجهة والمحتوى بلغتين مختلفتين، وأن يتّسم اتجاههما بالاختلاط.
لغة المحتوى
استخدم MediaWiki في الأصل ترميزًا خاصًا بكل لغة، ما سبّب مشكلات كثيرة؛ فمثلًا لم يكن بالإمكان استخدام النصوص المكتوبة بحروف غير لاتينية في عناوين الصفحات. فاعتُمد بدلًا منه UTF-8. وأُلغي دعم مجموعات المحارف غير UTF-8 عام 2005، إلى جانب التغيير الكبير في مخطّط قاعدة البيانات في MediaWiki 1.5؛ ويجب أن يكون المحتوى مشفَّرًا بـ UTF-8 الآن.
يمكن تخصيص المحارف غير المتاحة على لوحة مفاتيح المحرّر وإدراجها عبر Edittools في MediaWiki، وهي رسالة واجهة تظهر أسفل نافذة التحرير؛ والنسخة المبنية على JavaScript منها تُدرِج تلقائيًا المحرف الذي يُنقر عليه في نافذة التحرير. وتُدمج إضافة WikiEditor الخاصة بـ MediaWiki، والمطوّرة ضمن جهدٍ لقابلية الاستخدام، المحارف الخاصة مع شريط أدوات التحرير. وتوفّر إضافة أخرى، تُدعى Narayam، أساليب إدخال إضافية وميزات ربط مفاتيح للمحارف غير ASCII.
لغة الواجهة
تُخزَّن رسائل الواجهة في مصفوفات PHP من أزواج مفتاح-قيمة منذ إنشاء برمجية المرحلة الثالثة. وتُعرَّف كل رسالة بمفتاح فريد يُسنَد إليه قيم مختلفة عبر اللغات. ويحدّد المطوّرون المفاتيح، ويُشجَّعون على استخدام بادئات للإضافات؛ فمثلًا، تبدأ مفاتيح رسائل إضافة UploadWizard بـ mwe-upwiz-، حيث mwe اختصار لعبارة إضافة MediaWiki (MediaWiki extension).
يمكن لرسائل MediaWiki أن تتضمّن معاملات توفّرها البرمجية، وهي معاملات تؤثر كثيرًا في قواعد الرسالة. ولمّ دعم أي لغة ممكنة تقريبًا، جرى تطوير نظام التعريب في MediaWiki وتعقيده بمرور الزمن ليُفسح المجال لسمات اللغة الخاصة واستثناءاتها، التي كثيرًا ما يعدّها الناطقون بالإنجليزية غرائب.
على سبيل المثال، الصفات في الإنجليزية كلمات غير متغيّرة، لكن لغات مثل الفرنسية تتطلب مطابقة الصفة مع الاسم. فإذا حدّد المستخدم جنسه في تفضيلاته، فيمكن استخدام الوسيط {{GENDER:}} في رسائل الواجهة لمخاطبته على النحو الملائم. وتشمل الوسائط الأخرى {{PLURAL:}} لصيغ الجمع «البسيطة» ولغات مثل العربية التي تميّز بين المثنى والجمع القليل، و{{GRAMMAR:}} التي توفّر دوال تحويل نحوي للغات مثل الفنلندية التي تُحدث فيها الحالات النحوية تغييرات أو تصريفات.
توطين الرسائل
تقيم رسائل الواجهة المعرَّبة الخاصة بـ MediaWiki في ملفات MessagesXx.php، حيث Xx هو رمز اللغة وفق ISO-639 (مثل MessagesFr.php للفرنسية)؛ والرسائل الافتراضية بالإنجليزية وتُخزَّن في MessagesEn.php. وتستخدم إضافات MediaWiki نظامًا مشابهًا، أو تحشد كل الرسائل المعرَّبة في ملف .i18n.php. وإلى جانب الترجمات، تتضمّن ملفات الرسائل أيضًا معلومات تعتمد على اللغة مثل صيغ التاريخ.
كان تقديم الترجمات يتمّ عبر إرسال رقع PHP لملفات MessagesXx.php. وفي ديسمبر 2003، أدخل MediaWiki 1.1 «رسائل قاعدة البيانات»، وهي مجموعة فرعية من صفحات الويكي في مساحة أسماء MediaWiki، تحتوي على رسائل الواجهة. ويكون محتوى صفحة الويكي MediaWiki: هو نصّ الرسالة، ويتجاوز قيمته في ملف PHP. أما النسخ المعرَّبة من الرسالة فهي في MediaWiki:/؛ فمثلًا MediaWiki:Rollbacklink/de.
وقد سمحت هذه الميزة للمستخدمين المتقدّمين بترجمة رسائل الواجهة (وتخصيصها) محليًا على ويكيهم، لكن هذه العملية لا تحدّث ملفات i18n التي تأتي مع MediaWiki. وفي عام 2006، أنشأ Niklas Laxström موقع ويكي خاصًا بـ MediaWiki ومُعدًّا سكوتشًا بشكل مكثّف (أصبح مستضافًا الآن على http://translatewiki.net)، حيث يمكن للمترجمين تعريب رسائل الواجهة بجميع اللغات بسهولة عبر تحرير صفحة ويكي. ثم تُحدَّث ملفات MessagesXx.php في مستودع شيفرة MediaWiki، حيث يمكن لأي ويكي جلبها تلقائيًا وتحديثها باستخدام إضافة LocalisationUpdate. أما في مواقع ويكيميديا، فلا تُستخدم رسائل قاعدة البيانات اليوم إلا للتخصيص ولم يعد لها دور في التعريب. كما تُعرَّب إضافات MediaWiki وبعض البرامج المرتبطة، مثل الروبوتات، على translatewiki.net.
وحتى يتسنى للمترجمين فهم سياق رسالة الواجهة ومعناها، يُعدّ من الممارسات الجيدة في MediaWiki توفير توثيق لكل رسالة. ويُخزَّن هذا التوثيق في ملف رسائل خاص برمز اللغة qqq الذي لا يقابل لغة حقيقية. ثم يُعرض توثيق كل رسالة في واجهة الترجمة على translatewiki.net. وثمة أداة مفيدة أخرى هي رمز اللغة qqx؛ فعند استخدامه مع معامل &uselang لعرض صفحة ويكي (مثل https://en.wikipedia.org/wiki/Special:RecentChanges?uselang=qqx)، يعرض MediaWiki مفاتيح الرسائل بدل قيمها في واجهة المستخدم؛ وهذا مفيد جدًا لتحديد الرسالة التي ينبغي ترجمتها أو تغييرها.
يستطيع المستخدمون المسجّلون ضبط لغتهم الخاصة للواجهة في تفضيلاتهم، لتجاوز لغة الواجهة الافتراضية للموقع. كما يدعم MediaWiki لغات احتياطية: إذا كانت رسالة غير متاحة باللغة المختارة، فسيُعرض نصّها بأقرب لغة ممكنة، وليس بالضرورة بالإنجليزية. فمثلًا، اللغة الاحتياطية للبريتونية هي الفرنسية.
12.6. المستخدمون
يمثَّل المستخدمون في الشيفرة عبر نسخ (instances) من صنف User، الذي يضمّ كل الإعدادات الخاصة بالمستخدم (مُعرّف المستخدم والاسم والحقوق وكلمة المرور وعنوان البريد الإلكتروني إلخ). وتستخدم أصناف الواجهة مُلوِّنات (accessors) للوصول إلى هذه الحقول؛ وهي تقوم بكل العمل المتعلق بتحديد ما إذا كان المستخدم مسجَّل الدخول، وما إذا كان الخيار المطلوب يمكن تحقيقه من ملفات تعريف الارتباط (cookies) أم يحتاج إلى استعلام في قاعدة البيانات. وتضبط معظم الإعدادات اللازمة لعرض الصفحات العادية في ملف تعريف الارتباط لتقليل استعمال قاعدة البيانات.
يوفّر MediaWiki نظام صلاحيات شديد التدرّج، إذ لكل إجراء ممكن تقريبًا صلاحية مستخدم. فمثلًا، لتنفيذ إجراء «Rollback» (أي «التراجع سريعًا عن تحريريات آخر مستخدم حرّر صفحة بعينها»)، يحتاج المستخدم إلى الصلاحية rollback، وهي مشمولة افتراضيًا في مجموعة مستخدمي sysop في MediaWiki. غير أنها يمكن أيضًا إضافتها إلى مجموعات مستخدمين أخرى، أو تخصيص مجموعة مستخدمين خاصة لا تقدّم سوى هذه الصلاحية (وهذا هو الحال في ويكيبيديا الإنجليزية، مع مجموعة Rollbackers). ويتم تخصيص حقوق المستخدمين بتحرير مصفوفة $wgGroupPermissions في LocalSettings.php؛ فمثلًا، $wgGroupPermissions['user']['movefile'] = true; تسمح لجميع المستخدمين المسجّلين بإعادة تسمية الملفات. ويمكن أن ينتمي المستخدم إلى عدة مجموعات، فيرث أعلى الحقوق المرتبطة بكلٍّ منها.
غير أن نظام صلاحيات المستخدمين في MediaWiki صُمّم في جوهره مع وضع ويكيبيديا في الحسبان: موقع يكون محتواه متاحًا للجميع، ولا تُقيَّد فيه سوى إجراءات معيّنة لدى بعض المستخدمين. وينقص MediaWiki مفهومًا موحّدًا وشاملًا للصلاحيات؛ فهو لا يوفّر ميزات أنظمة إدارة المحتوى التقليدية مثل تقييد الوصول للقراءة أو الكتابة حسب الموضوع أو نوع المحتوى. وتوفّر بعض إضافات MediaWiki هذه الميزات بقدرٍ ما.
12.7. المحتوى
بنية المحتوى
استُخدم مفهوم المساحات الاسمية في عصر UseModWiki من ويكيبيديا، حيث كانت صفحات النقاش تحمل العنوان "Talk: أو File: وTemplate:)؛ أما مساحة المحتوى الرئيسة فلا بادئة لها. وقد تبنّى مستخدمو ويكيبيديا هذه البادئات بسرعة، فأتاحت للمجتمع مساحات مختلفة ليتطوّر فيها. وقد أثبتت المساحات الاسمية أنها ميزة مهمة في MediaWiki، إذ تهيّئ الشروط اللازمة لمجتمع الويكي وتُنشئ مناقشات على المستوى الثاني وعمليات مجتمعية وبوّابات وملفات تعريف للمستخدمين إلخ.
الإعداد الافتراضي لمساحة المحتوى الرئيسة في MediaWiki هو أن تكون مسطّحة (بلا صفحات فرعية)، لأن هذا هو أسلوب عمل ويكيبيديا، لكن تمكين الصفحات الفرعية أمر تافه. وهي مفعّلة في مساحات أخرى (مثل User:، حيث يمكن للناس مثلًا العمل على مسودات المقالات) وتعرض مسارات تنقّل (breadcrumbs).
تفصل المساحات الاسمية المحتوى حسب النوع؛ وداخل المساحة الاسمية الواحدة يمكن تنظيم الصفحات حسب الموضوع باستخدام التصنيفات (categories)، وهو مخطط تنظيم شبه هرمي أُدخل في MediaWiki 1.3.
معالجة المحتوى: لغة ترميز MediaWiki والمُحلِّل
المحتوى الذي ينشئه المستخدم ويخزّنه MediaWiki ليس بصيغة HTML، بل بلغة ترميز خاصة بـ MediaWiki، تُدعى أحيانًا «نصّ الويكي» (wikitext). وهي تتيح للمستخدمين إجراء تغييرات تنسيقية (مثل الغامق والمائل باستخدام الاقتباسات)، وإضافة وصلات (باستخدام الأقواس المربعة)، وتضمين القوالب، وإدراج محتوى يعتمد على السياق (مثل تاريخ أو توقيع)، وإنجاز عدد لا يُحصى من الأشياء السحرية الأخرى. (تتوفّر وثائق تفصيلية.)
لعرض صفحة، يجب تحليل هذا المحتوى وتجميعه من جميع الأجزاء الخارجية أو الديناميكية التي يستدعيها، ثم تحويله إلى HTML سليم. والمُحلِّل (parser) من أكثر الأجزاء جوهرية في MediaWiki، مما يجعل تغييره أو تحسينه صعبًا. ولأن مئات الملايين من صفحات الويكيات في العالم تعتمد على المُحلِّل كي يواصل إخراج HTML بالطريقة التي اعتاد عليها دائمًا، فلا بدّ أن يظل مستقرًا إلى حدٍّ كبير.
لم تُوضع المواصفة الرسمية للغة الترميز منذ البداية؛ فقد انطلقت قائمةً على ترميز UseModWiki، ثم تحوّلت وتطوّرت بحسب الحاجة. وفي غياب مواصفة رسمية، صارت لغة ترميز MediaWiki لغةً معقّدة ومتميّزة، متوافقة أساسًا مع مُحلِّل MediaWiki وحده؛ ولا يمكن التعبير عنها بقواعد نحوية رسمية. وتُشارَك مواصفة المُحلِّل الحالي ساخرًا بأنها «ما يُخرجه المُحلِّل من نصّ الويكي، إضافة إلى بضع مئات من حالات الاختبار».
كانت هناك محاولات كثيرة لمُحلِّلات بديلة، لكن لم تنجح أيٌّ منها حتى الآن. ففي عام 2004 كتب Jens Frank مُجزِّئًا (tokenizer) تجريبيًا لتحليل نصّ الويكي، وفُعّل على ويكيبيديا؛ ولم يكن إلا ثلاثة أيام حتى قُرِّر تعطيله بسبب سوء أداء تخصيص ذاكرة مصفوفات PHP. ومنذ ذلك الحين، جرى تنفيذ معظم التحليل باستخدام كومة ضخمة من التعبيرات النمطية (regular expressions) وحزمة ضخمة من الدوال المساعدة. وقد أصبح ترميز الويكي، وكل الحالات الخاصة التي يحتاج المُحلِّل إلى دعمها، أكثر تعقيدًا بكثير، مما يجعل أي محاولات لاحقة أصعب.
كان تحسين بارز هو إعادة كتابة المُعالِج المسبق (preprocessor) على يد Tim Starling في MediaWiki 1.12، وكان دافعه الرئيس تحسين أداء التحليل في الصفحات ذات القوالب المعقّدة. ويحوّل المُعالِج المسبق نصّ الويكي إلى شجرة XML DOM تمثّل أجزاء المستند (استدعاءات القوالب ودوالّ المُحلِّل وخطافات الوسوم وعناوين الأقسام وبعض البنى الأخرى)، لكنه يستطيع تخطّي «الفروع الميتة»، مثل حالات #switch غير المتَّبَّعة والقيم الافتراضية غير المستخدمة لمعاملات القوالب، أثناء توسيع القوالب. ثم يتكرّر المُحلِّل في بنية DOM ويحوّل محتواها إلى HTML.
وأدى العمل الحديث على محرّر مرئي لـ MediaWiki إلى الحاجة إلى تحسين عملية التحليل (وجعلها أسرع)، فعُود العمل على المُحلِّل وعلى الطبقات الوسيطة بين ترميز MediaWiki وHTML النهائي (انظر المستقبل أدناه).
الكلمات السحرية والقوالب
يوفّر MediaWiki «كلمات سحرية» (magic words) تغيّر السلوك العام للصفحة أو تُدرج محتوى ديناميكي فيها. وهي تتكوّن من: مفاتيح سلوك مثل __NOTOC__ (لإخفاء جدول المحتويات التلقائي) أو __NOINDEX__ (لإلغاء محركات البحث طلب فهرسة الصفحة)؛ ومتغيّرات مثل {{CURRENTTIME}} أو {{SITENAME}}؛ ودوالّ مُحلِّل (parser functions)، أي كلمات سحرية يمكن أن تتلقّى معاملات، مثل {{lc:}} (لإخراجه `` بالأحرف الصغيرة). أما البنيات مثل {{GENDER:}} و{{PLURAL:}} و{{GRAMMAR:}} المستخدمة في تعريب الواجهة فهي دوالّ مُحلِّل.
الطريقة الأكثر شيوعًا لتضمين محتوى من صفحات أخرى في صفحة ما في MediaWiki هي استخدام القوالب. وقد قُصد بالقوالب في الأصل أن تُستخدم لتضمين المحتوى نفسه في صفحات مختلفة، مثل لوحات التنقّل أو لافتات الصيانة في مقالات ويكيبيديا؛ والقدرة على إنشاء تخطيطات صفحات جزئية وإعادة استخدامها في آلاف المقالات مع صيانة مركزية أحدثت أثرًا هائلًا في مواقع مثل ويكيبيديا.
غير أن المستخدمين استخدموا القوالب (وأساءوا استخدامها) أيضًا لغرض مختلف تمامًا. فقد جعل MediaWiki 1.3 من الممكن أن تأخذ القوالب معاملات تغيّر مخرجاتها؛ والقدرة على إضافة معامل افتراضي (أُدخلت في MediaWiki 1.6) مكّنت من بناء لغة برمجة دلالية (functional programming language) منفَّذة فوق PHP، وكانت في النهاية إحدى أكثر الميزات كلفةً من حيث الأداء.
ثم طوّر Tim Starling دوالّ مُحلِّل إضافية (إضافة ParserFunctions) كإجراء مؤقت لصدّ البنى المجنونة التي أنشأها مستخدمو ويكيبيديا بالقوالب. وقد تضمّنت هذه المجموعة من الدوالّ بِنَى منطقية مثل #if و#switch، ودوالّ أخرى مثل #expr (لتقييم التعابير الرياضية) و#time (لتنسيق الوقت).
وفي القريب العاجل، بدأ مستخدمو ويكيبيديا ينشئون قوالب أكثر تعقيدًا باستخدام الدوال الجديدة، ما أضرّ كثيرًا بأداء التحليل في الصفحات الغنية بالقوالب. وقد نُفِّذ المُعالِج المسبق الجديد الذي أُدخل في MediaWiki 1.12 (وهي تغيير معماري جوهري) لمعالجة هذه المشكلة جزئيًا. وناقش مطوّرو MediaWiki مؤخرًا إمكانية استخدام لغة برمجية فعلية، ربما Lua، لتحسين الأداء.
ملفات الوسائط
يرفع المستخدمون الملفات عبر صفحة Special:Upload؛ ويمكن للمديرين ضبط أنواع الملفات المسموح بها عبر قائمة بيضاء من الإضافات. وبعد رفعها، تُخزَّن الملفات في مجلّد على نظام الملفات، وتُخزَّن الصور المصغّرة في مجلّد مخصّص اسمه thumb.
ولأن مهمة ويكيميديا تعليمية، يدعم MediaWiki أنواع ملفات قد تكون غير شائعة في تطبيقات الويب أو أنظمة إدارة المحتوى الأخرى، مثل صور SVG المتجهية وملفات PDF وDjVu متعددة الصفحات. وتُعرَض هذه الملفات بصيغة PNG، ويمكن إنشاء صور مصغّرة لها وعرضها ضمن السياق، كما هو الحال مع ملفات الصور الأكثر شيوعًا مثل GIF وJPG وPNG.
عند رفع ملف، يُسنَد إليه صفحة File: تحتوي على المعلومات التي أدخلها الرافع؛ وهذا نصّ حر ويشمل عادةً معلومات حقوق النشر (المؤلف والترخيص) وعناصر تصف محتوى الملف أو تصنّفه (الوصف والموقع والتاريخ والتصنيفات إلخ). ورغم أن الويكيات الخاصة قد لا تهتم كثيرًا بهذه المعلومات، فإنها حرجة في مكتبات الوسائط مثل ويكيميديا كومنز لتنظيم المجموعة وضمان مشروعية مشاركة هذه الملفات. وقد جُادل بأن معظم هذه البيانات الوصفية ينبغي في الواقع أن تُخزَّن في بنية قابلة للاستعلام مثل جدول في قاعدة البيانات. وهذا من شأنه أن يُسهّل البحث كثيرًا، وأن يبسّط أيضًا الإسناد وإعادة الاستخدام من قِبل الغير—مثلًا عبر واجهة البرمجة.
وتتيح معظم مواقع ويكيميديا أيضًا رفع «محلي» إلى كل ويكي، لكن المجتمع يحاول تخزين ملفات الوسائط المرخَّصة بحرية في مكتبة ويكيميديا للوسائط الحرّة، أي ويكيميديا كومنز. ويستطيع أي موقع من مواقع ويكيميديا عرض ملف مستضاف على كومنز وكأنه مستضاف محليًا. ويجنى هذا التخصيص الحاجة إلى رفع الملف إلى كل ويكي لاستخدامه فيه.
وبتيجة لذلك، يدعم MediaWiki أصليًا مستودعات الوسائط الأجنبية (foreign media repositories)، أي القدرة على الوصول إلى ملفات الوسائط المستضافة على ويكي آخر عبر واجهته البرمجية ونظام ForeignAPIRepo. ومنذ الإصدار 1.16، يستطيع أي موقع MediaWiki استخدام ملفات من ويكيميديا كومنز بسهولة عبر ميزة InstantCommons. وعند استخدام مستودع أجنبي، تُخزَّن الصور المصغّرة محليًا لتوفير النطاق الترددي (bandwidth). غير أنه ليس بالإمكان (بعد) الرفع إلى مستودع وسائط أجنبي من ويكي آخر.
12.8. تخصيص MediaWiki وتوسيعها
المستويات
توفّر معمارية MediaWiki طرائق مختلفة لتخصيص البرمجية وتوسيعها. ويمكن ذلك على مستويات وصول مختلفة:
- يستطيع مديرو النظام تثبيت الإضافات والسمات، وضبط برامج الويكي المساعدة المنفصلة (مثل إنشاء الصور المصغّرة وعرض TeX) والإعدادات العامة (انظر الإعدادات أعلاه).
- يستطيع مشغّلو الويكي (وهم مسمّون أحيانًا «المديرون» أيضًا) تحرير أدوات الموقع (gadgets) وإعدادات JavaScript وCSS على مستوى الموقع كله.
- يستطيع أي مستخدم مسجّل تخصيص تجربته وواجهته الخاصة باستخدام تفضيلاته (للإعدادات والسمات والأدوات الموجودة) أو إجراء تعديلاته الخاصة (باستخدام صفحات JavaScript وCSS الخاصة به).
كما يمكن للبرامج الخارجية أن تتواصل مع MediaWiki عبر واجهته البرمجية القابلة للقراءة آليًا، إن كانت مفعّلة، مما يجعل في متناول المستخدم أي ميزة وأي بيانات تقريبًا.
JavaScript وCSS
يستطيع MediaWiki قراءة JavaScript وCSS على مستوى الموقع أو على مستوى السمة وتطبيقهما باستخدام صفحات ويكي خاصة؛ وهذه الصفحات في مساحة أسماء MediaWiki:، ولذلك لا يمكن تحريرها إلا بواسطة مشغّلي النظام؛ فمثلًا، تعديلات JavaScript في MediaWiki:Common.js تنطبق على كل السمات، وCSS في MediaWiki:Common.css ينطبق على كل السمات، أما MediaWiki:Vector.css فينطبق فقط على المستخدمين الذين يستخدمون سمة Vector.
ويمكن للمستخدمين إجراء الأنواع نفسها من التغييرات، على أن تنطبق على واجهتهم وحدهم، عبر تحرير صفحات فرعية من صفحة المستخدم (مثل User:/common.js لـ JavaScript على كل السمات، وUser:/common.css لـ CSS على كل السمات، أو User:/vector.css لتعديلات CSS تنطبق على سمة Vector وحدها).
وإذا كانت إضافة Gadgets مثبَّتة، استطاع مشغّلو النظام أيضًا تحرير الأدوات (gadgets)، أي مقتطفات من شيفرة JavaScript، توفّر ميزات يمكن للمستخدمين تشغيلها وإيقافها من تفضيلاتهم. وستتيح التطويرات القادمة في هذا الاتجاه مشاركة الأدوات عبر الويكيات، بما يجنّب التكرار.
تركّزت هذه المجموعة من الأدوات أثرًا هائلًا وعمّمت بشكل كبير تطوير برمجية MediaWiki. فأفراد المستخدمون مأسورون على إضافة ميزات لأنفسهم؛ ويمكن للمستخدمين المتقدّمين مشاركتها مع غيرهم، بشكل رسمي وغير رسمي، وكذلك عبر أنظمة يتحكم بها مشغّلو النظام ويمكن تهيئتها عالميًا. وهذا الإطار مثالي للتعديلات الصغيرة المغلقة على ذاتها، ويضع عتبة دخول أدنى مما تتطلبه تعديلات الشيفرة الأثقل التي تُجرى عبر الخطافات والإضافات.
الإضافات والسمات
وحين لا تكفي تعديلات JavaScript وCSS، يوفّر MediaWiki نظام خطافات (hooks) يتيح لمطوّرين من خارج المشروع تشغيل شيفرة PHP مخصّصة قبل شيفرة MediaWiki أو بعدها أو بدلًا منها عند أحداث معيّنة. (تُوثَّق خطافات MediaWiki في https://www.mediawiki.org/wiki/Manual:Hooks.) وتستخدم إضافات MediaWiki الخطافات كي تتّصل بالشيفرة.
قبل وجود الخطافات في MediaWiki، كانت إضافة شيفرة PHP مخصّصة تعني تعديل الشيفرة الأساس، وهو أمر لم يكن سهلًا ولا موصى به. وقد اقترح Evan Prodromou الخطافات الأولى وأضافها عام 2004؛ وأُضيفت الكثير غيرها عبر السنين عند الحاجة. وباستخدام الخطافات، بات بالإمكان توسيع ترميز الويكي في MediaWiki بقدرات إضافية عبر إضافات الوسوم (tag extensions).
نظام الإضافات ليس مثاليًا؛ فتسجيل الإضافة يستند إلى تنفيذ شيفرة عند بدء التشغيل بدلًا من بيانات قابلة للتخزين المؤقت، ما يحدّ من التجريد والتحسين ويضرّ بأداء MediaWiki. لكن البنية العامة لنظام الإضافات صارت اليوم بنية تحتية مرنة إلى حدٍّ لا بأس به، فقد ساعدت في جعل الشيفرة المتخصّصة أكثر وحدات، وأبقت البرمجية الأساس من التوسّع (أكثر مما ينبغي)، وجعلت بناء وظائف مخصّصة فوق MediaWiki أسهل للمستخدمين من خارج المشروع.
وعلى العكس، من الصعب جدًا كتابة سمة جديدة لـ MediaWiki من دون إعادة اختراع العجلة. ففي MediaWiki، السمات أصناف PHP يرث كل منها الصنف الأب Skin؛ وهي تحوي دوالّ تجمع المعلومات اللازمة لتوليد HTML. وكانت سمة «MonoBook» طويلة العمر صعبة التخصيص لأنها تحوي قدرًا كبيرًا من CSS خاص بالمتصفحات لدعم المتصفحات القديمة؛ فكان تعديل القالب أو CSS يستلزم تغييرات لاحقة كثيرة حتى ينعكس التغيير على كل المتصفحات والمنصّات.
API
تُعدّ نقطة الدخول الرئيسة الأخرى لـ MediaWiki، إلى جانب index.php، هي api.php، وتُستخدم للوصول إلى واجهة استعلامات الويب القابلة للقراءة آليًا (Application Programming Interface) الخاصة بها.
أنشأ مستخدمو ويكيبيديا في الأصل «روبوتات» (bots) تعمل عبر كشط شاشات HTML الذي يقدّمه MediaWiki؛ وكانت هذه الطريقة غير موثوقة كثيرًا وتعطّلت مرات عديدة. ولتحسين هذا الحال، أدخل المطوّرون واجهة للقراءة فقط (تقع في query.php)، ثم تطوّرت لاحقًا إلى واجهة برمجية كاملة للقراءة والكتابة توفّر وصولًا مباشرًا وعالي المستوى إلى البيانات الموجودة في قاعدة بيانات MediaWiki. (تتوفّر وثائق شاملة لواجهة البرمجة.)
يمكن لبرامج العميل استخدام الواجهة البرمجية لتسجيل الدخول وجلب البيانات ونشر التغييرات. وتدعم الواجهة عملاء JavaScript رفيعين مبنيّين على الويب وتطبيقات المستخدم النهائي. وكل ما يمكن إنجازه عبر واجهة الويب يمكن أساسًا إتمامه عبر الواجهة البرمجية. وتتوفّر مكتبات عميلة تنفّذ واجهة MediaWiki البرمجية بلغات كثيرة، منها Python و.NET.
12.9. المستقبل
ما بدأ مشروعًا صيفيًا أنجزه مطوّر PHP متطوع واحد، نما ليصبح MediaWiki، وهو محرّك ويكي ناضج ومستقر يشغّل موقعًا من أكبر عشرة مواقع ببنية تشغيلية بالغة الصغر. وقد أمكن ذلك بفضل التحسين المستمر للأداء، والتغييرات المعمارية التكرارية، وفريق من المطوّرين المتميزين.
وتطوّر تقنيات الويب، ونمو ويكيبيديا، يستدعيان تحسينات مستمرة وميزات جديدة، بعضها يتطلب تغييرات جوهرية في معمارية MediaWiki. وهذا هو الحال مثلًا في مشروع المحرّر المرئي الجاري، الذي أعاد إشعال العمل على المُحلِّل وعلى لغة ترميز الويكي، وعلى DOM والتحويل النهائي إلى HTML.
MediaWiki أداة تُستخدم لأغراض شديدة الاختلاف. فداخل مشاريع ويكيميديا، مثلًا، تُستخدم لإنشاء موسوعة وصيانتها (ويكيبيديا)، ولتشغيل مكتبة وسائط ضخمة (ويكيميديا كومنز)، ولنسخ نصوص مرجعية ممسوحة ضوئيًا (ويكي مصدر)، وهكذا. وفي سياقات أخرى، يُستخدم MediaWiki كنظام إدارة محتوى مؤسسي، أو كمستودع بيانات، وأحيانًا مقترنًا بإطار دلالي. ومن المرجّح أن تستمرّ هذه الاستخدامات المتخصّصة غير المخطَّط لها في دفع تعديلات مستمرة في البنية الداخلية للبرمجية. وعليه، فإن معمارية MediaWiki حيّة إلى حدٍّ بعيد، تمامًا كالمجتمع الضخم من المستخدمين الذي يدعمه.
12.10. مراجع إضافية
- توثيق MediaWiki ودعمه
- توثيق MediaWiki المُولَّد تلقائيًا
- Domas Mituzas، Wikipedia: site internals, configuration, code examples and management issues، مؤتمر MySQL Users، 2007. النص الكامل متاح على http://dom.as/talks/.
12.11. شكر وتقدير
أُنجز هذا الفصل بشكل تعاوني. كتب Guillaume Paumier معظم المحتوى بتنظيم المدخلات التي قدّمها مستخدمو MediaWiki ومطوّروه الأساسيون. ونسّقت Sumana Harihareswara مراحل المقابلات وجمع المدخلات. وشكر خاص إلى Antoine Musso وBrion Vibber وChad Horohoe وTim Starling وRoan Kattouw وSam Reed وSiebrand Mazeland وErik Möller وMagnus Manske وRob Lanphier وAmir Aharoni وFederico Leva وGraham Pearce وآخرين على تقديم المدخلات و/أو مراجعة المحتوى.