محمد أحمد العيل

المساهمون
  • المساهمات

    205
  • تاريخ الانضمام

  • تاريخ آخر زيارة

السُّمعة بالموقع

93 Excellent

المعلومات الشخصية

  • النبذة الشخصية مهندس نظم معلومات، أكتب في مدونتي (تلميحات تقنية) عن البرامج الحرة ومفتوحة المصدر. لدي خبرة في التطوير بلغة جافا وإدارة قواعد بيانات MySQL و Oracle، إضافة إلى إدارة أنظمة لينوكس (دبيان ومشتقاتها).
  • الموقع الالكتروني

3 متابعين

آخر الزُوّار

2,816 زيارة للملف الشّخصي
  1. يتناول هذا المقال، الثاني من سلسلة من أربعة أجزاء، كيفيّة توزيع آلات افتراضيّة عبر وسائط شبكة في بيئة تستخدم KVM. تأكد - قبل تنفيذ الخطوات المشروحة هنا - من تثبيت المتطلّبات المذكورة في الجزء الأول من السلسلة. تثبيت نظام تشغيل عن طريق خادوم FTP في بيئة KVM سنثبّت لأغراض هذا الدرس خادوم FTP على النظام المُضيف؛ وذلك باتباع الخطوات التالية (راجع درس كيفية تنصيب وإعداد خادوم FTP على أوبنتو لتفاصيل أكثر عن إعداد خادوم FTP). سنكتفي هنا بالأوامر الأساسية للحصول على الخادوم وتثبيت نظام ضيف على آلة افتراضية عن طريقه. للتثبيت: $ sudo apt install vsftpd ثم نعدّل ملف الإعداد etc/vsftpd.conf/ للسماح بالوصول المجهول لخادوم FTP: $ sudo nano /etc/vsftpd.conf نغيّر قيمة التعليمة anonymous_enable من NO إلى YES؛ ثم نعيد تشغيل الخادوم: $ sudo systemctl restart vsftpd.service إن أردنا مشاركة ملفات عن طريق خادوم FTP فيمكننا وضعها على المسار ‎/srv/ftp. جهّزنا خادوم FTP لمشاركة الملفات؛ حان الآن وقت اختيار ملف ISO الخاص بنظام التشغيل الذي نريد تثبيته على الآلة الافتراضية (النظام الضّيف)؛ ونحدّد نقطة تركيب Mount point ليُركَّب عليها هذا الملف: $ sudo mount -t iso9660 -o ro ISO_FILE MOUNT_POINT تشير ISO_FILE إلى المسار الذي يوجد عليه ملف ISO وMOUNT_POINT إلى مسار مجلد التركيب. ملحوظة: تمثّل ملفات ISO نسخا خامة من أقراص صلبة ويجب تركيبها على نظام الملفات File system حتى يمكن لنظام التشغيل التعامل معها. يتعامل نظام التشغيل مع المجلَّد الذي رُكِّب عليه المحتوى كما لو كان يقرأ البيانات من قرص مًدمَج (CD أو DVD). نحدّد أثناء التركيب نظام الملفات المناسب للتعامل مع ملف ISO وهو iso9660. لا يمكن لحدّ الساعة الوصول إلى محتويات الملفّ أعلاه عن طريق FTP؛ إذ أنها لا توجد في المسار الذي يمكن لخادوم تشارك الملفات القراءة منه. ننشئ مجلدا جديدا على المسار ‎/srv/ftp: $ sudo mkdir /srv/ftp/ubuntu-14.04 ثم ننقل إليه محتويات ملفّ ISO انطلاقا من نقطة التركيب: $ sudo cp -r /mnt/ubuntu-14.04/* /srv/ftp/ubuntu-14.04/ حيثُ mnt/ubuntu-14.04/ هي نقطة التركيب (MOUNT_POINT) السابقة. نتأكد من أن مجموعة المستخدمين ftp هي المالكة للمجلد ubuntu-14.04 الذي أنشأناه للتو حتى يمكن لخادوم FTP قراءة محتوياته: $ sudo chown -R :ftp /srv/ftp/ubuntu-14.04/ يمكننا الآن استخدام أداة virt-manager لإنشاء آلات افتراضية تستخدم وسيط التثبيت الموجود على خادوم تشارك الملفات. تظهر عند طلب إنشاء آلة افتراضية جديدة النافذة التالية. نحدّد خيار التثبيت عبر الشبكة Network Install وننتقل للخطوة الموالية. نحدّد في هذه الخطوة المسار URL الذي يوجد عليه وسيط التثبيت. بما أننا نريد الوصول إلى خادوم FTP فالمسار سيكون حسب الصيغة التالية: ftp://ip_or_host/folder حيثُ ip_or_host عنوان IP الخاص بخادوم تشارك الملفات أو اسم المضيف Host الخاص به؛ وfolder المجلّد حيث توجد ملفات نظام التشغيل الذي نريد تثبيته على الآلة الافتراضية (مجلد ubuntu-14.04 الموجود على خادوم تشارك الملفات). تذكّر أننا في الدرس السابق ثبّتنا حزمة bridge-utils وذكرنا أنها تنشئ جسرا يعمل بين الآلات الافتراضية (النظام الضّيف) والنظام المُضيف. ستلاحظ بعد تثبيت الحزمة ظهور واجهة شبكة جديدة لديك على النظام المُضيف (حيثُ ثبتتنا KVM وأدواته) باسم virbr0. يمكن للأجهزة الافتراضية التواصل مع النظام المضيف عن طريق هذه الواجهة؛ لذا سنحصُل على عنوانها بتنفيذ الأمر التالي: $ ip -4 a show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 4: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000 inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0 valid_lft forever preferred_lft forever يظهر من نتيجة الأمر أعلاه أن الواجهة vibr0 لديها العنوان 192.168.122.1 (قد يختلف العنوان لديك). يصبح عنوان المجلّد حيث توجد ملفات التثبيت على النحو التالي: ftp://192.168.122.1/ubuntu-14.04 وهو العنوان الذي أعطيناه للأداة virt-manager كما في الصورة أعلاه. تشبه الخطوات الموالية (من 3 إلى 5) الخطوات المذكورة في الجزء الأول من هذه السلسلة. تثبيت نظام تشغيل عن طريق خادوم وِب في بيئة KVM لا تقتصر إمكانيات التثبيت عبر الشبكة على الوسائط الموجودة على خواديم تشارك ملفات، بل يمكن استخدام خواديم أخرى مثل خواديم الوِب (Apache أو Nginx على سبيل المثال). سنأخذ في هذه الفقرة مثالا لإنشاء آلة افتراضية عبر الأداة virt-manager وتثبيت نظام تشغيل ضيف عن طريق وسيط تثبيت موجود على خادوم وِب. راجع درس كيف تثبت حزم MySQL ،Apache ،Linux :LAMP و PHP على أوبنتو 14.04 للمزيد عن تفاصيل تثبيت خادوم وِب Apache؛ أو مقال كيف تثبت حزم MySQL ،nginx ،Linux :LEMP وPHP على أوبنتو 14.04 إن كنت تفضّل خادوم Nginx. يمكن الاكتفاء - لأغراض هذا الدرس - بالجزء الأول من أحد المقالين المذكوريْن سابقا (تثبيت Apache أو Nginx دون بقية الحزم). لا يختلف تثبيت النظام الضّيف انطلاقا من وسيط تثبيت على خادوم وِب عن التثبيت عبر خادوم تشارك ملفات سوى في الخطوة الثانية عند تحديد العنوان. في حالة خادوم الوِب يُحدّد العنوان على النحو التالي: http://192.168.122.1/ubuntu-14.04 رأينا في هذا الدرس والدرس السابق كيفية استخدام الأداة الرسومية virt-manager لإنشاء آلات افتراضيّة في بيئة تستخدم KVM للحوسبة الافتراضية؛ سنرى في الدرس الموالي كيفية إدارة الأقراص الافتراضية في هذه البيئة. ترجمة - بتصرّف لمقال How to Deploy Multiple Virtual Machines using Network Install (HTTP, FTP and NFS) under KVM Environment – Part 2 لصاحبه Mohammad Dosoukey.
  2. تقدّم تقنية KVM (اختصار Kernel-based Virtual Machine؛ الأجهزة الافتراضيّة المعتمدة على نواة لينكس) آلية لتشغيل الحوسبة الافتراضيّة (التخيّليّة أو الوهميّة) Virtualization على الأنظمة العاملة بلينكس. تمكّن هذه الآلية - التي تتوفّر على هيئة وحدة Module في نواة لينكس منذ الإصدار 2.6.20 - من استخدام أنظمة تشغيل مستقلّة ومنفصلة في وقت واحد على نفس العتاد Hardware. يتولّى نظامٌ يُعرَف بالمضيف Host تشغيل العتاد Hardware عن طريق برنامج يُعرَف بالمراقِب Hypervisor. يوفّر المراقب موارد (معالج، ذاكرة عشوائية، أجهزة طرفية وغيرها) للآلات الافتراضيّة. يُسمّى النظام الذي يُشغّل الآلة الافتراضيّة بالنظام الضيف Guest. يقدّم KVM الميزات التاليّة: التعهّد الزائد Over-commiting: يعني تخصيص موارد افتراضيّة (المعالجات والذاكرة العشوائية) أكثر من تلك التي يوفّرها العتاد. التموين السريع Thin provisionning: يسمح بالتوزيع المرن للمساحة التخزينية المتوفّرة والبحث عن أمثل طريقة لمشاركتها بين الآلات الافتراضية. تحجيم الإدخال/الإخراج من القرص Disk I/O throttling: يوفّر إمكانية تعريف حد لطلبات الإدخال والإخراج بالنسبة لكل آلة افتراضيّة. إمكانيّة زيادة قدرات المعالجة الخاصّة بالآلات الافتراضية حسب الطّلب دون الحاجة لإيقافها عن العمل. يتطرّق هذا المقال، الأوّل في سلسلة من أربعة أجزاء، لكيفية استخدام KVM والأدوات التي يوفّرها على توزيعة Ubuntu 16.04. تشترك توزيعات لينكس عموما في الخطوط العريضة، وكثير من الخطوات الواردة في هذه السلسلة. المتطلّبات يجب أن تكون لدى العتاد الذي يعمل عليه النظام المُضيف القدرةُ على تنفيذ طلبات المُراقب عن طريق ما يُعرَف بامتدادات العتاد الخاصّة بالحوسبة الافتراضية Hardware virtualization extensions؛ وهو ما توفّره أغلب الحواسيب الحديثة. يمكّن الأمر kvm-ok من التأكد من جاهزيّة جهازك لاستخدام KVM: $ kvm-ok INFO: /dev/kvm exists KVM acceleration can be used يظهر من نتيجة الأمر أعلاه أن الجهاز قادر على استخدام التقنيّة. تأكّد، إن كانت النتيجة مخالفة، من أن امتدادات العتاد موجودة ومفعّلة في محمّل الإقلاع BIOS (أو UEFI) الخاص بجهازك. تثبيت أدوات KVM ونشر الآلات الافتراضية سنحتاج لبضعة حزم قبل أن يمكننا البدء في إنشاء آلات افتراضية باستخدام KVM. يُثبّت الأمر التالي هذه الحزم: $ sudo apt install qemu-kvm libvirt-bin bridge-utils virt-manager تعمل حزمة أدوات kvm-qemu على تشغيل وحدة KVM في النواة لتنفيذ الشفرة البرمجية الخاصّة بالآلة الافتراضية. كما أن هذه الأدوات تحجز الذاكرة العشوائية والموارد التي تحتاجها الآلات الافتراضيّة للعمل؛ زيادة على كونها تعمل على محاكاة عمل الأجهزة الطرفية Peripherals الملموسة التي يتوفّر عليها النظام المُضيف من أجل إتاحة أجهزة طرفية افتراضية للنظام الضيف. تتيح الحزمة libvirt-bin مجموعة من الأدوات للتخاطب مع قدرات الحوسبة الافتراضية التي يتوفّر عليها الجهاز المضيف. نذكر مثلا الأداة virsh التي يمكن من خلالها إنشاء آلات افتراضية، تعليقها (توقيف مؤقّت) أو إيقافها عن العمل. تحوي الحزمة bridge-utils الأدوات الضرورية لإنشاء أجهزة طرفية تعمل جسورا Bridge بين واجهات شبكة عدّة، ولإدارة هذه الأجهزة. من المهمّ توفّر هذه الميزة حتى يمكننا ضبط شبكة حواسيب تشمل الآلات الافتراضية. توفّر حزمة virt-manage واجهة رسومية لإدارة الآلات الافتراضية. الخطوة التاليّة هي إضافة المستخدم الحالي إلى مجموعة المستخدمين libvirtd حتى يمكنه استخدام الآلات الافتراضيّة التي ننشئها عن طريق KVM؛ إذ لا تُتاح هذه الوظيفة لغير أعضاء هذه المجموعة والحساب الجذر: $ sudo adduser zeine77 libvirtd نطلُب، من أجل التأكد من أن كل شيء على ما يُرام، سردَ الآلات الافتراضية المتوفّرة؛ وذلك باستخدام الأمر virsh على النحو التالي: $ virsh -c qemu:///system list Id Name State ---------------------------------------------------- لا توجد آلات افتراضية لحد الساعة، لذا لن تظهر معلومات عن هذه الآلات؛ وسيكتفي الأمر بعرض أسماء أعمدة (المعرّف Id، الاسم Name والحالة State) تصف معلومات تتعلّق بالآلات الافتراضية. تشير هذه النتيجة إلى أننا مستعدون الآن للبدء في استخدام KVM. إنشاء آلات افتراضية باستخدام KVM سنستخدم في هذا الجزء من المقال الأداة virt-manager للتخاطب مع KVM من أجل إنشاء آلات افتراضية. يمكن تشغيل virt-manager من قوائم سطح المكتب الذي تستخدمه (Gnome، KDE أو غيرهما) أو بتنفيذ الأمر virt-manager في سطر الأوامر. تظهر النافذة التاليّة بعد تشغيل الأداة. يظهر في واجهة البرنامج أنه متّصل بمضيف محلي يستخدم المُراقب QEMU/KVM. يمكن من هذه الواجهة الاتّصال بمضيفات Hosts بعيدة (توجد على أجهزة مغايرة للجهاز الذي تعمل عليه الأداة virt-manager)، وذلك عن طريق القائمة …File -> Add Connection ثم تحديد الخانة Connect to remote host وذكر البيانات المطلوبة. ننقر على زر Create a new virtual machine في واجهة virt-manager لإنشاء آلة افتراضية جديدة. تظهر نافذة جديدة تطلُب تحديد طريقة لتثبيت نظام التشغيل الضّيف على الآلة الافتراضية. توجد أكثر من طريقة كما يظهر في لقطة الشاشة أعلاه. سنحدّد خيار Local install media (وسيط تثبيت محليّ). تظهر النافذة التاليّة. يمكن عبر الواجهة الظاهرة في الصورة أعلاه الاختيار بين قرص مُدمَج (CD أو DVD) أو ملفّ ISO. سنحدّد الخيار الثاني (ملف ISO) وننقر على الزّر Browse. تظهر النافذة التالية. نستطيع عبر هذه النافذة إنشاء مساحة تخزين Storage volume افتراضية لاستخدامها مع الآلة؛ إلا أننا لن نفعل ذلك الآن وسننقر على الزّر Browse Local لتحديد المسار Path الذي يوجد عليه ملفّ ISO. يعود البرنامج بعد تحديد المسار إلى واجهة الاختيار الخاصة بوسيط التثبيت. نلاحظ أن البرنامج تعرّف تلقائيا على نوعية نظام التشغيل وإصداره اعتمادا على اسم وسيط التثبيت. ثم يطلب منا البرنامج ضبط إعدادات المعالج والذاكرة العشوائية الخاصّين بالآلة الافتراضيّة. نختار القيم المناسبة اعتمادا على العتاد المتوفّر على المُضيف ثم ننتقل لإعدادات التخزين. يمكن تحديد أحد خيارين؛ إما إنشاء مساحة تخزين افتراضية جديدة أو اختيار مساحة تخزين افتراضية موجودة سلفا. بما أننا لم نضبُط مساحة تخزين قبلًا فسنحدّد الخيار الأول. ثم ننتقل للخطوة الأخيرة وهي تحديد اسم للآلة الافتراضية. إن أردت تخصيص عمليّة التثبيت فبإمكانك تحديد الخيار Customize configuration before install (تخصيص الإعدادات قبل التثبيت). ثم ننقر على زر Finish. تبدأ الآلة الافتراضية بالعمل مباشرة وتظهر في واجهة برنامج virt-manager شاشةُ التثبيت الخاصّة بنظام التشغيل الضيف على الآلة الافتراضية. توجد في واجهة virt-manager أزرار للتحكّم في الآلة الافتراضية: إعادة التشغيل Reboot، الإيقاف Shut Down، فرض إعادة التعيين Force reset، فرض الإيقاف Force off (يشبه فصل حاسوب عن الطاقة دون إيقاف نظام التشغيل) وحفظ حالة الآلة Save. كما يمكن عن طريق زرّ Open فتح نافذة خاصّة للآلة الافتراضية يمكن عبرها أخذ لقطات سريعة Snapshots. تخزّن اللقطات السريعة جميع البيانات الموجودة على الآلة ويمكن الرجوع إلى هذه اللقطات في حالات مثل حدوث مشكل مع الآلة الافتراضية، توقفها عن العمل أو لإنشاء آلة افتراضية مطابقة لها تماما. ترجمة - بتصرّف - لمقال How to Create Virtual Machines in Linux Using KVM (Kernel-based Virtual Machine) – Part 1 لصاحبه Mohammad Dosoukey.
  3. استخدم اسم المشروع الذي خصّصه لك Heroku بعد تنفيذ الأمر create (راجع مخرجات الأمر heroku create)؛ nameless-chamber-90421 هو اسم المشروع الذي أعطاه Heroku لي عند كتابة الدرس وليست لديك صلاحيات الوصول إليه.
  4. يتناول هذا المقال المفاهيم الأساسيّة للاستيثاق باستخدام LDAP: ماهيّته، متى يُستخدَم ولماذا؛ وكيفيةَ ضبط خادوم LDAP وإعداد عميل للاستيثاق عن طريقه اعتمادا على Red Hat Enterprise Linux 7. سنركّز في هذا الدّرس على الاستيثاق المعتمد على LDAP رغم وجود طرق أخرى للاستيثاق. بيئة المختبر سنفترض وجود بيئة اختبار مكوّنة من جهازيْن تشغّلهما توزيعة RHEL 7: الخادوم: 192.168.2.100 واسم نطاقه المعرَّف بالكامل academy1.virtuallab.dev. العميل: 192.168.2.200 واسم نطاقه المعرَّف بالكامل ldapclient.virtuallab.dev. راجع مقال إنشاء شبكة داخلية افتراضية باستخدام Oracle VirtualBox للمزيد حول إنشاء هذه البيئة باستخدام Oracle VirtualBox، ومقال حول إعداد أسماء المضيفات. ما هو LDAP؟ يعرفّ LDAP (اختصار لـLightweight Directory Access Protocol، الميثاق الخفيف للوصول إلى الدّليل) مجموعة من البروتوكولات التي تسمح لعميل بالوصول إلى معلومات مخزّنة مركزيًّا عبر الشبكة. يتعلّق الأمر بمعلومات يُتاح الوصول إليها من أماكن مختلفة أو لمستخدمين كثر؛ مثل صدفات الدّخول (الولوج) Login shells، مسارات الوصول إلى المجلّدات الشخصيّة للمستخدمين أو معلومات أخرى - عناوين أشخاص، أرقام هواتف - عن مستخدمي النظام، على سبيل المثال لا الحصر. جعلُ هذه المعلومات في مكان مركزي يسهّل من صيانتها وتحديثها ويعني أنه يمكن لأي شخص الوصول إليها إذا كان لديه التصريح بذلك. يدور LDAP حول مفاهيم أساسية ثلاثة: مَدخَل Entry: يُمثّل المَدخَل في LDAP معلومة أو وحدة معلومات، ويُعرَّف باسم مُميَّز Distinguished name. خاصيّة Attribute: وهي بيانات تتعلّق بالمَدخَل. قيم Values: تُسنَد لكلّ خاصيّة قيمة أو مجموعة قيم تفصِل بينها مسافة. يُشار إلى القيمة الوحيدة في المَدخَل (أي التي لا توجد إلا مرة واحدة في خاصيّات المدخل) بالاسم المُميَّز النسبي Relative Distinguished Name. سنرى في الخطوة التاليّة كيفية تثبيت LDAP على كلّ من الخادوم والعميل. تثبيت LDAP وإعداده على الخادوم والعميل يُنفّذ برنامج OpenLDAP مبادئ LDAP على RHEL 7؛ يمكن تثبيته على الخادوم والعميل على التوالي بالأمرين التاليّين: # yum update && yum install openldap openldap-clients openldap-servers # yum update && yum install openldap openldap-clients nss-pam-ldapd تحوي الحزمة nss-pam-ldapd التي نثبّتها على العميل مجموعة دوال مهمّتها البحث عن معلومات في دليل LDAP والاستيثاق من المستخدمين بناءً على المعلومات المتوفّرة على خادوم LDAP. يجب أن نعدّ بضعة أمور بعد اكتمال التثبيت. تأكّد من SELinux يسمح لـLDAP بالعمل عن طريق تفعيل الإعدادات التاليّة على كلّ من الخادوم والعميل. لا تنس استخدام الخيار P- حتى تستمر التعديلات لما بعد إعادة تشغيل النّظام: # setsebool -P allow_ypbind=1 authlogin_nsswitch_use_ldap=1 يتطلّب الاستيثاق عبر LDAP تفعيل الإعداد allow_ypbind، بينما تحتاج برامج أخرى تفعيل الإعداد authlogin_nsswitch_use_ldap حتى يمكنها استخدام LDAP للاستيثاق. ثم نفعّل خدمة slapd التي تنصِت للاتصالات القادمة إلى خادوم LDAP، مبدئيّا على المنفذ 389 وتجيب على الطلبات التي تتلقّاها عبر هذه الاتصالات: # systemctl enable slapd.service # systemctl start slapd.service تذكّر أن نظام التمهيد SystemD يمكّنك من تعطيل الخدمة، إعادة تشغيلها أو إيقافها: # systemctl disable slapd.service # systemctl restart slapd.service # systemctl stop slapd.service تعمل خدمة slapd بصلاحيّات الحساب ldap (وهو ما يمكن التأكد منه بتنفيذ الأمر ps -e -o pid,uname,comm | grep slapd)، الأمر الذي يعني أن هذا الحساب يجب أن يكون مالكَ المجلّد var/lib/ldap/ من أجل أن تستطيع خدمة slapd تعديل مداخل LDAP التي تُنشئها الأدوات الإداريّة، التي لا تعمل إلا بصلاحيّات الحساب الجذر، في المجلّد المذكور. تأكّد قبل تغيير ملكيّة المجلّد var/lib/ldap/ من نسخ نموذج ملفّ الإعداد لقاعدة بيانات LDAP: # cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG # chown -R ldap:ldap /var/lib/ldap ضبط الحساب الإداري لـOpenLDAP وتعيين كلمة سرّ له: # slappasswd مثل ما يظهر في الصّورة التالية: ثم ننشئ ملفّ LDIF باسم ldaprootpasswd.ldif. ملفّات LDIF (اختصار لـ LDAP Data Interchange Format، صيغة تبادل البيانات في LDAP) هي تمثيل للبيانات الموجودة في خادوم LDAP والتغيرات التي تطرأ عليها. نضع البيانات التاليّة في الملفّ ldaprootpasswd.ldif: dn: olcDatabase={0}config,cn=config changetype: modify add: olcRootPW olcRootPW: {SSHA}PASSWORD حيث: PASSWORD: كلمة السّر التي حصلنا عليها أعلاه. cn=config: تشير إلى خيار إعداد عامّ. olcDatabase: اسم قاعادة بيانات معيّنة، توجد عادة على المسار etc/openldap/slapd.d/cn=config/. يُضيف ملفّ ldaprootpasswd.ldif مدخلا إلى دليل LDAP. يشير كلّ سطر في هذا المدخل إلى خاصيّة وقيمتها اللتين تفصل بينهما نقطتان عموديّتان :؛ أي أن changetype، add، dn وolcRootPW خاصيّات توجد قيمها على نفس السّطر، يمين النقطتين. تنبغي المحافظة في الخطوات المواليّة على نفس الأسماء الشائعة =Common Names, cn المستخدمة أعلاه. نضيف الآن مدخلا إلى دليل LDAP باستخدام الأمر ldapadd وتحديد عنوان URI الخاصّ بالخادوم وملفّ LDIF الخاصّ بالمدخل على النحو التالي: # ldapadd -Y EXTERNAL -H ldapi:/// -f ldaprootpasswd.ldif ثم نضيف تعريفات للدليل باستيراد الأمثلة الموجودة في المجلّد etc/openldap/schema/: # for def in cosine.ldif nis.ldif inetorgperson.ldif; do ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/$def; done جعل LDAP يستخدم اسم النطاق في قاعدة بياناته. dn:olcDatabase={1}monitor,cn=config changetype:modify replace: olcAccess olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.base="cn=Manager,dc=virtuallab,dc=dev" read by * none dn:olcDatabase={2}hdb,cn=config changetype: modify replace: olcSuffix olcSuffix: dc=virtuallab,dc=dev dn: olcDatabase={2}hdb,cn=config changetype: modify replace: olcRootDN olcRootDN: cn=Manager,dc=virtuallab,dc=dev dn: olcDatabase={2}hdb,cn=config changetype: modify add: olcRootPW olcRootPW: {SSHA}07/TOeaEPDlpTscePfA5kyij9mmepdr0 dn: olcDatabase={2}hdb,cn=config changetype: modify add: olcAccess olcAccess: {0}to attrs=userPassword,shadowLastChange by dn="cn=Manager,dc=virtuallab,dc=dev" write by anonymous auth by self write by * none olcAccess: {1}to dn.base="" by * read olcAccess: {2}to * by dn="cn=Manager,dc=virtuallab,dc=dev" write by * read نستخدم الأمر ldapmodify للتعديل على مَداخل الدليل: # ldapmodify -Y EXTERNAL -H ldapi:/// -f ldapdomain.ldif ننشئ ملفّ LDIF باسم baseldapdomain.ldif ونحدّد فيه مداخل لإضافتها إلى الدليل: dn: dc=virtuallab,dc=dev objectClass: top objectClass: dcObject objectclass: organization o: virtuallab dev dc: virtuallab dn: cn=Manager,dc=virtuallab,dc=dev objectClass: organizationalRole cn: Manager description: Directory Manager dn: ou=People,dc=virtuallab,dc=dev objectClass: organizationalUnit ou: People dn: ou=Group,dc=virtuallab,dc=dev objectClass: organizationalUnit ou: Group ثم نضيفها إلى الدليل بتنفيذ الأمر ldapadd (مع تحديد اسم النطاق المناسب): # ldapadd -x -D cn=Manager,dc=virtuallab,dc=dev -W -f baseldapdomain.ldif ملحوظة: أدخل كلمة السّر التي أنشأتها سابقا عندما تُطلب منك. ننشئ حسابَ مستخدم لإضافته إلى دليل LDAP: # adduser ldapuser نبدأ بإنشاء ملفّ LDIF باسم ldapgroup.ldif سنستخدمه لإضافة المجموعة التي ينتمي إليها المستخدم السّابق إلى الدّليل: # nano ldapgroup.ldif نضيف المحتوى التالي إلى الملفّ: dn: cn=Manager,ou=Group,dc=virtuallab,dc=dev objectClass: top objectClass: posixGroup gidNumber: 1012 قيمة الخاصيّة gidNumber هي معرّف المجموعة التي ينتمي إليها المستخدم ldapuserالسابق. يمكن الحصول عليه بتنفيذ الأمر id -g ldapuser. ننفذ الأمر ldapaddعلى النحو التالي لإضافة مدخل لمجموعة المستخدم إلى الدليل: # ldapadd -x -W -D "cn=Manager,dc=virtuallab,dc=dev" -f ldapgroup.ldif نعرّف في ملفّ LDIF جديد باسم ldapuser.ldif بيانات المستخدم ldapuser (استخدم الأمر slappasswd لإنشاء كلمة سرّ للمستخدم وإضافتها للملف): dn: uid=ldapuser,ou=People,dc=virtuallab,dc=dev objectClass: top objectClass: account objectClass: posixAccount objectClass: shadowAccount cn: ldapuser uid: ldapuser uidNumber: 1009 gidNumber: 1012 homeDirectory: /home/ldapuser userPassword: {SSHA}9A93CS4LCUx9L8s6HPw1PB3ClH5JEI0U loginShell: /bin/bash gecos: ldapuser shadowLastChange: 0 shadowMax: 0 shadowWarning: 0 ثم ننفّذ الأمر: # ldapadd -x -D cn=Manager,dc=virtuallab,dc=dev -W -f ldapuser.ldif يمكن باستخدام الأمر ldapdelete حذفُ نفس المستخدم من الدليل على النحو التالي (لن نفعل ذلك هنا): # ldapdelete -x -W -D cn=Manager,dc=virtuallab,dc=dev "uid=ldapuser,ou=People,dc=virtuallab,dc=dev" نطلُب من الجدار الناري السماح لخدمة LDAP بالعمل على المنفذ 389: # firewall-cmd --add-service=ldap # firewall-cmd --permanent --add-port=389/tcp # firewall-cmd reload ننتقل إلى العميل لتفعيل إمكانيّة التسجيل لمستخدمي LDAP. تأكّد من أن العميل يمكنه الوصول إلى الخادوم (والعكس). غيّر - إن لزم الأمر - ملفّ etc/hosts/ لإضافة عنوان الخادوم على العميل (والعكس، العميل على الخادوم). ننفّذ الأمر التالي - على العميل - لضبط طرق الاستيثاق عليه: # authoconfig-tui تظهر الواجهة التالية: تأكد من تحديد خياري Use LDAP وUse LDAP authentication بوضع علامة * أمامهما. استخدم الأسهم للانتقال بين الخيارات، والمسافة لتفعيل خيّار أو تعطيله؛ ثم Enter عند الوصول إلى زرّ Next. أضف في الشاشة المواليّة عنوان خادوم LDAP بالصّيغة ldap://academy1.virtuallab.dev ثم الاسم المُميّز القاعدي DN. لم نستخدم شهادة TLS لذا اترك الخيّار TLS غير محدّد. يمكننا الآن اختبار عمل LDAP على العميل بالبحث في الدليل عن المستخدم ldapuser: # ldapsearch -x cn=ldapuser -b dc=virtuallab,dc=dev يجب أن تظهر جميع معلومات المستخدم ldapuser في الدليل: # extended LDIF # # LDAPv3 # base <dc=virtuallab,dc=dev> with scope subtree # filter: cn=ldapuser # requesting: ALL # # ldapuser, People, virtuallab.dev dn: uid=ldapuser,ou=People,dc=virtuallab,dc=dev objectClass: top objectClass: account objectClass: posixAccount objectClass: shadowAccount cn: ldapuser uid: ldapuser uidNumber: 1009 gidNumber: 1012 homeDirectory: /home/ldapuser userPassword:: e1NTSEF9OUE5M0NTNExDVXg5TDhzNkhQdzFQQjNDbEg1SkVJMFU= (...) نفس الشيء عند استخدام الأمر getent على العميل: # getent passwd ldapuser ldapuser:x:1009:1012:ldapuser:/home/ldapuser:/bin/bash ترجمة - يتصرّف - لمقال RHCSA Series: Setting Up LDAP-based Authentication in RHEL 7 – Part 14 لصاحبه Gabriel Cánepa.
  5. الجدران النارية Firewalls هي أنظمة حماية تتحكّم في حركة البيانات القادمة إلى شبكة أو الخارجة منها، اعتمادا على مجموعة من القواعد المعرَّفة مسبقا؛ على سبيل المثال وجهة الحزم Packets، مصدرها أو نوعية البيانات. سنعرض في هذا الدرس لأساسيات FirewallD وهو البرنامج المبدئي لإدارة الجدار الناري في Red Hat Enterprise Linux 7، وIptables الذي هو الجدار الناري التقليدي في أنظمة لينكس، ويتوفّر أيضا في RHEL 7. مقارنة بين FirewallD وIptables يعمل الجداران الناريان FirewallD وIptables عن طريق التخاطب مع النواة عبر نفس الواجهة، أمر iptables؛ إلا أن الاختلاف بينهما يكمن في أن FirewallD يمكنه تعديل الإعدادات أثناء عمل النظام دون ضياع الاتّصالات الجارية. يجب أن يكون FirewallD مثبتا مبدئيا على RHEL 7، إلا أنه يمكن ألا يكون مفعلا. يمكن التحقّق منه بالأوامر التاليّة: # yum info firewalld firewall-config تُظهر نتيجة الأمر أعلاه أن الجدار الناري FirewallD مثبت فعلا، وكذلك حزمة firewall-config التي توفّر أداة في واجهة المستخدم لإدارة الجدار الناري. الجدار الناري مثبّت، يمكننا الآن التحقق من ما إذا كان مفعّلا أم لا: # systemctl status -l firewalld.service على الجانب الآخر، لا يُضمَّن جدار Iptables الناري مبدئيا في Red Hat Enterprise Linux 7؛ إلا أنه يمكن تثبيته بالأمر: # yum update && yum install iptables-services تُشغَّل الخدمتان وتُفعّلان مع الإقلاع عن طريق أوامر systemd الاعتيادية: # systemctl start firewalld.service # systemctl start iptables.service # systemctl enable firewalld.service # systemctl enable iptables.service يوجد ملفّ إعداد iptables على المسار etc/sysconfig/iptables/ (يجب أن تكون الحزمة مثبتة حتى يوجد الملفّ)؛ بينما توجد ملفات إعداد FirewallD موزعة بين المجلدين usr/lib/firewalld/ وetc/firewalld/. يمكن الحصول على معلومات أكثر عن هذه الأدوات بتنفيذ الأوامر: # man firewalld.conf # man firewall-cmd # man iptables راجع مقال أساسيات التعامل مع الصدفة Shell في Red Hat Enterprise Linux لطرق أخرى حول الحصول على المعلومات عن الأوامر في Red Hat Enterprise Linux 7. استخدام Iptables للتحكم في حركة البيانات عبر الشبكة سنذكُر في ما يلي أمثلة لإعداد Iptables على RHEL 7؛ تأكد من مراجعة مقال ما هو الجدار الناري وكيف يعمل؟ والمقالات المرتبطة به لفهم آلية عمل الجدار الناري بالتفصيل. السماح لحركة البيانات المتجهة إلى خادوم الوِب والصّادرة منه تستخدم خواديم الوِب المنفذين 80 و443 للإنصات للطلبات القادمة إلى الخادوم. المنفذ الأول 80 خاصّ بحركة البيانات العاديّة بينما يُستخدم المنفذ الثاني 443 للبيانات المؤمّنة. تطلُب الأوامر التالية من Iptables السماح بحركة البيانات الواردة والصّادرة عبر المنفذين 80 و443 في واجهة الشبكة enp0s3: # iptables -A INPUT -i enp0s3 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT # iptables -A OUTPUT -o enp0s3 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT # iptables -A INPUT -i enp0s3 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT # iptables -A OUTPUT -o enp0s3 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT حجب بيانات قادمة من شبكة محدّدة تحتاج أحيانا لمنع اتصالات واردة من شبكة تحدّدها، مثلا 192.168.1.0/24. يؤدّي Iptables هذه المهمة بتنفيذ الأمر التالي: # iptables -I INPUT -s 192.168.1.0/24 -j DROP يحجب الأمر السابق جميع الاتصالات القادمة من عنوان IP ضمن الشبكة الفرعية 192.168.1.0/24؛ يمكننا تخصيص الأمر بحجب الاتصالات القادمة من هذه الشبكة عبر المنفذ 22 دون غيره: # iptables -A INPUT -s 192.168.1.0/24 --dport 22 -j ACCEPT توجيه البيانات الواردة إلى وجهة أخرى يمكن استخدام RHEL 7 فاصلا بين شبكتين بحيث يعيد توجيه البيانات بينهما؛ يجب في هذه الحالة تفعيل إعادة توجيه عناوين IP على النظام بتحرير الملف etc/sysctl.conf/ وتعيين القيمة 1 للتعليمة net.ipv4.ip_forward: net.ipv4.ip_forward = 1 احفظ التعديلات ثم نفّذ الأمر لاعتمادها: # sysctl -p /etc/sysctl.conf سنفترض أن لدينا طابعة مربوطة بخادوم للطباعة يعمل على العنوان 192.168.0.10 ويُنصِت للطلبات القادمة عبر المنفذ 631. يمكن في هذه الحالة توجيه طلبات الطباعة القادمة إلى الجدار الناري على المنفذ 631 إلى خادوم الطباعة بالأمر التالي: # iptables -t nat -A PREROUTING -i enp0s3 -p tcp --dport 631 -j DNAT --to 192.168.0.10:631 ملحوظة: يجب تذكر أن Iptables يقرأ القواعد الأمنية بالتسلسل، لذا تأكد من القواعد المحدّدة بعد القواعد أعلاه لا تلغيها. نفس الشيء بالنسبة للسياسات المبدئية Default policies. جدار FirewallD الناري المناطق Zones هي أحد التغييرات التي أضافها جدار FirewallD؛ وهي درجات مختلفة من الموثوقيّة يمنحها مدير النظام للأجهزة والبيانات في الشبكة. يُستخدم الأمر التالي لسرد لائحة بالمناطق النشطة في FirewallD: # firewall-cmd --get-active-zones public interfaces: enp0s3 enp0s9 يظهر في نتيجة الأمر أعلاه أن المنطقة public التي توجد بها الواجهتان enp0s3 وenp0s9، نشطة. نستخدم الأمر التالي للحصول على جميع المعلومات المتوفرة عن منطقة (public في المثال): # firewall-cmd --zone=public --list-all السماح للخدمات بالمرور عبر الجدار الناري يتعرّف FirewallD تلقائيا على أسماء عدد من الخدمات، يمكن الحصول على لائحة بها بتنفيذ الأمر: # firewall-cmd --get-services تطلب الأوامر التالية من الجدار الناري السماح بمرور بيانات الخدمتين http (المنفذ 80) وhttps (المنفذ 443) وتفعيلها مع إقلاع النظام (permanent--): # firewall-cmd --zone=MyZone --add-service=http # firewall-cmd --zone=MyZone --permanent --add-service=http # firewall-cmd --zone=MyZone --add-service=https # firewall-cmd --zone=MyZone --permanent --add-service=https # firewall-cmd --reload إن لم تحدّد المنطقة عن طريق الخيار zone فستُسخدَم المنطقة المبدئيّة. استخدم remove مكان add إن أردت حذف القاعدة. توجيه البيانات يجب التأكد أولا من أن إخفاء العناوين IP masquerading مفعَّل بالنسبة للمنطقة المطلوبة: # firewall-cmd --zone=MyZone --query-masquerade yes # firewall-cmd --zone=public --query-masquerade no يظهر في نتيجة الأمر السابق أن إخفاء العناوين مفعَّل بالنسبة للمنطقة MyZone بينما هو معطَّل بالنسبة لـpublic. ملحوظة: إخفاء العناوين IP masquerading هو آلية في لينكس تشبه ترجمة العناوين Network address translation, NAT في الموجّهات Routers. تمكّن هذه الآلية - مثلا - مجموعة من الأجهزة من الاتّصال بالإنترنت باستخدام نفس عنوان IP؛ حيث يتولى الجهاز الذي يُفعَّل عليه إخفاء العناوين التخاطب مع العالم الخارجي ثم يعيد توجيه الحزم في الشبكة الداخلية. يمكن تفعيل إخفاء العناوين بالنسبة للمنطقة public على النحو التالي: # firewall-cmd --zone=public --add-masquerade يؤدي الأمر التالي نفس مهمة مثال التوجيه السابق باستخدام FirewallD بدلا من Iptables: # firewall-cmd --zone=public --add-forward-port=port=631:proto=tcp:toport=631:toaddr=192.168.0.10 لا تنس إعادة تحميل إعدادات الجدار الناري لاعتماد التعديلات: # firewall-cmd --reload يمكنك الحصول على أمثلة أخرى في درس إعداد خادوم وِب وخادوم FTP على Red Hat Enterprise Linux حيث شرحنا كيفية السماح للبيانات بالمرور عبر المنافذ التي يستخدمها عادة خادومُ الوِب وخادوم FTP وكيفية تغيير القاعدة في الجدار الناري عند تغيير المنفذ الذي تعمل عبره هذه الخدمات. تمكن أيضا الاستعانة بويكي FirewallD للمزيد من الأمثلة. ترجمة - بتصرّف - لمقال RHCSA Series: Firewall Essentials and Network Traffic Control Using FirewallD and Iptables – Part 11 لصاحبه Gabriel Cánepa.
  6. المسترجعات Accessors والمعدلات Mutators في Laravel

    المسترجِعات Accessors والمعدِّلات Mutators في Laravel هي مجموعة دوالّ مخصّصة يعرّفها المستخدم لتهيئة خواص النماذج Models. تُستخدم المسترجعات لتهيئة خواصّ النموذج عند طلب الحصول عليها من قاعدة البيانات، بينما تُستخدَم المعدّلات لتهيئة الخواصّ قبل حفظ النموذج في القاعدة. تعريف مسترجع تُسمى الدوال المسترجعة بالصيغة ()getFooAttribute حيث Foo هو اسم الخاصيّة التي نريد تهيئتها في الدالة، مع الانتباه إلى حالة الحرف الأول من الخاصية (حرف كبير Uppercase). سيستدعي Laravel تلقائيا هذه الدالة في كلّ مرة تبحث فيها عن قيمة الخاصيّة foo. لا يقتصر استخدام المسترجعات على سلاسل المحارف، بل يمكنك استخدامها لتهيئة أي نوع من البيانات تواريخ، أثمان، …إلخ. سنفترض أن لدينا نموذجا باسم Member (عضو) يحوي الخاصيّات التاليّة: first_name last_name email password last_visit settings created_at updated_at توجد من ضمن اللائحة أعلاه بضعة خاصيّات سيكون مفيدا لنا تطبيق المسترجعات عليها. على سبيل المثال، لا يهتمّ المستخدمون كثيرا بطريقة كتابة أسمائهم، لذا يمكننا استخدام المسترجعات للتأكد من أن الأسماء تُكتب بطريقة صحيحة. يحاكي المثال التالي إضافة مستخدم لم ينتبه كثيرا لطريقة كتابة بياناته: $user = App\Member::create([ 'first_name' => 'mirza', 'last_name' => 'pasic', 'email' => 'mirza.pasic@bosnadev.com', 'password' => '!supersecretpassword!', 'last_login' => Carbon\Carbon::now(), 'settings' => ['two_factor_aut' => false, 'session_time' => 1200], 'created_at' => Carbon\Carbon::now(), 'updated_at' => Carbon\Carbon::now() ]); يمكننا استخدام المسترجعات لتهيئة مُدخلات المستخدم: use Illuminate\Database\Eloquent\Model; /** * Class Member * @package App */ class Member extends Model { /** * التأكد من تهيئة الاسم الشخصي بعد الحصول على النموذج من قاعدة البيانات * * @param $value * @return string */ public function getFirstNameAttribute($value) { return ucfirst($value); } /** * التأكد من تهيئة الاسم العائلي بعد الحصول على النموذج من قاعدة البيانات * * @param $value * @return string */ public function getLastNameAttribute($value) { return ucfirst($value); } } سيعمل المسترجعان getFirstNameAttribute و getLastNameAttribute على تهيئة الحقلين first_name (الاسم الشخصي) وlast_name (الاسم العائلي) على التوالي لجعل الحرف الأول في كلّ واحد منهما يُكتب كبيرا (Uppercase)، بغضّ النظر عن الطريقة التي أدخلهما بها المستخدم. يمكن أيضا استخدام المسترجعات لدمج خاصيّتين في النموذج لتكوّنا واحدة جديدة. يمكن مثلا تعريف الاسم الكامل full_name بناء على الاسم الشخصي والاسم العائلي: /** * Get members full name * * @return string */ public function getFullNameAttribute() { return ucfirst($this->first_name) . ' ' . ucfirst($this->last_name); } ثم يمكننا استخدامه كما لو كان فعلا يوجد حقل باسم full_name في النموذج: $member = App\Member::find(1); echo $member->full_name; يمكنك إن أردت استخدام المسترجعات على أنواع بيانات أخرى. مثلا، لتهيئة التاريخ. نستخدم في المثال التالي الدالة getLastLoginAttribute لتهيئة تاريخ آخر دخول (الحقل last_login) بحيث يظهر بالصيغة d.m.Y (يمثّل الحرف d اليوم، الحرفm الشهر وY السنة مكتوبة بأربعة أرقام): /** * Custom format for the last login date * * @param $value * @return string */ public function getLastLoginAttribute($value) { return \Carbon\Carbon::parse($value)->format('d.m.Y.'); } ثم نستخدم الحقل last_login كما في المثال التالي: $member = App\Member::find(1); echo $member->last_login; يظهر الحقل كما يلي: 11.07.2016. تعريف معدل تشبه آلية تسميّة المعدِّل تعريفَ المسترجع، مع فرق إحلال set مكان get. إذا أردنا تعريف معدِّل للخاصيّة foo فسيكون اسمُه setFooAttribute. نعود لمثال النموذج Member السابق. نريد الآن أن نتأكد من تهيئة اسم العضو قبل حفظ النموذج في قاعدة البيانات: /** * التأكد من تهيئة الاسم الشخصي **قبل** حفظ النموذج * * @param $value * @return string */ public function setFirstNameAttribute($value) { $this->attributes['first_name'] = ucfirst($value); } /** * التأكد من تهيئة الاسم العائلي **قبل** حفظ النموذج * * @param $value * @return string */ public function setLastNameAttribute($value) { $this->attributes['last_name'] = ucfirst($value); } ربما لاحظت أن الدالة لا ترجِع أية قيمة. ما يحدُث هو أننا نضبُط الخاصيّة بالقيمة التي نريد مباشرة. نتأكد بهذه الطريقة أن الاسمين الشّخصي والعائلي سيكونان مهيأيْن دائما بالصيغة التي نريد. أمثلة على المسترجعات والمعدلات رأينا في الفقرات السابقة أمثلة لاستخدامات سهلة للمسترجعات والمعدّلات؛ إلا أن هذه الدوال يمكن أن تُستخدَم لأمور أكثر تخصيصا كما سنرى في الأمثلة التالية. حماية كلمات السّر يمكن استخدام المعدِّلات لتجزئة كلمة السّر Password hashing قبل حفظها في قاعدة البيانات؛ مثلا: public function setPasswordAttribute($value) { $this->attributes['password'] = Hash::make($value); } تتأكد بهذه الطريقة أن كلمة السّر لن تُحفَظ أبدا بصيغتها المقروءة في قاعدة البيانات، وهو ما يعدّ إجراء أمنيًّا أساسيا. استخدمنا في المثال السابق صنف Hash الذي يوفّره Laravel مبدئيا، ولكن يمكنك استخدام دوال تعميّة إن أردت، مثل ()bcrypt. الترميز بصيغة Json إن نظرت إلى نموذج Member السابق فستجد أنه يحوي خاصيّة باسم settings تُستخدَم لحفظ تفضيلات العضو الشخصيّة وخيارات أخرى يتيحها التطبيق. يمكن استخدام مصفوفة لإدارة هذه الخيارات وحفظها في قاعدة البيانات بصيغة Json. تتيح قواعد بيانات مثل PostgreSQL نوع البيانات Json في حقول الجدول منذ زمن، كما أن MySQL أتاحت نوع البيانات هذا في الإصدار 5.7.8. ملحوظة: دعم نوع البيانات Json في MySQL لا زال في بداياته، وقد تواجه مشاكل عند استخدامه. بالنسبة لخاصيّة settings فسنحتاج لمعدِّل يخزّن البيانات بصيغة Json في القاعدة ومسترجِع لتحويل Json إلى مصفوفة من سلسلة محارف: /** * Make sure that we get an array from JSON string * * @param $value * @return array */ public function getSettingsAttribute($value) { return json_decode($value, true); } /** * Encode an array to a JSON string * * @param $value */ public function setSettingsAttribute($value) { $this->attributes['settings'] = json_encode($value); } المثال كاملا في ما يلي الخطوات اللازمة لإنشاء مثال عملي يعتمد على النموذج المقدّم في هذا الدرس. نفترض وجود Laravel مثبّت بقاعدة بيانات مضبوطة. إنشاء التهجير والنموذج php artisan make:model Member -m Model created successfully. Created Migration: 2016_07_04_020531_create_members_table التعديل على التهجير public function up() { Schema::create('members', function (Blueprint $table) { $table->increments('id'); $table->string('first_name'); $table->string('last_name'); $table->string('email'); $table->string('password'); $table->date('last_login'); $table->string('settings'); $table->timestamps(); }); } التعديل على النموذج في ما يلي الشفرة الكاملة للنموذج Member مع المسترجعات والمعدِّلات. <?php namespace App; use Illuminate\Support\Facades\Hash; use Illuminate\Database\Eloquent\Model; /** * Class Member * @package App */ class Member extends Model { /** * @var array */ protected $fillable = ['first_name', 'last_name', 'email', 'password', 'last_login', 'settings', 'created_at', 'updated_at']; /** * التأكد من تهيئة الاسم الشخصي بعد الحصول على النموذج من قاعدة البيانات * * @param $value * @return string */ public function getFirstNameAttribute($value) { return ucfirst($value); } /** * التأكد من تهيئة الاسم العائلي بعد الحصول على النموذج من قاعدة البيانات * * @param $value * @return string */ public function getLastNameAttribute($value) { return ucfirst($value); } /** * الاسم الكامل للعضو * * @return string */ public function getFullNameAttribute() { return ucfirst($this->first_name) . ' ' . ucfirst($this->last_name); } /** * تهيئة تاريخ آخر زيارة * * @param $value * @return string */ public function getLastLoginAttribute($value) { return \Carbon\Carbon::parse($value)->format('d.m.Y.'); } /** * التأكد من تهيئة الاسم الشخصي **قبل** حفظ النموذج * * @param $value * @return string */ public function setFirstNameAttribute($value) { $this->attributes['first_name'] = ucfirst($value); } /** * التأكد من تهيئة الاسم العائلي **قبل** حفظ النموذج * * @param $value * @return string */ public function setLastNameAttribute($value) { $this->attributes['last_name'] = ucfirst($value); } /** * تهيئة كلمة السّر **قبل** حفظها * * @param $value */ public function setPasswordAttribute($value) { $this->attributes['password'] = Hash::make($value); } /** * الحصول على مصفوفة من حقل بصيغة * Json * * @param $value * @return array */ public function getSettingsAttribute($value) { return json_decode($value, true); } /** * الترميز بصيغة * Json * قبل حفظ الحقل * @param $value */ public function setSettingsAttribute($value) { $this->attributes['settings'] = json_encode($value); } } استخدام النموذج Route::get('members', function() { $user = App\Member::create([ 'first_name' => 'mirza', 'last_name' => 'pasic', 'email' => 'mirza.pasic@bosnadev.com', 'password' => '!supersecretpassword!', 'last_login' => Carbon\Carbon::now(), 'settings' => ['two_factor_aut' => true, 'session_time' => 1200], 'created_at' => Carbon\Carbon::now(), 'updated_at' => Carbon\Carbon::now() ]); $member = App\Member::find(1); echo $member->last_login . '<br>'; echo $member->full_name . '<br>'; }); ترجمة -وبتصرّف- للمقال Laravel Accessors and Mutators لصاحبه Mirza Pasic.
  7. يتكوّن نظام التمهيد systemd من مجموعة من الأدوات التي تمثّل منصة مركزية لإدارة نظام لينكس وإعداده. تُستخدم أداة systemctl للتحكّم في systemd وإدارة الخدمات المرتبطة به. يهدف هذا المقال إلى إلقاء الضوء على كيفية إدارة النظام والخدمات على نظام تشغيل يستخدم systemd للتمهيد. أساسيات systemd وsystemctl التحقق من أن systemd مثبّت وإصداره: $ systemd --version systemd 229 +PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ -LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN يظهر من المثال أعلاه أن نظام التمهيد systemd مثبت وأن لدينا الإصدار 229. التحقق من مكان تواجد الملفات التنفيذية والمكتبات البرمجية الخاصّة بـ وsystemctl: $ whereis systemd systemd: /usr/lib/systemd /bin/systemd /etc/systemd /lib/systemd /usr/share/systemd /usr/share/man/man1/systemd.1.gz $ whereis systemctl systemctl: /bin/systemctl /usr/share/man/man1/systemctl.1.gz التحقق من حالة عمل systemd يمكن استخدام الأمر ps لسرد العمليات Processes النشطة ثم عزل تلك المتعلقة بـsystemd، وذلك على النحو التالي: $ ps -eaf | grep [s]ystemd root 1000 1 0 12:23 ? 00:00:00 /lib/systemd/systemd-journald root 1029 1 0 12:23 ? 00:00:00 /lib/systemd/systemd-udevd systemd+ 2639 1 0 12:23 ? 00:00:00 /lib/systemd/systemd-timesyncd message+ 2781 1 0 12:23 ? 00:00:01 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation root 2862 1 0 12:23 ? 00:00:00 /lib/systemd/systemd-logind sddm 3284 1 0 12:23 ? 00:00:00 /lib/systemd/systemd --user academy 3532 1 0 12:25 ? 00:00:00 /lib/systemd/systemd --user تحمل عمليّة systemd المعرِّف 1. استخدمنا الخيار e- مع الأمر ps لسرد جميع العمليات، ثم حدّدنا العمليات التي لا ترأس جلسة Session leaders (العمليات التي يساوي معرّف العمليّة السّلف Parent Id معرّفَ الجلسة Session Id). استخدمنا الخيار f- لتهيئة مخرجات الأمر التي طبّقنا عليه الأمر grep لتحديد تلك التي توافق التعبير النمطي s]ystemd]. تحليل متتالية الإقلاع في systemd تُستخدَم أداة systemd-analyze لتحليل متتالية الإقلاع: $ systemd-analyze Startup finished in 9.314s (firmware) + 2.897s (loader) + 9.290s (kernel) + 46.672s (userspace) = 1min 8.175s نضيف المعطى blame للأمر أعلاه من أجل الحصول على الوقت الذي استغرقته كل خدمة للإقلاع: $ systemd-analyze blame 40.880s systemd-suspend.service 25.010s apt-daily.service 14.173s dev-sda7.device 10.530s dnsmasq.service 10.228s click-system-hooks.service 7.909s accounts-daemon.service 7.908s ModemManager.service 7.120s NetworkManager-wait-online.service 7.084s gpu-manager.service (...) يمكن أيضا تحليل الوقت المستغرق للعمليات الحرجة باستخدام المعطى critical-chain الذي يطبع شجرة بتتالي العمليات التي تنتظر بقية العمليات إقلاعها: $ systemd-analyze critical-chain The time after the unit is active or started is printed after the "@" character. The time the unit takes to start is printed after the "+" character. graphical.target @41.348s └─multi-user.target @41.348s └─apache2.service @34.735s +6.612s └─network-online.target @34.717s └─NetworkManager-wait-online.service @27.596s +7.120s └─NetworkManager.service @21.672s +5.913s └─dbus.service @21.471s └─basic.target @21.470s └─sockets.target @21.470s └─snapd.socket @21.441s +17ms └─sysinit.target @21.391s └─apparmor.service @20.785s +605ms └─local-fs.target @20.772s └─run-user-123.mount @35.991s └─local-fs-pre.target @15.110s └─systemd-remount-fs.service @15.038s +27ms └─systemd-journald.socket @3.530s └─-.slice @3.497s تظهر بعد علامة @ المدة التي فُعلت بعدها الوحدة، في ما يظهر الوقت الذي استغرقته الوحدة للإقلاع بعد علامة +. يمكن تمرير اسم وحدة إلى الأمر أعلاه لقصر السّرد على العمليات التي تنتظر الوحدة إقلاعها: $ systemd-analyze critical-chain apache2.service The time after the unit is active or started is printed after the "@" character. The time the unit takes to start is printed after the "+" character. └─network-online.target @35.533s └─NetworkManager-wait-online.service @29.424s +6.108s └─NetworkManager.service @22.174s +7.234s └─dbus.service @20.998s └─basic.target @20.976s └─sockets.target @20.976s └─snapd.socket @20.919s +46ms └─sysinit.target @20.902s └─apparmor.service @19.691s +1.193s └─local-fs.target @19.681s └─run-user-123.mount @37.402s └─local-fs-pre.target @14.915s └─systemd-remount-fs.service @14.866s +32ms └─system.slice @3.541s └─-.slice @3.508s سرد الوحدات يعمل الأمر systemctl عند استخدام المعطى list-unit-files على سرد قائمة بجميع الوحدات الموجودة في النظام: $ systemctl list-unit-files UNIT FILE STATE proc-sys-fs-binfmt_misc.automount static org.freedesktop.hostname1.busname static org.freedesktop.locale1.busname static org.freedesktop.login1.busname static org.freedesktop.network1.busname static org.freedesktop.resolve1.busname static org.freedesktop.systemd1.busname static org.freedesktop.timedate1.busname static dev-hugepages.mount static dev-mqueue.mount static proc-sys-fs-binfmt_misc.mount static sys-fs-fuse-connections.mount static sys-kernel-config.mount static sys-kernel-debug.mount static acpid.path enabled cups.path enabled (...) ملحوظة: يمكن للوحدة أن تكون خدمة، نقطة تركيب Mount point، مقبس شبكة Socket أو جهازا طرفيا Device. يمكنك الاقتصار على الوحدات العاملة حاليا بالمعطى list-units: $ systemctl list-units UNIT LOAD ACTIVE SUB DESCRIPTION proc-sys-fs-binfmt_misc.automount loaded active running Arbitrary Executable File Formats File System Automoun sys-devices-pci0000:00-0000:00:02.0-drm-card0-card0\x2deDP\x2d1-intel_backlight.device loaded active plugged /sys/devices/pci0000: sys-devices-pci0000:00-0000:00:03.0-sound-card0.device loaded active plugged Broadwell-U Audio Controller sys-devices-pci0000:00-0000:00:14.0-usb1-1\x2d3-1\x2d3:1.0-net-enx582c80139263.device loaded active plugged E353/E3131 sys-devices-pci0000:00-0000:00:14.0-usb1-1\x2d4-1\x2d4:1.0-bluetooth-hci0.device loaded active plugged /sys/devices/pci0000:00/000 sys-devices-pci0000:00-0000:00:1b.0-sound-card1.device loaded active plugged Wildcat Point-LP High Definition Audio Controller (…) كما يمكن عزل الوحدات التي أخفقت بالمعطى failed--: $ systemctl --failed UNIT LOAD ACTIVE SUB DESCRIPTION ● snapd.refresh.service loaded failed failed Automatically refresh installed snaps ● systemd-suspend.service loaded failed failed Suspend LOAD = Reflects whether the unit definition was properly loaded. ACTIVE = The high-level unit activation state, i.e. generalization of SUB. SUB = The low-level unit activation state, values depend on unit type. 2 loaded units listed. Pass --all to see loaded but inactive units, too. To show all installed unit files use 'systemctl list-unit-files'. التحقق من تفعيل خدمة يطلُب الأمر التالي التحقق من أن خدمة الجدولة Cron مفعَّلة (تعمل مع إقلاع النظام): $ systemctl is-enabled cron.service enabled يظهر من نتيجة الأمر أن الخدمة مفعَّلة enabled. التحقق من حالة خدمة نتحقق في الأمر التالي من حالة الخدمتين mysql وapache2: systemctl status apache2.service ● apache2.service - LSB: Apache2 web server Loaded: loaded (/etc/init.d/apache2; bad; vendor preset: enabled) Drop-In: /lib/systemd/system/apache2.service.d └─apache2-systemd.conf Active: active (running) since Wed 2016-09-14 12:23:56 GMT; 4h 31min ago يظهر في نتيجة تنفيذ الأمرين أعلاه أن mysql غير مفعَّلة وليست نشطة أثناء تنفيذ الأمر؛ أما الخدمة apache2 فهي مفعَّلة وتعمل منذ أربع ساعات. التحكم في الخدمات وإداراتها بـ systemctl سرد جميع الخدمات يسرُد الأمر التالي جميع خدمات النظام بغضّ النظر عن حالتها (مفعَّلة أو معطَّلة): $ systemctl list-unit-files --type=service UNIT FILE STATE accounts-daemon.service enabled acpid.service disabled apport-forward@.service static apt-daily.service static atd.service enabled autovt@.service enabled bootlogd.service masked bootlogs.service masked bootmisc.service masked cgmanager.service enabled cgproxy.service enabled checkfs.service masked checkroot-bootclean.service masked checkroot.service masked (...) تشغيل خدمة (apache2)، إيقافها، إعادة تشغيلها أو إعادة تحميلها: تبدأ الأوامر التالية تشغيل الخدمة apache2، تعيد تحميلها، تعيد تشغيلها وتوقفها على التوالي (تحتاج لصلاحيات إدارية): # sudo systemctl start apache2 # sudo systemctl restart apache2 # sudo systemctl stop apache2 # sudo systemctl reload apache2 apache2.service is not active, cannot reload. # sudo systemctl start apache2 # sudo systemctl reload apache2 # sudo systemctl status apache2 ● apache2.service - LSB: Apache2 web server Loaded: loaded (/etc/init.d/apache2; bad; vendor preset: enabled) Drop-In: /lib/systemd/system/apache2.service.d └─apache2-systemd.conf Active: active (running) since Wed 2016-09-14 17:15:11 GMT; 17s ago لا تُظهر الأوامر أعلاه مخرجات عند تنفيذها بدون مشاكل. استخدم أمر التحقق status لمعرفة حالة الخدمة. تفعيل خدمة أو تعطيلها تُسمّى الخدمات التي تبدأ بالعمل مع إقلاع النظام بالخدمات المفعَّلة Enabled، وعكسُها الخدمات المعطّلة Disabled. أما الخدمات النشطة Active فهي الخدمات العاملة حاليا (تُشغَّل بالأمر start). يستفسر الأمر التالي عن نشاط الخدمة apache2 (تعمل أم لا): $ systemctl is-active apache2.service active نستخدم الأمر disable لتعطيل خدمة وenable لتفعيلها: # systemctl enable apache2.service # systemctl disable apache2.service إخفاء خدمة يمنع الإخفاء Masking تشغيل خدمة. يمكن إخفاء الخدمة apache2 على النحو التالي: # systemctl mask apache2.service Created symlink from /etc/systemd/system/apache2.service to /dev/null. ولإلغاء الإخفاء: $ sudo systemctl unmask apache2.service Removed symlink /etc/systemd/system/apache2.service. الإيقاف الإجباري لخدمة بـsystemctl # systemctl kill apache2 # sudo systemctl status apache2 ● apache2.service - LSB: Apache2 web server Loaded: loaded (/etc/init.d/apache2; bad; vendor preset: enabled) Drop-In: /etc/systemd/system/apache2.service.d └─50-CPUShares.conf /lib/systemd/system/apache2.service.d └─apache2-systemd.conf Active: inactive (dead) Docs: man:systemd-sysv-generator(8) التحكم في نقاط التركيب وإداراتها بـsystemctl سرد جميع نقاط التركيب في النظام $ systemctl list-unit-files --type=mount UNIT FILE STATE dev-hugepages.mount static dev-mqueue.mount static proc-sys-fs-binfmt_misc.mount static sys-fs-fuse-connections.mount static sys-kernel-config.mount static sys-kernel-debug.mount static tmp.mount disabled 7 unit files listed. إدارة نقاط التركيب يمكن بالأوامر التالية تشغيل نقطة تركيب، فصلها، إعادة تركيبها والتحقق من حالتها على التوالي: # systemctl start tmp.mount # systemctl stop tmp.mount # systemctl restart tmp.mount # systemctl reload tmp.mount # systemctl status tmp.mount tmp.mount - Temporary Directory Loaded: loaded (/usr/lib/systemd/system/tmp.mount; disabled) Active: active (mounted) since Wed 2016-09-14 17:36:11 GMT;; 2min 48s ago Where: /tmp What: tmpfs (...) تفعيل نقطة تركيب أو تعطيلها يمكن بطريقة مشابهة للخدمات تفعيل نقاط التركيب أوتعطيلها: # systemctl enable tmp.mount # systemctl disable tmp.mount إخفاء نقطة تركيب يُستخدَم الأمر mask لإخفاء نقطة تركيب على النحو التالي: # systemctl mask tmp.mount Created symlink from /etc/systemd/system/tmp.mount to /dev/null. ولإلغاء الإخفاء: # systemctl unmask tmp.mount Removed symlink /etc/systemd/system/tmp.mount التحكّم في مقابس الشبكة بـsystemctl سرد جميع المقابس $ systemctl list-unit-files --type=socket UNIT FILE STATE acpid.socket enabled apport-forward.socket enabled avahi-daemon.socket enabled cups.socket enabled dbus.socket static lxd.socket masked saned.socket disabled snapd.socket enabled syslog.socket static systemd-bus-proxyd.socket static systemd-fsckd.socket static systemd-initctl.socket static systemd-journald-audit.socket static systemd-journald-dev-log.socket static systemd-journald.socket static systemd-networkd.socket disabled systemd-rfkill.socket static systemd-udevd-control.socket static systemd-udevd-kernel.socket static uuidd.socket enabled 20 unit files listed. تشغيل مقبس (cups)، إعادة تشغيله، إعادة تحميله أو إيقافه: # systemctl start cups.socket # systemctl restart cups.socket # systemctl reload cups.socket # systemctl stop cups.socket $ systemctl status cups.socket ● cups.socket - CUPS Scheduler Loaded: loaded (/lib/systemd/system/cups.socket; enabled; vendor preset: enabled) Active: active (listening) since Thu 2016-09-15 14:39:47 GMT; 5s ago Listen: /var/run/cups/cups.sock (Stream) تفعيل مقبس أو تعطيله: # systemctl enable cups.socket # systemctl disable cups.socket إخفاء مقبس $ sudo systemctl mask cups.socket Created symlink from /etc/systemd/system/cups.socket to /dev/null. $ sudo systemctl unmask cups.socket Removed symlink /etc/systemd/system/cups.socket. استخدام المعالج حصة خدمة من المعالج يمكن استخدام systemctl لعرض عدد الحصص الحاليّة المحدّدة لخدمة من المعالج: # systemctl show -p CPUShares apache2.service CPUShares=18446744073709551615 تعرّف قيمة CPUShares الوقت المخصّص للخدمة من المعالج. تعني زيادة هذه القيمة الرفع من أولويّة للخدمة. يمكن تحديد الحصّة بتغيير قيمة المتغيّر على النحو التالي: # systemctl set-property apache2.service CPUShares=1500 $ systemctl show -p CPUShares apache2.service CPUShares=1500 ينشئ النظام عند تحديد حصّة خدمة مجلّدا يوافق اسمه اسمَ الخدمة (مثلا apache2.service.d) وينشئ بداخله ملف إعداد يبدأ برقم يتبعه اسم المتغيّر (مثلا 50-CPUShares.conf): $ cat /etc/systemd/system/apache2.service.d/50-CPUShares.conf [Service] CPUShares=1500 عرض تفاصيل الإعداد الخاصّة بخدمة $ systemctl show apache2 Type=forking Restart=no NotifyAccess=none RestartUSec=100ms TimeoutStartUSec=5min TimeoutStopUSec=5min RuntimeMaxUSec=infinity WatchdogUSec=0 WatchdogTimestampMonotonic=0 FailureAction=none PermissionsStartOnly=no RootDirectoryStartOnly=no RemainAfterExit=no GuessMainPID=no MainPID=0 ControlPID=0 FileDescriptorStoreMax=0 NFileDescriptorStore=0 StatusErrno=0 (...) عرض اعتماديّات خدمة $ systemctl list-dependencies apache2.service apache2.service ● ├─system.slice ● ├─network-online.target ● │ ├─networking.service ● │ └─NetworkManager-wait-online.service ● └─sysinit.target ● ├─apparmor.service ● ├─brltty.service ● ├─console-setup.service ● ├─dev-hugepages.mount ● ├─dev-mqueue.mount ● ├─friendly-recovery.service ● ├─keyboard-setup.service ● ├─kmod-static-nodes.service ● ├─plymouth-read-write.service ● ├─plymouth-start.service ● ├─proc-sys-fs-binfmt_misc.automount ● ├─resolvconf.service ● ├─setvtrgb.service (...) سرد مجموعات التحكّم Control groups يُستخدَم الأمر systemd-cgls لسرد مجموعات التحكّم هرميّا على النحو التالي: # systemd-cgls ├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 21 ├─user.slice │ └─user-1000.slice │ └─session-1.scope │ ├─ 2292 gdm-session-worker [pam/gdm-password] │ ├─ 2308 /usr/bin/gnome-keyring-daemon --daemonize --login │ ├─ 2351 gnome-session --session gnome-classic │ ├─ 2358 dbus-launch --sh-syntax --exit-with-session │ ├─ 2359 /bin/dbus-daemon --fork --print-pid 4 --print-address 6 --sessi... │ ├─ 2424 /usr/libexec/gvfsd │ ├─ 2428 /usr/libexec/gvfsd-fuse /run/user/1000/gvfs -f -o big_writes يُمكن سرد هذه المجموعات حسب استخدام المعالج والذاكرة العشوائية أو حسب المُدخَلات والمُخرجات بالأمر systemd-cgtop: Path Tasks %CPU Memory Input/s Output/s / 216 37.7 1.6G - - /system.slice - 7.1 - - - /system.slice/gdm.service 2 7.1 - - - /system.slice/rngd.service 1 0.0 - - - /system.slice/tuned.service 1 0.0 - - - /system.slice/vboxadd-service.service 1 0.0 - - - /system.slice/httpd.service 6 0.0 - - - التحكم في مستويات التشغيل Runlevels الإقلاع في وضع الإنقاذ Rescue mode أو وضع الطوارئ Emergency mode يمكن في حال حدوث مشكل الإقلاعُ في وضع الإنقاذ بالأمر التالي: # systemctl rescue كما يُستخدم الأمر systemctl للإقلاع في وضع الطوارئ: # systemctl emergency وللعودة إلى وضع الإقلاع المبدئي: # systemctl default عرض مستوى التشغيل الحالي $ systemctl get-default graphical.target الإقلاع على مستوى تشغيل يمكن تحديد مستوى التشغيل الذي نريد الإقلاع عليه بالأمر systemctl isolate؛ مثلا: # systemctl isolate runlevel5.target # systemctl isolate runlevel3.target أو بذكر اسم المستوى: # systemctl isolate graphical.target # systemctl isolate multiuser.target تعيين مستوى التشغيل المبدئي # systemctl set-default runlevel3.target # systemctl set-default runlevel5.target مستويات التشغيل هي التالية: المستوى 0 runlevel0: إيقاف تشغيل النظام وفصله عن الطاقة. المستوى 1 runlevel1: وضع الإنقاذ والصيانة. المستوى 2 runlevel2: تعدّد المستخدمين. المستوى 3 runlevel3: تعدّد المستخدمين مع تشغيل خدمات الشبكة. المستوى 4 runlevel4: مستوى تشغيل محجوز لما يعرّفه المستخدم. المستوى 5 runlevel5: المستوى 3 + واجهة رسومية. المستوى 6 runlevel6: إعادة تشغيل النظام. إعادة تشغيل النظام، إيقافه، تعليقه وإسباته # systemctl reboot # systemctl halt # systemctl suspend # systemctl hibernate كما يمكن جعل النظام في وضع السبات المزدوج (مزيج من وضع السبات والتعليق) بالأمر: # systemctl hybrid-sleep ترجمة - بتصرّف - لمقال How to Manage ‘Systemd’ Services and Units Using ‘Systemctl’ in Linux.
  8. يُراجع هذا المقال تثبيت الحزم، تحديثها وحذفها في توزيعة Red Hat Enterprise Linux 7؛ كما يغطّي أتمتة المهامّ باستخدام Cron وكيفيةَ تحليل ملفات السّجلات Logs الموجودة على النظام. استخدام Yum لإدارة الحزم تثبيت الحزم يُستخدَم أمر yum لتثبيت الحزم على Red Hat Enterprise Linux بالطريقة التالية: # yum -y install package_name حيثُ package_name اسم الحزمة التي نريد تثبيتها. يمكننا تثبيت أكثر من حزمة في نفس الوقت بكتابة أسمائها على التوالي. نطلُب في المثال التالي تثبيت الحزم httpd وmlocate: # yum -y install httpd mlocate يؤدي استخدامُ الخيار y- إلى تجاوز طلب التأكيد الذي يظهر قبل تنزيل الحزم وتثبيتها. يمكن حذفه من الأمر إن أردت. يُثبّت yum مبدئيا الحزم المطابقة لمعمارية Architecture نظام التشغيل؛ إلا أنه يمكن تخصيص معماريّة الحزمة بإلحاق المعمارية المرغوبة باسم الحزمة. على سبيل المثال، إن كنت تستخدم نظام تشغيل بمعمارية 64 بت فإن تنفيذ الأمر yum install package سيُثبّت الإصدار 64 بت (x86_64) من الحزمة package؛ في حين يؤدي تنفيذ الأمر yum install package.x86 إلى تثبيت الإصدار 32 بت، في حال توفّره. البحث عن حزمة قد تحتاج أحيانا لتثبيت حزمة ولكنّك لا تعرف اسمها بالضبط؛ يمكن في هذه الحالة استخدام الأمر yum search أو yum search all للبحث في المستودعات المُفعَّلة عن كلمة مفتاحية في اسم الحزمة أو في وصفها، على التوالي. على سبيل المثال؛ يبحث الأمر التالي ضمن المستودعات المفعَّلة عن الحزم التي تحوي كلمة log في أسمائها أو في مختصر عملها: # yum search log بينما يبحث الأمر التالي عن الكلمة log في أسماء الحزم، مختصرات عملها، أوصافها وروابط url الخاصّة بها: # yum search all log ماذا إن كنت تعرف اسم برنامج دون أن تعرف الحزمة التي تُثبته؟ مثلا برنامج ps2pdf. يمكن اللجوء في هذه الحالة إلى الأمر yum whatprovides على النحو التالي: # yum whatprovides "*/ps2pdf" الحصول على معلومات عن حزمة قد تودّ الحصول على معلومات عن حزمة، قبل أن تقرّر تثبيتها على جهازك؛ بعد ظهورها مثلا في نتيجة البحث بالأمر السابق. يمكنك استخدام الأمر yum لهذا الغرض: # yum info logwatch البحث عن تحديثات يُستخدم الأمر yum check-update للبحث عن التحديثات المتوفّرة للحزم. يُظهر الأمر لائحة بالحزم التي يتوفر لها تحديث. يمكنك بعدها تحديث جميع الحزم مرة واحدة بتنفيذ الأمر yum update؛ كما يمكنك تحديث حزمة محدّدة بتنفيذ الأمر yum update package حيثُ package هو اسم الحزمة. حذف حزمة يمكن حذف حزمة بالأمر yum remove على النحو التالي: # yum remove httpd حزم RPM يمكن تثبيت البرامج على Red Hat Enterprise Linux بحزم RPM (اختصار لـ RedHat Package Manager) القائمة بذاتها (لا توجد ضمن مستودعات ولا تحتاج للاتصال بالشبكة). تثبيت الحزم يُستخدَم الأمر rpm لتثبيت هذه الحزم، ويكثُر استخدام الخيارات Uvh- التي تشير إلى أنه يجب تثبيت الحزمة إن لم تكن مثبّتة على النظام ومحاولة تحديثها إن كانت مثبّتة (U-)، إظهار عرض تفصيلي بنتيجة تنفيذ الأمر (v-) وعرض شريط بتقدّم تنفيذ الأمر (h-). مثلا: # rpm -Uvh package.rpm عرض لائحة بالحزم المثبتة يمكن استخدام الأمر rpm مع الخيار qa- (اختصار لـ Query all) لإظهار لائحة بجميع الحزم المثبتة على النظام: # rpm -qa جدولة المهامّ باستخدام Cron تتضمّن أنظمة تشغيل لينكس والأنظمة الشبيهة بيونكس أداة تُسمّى Cron لجدولة المهام (أوامر أو سكربتات الصدفة) للعمل دوريا. تبحث أداة Cron كل دقيقة في المجلّد var/spool/cron/ عن ملفات بأسماء حسابات موافقة لتلك المذكورة في الملف etc/passwd/. تُرسَل مخرجات تنفيذ المهامّ إلى صاحب المهمّة أو المستخدم المحدَّد في متغيّر البيئة MAILTO ضمن الملفّ etc/crontab/ إن كان موجودا. يُستخدَم الأمر crontab -e لإنشاء ملفات Crontab التي تأخذ الأسطُر فيها الصيغة التالية: نطلُب في المثال التالي جدولة تحديث قاعدة البيانات الخاصة بالملفات (يستخدمها الأمر locate للبحث في الملفات) بحيثُ ينفَّذ أمر الجدولة bin/updatedb/ في اليوم الثاني من كلّ شهر عند الساعة 2:15 صباحا: 15 02 2 * * /bin/updatedb يُقرأ السطر أعلاه “نفّذ الأمر bin/updatedb/ في اليوم الثاني من الشّهر، كل شهر من السنة بدون النظر في يوم الأسبوع (أحد، اثنان، …إلخ) عند الساعة 2 صباحا والدقيقة 15”. تشير العلامة * إلى أن قيمة الحقل غير معيّنة. ملحوظة: المحرّر المستخدم مبدئيا عند تنفيذ الأمر crontab -e هو محرّر vi. ستلاحظ بعد إضافة المهمة إلى الجدول إنشاءَ ملفّ باسم root في المجلد var/spool/cron/، كما ذكرنا آنفا. يمكن عرض جميع ملفات Crontab بسرد محتويات المجلّد السّابق الذكر: # ls -l /var/spool/cron كما يمكن للمستخدم الحالي (root) عرضُ جميع مهامّه المجدولة إما بعرض محتوى الملف var/spool/cron/root/ أو بتنفيذ الأمر crontab -l. تستطيع جدولة مهمّة للعمل أكثر من مرة. نطلُب من Cron في المثال التالي تنفيذ السكربت myscript وتوجيه مخرجاته إلى dev/null/ في الدقيقة الأولى من اليومين الأول والخامس عشر من كل شهر: 01 00 1 * * /myscript > /dev/null 2>&1 01 00 15 * * /my/script > /dev/null 2>&1 يمكن دمج السّطرين على النحو التالي: 01 00 1,15 * * /my/script > /dev/null 2>&1 نطلُب في المثال التالي تنفيذ سكربت عند الساعة الواحدة و30 دقيقة صباحا في اليوم الأول من الشهر كل ثلاثة أشهر (الأشهر 1، 4، 7 و10): 30 01 1 1,4,7,10 * /my/other/script > /dev/null 2>&1 إلا أنه توجد طريقة أسهل من السابقة؛ إذ يتيح Cron تحديد عدد مرات للتنفيذ. إن أردنا مثلا تنفيذ أمر كل 3 دقائق فإننا نستخدم الصّيغة 3/* مكان الدقائق. نفس الشي بالنسبة للساعات، الأيام أو الأشهر. يؤدي السّطر التالي نفس غرض السّطر السابق: 30 01 1 */3 * /my/other/script > /dev/null 2>&1 توجد اختصارات لجدولة الأوامر للتنفيذ بتردّد ثابت أو مباشرة بعد إعادة تشغيل النظام. يوضّح الجدول التالي هذه الاختصارات والصّيغة المكافئة لها؛ إن أردت استخدام أحد الاختصارات اكتبه مكان الحقول الزمنية الخمسة في ملفّ Cron: @reboot - - تنفيذ السكربت أو الأمر مباشرة بعد إقلاع النظام. @yearly - 00 00 1 1 * - مرة في السنة. @monthly - 00 00 1 * * - مرة في الشهر. @weekly - 00 00 * * 0 - مرة في الأسبوع. @daily - 00 00 * * * - مرة في اليوم. @hourly - 00 * * * * - مرة في الساعة. راجع مقال كيف تجدول مهامك الروتينية باستخدام أداتي Cron و Anacron في لينكس للمزيد. السّجلات توجد سجلّات النظام في المجلّد var/log/. يحتفظ النظام بسجلات مختلفة داخل هذا المجلّد، موزّعة على مجلّدات فرعية مثل audit، httpd وsamba. يعمل النّظام على تقسيم السّجل على ملفات لتجنّب الحصول على ملفات كبيرة جدا؛ تُعرَف هذه العمليّة بالتدوير Rotation حيثُ تُنقَل السجلات القديمة إلى ملفّ آخر بنفس الاسم مع عدد أو تاريخ للترتيب (مثلا secure-20160530). من أهمّ ملفات السّجلات: dmesg الذي يحوي الرسائل القادمة من النواة Kernel، ملفّ secure الذي توجد به سجلات لمحاولات الاتصال بالخادوم التي تتطلّب الاستيثاق، messages الذي توجد به رسائل متعلقّة بالنظام ككلّ وwtmpالذي يحوي سجلات بعمليات الدخول Logins والخروج Logouts. تكمُن أهميّة السّجلات في أنها تعطيك نظرة عن ما يحدُث في النظام أو ما حدث في الماضي. تُستخدَم السّجلات لفحص اختلالات النظام وإصلاحها أو لمراقبة الخادوم. إن أردت تتبّع ما يطرأ على أحد السّجلات مباشرة فيمكنك استخدام الأمر tail مع الخيار f-؛ مثلا: # tail -f /var/log/dmesg وإن كنت تريد رؤية عمليات الوصول إلى خادوم الوِب فور حدوثها: # tail -f /var/log/httpd/access.log من المهمّ النظرُ إلى السجلات دوريا، ومعرفة ملفّ السّجلات المناسب لكلّ خدمة تعمل على خادومك. ترجمة - بتصرّف - لمقال RHCSA Series: Yum Package Management, Automating Tasks with Cron and Monitoring System Logs – Part 10 لصاحبه Gabriel Cánepa.
  9. 15 مثالا لإدارة الحزم باستخدام RPM

    تستخدم بعض توزيعات لينكس، خصوصا تلك المعتمدة على Fedora مثل CentOS وRed Hat Enterprise Linux، حزم RPM لتثبيت البرامج وإدارتها. ملف rpm. هو عبارة عن تجميع لبرامج ومكتبات تحتاجها هذه البرامج في حزمة تُستخدَم أداة باسم rpm لتثبيتها. الأداة rpm هي أداة مفتوحة المصدر تحتفظ ببيانات الحزم المثبّتة على النظام في المجلّد var/lib/rpm/. من المهم الانتباه إلى أن أداة rpm لا تستطيع التعامل مع البرامج التي ثُبِّتت انطلاقا من المصدر Source. يحتوي ملفّ rpm. على معلومات من قبيل ماهية الحزمة، من أين تأتي، الاعتماديات التي تحتاجها للعمل، الإصدار… إلخ. توجد خمسة أوضاع أساسية لأداة rpm: التثبيت i-: يُستخدَم لتثبيت حزم RPM. الحذف e-: يُستخدَم لحذف حزمة وإلغاء تثبيتها. الترقية U-: يُحدّث حزمة مثبّتة (تثبيت إصدار جديد من الحزمة). التحقق V-: يُستخدَم للتحقّق من حزمة RPM. الاستعلام q-: يُستخدَم للاستعلام عن حزم RPM. حزم RPM هي حزم قائمة بذاتها؛ تمكن الاستفادة من المواقع التالية للحصول على حزم RPM الخاصّة ببرنامج تريده: redhat.com rpmfind.net. rpm.pbone.net rpmseek.com يقدّم هذا المقال أمثلة لأوامر RPM من أجل المساعدة في تثبيت البرامج، تحديثها أو حذفها على توزيعة تستخدم RPM للتحزيم. ملحوظة: يجب أن تكون لديك صلاحيات الجذر حتى تستطيع إدارة الحزم. التحقق من توقيع حزمة يجب أولا التحقّق من مصدر الحزمة وموثوقيتها قبل تثبيتها. يُستخدم الخيار checksig-- مع الأمر rpm لهذا الغرض. لكي نستطيع التحقق من حزمة فإنه يجب أولا استيراد المفاتيح العمومية Public keys الخاصّة بالنظام الذي نعمل عليه (Fedora، CentOS، RHEL أو غيرها). بالنسبة لتوزيعة Red Hat Enterprise Linux فالأمر على النحو التالي: rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-* نطلب في الأمر التالي التحقق من الحزمة pidgin-1.5.1-6.el3.x86_64.rpm: [root@academy1 ~]# rpm --checksig pidgin-1.5.1-6.el3.x86_64.rpm pidgin-1.5.1-6.el3.x86_64.rpm: (sha1) dsa sha1 md5 gpg OK لاحظ أن نتيجة التحقق هي OK. تثبيت حزمة يطلُب الأمر التالي تثبيت الحزمة pidgin-1.5.1-6.el3.x86_64.rpm التي تحققنا من موثوقيتها أعلاه: [root@academy1 ~]# rpm -ivh pidgin-1.5.1-6.el3.x86_64.rpm Preparing... ########################################### [100%] 1:pidgin ########################################### [100%] تظهر في الأمر أعلاه الخيارات التالية: i-: وضع التثبيت، v-: طلب إظهار رسائل بتقدم عملية التثبيت، h-: طلب إظهار علامات # للدلالة على التقدم الحاصل في تنفيذ خطوات التثبيت. الخياران الأخيران v- وh- ليسا ضروريين. التحقق من اعتماديات حزمة قبل تثبيتها تتيح أداة rpm التحقق من اعتماديات حزمة قبل تثبيتها، مثلا للتحقق من اعتماديات الحزمة pidgin-2.11.0-1.fc24.x86_64.rpm: [root@academy1 ~]# rpm -qpR pidgin-1.5.1-6.el3.x86_64.rpm /bin/sh /bin/sh glib2 >= 2.2 htmlview libICE.so.6()(64bit) libSM.so.6()(64bit) libX11.so.6()(64bit) libXext.so.6()(64bit) libao.so.2()(64bit) libatk-1.0.so.0()(64bit) libaudiofile.so.0()(64bit) (...) يشير الخيار q- إلى أننا في وضع الاستعلام عن الحزمة. يطلب الخيار p- معلومات عن حزمة غير مثبّتة ويسرُد الخيار R- اعتماديّات الحزمة. تثبيت حزمة بغض النظر عن اعتمادياته لا يقبل rpm في الحالة العادية تثبيت حزمة إلا إذا كانت جميع اعتمادياتها مثبتة؛ إلا أنه يمكن إجباره على ذلك باستخدام الخيار nodeps--: [root@academy1 ~]# rpm -ivh --nodeps pidgin-1.5.1-6.el3.x86_64.rpm Preparing... ################################# [100%] Updating / installing... 1:pidgin-1.5.1-6.el3 ################################# [100%] يُثبّت الأمر أعلاه الحزمة بتجاهل الأخطاء المتعلقة باعتماديّاتها؛ إلا أن البرنامج لن يعمل إلا بعد تثبيت الاعتماديات المطلوبة. التحقق من أن حزمة مثبّتة استخدم وضع الاستعلام q- للتأكد من أن حزمة مّا مثبتة على النظام: [root@academy1 ~]# rpm -q BitTorrent package BitTorrent is not installed [root@academy1 ~]# rpm -q pidgin pidgin-1.5.1-6.el3.x86_64.rpm سرد قائمة بجميع ملفات حزمة مثبتة أضف خيار السرد l- إلى وضع الاستعلام q- للحصول على قائمة بملفات حزمة مثبتة على النظام: [root@academy1 ~]# rpm -ql pidgin /etc/gconf/schemas/purple.schemas /usr/bin/gaim /usr/bin/pidgin /usr/lib64/pidgin /usr/lib64/pidgin/convcolors.so /usr/lib64/pidgin/extplacement.so /usr/lib64/pidgin/gestures.so /usr/lib64/pidgin/gtkbuddynote.so (...) سرد الحزم المُثبتة يسرُد الخيار a- عند استخدامه في وضع الاستعلام قائمة بأسماء جميع الحزم المثبتة: [root@academy1 ~]# rpm -qa libsss_nss_idmap-1.13.0-40.el7_2.9.x86_64 pygobject3-base-3.14.0-3.el7.x86_64 libfprint-0.5.0-3.el7.x86_64 man-pages-3.53-5.el7.noarch redhat-release-server-7.2-9.el7.x86_64 rsyslog-7.4.7-12.el7.x86_64 libsane-hpaio-3.13.7-6.el7_2.1.x86_64 (...) يمكن ترتيب القائمة لتظهر الحزم المثبتة مؤخرا في الأعلى باستخدام الخيار last--: [root@academy1 ~]# rpm -qa --last pidgin-1.5.1-6.el3.x86_64.rpm Sun 04 Sep 2016 09:47:32 PM GMT glibc-devel-2.17-106.el7_2.8.x86_64 Tue 02 Aug 2016 11:42:29 PM GMT nss-pam-ldapd-0.8.13-8.el7.x86_64 Tue 02 Aug 2016 11:42:23 PM GMT nscd-2.17-106.el7_2.8.x86_64 Tue 02 Aug 2016 11:42:17 PM GMT glibc-headers-2.17-106.el7_2.8.x86_64 Tue 02 Aug 2016 11:42:14 PM GMT glibc-common-2.17-106.el7_2.8.x86_64 Tue 02 Aug 2016 11:42:01 PM GMT (...) تحديث حزمة يُستخدَم وضع الترقية U- لتحديث إصدار حزمة مثبتة. يحتفظ أمر rpm عند تحديث حزمة بنسخة احتياطية من الإصدار المثبت للعودة إليها في حال لم تعمل الحزمة حسب المطلوب بعد تحديثها: [root@academy1 ~]# rpm -Uvh pidgin-1.5.1-6.el3.x86_64.rpm Preparing... ########################################### [100%] 1:pidgin ########################################### [100%] حذف حزمة استخدم الخيار e- مع الأمر rpm لحذف حزمة بذكر اسمها. مثلا؛ لحذف حزمة pidgin السابقة: [root@academy1 ~]# rpm -e pidgin تمكن أيضا إضافة الخيار v إلى الأمر لعرض رسائل بما يحدُث: [root@academy1 ~]# rpm -ev pidgin Preparing packages... pidgin-1.5.1-6.el3.x86_64.rpm كما يمكن الإبقاء على اعتماديات الحزمة باستخدام الخيار nodeps-- مع أمر الحذف وهو ما ينتج عنه حذف الحزمة فقط دون اعتمادياتها: [root@academy1 ~]# rpm -ev --nodeps pidgin انتبه إلى أن حذف حزمة من النظام يمكن أن يؤدي إلى عدم استقراره؛ لذا تأكد من حاجتك فعلا لحذف الحزمة. معرفة الحزمة التي ينتمي إليها ملف استخدم الخيار f- في وضع الاستعلام لمعرفة الحزمة التي ينتمي إليها ملف. مثلا؛ تخبرنا نتيجة الأمر التالي أن الملف usr/bin/htpasswd/ ينتمي للحزمة httpd-tools-2.4.6-40.el7_2.4.x86_64. [root@academy1 ~]# rpm -qf /usr/bin/htpasswd httpd-tools-2.4.6-40.el7_2.4.x86_64 الحصول على معلومات عن حزمة يعرض الخيار i- عند استخدامه في وضع الاستعلام معلومات عن حزمة مثبتة؛ مثلا بالنسبة لحزمة vsftpd: [root@academy1 ~]# rpm -qi vsftpd Name : vsftpd Version : 3.0.2 Release : 11.el7_2 Architecture: x86_64 Install Date: Thu 21 Jul 2016 03:29:37 PM GMT Group : System Environment/Daemons Size : 355788 License : GPLv2 with exceptions Signature : RSA/SHA256, Fri 18 Mar 2016 01:08:35 AM GMT, Key ID 199e2f91fd431d51 Source RPM : vsftpd-3.0.2-11.el7_2.src.rpm Build Date : Wed 24 Feb 2016 11:06:41 AM GMT Build Host : x86-019.build.eng.bos.redhat.com Relocations : (not relocatable) Packager : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla> Vendor : Red Hat, Inc. URL : https://security.appspot.com/vsftpd.html Summary : Very Secure Ftp Daemon Description : vsftpd is a Very Secure FTP daemon. It was written completely from scratch. أما إن أردت الحصول على معلومات عن حزمة قبل تثبيتها فالأمر هو التالي: [root@academy1 ~]# rpm -qip pidgin-1.5.1-6.el3.x86_64.rpm Name : pidgin Version : 1.5.1 Release : 6.el3 Architecture: x86_64 Install Date: (not installed) Group : Applications/Internet Size : 11168813 License : GPL Signature : DSA/SHA1, Thu 29 Oct 2009 08:14:44 AM GMT, Key ID 219180cddb42a60e Source RPM : pidgin-1.5.1-6.el3.src.rpm Build Date : Wed 28 Oct 2009 03:52:51 PM GMT Build Host : x86-003.build.bos.redhat.com Relocations : (not relocatable) Packager : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla> Vendor : Red Hat, Inc. URL : http://www.pidgin/im/ Summary : A Gtk+ based multiprotocol instant messaging client Description : Pidgin allows you to talk to anyone using a variety of messaging protocols, including AIM, ICQ, IRC, Yahoo!, Novell Groupwise, MSN Messenger, Jabber, Gadu-Gadu, Napster, and Zephyr. These protocols are implemented using a modular, easy to use design. To use a protocol, just add an account using the account editor. Pidgin supports many common features of other clients, as well as many unique features, such as perl scripting, TCL scripting and C plugins. Pidgin is NOT affiliated with or endorsed by America Online, Inc., Microsoft Corporation, Yahoo! Inc., or ICQ Inc. [root@academy1 ~]# الاستعلام عن التوثيق Documentation الخاص بحزمة مثبتة يمكن الحصول على مستندات التوثيق الخاصّة بحزمة باستخدام الخيارين df- في وضع الاستعلام. يأخذ الأمر معطى عبارة عن مسار الحزمة؛ وهو ما يمكن الحصول عليه عن طريق الأمر which. نطلب في المثال التالي معرفة مسار الحزمة vsftpd ثم نستعلم عن مستدات التوثيق الخاصّة بها: [root@academy1 ~]# which vsftpd /sbin/vsftpd [root@academy1 ~]# rpm -qdf /sbin/vsftpd /usr/share/doc/vsftpd-3.0.2/AUDIT /usr/share/doc/vsftpd-3.0.2/BENCHMARKS /usr/share/doc/vsftpd-3.0.2/BUGS /usr/share/doc/vsftpd-3.0.2/COPYING /usr/share/doc/vsftpd-3.0.2/Changelog (...) التحقق من حزمة تقارن أداة rpm عند طلب التحقق من حزمة المعلومات المستقاة من الملفات المثبتة مع تلك الموجودة في قاعدة بيانات rpm. يُستخدم الخيار V- لوضع التحقق وp لتمرير حزمة إلى الأمر: [root@academy1 ~]# rpm -Vp vsftpd-3.0.3-2.fc24.x86_64.rpm warning: vsftpd-3.0.3-2.fc24.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 81b46521: NOKEY .......T. c /etc/logrotate.d/vsftpd .......T. c /etc/pam.d/vsftpd .......T. c /etc/vsftpd/ftpusers .......T. c /etc/vsftpd/user_list .......T. c /etc/vsftpd/vsftpd.conf .......T. /etc/vsftpd/vsftpd_conf_migrate.sh .......T. /usr/lib/systemd/system-generators/vsftpd-generator .......T. /usr/lib/systemd/system/vsftpd.service .......T. /usr/lib/systemd/system/vsftpd.target .......T. /usr/lib/systemd/system/vsftpd@.service S.5....T. /usr/sbin/vsftpd missing /usr/share/doc/vsftpd missing d /usr/share/doc/vsftpd/AUDIT missing d /usr/share/doc/vsftpd/BENCHMARKS missing d /usr/share/doc/vsftpd/BUGS (...) يمكن طلب التحقق من جميع الحزم في النظام بالخيار a في وضع التحقق على النحو التالي: [root@academy1 ~]# rpm -Va S.5....T. c /etc/os-release S.5....T. /usr/src/kernels/3.10.0-327.22.2.el7.x86_64/include/config/auto.conf S.5....T. /usr/src/kernels/3.10.0-327.22.2.el7.x86_64/include/config/auto.conf.cmd S.5....T. /usr/src/kernels/3.10.0-327.22.2.el7.x86_64/include/config/tristate.conf S.5....T. /usr/src/kernels/3.10.0-327.22.2.el7.x86_64/include/generated/autoconf.h (...) سرد جميع المفاتيح العمومية المستوردة يمكنك إن أردت سرد جميع المفاتيح العمومية للحزم المثبتة على نظامك، وذلك على النحو التالي: [root@academy1 ~]# rpm -qa gpg-pubkey* gpg-pubkey-2fa658e0-45700c69 gpg-pubkey-37017186-45761324 gpg-pubkey-897da07a-3c979a7f gpg-pubkey-f21541eb-4a5233e7 gpg-pubkey-42193e6b-4624eff2 gpg-pubkey-fd431d51-4ae0493b gpg-pubkey-db42a60e-37ea5438 تصحيح قاعدة بيانات RPM معطوبة يحدُث أن تُصاب قاعدة البيانات الخاصّة بحزم RPM بعُطب مما ينتُج عنه غياب وظائف من أداة rpm. يمكنك في هذه الحالة محاولة بناء قاعدة البيانات من جديد بالأوامر التالية: [root@academy1 ~]# cd /var/lib/rpm [root@academy1 rpm]# rm __db* [root@academy1 rpm]# rpm --rebuilddb [root@academy1 rpm]# /usr/lib/rpm/rpmdb_verify Packages BDB5105 Verification of Packages succeeded. ترجمة - وبتصرف - لمقال 20 Practical Examples of RPM Commands in Linux لصاحبه Ravi Saive.
  10. نشر تطبيقات Laravel على منصة Heroku

    اشتهر استخدام منصة Heroku السحابية ضمن مجتمع مطوري Ruby on Rails ونالت فيه شعبية واسعة؛ إلا أن الخدمة لم تقتصر على مطوري Ruby وما يدور حولها بل تجاوزتهم إلى تقديم الدعم للغات برمجة مثل Node.js ،Java و PHP؛ من بين أخرى. توفّر Heroku خطّة اشتراك مجانية يمكن استخدامها لإدارة مشاريع صغيرة جدا أو لأغراض الاختبار. سنشرح في هذا الدرس كيفية الاستفادة من Heroku عبر هذه الخطة لنشر Deploying تطبيقات Laravel. إنشاء حساب على Heroku يجب أولا أن ننشئ حسابا على موقع الخدمة حتى يمكننا الاستفادة منها. التسجيل مجاني ولا يستغرق سوى دقائق. ستُعرَض عليك خلال عملية التسجيل خيارات للغة البرمجة التي تريد استخدامها، اختر PHP؛ مع العلم أن هذا الخيار لا يؤثّر على إمكانية استعمالك للغات برمجة أخرى مستقبلا. تثبيت Heroku Toolbelt الخطوة الثانية بعد إنشاء الحساب هي تثبيت أداة Heroku Toolbelt. تُستخدَم هذه الأداة، التي تعمل عبر سطر الأوامر، لإدارة جوانب عدّة من المشاريع المضافة إلى Heroku؛ ومن ضمنها إدارة عمليّة النشر، تهجير Migrating قاعدة البيانات والتخاطب مع خادوم Heroku. تتوفّر الأداة على وندوز، ماك وتوزيعة أوبونتو لينكس. نفّذ بعد تثبيت الأداة الأمر التالي: $ heroku login heroku-cli: Installing CLI... 21.83MB/21.83MB Enter your Heroku credentials. Email: mail@example.com Password (typing will be hidden): Logged in as mail@example.com انتظر قليلا حتى يكتمل تنزيل عميل Heroku ثمّ أدخل معلومات الاستيثاق الخاصّة بك (عنوان البريد وكلمة السر). نشر تطبيق Laravel على Heroku يمكننا الآن بعد التسجيل في Heroku وتثبيت الأداة Heroku Toolbelt نشرُ مشروع Laravel. نبدأ بإنشاء مشروع Laravel جديد (على الحاسوب الشخصي): $ composer create-project laravel/laravel dev.herokutest.com dev-develop Installing laravel/laravel (dev-develop 083db95...dac46617) - Installing laravel/laravel (dev-develop develop) Cloning develop ... Compiling views Do you want to remove the existing VCS (.git, .svn..) history? [Y,n]? Y Application key [9UCBk7IDjvAGrkLOUBXw43yYKlymlqE3Y] set successfully. ثم ننشئ ملفا باسم Procfile ونضعه في المجلد الجذر لمشروع Laravel. طريقة كتابة اسم الملفّ مهمة جدا (الحرف الأول كبير، ولا وجود لامتداد للملف). يقرأ Heroku هذا الملفّ لتحديد نوع العمليات التي سيجريها بعد نشر التطبيق. في حالة تطبيق Laravel فإن نوع العمليات المطلوب هو وِب web. نحدّد نوع خادوم الوِب المستخدم لتقديم التطبيق (Apache) والمجلّد الذي توجد به ملفات التطبيق المخصّصة للعرض، وهو في حالة Laravel المجلد public. يصبح ملفّ Procfile على النحو التالي: web: vendor/bin/heroku-php-apache2 public هذا فقط مثال على الخيارات المتاحة، يمكنك تغيير هذه الخيارات (خادوم الوِب مثلا) إن أردت ذلك. الخطوة الموالية لإنشاء ملفّ Procfile هي وضع المشروع تحت تصرّف نظام إدارة الإصدارات Git بإنشاء مستودع للمشروع: $ git init Initialized empty Git repository in /home/zeine77/dev.herokutest.com/.git/ $ git add . $ git commit -m "First commit" يسهّل استخدامُ Git كثيرا عمليةَ النشر، فإطار العمل Laravel يأتي مبدئيا بميزات خاصّة بنظام إدارة الإصدارات Git (مثل ملفات gitignore.)؛ كما أن Heroku أيضا يتفاعل مع مستودع Git المحلي لتسهيل النشر. راجع هذه المقالات لمعرفة المزيد عن Git. نحن الآن جاهزون لنشر التطبيق على Heroku. نستخدم Heroku Toolbelt لهذه المهمة: $ heroku create Heroku CLI submits usage information back to Heroku. If you would like to disable this, set `skip_analytics: true` in /home/zeine77/.heroku/config.json Creating app... done, ⬢ nameless-chamber-90421 https://nameless-chamber-90421.herokuapp.com/ | https://git.heroku.com/nameless-chamber-90421.git ينشئ الأمر heroku create اسما جديدا لمشروعك (أعطاني الاسم nameless-chamber-90421) ويعرّف رابطا يمكن عبره الوصول إلى التطبيق. لا يوجد على الرابط - لحد السّاعة - سوى صفحة مبدئية من Heroku. زيادة على الرابط والاسم، أنشأ الأمر السابق مستودع Git بعيدا. مستودع Git بعيد هو مستودع يضم ملفات مشروعك ولكنه يوجد في مكان آخر غير جهازك؛ يمكن دفع التغييرات إلى المشروع البعيد أو جلبها منه. سنكتفي في حالة Heroku بدفع التعديلات إلى المستودع البعيد، كما سنرى بعد قليل. يستخدم Heroku ملفات تسمى buildpacks (حزم بناء) لمعرفة البرامج التي يجب عليه إعدادها على الخادوم بعد تثبيت التطبيق؛ لذا يجب أن نحدّد واحدا. اخترنا ملفّ buildpack الرسمي من Heroku الخاص بتطبيقات PHP؛ نستخدم الأمر config:add في Heroku Toolbelt لتحديد هذا الملف: $ heroku config:add BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-php Setting BUILDPACK_URL and restarting ⬢ nameless-chamber-90421... done, v3 BUILDPACK_URL: https://github.com/heroku/heroku-buildpack-php تستخدم تطبيقات Laravel مفتاح تعميّة Encryption key لتعمية معلومات جلسة المستخدم ومعلومات أخرى؛ توجد قيمة هذا المفتاح في متغيّر البيئة APP_KEY. يوجد المتغيّر APP_KEY في الملفّ env.، إلا أن الملف env. لا يدخل في إطار الملفات التي يتعامل معها Git، نظرا لوجوده في الملفات المحدّدة في gitignore.. سنحتاج إذن لتوليد مفتاح تعميّة لاستخدامه على خادوم Heroku. تُستخدم أداة artisan لتوليد مفتاح تعمية على النحو التالي: php artisan key:generate --show يولّد الأمر أعلاه مفتاح تعميّة ويعرضه على سطر الأوامر؛ إلا أننا نريد أن نخزّن المفتاح على الخادوم؛ نستخدم Toolbelt لهذا الغرض على النحو التالي: heroku config:set APP_KEY=$(php artisan --no-ansi key:generate --show) Setting APP_KEY and restarting ⬢ nameless-chamber-90421... done, v7 APP_KEY: base64:jp40IC7SV5eJ5IhjQYwqk/KXJG0uS+ZhCqSGwkwgELs= يضبط الأمر السابق قيمة المتغيّر APP_KEY على الخادوم لتساوي نتيجة تنفيذ الأمر php artisan --no-ansi key:generate --show. حان الآن وقت النشر فعليا؛ ندفع التغييرات في المستودع المحلي إلى المستودع البعيد باستخدام Git على النحو التالي: $ git push heroku master Counting objects: 103, done. Delta compression using up to 4 threads. Compressing objects: 100% (84/84), done. Writing objects: 100% (103/103), 43.87 KiB | 0 bytes/s, done. Total 103 (delta 5), reused 0 (delta 0) remote: Compressing source files... done. remote: Building source: remote: remote: -----> Fetching set buildpack https://github.com/heroku/heroku-buildpack-php... done remote: -----> PHP app detected remote: remote: ! WARNING: Your 'composer.json' contains a non-'stable' setting remote: for 'minimum-stability'. This may cause the installation of remote: unstable versions of runtimes and extensions during this deploy. remote: It is recommended that you always use stability flags instead, remote: even if you have 'prefer-stable' enabled. For more information, remote: see https://getcomposer.org/doc/01-basic-usage.md#stability remote: remote: -----> Bootstrapping... remote: -----> Installing platform packages... remote: - php (7.0.7) remote: - ext-mbstring (bundled with php) remote: - apache (2.4.20) remote: - nginx (1.8.1) remote: -----> Installing dependencies. (...) remote: -----> Compressing... remote: Done: 15.5M remote: -----> Launching... remote: Released v4 remote: https://nameless-chamber-90421.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done. To https://git.heroku.com/nameless-chamber-90421.git * [new branch] master -> master إن نظرت إلى لوحة التحكّم في Heroku ستجد سجلا بالإجراءات السابقة. هذا كلّ ما في الأمر؛ اكتمل نشرُ تطبيقك الآن ويمكنك الوصول إليه على الرابط المذكور أعلاه. يجب أن تظهر صفحة Laravel المبدئية. تذكّر أن الرابط المنشَأ سابقا موجود فقط لأغراض الاختبار والتجربة، عندما يكون تطبيقك جاهزا لتلقي الجماهير يمكنك استخدام نطاقك الخاص وربطه بالتطبيق. تهجير قاعدة البيانات نشرنا في الخطوات السابقة تطبيق Laravel جديدا؛ إلا أن هذه الخطوات لن تكون كافية إن كان التطبيق يعتمد على قاعدة بيانات. ستحتاج في هذه الحالة إلى التأكد من تنفيذ جميع التهجيرات العالقة بعد كلّ عملية نشر. بما أن التطبيق جديد على Heroku فسنحتاج لتموين Provision قاعدة البيانات؛ نستخدم Toolbelt لهذا الغرض: $ heroku addons:create heroku-postgresql:hobby-dev Creating postgresql-rigid-59415... done, (free) Adding postgresql-rigid-59415 to nameless-chamber-90421... done Setting DATABASE_URL and restarting nameless-chamber-90421... done, v10 Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pg:copy Use `heroku addons:docs heroku-postgresql` to view documentation. ينشئ الأمر السابق قاعدة بيانات PostgreSQL معرّفة بالخطة المجانيّة hobby-dev التي تمكننا من إنشاء قاعدة بيانات مجانية على Heroku، على ألا يتجاوز عدد أسطرها العشرة آلاف. توجد خطط أخرى يمكن النظر فيها لإيجاد ما يناسبك إن كنت تريد استخدام Heroku بيئةً للإنتاج. يعود السبب في اختيارنا لقاعدة بيانات PostgreSQL بدلا من MySQL إلى أن دعم الأخيرة على Heroku محدود، ستجد لهذا السبب أن الكثير من التوثيق حول خدمة Heroku يعتمد على قاعدة البيانات PostgreSQL. ثم نفذ الأمر التالي للحصول على المزيد من التفاصيل عن قاعدة البيانات ومن ضمنها الاستيثاق (تأكد من اسم التطبيق): $ heroku config --app nameless-chamber-90421 | grep DATABASE_URL DATABASE_URL: postgres://USERNAME:PASSWORD@HOSTNAME:PORT/DATABASE يظهر في نتيجة الأمر اسمُ المستخدم USERNAME، كلمة السّر PASSWORD، اسم المضيف HOSTNAME، المنفذ PORT واسم قاعدة البيانات DATABASE. لن يكون ضروريا حفظ هذه الإعدادات فالمتغير DATABASE_URL الذي يخزّنها محفوظ تلقائيا في إعدادات الخادوم. يمكنك تسهيل إدارة قاعدتي البيانات على طرفيْ العمل (بيئة التطوير وبيئة الإنتاج) بضبط متغيّر بيئة باسم DATABASE_URL على جهازك المحلي وتخزين إعدادات قاعدة البيانات فيه ثم استخدامه لإعداد اتصال Laravel بقاعدة البيانات. ستحتاج لتثبيت PostgreSQL على جهازك إن لم يكن مثبتا مسبقا. يستعمل Laravel مبدئيا قاعدة بيانات MySQL، لذا يجب أن نعدّه لاستخدام PostgreSQL. نفتح ملفّ إعداد الاتصال بقاعدة البيانات config/database.php ونبحث عن السطر التالي: 'default' => env('DB_CONNECTION', 'mysql'), ثم نعدّله على النحو التالي: 'default' => env('DB_CONNECTION', 'pgsql'), ثم ننتقل إلى المقطع الخاصّ بإعداد PostgreSQL ضمن ملفّ إعداد الاتصال ونعدّله ليصبح كالتالي: 'pgsql' => [ 'driver' => 'pgsql', 'host' => parse_url(getenv("DATABASE_URL"))["host"], 'database' => substr(parse_url(getenv("DATABASE_URL"))["path"], 1), 'username' => parse_url(getenv("DATABASE_URL"))["user"], 'password' => parse_url(getenv("DATABASE_URL"))["pass"], 'charset' => 'utf8', 'prefix' => '', 'schema' => 'public', ], احفظ التعديلات ثم تأكد من أن اتصال التطبيق بقاعدة البيانات (محليّا)؛ يمكنك إنشاء نموذج في Laravel وتهجير مرافق له لغرض اختبار الاتصال بقاعدة البيانات. نفذ بعد التأكد من إعداد قاعدة البيانات التعديلات التي أضفتها إلى منطقة الإدارج في Git ثم أودعها في المستودع وأرسلها إلى المستودع البعيد على الخادوم: $ git add . $ git commit -m "Updated database configuration" $ git push heroku master يمكنك الآن تنفيذ التهجير على قاعدة البيانات على الخادوم عن طريق Toolbelt كالتالي: $ heroku run php artisan migrate --app nameless-chamber-90421 Running `php artisan migrate` attached to terminal... up, run.6981 ************************************** * Application In Production! * ************************************** Do you really wish to run this command? [y/N] y Migration table created successfully. Migrated: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_100000_create_password_resets_table Migrated: 2015_01_30_032004_create_todolists_table.php ترجمة -وبتصرّف- للمقال Deploying a Laravel Application to Heroku لصاحبه W. Jason Gilmore.
  11. 18 مثالا لاستخدام مدير الحزم YUM

    يتناول هذا المقال كيفية تثبيت الحزم، تحديثها، حذفها، البحث عنها وإدارة مستودعاتها Repositories على توزيعة لينكس تستخدم مدير الحزم YUM الذي تُطوّره شركة Red Hat. يُمكن استخدام الأمثلة المذكورة في هذا الدّرس، والتي جُرِّبت على خادوم Red Hat Enterprise Linux 7، لأغراض الدراسة، التحضير لشهادة متخصّصة أو لاستكشاف طرق جديدة لتثبيت الحزم والإبقاء على نظامك محدَّثا. يجب، لكي تتبع الأمثلة المقدَّمة في هذا الدرس، أن يكون لديك فهم لأساسيات عمل الأوامر في لينكس وتوزيعة تستخدم YUM للتجربة عليها، Fedora أو Red Hat Enterprise Linux 7 على سبيل المثال. ما هو مدير الحزم YUM؟ يُستخدَم مدير الحزم YUM (اختصار لـYellowdog Updater Modified) لإدارة البرامج المُحزَّمة بصيغة RPM (RedHat Package Manager). يمكن استخدام YUM من سطر الأوامر أو عبر واجهة رسومية. يتيح مدير الحزم YUM لمدير النظام تثبيت الحزم، تحديثها، حذفها أو البحث عنها. يُوزَّع مدير الحزم YUM حسب رخصة غنو GNU العمومية. تثبيت الحزم يُستخدَم الأمر install في مدير الحزم YUM على النحو التالي لتثبيت حزمة برنامج يُسمَّى Firefox. يتولّى مدير الحزم تثبيت الاعتمادات Dependencies، أي البرامج والمكتبات Libraries التي يتطلب عملُ الحزمة Firefox وجودَها (يجب أن تكون لديك صلاحيات المستخدم الجذر لتثبيت الحزم): [root@academy1 ~]# yum install firefox Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager Resolving Dependencies --> Running transaction check ---> Package firefox.x86_64 0:45.3.0-1.el7_2 will be installed --> Finished Dependency Resolution Dependencies Resolved ========================================================================= Package Arch Version Repository Size ========================================================================= Installing: firefox x86_64 45.3.0-1.el7_2 rhel-7-server-eus-rpms 76 M Transaction Summary ========================================================================= Install 1 Package Total download size: 76 M Installed size: 142 M Is this ok [y/d/N]: y Downloading packages: (...) Installed: firefox.x86_64 0:45.3.0-1.el7_2 Complete! يطلُب الأمر أعلاه التأكيد (Is this ok) قبل البدء في تنزيل الحزمة وتثبيتها (اكتب y ثم اضغط على زرّEnter للتأكيد). استخدم الخيار y- إن كنت ترغب في تثبيت الحزم تلقائيا دون طلب التأكيد: # yum -y install firefox حذف حزمة يحذف الأمر التالي الحزمة firefox تماما من النظام (بما في ذلك اعتماداتها): [root@academy1 ~]# yum remove firefox Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager Resolving Dependencies --> Running transaction check ---> Package firefox.x86_64 0:45.3.0-1.el7_2 will be erased --> Finished Dependency Resolution Dependencies Resolved =========================================================================================== Package Arch Version Repository Size =========================================================================================== Removing: firefox x86_64 45.3.0-1.el7_2 @rhel-7-server-eus-rpms 142 M Transaction Summary =========================================================================================== Remove 1 Package Installed size: 142 M Is this ok [y/N]: y Downloading packages: Running transaction check Running transaction test Transaction test succeeded Running transaction Erasing : firefox-45.3.0-1.el7_2.x86_64 1/1 Verifying : firefox-45.3.0-1.el7_2.x86_64 1/1 Removed: firefox.x86_64 0:45.3.0-1.el7_2 Complete! يطلُب الأمر التأكيد قبل حذف الحزمة. استخدم الخيار y- لتعطيل طلب التأكّد كالتالي: # yum -y remove firefox تحديث حزمة فلنفترض أن لديك حزمة MySQL قديمة، لم تُحدَّث منذ زمن؛ وترغب في تحديثها إلى آخر إصدار. الأمر التالي يؤدي المهمة: # yum update mysql سرد قائمة بالحزم يُستخدَم أمر السرد list للبحث عن حزمة معيّنة عن طريق اسمها. يبحث الأمر التالي عن حزمة باسم openssh: [root@academy1 ~]# yum list openssh Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager Installed Packages openssh.x86_64 6.6.1p1-25.el7_2 @rhel-7-server-eus-rpms يمكن جعل البحث أكثر دقة بذكر إصدار الحزمة إن عُرِف؛ مثلا: # yum list openssh-6.6.1p1 البحث عن حزمة يمكن استخدام الأمر search للبحث عن حزمة لا تتذكر اسمها بالضبط؛ مثلا نبحث عن ftp: [root@academy1 ~]# yum search ftp Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager ================== N/S matched: ftp ================================= ftp.x86_64 : The standard UNIX FTP (File Transfer Protocol) client tftp.x86_64 : The client for the Trivial File Transfer Protocol (TFTP) tftp-server.x86_64 : The server for the Trivial File Transfer Protocol (TFTP) vsftpd.x86_64 : Very Secure Ftp Daemon curl.x86_64 : A utility for getting files from remote servers (FTP, HTTP, and others) lftp.i686 : A sophisticated file transfer program lftp.x86_64 : A sophisticated file transfer program wget.x86_64 : A utility for retrieving files using the HTTP or FTP protocols Name and summary matches only, use "search all" for everything. الحصول على معلومات عن حزمة استخدم الأمر info للحصول على معلومات عن حزمة؛ مثلا قبل تثبيتها: [root@academy1 ~]# yum info firefox Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager Available Packages Name : firefox Arch : x86_64 Version : 45.3.0 Release : 1.el7_2 Size : 76 M Repo : rhel-7-server-eus-rpms/7Server/x86_64 Summary : Mozilla Firefox Web browser URL : http://www.mozilla.org/projects/firefox/ License : MPLv1.1 or GPLv2+ or LGPLv2+ Description : Mozilla Firefox is an open-source web browser, designed for standards : compliance, performance and portability. سرد جميع الحزم المتوفّرة يسرُد الأمر list عند استخدامها دون معطيات جميع الحزم المتوفرة في المستودعات؛ وهي كثيرة؛ لذا أعد توجيه نتيجة أمر السّرد إلى الأمر less لتيسير عمليّة التصفح: [root@academy1 ~]# yum list | less استخدم المعطى installed إن أردت أن يقتصر السّرد على الحزم المثبّتة: [root@academy1 ~]# yum list installed | less العثور على حزمة انطلاقا من ملفّ يُستخدَم الأمر provides في مدير الحزم YUM لمعرفة الحزمة التي يتبع لها ملفّ مّا. مثلا؛ نريد معرفة الحزمة التي توفّر ملفّ الإعداد etc/httpd/conf/httpd.conf/، لذا ننفذ الأمر بالطريقة التالية: [root@academy1 ~]# yum provides /etc/httpd/conf/httpd.conf Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager httpd-2.4.6-17.el7.x86_64 : Apache HTTP Server Repo : rhel-7-server-eus-rpms Matched from: Filename : /etc/httpd/conf/httpd.conf httpd-2.4.6-17.el7.x86_64 : Apache HTTP Server Repo : rhel-7-server-rpms Matched from: Filename : /etc/httpd/conf/httpd.conf يُظهر الأمر اسم الحزمة والمستودع الذي تأتي منه. التحقق من وجود تحديثات وتحديث النظام استخدم الأمر yum check-update لمعرفة الحزم المثبّتة التي تتوفّر لها تحديثات. أما إن أردت تحديث الحزم إلى آخر إصدار متوفّر فالأمر yum update يؤدي المهمة. سرد مجموعات الحزم تُجمَّع كثير من الحزم في مجموعات لتسهيل التعامل معها؛ فبدلا من تثبيت هذه الحزم الواحدة تلو الآخرى، أو كتابة أسمائها جميعا، يمكن تثبيتها دفعة واحدة عن طريق اسم المجموعة. استخدم الأمر grouplist لسرد مجموعات الحزم المتوفّرة: [root@academy1 ~]# yum grouplist Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager Available Environment Groups: Minimal Install Infrastructure Server File and Print Server Basic Web Server Virtualization Host Server with GUI Installed Groups: Development Tools Graphical Administration Tools Legacy UNIX Compatibility Security Tools System Administration Tools Available Groups: Compatibility Libraries Console Internet Tools RT Scientific Support Smart Card Support System Management Done تثبيت مجموعة حزم استخدم الأمر groupinstall لتثبيت مجموعة حزم. يثبّت الأمر التالي مجموعة حزم File and Print Server (خادوم الطباعة وتشارك الملفات): [root@academy1 ~]# yum groupinstall 'File and Print Server' Dependencies Resolved ====================================================================================== Package Arch Version Repository Size ====================================================================================== Installing for group install "File and Storage Server": cifs-utils x86_64 6.2-7.el7 rhel-7-server-eus-rpms 84 k nfs4-acl-tools x86_64 0.3.3-14.el7 rhel-7-server-eus-rpms 47 k targetcli noarch 2.1.fb41-3.el7 rhel-7-server-eus-rpms 61 k targetd noarch 0.7.1-1.el7 rhel-7-server-eus-rpms 48 k Installing for dependencies: PyYAML x86_64 3.10-11.el7 rhel-7-server-eus-rpms 153 k libyaml x86_64 0.1.4-11.el7_0 rhel-7-server-eus-rpms 55 k lvm2-python-libs x86_64 7:2.02.130-5.el7_2.5 rhel-7-server-eus-rpms 166 k pyparsing noarch 1.5.6-9.el7 rhel-7-server-eus-rpms 94 k python-configshell noarch 1:1.1.fb18-1.el7 rhel-7-server-eus-rpms 67 k python-kmod x86_64 0.9-4.el7 rhel-7-server-eus-rpms 57 k python-rtslib noarch 2.1.fb57-3.el7 rhel-7-server-eus-rpms 88 k python-setproctitle x86_64 1.1.6-5.el7 rhel-7-server-eus-rpms 15 k python-urwid x86_64 1.1.1-3.el7 rhel-7-server-eus-rpms 654 k Transaction Summary ========================================================================================= Install 4 Packages (+9 Dependent packages) Total download size: 1.6 M Installed size: 5.7 M Is this ok [y/d/N]: تحديث مجموعة حزم يُستخدَم الأمر groupupdate على النحو التالي لتحديث مجموعة حزم سبق تثبيتها: [root@academy1 ~]# yum groupupdate 'File and Print Server' حذف مجموعة حزم استخدم الأمر groupremove لحذف مجموعة حزم مثبتة؛ مثلا لحذف مجموعة الحزم السابقة: [root@academy1 ~]# yum groupremove 'File and Print Server' سرد مستودعات YUM يمكن سرد المستودعات المفعَّلة في مدير الحزم YUM باستخدام الأمر التالي: [root@academy1 ~]# yum repolist Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager repo id repo name status !rhel-7-server-eus-rpms/7Server/x86_64 Red Hat Enterprise Linux 7 Server - Extended Update Support (RPMs) 11,241 !rhel-7-server-rpms/7Server/x86_64 Red Hat Enterprise Linux 7 Server (RPMs) 11,250 !rhel-7-server-rt-beta-rpms/x86_64 Red Hat Enterprise Linux for Real Time Beta (RHEL 7 Server) (RPMs) 15 !rhel-7-server-rt-rpms/7Server/x86_64 Red Hat Enterprise Linux for Real Time (RHEL 7 Server) (RPMs) 129 !rhel-ha-for-rhel-7-server-eus-rpms/7Server/x86_64 Red Hat Enterprise Linux High Availability (for RHEL 7 Server) - Extended Update Support (RP 224 !rhel-ha-for-rhel-7-server-rpms/7Server/x86_64 Red Hat Enterprise Linux High Availability (for RHEL 7 Server) (RPMs) 224 !rhel-rs-for-rhel-7-server-eus-rpms/7Server/x86_64 Red Hat Enterprise Linux Resilient Storage (for RHEL 7 Server) - Extended Update Support (RP 279 !rhel-rs-for-rhel-7-server-rpms/7Server/x86_64 Red Hat Enterprise Linux Resilient Storage (for RHEL 7 Server) (RPMs) 279 repolist: 23,641 أضف الخيار all إلى الأمر السابق إن أردت سرد جميع المستودعات بما فيها تلك غير المفعَّلة: [root@academy1 ~]# yum repolist all تثبيت حزمة مع تحديد المستودع يُستخدم الخيار enablerepo-- في أمر التثبيت لتحديد المستودع الذي نريد تنزيل الحزمة منه: [root@academy1 ~]# yum --enablerepo=rhel-7-server-rpms install postgresql Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager Resolving Dependencies --> Running transaction check ---> Package postgresql.x86_64 0:9.2.15-1.el7_2 will be installed --> Processing Dependency: postgresql-libs(x86-64) = 9.2.15-1.el7_2 for package: postgresql-9.2.15-1.el7_2.x86_64 --> Processing Dependency: libpq.so.5()(64bit) for package: postgresql-9.2.15-1.el7_2.x86_64 --> Running transaction check ---> Package postgresql-libs.x86_64 0:9.2.15-1.el7_2 will be installed --> Finished Dependency Resolution Dependencies Resolved ======================================================================================= Package Arch Version Repository Size ======================================================================================= Installing: postgresql x86_64 9.2.15-1.el7_2 rhel-7-server-eus-rpms 3.0 M Installing for dependencies: postgresql-libs x86_64 9.2.15-1.el7_2 rhel-7-server-eus-rpms 231 k Transaction Summary ======================================================================================== Install 1 Package (+1 Dependent package) Total download size: 3.2 M Installed size: 16 M Is this ok [y/d/N]: صدفة YUM تفاعلية يتيح مدير الحزم YUM صدفة Shell لتنفيذ أوامر عدّة لإدارة الحزم: [root@academy1 ~]# yum shell Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager > update > repolist repo id repo name status rhel-7-server-eus-rpms/7Server/x86_64 Red Hat Enterprise Linux 7 Server - Extended Update Support (RPMs) 11,241 rhel-7-server-rpms/7Server/x86_64 Red Hat Enterprise Linux 7 Server (RPMs) 11,250 rhel-7-server-rt-beta-rpms/x86_64 Red Hat Enterprise Linux for Real Time Beta (RHEL 7 Server) (RPMs) 15 rhel-7-server-rt-rpms/7Server/x86_64 Red Hat Enterprise Linux for Real Time (RHEL 7 Server) (RPMs) 129 rhel-ha-for-rhel-7-server-eus-rpms/7Server/x86_64 Red Hat Enterprise Linux High Availability (for RHEL 7 Server) - Extended Update Support (RPM 224 rhel-ha-for-rhel-7-server-rpms/7Server/x86_64 Red Hat Enterprise Linux High Availability (for RHEL 7 Server) (RPMs) 224 rhel-rs-for-rhel-7-server-eus-rpms/7Server/x86_64 Red Hat Enterprise Linux Resilient Storage (for RHEL 7 Server) - Extended Update Support (RPM 279 rhel-rs-for-rhel-7-server-rpms/7Server/x86_64 Red Hat Enterprise Linux Resilient Storage (for RHEL 7 Server) (RPMs) 279 > exit Leaving Shell عرض سجلّ أوامر YUM يُستخدَم الأمر history على النحو التالي لعرض قائمة بآخر أوامر YUM المنفّذة: [root@academy1 ~]# yum history Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager ID | Login user | Date and time | Action(s) | Altered ------------------------------------------------------------------------------- 14 | Mohamed ... <meyil> | 2016-09-01 23:57 | Erase | 1 13 | Mohamed ... <meyil> | 2016-09-01 23:48 | Install | 1 12 | Mohamed ... <meyil> | 2016-08-02 23:41 | I, U | 6 11 | Mohamed ... <meyil> | 2016-07-31 23:19 | Install | 2 10 | Mohamed ... <meyil> | 2016-07-21 22:09 | Install | 1 9 | Mohamed ... <meyil> | 2016-07-21 15:29 | Install | 4 8 | Mohamed ... <meyil> | 2016-07-21 14:18 | I, U | 75 7 | Mohamed ... <meyil> | 2016-06-11 01:32 | Erase | 1 6 | Mohamed ... <meyil> | 2016-06-07 13:51 | Update | 1 5 | Mohamed ... <meyil> | 2016-06-05 02:57 | Install | 2 4 | Mohamed ... <meyil> | 2016-06-05 02:56 | Update | 1 3 | Mohamed ... <meyil> | 2016-05-28 03:16 | Install | 1 2 | Mohamed ... <meyil> | 2016-05-28 02:45 | I, U | 190 EE 1 | System <unset> | 2016-05-27 20:43 | Install | 1293 history list تنظيف تخبئة Cache مدير الحزم يحتفظ مدير الحزم YUM بنسخ من البيانات المتعلقة بالحزم ضمن مجلّد var/cache/yum/؛ يمكن حذف جميع هذه النسخ بتنفيذ الأمر التالي: [root@academy1 ~]# yum clean all Loaded plugins: langpacks, product-id, search-disabled-repos, subscription-manager Cleaning repos: rhel-7-server-eus-rpms rhel-7-server-rpms rhel-7-server-rt-beta-rpms rhel-7-server-rt-rpms rhel-ha-for-rhel-7-server-eus-rpms : rhel-ha-for-rhel-7-server-rpms rhel-rs-for-rhel-7-server-eus-rpms rhel-rs-for-rhel-7-server-rpms Cleaning up everything ترجمة - بتصرّف - لمقال20 Linux YUM (Yellowdog Updater, Modified) Commands for Package Management لصاحبه Ravi Saive.
  12. 10 أمثلة لجدولة المهام باستخدام Cron

    يتكرّر أحيانا تنفيذ مهامّ وعمليات بحيث يستهلك إتمامها يدويا الكثير من الوقت. يمكن في هذه الحالة اللجوء إلى جدولة المهام لتنفيذها دوريّا في الخلفية، دون الحاجة للتدخل اليدوي، حسب معايير زمنية محدّدة مسبقا. سنرى في هذا المقال كيف يمكننا استخدام أداة Cron والأوامر المصاحبة لها من أجل تنفيذ إجراءات دوريا في الخلفية. يكثُر استخدام Cron لتنفيذ مهامّ النسخ الاحتياطي Backup، تحديث الحزم ومزامنة Synchronization الملفات؛ على سبيل المثال. يقوم مبدأ عمل Cron على التحقق كلّ دقيقة من العناصر الموجودة في الجدول الخاصّ به (ملفّ)، ويُسمّى Crontab (اختصار لـCron table؛ جدول Cron). تحدّد عناصر Crontab المهامّ المُجدوَلة والمجالات الزمنية لتنفيذها. ملحوظة: يُفعَّل Cron مبدئيا لجميع المستخدمين، فيحصُل كل مستخدم على جدول Cron خاصّ به؛ إلا أنه يمكن، عبر الملفّ etc/cron.deny/، تغيير هذا الإعداد وتقييد إمكانيّة جدولة المهامّ بالنسبة للمستخدمين. توجد في ملفّ Crontab أسطر تتكوّن من ستة حقول يُفصل بينها بمسافة أو علامة جدولة (زرّ Tab في لوحة المفاتيح). تُمثّل الحقول الخمسة الأولى من الملفّ المجال الزمني لتنفيذ الأمر الموجود في الحقل السادس؛ وهي على النحو التالي (ابتداءً من اليسار): الدقيقة: يأخذ هذا الحقل قيما عددية في المجال من 0 إلى 59. الساعة: يأخذ قيما تتراوح بين 0 و23. اليوم (في الشهر): يأخذ قيمة من 1 إلى 31. الشهر: يأخذ قيمة عددية في المجال من 1 إلى 12؛ كما يمكن تحديد الأحرف الأولى من اسم الشهر (Jan وDec ليناير ودجمبر على التوالي). اليوم (في الأسبوع): يأخذ قيمة في المجال من 0 إلى 6. يمثّل العدد 0 يوم الأحد، 1 الاثنين.. و6 السبت. كما يمكن تعيين الأحرف الثلاثة الأولى من اليوم (Wed مثلا بالنسبة ليوم الأربعاء). بالنسبة للحقل السادس فهو - كما أسلفنا - الأمر الذي نريد تنفيذه في الوقت المحدّد عن طريق الحقول الزمنية السابقة. سرد المهامّ الموجودة في جدول Cron يُستخدَم الخيار l- مع الأمر crontab لسرد قائمة بأسطر (مهامّ) المستخدم الحالي المضبوطة في جدول Crontab: $ crontab -l 00 10 * * * /bin/ls >/ls.txt التعديل على المهام المُجدولة يتيح الخيّار e- مع الأمر crontab التعديل على المهامّ المجدولة بتغيير إعداداتها في الملف Crontab: $ crontab -e يفتح الأمر جدول المهامّ بمحرّر النصوص المبدئي (أو يُظهر قائمة بالمحرّرات المتاحة للاختيار منها). يمكن بعدها تغيير الإعدادات ثم حفظ الملف. سرد المهام المجدولة لمستخدم يُحدّد الخيار u- المستخدم الذي نريد سرد مهامّه؛ وذلك على النحو التالي: $ crontab -u academy -l no crontab for academy يطلُب الأمر أعلاه سرد المهام المجدولة الخاصّة بالمستخدم academy، وتشير النتيجة إلى عدم وجود مهام مجدولة لهذا المستخدم. ملحوظة: لا يمكن لمستخدم عادي سرد مهام مستخدم آخر؛ لا تُتاح هذه الصلاحية سوى للمستخدم الجذر. حذف المهام المجدولة ينبغي الحذر عند استخدام الخيار r- مع الأمر crontab إذ أنه يحذف جميع المهام المجدولة، دون طلب تأكيد الأمر. أضف الخيار i-، الذي يطلُب تأكيد الحذف، بدلا من استخدام r- لوحده: $ crontab -i -r crontab: really delete academy's crontab? تخصيص المدة الزمنية باستخدام المحارف الخاصّة (*، -، / و#) تُستخدَم هذه المحارف لتخصيص الحقول الزمنية في أسطر جدول المهام: يعني استخدام العلامة * في أحد الحقول الخمسة الأولى من السّطر أننا نريد تنفيذ الأمر مهما كانت قيمة هذا الحقل. مثلا؛ إن استُخدمت في الحقل الثاني فهذا يعني أن المطلوب تنفيذ الأمر بغض النظر عن الساعة. تُستخدَم العلامة - لتعريف مجال بالنسبة للحقل. مثلا 9-0 في حقل الدقيقة تعني أن المطلوب تنفيذ الأمر في الدقائق من 0 إلى 9. يُساعد الخط المائل / في تقسيم الحقل. مثلا 10/ في حقل الدقائق تعني كل عشر دقائق. تفرّق الفاصلة , بين عناصر عدّة في نفس الحقل. مثلا؛ 1,3,5 في الحقل الخامس تعني أننا نريد تنفيذ المهمة أيام الاثنين، الأربعاء والخميس. جدولة المهام على مستوى النظام يُمكن لمديري الأنظمة استخدام مجلدات معدّة مسبقا لتنفيذ مهام على مستوى النظام. تُنفَّذ السكربتات الموجودة في المجلدات التاليّة -على الترتيب - مرة كلّ يوم، مرة كلّ ساعة، مرة في الشّهر ومرة في الأسبوع: /etc/cron.daily /etc/cron.hourly /etc/cron.monthly /etc/cron.weekly كما يُمكن استخدام المجلّد etc/cron.d/ لجدولة المهام بوضع ملفات تشبه في صيغتها Crontab؛ مع زيادة حقل، بعد الحقول الزمنية وقبل الأمر (ليصبح العدد الإجمالي للحقول سبعة)، للمستخدم الذي تُنفَّذ باسمه المهمة. تنفيذ أمر عند وقت معيَّن نستخدم في المثال أدناه الأمر crontab -e للتعديل على جدول المهام ثم نضيف سطرا جديدا لمهمة تحذف جميع الملفات الفارغة في المجلّد tmp/. تُنفَّذ المهمة يوميا عند الساعة 00 (منتصف الليل) و30 دقيقة. # crontab -e 30 0 * * * find /tmp -type f -empty -delete المدد الزمنية الشائعة يمكنك استخدام سلاسل المحارف التالية مكانَ الحقول الزمنية الخمسة سلسلة المحارف العمل reboot@ تنفيذ الأمر عندما يعاد تشغيل النظام daily@ مرة في اليوم. يمكن أيضا استخدام @midnight للتنفيذ عند منتصف الليل. weekly@ مرة في الأسبوع. yearly@ مرة في السنة. تنفيذ أوامر عدّة تُستخدم العلامة && في حقل الأمر لتحديد أكثر من أمر للتنفيذ؛ مثلا: @daily command1 && command2 يطلب السّطر السابق تنفيذ الأمر command1 وcommand2 يوميا. تعطيل إشعارات البريد يُرسل Cron مبدئيا رسائل بريد إلى المستخدم عند تنفيذ المهام المجدولة (في حال كان النظام الذي يعمل عليه قادرا على ذلك). يمكن تعطيل هذه الإشعارات بإضافة السطر التالي إلى Crontab (عن طريق الأمر crontab -e): * * * * * >/dev/null 2>&1 ترجمة - بتصرّف - لمقال 11 Cron Scheduling Task Examples in Linux لصاحبه Ravi Saive.
  13. تثبيت Homestead وإعداده لتشغيل تطبيقات Laravel

    إن كنت تخطّط لتطوير مشروع على Laravel فإطار العمل - ولغة البرمجة PHP - لن يكونا كلّ ما تحتاجه للبدء في العمل؛ بل ستكون بحاجة إلى برنامج لإدارة قاعدة البيانات (مثلا MySQL أو PostgreSQL)، خادوم وِب (Nginx أو Apache) وربما تقنيات أخرى حسب الحاجة. قد يمثّل إعداد بيئة عمل بكلّ هذه التقنيات الكثير من العمل المرهق بالنسبة لك؛ خصوصا إن كنت ممّن يفضّل كتابة الشفرة البرمجية بدلا من التعامل مع مشاكل الإعدادات. مثّل ظهور الآلات الافتراضية Virtual machines, VM وانتشارها في السنوات الأخيرة فرصة للتغلب على الكثير من مشاكل الإعدادات. الآلات (الأجهزة) الافتراضية هي مجموعة برمجيات تعمل على نظام تشغيل لمحاكاة عمل جهاز فعلي. يمكن بهذه الطريقة مثلا، تشغيل أوبونتو لينكس داخل وندوز أو العكس. كما تمكن تجربة نظام مخصّص للخواديم داخل حاسوب شخصي؛ زيادة على أمور أخرى كثيرة. تتيح الآلات الافتراضية إعداد نظام تشغيل مخصّص، تثبيت برامج عليه، إعدادها؛ ثم توزيع النظام بعد ذلك للمهتمين للبدء في استعماله كما هو. استفاد مطورو Laravel من تقنية الآلات الافتراضية وأنشؤوا نظاما مخصّصا معدّا بجميع ما تحتاجه للبدء في التطوير على Laravel؛ أعطى فريق Laravel لهذه الآلات الافتراضية اسم Homestead. تستخدم Homestead برنامج إدارة الإعدادات Vagrant لتشغيلها. تأتي آلة Homestead معدّة بنظام تشغيل أوبونتو 14.04، لغة البرمجة PHP 7، خادوم وِب Nginx، نظامي إدارة قواعد بيانات MySQL وPostgreSQL وأدوات متفرقة أخرى. لا يتطلّب إعداد Vagrant لتشغيل Homestead الكثير من الوقت، كما أنه يعمل على OSX، لينكس ووندوز. تثبيت Homestead الخطوة الأولى لتثبيت Homestead هي تثبيت VirtualBox وVagrant على التوالي. يمكن من موقعي البرنامجيْن الحصولُ على مثبّتات Installers سهلة لأنظمة التشغيل المختلفة. افتح بعد تثبيت VirtualBox وVagrant سطر الأوامر ونفّذ الأمر التالي (قد يستغرق تنزيل الآلة الافتراضية وقتا، حسب سرعة اتصالك بالإنترنت): $ vagrant box add laravel/homestead ==> box: Loading metadata for box 'laravel/homestead' box: URL: https://atlas.hashicorp.com/laravel/homestead This box can work with multiple providers! The providers that it can work with are listed below. Please review the list and choose the provider you will be working with. 1) virtualbox 2) vmware_desktop Enter your choice: 1 ==> box: Adding box 'laravel/homestead' (v0.4.4) for provider: virtualbox box: Downloading: https://vagrantcloud.com/laravel/boxes/homestead/versions/0.4.4/providers/virtualbox.box ==> box: Successfully added box 'laravel/homestead' (v0.4.4) for 'virtualbox'! يثبت الأمر أعلاه صندوق Homestead. يُستخدَم المصطلح صندوق Box للإشارة إلى حزمة في Vagrant. يعدّ مجتمع Vagrant آلات افتراضية بأنظمة تشغيل ثُبتت عليها برامج مختلفة - حسب الغرض - لتكون الآلة جاهزة للعمل فورا. يمكنك الحصول على لائحة بالآلات الافتراضية الشائعة الاستخدام التي يشرف مجتمع Vagrant على صيانتها عبرهذا الرابط. ثم ننتقل لتثبيت Homestead باستنساخ مستودع Github في المجلّد الشخصي للمستخدم كالتالي: cd ~ git clone https://github.com/laravel/homestead.git Homestead ثم ننفذ، بعد نسخ المستودع، الأمر التالي الذي ينشئ ملفّ الإعداد Homestead.yaml ضمن مجلّد مخفي باسم homestead.: bash init.sh ملحوظة: يجب تنفيذ الأمر من داخل المجلد Homestead. إعداد Homestead تحدّد التعليمة provider في ملفّ الإعداد homestead/Homestead.yaml. المزوّد الذي سيستخدمه Vagrant؛ إما virtualbox أو vmware_desktop. في حالتنا اخترنا virtualbox. الخطوة التالية هي إعداد مجلّد المشروع الذي ستتشاركه مع الآلة الافتراضية. تتطلّب مشاركةُ مجلد المشروع تحديد مكان مفتاح SSH العمومي الخاص بك. تُستخدَم التعمية Encryption المعتمدة على المفاتيح العموميّة والخصوصيّة لتأمين تشارك المجلّد مع الآلة الافتراضية. افتح ملفّ Homestead.yaml الموجود في مجلّد homestead. وحدّد مكان السّطر التالي: authorize: ~/.ssh/id_rsa.pub إن كنت تعمل على لينكس أو OS X فلن تحتاج - على الأرجح - للتعديل على هذا السطر، نظرا لكون الملفات الخاصة بمفاتيح SSH تُخزَّن عادة في مجلّد باسم ssh. ضمن مجلّد المستخدم. إن استخدمتَ مجلدا مخصّصا لمفاتيح SSH فسيتوجّب عليك تحديث المسار بمقتضى ذلك. أما إذا كنت تستخدم وندوز فستحتاج إلى تحديث السطر ليوافق صيغة المسارات في وندوز، مثلا كالتالي: authorize: c:/Users/wjgilmore/.ssh/id_rsa.pub ملحوظة: استخدم برنامج PuTTY على وندوز لتوليد مفاتيح التعميّة. نحتاج الآن لتعديل قائمة المجلدات في ملفّ إعداد Homestead لتعيين مسار التطبيق. توجد فقرتان في ملفّ الإعدادات تتوليان التعامل مع مجلدات التطبيق وهما folders وsites. تبدو الفقرتان مبدئيا على النحو التالي: folders: - map: ~/Code to: /home/vagrant/Code sites: - map: homestead.app to: /home/vagrant/Code/Laravel/public تعرفّ الخاصيّة map في الفقرة folders المسار الذي توجد عليه ملفات مشروع Laravel الذي تعمل عليه. القيمة المبدئية لهذه الخاصيّة هي Code/~؛ بمعني أن Homestead يتوقّع وجود ملفات مشروعك ضمن مجلّد باسم Code متفرّع من المجلّد الشخصي للمستخدم. يمكنك تغيير قيمة هذه الخاصيّة حسب رغبتك؛ لكن تذكر أن المسار يجب أن يحيل إلى المجلد الجذر لمشروع Laravel. بالنسبة للخاصية to في الفقرة folders فتعرّف مسار المجلّد الذي ستُزامن معه محتويات المجلّد المعرَّف في الخاصيّة map السابقة. يمكن للآلة الافتراضية قراءة محتويات المجلد المعرَّف على المسار to عكس محتويات المجلّد المعرَّف في map. نتيجة لهذا الإعداد يُزامن محتوى المجلد الأخير (المعرَّف في to) تلقائيا مع محتوي المجلّد الأول (المعرَّف في map)؛ لتتمكن الآلة الافتراضية من قراءته. ملحوظة: من الأفضل ألا تحتوي أسماء المجلدات على مسافات. توجد في الفقرة sites خاصيتان تحملان نفس الاسميْن السابقيْن، map وto. تعرّف الخاصيّة map في الفقرة sites اسم النطاق الذي ستستخدمه للوصول إلى التطبيق؛ في المثال أعلاه تصل إلى التطبيق بكتابة homestead.app في شريط عنوان المتصفح. أما الخاصيّة to فتعرّف مجلّد الوِب الجذر في مشروع Laravel، وهو مبدئيا المجلّد public الموجود في المجلّد الجذر للمشروع. ملحوظة: المسارات المحدّدة في خاصيّة to في كلتا الحالتين هي بالنسبة لمجلدات موجودة داخل الآلة الافتراضية. سننشئ مجلّدا باسم app.homestead نخصّصه للمشروع الذي سنعمل عليه؛ نضيف مسار هذا المجلّد إلى الخاصية map في الفقرة folders التي تصبح كالتالي: folders: - map: /home/zeine77/Documents/projects/app.homestead to: /home/vagrant/Code ثم ننشئ داخل المجلد app.homestead مجلدا باسم Laravel وداخل هذا الأخير مجلدا باسم public حتى نوافق مسار المجلد home/vagrant/Code/Laravel/public/ الذي يشير إليه اسم النطاق (الخاصيّة to في الفقرة sites). ملحوظة: تذكّر أن المجلّد home/vagrant/Code/ هو نسخة طبق الأصل من المجلّد home/zeine77/Documents/projects/app.homestead/، ولكنه موجود داخل الآلة الافتراضية. يعني هذا أن المجلّد /Laravel/public المستخدَم في الخاصيّة to من الفقرة sites (القيمة /home/vagrant/Code/Laravel/public/) يجب أن يكون موجودا في الأصل (أي في المجلّد home/zeine77/Documents/projects/app.homestead/). هذا هو السبب الذي جعلنا ننشئ المجلد Laravel/public بالطريقة المذكورة أعلاه. سننشئ الآن داخل المجلّد public ملفا باسم index.php ونضع فيه الشفرة التالية: <?php echo "Hello from Homestead!"; ?> احفظ الملفّ ثم أغلقه. يعني هذا أننا عند تشغيل الآلة الافتراضية والدخول إلى العنوان homestead.app ستظهر لدينا العبارة !Hello from Homestead. الخطوة الأخيرة قبل الانتقال لتشغيل الآلة الافتراضية هي تعديل ملف المضيفات ليتعرّف النظام على العنوان homestead.app. يوجد ملف المضيفات على المسار etc/hosts/ بالنسبة للينكس و C:\Windows\System32\drivers\etc\hosts بالنسبة لوندوز. أضف السّطر التالي إلى الملفّ: 192.168.10.10 homestead.app ملحوظة: تأكّد من موافقة العنوان (192.168.10.10 في السطر أعلاه) لعنوان IP الموجود في بداية الملفّ Homestead.yaml. حان الوقت - بعد إكمال الخطوات المشروحة أعلاه - لتشغيل الآلة الافتراضية وتجربة عمل الإعدادات. ننتقل إلى المجلد Homestead (حيثُ نسخنا المشروع من Github) ثم ننفّذ الأم التالي: $ vagrant up يستغرق تشغيل الآلة الافتراضية بعض الوقت وتظهر مخرجات الأمر: Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'laravel/homestead'... ==> default: Matching MAC address for NAT networking... ==> default: Checking if box 'laravel/homestead' is up to date... (...) ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat default: Adapter 2: hostonly ==> default: Forwarding ports... default: 80 (guest) => 8000 (host) (adapter 1) default: 443 (guest) => 44300 (host) (adapter 1) default: 3306 (guest) => 33060 (host) (adapter 1) default: 5432 (guest) => 54320 (host) (adapter 1) default: 22 (guest) => 2222 (host) (adapter 1) (...) ==> default: nginx stop/waiting ==> default: nginx start/running, process 1940 ==> default: php7.0-fpm stop/waiting ==> default: php7.0-fpm start/running, process 1959 (...) ==> default: Running provisioner: shell... default: Running: /tmp/vagrant-shell20160628-13381-s5ikfi.sh يمكنك الآن فتح المتصفّح وتجربة عمل الإعدادت بزيارة الرابط http:homestead.app. إن جرت الأمور على ما يُرام فستظهر العبارة التالية في المتصفّح: Hello from Homestead ! إن تعذّر تشغيل الآلة الافتراضية (خطأ في مخرجات الأمر vagrant up) فتأكد من ملف الإعداد Homestead.yaml. إن اشتغلت الآلة ولم تستطع إظهار محتوى الصفحة فتأكد من إعدادات المضيف، وخصوصا عنوان IP وموافقته للعنوان الموجود في ملفّ الإعداد Homestead.yaml؛ ينبغي التأكد كذلك من المسارات ومن حالة كتابة الأحرف (كبيرة أو صغيرة). أنشأنا المجلّد Laravel/public وأضفنا إليه الملفّ index.php للتأكد من أن Homestead يعمل من دون مشاكل؛ لكن هدفنا هو استخدام Homestead لعرض مشاريع بـLaravel؛ وهو ما سنعدّه بعد قليل. يمكننا الآن توقيف عمل الآلة الافتراضية بتنفيذ الأمر (من داخل المجلد Homestead): $ vagrant destroy --force ==> default: Forcing shutdown of VM... ==> default: Destroying VM and associated drives... ثم حذف المجلّد Laravel (وبالتالي المجلد public المتفرع منه). الولوج إلى الآلة الافتراضية عن طريق SSH نظرا لكون Homestead مبني على توزيعة أوبونتو فيمكن الولوج إليه عن طريق SSH، تماما كما هي الحال بالنسبة لأي خادوم آخر. قد تودّ الدخول إلى الآلة الافتراضية لأسباب منها على سبيل المثال تغيير إعدادات قاعدة البيانات أو خادوم الوِب، إضافة برامج جديدة أو لإجراء تعديلات أخرى. استخدم الأمر التالي، بعد تشغيل الآلة الافتراضية ، للدخول عن طريق SSH: $ vagrant ssh تظهر بعد تنفيذ الأمر رسالة ترحيبية ومحثّ Prompt أوامر: Welcome to Ubuntu 14.04.4 LTS (GNU/Linux 3.19.0-25-generic x86_64) * Documentation: https://help.ubuntu.com/ vagrant@homestead:~$ سيُسجَّل دخولك باسم المستخدم vagrant؛ يمكنك بعدها تنفيذ أوامر لينكس حسب الحاجة. ستجد أنه يوجد مجلّد باسم Code داخل المجلّد الشخصي للمستخدم vagrant. نفّذ الأمر exit إن أردت الخروج من الآلة الافتراضية. إنشاء تطبيق Laravel تأكدنا في الخطوات السابقة من إعداد Homestead وأنه جاهز للعمل. يمكننا الآن إنشاء مشروع Laravel على Homestead. لذا سنستخدم composer لإنشاء مشروع Laravel جديد داخل المجلّد app.homestead. اختر اسما مناسبا للمشروع؛ مثلا demo: $ composer create-project laravel/laravel demo لدينا الآن مشروع Laravel على المسار home/zeine77/Documents/projects/app.homestead/demo/؛ ينبغي أن نعدّل ملفّ الإعداد Homestead.yaml ليشير إلى هذا المجلد. نفتح الملفّ لتحريره؛ ونغيّر قيمة الخاصيّة to ضمن الفقرة sites. القيمة القديمة هي التالية (أعددناها في خطوة سابقة): sites: - map: homestead.app to: /home/vagrant/Code/Laravel/public لتصبح كالتالي: sites: - map: homestead.app to: /home/vagrant/Code/demo/public احفظ الملفّ ثم أغلقه. نعود لمجلّد Homestead وننفذ الأمر التالي لاعتماد التعديلات (إن كانت الآلة الافتراضية تعمل): $ vagrant provision أما إن لم تكن الآلة الافتراضية تعمل فيجب تشغيلها: $ vagrant up انتظر اعتماد التعديلات أو تشغيل الآلة الافتراضية؛ ثم توجّه إلى المتصفّح وأدخل العنوان http://homestead.app، وستظهر الصفحة المبدئية لمشروع Laravel. خاتمة لست ملزما بمشروع Laravel واحد على آلة Homestead؛ بل يمكنك إنشاء العدد الذي تريد. كل ما يجب عليك فعله هو تحديث قيم map وto في فقرتي folders وsites من ملف الإعداد Homestead.yaml بالمسارات المناسبة. يمكن مثلا اتخاذ مجلد لمشاريع Laravel تستخدمه لإنشاء المشاريع الجديدة داخله ثم تعدّ الخاصيّة map في folders للإشارة إلى المجلد المشترك؛ وعند إضافة مشروع جديد تضيف نطاقا جديدا له في sites؛ مع تحديث قيمة to لتشير إلى المجلد الموافق له في المجلد المشترك كما في المثال التالي: folders: - map: /home/zeine77/Documents/projects/app.homestead to: /home/vagrant/Code sites: - map: homestead.app to: /home/vagrant/Code/demo/public - map: anotherhomestead.app to: /home/vagrant/Code/anotherdemo/public لا تنس تحديث ملف المضيفات (hosts) بإضافة اسم النطاق الجديد (anotherhomestead.app) في المثال أعلاه: 192.168.10.10 anotherhomestead.app ترجمة - بتصرّف - لمقال Installing and Configuring Homestead 2.0 for Laravel 5. حقوق المقال محفوظة لصاحبه W. Jason Gilmore.
  14. هيأنا في الجزأ الأوّل من هذا الدرس قاعدة البيانات والتهجيرات، وأعددنا أساس التوجيه والمخطّط العام للقوالب والعروض. نكمل في هذا الجزأ الثاني إعداد بقية العناصر اللّازمة لبناء تطبيق إدارة مهام قاعدي. إضافة المهامّ التحقّق لدينا الاآن استمارة في العرض resources/views/tasks/index.blade.php؛ سنحتاج لإضافة شفرة إلى الدالة TaskController@store من أجل التحقّق من المُدخلات القادمة من الاستمارة ثم إنشاء مهمة جديدة. نبدأ بالتحقّق من المدخلات. سنضع شرطا على حقل الاسم في استمارة إضافة مهمّة جديدة؛ يتمثّل الشرط في وجوب إدخال اسم للمهمة، على ألا يتجاوز طوله 255 محرفا Characters. إن لم يتحقّق الشرط نعيد المستخدم إلى الرابط tasks/ مع إضاءة المُدخلات القديمة وإظهار أخطاء: /** * Create a new task. * * @param Request $request * @return Response */ public function store(Request $request) { $this->validate($request, [ 'name' => 'required|max:255', ]); // شفرة إنشاء المهمة } تتضمّن المتحكّمات في Laravel مبدئيا السمة ValidatesRequests التي يمكن عن طريقها التحقّق من موافقة المُدخلات لشروط تُحدَّد في مصفوفة من القواعد. تأخذ دالة التحقّق validate الطّلب request$ الذي نريد التحقّق منه ومصفوفة القواعد التي نريد تطبيقها. تشير الشفرة أعلاه إلى أن الحقل name مطلوب required ويجب ألا يتجاوز طوله 255 (الشّرط max). لن نحتاج لتحديد ما الذي سيحصُل عند إخفاق التحقّق من الطلب (مثلا عند كتابة اسم يتجاوز طوله 255 محرفا). يُوجَّه المستخدَم تلقائيا عند إخفاق التحقّق إلى المسار الذي أتى منه وستُعرَض رسائل الخطأ تلقائيا. المتغيّر errors$ تذكّر أننا استخدمنا التعليمة ('include('common.errors@ داخل العرض tasks.index لتقديم أخطاء التحقّق عبر العرض common.errors. يمكّننا العرض common.errors من إظهار أخطاء التحقّق بسهولة وحسب نفس التنسيق في كامل التطبيق. نعرّف في ما يلي العرض resources/views/common/errors.blade.php: @if (count($errors) > 0) <!-- Form Error List --> <div class="alert alert-danger"> <strong>Whoops! Something went wrong!</strong> <br><br> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif ملحوظة: يتوفّر المتغيّر errors$ في كلّ عرض في Laravel. يحوي المتغيّر كائنا فارغا من الصّنف ViewErrorBag إن لم توجد أخطاء. إنشاء المهمّة ضبطنا في الفقرة السابقة آلية التحقّق؛ يمكننا الآن إكمال الدالة store في المتحكم TaskController من أجل إنشاء مهمّة جديدة. نوجِّه المستخدم بعد إنشاء المهمّة إلى الرابط tasks/. سنلجأ إلى الإمكانيّات التي توفّرها علاقات Eloquent لإنشاء المهمّة. تتوفّر أغلب علاقات Eloquent على دالة باسم create تأخذ مصفوفة من الخاصيّات وتضبط تلقائيا قيمة المفتاح الخارجي Foreign key بالاعتماد على النماذج التي تربط بينها العلاقة، ثم تنشئ سطرا جديدا في جدول البيانات لتخزين خاصيّات الكائن. تستخدم الشفرة التالية متغيّرالطلب request$ للحصول على المستخدم الذي طلب إنشاء المهمة ()request->user$ ثم باستخدام الدالة create في العلاقة tasks (عرّفناها سابقا في النموذج User) نعطي القيمة request->name$ (أي الاسم الّذي أدخله المستخدم في الاستمارة) للخاصيّة name في النموذج Task. ستتولّى العلاقة ()tasks تحديد قيمة معرّف المستخدم صاحب المهمة بالاعتماد على المعلومات الواردة في الطلب عن المستخدم. /** * Create a new task. * * @param Request $request * @return Response */ public function store(Request $request) { $this->validate($request, [ 'name' => 'required|max:255', ]); $request->user()->tasks()->create([ 'name' => $request->name, ]); return redirect('/tasks'); } لاحظ كيف أن تعريف العلاقات أتاح لنا إمكانيّة فعل الكثير من الأمور بسطر برمجي واحد تقريبا. عرض المهامّ المخزّنة سنحتاج للتعديل على الدالة index في المتحكّم TaskController من أجل تمرير المهامّ المخزّنة إلى العرض. تقبل الدالة view إضافة إلى اسم العرض، معطى ثانيا يحوي مصفوفة من البيانات المتوفّرة للعرض. يمكن معالجة كلّ عنصر من المصفوفة بعد تمريرها إلى العرض باستخدام متغيّر بنفس الاسم، مثلا: /** * Display a list of all of the user's task. * * @param Request $request * @return Response */ public function index(Request $request) { $tasks = $request->user()->tasks()->get(); return view('tasks.index', [ 'tasks' => $tasks, ]); } لكننا سنختار طريق حقن الاعتمادات التي يوفرها Laravel. حقن الاعتمادات يستخدم Laravel ، كما أشرنا لذلك في درس إنشاء مزود خدمة في Laravel حاويةَ خدمة Service container لإدارة الاعتمادات بين الأصناف: ماهي الأصناف التي يعتمد عليها الصّنف الجديد للعمل؟ كيف يمكنه الحصول على كائن من هذه الأصناف؟ أين يوجد الصّنف وهل سبق لإطار العمل تحميلُه إلى الذاكرة؟ إنشاء مستودع في Laravel تمكّن المستودعات Repositories من تخليص المتحكّم من ضرورة معرفة مصدر البيانات؛ إذ تجرّد المصدر الذي تأتي منه (قاعدة بيانات، ملفّ، واجهة تطبيقات API). تساعد المستودعات - بهذه الحيلة - في زيادة قابليّة التطبيق للصيانة والاختبار. نودّ أن نعرّف مستودعا باسم TaskRepository للوصول إلى بيانات نموذج المهمة Task. تفيد هذه الطريقة كثيرا عند تزايد حجم المشروع والحاجة لتشارك استعلامات Eloquent عبر التطبيق. سننشئ مجلدا باسم Repositories في المجلّد app. تذكّر أن Laravel يحمّل تلقائيا جميع مجلدات التطبيق؛ لذا يمكنك إنشاء المجلدات حسب الحاجة.ننشئ داخل مجلد المستودعات الصنف TaskRepository: <?php namespace App\Repositories; use App\User; class TaskRepository { /** * Get all of the tasks for a given user. * * @param User $user * @return Collection */ public function forUser(User $user) { return $user->tasks() ->orderBy('created_at', 'asc') ->get(); } } حقن المستودع يمكننا الآن تمرير المستودع، بعد استدعائه، إلى مشيّد المتحكم TaskController ثم استخدامه في الدالة index. تصبح شفرة المتحكّم TaskController على النحو التالي: <?php namespace App\Http\Controllers; use App\Task; use App\Http\Requests; use Illuminate\Http\Request; use App\Http\Controllers\Controller; // استدعاء المستودع use App\Repositories\TaskRepository; class TaskController extends Controller { /** * The task repository instance. * * @var TaskRepository */ protected $tasks; /** * Create a new controller instance. * * @param TaskRepository $tasks * @return void */ // التمرير إلى المتحكّم public function __construct(TaskRepository $tasks) { $this->middleware('auth'); $this->tasks = $tasks; } /** * Display a list of all of the user's task. * * @param Request $request * @return Response */ public function index(Request $request) { // الاستخدام في الدالة return view('tasks.index', [ 'tasks' => $this->tasks->forUser($request->user()), ]); } /** * Create a new task. * * @param Request $request * @return Response */ public function store(Request $request) { $this->validate($request, [ 'name' => 'required|max:255', ]); $request->user()->tasks()->create([ 'name' => $request->name, ]); return redirect('/tasks'); } } إظهار المهامّ يمكننا، بعد تمرير البيانات إلى العرض tasks/index.blade.php من المتحكّم، إظهار المهامّ في جدول. تُستخدَم التعليمة foreach@ في قوالب Blade لكتابة حلقات تكرارية يُحوّلها Laravel شفرة PHP. ملحوظة: سبق لنا في الجزأ الأول من الدرس تعريف استمارة إنشاء مهمة جديدة. توضع الشفرة أدناه مكان التعليق الأخير في قالب tasks/index.blade.php الذي أنشأناه سابقا. @if (count($tasks) > 0) <div class="panel panel-default"> <div class="panel-heading"> Current Tasks </div> <div class="panel-body"> <table class="table table-striped task-table"> <!-- عناوين الجدول --> <thead> <th>Task</th> <th> </th> </thead> <!-- المهام الموجودة --> <tbody> @foreach ($tasks as $task) <tr> <!-- اسم المهمة --> <td class="table-text"> <div>{{ $task->name }}</div> </td> <td> <!-- سنضع هنا الشفرة الخاصة بحذف مهمة --> </td> </tr> @endforeach </tbody> </table> </div> </div> @endif </div> </div> شارف التطبيق على النهاية؛ ولكن تنقصنا طريقة تمكّن المستخدم من حذف مهام أضافها سابقا. حذف المهام زرّ حذف مهمة تركنا في العرض tasks/index.blade.php تعليقا للدلالة على المكان المفترض لزرّ حذف مهمة. سنضيف الآن، لكلّ سطر في جدول المهامّ، زرّا يمكّن من حذف المهمة الموجودة في السطر. يُرسَل، عند النقر على زرّ الحذف، طلب بإجراء DELETE إلى المسار task/، يستقبل المسار الطلب ويحيله إلى الدالة destroy في المتحكّم TaskController. نعدّل العرض tasks/index.blade.php بتعديل شفرة أسطُر الجدول لتصبح على النحو التالي: <tr> <!-- اسم المهمة --> <td class="table-text"> <div>{{ $task->name }}</div> </td> <!-- زرّ حذف المهمة --> <td> <form action="{{ url('task/'.$task->id) }}" method="POST"> {{ csrf_field() }} {{ method_field('DELETE') }} <button type="submit" id="delete-task-{{ $task->id }}" class="btn btn-danger"> <i class="fa fa-btn fa-trash"></i>Delete </button> </form> </td> </tr> لاحظ أن الاستمارة في خلية الجدول حيث يوجد زرّ الحذف تستخدم الإجراء POST بينما نجيب على الطلب بمسار يستخدم الإجراء DELETE. لا تسمح الاستمارات في HTML باستخدام سوى الإجراءيْن POST وGET، أي أننا يجب أن نجد طريقة لإرسال طلب بإجراء DELETE. يكمُن الحل في تنفيذ الدالة ('method_field('DELETE داخل الاستمارة. تولّد هذه الدالة حقل إدخال input مخفيّا يتعرّف عليه Laravel ويستخدمه في إلغاء الإجراء المستخدَم في طلب HTTP. يبدو الحقل المولَّد كالتالي: <input type="hidden" name="_method" value="DELETE"> ربط النموذج والمسار نحن الآن جاهزون لتعريف الدالة destroy في المتحكّم TaskController: /** * Destroy the given task. * * @param Request $request * @param Task $task * @return Response */ public function destroy(Request $request, Task $task) { // } سنلقي، قبل أن نكمل تعريف الدالة destroy، نظرة على المسار الخاصّ بحذف مهمة: Route::delete('/task/{task}', 'TaskController@destroy'); نظرا لكون المتغيّر {task} في المسار يوافق المتغيّر task$ في دالة المتحكم فإن Laravel سيربط تلقائيا بين الاثنين ويحقن كائنا مناسبا من النموذج Task في المسار؛ أي أن الكائن سيكون متاحا للمتحكّم لتنفيذ العمليات عليه. التصريح لدى المتحكّم الآن نسخة من نموذج المهمة Task لاستخدامه في الدالة destroy، إلا أننا لسنا متأكدين من أن المستخدم هو فعلا صاحب المهمة التي طلب حذفها. يمكن، على سبيل المثال، تمرير معرّف عشوائي إلى الرابط {tasks/{task، وستحذف الدالة المهمة ذات المعرّف {task}، إن وُجدت. نستخدم قدرات إدارة التصريحات Authorization في Laravel لحلّ هذه المشكلة، والتأكد من أن المستخدَم المُسجَّل هو فعلا صاحب المهمة التي يطلُب حذفها. إنشاء سياسة تصريح يستخدم Laravel سياسات Policies لتنظيم التصريحات في أصناف صغيرة وسهلة. تتعلّق كلّ سياسة - عادة - بنموذج. نستخدم artisan لإنشاء سياسة تصريحات للنموذج Task كالتالي: php artisan make:policy TaskPolicy سينشئ الأمر ملفا باسم TaskPolicy.php على المسار /app/Policies. نضيف دالة باسم destroy إلى سياسة التصريح TaskPolicy. تتلقى هذه الدالة كائنا من صنف User وآخر من صنف Task، ثمّ تتحقّق من أن معرّف المستخدم يطابق الحقل user_id في المهمة. تُرجع الدالة destroy في الصّنف TaskPolicy قيمة منطقية (falseأو true)، كما هي الحال في جميع دوال سياسات التصريح: <?php namespace App\Policies; use App\User; use App\Task; use Illuminate\Auth\Access\HandlesAuthorization; class TaskPolicy { use HandlesAuthorization; /** * Determine if the given user can delete the given task. * * @param User $user * @param Task $task * @return bool */ public function destroy(User $user, Task $task) { return $user->id === $task->user_id; } } نحتاج الآن لإخبار Laravel بأن سياسة التصريح TaskPolicy تنطبق على النموذج Task. يتمّ هذا الأمر عبر إضافة عنصر جديد إلى خاصيّة policies$ في مزوّد خدمات الاستيثاق app/Providers/AuthServiceProvider.php. سيعرف Laravel بهذه الطريقة سياسة التصريح التي يجب عليه استخدامها للسماح بإجراء مّا (أو رفضه) على النموذج Task: /** * The policy mappings for the application. * * @var array */ protected $policies = [ 'App\Task' => 'App\Policies\TaskPolicy', ]; السماح بحذف المهمة سياسة التصريح جاهزة، ويمكننا بالتالي استخدامها في المتحكّم TaskController. يمكن لجميع المتحكمات في Laravel استخدام الدالة authorize التي توفّرها السمة AuthorizesRequest: /** * Destroy the given task. * * @param Request $request * @param Task $task * @return Response */ public function destroy(Request $request, Task $task) { $this->authorize('destroy', $task); // حذف المهمة } المعطى الأوّل المُمرَّر للدالة authorize هو اسم الدالة التي نريد استدعاءها في سياسة التصريح؛ المعطى الثاني هو الكائن الذي نريد التعامل معه. تذكّر أننا أخبرنا Laravel للتو أن سياسة التصريح TaskPolicy تنطبق على النموذج Task، أي أن إطار العمل يعرف في أي سياسة تصريح سيبحث عن الدالة التي حدّدنا اسمها في المعطى الأول المُمرَّر للدالة authorize. بالنسبة للمستخدم فإن المستخدم الحالي سيُرسَل تلقائيا إلى الدالة destroy في الصّنف TaskPolicy. إن تحقّق الشرط (المستخدم صاحب المهمة هو من طلب حذفها) فسيستمرّ تنفيذ الدالة destroy في المتحكّم TaskController بصورة طبيعية؛ وإلا فسينطلق استثناء Exception برمز الخطأ 403 (غياب التصريح) وتظهر صفحة خطأ. ملحوظة: ليست هذه هي الطريقة الوحيدة للتخاطب مع خدمات التصريح التي يوفرها Laravel. حذف المهمة أخذنا الاحتياطات اللازمة، ويمكننا الآن إضافة الشفرة الخاصة بحذف مهمة من قاعدة البيانات. نستخدم دالة delete التي تتوفّر عليها نماذج Eloquent؛ ثم نوجّه المستخدم بعد حذف المهمة إلى المسار tasks/. تصبح الدالة destroy في المتحكّم TaskController كما يلي: /** * Destroy the given task. * * @param Request $request * @param Task $task * @return Response */ public function destroy(Request $request, Task $task) { $this->authorize('destroy', $task); $task->delete(); return redirect('/tasks'); } ترجمة - بتصرّف - للجزء الثاني من مقال Intermediate Task List.
  15. أساسيات التحقق من المدخلات في Laravel

    كان من الشائع في بدايات التطوير للوب كتابةُ الاستمارات بوسوم HTML ثم إضافة شفرة مخصَّصة للتأكد من مُدخَلات الزائر. وفّرت لغة البرمجة PHP بعد ذلك دوالَّ معيارية للتحقّق من المُدخلات؛ خفّفت هذه الدوّال قليلا من العبء على المطوِّر إلا أنها تركت له مهمّة تعريف طريقة للتحقّق من المُدخلات ومن ثمّ معالجتها أو إشعار الزائر بالبيانات غير الصالحة وعرض الاستمارة من جديد. يزيح Laravel هذه المتاعب بتوفير شيفرة للتحقّق وطريقة للتعامل مع المُدخلات. يقدّم هذا المقال دليلا لكيفيّة إنشاء استمارات والتحقّق من مدخلات الزائر في Laravel. سنأخذ مثالا لإضافة تصنيف Category ضمن جدول تصنيفات Categories في تطبيق؛ يمكن أن يتعلّق الأمر بتصنيف منشورات مدوّنة، منتجات متجر أو أي شيء مماثل. تهيئة تطبيق Laravel نفترض أن Laravel مثبَّت وجاهز للعمل مع قاعدة البيانات. نهيّئ التطبيق قبل أن نشرع في إنشاء الاستمارة وأدوات التحقّق المصاحبة لها. إنشاء نموذج التصنيف والتهجير الموافق له سيتكون نموذج التصنيف من حقل للاسم إضافة إلى حقل المعرّف id والأختام الزمنية Timestamps. نستخدم artisan لتوليد النموذج والتهجير: $ php artisan make:model Category -m Model created successfully. Created Migration: 2016_06_13_010501_create_categories_table ثم نفتح ملفّ التهجير (داخل المجلّد database/migrations) ونحدّث الدالة up على النحو التالي: public function up() { Schema::create('categories', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->timestamps(); }); } ثم ننفّذ التهجير: $ php artisan migrate Migration table created successfully. Migrated: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_100000_create_password_resets_table Migrated: 2016_06_13_010501_create_categories_table ننتقل الآن للعمل على المتحكّم Controller الذي سيكون المسؤول عن معالجة محتوى الاستمارة. إنشاء المتحكم وتعريف المسارات نستخدم أداة artisan لإنشاء المتحكّم الذي سنستخدمه - من بين أمور أخرى - لعرض النموذج ومعالجة بياناته: $ php artisan make:controller CategoriesController.php --resource Controller created successfully. ينشئ أمر make:controller عند استخدام المعطى resource--متحكّما بدوال update، edit، store، create، show``index وdestroy. راجع درس أساسيات بناء التطبيقات في إطار العمل Laravel 5 للمزيد عن هذه الدوال. بقي لنا تعريف المسارات في الملفّ app/Http/routes.php؛ نستخدم Route::resource لهذا الغرض: Route::resource('categories', 'CategoriesController'); إنشاء العروض Views نركّز لأغراض هذا الدّرس على الدالتيْن create وstore المسؤولتيْن على التوالي عن عرض الاستمارة وتخزين بياناتها (في حال تجاوز اختبار التحقّق؛ كما سنرى). تبدو الدالتان لحدّ الساعة فارغتيْن: public function create() { // } public function store(Request $request) { // } ... نحدّث الدالة create كالتالي: public function create() { return view('categories.create'); } أي أننا نطلُب تقديم العرض create.blade.php الموجود في المجلّد resources/views/categories. ننشئ المجلّد categories وننشئ بداخله الملفّ create.blade.php. سنكتفي الآن بإضافة الوسوم التالية إلى ملفّ العرض: <h1>Create a Category</h1> يمكنك بعد حفظ الملفّ زيارة الرابط categories/create/ وسيظهر العنوان أعلاه. إنشاء استمارة في Laravel نريد أن نعرض للزائر استمارة لملئها؛ يمكن أن ننشئ هذه الاستمارة بكتابة وسوم HTML المطلوبة في ملفّ العرض create؛ إلا أنه يمكننا الاستفادة من حزمة laravelcollective/html لتولّي هذه المهمّة. نضيف الحزمة إلى مشروع Laravel بتنفيذ الأمر التالي داخل مجلّد المشروع: $ composer require laravelcollective/html ثم نفتح ملفّ الإعداد config/app ونضيف السطر التالي إلى مصفوفة providers: Collective\Html\HtmlServiceProvider::class, لتبدو المصفوفة كالتالي (نزعنا بعض محتويات المصفوفة للاختصار): 'providers' => [ ... App\Providers\AuthServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, Collective\Html\HtmlServiceProvider::class, ] نكمل مع نفس الملفّ بالانتقال إلى المصفوفة aliases التي نضيف إليها السّطر التالي: 'Form' => Collective\Html\FormFacade::class لتصبح كما يلي: 'aliases' => [ ... 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, 'Form' => Collective\Html\FormFacade::class ] احفظ الملفّ. أكملنا تثبيت الحزمة وإعدادها. نعيد فتح ملفّ العرض create ونعدّل محتواه ليصبح على النحو التالي: <h1>Create a Category</h1> {!! Form::open( array( 'route' => 'categories.store', 'class' => 'form') ) !!} @if (count($errors) > 0) <div class="alert alert-danger"> There were some problems adding the category.<br /> <ul> @foreach ($errors->all() as $error) <li></li> @endforeach </ul> </div> @endif <div class="form-group"> {!! Form::label('Category') !!} {!! Form::text('name', null, array( 'class'=>'form-control', 'placeholder'=>'List Name' )) !!} </div> <div class="form-group"> {!! Form::submit('Create Category!', array('class'=>'btn btn-primary' )) !!} </div> {!! Form::close() !!} </div> تضيف حزمة laravelcollective/html تعليمات خاصّة بإنشاء الاستمارات إلى نظام Blade للقوالب. يشير مسار الاستمارة إلى categories/store لأن دالّة store في المتحكّم CategoriesController هي التي ستتولّى معالجة بيانات الاستمارة. تستخدم التعليمة Form::open مبدئيا إجراء POST؛ لذا لا حاجة لتعيينه. يُستخدَم المقطع if..@endif@ لتقديم معلومات إلى المستخدم عن أخطاء التحقق. سنفصّل هذا الأمر بعد قليل. مرّرنا لأغراض جمالية أصنافا وخاصيّات من Bootstrap إلى الاستمارة ؛ هذا ليس ضروريا وستعمل الاستمارة بدونه. تظهر الآن الاستمارة بالذهاب إلى categories/create/. يمكنك إدخال اسم تصنيف وإرسال الاستمارة وستُوجَّه إلى categories/store/ لكنّ شيئا لن يحدُث لأننا لم نكتب حتى الآن شيئا في الدالة store من المتحكّم CategoriesController. معالجة الاستمارة نعود للدالة store في المتحكم CategoriesController. هذه هي الدالة التي تُرسَل إليها بيانات الاستمارة بعد النقر على زرّ الإرسال. نحدّث المتحكّم كالتالي: use App\Category; ... public function store(Request $request) { $category = new Category; $category->name = $request->get('name'); $category->save(); return \Redirect::route('categories.show', array($category->id)); } بدأنا أولا باستيراد النموذج Category في المتحكّم ثم استخدمناه في الدالة store لتخزين تسجيلة Record جديدة في جدول قاعدة البيانات اعتمادا على محتويات الاستمارة؛ ثم بعد التخزين نعيد توجيه المستخدم إلى الدالة show ضمن المتحكّم CategoriesController مع معرّف التصنيف الذي أضفناه للتو. يمكننا تعديل الدالة show كالتالي لعرض رسالة تفيد بنجاح إضافة التصنيف: public function show($id) { // $category = Category::find($id); $message = "$category->name has been added succefully"; return $message; } من الملاحظ أننا لم نتحقّق في العمليّة السابقة من مُدخلات المستخدم. يعني هذا أنه يمكن - مثلا - ترك الحقل الخاصّ باسم التصنيف فارغا وسيُحفظ تصنيف بدون اسم في قاعدة البيانات؛ طبعا هذا غير مقبول. التحقق من الاستمارة قبل الإرسال يوفّر Laravel 5 ميزة تُسمى طلب الاستمارة Form request تسمح بالتحقق من حقول الاستمارة دون تلويث المتحكّم. يدير ملفّ منفصل قواعد التحقّق من الاستمارة؛ نستخدم أمر artisan التالي لإنشاء هذا الملفّ: $ php artisan make:request CreateCategoryFormRequest Request created successfully. ينشئ الأمر ملفا باسم CreateCategoryFormRequest.php في المجلد app/Http/Requests. يبدو الملفّ كالتالي: <?php namespace App\Http\Requests; use App\Http\Requests\Request; class CreateCategoryFormRequest extends Request { public function authorize() { return false; } public function rules() { return [ // ]; } } عدّل الدالة authorize كالتالي: public function authorize() { return true; } نحتاج لتحديد القيمة true بالنسبة للدالة authorize لأنه في حال كانت القيمة false فلن تُعالج بيانات الاستمارة. ثم نعدّل الدالة rules: public function rules() { return [ 'name' => 'required' ]; } تعرّف الدالة قواعد التحقّق؛ عرّفنا أعلاه الحقل name ضمن الاستمارة بأنه مطلوب required؛ أي أن الاستمارة لن تُرسَل إلا إذا كانت توجد قيمة لهذا الحقل. تمكن إضافة أكثر من شرط على الحقل كالتالي: 'name' => 'required|alpha' نحتاج الآن لدمج طلب الاستمارة في الدالة store ضمن المتحكّم CategoriesController. نبدأ باستيراد الصنف في المتحكّم كالتالي: use App\Http\Requests\CreateCategoryFormRequest; ثم نحدّث الدالة store ليكون الكائن الممرَّر إليها من الصّنف CreateCategoryFormRequest: public function store(CreateCategoryFormRequest $request) { ... } ابتداءً من الآن سيتحقّق Laravel من بيانات الحقل قبل إرسالها؛ وفي حال الإخفاق في التحقق من الشرط سيعيد الزائر إلى صفحة الاستمارة مع عرض رسالة بوجود خطأ. ترجمة -وبتصرّف- للمقال Creating and Validating a Laravel 5 Form: The Definitive Guide. حقوق المقال محفوظة لصاحبه W. Jason Gilmore.