issa issa

الأعضاء
  • المساهمات

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

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

  • Days Won

    1

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

4 Neutral
  1. مقدّمة يُعتبر Apache و Nginx اثنين من أشهر خوادم الويب مفتوحة المصدر ويُستخدمان غالباً مع PHP. قد يكون من المفيد تشغيل كل منهما على نفس الجهاز الإفتراضي virtual machine عند استضافة مواقع ويب متعددة ذات متطلباتٍ متنوعة. إنّ الحل العام لتشغيل خوادم الويب على نظام واحد هو استخدام عناوين IP متعددة أو أرقام منافذ مختلفة. بالإمكان ضبط الخوادم التي تملك كلّا من عناوين IPv4 و IPv6 لخدمة مواقع Apache على أحد البروتوكولين ومواقع Nginx على البروتوكول الآخر، ولكن عمليًا هذا غير مُطبّق حاليًا، نظرًا لأن تبنّي مزودي خدمات الإنترنت لـ IPv6 لا يزال غير شائع. حيث يعدّ وجود رقم منفذ مختلف مثل 81 أو 8080 لخادم الويب الثاني حلاً آخر، ولكن مشاركة عناوين URL بأرقام المنافذ (مثل http://example.com:81) ليس منطقيًّا أو مثاليًّا دائمًا. سنتعلّم في هذه الدورة كيفيّة ضبط Nginx كخادم ويب وكذلك كوسيط عكسي Reverse Proxy لـ Apache - كل ذلك على خادم واحد. قد تكون هنالك حاجة اعتمادًا على تطبيق الويب إلى تغييرات في الشفرة ليبقى Apache مُدركًا بالوسيط العكسي، وخاصّة عند ضبط مواقع SSL. سنتجنّب ذلك بتثبيت module وحدة Apache تسمى mod_rpaf والتي تُعيد كتابة متغيرات بيئة معيّنة بحيث يبدو أن Apache يتعامل مباشرة مع الطلبات من عملاء الويب. ستُضاف أربعة أسماء نِطاقات domain names على خادم واحد. وسيُخدَّم اثنين منهما بواسطة Nginx هما:example.com (المُضيف الظاهري الافتراضي) و sample.org. والاثنين المتبقيين، foobar.net و test.io، سيُخدّمان من قبل Apache. سنُعدّ أيضًا Apache لخدمة تطبيقات PHP باستخدام PHP-FPM، والذي يقدّم أداء أفضل عبر mod_php. المتطلبات المُسبقة ستحتاج لإكمال هذه الدورة التعليميّة إلى ما يلي: خادم Ubuntu 18.04 جديد تم إعداده من خلال اتباع خطوات الإعداد الأولي للخادم في Ubuntu 18.4، مع مستخدم sudo عادي (non-root) و جدار ناري. ضبط أربعة أسماء نطاق مؤهلة بالكامل للإشارة لعنوان IP الخاص بخادمك. انظر الخطوة 3 من كيفية إعداد اسم مضيف فيDigitalOcean كمِثال لكيفية القيام بذلك. إذا كنت تستضيف DNS للنطاقات الخاصّة بك في مكان آخر، فعليك إنشاء سجلات A مناسبة هناك بدلاً من ذلك. الخطوة 1 - تثبيت Apache و PHP-FPM لنبدأ بتثبيت Apache و PHP-FPM. سنثبّت أيضًا بالإضافة إلى تثبيت Apache و PHP-FPM، وحدة PHP FastCGI Apache وهيlibapache2-mod-fastcgi، لدعم تطبيقات ويب FastCGI. أولاً، يجب تحديث قائمة الحزم package الخاصّة بك للتأكد من حصولك على أحدث الحزم. $ sudo apt update يجب بعد ذلك تثبيت حزم Apache و PHP-FPM: $ sudo apt install apache2 php-fpm يجب تنزيل وحدة FastCGI Apache من kernel.org وتثبيتها باستخدام الأمر dpkg لأنّها غير متوفرة في مستودع Ubuntu: $ Wget https://mirrors.edge.kernel.org/ubuntu/pool/multiverse/liba/ libapache-mod-fastcgi/libapache2-mod-fastcgi_2.4.7~0910052141-1.2_amd64.deb $ sudo dpkg -i libapache2-mod-fastcgi_2.4.7~0910052141-1.2_amd64.deb علينا بعد ذلك تغيير الضبط الافتراضي لخادم Apache من أجل استخدام PHP-FPM. الخطوة 2 - ضبط Apache و PHP-FPM سنغيّر في هذه الخطوة رقم منفذ Apache إلى 8080 وضبطه للعمل مع PHP-FPM باستخدام الوحدة mod_fastcgi. أعد تسمية ملف ضبط ports.conf لمخدم Apache: $ sudo mv /etc/apache2/ports.conf /etc/apache2/ports.conf.default أنشئ ملف ports.conf جديد مع تعيين المنفذ إلى 8080: $ echo "Listen 8080" | sudo tee /etc/apache2/ports.conf ملاحظة: تُضبط خوادم الويب بشكل عام للتنصت على المنفذ 127.0.0.1:8080 عند ضبط الوكيل العكسي، ولكن القيام بذلك سيؤدي إلى ضبط قيمة متغير بيئة (PHP (SERVER_ADDR إلى عنوان IP الاسترجاع بدلاً من عنوان الـ IP العام للخادم. هدفنا هو إعداد Apache بطريقة لا ترى مواقعه على الويب الوكيل العكسي أمامها. لذلك، سنضبطه للتنصت على المنفذ 8080 لجميع عناوين IP. سننشئ بعد ذلك ملف مضيف افتراضي لـ Apache. سيعدّ التوجيه في هذا الملف ليخدّم المواقع فقط على المنفذ 8080. عطّل المضيف الظاهري الافتراضي: $ sudo a2dissite 000-default ثم أنشئ ملف مضيف افتراضي جديد، باستخدام الموقع الافتراضي الموجود: $ sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/001-default.conf افتح الآن ملف الضبط الجديد: $ sudo nano /etc/apache2/sites-available/001-default.conf غيّرمنفذ التنصت إلى 8080: /etc/apache2/sites-available/000-default.conf ServerAdmin webmaster@localhost DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined احفظ الملف وقم بتنشيط ملف الضبط الجديد: $ sudo a2ensite 001-default ثم أعد تحميل Apache: $ sudo systemctl reload apache2 تحقّق من أن Apache يتنصت الآن على 8080: $ sudo netstat -tlpn يجب أن يبدو الخرج output كالمثال التالي، حيث يتنصّت apache2 على المنفذ 8080: output Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1086/sshd tcp6 0 0 :::8080 :::* LISTEN 4678/apache2 tcp6 0 0 :::22 :::* LISTEN 1086/sshd يمكنك إعداد دعم PHP و FastCGI بمجرّد التحقق من أن Apache يتنصت على المنفذ الصحيح. الخطوة 3 - ضبط Apache لاستخدام mod_fastcgi يخدّم Apache صفحات PHP باستخدام mod_php افتراضيًا، ولكنه يتطلب إعدادًا إضافيًّا للعمل مع PHP-FPM. ملاحظة: إذا كنت تجرّب هذا الدرس على نسخة موجودة مسبقًا من LAMP مع mod_php، عطّله أولاً باستخدام sudo a2dismod php7.2. سنضيف كتلة ضبط لوحدة mod_fastcgi التي تعتمد على mod_action. يُعطّل mod_action بشكل افتراضي، لذلك نحتاج أولاً إلى تفعيله: $ sudo a2enmod action أعد تسمية ملف ضبط FastCGI الموجود: $ sudo mv /etc/apache2/mods-enabled/fastcgi.conf/etc/apache2/mods -enabled/fastcgi.conf.default أنشئ ملف ضبط جديد: $ sudo nano /etc/apache2/mods-enabled/fastcgi.conf أضف التوجيهات التالية إلى الملف لتمرير طلبات ملفات php. إلى مقبس PHP-FPM UNIX: /etc/apache2/mods-enabled/fastcgi.conf AddHandler fastcgi-script .fcgi FastCgiIpcDir /var/lib/apache2/fastcgi AddType application/x-httpd-fastphp .php Action application/x-httpd-fastphp /php-fcgi Alias /php-fcgi /usr/lib/cgi-bin/php-fcgi FastCgiExternalServer /usr/lib/cgi-bin/php-fcgi -socket /run/php/php7.2-fpm.sock -pass-header Authorization Require all granted احفظ التغييرات واختبر الضبط: $ sudo apachectl -t إذا ظهرت عبارة Syntax OK، أعد تحميل Apache: $ sudo systemctl reload apache2 إذا رأيت رسالة التحذير التالية، يمكنك تجاهلها الآن بشكل آمن. سنَضبط أسماء الخادم في وقت لاحق: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message. دعنا نتأكد الآن من أنّه بإمكاننا تخديم PHP من Apache. الخطوة 4 - التحقق من عمل PHP سَنتأكّد من أن PHP يعمل، وذلك من خلال إنشاء ملف ()phpinfo والوصول إليه من متصفح الويب. أنشئ الملف var/www/html/info.php/ والذي يحتوي على استدعاء للدّالة phpinfo: $ echo "" | sudo tee /var/www/html/info.php انتقل في المتصفح إلى http: // your_server_ip: 8080 / info.php لاستعراض هذا الملف. ستظهر لك قائمة إعدادات الضبط التي يستخدمها PHP. كما في الشكل التالي: تحقّق من أن الخيار Server API يأخذ القيمة FPM/FastCGI وذلك في أعلى الصفحة كما في الصورة السابقة. سترى كذلك في أسفل الصفحة تقريبًا في القسم PHP Variables بأنّ قيمة SERVER_SOFTWARE هي Apache على Ubuntu. وهذا يؤكّد أنّ الوحدة mod_fastcgi مُفعّلة وأنّ Apache يستخدم PHP-FPM لمعالجة ملفات PHP. الخطوة 5 - إنشاء مضيفات افتراضيّة لـ Apache دعونا ننشئ ملفات المضيف الافتراضي لـ Apache للنطاقين foobar.net و test.io. سنقوم لعمل ذلك أولاً بإنشاء الأدلّة الجذر للمستند في كِلا الموقعين ووضع بعض الملفات الافتراضيّة في هذه الأدلة حتى نتمكن من اختبار الضبط لدينا بسهولة. أولاً، أنشئ الأدلّة الجذر للمستند: $ sudo mkdir -v /var/www/foobar.net /var/www/test.io أنشئ بعد ذلك ملف index لكل موقع: $ echo "<h1 style='color: green;'>Foo Bar</h1>" | sudo tee /var/www/foobar.net/index.html $ echo "<h1 style='color: red;'>Test IO</h1>" | sudo tee /var/www/test.io/index.html " | sudo tee /var/www/test.io/index.html ثم أنشئ ملف ()phpinfo لكل موقع حتى نتمكن من اختبار فيما إذا ضُبط PHP بشكل صحيح. $ echo "" | sudo tee /var/www/foobar.net/info.php $ echo "" | sudo tee /var/www/test.io/info.php الآن أنشئ ملف المضيف الافتراضي للنطاق foobar.net: $ sudo nano /etc/apache2/sites-available/foobar.net.conf أضف الشفرة التالية إلى الملف لتعريف المضيف: /etc/apache2/sites-available/foobar.net.conf ServerName foobar.net ServerAlias www.foobar.net DocumentRoot /var/www/foobar.net AllowOverride All يتيح السطر AllowOverride All تفعيل دعم htaccess. احفظ وأغلق الملف. ثم أنشئ ملف ضبط مماثل لـ test.io. أولاً أنشئ الملف: $ sudo nano /etc/apache2/sites-available/test.io.conf ثم أضف الضبط إلى الملف: /etc/apache2/sites-available/test.io.conf ServerName test.io ServerAlias www.test.io DocumentRoot /var/www/test.io AllowOverride All احفظ الملف وإغلاق المحرّر. والآن بعد إعداد كل من مضيفي Apache الافتراضيين، فعّل المواقع باستخدام الأمر a2ensite. والذي يُنشئ رابط رمزي لمَلف المضيف الافتراضي في الدليل sites-enabled: $ sudo a2ensite foobar.net $ sudo a2ensite test.io تحقّق من Apache للتأكّد من وجود أخطاء في الضبط مرّة أخرى: $ sudo apachectl –t سترى عبارة Syntax OK إذا لم يكن هناك أخطاء. إذا رأيت أي شيء آخر، فتحقّق من الضبط وحاول مرّة أخرى. قم بإعادة تحميل Apache لتطبيق التغييرات بمجرّد أن يكون الضبط الخاص بك خاليًا من الأخطاء: $ sudo systemctl reload apache2 افتح http://foobar.net:8080 و http://test.io:8080 في متصفحك للتأكّد من عمل المواقع والتحقّق من أنّ كل موقع يعرض ملف index.html الخاص به. سترى النتائج التالية: تأكّد أيضًا من أن PHP تعمل وذلك عن طريق الوصول إلى ملفات info.php لكل موقع. افتح http://foobar.net:8080/info.php و http://test.io:8080/info.php في متصفحك. سترى قائمة مواصفات ضبط PHP نفسها على كل موقع كما رأيت في الخطوة 4. لدينا الآن موقعين مُستضافين على Apache على المنفذ 8080. فلنَضبط بعد ذلك Nginx. الخطوة 6 - تثبيت وضبط Nginx سنقوم في هذه الخطوة بتثبيت Nginx وإعداد ضبط النطاقات example.com و sample.org كمضيفين افتراضيين لـ Nginx. ثبّت Nginx باستخدام مدير الحزم: $ sudo apt install nginx أزل الرابط الرمزي الافتراضي للمضيف الافتراضي حيث أننا لن نستخدمه بعد الآن: $ sudo rm /etc/nginx/sites-enabled/default سنُنشئ الموقع الافتراضي الخاص بنا فيما بعد (example.com). سنُنشئ الآن مضيفين افتراضيين لـ Nginx باستخدام نفس الإجرائيّة التي استخدمناها من أجل Apache. أنشئ أولاً الأدلّة للمستند الجذر لكل من موقعي الويب: $ sudo mkdir -v /usr/share/nginx/example.com /usr/share/nginx/sample.org سنحتفظ بمواقع الويب الخاصّة بـ Nginx في /usr/share/nginx، وهو المسار الافتراضي الذي سيختاره Nginx. يمكنك وضع هذه المواقع في /var/www/html مع مواقع Apache، لكن هذا الفصل بينها قد يساعدك على ربط المواقع بـ Nginx. كما فعلت مع مضيفي Apache الافتراضيين، أنشئ ملفات index و ()phpinfo من أجل الاختبار بعد اكتمال الإعداد: $ echo "<h1 style='color: green;'>Example.com</h1>" | sudo tee /usr/share/nginx/example.com/index.html $ echo "<h1 style='color: red;'>Sample.org</h1>" | sudo tee /usr/share/nginx/sample.org/index.html $ echo "<?php phpinfo(); ?>" | sudo tee /usr/share/nginx/example.com/info.php $ echo "<?php phpinfo(); ?>" | sudo tee /usr/share/nginx/sample.org/info.php الآن أنشئ ملف مضيف افتراضي للنطاق example.com: $ sudo nano /etc/nginx/sites-available/example.com يستدعي Nginx كتل server {. . .} من ملف الضبط server blocks. أنشئ كتلة خادم من أجل المضيف الافتراضي الأساسي example.com. تجعل ضبط التوجيه default_server هذا المضيف كمضيف افتراضي افتراضي لمعالجة طلبات HTTP التي لا تتطابق مع أي مضيف افتراضي آخر. /etc/nginx/sites-available/example.com server { listen 80 default_server; root /usr/share/nginx/example.com; index index.php index.html index.htm; server_name example.com www.example.com; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { fastcgi_pass unix:/run/php/php7.2-fpm.sock; include snippets/fastcgi-php.conf; } } احفظ وأغلق الملف. أنشئ الآن ملف مضيف Nginx افتراضي للنطاق الثاني، sample.org: $ sudo nano etc/nginx/sites-available/sample.org أضف ما يلي إلى الملف: /etc/nginx/sites-available/sample.org server { root /usr/share/nginx/sample.org; index index.php index.html index.htm; server_name sample.org www.sample.org; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { fastcgi_pass unix:/run/php/php7.2-fpm.sock; include snippets/fastcgi-php.conf; } } احفظ وأغلق الملف. ثم فعّل كِلا الموقعين من خلال إنشاء روابط رمزيّة للدّليل sites-enabled: $ sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com $ sudo ln -s /etc/nginx/sites-available/sample.org /etc/nginx/sites-enabled/sample.org اختبر بعد ذلك ضبط Nginx لضمان عدم وجود أخطاء في الضبط: $ sudo nginx -t ثم أعد تحميل Nginx إذا لم يكن هناك أخطاء: $ sudo systemctl reload nginx الآن قم بالوصول إلى ملف ()phpinfo الخاص بمُضيفي Nginx الافتراضيين من متصفح الويب من خلال زيارة http://sample.org/info.php و http://example.com/info.php. انظر مجدّدًا إلى الصورة في الأسفل إلى قسم المتغيرات PHP Variables. يجب أن يحوي["SERVER_SOFTWARE"] على القيمة Nginx، مشيرًا إلى أنّ الملفات خُدّمت بشكل مباشر بواسطة Nginx. يجب أن يشير["DOCUMENT_ROOT"] إلى الدليل الذي أنشأته مُسبقًا في هذه الخطوة لكل موقع من مواقع Nginx. ثبّتنا في هذه المرحلة Nginx وأنشأنا مضيفين افتراضيين.سنقوم بعد ذلك بضبط Nginx على طلبات الوكيل المخصّصة للنطاقات المستضافة على Apache. الخطوة 7 - ضبط Nginx لمضيفي Apache الافتراضيين لنُنشئ مضيف Nginx افتراضي إضافي مع أسماء نطاقات متعددة في توجيهات server_name. سيتم توكيل طلبات هذه النطاقات إلى Apache. أنشئ ملف مضيف Nginx افتراضي جديد لإعادة توجيه الطلبات إلى Apache: $ sudo nano /etc/nginx/sites-available/apache أضف كتلة الشفرة التالية التي تحدد أسماء نطاقات كلاً من مضيفي Apache الاتراضيين وتوكل طلباتها إلى Apache. تذكّر استخدام عنوان IP العام في proxy_pass: /etc/nginx/sites-available/apache server { listen 80; server_name foobar.net www.foobar.net test.io www.test.io; location / { proxy_pass http://your_server_ip:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } قم بحفظ الملف وتفعيل هذا المضيف الافتراضي الجديد عن طريق إنشاء رابط رمزي: $ sudo ln -s /etc/nginx/sites-available/apache /etc/nginx/sites-enabled/apache اختبر الضبط للتأكد من عدم وجود أخطاء: $ sudo nginx -t إذا لم يكن هنالك أخطاء، أعد تحميل Nginx: $ sudo systemctl reload nginx افتح متصفحك وقم بالوصول إلى العنوان http://foobar.net/info.php. انتقل لأسفل إلى قسم PHP Variables وتحقق من القيم المعروضة كما في الصورة. يؤكّد المتغيران ERVER_SOFTWARE و DOCUMENT_ROOT أنّ هذا الطلب عُولج بواسطة Apache. وأضيفت المتغيرات HTTP_X_REAL_IP و HTTP_X_FORWARDED_FOR بواسطة Nginx ويجب أن تُظهر عنوان IP العام للحاسب الذي تستخدمه للوصول إلى عنوان URL. لقد أعددنا Nginx بنجاح ليوكل بطلبات نطاقات محدّدة إلى Apache. بعد ذلك، لنقم بضبط Apache لضبط المتغير REMOTE_ADDR كما لو أنه يتعامل مع هذه الطلبات مباشرة. الخطوة 8 - تثبيت وضبط mod_rpaf سنُثبّت في هذه الخطوة وحدة Apache تسمى mod\_rpaf والتي تعيد كتابة قيم REMOTE_ADDR، HTTPS و HTTP_PORT استنادًا إلى القيم المقدّمة من قبل وسيط عكسي. وبدون هذه الوحدة، تتطلب بعض تطبيقات PHP تغييرات في الشفرة للعمل بسلاسة من خلفْ الخادم الوكيل. هذه الوحدة موجودة في مستودع Ubuntu باسم libapache2-mod-rpaf ولكنها قديمة ولا تدعم توجيهات ضبط معينة. سنقوم بدلاً من ذلك بتثبيتها من المصدر. تثبيت الحزم اللازمة لبناء الوحدة: $ sudo apt install unzip build-essential apache2-dev نزّل أحدث إصدار مستقر من GitHub: $ wget https://github.com/gnif/mod_rpaf/archive/stable.zip استخراج الملف الذي نزل: $ unzip stable.zip انتقل إلى المجلد الجديد الذي يحتوي على الملفات: $ cd mod_rpaf-stable ترجم Compile الوحدة ثم ثبّتها: $ make $ sudo make install أنشئ بعد ذلك ملف في المجلد mods-available والذي سيُحمّل وحدة rpaf: $ sudo nano /etc/apache2/mods-available/rpaf.load أضف الشفرة التالية إلى الملف لتحميل الوحدة: /etc/apache2/mods-available/rpaf.load LoadModule rpaf_module /usr/lib/apache2/modules/mod_rpaf.so احفظ الملف وأغلق المحرر. أنشئ ملف آخر في نفس الدليل وسمّه rpaf.conf والذي سوف يحتوي على توجيهات الضبط للوحدة mod_rpaf: $ sudo nano /etc/apache2/mods-available/rpaf.conf أضف كتلة الشفرة التالية لضبط mod_rpaf، مع التأكّد من تحديد عنوان IP الخاص بخادمك: /etc/apache2/mods-available/rpaf.conf RPAF_Enable On RPAF_Header X-Real-Ip RPAF_ProxyIPs your_server_ip RPAF_SetHostName On RPAF_SetHTTPS On RPAF_SetPort On فيما يلي وصف موجز لكل توجيه. لمزيد من المعلومات، راجع ملف mod_rpaf README. RPAF_Header - الترويسة المراد استخدامها لعنوان IP الحقيقي للعميل. RPAF_ProxyIPs - عنوان IP للوكيل لضبط طلبات HTTP من أجله. RPAF_SetHostName - يقوم بتحديث اسم المضيف الافتراضي بحيث يعمل كل من ServerName و ServerAlias. RPAF_SetHTTPS - يضبط متغير بيئة HTTPS استنادًا إلى القيمة الموجودة في X-Forwarded-Proto. RPAF_SetPort - يضبط متغير بيئة SERVER_PORT. يكون مفيد عندما يكون Apache يعمل خلف وكيل SSL. احفظ الملف rpaf.conf وقم بتفعيل الوحدة: $ sudo a2enmod rpaf يؤدي هذا إلى إنشاء روابط رمزيّة من الملفات rpaf.load و rpaf.conf في الدليل mods-enabled. الآن قم بإجراء اختبار الضبط: $ sudo apachectl -t أعد تحميل Apache إذا لم يكن هنالك أخطاء: $ sudo systemctl reload apache2 قم بالوصول إلى الملف ()phpinfo في الصفحات http://foobar.net/info.php و http://test.io/info.php من متصفحك وتحقق من قسم PHP Variables. الآن سيكون المتغير REMOTE_ADDR هو أيضًا عنوان IP العام للحاسب المحلي لديك. الآن دعنا نعد تشفير TLS / SSL لكل موقع. الخطوة 9 - إعداد مواقع HTTPS باستخدام Let's Encrypt (اختياري) سنضبط في هذه الخطوة شهادات TLS / SSL لكل من النطاقات المُستضافة على Apache. سوف نحصل على الشهادات بواسطة [Let's Encrypt](https://letsencrypt.org]. يدعم Nginx إنهاء SSL، لذا من الممكن إعداد SSL بدون تعديل ملفات ضبط Apache. تَضمنْ الوحدة mod_rpaf أن يتم تعيين متغيرات البيئة المطلوبة على Apache لجعل التطبيقات تعمل بسلاسة خلفْ وكيل عكسي لـ SSL. أولاً سنفصل كتل الخادم {...}server من كِلا النطاقين بحيث يمكن أن يكون لكلٍ منهما شهادات SSL خاصّة به. افتح الملف etc/nginx/sites-available/apache/ في المحرّر الخاص بك: $ sudo nano /etc/nginx/sites-available/apache عدّل الملف بحيث يبدو مثل هذا، مع foobar.net و test.io في كتل الخادم الخاصّة بهم: /etc/nginx/sites-available/apache server { listen 80; server_name foobar.net www.foobar.net; location / { proxy_pass http://your_server_ip:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } server { listen 80; server_name test.io www.test.io; location / { proxy_pass http://your_server_ip:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } سنستخدم Certbot لإنشاء شهادات TLS/SSL الخاصّة بنا. ستتولى إضافة Nginx plugin" Nginx" مُهمة إعادة ضبط Nginx وإعادة تحميل الضبط عند الضرورة. أولاً، أضف مستودع Certbot المرخّص: $ sudo add-apt-repository ppa:certbot/certbot اضغط على ENTER عند مطالبتك بتأكيد رغبتك في إضافة المستودع الجديد. ثم قم بتحديث قائمة الحزم للحصول على معلومات حزمة المستودع الجديدة: $ sudo apt update ثم ثبّت حزمة Nginx الخاصّة بـ Certbot باستخدام apt: $ sudo apt install python-certbot-nginx وبمجرّد تثبيته، استخدم أمر certbot لإنشاء الشهادات لـ foobar.net و www.foobar.net: $ sudo certbot --nginx -d foobar.net -d www.foobar.net يخبر هذا الأمر Certbot ليستخدم ملحق nginx، وباستخدم –d لتحديد الأسماء التي نودّ أن تكون الشهادة صالحة لها. إذا كانت هذه هي المرة الأولى التي تُشغّل فيها certbot، فسَتتم مطالبتك بإدخال عنوان بريد إلكتروني والموافقة على شروط الخدمة. سيتصل بعد القيام بذلك certbot بخادم Let's Encrypt، ثم يشغّل ردّا للتحقق من أنّك تتحكم في النطاق الذي تطلب الحصول على شهادة له. سَيسألك Certbot بعد ذلك عن الطريقة التي ترغب في ضبط إعدادات HTTPS الخاصّة بك: Output Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access. ------------------------------------------------------------------------------- 1: No redirect - Make no further changes to the webserver configuration. 2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration. ------------------------------------------------------------------------------- Select the appropriate number [1-2] then [enter] (press 'c' to cancel): حدّد خيارك، ثم اضغط على ENTER. سيتم تحديث الضبط، وإعادة تحميل Nginx لتفعيل الإعدادات الجديدة. الآن، نفّذ الأمر للنطاق الثاني: $ sudo certbot --nginx -d test.io -d www.test.io انظر في قسم PHP Variables. تم تعيين المتغير SERVER_PORT على القيمة 443 وضبط HTTPS على القيمة on، كما لو أنّه تم الوصول إلى Apache مباشرةً عبر HTTPS. مع ضبط هذه المتغيرات، لن تحتاج تطبيقات PHP إلى إعداد خاص للعمل خلف وسيط عكسي. سنقوم الآن بتعطيل الوصول المباشر إلى Apache. الخطوة 10 - حظر الوصول المباشر إلى Apache (اختياري) بما أن Apache يستمع على المنفذ 8080 على عنوان IP العام، فإنّه بإمكان الجميع الوصول إليه. ويمكن حظره من خلال عمل الأمر IPtables التالي في مجموعة قواعد الجدار الناري. $ sudo iptables -I INPUT -p tcp --dport 8080 ! -s your_server_ip -j REJECT --reject-with tcp-reset تأكّد من استخدام عنوان IP لخَادمك مكان اللون الأحمر في المثال السابق. بمجرد حظر المنفذ 8080 في الجدار الناري، اختبر عدم إمكانية الوصول إلى Apache. افتح متصفح الويب الخاص بك وحاول الوصول إلى أحد أسماء نطاقات Apache على المنفذ 8080. على سبيل المثال: http://example.com:8080 يجب أن يعرض المتصفح رسالة خطأ "غير قادر على الاتصال" أو "صفحة الويب غير متوفرة". وبضبط خيار IPtables tcp-reset، لن يرى أحد أي اختلاف بين المنفذ 8080 والمنفذ الذي لا يحتوي أيّ خدمةٍ عليه. ملاحظة: عند إعادة تشغيل النظام وبشكل افتراضي لن تبقى قواعد IPtables كما حدّدناها. هناك طرق متعددة للحفاظ على قواعد IPtables، ولكن أسهلها هو استخدام iptables-persistent في مستودع Ubuntu. استكشف هذه المقالة لمعرفة المزيد حول كيفيّة ضبط IPTables. لنضبط الآن Nginx لخدمة ملفات ثابتة لمواقع Apache. الخطوة 11 - تخديم الملفات الثابتة باستخدام Nginx (اختياري) عندما يقدم وسيط Nginx طلبات لنطاقات Apache، فإنّه يرسل كل ملف طلب لهذا النطاق إلى Apache. Nginx أسرع من Apache في خدمة الملفات الثابتة مثل الصور، وجافا سكريبت وأوراق الأنماط. لذلك دعونا نضبط ملف مضيف apache افتراضي خاص بـ Nginx لتخديم الملفات الثابتة مباشرة ولكن مع إرسال طلبات PHP إلى Apache. افتح الملف etc/nginx/sites-available/apache/ في محرّرك الخاص: $ sudo nano /etc/nginx/sites-available/apache ستحتاج إلى إضافة موضعين location إضافيين لكل كتلة خادم، بالإضافة إلى تعديل أقسام location الموجودة. بالإضافة إلى ذلك، ستحتاج إلى إخبار Nginx بمكان تواجد الملفات الثابتة لكل موقع. إذا قرّرت عدم استخدام شهادات SSL و TLS، فعدّل ملفك بحيث يبدو كالتالي: /etc/nginx/sites-available/apache server { listen 80; server_name test.io www.test.io; root /var/www/test.io; index index.php index.htm index.html; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { proxy_pass http://your_server_ip:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location ~ /\.ht { deny all; } } server { listen 80; server_name foobar.net www.foobar.net; root /var/www/foobar.net; index index.php index.htm index.html; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { proxy_pass http://your_ip_address:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location ~ /\.ht { deny all; { { إذا كنت تريد بأن يكون HTTPS متوفرًا أيضًا، فاستخدم الضبط التالي بدلاً من ذلك: server { listen 80; server_name test.io www.test.io; root /var/www/test.io; index index.php index.htm index.html; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { proxy_pass http://your_server_ip:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location ~ /\.ht { deny all; } listen 443 ssl; ssl_certificate /etc/letsencrypt/live/test.io/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/test.io/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; } server { listen 80; server_name foobar.net www.foobar.net; root /var/www/foobar.net; index index.php index.htm index.html; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { proxy_pass http://your_ip_address:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location ~ /\.ht { deny all; } listen 443 ssl; ssl_certificate /etc/letsencrypt/live/foobar.net/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/foobar.net/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; { إنّ التوجيه try_files يجعل Nginx يبحث عن الملفات في المستند الجذر ويقدّمها مباشرةً. إذا كان الملف له امتداد php.، سيتم تمرير الطلب إلى Apache. حتى إذا لم يُعثر على الملف في المستند الجذر، يُمرّر الطلب إلى Apache لتعمل ميزات التطبيق مثل permalinks بدون أخطاء. تحذير: إنّ التوجيه location ~ /\.ht مهم جداً؛ حيث يمنع Nginx من عرض محتويات ملفات الضبط Apache مثل htaccess. و htpasswd. التي تحتوي على معلومات حساسة. احفظ الملف وقم بإجراء اختبار الضبط: $ sudo nginx -t أعد تحميل Nginx إذا نجح الاختبار: $ sudo service nginx reload يمكنك للتحقّق من أن العمل تم بشكل صحيح فحص ملفات سجل Apache في var/log/apache2/ ومشاهدة طلبات GET لملفات info.php من test.io و foobar.net. استخدم الأمر tail لمشاهدة الأسطر القليلة الأخيرة من الملف، واستخدم رمز التبديل f- لمشاهدة الملف من أجل التغييرات: $ sudo tail -f /var/log/apache2/other_vhosts_access.log قم الآن بزيارة http://test.io/info.php في مستعرض الويب الخاص بك ثم انظر إلى خرج السجل. سترى أن Apache يجيب بالفعل: Output test.io:80 your_server_ip - - [01/Jul/2016:18:18:34 -0400] "GET /info.php HTTP/1.0" 200 20414 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36" ثم قم بزيارة صفحة index.html لكل موقع ولن ترى أي إدخالات للسجّل من قبل Apache. لأن Nginx هو من يخدّمهم. عند الانتهاء من معاينة ملف السجل، اضغط على CTRL + C لإيقاف تعقبّه. باستخدام هذا الإعداد، لن يكون Apache قادرًا على تقييد الوصول إلى الملفّات الثابتة. وللتَحكم في الوصول إلى الملفّات الثابتة تحتاج إلى ضبط في ملف المضيف apache الافتراضي الخاص بـ Nginx، ولكن هذا خارج نطاق هذه الدورة التعليميّة. الخلاصة لديك الآن خادم Ubuntu مع Nginx يُخدّم example.com و sample.org، جنبًا إلى جنب مع Apache والذي يُخدّم foobar.net و test.io. على الرغم من أن Nginx يعمل كوكيل عكسي لـ Apache، إلا أن خدمة الوكيل في Nginx تتسم بالشفافية وتُظهر اتصالها بنطاقات Apache كما لو أنها مخدّمة مباشرةً من Apache. يمكنك استخدام هذه الطريقة لتخديم مواقع آمنة وثابتة. ترجمة بتصرف للمقال How To Configure Nginx as a Web Server and Reverse Proxy for Apache on One Ubuntu 18.04 Server لصاحبه Jesin A.
  2. مقدمة صُممت أنظمة إدارة الضبط لتجعل من التحكم في عددٍ كبيرٍ من الخوادم أمرًا سهلًا للمدراء وفِرق العمليات. فهي تسمح بالتحكم في العديد من الأنظمة المختلفة بطريقةٍ آلية ومن موقع مركزي واحد. وعلى الرغم من وجود العديد من أنظمة إدارة الضبط الشائعة المتوفرة لأنظمة Linux، مثل Chef وPuppet، إلاّ أنّ هذه الأنظمة غالباً ما تكون أكثر تعقيدًا مما يريده أو يحتاجه الكثير من الأشخاص. يُعدّ Ansible بديلاً هامًا لهذه الخيارات نظرًا لأنّه يتطلب عبئا أقل بكثير للبدء. سنناقش في هذا الدليل كيفيّة تثبيت Ansible على خادم Ubuntu 18.04 وسنتحدّث عن بعض الأساسيّات حول كيفيّة استخدام البرنامج. كيف يعمل Ansible؟ يعمل Ansible عن طريق ضبط أجهزة العميل من خلال حاسب يحوي مكوّنات Ansible مُثبّتة ومُهيأة. يتصل عبر قنوات SSH الاعتيادية لاسترداد المعلومات من الأجهزة البعيدة، وإصدار الأوامر، ونسخ الملفات. ولذلك لا يتطلب نظام Ansible تثبيت أيّة برمجيّات إضافيّة على أجهزة حواسب العملاء. هذه هي إحدى الطرق التي يّبسط فيها Ansible إدارة الخوادم. يمكن ضم أي خادم لديه منفذ SSH مكشوف تحت مظلة ضبط Ansible بغض النظر عن الطور الذي يتواجد فيه ضمن دورة حياته. وهذا يعني أن أي حاسب يمكنك إدارته من خلال SSH، يمكنك إدارته أيضًا من خلال Ansible. يتخذ Ansible نهجًا معياريًا، جاعلًا من السهل التوسع لاستخدام وظائف النظام الرئيسي للتعامل مع سيناريوهات محدّدة. يمكن كتابة الوحدات باستخدام أيّة لغة وتتواصل في JSON القياسيّة. إن ملفات الضبط مكتوبة بشكل أساسي بصيغة تسلسل بيانات YAML بسبب طبيعتها الدلاليّة وتشابهها مع لغات الترميز الشائعة. ويمكن أن يتفاعل Ansible مع المضيفات hosts إما عبر أدوات سطر الأوامر أو من خلال سكربتات الضبط ، والتي تُعرف باسم Playbooks. المتطلبات المسبقة ستحتاج لمتابعة هذه الدورة التعليميّة إلى: اثنين أو أكثر من خوادم Ubuntu 18.04. سيُستخدم واحد منها كخادم Ansible الخاص بك، بينما سيُستخدم الباقي كمضيفين Ansible الخاصين بك. يجب أن يكون لكل منهم مستخدم غير جذري non-root بامتيازات sudo وجدار ناري firewall أساسي مُهيئ. يمكنك إعداد ذلك باتباع دليل إعداد الخادم المبدئي لـ Ubuntu 18.04. ويرجى ملاحظة أنّ الأمثلة في هذا الدليل تحدّد ثلاثة مضيفين Ansible، ولكن يمكن ضبط الأوامر لأيّ عدد تريده من العملاء. أُنشئت مفاتيح SSH للمستخدم الغير جذري non-root user على خادم Ansible الخاص بك. وللقيام بذلك، تابع الخطوة 1 من دليلنا حول كيفية إعداد مفاتيح SSH على Ubuntu 18.04. يمكنك من أجل هذه الدورة التعليميّة حفظ زوج المفاتيح إلى الموقع الافتراضي (ssh/id_rsa./~) ولا تحتاج إلى حماية بكلمة المرور. الخطوة 1 - تثبيت Ansible يجب تثبيت برنامج Ansible على جهاز واحد على الأقل لبدء استخدامه كوسيلة لإدارة الخوادم المختلفة. يمكنك إضافة أرشيف الحزمة الشخصيّة للمشروع (PPA (personal package archive إلى النظام الخاص بك للحصول على أحدث إصدار من Ansible على نظام Ubuntu. عليك قبل القيام بذلك أولاً تحديث فهرس الحزمة وتثبيت حزمة software-properties-common. حيث تسهّل هذه البرمجية إدارة هذا المستودع ومستودعات البرمجيات المستقلة الأخرى: $ sudo apt update $ sudo apt install software-properties-common ثم أضف PPA Ansible عن طريق كتابة الأمر التالي: $ sudo apt-add-repository ppa: ansible / ansible اضغط ENTER لقبول إضافة PPA. بعدها، حدّث فهرس حزمة النظام مرّةً أخرى حتى يصبح على معرفةٍ بالحزم المتاحة في PPA: $ sudo apt update يمكنك تثبيت برمجيّة Ansible بعد هذا التحديث: $ sudo apt install ansible يحتوي الآن خادم Ansible على جميع البرمجيّات المطلوبة لإدارة المضيفات hosts. الخطوة 2 - تهيئة الـ SSH للوصول إلى مضيفات Ansible يتصل Ansible كما ذُكر سابقًا بشكل أساسي مع أجهزة الحواسب العميلة من خلال SSH. وعلى الرغم من أن لديها بالتأكيد القدرة على التعامل مع استيثاق SSH المعتمد على كلمة المرور، إلاّ أن استخدام مفاتيح SSH يمكن أن يساعد في إبقاء الأمور بسيطة. استخدم أمر cat على خادم Ansible خاصتك لطباعة محتويات ملف مفتاح SSH العام للمستخدم الغير جذري non-root الخاص بك إلى خرْج الطرفيّة terminal: $ cat ~ / .ssh / id_rsa.pub انسخ الخرج الناتج إلى حافظتك، ثم افتح طرفيّة جديدة terminal واتصل بأحد مضيفي Ansible مُستخدمًا SSH: $ ssh sammy @ ansible_host_ip بدّل إلى المستخدم الجذري root لجهاز العميل: $ su – افتح الدليل authorized_keys ضمن المسار ~/.ssh كمستخدم جذر root : # nano ~/.ssh/authorized_keys الصق مفتاح SSH لمستخدم Ansible server في الملف، ثم احفظ الملف وأغلق المحرر (, اضغط CTRL + X, Y، ثم ENTER). ثم شغِّل الأمر exit للرجوع إلى المستخدم العادي للمضيف: # exit أخيرًا، ونظرًا لأن Ansible يستخدم مُفسّر بايثون python interpreter الموجود في المسار / usr / bin / python لتشغيل وحداته، فستحتاج إلى تثبيت Python 2 على المضيف حتى يتمكن Ansible من الاتصال به. شغّل الأوامر التالية لتحديث فهرس حزمة المضيف وتثبيت حزمة python: $ sudo apt update $sudo apt install python يمكنك بعد ذلك تشغيل أمر exit مرّةً أخرى لإغلاق الاتصال بالعميل: $ exit كرّر هذه العملية من أجل كل خادم تنوي التحكم فيه باستخدام خادم Ansible الخاص بك. بعد ذلك، سنُهيئ خادم Ansible للاتصال بالمضيفات باستخدام ملف (hosts)الخاص بـ Ansible. الخطوة 3 - إعداد مضيفات Ansible يتتبع Ansible كافة الخوادم الذي يتعرف عليها من خلال ملف المضيفات hosts. نحتاج أولًا إلى إعداد هذا الملف قبل أن نتمكن من بدء الاتصال بحواسبنا الأخرى: $ sudo nano /etc/ansible/hosts سترى ملفًا يحوي عددًا من أمثلة "نماذج" الضبط المُعقّب عليها (بإشارة # تسبق كل سطر). لن تعمل هذه الأمثلة فعليًا في حالتنا نظرًا لأن المضيفات المُدرجات في كل منها وهميّة. بكافة الأحوال سنحتفظ بهذه الأمثلة في الملف لمساعدتنا في الضبط في حال أردنا تنفيذ حالات أكثر تعقيدًا في المستقبل. إن ملف hosts مرن إلى حدّ ما ويمكن ضبطته بعدّة بطرق مختلفة. وبناءً عليه، ستبدو الصياغة التي سنستخدمها كما يلي: [group_name] alias ansible_ssh_host=your_server_ip في هذا المثال، إن group_name وسم تنظيمي يتيح لك الإشارة إلى أي خادم مدرج تحته بكلمة واحدة، بينما alias هو مجرد اسم للإشارة إلى خادم معيّن. نعتبر في حالتنا أن لدينا ثلاثة خوادم سنتحكم بهم باستخدام Ansible. يمكن عند هذه النقطة الوصول إلى هذه الخوادم من خادم Ansible بكتابة: $ ssh root@ansible_host_ip إذا أعددت هذا بشكل صحيح فلا يجب أن تُطالب بكلمة مرور. سنفترض هنا لأغراض العرض التوضيحي أن عناوين IP لمضيفاتنا هي 203.0.113.1 و 203.0.113.2 و 203.0.113.3. وسنضبط ذلك بحيث يمكننا الإشارة إليها بشكل فردي كـ host1، و host2، و host3، أو كمجموعة باسم servers. و لإتمام ذلك يتوجب إضافة هذه الكتلة إلى ملف hosts الخاص بنا: [servers] host1 ansible_ssh_host=203.0.113.1 host2 ansible_ssh_host=203.0.113.2 host3 ansible_ssh_host=203.0.113.3 يمكن أن تكون المضيفات في مجموعاتٍ متعددة، ويمكن للمجموعات ضبط المعاملات parameters من أجل جميع أعضائها. فلنجرّب هذا الآن. إن حاولنا باستخدام إعداداتنا الحاليّة الاتصال بأي من هذه الأجهزة المضيفة hosts من خلال Ansible، فسيفشل الأمر (على افتراض أنك لا تعمل كمستخدم جذر root). يحدث هذا لأنّه تم تضمين مفاتيح SSH من أجل المستخدم الجذر على الأنظمة البعيدة وسيحاول Ansible الاتصال بشكل افتراضي بواسطة المستخدم الحالي، ستعطينا محاولة الاتصال هذا الخطأ: [servers] Output host1 | UNREACHABLE! => { "changed": false, "msg": "Failed to connect to the host via ssh.", "unreachable": true } نستخدم على خادم Ansible مستخدمًا اسمه sammy. سيحاول Ansible الاتصال بكل مضيف باستخدام ssh sammy @ server. ولن يعمل هذا إذا لم يكن المستخدم sammy موجودًا على النظام البعيد أيضًا. يمكننا إنشاء ملف يخبر جميع الخوادم في مجموعة "servers " للاتصال كمستخدم جذر root. سننشئ لعمل ذلك دليلًا في بنية ضبط Ansible يدعى group_vars. ويمكننا ضمن هذا المجلد إنشاء ملفات بتنسيق YAML لكل مجموعة نريد ضبطها: $ sudo mkdir /etc/ansible/group_vars $sudo nano /etc/ansible/group_vars/servers يمكننا وضع ضبطنا هنا. تبدأ ملفات YAML بـ "---"، لذا تأكد من عدم نسيان هذا الجزء. /etc/ansible/group_vars/servers --- ansible_ssh_user: root احفظ وأغلق هذا الملف عند الانتهاء. إذا كنت تريد تحديد تفاصيل الضبط لكل خادم، بغض النظر عن المجموعة المرتبط بها، فيمكنك وضع هذه التفاصيل في ملف في المسار etc/ansible/group_vars/all/. يمكن ضبط المضيفات بشكل فردي عن طريق إنشاء ملفات مُسماة بالاسم البديل alias تحت الدليل في /etc/ansible/host_vars. الخطوة 4 - استخدام أوامر Ansible بسيطة يمكننا الآن -وبعد أن أعددنا مضيفاتنا و ضبطنا تفاصيل تهيئة كافية للسماح لنا بالاتصال بنجاح مع مضيفاتنا- تجربة الأمر الأول. عمل اختبار ping لجميع خوادمنا المُهيئة وذلك بكتابة: $ anmible -m ping all ستكون المخرجات كالتالي: host1 | SUCCESS => { "changed": false, "ping": "pong" } host3 | SUCCESS => { "changed": false, "ping": "pong" } host2 | SUCCESS => { "changed": false, "ping": "pong" } وهو اختبار بسيط للتأكّد من أنّ Ansible يتصل بجميع مضيفاته. تعني all جميع المضيفات. ويمكننا بسهولة تحديد مجموعة معيّنة كما يلي: $ ansible -m ping servers يمكننا أيضًا تحديد مضيف بشكل فردي: $ anmible -m ping host1 يمكننا تحديد عدّة مضيفات من خلال فصلها باستخدام النقطتين: $ anmible -m ping host1: host2 إنّ المقطع -m ping من الأمر عبارة عن تعليمة لـ Ansible لاستخدام الوحدة "ping". وهي في الأساس أوامر يمكنك تشغيلها على المضيفات عن بعد. تعمل وحدة ping بعدّة طرق مثل أداة ping العادية في Linux، ولكنها بدلاً من ذلك تتحقق من اتصال Ansible. لا تأخذ وحدة ping في الواقع أيّة وسائط arguments، لكن يمكننا تجربة أمر آخر لمعرفة كيفيّة عمل ذلك. نمرّر المعاملات في تدوين نصي "سكريبت" عن طريق كتابة -a. تتيح لنا الوحدة "shell" إرسال أمر طرفيّة terminal command إلى المضيف البعيد واسترداد النتائج. على سبيل المثال، يمكننا استخدام الأمر التالي لمعرفة استخدام الذاكرة على جهاز host1: $ ansible -m shell -a 'free -m' host1 ستكون مخرجات Shell كالتالي: host1 | SUCCESS | rc=0 >> total used free shared buffers cached Mem: 3954 227 3726 0 14 93 -/+ buffers/cache: 119 3834 Swap: 0 0 0 وبذلك أصبح خادم Ansible الخاص بك مُهيئًا ويمكنك الاتصال والتحكم في المضيفات بنجاح. الخلاصة ضبطنا في هذه الدورة التعليميّة Ansible وتأكّدنا من إمكانية اتصاله مع كل مضيف. واستخدمنا أيضًا الأمر ansible لتنفيذ مهام بسيطة عن بُعد. وعلى الرغم من أن هذا مفيد، إلا أنّنا لم نُغطّي أهم ميزة لـ Ansible في هذا المقال وهي الـ Playbooks. تعتبر Ansible Playbooks طريقةً قويّة وبَسيطة لإدارة عمليات تهيئة الخادم وعمليات النشر المتعدّدة الأجهزة. للحصول على تمهيد حول كتب Playbook، راجع هذا الدليل. بالإضافة إلى ذلك، فإننا نشجعك على مراجعة توثيق Ansible الرسميّة لمعرفة المزيد عن الأداة ترجمة وبتصرّف للمقال How to Install and Configure Ansible on Ubuntu 18.04 لصاحبيه Stephen Rees-Carter و Mark Drake
  3. مقدمة تأتي قواعد بيانات SQL مُثبّتة مع جميع الأوامر التي تحتاجها للإضافة، والتعديل، والحذف والاستعلام عن بياناتك. يوفّر هذا الدليل لنمط الورقة المرجعية cheat sheet مرجعًا سريعًا لبعضٍ من أوامر SQL الأكثر شيوعًا. كيفية استخدام هذا الدليل: هذا الدليل على شكل ورقة مرجعيّة فيها أمثلة منفصلة قابلة للاستخدام فرادى. انتقل إلى أي مقطع ذي صلة بالمهمة التي تحاول إكمالها. عندما ترى نصًّا مميّزًا في أوامر هذا الدليل، فضع بالحسبان أن هذا النص يشير إلى الأعمدة، والجداول، والبيانات في قاعدة البيانات الخاصة بك. ضُمّنت قيم البيانات في هذا الدليل في الأمثلة المُعطاة بعلامة ('). من الضروري في SQL تضمين أي قيم بيانات تحتوي على سلاسل نصية في علامات اقتباس أحادية. هذا التضمين غير مطلوب من أجل البيانات الرقمية، ولكنه لن يتسبب بأيّة مشاكل أيضًا. يرجى ملاحظة أنّه على الرغم من كون SQL معياريّة، إلاّ أنّ معظم برامج قواعد بيانات SQL لها إضافاتها الخاصّة. يستخدم هذا الدليل MySQL كنموذج لنظام إدارة قواعد البيانات العلائقية (RDBMS)، ولكن الأوامر المقدّمة ستعمل مع برامج قواعد البيانات العلائقية الأخرى، بما في ذلك PostgreSQL و MariaDB وSQLite. سنُضمّن الأوامر البديلة عند وجود فروق مهمّة بين أنظمة إدارة قواعد البيانات العلائقية RDBMSs. بدء مِحث أوامر قاعدة البيانات (باستخدام استيثاق Socket/Trust) يمكن لمستخدم MySQL الجذر root الاستيثاق بدون كلمة مرور بشكل افتراضي في نظام التشغيل أبونتو Ubuntu 18.04 باستخدام الأمر التالي: $ sudo mysql استخدم الأمر التالي لفتح مِحث أوامر PostgreSQL. سيُسجلك هذا المثال كمستخدم postgres، والذي يتضمن صلاحيات دور المستخدم المميّز superuser role، ولكن يمكنك استبداله بأي دور مُنشئ مُسبقًا: $ sudo -u postgres psql بدء مِحث أوامر قاعدة البيانات (باستخدام استيثاق كلمة المرور) إذا ُضبط مستخدم MySQL الجذر root للاستيثاق باستخدام كلمة مرور، فبإمكانك استخدام الأمر التالي: $ mysql -u root -p إذا أعددت مُسبقًا حساب مستخدم عادي non-root لقاعدة بياناتك، فيمكنك أيضًا استخدام هذه الطريقة لتسجيل الدخول باسم هذا المستخدم: $ mysql -u user -p سيُقاطعك الأمر السابق بعد تشغيله للمطالبة بكلمة المرور الخاصّة بك. إذا كنت ترغب في جعل كلمة المرور كجزء من الأمر، فأَتبعْ الخيار p- مباشرة بكلمة مرورك، بدون ترك فراغ بينهما: $ mysql -u root -ppassword إنشاء قاعدة بيانات يُنشئ الأمر التالي قاعدة بيانات بإعداداتٍ افتراضيّة: mysql> CREATE DATABASE database_name; يمكنك إذا أردت لقاعدة بياناتك أن تستخدم مجموعة محارف وتصنيف مختلفة عن الإعدادات الافتراضيّة تحديد ذلك باستخدام الصياغة التالية: mysql> CREATE DATABASE database_name CHARACTER SET character_set COLLATE collation; إظهار قائمة قواعد البيانات شغّل الأمر التالي لرؤية قواعد البيانات الموجودة في نظام MySQL أو MariaDB: mysql> SHOW DATABASES; يمكنك في PostgreSQL مشاهدة قواعد البيانات المُنشأة باستخدام الأمر التالي: postgres=# \list حذف قاعدة البيانات شغّل الأمر التالي لحذف قاعدة بيانات بما في ذلك ضمنًا أي جداول وبيانات موجودة فيها: mysql> DROP DATABASE IF EXISTS database; إنشاء مستخدم نفّذ الأمر التالي لإنشاء معرّف مستخدِم لقاعدةِ بياناتك من دون تحديد أيّ امتيازاتٍ له: mysql> CREATE USER username IDENTIFIED BY 'password'; تَستخدم PostgreSQL بنية مشابهة، ولكنها مختلفة قليلاً، إليك الصياغة: postgres=# CREATE USER user WITH PASSWORD 'password'; يمكنك إذا أردتَ إنشاء مستخدم جديد ومنحه امتيازات باستخدام أمر واحد عن طريق إصدار عبارة GRANT. ينشئ الأمر التالي مستخدمًا جديدًا ويمنحه امتيازات كاملة لكامل قاعدة البيانات والجداول في نظام إدارة قواعد البيانات العلائقية RDBMS: mysql> GRANT ALL PRIVILEGES ON *.* TO 'username'@'localhost' IDENTIFIED BY 'password'; لاحظ الكلمة المفتاحيّة PRIVILEGES في تعليمة GRANT السابقة. إن هذه الكلمة اختيارية في معظم أنظمة إدارة قواعد البيانات العلائقية، ويمكن كتابة هذه التعليمة بشكل مكافئ على النحو التالي: mysql> GRANT ALL ON *.* TO 'username'@'localhost' IDENTIFIED BY 'password'; كن منتبهًا مع ذلك، أنّ الكلمة المفتاحيّة PRIVILEGES مطلوبة لمنح امتيازات كهذه عندما يكون وضع Strict SQL مُشغّلًا. حذف مستخدم استخدم الصياغة التالية لحذف اسم مستخدم قاعدة البيانات: mysql> DROP USER IF EXISTS username; لاحظ أن هذا الأمر لا يحذف افتراضيًا أيّة جداول أُنشأت بواسطة المستخدم المحذوف، وقد تؤدي محاولات الوصول إلى جداول كهذه إلى حدوث أخطاء. اختيار قاعدة البيانات يجب أولًا إخبار RDBMS بقاعدة البيانات التي ترغب في إنشائها في MySQL و MariaDB قبل أن تتمكن من إنشاء جدول. استخدم الصياغة التالية للقيام بذلك: mysql> USE database; يجب عليك استخدام الأمر التالي في PostgreSQL لاختيار قاعدة بياناتك المرغوبة: postgres=# \connect database إنشاء جدول تنشئ بنية الأمر التالية جدولًا جديدًا باسم table يحوي عمودين لكل منهما نوع بياناته الخاص: mysql> CREATE TABLE table ( column_1 column_1_data_type, column_2 column_2_data_taype ); حذف جدول نفّذ ما يلي لحذف جدول بالكامل، بما في ذلك جميع البيانات الخاصّة به: mysql> DROP TABLE IF EXISTS table إدخال البيانات في جدول استخدم الصياغة التالية لملء جدول بصف واحد من البيانات (row): mysql> INSERT INTO table ( column_A, column_B, column_C ) VALUES ( 'data_A', 'data_B', 'data_C' ); يمكنك أيضًا ملء جدول بعدة صفوف من البيانات باستخدام أمر واحد، على النحو التالي: mysql> INSERT INTO table ( column_A, column_B, column_C ) VALUES ( 'data_1A', 'data_1B', 'data_1C' ), ( 'data_2A', 'data_2B', 'data_2C' ), ( 'data_3A', 'data_3B', 'data_3C' ); حذف بيانات من جدول استخدم بنية الأوامر التالية لحذف صف من البيانات من جدول. لاحظ أن value يجب أن تكون القيمة الموجودة في العمود المحدد column في الصف الذي تريد حذفه: mysql> DELETE FROM table WHERE column='value'; ملاحظة: إذا لم تُضمّن عبارة WHERE في تعليمة DELETE، كما هو موضّح في المثال التالي، فستُحذف جميع البيانات الموجودة في الجدول، ولكن لن تُحذف الأعمدة أو الجدول نفسه: mysql> DELETE FROM table; تغيير البيانات في جدول استخدم الصياغة التالية لتحديث البيانات الموجودة في الصف المُعطى. لاحظ أنّ عبارة WHERE في نهاية الأمر تُخبر SQL بالصف المطلوب تحديثه. إنّ value هي القيمة الموجودة في column_A المحاذية للصفِ الذي تريد تغييره. ملاحظة: إذا أهملتَ تضمين عبارة WHERE في تعليمة UPDATE، فسيَستبدِل الأمر البيانات الموجودة في كل صف من الجدول. mysql> UPDATE table SET column_1 = value_1, column_2 = value_2 WHERE column_A=value; إضافة عمود ستضيف صياغة الأمر التالية عمودًا جديدًا إلى جدول: mysql> ALTER TABLE table ADD COLUMN column data_type; حذف عمود سيؤدي هذا الأمر إلى حذف عمود من جدول: mysql> ALTER TABLE table DROP COLUMN column; تنفيذ الاستعلامات الأساسيّة استخدم الصياغة التالية لعرض جميع البيانات من عمود واحد من جدول: mysql> SELECT column FROM table; افصلْ بين أسماء الأعمدة بفاصلة للاستعلام عن أعمدة متعددة من نفس الجدول: mysql> SELECT column_1, column_2 FROM table; يمكنك أيضًا الاستعلام عن كل الأعمدة في جدول عن طريق استبدال أسماء الأعمدة بعلامة النجمة (*). تعمل علامات النجمة في SQL كبدائل لتمثيل "الكل": mysql> SELECT * FROM table; استخدام عبارات WHERE يمكنك تضييق نطاق نتائج استعلام عن طريق إلحاق تعليمة SELECT بعبارة WHERE، كما يلي: mysql> SELECT column FROM table WHERE conditions_that_apply; يمكنك على سبيل المثال الاستعلام عن جميع البيانات من صف واحد من خلال صياغة مشابهة لما يلي. لاحظ أن value يجب أن تكون قيمة محفوظة في كل من column المحدّد والصف الذي تريد الاستعلام عنه: mysql> SELECT * FROM table WHERE column = value; العمل مع مُعاملات المقارنة يحدّد مُعامل المقارنة في جملة WHERE كيفيّة مقارنة العمود المحدّد بقيمة ما. فيما يلي بعض معاملات المقارنة الشائعة لـ SQL: = : اختبار المساواة != : اختبار عدم المساواة < : اختبار أقل من > : اختبار أكبر من <= : اختبار أقل من أو يساوي >= : اختبار أكبر من أو يساوي BETWEEN : اختبار فيما إذا كانت القيمة ضمن مجال مُعطى IN : اختبار ما إذا كانت قيمة الصّف مُتضَمّنة في مجموعة من القيم المحدّدة EXISTS : اختبار ما إذا كانت صفوف موجودة، تبعاً للشروط المحدّدة LIKE : اختبار فيما إذا كانت قيمة تتطابق مع سلسلة نصيّة محدّدة IS NULL : اختبار القيم الفارغة IS NOT NULL : اختبار كافّة القيم غير الفارغة "NULL" العمل مع محارف البدل Wildcards يسمح SQL باستخدام محارف البدل wildcard. وهي مفيدة عندما تحاول العثور على مُدخل محدّد في جدول، ولكنك لا تكون متأكدًا تماماً من هذا المُدخل. تعتبر علامات النجمة (*) عناصر بديلة لتمثيل "الكل"، حيث تقوم بالاستعلام كل الأعمدة في جدول: mysql> SELECT * FROM table; تمثل علامات النسبة المئوية (٪) صفراً أو أكثر من محارف غير معروفة. mysql> SELECT * FROM table WHERE column LIKE val%; يُستخدم التسطير السفلي (_) لتمثيل محرف واحد غير معروف: mysql> SELECT * FROM table WHERE column LIKE v_lue; حساب المُدخلات في عمود تُستخدم الدّالة COUNT لإيجاد عدد الإدخالات في عمود محدّد. ستُرجع الصياغة التالية إجمالي عدد القيم الموجودة في column: mysql> SELECT COUNT(column) FROM table; يمكنك تضييق نتائج دالة COUNT من خلال إضافة عبارة WHERE، كما يلي: mysql> SELECT COUNT(column) FROM table WHERE column=value; إيجاد قيمة المعدل في عمود تُستخدم الدّالة AVG لإيجاد المعدل بين القيم الموجودة في عمود محدّد. لاحظ أن دالة AVG ستعمل فقط مع الأعمدة التي تحتوي على قيم رقميّة. وقد تُعيد خطأ أو 0 عند استخدامها على عمود يحمل قيم نصيّة: mysql> SELECT AVG(column) FROM table; إيجاد مجموع القيم في عمود تُستخدم الدّالة SUM لإجمالي مجموع القيم الرقميّة الموجودة في عمود: mysql> SELECT SUM(column) FROM table; كما هو الحال مع دالة AVG، إذا نَفّذتَ الدالة SUM على عمود يحوي قيم نصيّة، فقد تُعيد خطأ أو فقط 0، وذلك اعتمادًا على نظام إدارة قواعد البيانات العلائقية خاصتك. إيجاد القيمة الكبرى في عمود استخدم دالة MAX للعثور على أكبر قيمة رقميّة في عمود أو القيمة الأخيرة أبجديًا : mysql> SELECT MAX(column) FROM table; إيجاد القيمة الصغرى في عمود استخدم الدّالة MIN للعثور على أصغر قيمة رقميّة في عمود أو القيمة الأولى أبجديًا: mysql> SELECT MIN(column) FROM table; فرز النتائج باستخدام عبارات ORDER BY تُستخدم عبارة ORDER BY لفرز نتائج الاستعلام. تُعيد الصياغة التالية للاستعلام القيم من column_1 و column_2 وتُرتّب النتائج حسب القيم الموجودة في column_1 بترتيب تصاعدي، أو بترتيب أبجدي بالنسبة لقيم السلاسل النصيّة: mysql> SELECT column_1, column_2 FROM table ORDER BY column_1; أتبع الاستعلام بـ DESC لتنفيذ نفس الإجراء، ولكن مع ترتيب النتائج بترتيب أبجدي تنازلي: mysql> SELECT column_1, column_2 FROM table ORDER BY column_1 DESC; فرز النتائج باستخدام عبارات GROUP BY تشبه عبارة GROUP BY عبارة ORDER BY، ولكنها تُستخدم لفرز نتائج استعلام يتضمن دالة مُجمِّعة مثل COUNT أو MAX أو MIN أو SUM. ستؤدي الدوال التجميعيّة الموضّحة في القسم السابق بمفردها إلى إرجاع قيمة واحدة فقط. ويمكنك مع ذلك عرض نتائج دالة التجميع المنفّذة على كل قيمة مطابقة في العمود من خلال تضمين عبارة GROUP BY. ستَحسب الصياغة التالية عدد القيم المطابقة في column_2 وتُجمّعها بترتيب تصاعدي أو أبجدي: mysql> SELECT COUNT(column_1), column_2 FROM table GROUP BY column_2; أتبِعْ الاستعلام بـ DESC لتنفيذ نفس الإجراء، ولكن بتجميع النتائج بالترتيب الأبجدي التنازلي: mysql> SELECT COUNT(column_1), column_2 FROM table GROUP BY column_2 DESC; الاستعلام عن جداول متعددة مع عبارات JOIN تستخدم عبارات JOIN لإنشاء مجموعات نتائج تجمع بين صفوف من جدولين أو أكثر. لن تعمل عبارات JOIN إلا إذا كان لكل من الجدولين عمود له اسم ونوع بيانات متطابقان، كما في هذا المثال: mysql> SELECT table_1.column_1, table_2.column_2 FROM table_1 JOIN table_2 ON table_1.common_column=table_2.common_column; هذا مثال على عبارة INNER JOIN. ستقوم INNER JOIN بإرجاع جميع السجلات التي تحتوي على قيم متطابقة في كلا الجدولين، ولكنها لن تعرض أي سجلات لا تحتوي على قيم متطابقة. من الممكن إرجاع كافة السجلات من أحد الجدولين، بما في ذلك القيم التي لا تحتوي على مطابق في الجدول الآخر، وذلك باستخدام عبارة JOIN خارجيّة. تُكتب عبارات JOIN الخارجية إما كـ LEFT JOIN أو RIGHT JOIN. تُرجع عبارة LEFT JOIN كافة السجلات من الجدول "الأيسر" والسجلات المطابقة فقط من الجدول "اليمين". في سياق عبارة JOIN الخارجيّة، يكون الجدول الأيسر هو المشار إليه في جملة FROM، والجدول الأيمن هو أي جدول آخر مشار إليه بعد عبارة JOIN. سيَعرض الاستعلام التالي كل سجل من table_1 وفقط القيم المطابقة من table_2. ستظهر القيم غير المطابقة في table2 كـ NULL في مجموعة النتائج: mysql> SELECT table_1.column_1, table_2.column_2 FROM table_1 LEFT JOIN table_2 ON table_1.common_column=table_2.common_column; إن وظيفة عبارة RIGHT JOIN مماثلة لـ LEFT JOIN، ولكنها تُرجع جميع النتائج من الجدول الأيمن، والقيم المطابقة فقط من الجدول الأيسر: mysql> SELECT table_1.column_1, table_2.column_2 FROM table_1 RIGHT JOIN table_2 ON table_1.common_column=table_2.common_column; دمج تعليمات SELECT متعددة باستخدام عبارات UNION يفيد مُعامل UNION في دمج نتائج تعليمتي SELECT (أو أكثر) في مجموعة نتائج واحدة: mysql> SELECT column_1 FROM table UNION SELECT column_2 FROM table; يمكن بالإضافة إلى ذلك أن تجمع عبارة UNION بين تعليمتي SELECT (أو أكثر) والتي تستعلم عن جداول مختلفة في نفس مجموعة النتائج: mysql> SELECT column FROM table_1 UNION SELECT column FROM table_2; الخلاصة يغطي هذا الدليل بعضًا من الأوامر الأكثر شيوعًا في SQL المُستخدمة لإدارة قواعد البيانات، والمستخدمين، والجداول، والاستعلام عن المحتويات الموجودة في هذه الجداول. ومع ذلك، هناك العديد من تجميعات العبارات والمعاملات والتي تنتج جميعها مجموعات فريدة من النتائج. إذا كنت تبحث عن دليل أكثر شموليّة للعمل مع SQL، فإنّنا نُشجعك على مراجعة Oracle's Database SQL Reference بالإضافة إلى ذلك، إذا كانت هناك أوامر SQL شائعة ترغب في رؤيتها في هذا الدليل، فيرجى طرحها أو تقديم اقتراحات في التعليقات أدناه. ترجمة بتصرّف للمقال How To Manage an SQL Database لصاحبه Mark Drake
  4. مقدمة تقدم المواقع والتطبيقات الحديثة في كثير من الأحيان كميّة كبيرة من المحتوى الثابت static content للمستخدمين النهائيين. يتضمن هذا المحتوى الصور، وأوراق الأنماط stylesheets، والجافا سكربت والفيديو. حيث يزداد استخدام عرض الحزمة bandwidth ويزداد زمن تحميل الصفحة مع زيادة حجم وعدد هذه الأصول الثابتة، مما يؤدي إلى تدني عملية التصفح لزبائنك وتقليص السعة المتاحة لخوادمك. يمكنك تنفيذ CDN أو شبكة تسليم المحتوى لتخزين هذه الأصول مؤقتًا عبر مجموعة من الخوادم الموزّعة جغرافيًا لتقليل زمن تحميل الصفحة بشكل كبير، وتحسين الأداء، وتقليل تكاليف عرض الحزمة bandwidth والبنية التحتيّة. سنقدّم في هذه الدورة التعليمية نظرة عامّة عالية المستوى على شبكات CDN وكيفيّة عملها، فضلاً عن الفوائد التي يمكن أن توفّرها لتطبيقات الويب الخاصّة بك. ما هي CDN ؟ شبكات تسليم المحتوى (Content Delivery Networks) هي عبارة عن مجموعة خوادم موزّعة جغرافيًا حُسّنت لتقديم المحتوى الثابت للمستخدمين النهائيين. يمكن أن يكون هذا المحتوى الثابت أي نوع من أنواع البيانات تقريبًا، ولكن تُستخدم شبكات CDN بشكل أكثر شيوعًا لتسليم صفحات الويب والملفات المرتبطة بها، وتدفقات الفيديو والصوت، وحزم البرامج الكبيرة. تتكون CDN من نقاط تواجد متعددة PoPs) points of presence) في مواقع مختلفة، يتألف كل منها من عدّة خوادم طرفيّة ‎.edge servers تخزّن هذه الخوادم الأصول مؤقتًا من ملفاتك الأصليّة، أو من خادم مضيف. وعندما يزور أحد المستخدمين موقعك ويطلب أصولًا ثابتةً كالصور أو ملفات جافا سكربت، ستُوجّه طلباته بواسطة شبكة CDN إلى أقرب خادم طرفي edge server موجود، والذي سيُعرض المحتوى منه. إذا لم يكن لدى الخادم الطرفي الأصول المخزنة وقتيّا أو كانت صلاحيتها منتهية، فسيجلب CDN النسخة الأخيرة من خادم طرفي CDN آخر قريب أو من خوادم الأصل الخاصّة بك وتخزينها مؤقتًا. وستُرجع النسخة المخزّنة إلى المستخدم النهائي إذا كانت طرفيّة CDN تحتوي على إدخالات مخبأة لهذه الأصول (والذي يحدث في معظم الأوقات عندما يستقبل موقعك كمية معتدلة من الزيارات). يسمح ذلك للمستخدمين المتوزعين جغرافيًا بتقليل عدد القفزات اللازمة لاستلام المحتوى الثابت، وجلب المحتوى مباشرة من النسخة المخزّنة للخادم الطرفي المجاور. والنتيجة هي تقليل كبير لزمن الاستجابة ولفقد الحزم، وتسريع أوقات تحميل الصفحات، وتخفيض كبير للتحميل على البنية التحتيّة الأصليّة. غالبًا ما يقدم مزوِّدو خدمات شبكات CDN ميّزات إضافية مثل تخفيف معدل هجمات DDoS، والإحصائيات الخاصّة بالمستخدمين، والتحسينات المتعلّقة بالتدفق أو بحالات الاستخدام المتنقل بتكلفة اضافية. كيف تعمل CDN؟ عندما يزور أحد المستخدمين موقعك على الويب، فإنّه يتلقى أولاً استجابةً من خادم DNS يحتوي على عنوان IP لخادم الويب المضيف. ثم يطلب متصفحهم محتوى صفحة الويب، والذي يتكون غالبًا من مجموعة متنوعة من الملفات الثابتة، مثل صفحات HTML، وأوراق الأنماط المتتالية CSS، وشفرات جافا سكربت، والصور. بمجرد طرح CDN وتفويض هذه الأصول الثابتة إلى خوادم CDN، إمّا عن طريق "دفعها" يدويًا أو جعل CDN "يسحب" الأصول تلقائيًا (كلا الآلتين مشروحتان في القسم التالي)، فأنت عندها توجّه خادم الويب الخاص بك لإعادة كتابة روابط links المحتوى الثابت بحيث تشير هذه الارتباطات إلى الملفات المستضافة بواسطة CDN. بإمكانك إذا كنت تستخدم نظام إدارة محتوى مثل WordPress، تنفيذ إعادة كتابة هذا الارتباط باستخدام إضافات الطرف الثالث third-party plugin مثل CDN Enabler. توفّر العديد من شبكات CDN الدعم للنطاقات المخصّصة custom domains، مما يسمح لك بإنشاء سجل CNAME تحت النطاق الخاص بك للإشارة إلى نقطة نهاية CDN. عندما يتلقى CDN طلب مستخدم عند نقطة النهاية هذه (الموجودة على الطرفيّة ، والأقرب إلى المستخدم من خوادمك الخلفية backend servers، فإنّه يُوجّه الطلب إلى نقطة التواجد (PoP) الأقرب إلى المستخدم. غالبًا ما يتكون PoP هذا من واحد أو أكثر من خوادم طرفيّة CDN مجمّعة في نقطة تبادل الإنترنت (IxP)، وهي في الأساس مركز البيانات الذي يستخدمه مزودي خدمة الإنترنت (ISP) لربط شبكاتهم. يقوم موازن الحمل الداخلي الخاص بـ CDN بتوجيه الطلب إلى خادم طرفي موجود في نقطة التواجد، والذي يقدّم بدوره المحتوى إلى المستخدم. تختلف آليات التخزين المؤقت Caching عبر مزودي خدمات CDN، ولكنها تعمل بشكل عام كما يلي: 1- عندما يتلقى CDN طلبًا لأصل ثابت للمرة الأولى، مثلا صورة PNG، وهو لا يحتوي على نسخة مخبأة من هذا الأصل فيتوجب عليه جلب نسخة من الأصل من خادم طرفي CDN قريب أو من الخادم الأصلي نفسه. يُعرف هذا بفقدان البيانات من ذاكرة التخزين المؤقت " Cache miss"، ويمكن عادةً اكتشافه عن طريق فحص ترويسة header استجابة HTTP، الذي يحتوي على X-Cache: MISS. سيكون هذا الطلب في المرّة الأولى أبطأ من الطلبات المستقبلية له لأن هذا الأصل سيخزّن كنسخة مخبأة على خادم طرفي بعد إكمال هذا الطلب. 2- سيتم الآن تخديم الطلبات المستقبلية لهذا الأصل (المخبأ)، الموجهة إلى موقع الطرفيّة هذا من النسخة المخبأة حتى انتهاء صلاحيتها (عادةً ما تُضبط من خلال HTTP headers ). وستكون هذه الاستجابات أسرع بشكل كبير من الطلب الأول، مما يقلّل وقت الاستجابة بشكل كبير للمستخدمين ويقلّل حركة مرور البيانات traffic إلى شبكة CDN. يمكنك التحقق من أن الاستجابة قد تم عرضها من ذاكرة التخزين المؤقت لـ CDN من خلال فحص ترويسة استجابة الـ HTTP، والذي يجب أن يحتوي الآن على X-Cache: HIT. راجع توثيق مزود CDN الخاص بك لمعرفة المزيد حول كيفية عمل وتنفيذ شبكة CDN محدّدة. سنقدم في القسم التالي نوعين شائعين من شبكات CDN: شبكات "دفع" و "سحب" CDN. مناطق الدفع مقابل مناطق السحب يوفر أغلب مزودي خدمة CDN طريقتين لتخزين بياناتك: مناطق السحب ومناطق الدفع. تنطوي مناطق السحب على إدخال عنوان خادمك الأصلي، والسماح لـ CDN تلقائيًا بجلب وعمل نسخة مخزّنة لجميع الموارد الثابتة المتوفرة على موقعك. تُستخدم مناطق السحب بشكل عام لتسليم "توفير" التحديثات المتكررة، وأصول الويب الصغيرة إلى متوسطة الحجم مثل ملفات HTML وCSS وجافا سكربت. بعد تزويد الـ CDN بعنوان الخادم الأصلي "المصدر"، فإنّ الخطوة التالية هي عادة إعادة كتابة الروابط links إلى الأصول الثابتة بحيث تشير الآن إلى عنوان URL المقدّم من شبكة CDN. ستتعامل شبكة CDN من الآن فصاعدًا مع طلبات الأصول الواردة للمستخدمين وستعرض المحتوى من ذاكرات التخزين المؤقت "النسخ المخبأة" الموزّعة جغرافيًا ومن الأصل عندما يكون ذلك مناسبًا. لاستخدام منطقة الدفع، حمّل بياناتك إلى خانة معيّنة أو موضع تخزين (bucket )، والتي تنقلها شبكات CDN للتخزين المؤقت على أسطول fleet الخوادم الطرفيّة المتوزعة. تُستخدم مناطق الدفع عادةً من أجل الملفات الأكبر حجمًا والقليلة التغيّر، مثل الأرشيفات، وحزم البرمجيات، وملفات الكتب الإلكترونية PDF، وملفات الفيديو والملفات الصوتية. فوائد استخدام CDN يمكن لأي موقع تقريبًا الاستفادة من الفوائد التي يوفرها توزع CDN، ولكن عادةً ما تكون الأسباب الأساسيّة للتنفيذ واحدة وهي لتخفيف استخدام عرض الحزمة بين خوادم الأصل الخاصّة بك وخوادم CDN، ولتقليل زمن الاستجابة للمستخدمين الموزعين جغرافيًا. سنستعرض هذا أدناه إضافة إلى العديد من الفوائد الرئيسيّة الأخرى المتاحة باستخدام CDN. تخفيف الحمل عن الأصل Origin Offload إذا كنت تقترب من استخدام كامل سعة عرض الحزمة على خوادمك، فسيُنقَل تخديم الأصول الثابتة كالصور، ومقاطع الفيديو، وملفات CSS وجافا سكريبت، مما يؤدي إلى تقليل استخدام عرض الحزمة للخوادم بشكل كبير. حيث صُمّمت شبكات تسليم المحتوى وحُسّنت لتخديم المحتوى الثابت، وستوجَّه طلبات العميل لهذا المحتوى إلى خوادم Edge CDN وتخدّم منها. ولهذا فائدة إضافية تتمثل في تقليل الحمل على خوادم الأصل الخاصّة بك، حيث ستُخدّم هذه البيانات بعدها بتكرار أقل بكثير. زمن استجابة أقل لتحسين تجربة المستخدم يمكن لـ CDN تقليل التأخير إذا كان المستخدمين لديك موزعين جغرافيًا، وكان جزء كبير من حركة مرور البيانات traffic الخاصّة بك يأتي من منطقة جغرافيّة بعيدة وذلك عن طريق التخزين المؤقت لأصول ثابتة على خوادم طرفيّة أقرب إلى هؤلاء المستخدمين. يمكنك من خلال تقليل المسافة بين المستخدمين والمحتوى الثابت، تقديم محتوى للمستخدمين بسرعة أكبر وتحسين تجربتهم بزيادة سرعات تحميل الصفحات. تتضاعف هذه الفوائد بالنسبة إلى مواقع الويب التي تُخدّم في المقام الأول محتوى الفيديو المستهلك لعرض الحزمة، حيث يؤدي التأخير المرتفع وأوقات التحميل البطيئة إلى التأثير بشكل مباشر على تجربة المستخدم وترابط المحتوى. إدارة الموجات الكبيرة لحركة مرور البيانات وتجنب التوقف تسمح لك شبكات CDN بالتعامل مع الموجات المروريّة الكبيرة والتدفقات الفائضة bursts من خلال طلبات موازنة الحمل load عبر شبكة كبيرة موزّعة من خوادم طرفيّة. يمكنك استيعاب عدد أكبر من المستخدمين المتزامنين في البنية التحتيّة المتواجدة من خلال إلغاء التحميل offloading عن الأصل والتخزين المؤقت للمحتوى الثابت في شبكة التسليم. يمكن أن تؤدي هذه الموجة الكبيرة في حركة مرور البيانات في مواقع الويب التي تستخدم خادمًا واحدًا إلى إغراق overwhelm النظام، مما يؤدي إلى حدوث انقطاع غير متوقع وتوقف عن العمل. تؤدي عملية نقل الحمل الى شبكات CDN ذات البنية العالية التوافريّة والمتاحّية والمخصّصة للتعامل مع مستويات متعددة من حمل الإنترنت، إلى زيادة توافرية أصولك ومحتوياتك. خفض التكاليف نظرًا لأن المحتوى الثابت يمثل غالبًا معظم استخدام عرض الحزمة، يمكن أن يؤدي تفويض هذه الأصول إلى شبكة تسليم المحتوى إلى تقليل الإنفاق على البنية التحتيّة بشكل كبير. بالإضافة إلى خفض تكاليف عرض الحزمة. يمكن أن تقلل شبكة CDN تكاليف الخادم من خلال تقليل الحمل على خوادم الأصل، مما يمكّن البنية التحتيّة الحالية الخاصّة بك من التوسع. أخيرًا، يقدم بعض مزودي خدمات شبكات CDN فواتير شهرية محدّدة السعر، مما يسمح لك بتحويل استخدامك الشهري المتغيّر لعرض الحزمة إلى إنفاق متكرر ولكن متوقع. زيادة الأمن هناك حالة استخدام شائعة أخرى لـ CDNs وهي التخفيف من هجمات حجب الخدمة DDoS. يُضمّن العديد من موفري خدمات CDN ميزات لمراقبة وتصفية الطلبات على خوادم الحافّة. تقوم هذه الخدمات بتحليل حركة مرور البيانات على شبكة الإنترنت بحثًا عن الأنماط المشبوهة، ومنع حركة المرور الهجوميّة الضارّة بينما تستمر في السماح بمرور الـ trafffic الخاص بالمستخدم النظامي. عادةً ما يقدّم موفرو خدمات CDN مجموعة متنوعة من خدمات التخفيف من هجمات DDoS، بدءًا من الحماية من الهجمات الشائعة على مستوى البنية التحتيّة الأساسيّة (طبقات OSI 3 و 4)، إلى خدمات التخفيف والحد من المعدل الأكثر تقدمًا. تسمح لك معظم شبكات CDN بالإضافة إلى ذلك بتكوين كامل لبروتوكول SSL Secure Sockets Layer configure full SSL، بحيث يمكنك تشفير حركة مرور البيانات بين CDN والمستخدم النهائي، بالإضافة إلى تشفير حركة المرور بين CDN وخوادم الأصل الخاصّة بك، إما باستخدام شهادات CDN أو شهادات SSL المخصّصة. اختيار الحل الأفضل إذا كانت الغاية هي حمل وحدة المعالجة المركزية CPU على الخادم المصدر، وليس عرض الحزمة، فقد لا يكون CDN هو الحل الأنسب. قد يؤدي التخزين المؤقت المحلي local caching في هذه الحالة باستخدام وسائل التخزين الشهيرة مثل NGINX أو Varnish إلى تقليل الحمل بشكل كبير من خلال تخديم الأصول من ذاكرة النظام. قبل طرح CDN، يمكن لخطوات التحسين الإضافية - مثل تقليل وضغط ملفات JavaScript وCSS، وتمكين ضغط طلب HTTP لخادم الويب - أن يكون لها تأثيرُا كبيرًا على أوقات تحميل الصفحة واستخدام عرض الحزمة. تعتبر أداة google لتحليل سرعة الصفحات أداةً مفيدةً لقياس سرعة تحميل صفحتك وتحسينها. ويعتبرPingdom من بين الأدوات المفيدة الأخرى التي توفر تخفيضًا كبيرًا لأوقات الطلب والاستجابة إلى جانب التحسينات المقترحة. الخلاصة يمكن أن تشّكل شبكات تسليم المحتوى حلاً سريعًا وفعالًا لتحسين قابلية التوسّع وإتاحيّة مواقع الويب الخاصّة بك. يمكنك من خلال التخزين المؤقت لأصول ثابتة على شبكة موزّعة جغرافيًا من الخوادم المحسّنة تقليل أوقات تحميل الصفحات ووقت الاستجابة للمستخدمين بشكل كبير. إضافة إلى ذلك، تسمح لك شبكات CDN بتقليل استخدام عرض الحزمة بشكل كبير من خلال استيعاب طلبات المستخدمين والاستجابة لهم من ذاكرة التخزين المؤقت في الخادم الطرفي، وبالتالي تقليل تكاليف عرض الحزمة والبنية التحتيّة. يمكن لشبكات CDN باستخدام الإضافات plugin ودعم الطرف الثالث Support Third-party لمنصّات إدارة المحتوى الرئيسيّة مثل WordPress و Drupal و Django و Ruby on Rails، بالإضافة إلى الميزات الإضافيّة مثل DDoS mitigation و SSL الكامل ومراقبة المستخدمين وضغط الأصول "المحتوى"، يمكنها أن تكون أداةً مؤثرةً في تحسين مواقع الويب ذات المعدّلات العالية لحركة مرور البيانات. ترجمة وبتصرّف للمقال Using a CDN to Speed Up Static Content Delivery لصاحبه Hanif Jetha.
  5. مقدّمة إنّ TaskBoard أو "لوح المهام" هو برمجيّة مجانيّة ومفتوحة المصدر، مستوحاة من ألواح Kanban لتتبُع المهام. وألواح Kanban هي تقنية لإظهار تدفق العمل وتنظيم المشاريع. وخاصّةً في مجال تطوير البرمجيات، فهي توفّر نظامًا مرئيًّا لإدارة العمليّات للمساعدة في تحديد كيفيّة تنظيم الإنتاج. تجعل هذا البرمجيّة التتبع البصري لتطوّر مشاريعك سهلًا كما يظهر في الصورة. ميزات TaskBoard: حرّة، ومفتوحة المصدر (رخصة MIT)، وذاتيّة الاستضافة سهلة التثبيت ألواح (مشاريع) غير محدودة تخصيص الأعمدة داخل الألواح وتوسيع / تصغير مستمر من أجل كل مستخدم تسمح العناصر بالألوان المخصّصة، والتصنيفات، وتنسيق التوصيفات، والمرفقات، والتعليقات تعرض العناصر تاريخًا كاملًا "أرشيف" للأنشطة activities تعرض للمشرفين التاريخ الكامل لجميع أنشطة الألواح سهلة التخصيص تتيح إدارة أوليّة للمستخدمين (المشرف، والمستخدمين العاديين) لا وجود لتبعيّات خارجيّة إنشاء لقاعدة بيانات SQLite عند الاستخدام الأول واجهة برمجيّة RESTful API) RESTful) تبعيّات محدودة جدًا ستشرح هذه الدورة التعليميّة كيفيّة تثبيتها على CentOS 7. تثبيت خادم الويب Apache ثبّت في البداية Apache على جهاز CentOS 7 من خلال تنفيذ الأمر التالي: # yum install httpd شغّل Apache ومكّنه من التشغيل في وقت الإقلاع وذلك بمجرد انتهائك من التثبيت: # systemctl start httpd # systemctl enable httpd تثبيت PHP يجب تثبيت php باعتبار أن TaskBoard مكتوبة بهذه اللغة. ونظرًا لأنّها تتطلب الإصدار PHP الخامس أو أكثر، فسنثبّت PHP7 باستخدام مستودع Webtatic. أولاً، ثَبّت مستودع EPEL المطلوب من قبل Webtatic: # yum install epel-release حدّث: # yum install epel-release بالإمكان الآن تثبيت مستودع Webtatic عن طريق تنفيذ الأوامر التالية: # rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm # yum update ثبّت PHP 7.1 والإضافات التي تتطلبها TaskBoard وذلك بمجرّد أن يصبح المستودع جاهزًا ويصبح بالإمكان لـ yum استخدامه: # yum install php71w php71w-gd php71w-json php71-readline php71w-cli php71w-sqlite3 تثبيت SQLite يستخدم TaskBoard الـ SQLite كقاعدة بيانات، مما يعني أنه بإمكاننا استخدامه دون الحاجة إلى تثبيت MySQL أو أيّة قواعد بيانات "كبيرة" أخرى. يمكن تثبيت SQLite باستخدام أمر yum التالي: # yum install sqlite تثبيت TaskBoard إنّ تثبيت TaskBoard سهلٌ للغاية، كما هو متوقع من قائمة الميزات المطوّلة المعروضة في التمهيد. يتطلب الأمر في الواقع فقط تنزيل واستخراج أرشيف TaskBoard. انتقل إلى المسار الجذر للويب في Apache: # cd /var/www نزّل الأرشيف هنا: # wget https://github.com/kiswa/TaskBoard/archive/master.zip فُك ضغطه: # unzip master.zip سيستَخرج unzip الأرشيف إلى دليل يدعى TaskBoard-master. يمكنك إعادة تسميته (اختياري): # mv TaskBoard-master taskboard ثبّت الملحقات المطلوبة بواسطة Composer: ./taskboard/build/composer.phar install ثم غيّر مالك taskboard إلى مستخدم apache: # chown -R apache:apache /var/www/taskboard إنشاء مضيف افتراضي Virtual Host أنشئ ملف مضيف افتراضي جديد لـ TaskBoard: # $EDITOR /etc/httpd/conf.d/board.example.com.conf ثم الصق المحتوى التالي في هذا الملف: <VirtualHost *:80> ServerAdmin admin@example.com DocumentRoot "/var/www/taskboard" ServerName board.example.com ServerAlias www.board.example.com <Directory "/var/www/taskboard"> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> ErrorLog "/var/log/httpd/board.example.com-error_log" CustomLog "/var/log/httpd/board.example.com-access_log" combined </VirtualHost> أعد تشغيل Apache: # systemctl restart httpd إنهاء التثبيت للقيام بالخطوة الأخيرة لإنهاء التثبيت من خلال متصفح الويب، انتقل إلى عنوان الـ URL: http://board.example.com سجّل الدخول مستخدمًا كلمة admin في كل من اسم المستخدم وكلمة المرور على حد سواء. ثم غيّر كلمة مرور المسؤول administrator بعد تسجيلك للدخول مباشرةً وذلك بالانتقال إلى صفحة الإعدادات Settings. الخلاصة رأينا كيفيّة تثبيت TaskBoard على CentOS 7. سيُساعد بالتأكيد هذا التطبيق المعتمد على Kanban العديد من النّاس في تنظيم سير عمل مشاريعهم. ترجمة وبتصرّف للمقال TaskBoard: Kanban-based Software on CentOS 7 لصاحبه Giuseppe Molica.
  6. مقدمة إذا كنت تعمل(على الشبكة) مُستخدمًا بروتوكول النقل الآمن Secure Shell) SSH)، فإنّك تعلم مُسبقًا أنّ الجلسة session ستُغلق تلقائيًا بعد دقائقٍ قليلةٍ من عدم النشاط "الخمول"، وذلك لأسبابٍ أمنية.من الممكن في الحقيقة أن تكون قد نسيت إغلاقها، وبالتالي فقد يتمكن شخص آخر من السيطرة على نظامك. ولكن إذا كنت لا ترى في ذلك مشكلة، فبإمكانك تغيير هذا السلوك في ضبط GNU/Linux. يجب تنفيذ الأوامر التالية من عميل SSH. كيفيّة منع SSH من قطع الاتصال يجب تنفيذ الخطوات التالية في عميل SSH، وليس في الخادم البعيد. افتح محرّر النص خاصتك في البداية وعدّل ملف الـ config الحالي للمستخدم الخاص بك، والذي تجده في المسار التالي: ~/.ssh/config أضف الأسطر التالية: تأكّد من أن السطر الثاني سيبدأ بمسافة فارغة. يُخبر السطر الأول الـ SSH بتطبيق هذا الضبط على جميع المضيفات البعيدة remote hosts. كما يمكنك بالطبع تحديد واحد منها فقط، وذلك باستبدال رمز الـ "*" بالمضيف المطلوب. ستحتاج بعد الانتهاء من ذلك إلى تطبيق الإعدادات المذكورة أعلاه: sudo source ~/.ssh/config أضف أو عدّل السطر التالي في ملف etc / ssh / ssh_config/ لتطبيق هذه الإعدادات على المستوى العام globally: ServerAliveInterval 60 احفظ الملف واغلقه. وبهذه الطريقة، لن تُغلق جلسة SSH بعد الآن بسبب الخمول. الخلاصة تذكّر أن أمان نظامك، وخصوصًا في حالة الخادم server، ليس أمرًا ثانويًا، وذلك كلّه بيديك. إنّ تغيير سلوك برامج مثل SSH يجب أن يتم فقط في حال كنت تعرف بالضبط ما تريده، وبعد التأكّد من أنّ ذلك لن يضعك في مشكلةٍ ما. ترجمة وبتصرّف للمقال How to prevent SSH from disconnecting sessions لصاحبه Giuseppe Molica
  7. MySQL replication هي العمليّة التي يمكن من خلالها نسخ البيانات أوتوماتيكيًا من أحد مخدّمات قاعدة بيانات MySQL “الرئيسي” (master) إلى واحد أو أكثر من مخدّمات قواعد بيانات MySQL “التابع” (slaves). وعادةً ما تستخدم لتوزيع إمكانيّة وصول القراءة read access على مخدّمات متعددة من أجل قابلية التوسع scalability، كما يمكن أن تستخدم أيضًا لأغراض أخرى مثل تجاوز الفشل failover، أو تحليل البيانات على الـ slave من أجل عدم زيادة التحميل على الـ master. كما أنّ الـ master-slave replication هي عمليّة باتجاه واحد (من الـ master إلى slave)، تستخدم قاعدة بيانات الـ master فقط لعمليات الكتابة. بينما يمكن أن توزّع عمليات القراءة على عدّة قواعد بيانات slave. ما الذي يعنيه إذا استخدم master-slave replication كحل للتوسع، ستحتاج لأن تملك على الأقل مصدرين محدّدين للبيانات، واحد لعمليات الكتابة وآخر لعمليات القراءة. يعمل مطوّرو MySQL عادةً على جهاز واحد فقط و ويسعون لأن يكون لديهم كامل بيئة التطوير على ذلك الجهاز. مع منطق عدم الاعتماد على شبكة أو اتصال بالإنترنت. إذا كان هناك حاجة لـ master-slave replication فلأنه على سبيل المثال، يحتاجون إلى اختبار النسخ المتماثل/التكرار replication في بيئة التطوير قبل نشر التغييرات في مكان آخر، عليهم إنشاؤئه على نفس الجهاز. إن الإعداد لمثال MySQL واحد (single MySQL instance) بسيط نوعًا ما، ونحتاج لبذل بعض الجهد الإضافي لإعداد المثال الثاني، وبعدها عملية التكرار master-slave replication. للمتابعة في هذه الدرس خطوة بخطوة، اخترت Ubuntu Linux كنظام تشغيل مضيف (host). والأوامر الواردة هي من أجل هذا النظام. إذا أردت إعداد الـ MySQL master-slave replication الخاص بك على نظام تشغيل مختلف، ستكون بحاجة إلى القيام بتعديلات على هذه الأوامر. ومع ذلك ، المبادئ العامة لإعداد الـ MySQL master-slave replication على نفس الجهاز هي نفسها بالنسبة لجميع أنظمة التشغيل. تثبيت أول مثالMySQL (MySQL instance) إذا كان لديك مسبقًا مثال قاعدة بيانات MySQL واحد على جهازك، فيمكنك تجاوز هذه الخطوة. هذه أسهل طريقة لتثبيت MySQL على نظام Ubuntu وهي بتشغيل الأوامر التالية في موجّه الطرفية (terminal prompt): sudo apt-get install mysql-server خلال عملية التثبيت، ستُقاطع لوضع كلمة مرور لمستخدم root لـ MySQL. إعداد mysqld_multi من أجل إدارة مثالية لـ MuSQL على نفس الجهاز بكفاءة، نحن بحاجة إلى استخدام mysqld_multi. الخطوة الأولى في إعداد mysqld_multi هي إنشاء مجموعتي [mysqld] منفصلتين في الملف الموجود my.cnf. المكان الافتراضي لملف my.cnf في Ubuntu هو /etc/mysql/. لذلك افتح ملف my.cnf بمحرّر نصوصك المفضّل، وسمِّ مجموعة [mysqld] الموجودة إلى [mysqld1]. هذه المجموعة المسمّاة تستخدم لتكوين أول مثال MySQL وستكوّن أيضا كمثال رئيسي. كما هو الحال في MySQL master-slave replication كل مثال يجب أن يكون له server-id فريد خاص به، أضف السطر التالي في مجموعة [mysqld1]: server-id = 1 نظرًا لأننا بحاجة إلى مجموعة [mysqld]منفصلة لمثال MySQL الثاني ، انسخ المجموعة [mysqld1] مع كافة التهيئات الحالية، والصقها في ملف my.cnf نفسه. الآن، أعد تسمية المجموعة المنسوخة إلى [mysqld2]، وقم بإجراء التغييرات التالية في تكوين الـ slave: server-id = 2 port = 3307 socket = /var/run/mysqld/mysqld_slave.sock pid-file = /var/run/mysqld/mysqld_slave.pid datadir = /var/lib/mysql_slave log_error = /var/log/mysql_slave/error_slave.log relay-log = /var/log/mysql_slave/relay-bin relay-log-index = /var/log/mysql_slave/relay-bin.index master-info-file = /var/log/mysql_slave/master.info relay-log-info-file = /var/log/mysql_slave/relay-log.info read_only = 1 لإعداد مثيل MySQL الثاني كـتابع slave ، اضبط server-id إلى 2، والتي يجب أن تكون مختلفة بالنسبة لـ master’s server-id. كلا المثالين سيُشغّلان على نفس الجهاز، اضبط منفذ المثال الثاني إلى قيمة 3307 بحيث يمتلك رقم مختلف عن المنفذ الخاص بالمثال الأول، والذي يكون افتراضيًا 3306. من أجل تفعيل هذا المثال الثاني ليستخدم نفس MySQL binaries، نحتاج لضبط قيم مختلفة للـ socket، pid-file، datadir و log_error. نحن أيضًا بحاجة لتفعيل relay-log من أجل استخدام المثال الثاني كتابع (slave) (المتغيرات relay-log، relay-log-index و relay-log-info-file)، فضلًا عن تعيين master-info-file. أخيرًا، من أجل جعل المثال التابع للقراءة فقط read-only، ضبط المتغير read_only بقيمة 1. يجب أن تكون حذرًا معه فهو لا يمنع التغيرات بشكل كامل على الـ slave. حتى عندما تضبط read_only إلى 1، سيسمح للتحديثات فقط من المستخدمين الذين يملكون امتياز SUPER. أدخل MySQL المتغير الجديد super_read_only لمنع إجراء تغييرات من قبل مستخدمين الـ SUPER. هذا الخيار متوفر مع الإصدار 5.7.8. بعيدًا عن مجموعات الـ [mysqld1] و [mysqld2]، نحن بحاجة إلى إضافة مجموعة جديدة [mysqld_multi] إلى ملف my.cnf. [mysqld_multi] mysqld = /usr/bin/mysqld_safe mysqladmin = /usr/bin/mysqladmin user = multi_admin password = multipass بمجرد تثبيتنا لمثال MySQL الثاني، والقيام بتشغيلهما، سنمنح الامتيازات المناسبة للمستخدم multi_admin ليكون قادرًا على إيقاف تشغيل أمثلة MySQL. أنشئ مجلدات جديدة من أجل مثال MySQL الثاني في الخطوة السابقة قمنا بإعداد ملف التكوين من أجل مثال MySQL الثاني. في ملف التكوين هذا يتم استخدام مجلدين جديدين. يجب استخدام أوامر لينكس التالية من أجل إنشاء هذه المجلدات مع الامتيازات المناسبة: mkdir -p /var/lib/mysql_slave chmod --reference /var/lib/mysql /var/lib/mysql_slave chown --reference /var/lib/mysql /var/lib/mysql_slave mkdir -p /var/log/mysql_slave chmod --reference /var/log/mysql /var/log/mysql_slave chown --reference /var/log/mysql /var/log/mysql_slave إعدادات أمنية إضافية في AppArmor في بعض بيئات لينكس، هناك حاجة إلى إعدادات أمن AppArmor لتشغيل مثال MySQL الثاني. على الأقل هي مطلوبة في Ubuntu . لإعداد AppArmor بشكل صحيح. حرّر ملف /etc/apparmor.d/usr.sbin.mysqld بمحرّر نصوصك المفضّل، وأضف الأسطر التالية: /var/lib/mysql_slave/ r، /var/lib/mysql_slave/** rwk، /var/log/mysql_slave/ r، /var/log/mysql_slave/* rw، /var/run/mysqld/mysqld_slave.pid rw، /var/run/mysqld/mysqld_slave.sock w، /run/mysqld/mysqld_slave.pid rw، /run/mysqld/mysqld_slave.sock w، بعد أن تحفظ الملف، أعد تشغيل الجهاز حتى تصبح هذه التغييرات نافذة المفعول. تثبيت مثال MySQL الثاني يمكن اتباع عدّة نُهج مختلفة لتركيب مثال MySQL الثاني. يستخدم النهج المعروض في هذه الدورة التعليميّة نفس ثنائيات الـ MySQL كما في الأول، مع ملفات بيانات منفصلة ضرورية للتثبيت الثاني. حيث أننا قمنا بالفعل بإعداد ملف التكوين والمجلدات الضرورية والتغييرات الأمنية في الخطوات السابقة، الخطوة الأخيرة في التثبيت للمثال الثاني لـ MySQL هي تهيئة دليل بيانات MySQL. نفذ الأمر التالي من أجل تهيئة دليل بيانات MySQL جديد: mysql_install_db --user=mysql --datadir=/var/lib/mysql_slave بمجرد تهيئة دليل بيانات MySQL، يمكنك بدء كل من مثالي MySQL باستخدام الخدمة mysqld_multi. mysqld_multi start ضع كلمة سر الـ root لمثال MySQL الثاني باستخدام الـ mysqladmin مع المضيف والمنفذ المناسبين. وضع في اعتبارك ، أنه إذا تَركت المنفذ والمضيف دون تحديد، سيتصل mysqladmin بأول مثال MySQL افتراضيًا. mysqladmin --host=127.0.0.1 --port=3307 -u root password rootpwd في المثال الذي في الأعلى قم بوضع “rootpwd” ككلمة سر، ولكن يستحسن استخدام كلمة سر أكثر أمنًا. تهيئة إضافية لـ mysqld_multi في نهاية قسم " إعداد mysqld_multi، كتبت أننا سنقدم امتيازات مناسبة للمستخدم multi_admin في وقت لاحق، والآن حان الوقت لذلك. نحن بحاجة إلى منح امتيازات هذا المستخدم في كلا المثالين، لذلك دعونا أولًا نقوم بالاتصال بالمثال الأول: mysql --host=127.0.0.1 --port=3306 -uroot -p عند تسجيلك الدخول، نفّذ الأمرين التاليين: mysql> GRANT SHUTDOWN ON *.* TO 'multi_admin'@'localhost' IDENTIFIED BY 'multipass'; mysql> FLUSH PRIVILEGES; اخرج من MySQL client، وقم بالاتصال بالمثال الثاني: mysql --host=127.0.0.1 --port=3307 -uroot -p عند تسجيلك الدخول، نفّذ نفس الأمرين كما في الأعلى: mysql> GRANT SHUTDOWN ON *.* TO 'multi_admin'@'localhost' IDENTIFIED BY 'multipass'; mysql> FLUSH PRIVILEGES; اخرج من MySQL client. بدء كل من مثالي MySQL أوتوماتيكيًا عند الإقلاع الخطوة الأخيرة في إعداد mysqld_multi هي التثبيت لسكريبت الإقلاع الأتوماتيكي في الـ init.d. لفعل ذلك، أنشئ ملف جديد سمّه mysqld_multi في /etc/init.d، وامنحه الامتيازات المناسبة: cd /etc/init.d touch mysqld_multi chmod +x /etc/init.d/mysqld_multi افتح هذا الملف الجديد بمحرّر نصوصك المفضل، وانسخ السكريبت التالي: #!/bin/sh ### BEGIN INIT INFO # Provides: scriptname # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start daemon at boot time # Description: Enable service provided by daemon. ### END INIT INFO bindir=/usr/bin if test -x $bindir/mysqld_multi then mysqld_multi="$bindir/mysqld_multi"; else echo "Can't execute $bindir/mysqld_multi"; exit; fi case "$1" in 'start' ) "$mysqld_multi" start $2 ;; 'stop' ) "$mysqld_multi" stop $2 ;; 'report' ) "$mysqld_multi" report $2 ;; 'restart' ) "$mysqld_multi" stop $2 "$mysqld_multi" start $2 ;; *) echo "Usage: $0 {start|stop|report|restart}" >&2 ;; esac أضف خدمة mysqld_multi لـ runlevels الافتراضي بالأمر التالي: update-rc.d mysqld_multi defaults أعد تشغيل جهازك، وتحقق من أن كلا مثالي MySQL قيد التشغيل باستخدام الأمر التالي: mysqld_multi report إعداد Setup master-slave replication الآن، عندما يكون لدينا مثالي MySQL قيد التشغيل على نفس الجهاز، نقوم بإعداد المثال الأول كـ master، والثاني كـ slave. تم القيام بجزء واحد من التكوين configuration مسبقا في فصل “إعداد mysqld_multi”. التغيير الوحيد المتبقي في الملف my.cnf هو ضبط binary logging على الـ master. لفعل ذلك، حرّر ملف my.cnf مع التغيرات التالية والإضافات في المجموعة [mysqld1]: log_bin = /var/log/mysql/mysql-bin.log innodb_flush_log_at_trx_commit = 1 sync_binlog = 1 binlog-format = ROW أعد تشغيل مثال MySQL الرئيسي (master MySQL instance) لتأخذ التغيرات مفعولها: mysqld_multi stop 1 mysqld_multi start 1 من أجل اتصال الـ slave بالـ master بامتيازات تكرار replication مناسبة، يجب أن ينشأ المستخدم الجديد في الـ Master. اتصل بمثال maste باستخدام الـ MySQL clien مع المضيف والمنفذ المناسبين: mysql -uroot -p --host=127.0.0.1 --port=3306 أنشئ مستخدم جديد من أجل التكرار replication: mysql> CREATE USER 'replication'@'%' IDENTIFIED BY 'replication'; mysql> GRANT REPLICATION SLAVE ON *.* TO 'replication'@'%'; اخرج من MySQL client. نفّذ الأمر التالي من أجل إنشاء ملف نسخ احتياطي (dump) لبيانات الـ master: mysqldump -uroot -p --host=127.0.0.1 --port=3306 --all-databases --master-data=2 > replicationdump.sql هنا استخدمنا الخيار --master-data=2 من أجل الحصول على تعليق يحتوي على عبارة CHANGE MASTER داخل ملف النسخ الاحتياطي، ذاك التعليق يشير الى إحداثيات الـ replication في وقت النسخ الاحتياطي، وسنحتاج هذه الإحداثيات لاحقًا لتحديث معلومات الـ master في مثال الـ slave. وهنا مثال لهذا التعليق: -- -- Position to start replication or point-in-time recovery from -- -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001'، MASTER_LOG_POS=349; استورد dump الذي أنشأته في الخطوة السابقة ضمن مثال الـ slave. mysql -uroot -p --host=127.0.0.1 --port=3307 < replicationdump.sql أخيرًا، من أجل اتصال مثال الـ slave بمثال الـ master، يجب تحديث معلومات الـ master في الـ slave مع متغيرات الاتصال المناسبة. اتصل بمثال الـ slave باستخدام MySQL clien مع المضيف والمنفذ المناسبين: mysql -uroot -p --host=127.0.0.1 --port=3307 نفّذ الأمر التالي لتحديث معلومات الـ master (خُذ احداثيات التكرار replication من ملف (dump) replicationdump.sql، كما شُرح سابقًا): mysql> CHANGE MASTER TO -> MASTER_HOST='127.0.0.1'، -> MASTER_USER='replication'، -> MASTER_PASSWORD='replication'، -> MASTER_LOG_FILE='mysql-bin.000001'، -> MASTER_LOG_POS=349; نفذ الأمر التالي من أجل تشغيل الـ slave: mysql> START SLAVE; نفذ الأمر التالي للتأكد من أن replication قيد التشغيل: mysql> SHOW SLAVE STATUS \G تهانينا. تم إعداد MySQL master-slave replication على نفس الجهاز لديك بنجاح. خاتمة وجود النسخ المتماثل master-slave مهيئًا في بيئة التطوير الخاصة بك مفيد إذا كنت بحاجة لحل للتوسع في بيئة الإنتاج. بهذه الطريقة، سيكون لديك مصادر بيانات منفصلة مُهيئة لعمليات الكتابة والقراءة وبذلك تكون قادرًا على اختبار أن كل شيء يعمل محلياً كما هو متوقع قبل النشر. بالإضافة إلى ذلك، قد تحتاج إلى تكوينات أمثلة slave على نفس الجهاز لاختبار موازن الحمل الذي يوزّع عمليات القراءة إلى عدد من الـ slave. في هذه الحالة، يمكنك استخدام هذه الطريقة لإعداد أمثلة أخرى بتكرار كل الخطوات السابقة نفسها. ترجمة -وبتصرّف- للمقال MySQL Master-Slave Replication on the Same Machine لصاحبه Ivan Bojovic
  8. من الممكن أن تكون المعايرة مهمّة صعبة جدًا، وخاصّة عند العمل مع بيانات ضخمة، حيث أنّ أصغر تغيير من الممكن أن يتسبب بتغيرات غير متوقعه ( إيجابية أو سلبية) على الأداء ككل. تتم معظم عمليات معايرة SQl database في الشركات المتوسطة والصغيرة من قبل مدير قاعدة البيانات (Database Administrator (DBA، لكن صدقني، يوجد العديد من المطوّرين بحاجة للقيام بعمليات متعلقة بالإدارة، وأكثر من ذلك أنا شاهدت أنّهم يقومون فعليًّا بعمليات الإدارة في كثير من الشركات التي تتطلع للعمل مع المطوّرين، حين يتطلب الوضع ببساطة تقنيات مختلفة لحل المشاكل، والتي يمكن أن تؤدي إلى خلاف بين زملاء العمل. عند التعامل مع بيانات ضخمة، فإنّ التغيير الصغير قد يؤدي إلى تغيرات غير متوقعة على الأداء. وبناء على ذلك، فإنّ هيكلية الشبكة أيضًا لها تأثير، افترض أن فريق الإدارة DBA team مع قواعد البيانات التي يديرونها يتوضع في الطابق العاشر، بينما يتوضع المطوّرين في الطابق الخامس عشر، أو حتى في بناء مختلف تحت هيكلية منفصلة تمامًا، وبالتالي من الصعب العمل المشترك بينهم بمرونة تحت هذه الظروف، سأقوم بإتمام شيئين هامين في هذه المقالة: تزويد المطوّرين بتقنيات معايرة لقواعد بيانات خاصة بالمطوّرين. شرح كيف يمكن لمطوّري ومديري قواعد البيانات العمل معًا بكفاءة. تحسين قاعدة البيانات (في Codebase) الفهارس إذا كنت حديثًا في مجال قواعد البيانات أو حتى تسأل نفسك، “ماهي معايرة SQL”، فيجب أن تعلم أنّ الفهرسة هي طريقة فعّالة لمعايرة قاعدة البيانات database SQL الخاصة بك، والتي غالبًا ما يتم إهمالها خلال عملية التطوير، كمصطلح أولي: الفهرس index هو هيكلة للبيانات تسمح بتسريع عملية استخلاص هذه البيانات من جدول قاعدة البيانات، عن طريق تأمين عمليات بحث عشوائية سريعة، وطريقة فعّالة للوصول إلى السجلات المرتبة، هذا يعني أنّه حالما تقوم بإنشاء فهرس يمكنك القيام بعمليات الاستعلام والترتيب بشكل أسرع. تستخدم الفهارس أيضًا لتعريف المفتاح الرئيسي أو فهرس فريد يضمن أنّ أي عمود آخر لن يحتوي نفس القيمة. بالطبع إنّ موضوع الفهرسة متنوع وهام ولا يمكنني إعطاءه حقه في هذا الوصف الموجز. إذا كنت حديثًا على موضوع الفهرسة فأنا أفضل أن تستخدم هذا المخطط لهيكلة استعلاماتك. بشكل أولي، الهدف هو فهرسة أعمدة البحث والترتيب. لاحظ أنه إذا كانت تجري بشكل مستمر عمليات إدخال INSERT أو تعديل UPDATE أو حذف DELETE، فيجب عليك الحذر من القيام بعمليات الفهرسة، حيث يمكن أن يؤدي إلى هبوط في الأداء، إذ أنّه يتطلب تعديل جميع الفهارس بعد هذه العمليات. كذلك مديري قواعد البيانات يقومون بحذف الفهارس قبل القيام مثلًا بإدخال أكثر من مليون سجل دفعة واحدة، وذلك لتسريع عملية الإدخال، ثم يقومون بإعادة إنشاء الفهارس بعد انتهاء الإدخال، تذكر على أية حال أن حذف الفهارس يؤثر على كافة الاستعلامات على الجداول، لذلك هذه الطريقة محبذة فقط عند عملية إدخال واحدة ضخمة للبيانات. معايرة أداء SQL Server: خطط التنفيذ بالمناسبة، أداة خطة التنفيذ في SQL Server مفيدة لإنشاء الفهارس. مهمتها الأساسية تتمثل في الإظهار المرئي لطرق تحصيل البيانات المختارة من قبل منسق استعلام SQL Server. للحصول على خطة التنفيذ (في برنامج الإدارة SQL Server Management Studio)، قم فقط بالنقر على Include Actual Execution Plan" CTRL + M" قبل بدء تشغيل الاستعلام. بعدئذ ،سوف يظهر إطار ثالث اسمه “Execution Plan”، حيث يمكن أن تشاهد اكتشاف فهرس مفقود، ولإنشائه قم بالنقر بالزر اليميني على execution plan وقم باختيار Missing Index Details، بكل بساطة. معايرة استعلام SQL عن طريق تجنب حلقات الشفرة تخيّل سيناريو يقوم فيه 1000 استعلام بإضافة بيانات على قاعدة بياناتك بشكل تسلسلي، كالتالي: for (int i = 0; i < 1000; i++) { SqlCommand cmd = new SqlCommand("INSERT INTO TBL (A,B,C) VALUES..."); cmd.ExecuteNonQuery(); } يجب عليك تجنب مثل هذه الحلقات في شفرتك، وكمثال سنقوم بتحويل باستخدام العبارات الفريدة INSERT UPDATE مع أسطر وقيم عدّة. INSERT INTO TableName (A,B,C) VALUES (1,2,3),(4,5,6),(7,8,9) -- SQL SERVER 2008 INSERT INTO TableName (A,B,C) SELECT 1,2,3 UNION ALL SELECT 4,5,6 -- SQL SERVER 2005 UPDATE TableName SET A = CASE B WHEN 1 THEN 'NEW VALUE' WHEN 2 THEN 'NEW VALUE 2' WHEN 3 THEN 'NEW VALUE 3' END WHERE B in (1,2,3) تأكد من أن عبارة تتجنب تحديث القيم المخزنة إذا كانت تتطابق مع القيمة الموجودة. مثل هذه يمكن أن تحسّن أداء الاستعلام بشكل كبير عن طريق تعديل مئات السجلات بدل الآلاف وكمثال: UPDATE TableName SET A = @VALUE WHERE B = 'YOUR CONDITION' AND A <> @VALUE -- VALIDATION تجنّب الاستعلامات الفرعيّة المرتبطة Correlated Subqueries الاستعلامات المرتبطة هي الاستعلامات التي تستخدم قيم من الاستعلام الأب، هذه النوع من الاستعلامات ينحو إلى العمل سجل بعد سجل row-by-row، مرة لكل سجل معاد من الاستعلام الخارجي الأب، ولذلك فإنه ينقص أداء استعلام SQl. المطوّرين الحديثين غالبًا ما يبنون استعلاماتهم على هذه الشاكلة لأنها عادة الطريقة الأسهل. هنا تجد مثال عن الاستعلامات المرتبطة: SELECT c.Name, c.City, (SELECT CompanyName FROM Company WHERE ID = c.CompanyID) AS CompanyName FROM Customer c بشكل خاص، المشكلة تكون بأن الاستعلام الداخلي(...SELECT CompanyName) ينفذ لكل سجل مسترجع من الاستعلام الخارجي (...SELECT c.Name)، لكن لماذا العودة إلى مرّة ثم أخرى في كل مرة يعالج فيها سجل من الاستعلام الخارجي؟ التقنية الافضل لمعايرة الأداء تكون بمعاملة الاستعلام الفرعي كعملية ربط join SELECT c.Name, c.City, co.CompanyName FROM Customer c LEFT JOIN Company co ON c.CompanyID = co.CompanyID وبهذه الحالة نقوم بالمرور على جدول Company مرة واحدة ، نربطه بجدول Customer، وعندها يمكننا الحصول على القيم التي نريدها (co.CompanyName) بشكل أفضل. الاختيار باعتدال Select Sparingly واحدة من أهم نصائح المعايرة هو تجنب استخدام تعليمة SELECT * . وبدلًا من ذلك يجب تحديد الأعمدة التي تحتاجها فقط مره ثانية. هذا الأمر بسيط، لكن هذا الخطأ منتشر، افترض جدولًا بمئات الأعمدة وملايين السجلات فإذا كان تطبيقك يحتاج إلى عدد محدّد من الأعمدة فقط، فلا حاجة لاستجلاب جميع البيانات، لأن ذلك تضييع للمصادر كمثال: SELECT * FROM Employees مقابل SELECT FirstName, City, Country FROM Employees إذا كنت بالفعل تحتاج إلى كل الأعمدة ، قم بتسميتهم ضمن الاستعلام، هذه ليست قاعدة، لكنها طريقة للمعايرة و لتجنب الأخطاء المستقبلية. كمثال إذا كنت تستخدم التعليمة INSERT... ...SELECT وتم تغيير الجدول عن طريق إضافة عمود جديد، عندها ربما تقع في مشكلة إذا كان هذا العمود غير مطلوبًا في الجدول الهدف وكمثال: INSERT INTO Employees SELECT * FROM OldEmployees Msg 213, Level 16, State 1, Line 1 Insert Error: Column name or number of supplied values does not match table definition ولتجنب هذا الخطأ عليك تسمية كل عمود بشكل مستقل. INSERT INTO Employees (FirstName, City, Country) SELECT Name, CityName, CountryName FROM OldEmployees ملاحظة: على أية حال، هنالك بعض الحالات يكون فيها استخدام SELECT مناسبًا، كمثال من أجل الجداول المؤقتة، وهذا يقودنا الى الفقرة التالية. استخدام الجداول المؤقتة Temporary Tables الجداول المؤقتة عادة ما تزيد تعقيد الاستعلام، فإذا كان بالإمكان كتابة شيفرتك بطريقة بسيطة ومباشرة، فأنا أنصحك بتجنب الجداول المؤقتة. لكن إذا كنت تمتلك إجرائية مخزّنة stored procedure مع عمليات تعديل على البيانات لا يمكن إتمامها باستعلام واحد ، يمكنك استخدام الجداول المؤقتة كوسيط لمساعدتك في تحصيل النتائج النهائية. عندما تودّ أن تقوم بعملية ضم جدول ضخم وهنالك قيود على الجدول المذكور، يمكنك تحسين أداء قاعدة البيانات عن طريق ترحيل البيانات الى جدول مؤقت، والقيام بعملية ضم ذلك الجدول، حيث ان الجدول المؤقت يحتوي على سجلات أقل من الجدول الأساسي الضخم، ولذلك ستتم عملية الضم بشكل أسرع. القرار ليس واضح بشكل دائم، ولكن هذا المثال سوف ينبهك للحالات التي يمكنك فيها استخدام الجداول المؤقتة. تخيّل جدول الزبائن بملايين من السجلات، وعليك أن تقوم بعملية الضم لمنطقة محدّدة، يمكنك القيام بذلك عن طريق استخدام SELECT INTO ،والقيام بعملية الضم مع الجدول المؤقت. SELECT * INTO #Temp FROM Customer WHERE RegionID = 5 SELECT r.RegionName, t.Name FROM Region r JOIN #Temp t ON t.RegionID = r.RegionID لاحظ : مطوري SQl أيضًا يتجنبون استخدام SELECT INTO لإنشاء الجداول المؤقتة، لأن هذا الأمر يؤدي إلى قفل قاعدة بيانات tempdb database مما يمنع باقي المستخدمين من إنشاء جداول مؤقتة ، ولحسن الحظ تم التصحيح في النسخة السابعة وما بعدها. وكحل بديل عن استخدام الجداول المؤقتة يمكن استخدام الاستعلام الفرعي كجدول. SELECT r.RegionName, t.Name FROM Region r JOIN (SELECT * FROM Customer WHERE RegionID = 5) AS t ON t.RegionID = r.RegionID لكن انتظر، هنالك مشكلة في الاستعلام الثاني، كما تم شرحه أعلاه، يجب تضمين الأعمدة التي نحتاجها فقط (عدم استخدام * SELECT )، يجب أخذ هذا الأمر بالحسبان SELECT r.RegionName, t.Name FROM Region r JOIN (SELECT Name, RegionID FROM Customer WHERE RegionID = 5) AS t ON t.RegionID = r.RegionID كل هذه الطرق ستعيد نفس البيانات، لكن باستخدام الجداول المؤقتة، وكمثال يمكننا انشاء فهرس في جدول مؤقت لتحسين الأداء. وأخيرًا، عندما تنهي عملك بالجدول المؤقت، قم بحذفه لتنظيف مصادر tempdb بدل أن تنتظر عملية الحذف الاوتوماتيكي (عندما يتم إنهاء اتصالك مع قاعدة البيانات) DROP TABLE #temp هل يتواجد السجل الخاص بي؟ تقنية المعايرة هذه الخاصة ب SQl متعلقة باستخدام التعليمة ()EXISTS إذا كنت تنوي تفحص فيما إذا كان السجل موجودًا استخدم ()EXISTS بدل من ()COUNT. حيث أن ()COUNT يقوم بفحص كامل الجدول، معتبرًا جميع القيم التي تطابق شروطك، بينما ()EXISTS ستوقف الفحص حالما تجد قيمة مطابقة لما تحتاجه. وهذا يفضي إلى أداء أفضل و شفرة أوضح IF (SELECT COUNT(1) FROM EMPLOYEES WHERE FIRSTNAME LIKE '%JOHN%') > 0 PRINT 'YES' مقابل IF EXISTS(SELECT FIRSTNAME FROM EMPLOYEES WHERE FIRSTNAME LIKE '%JOHN%') PRINT 'YES' معايرة قاعدة البيانات (في المكتب) مديري ومطوري قاعدة البيانات غالبًا ما يتجادلون فيما إذا كانت القضايا التي يواجهونها متعلقة أو غير متعلقة بالبيانات. ومن خبرتي الشخصية أقدم هنا مجموعة من النصائح لكليهما كي يتمكنا من العمل بشكل أكثر فاعلية. للمطوّرين: إذا توقف تطبيقك عن العمل فجأة، فقد لايكون الأمر متعلقًا بقاعدة البيانات، كمثال ربما هنالك مشكلة بالشبكة، قم بالتحقق قليلًا قبل أن ترجع السبب إلى مدير قاعدة البيانات. حتى ولو كنت بارعًا في نمذجة بيانات SQl، قم بطلب المساعدة من مدير قاعدة البيانات في المخطط العلائقي relational diagram فلديه الكثير ليقدمه لك. مديري قاعدة البيانات لا يحبون التغيرات السريعة، هذا طبيعي، عليهم تحليل قاعدة البيانات بشكل كامل واكتشاف مدى تأثير أي تغيير من كافة الزوايا. تغيير بسيط في عمود يمكن أن يستغرق اسبوعًا للإنجاز هذا بسبب أن الخطأ قد يعتبر خسارة ضخمة للشركة. كن صبورًا! لا تقم بالطلب من مدير قاعدة بيانات SQL بإجراء تغييرات على البيانات في بيئة العمل وقت التشغيل. إذا كنت تود الوصول الى قاعدة البيانات النشطة، يجب عليك تحمل المسؤولية عن كافة التغيرات. لمديري قاعدة بيانات SQl: إذا كنت لا تحب أن يسألك النّاس بشأن قاعدة البيانات، قم بتزويدهم بلوحة تبيّن الحالة وقت التشغيل. فالمطوّرين عادة لديهم شك بحالة قاعدة البيانات، وهذه اللوحة تساعد في توفير الوقت والجهد للجميع. ساعد المطوّرين في اختبارات ضمان الجودة للبيئة. قم بتسهيل عملية محاكاة عمل المخدّم مع اختبار بسيط على بيانات حقيقية. مما يوفر الوقت بشكل كبير عليك وعليهم. يقضي المطوّرين كل اليوم متعاملين مع أنظمة بمفاهيم عمل تتغير بشكل مستمر. تفهمك لذلك يجعل الأمر أكثر مرونة، ويمكنك من تجاوز بعض القواعد في اللحظات الحرجة. قواعد البيانات تتطور، سيأتي اليوم الذي تحتاج فيه إلى نقل بياناتك الى إصدار جديد، حيث يعتمد المطوّرين على خصائص جديدة في كل إصدار جديد، لذلك خطط و تحسب لعملية النقل بدلًا من أن تقوم برفض هذه التغيرات. ترجمة -وبتصرّف- للمقال SQL-Database-Performance-Tuning-for-Developers لصاحبه Rodrigo Koch حقوق خلفية الصورة البارزة Gradient clouds background محفوظة لـ Vexels
  9. مقدمة إنّ azk عبارة عن أداة خفيفة مفتوحة المصدر، تستطيع استخدامها لتنسيق بيئات التطبيقات. هل سبق أن كان لديك تطبيق يعمل على محطة العمل المحليّة الخاصة بك، ووجدت أنّ الإعدادات تختلف كليًا عندما تقوم بنشر التطبيق على مخدّم إنّتاج. تُقدّم هذه المقالة أداة تنسيق، تُدعى azk، والتي يتم استخدامها حاليًا من قبل هذه التطبيقات، وهي قابلة للاستخدام لأكثر من ذلك بكثير. عندما تقوم بنشر تطبيق جاهز للعمل مع azk، فإنّه يمكنك بسهولة إنّ تشغلّه محليًا أو في مخدّم إنّتاج. لا يجعل azk تشغيل التطبيق فقط سهلًا و سريعًا بل كل تبعياته أيضًا، بما فيها نظام التشغيل المطلوب، اللغات، أطر العمل، قواعد البيانات و التبعيات الأخرى (المهام الثقيلة، الطويلة، التكرارية، الأكثر عرضة للخطأ)، سواء كنت تعمل في بيئة محلية أو على مخدم. إنّ غرض هذه المقالة، هو إظهار كيف يعمل azk كأداة تنسيق، باستخدام تطبيق Rails بسيط يُدعى Stringer كمثال. يهتم azk بالعديد من التفاصيل خلف الكواليس، لجعل عملية التنسيق أسهل. لهذا، تحوي هذه المقالة على العديد من الخطوات الاختيارية، التي ليست بضرورية لإعداد التطبيق المثال، ولكنها تشرح آلية عمل azk. سوف نقوم بتشغيل التطبيق من شفرة المصدر على جهاز حاسوب محلي، ثم نشره على مخدّم، و من ثم سنقوم ببعض التغييرات المحليّة، وبعدها نقوم بنشر هذه التغييرات، و من ثم سنقوم بعميلة الإرجاع. بعد إتمام هذه المقالة، سوق تحصل على فكرة جيدة حول كيفية عمل azk كأداة تنسيق سير عملية التطوير والنشر الخاصة بك. كيف يعمل؟ بدايةً، يُنسق azk بيئة التطبيق على جهاز الحاسب المحلي الخاص بك. حالما يعمل التطبيق لديك محليًا، سيقوم azk أيضًا بتنسيق نشره إلى المخدّم Droplet الخاص بك. طالما يُشغل azk التطبيقات من شفرة المصدر، فإنّك تستطيع أن تعمل مع التطبيق محليًا (إذا كنت ترغب بذلك)، و من ثم تقوم بنشره أو استرجاعه مرة ثانية بدون أيّة خطوات إضافية خاصة. يعزل azk البيئات التي تستخدم الحاويات، ولهذا فمن الآمن تشغيل التطبيقات على جهاز الحاسب المحلي الخاص بك. يعمل azk مع كل من المشاريع الجديدة، تلك التي تبدأ منذ الصفر، أو مع الشيفرات الموجودة سابقًا. استخدام azk مع تطبيقات مخصّصة باستخدام القائمة الحالية من التطبيقات التي تم تشكيلها مسبقًا للعمل مع azk كأمثلة، و مع قليل من العمل الإضافي ستستطيع إعداد أي مشروع للعمل مع azk. للقيام بهذا أضف الملف Azkfile إلى مشروعك. Azkfile عبارة عن ملف رئيسي manifest، يحتوي العناصر الضرورية لتشغيل التطبيق، و يقوم بتلخيص علاقاتها فيما بينها (نظام التشغيل، اللغات، قواعد البيانات، … ). فوائد إضافة الملف Azkfile إلى مشروعك: استخدام azk لأتمته إعداد البيئة لمشروعك محليًا و عند النشر. يستطيع الأشخاص الأخرين، الذين يرغبون بنشر تطبيقك، القيام بهذا باستخدام azk. المتطلبات الأساسية للمتابعة مع هذه المقالة، فإنّك ستحتاج إلى جهاز حاسوب يقوم بتشغيل أية من أنظمة التشغيل التالية(64 - بت) للبيئة المحليّة الخاصة بك: Mac OS X 10.6 (Snow Leopard) أو أي إصدار لاحق. Ubuntu 12.04، 14.04 or 15.10 Fedora 21 or 22 أيضاً ستحتاج إلى إنّ تكون قادر على تشكيل git commits. يحتاج جهاز حاسوبك إلى تثبيت Git. إنّظر إلى هذه السلسلة لاستخدام Git من أجل التعليمات الخاصة لأنظمة التشغيل Linux، أو قم بزيارة صفحة تحميل Git. تأكّد من قيامك بتشغيل الأوامر المقترحة : git config --global user.email "you@example.com" git config --global user.name "Your Name" وذلك قبل القيام بقراءة المقالة، انظر الروابط السابقة للحصول على التفاصيل حول Git. لاحظ أنّه لا يوجد ضرورة للحصول على مخدّم فعّال Droplet في هذا الدرس. سيقوم azk بتشكيل واحد باستخدام واجهة التطبيق DigitalOcean’s API. يُكلف نشر مخدم Droplet المال، ومن أجل هذا الدرس ستقوم بنشر مخدم Droplet، يحوي افتراضيًا فقط واحد جيجابايت. مستخدمي Linux : تثبيت الـ Docker: إذا كنت تستخدم نظام تشغيل ( Linux Ubuntu أو Fedora)، ستحتاج لتثبيت الـ 1.8.1 Docker أو أي اصدار لاحق، وذلك لاستخدامه كبرمجية حاويّة. إنّ تشغيل سكريبت تثبيت Docker، هي إحدى طرق تثبيته. (بشكل عام، كُن متأكد من فهمك ماذا يفعل السكريبت، وذلك قبل القيام بتشغيله): $ wget -nv https://get.docker.com/ -O- -t 2 -T 10 | bash إذا كنت ترغب بتعلّم المزيد حول تثبيت Docker في نظام التشغيل Linux، تفحّص تعليمات التثبيت المتاحة في ملفات التوثيق الرسمية. مستخدمي Mac OS X : تثبيت الـ VirtualBox: ستحتاج إلى VirtualBox 4.3.6 أو أي اصدار لاحق، وذلك لاستخدامه كبرمجيّة حاويّة. لتثبيت VirtualBox، حمّل رزمة تثبيت Virtualbox المناسبة من صفحة التحميل الرسميّة. الخطوة الأولى: تثبيت azk محليًا سنقوم بتثبيت azk، باستخدام سكريبت تثبيت المشروع. تأكد من فهمك ماذا يفعل أي سكريبت، قبل تنفيذه في نظامك. إذا كان لديك للتو نسخة قديمة مثبتة من azk، فإنّك تستطيع استخدام سكريبت التثبيت لتحديث الـ azk. وإلا قُم بتفحص إرشادات تثبيت الحزم لنظم التشغيل المدعومة. تثبيت azk على Linux: إذا كنت تستخدم نظام التشغيل (Linux Ubuntu أوFedora)، قُم بتشغيل هذا الأمر في الوحدة الطرفية، وذلك لتثبيت azk باستخدام سكريبت المشروع. نحن ننصح بتدقيق أي سكريبت قبل تشغيله على نظامك: $ wget -nv http://azk.io/install.sh -O- -t 2 -T 10 | bash بعد إتمام التثبيت، قُم بتسجيل الخروج، ومن ثم تسجيل الدخول مرة أخرى، وذلك لجعل كل التعديلات فعّالة. يتجلى سبب تسجيل الخروج، في أنّه خلال عملية التثبيت، سيتم إضافة مستخدمك إلى مجموعة الـ docker. تُعد هذه الخطوة مطلوبة، وبذلك نستطيع استخدام الـ Docker بدون أن تكون المستخدم الأساسي (root). أي عليك الخروج من الجلسة الحالية، لتحصل على كل التعديلات المضافة. إذا كنت ترغب بتعلم المزيد حول مجموعة الـ Docker، فإنّك تستطيع تفحص التوثيق الرسمي لـ Docker. تثبيت azk على Mac OS X: قُم بتشغيل الأمر التالي في الوحدة الطرفية، وذلك لتثبيت azk باستخدام سكريبت المشروع. نحن ننصح بتدقيق أي سكريبت قبل تشغيله على نظامك: $ curl -sSL http://www.azk.io/install.sh | bash الخطوة الثانية: التحقق من تثبيت azk حالما يصبح تثبيت azk كامل، قُم بتشغيل الأمر الذي في الأسفل، وذلك للتحقق من نجاح عملية التثبيت: $ azk version يتحقق هذا الأمر من نسخة الـ azk المثبّتة. إذا أعاد هذا الأمر رقم النسخة (على سبيل المثال azk 0.17.0 أو أي إصدار لاحق)، فالوضع جيد و تستطيع الانتقال إلى الخطوة التالية. تهانينا لك على تثبيت azk في البيئة المحليّة الخاصة بك. إذا لم يكن الأمر كذلك، فاقرأ أدناه أحد أقسام تحرّي الأخطاء وإصلاحها للحصول على المساعدة. استكشاف الأخطاء وإصلاحها في عملية تثبيت azk في Linux: دعونا نتفحص نسخة الـ Docker المثبّتة، وذلك عن طريق تشغيل الأمر: $ docker version ستحتاج إلى الإصدار 1.8.1 أو أحدث. على كل حال، إذا حصلت على رسالة خطأ، فهذا يعني لم تحصل حتى الآن على تثبيت Docker، تتبع إرشادات التثبيت الخاصة بنظام التشغيل في ملفات توثيق Docker. بعد قيامك من التأكد من حصولك على النسخة المثبّتة المناسبة من Docker، قُم بتشغيل الأمر التالي كمستخدم sudo و ذلك للتأكد من أنّ مستخدمك في مجموعة docker: $ id -Gn إذا كانت قائمة المجموعات تتضمن docker، هذا يعني أنه تم إعداده بشكل صحيح. و إلا، إذا لم تحصل على الكلمة docker في قائمة المجموعات، قُم بتشغيل هذا الأمر لإضافة مستخدمك إلى المجموعة: $ sudo usermod -aG docker $USER ومن ثم قُم بتسجيل الخروج، و تسجل الدخول مرة أخرى. تحقق من الأمر id –Gn مرة أخرى للتأكد من أنّه يُعيد قائمة المجموعات مع كلمة docker بينهم. إذا كانت هذه الإرشادات غير كافية لجعل الـ Docker يعمل بالشكل المناسب (على سبيل المثال، لا تزال غير قادر على تشغيل أمر docker version بشكل صحيح)، يّرجى الرجوع إلى تعليمات تثبيت Docker. استكشاف الأخطاء وإصلاحها في عملية تثبيت azk في Mac OS X: تأكّد من تثبيت VirtualBox $ which VBoxManage إذا كان هذا يُعيد مسار ملف (مثل، usr/local/bin/VboxManage/)، فنستطيع المضي قُدمًا. و إلا، إذا كان يُعيد رسالة " not found "، هذا يعني ليس لديك تثبيت VirtualBox. في هذه الحالة، قُم بتحميل و تثبيت رزمة تثبيت VirtualBox من الموقع الرسمي لهم. الخطوة الثالثة (اختيارية): التعلّم حول التطبيق التجريبي Stringer لقد قُمنا باختيار Stringer كتطبيق تجريبي لهذه المقالة، وذلك لأنه تطبيق بسيط، وتم إعداده للعمل مع azk. وهو عبارة عن تطبيق Rails مع حالة استخدام محددة جيدًا: قارئ RSS أساسي. المزيد حول Stringer تُقدم بعض مواقع الأخبار أيضًا محتواها في صيغة تغذية RSS. هذه عبارة عن صيغة ملف XML قياسية، تُمكن الناشرين من نشر المعطيات بشكل اتوماتيكي. قارئ RSS هو عبارة عن برنامج مُستخدم للاشتراك، وتقديم محتوى الـ RSS. تُزيل عملية الاشتراك في تغذية RSS لموقع ما، حاجة المستخدمين للتفحص اليدوي للموقع للحصول على المحتوى الجديد. حيث يستطيع المستخدمين تشكيل قائمة بالتغذيات المُشترك فيها، وتخصيص محتواهم على قارئ RSS (عادةً على شكل قائمة مرتبة ترتيبًا زمنيًا) الخطوة الرابعة (اختيارية): إعداد تطبيق مُخصّص لاستخدام azk طالما أنّ التركيز الأساسي لهذه المقالة هو على إظهار كيفية عمل azk للتطبيقات، التي تملك للتو تفاصيل البيئة المنصوص عليها للعمل مع azk، فعلى المدى الطويل هذه الأداة، هي أكثر فائدة عندما يمكنك استخدامها لنشر أي تطبيق. لهذا، خُذ نظرة عن كيفية مقارنة هذه النسخة من Stringer مع النسخة الأساسية من Stringer في المستودع. تملك نسخة azk فقط إضافتين اثنتين إلى نسخة Stringer الأصلية: ملف Azkfile، الذي يزّود بمعلومات البيئة لـ azk زر azk لتشغيل المشروع Run Project يمكن تعلم المزيد حول جعل azk يعمل مع تطبيقات أخرى، وذلك عن طريق ملفات توثيق azk حول ملف Azkfile و زر تشغيل المشروع Run Project. تالياً، سوف نرى كيف يبدو التطبيق الصديق لـ azk في GitHub. الخطوة الخامسة (اختيارية): استخدام زر تشغيل المشروع لـ azk على GitHub إنّ جزء الممارسات الأفضل من azk من أجل مشاريع GitHub، هو التوضيح الجيد لكيفيّة عمل هذا المشروع مع azk. لهذا، بدلاً من إظهار فقط أمر الـ azk في وسط ملف readme للمشروع، فإنّ المشروع الذي يستخدم azk يستطيع استخدام زر تشغيل المشروع، وذلك للعزل البصري لأمر الـ azk. يستخدم Stringer هذا الزر. قُم بزيارة قسم التشغيل المحلي لنسخة azk المتشعبة من Stringer. أضغط زر تشغيل المشروع Run Project. في أول مرة تضغط فيها زر تشغيل المشروع، سوف ترى شرح بسيط عن ماذا يجري. عندما تصبح جاهزا للمضي قُدماً، انقر على الزر OK، DISMISS في أسفل الشرح. بعدها سيتم توجيهك إلى صفحة مع أمر azk لمشروع Stringer. $ azk start -o run-project/stringer يمكنك دائماً أنّ تنقر على إشارة ما هذا؟ على الزاوية العليا اليُمنى، وذلك لترى الشرح مرّة أخرى. في مركز الشاشة، يوجد صندوق أوامر مع ثلاث علامات تبويب: curl، wget، azk. طالما لدينا للتو مُثبت azk فتستطيع استخدام علامة التبويب azk. هذا هو الأمر، الذي سنستخدمه في الخطوة التالية للتشغيل الفعلي لـ Stringer. الخطوة السادسة: تشغيل Stringer محليًا في هذا القسم سنستخدم azk لتشغيل Stringer على محطّة العمل المحليّة. دعونا نتأكد أنّنا في المسار الرئيسي home على جهاز حاسوبنا المحلي (إذا قمت باستخدام مجلد تثبيت مختلف، تذكر فقط تغيير الأوامر إلى مسارك المختار): $ cd ~ أمضي قُدمًا، و قم بتشغيل الأمر التالي على حاسوبك المحلي، وذلك لتشغيل Stringer: $ azk start -o run-project/stringer طالما هذه هي أول مره تقوم بها بتشغيل azk، سيطلب منك قبول بنود الخدمة. و يجب أنّ تظهر رسالة كالتالية: ? ========================================================================= Thank you for using azk! Welcome! Before we start، we need to ask: do you accept our Terms of Use? http://docs.azk.io/en/terms-of-use ========================================================================= (Y/n) اضغط على Y إذا كنت موافق أو N إذا كنت غير موافق. و من ثم اضغط على ENTER لتأكيد جوابك. في حالة عدم موافقتك، فلن تتمكن من استخدام azk. و اخيراً، سيقوم azk أوتوماتيكيًا بتحميل الشفرة المصدر لـ Stringer، إضافة إلى أنّ الملف المسند Azkfile سيقوم بتشغيل هذا الشفرة في بيئة معزولة و آمنة في حاسوبك المحلي. ومن ثم سيتم سؤالك فيما إذا كنت ترغب ببداية تشغيل عميل الـ azk. ? The agent is not running، would you like to start it? (Y/n) العميل هو عبارة عن مُركب azk، الذي يقوم بإعداد Docker (على نظام التشغيل Linux )، أو بإعداد الآلة الافتراضيّة VirtualBox (على نظام التشغيل Mac OS X). اضغط ENTER للجواب “Yes” (الخيار الافتراضي). في أول مرة تُشغل فيها العميل، سيقوم azk بتشغيل إعداداته. يقوم الإعداد بالعديد من الأشياء وراء الكواليس، بما في ذلك توليد الملف /etc/resolver/dev.azk.io، الذي يحوي إعدادات نظام أسماء النطاقات DNS، لتصميم العناوين التي تنتهي باللاحقة dev.azk.io. يستخدم azk هذه اللاحقة عند تشغيل التطبيقات لاستخدام العناوين القابلة للقراءة بدلاً من الاستخدام اليدوي للعناوين من الشكل http://localhost:PORT_NUMBER . أيضاً هذا يقوم بتجنب تعارض أرقام المنافذ بين التطبيقات المختلفة. بشكل أساسي يقوم هذا بنفس الشيء عند تحرير ملفك /etc/hosts لإعادة توجيه اسم نطاق محليًا. إذا حصلت على رسالة من الشكل التالي: ? Enter the vm ip: (192.168.50.4) فإنّك تستطيع إدخال أي عنون IP محلي، ترغب بتشغيل التطبيق عليه. يجب أن تكون الحالة الافتراضية مناسبة لجميع الحالات. للموافقة على هذا، فقط اضغط ENTER. لإتمام إعدادات عميل الـ azk، سيتم سؤالك عن كلمة المرور الخاصة بالمستخدم sudo (لمستخدمي نظام التشغيل Mac OS X، هي عبارة عن كلمة مرور المُشرف admin). الآن سيبدأ azk بالعمل. سوف ترى أنّ azk يُحمّل العناصر المُسردة في الملف Azkfile (على صيغة صور Docker ). من الممكن أن يستغرق تحميل هذه الصور أول مرة عدة دقائق (حوالي 10 دقائق أو أقل). حالما يُكمل azk الإعداد، سيقوم مُتصفحك بشكل أتوماتيكي بتحميل شاشة البدء لـ Stringer على حاسوبك المحلي. كما تستطيع إنّ ترى، أنّه يستخدم اسم نطاق محلي DNS، و هذا التطبيق مرئي على http://stringer.dev.azk.io. و تستطيع الوصول إلى التطبيق بشكل يدوي عبر الذهاب إلى http://stringer.dev.azk.io . إذا كنت ترغب بإعداد كلمة المرور و بداية التشغيل باستخدام التطبيق، فإنّك تستطيع فعل ذلك. نحن نرغب فقط برؤية أنّ azk يستطيع تشغيل Stringer محلياً. والآن طالما لديك Stringer يعمل على الحاسوب المحلي، فتستطيع نشره من جهاز الحاسوب لديك إلى المخدّم Droplet. الخطوة السابعة: الحصول على الرمز DigitalOcean API Token قبل أن نتمكن من نشر Droplet من azk، فإنّنا نحتاج إلى رمز API token. يُعطي هذا الرمز الإذن لـ azk لنشر مخدّم جديد على حسابك. في أول مرّة تقوم بها بتشغيل azk من هذه البيئة باستخدام هذا الرمز، سيتم نشر واحد جيجابايت مخدّم جديد Ubuntu 14.04 Droplet . و ستستخدم عمليات النشر اللاحقة من نفس البيئة المحليّة، نفس المخدّم المفرد Droplet. اتّبع الإرشادات من قسم المراجع المرتبطة بالمقالة حول كيفية تشكيل رمز الوصول الشخصي. و يجب أن يمتلك الرمز المُشكّل تصاريح الكتابة القراءة. قُم بنسخ المحارف الأربعة و الستين بالترميز الست عشري لرمزك، بشكل مشابه للتالي: Example API Token A17d6a72566200ad1a8f4e090209fe1841d77d7c85223f769e8c5de47475a726 سوف ترى هذا الرمز النصيّ فقط مرة واحدة، لذلك قُم بنسخه إلى مكان آمن. (تذكّر، إذا تم اختراق هذا الرمز، فإنّه يمكن استخدامه للدخول إلى حسابك، لذلك حافظ عليه خاصًا). من أجل الإرشادات أسفلا، تذكر استبدال الرمز المثال بالرمز الحقيقي الخاص بك. اذهب إلى مجلد Stringer: $ cd ~/stringer احفظ رمز الوصول الشخصي في ملف ستدعوه env. للقيام بهذا، قُم بتشغيل أمر تشكيل ملف (لا تنسى استبدال الرمز): $ echo "DEPLOY_API_TOKEN=a17d6a72566200ad1a8f4e090209fe1841d77d7c85223f769e8c5de47475a726" >> .env يجب إنّ يبدو محتوى الملف env. بالشكل التالي: DEPLOY_API_TOKEN=a17d6a72566200ad1a8f4e090209fe1841d77d7c85223f769e8c5de47475a726 الخطوة الثامنة (اختيارية): التعلم حول مفاتيح SSH ليس عليك إنّ تقوم بأي شيء لإعداد مفتاح SSH من أجل azk، ولكن من المفيد معرفة الكيفية التي يستخدم فيها azk هذا المفتاح. يستخدم azk مفتاح SSH للوصول إلى المخدّم Droplet. إذا كان لديك للتو مفتاح SSH، فإنّ azk سيستخدمه. لرؤية فيما إذا كان لديك مفتاح SSH على جهاز الحاسوب لديك، شغّل: $ ls ~/.ssh/*.pub إذا قام بإرجاع رسالة “not found”، فهذا يعني إنّه ليس لديك أيّة مفاتيح SSH على جهاز الحاسوب. في هذه الحالة، سيولّد azk بشكل أتوماتيكي مفتاح SSH جديد، ليتم استخدامه حصريًا لنشر أي تطبيق جديد من جهاز الحاسوب لديك. سيقوم azk بتوليد مفتاحه في الذاكرة المحجوزة له، ولن يقوم بأيّة تعديلات على مسارك ~/.ssh. إذا كنت ترغب بتفحص المفتاح العام المولّد، يمكنك تشغيل الأمر التالي بعد نشر التطبيق الأول: $ azk deploy shell -c "cat /azk/deploy/.config/ssh/*.pub" الخطوة التاسعة: النشر مع azk بشكل افتراضي، سيولد azk مخدّم DigitalOcean Droplet واحد جيجابايت، يُشغّل النظام Ubuntu 14.04، وذلك من أجل نشر تطبيقك. إذا كنت ترغب بنشر Droplet بمواصفات مختلفة، فيمكنك تغيير الإعدادات في خصائص envs لنظام deploy في الملف Azkfile.js . من أجل الإرشادات الإضافية أشر إلى ملفات توثيق حول نشر azk . أولاً، اذهب إلى مسار Stringer ( أو إلى مسار تطبيقك): $ cd ~/stringer ومن ثم، ابدأ عملية النشر، فقط قُم بتشغيل: $ azk deploy إنّ الأمر azk deploy، هو الأمر الذي ستقوم بتشغيله معظم الأوقات، عندما تستخدم azk لتنسيق تطبيقك. من الممكن أن تستغرق أول عملية نشر فترة معينة (حوالي عشر دقائق)، حتى يقوم azk بكل العمل. بشكل مخصص، على azk القيام بما يلي: تحميل عناصر الدعم ( صورة Docker للنشر) تشكيل و إعداد الـ Droplet رفع شفرة المصدر للتطبيق إلى المخدّم Droplet تشغيل التطبيق بعدها ستستغرق كل عملية نشر جديده لهذا التطبيق من جهاز الحاسوب لديك مدة زمنية قليلة (حوالي 30 ثانية أو أقل)، هذا لان معظم الخطوات الطويلة جاهزة للتو. إذا كان مفتاحك SSH محمي بكلمة مرور، فسيكون مطلوباً وقت أكبر لعملية النشر. فقط قُم بكتابة كلمة المرور للمفتاح SSH، و أضغط زر ENTER في كل مرة تظهر رسالة كالتالية: Output Enter passphrase for ~/.ssh/id_rsa: سيظهر خرج الوحدة الطرفية بعض الإجراءات المُتخذة على النظام البعيد، تنتهي برسالة النشر الناجحة App successfully deployed at http://your_server_ip. قُم بزيارة الموقع http://your_server_ip لعرض التطبيق المُستضاف على الخادم الخاص بك. من الآن، يُمكنك تغيير شفرة التطبيق على جهاز الحاسوب الخاص بك، و يمكنك اختباره محلياً، و يمكنك نشر التغييرات على المخدّم Droplet بواسطة الأمر azk deploy. الخطوة العاشرة: تعديل Stringer لتوضيح سهولة استخدام azk لنشر تطبيق، للتخصيص، أو للتحكم في النسخة، دعونا نقوم بعدد من التغييرات على صفحة الاشتراك Stringer، و من ثم نقوم بإعادة نشر التطبيق. تأكد من كونك على مسار Stringer: $ cd ~/stringer دعونا نقوم بتعديل الملف app/views/first_run/password.erb، الذي هو عبارة عن الصفحة الحاوية على النص لصفحة الاشتراك الأولى. استخدم nano أو محرر النصوص المفضل لديك: $ nano ~/stringer/app/views/first_run/password.erb هنا نقوم بإضافة السطر الإضافي، الذي يقول "! It’s easy with azk ": app/views/first_run/password.erb <div class="setup" id="password-setup"> <h1><%= t('first_run.password.title') %> <span class="orange"> <%= t('first_run.password.anti_social') %></span>.</h1> <h2><%= t('first_run.password.subtitle') %></h2> <h2>It's easy with azk!</h2> <hr /> . . . </div> قُم بالحفظ و الخروج من محرر النصوص. إذا كنت تستخدم nano، اضغط CTRL+O للحفظ، و CTRL+X للخروج. طالما إنّ Stringer مُعد افتراضياً للعمل في وضع الانتاج، لذلك فإنّ إعادة تحديث صفحة المتصفح ليس بكافٍ لتشغيل التغييرات. بل قُم بإعادة تشغيل التطبيق من azk: $ azk restart stringer -o يجب على علامة التبويب الجديدة للمتصفح أن تفتح النسخة الجديدة من Stringer. أسفل النص الافتراضي مباشرةً “There is only one user: you”، يجب الآن أن يكتب “!It’s easy with azk”. الخطوة الحادية عشر: إعادة نشر Stringer الآن، دعونا نُودع (commit) التغييرات داخل نسخة نظام التحكم، من أجل أن نستطيع نشرها. $ git add app/views/first_run/password.erb $ git commit . سيظهر لك محرر نصوص (على الأرجح nano أو vim). أدخل رسالة إيداع commit، مثل It is easy with azk. سيتم استخدام هذه الرسالة commit لتسمية الإصدارات من تطبيقك داخل azk، لذلك اختر الرسالة التي من شأنها تحفيز ذاكرتك، إذا كنت بحاجة إلى الرجوع إليها في وقت لاحق. احفظ و أغلق رسالة الـ commit. إذا حصلت على الخطأ : fatal: empty ident name (for <sammy@azk.(none)>) not allowed عندها قُم بتشغيل أوامر الإعدادات المقترحة من أجل Git لإعداد عنوان إيميل و اسم (المزيد من التفاصيل في قسم المتطلبات الأساسية). لنشر تغييراتك و رفع تشغيل التطبيق على Droplet، قُم بتشغيل: $ azk deploy بعد الانتهاء من ذلك، قُم بالوصول إلى عنوان IP لـ Droplet من متصفحك (مثلاً http://your_server_ip) .عندها يجب أن ترى أيضاً هنا السطر الجديد !It’s easy with azk سيقوم هذا النشر الجديد بتشكيل نسخة جديدة من التطبيق على Droplet. إنّ كل نسخ التطبيق مخزنة، لذلك يمكنك العودة إلى نسخة سابقة ومن ثم إلى الأمام مرّة أخرى. الخطوة الثانية عشر: الرجوع إلى خطوة سابقة للحصول على كل النسخ المتاحة من تطبيقنا على Droplet، شغّل الأمر التالي محليًا: $ azk deploy versions يجب إنّ تكون النتيجة بقائمة من الشكل: Output ⇲ Retrieving deployed versions... ➜ v2 It is easy with azk v1 Merge branch 'master' of https://github.com/swanson/stringer لإرجاع التطبيق إلى نسخة أقدم، فقط قوم بتشغيل: $ azk deploy rollback v1 إنّ المعامل v1 عبارة عن رقم النسخة، الذي يظهر على خرج الأمر azk deploy versions. إذا قمت بتشغيل الأمر بدون هذا المعامل (مثلاً، . azk deploy rollback )، سيرجع عندها التطبيق إلى نسخة سابقة تماماً قبل النسخة الحالية. لتفحص إتمام عملية الرجوع، فقط قُم بتحديث علامة تبويب المتصفح، التي تظهر نسخة المخدم. الآن عليك إنّ ترى التطبيق بدون النص الذي قمنا بإدخاله، أي يجب أن ترى النسخة الأصليّة من التطبيق. وإذا كنت ترغب بالرجوع للأمام، يمكنك اختيار النسخة الأحدث: $ azk deploy rollback v2 أتت التسمية لهذه النسخ من رسائل الـ git commit في الخطوة السابقة. الخاتمة في هذا الدليل التعليمي، لقد استخدمنا تطبيق Rails بسيط، لتوضيح كيف يقوم azk بأتمتة مهام إعداد بيئة تطبيقنا. يجعل هذا من السهل نشر التطبيق نفسه في عدة بيئات. إذا أعجبت بعملية النشر من azk، خُذ بعين الاعتبار استخدامه لمشروعك الخاص، أو إضافة الملف Azkfile إلى fork مشروع أخر مفتوح المصدر. يدعم azk بالإضافة إلى عملية rollback و versions، غيرها من الأوامر الفرعيّة المساعدة، التي تسمح لنا بإنّجاز بعض الإجرائيات الإضافية (مثلاً، الوصول إلى Droplet’s shell عن طريق المفتاح SSH ). ترجمة -وبتصرّف- للمقال How To Deploy a Rails App with azk لصاحبه Felipe Arenales
  10. يشرح هذا المقال +PHP 5. يجب أن تكون شفرة PHP مغلقة بوسوم php?> ومن الأفضل عمليًا تجاهل وسم الإغلاق إذا كان ملف php يحتوي على شفرة php فقط، لتلافي نتيجة خرج غير متوقعة. // استخدم علامة القوسين المائلين // لبدأ تعليق بسطر واحد // يمكن استخدام العلامة # لكن علامة // أكثر شيوعيا. /* إحاطة نص بالقوس المائل متبوعا بالنجمة بداية وبالنجمة متبوعة بالقوس المائل نهاية يجعل من هذا النص تعليقا متعدد الأسطر */ استخدم "echo" أو "print" لطباعة الخرج. print('Hello '); // بدون سطر فاصل "Hello " طباعة استخدام القوسين ( ) اختياري مع تعليمتي echo و print echo "World\n"; // مع سطر فاصل "World" طباعة كل العبارات يجب أنت تنتهي بالفاصلة المنقوطة ";" وأي شيء مكتوب خارج وسوم php?> ستتم طباعته على الشاشة بشكل تلقائي. الأنماط Types والمتغيرات Variables تبدأ المتغيرات بالرمز $ أسماء المتغيرات المقبولة تبدأ بحرف أو تسطيرة سفلية متبوعة بأي عدد من الأحرف، الأرقام أو التسطيرة السفلية. والمتغيرات المنطقية حساسة لحالة الأحرف. $boolean = true; // TRUE أو True $boolean = false; // FALSE أو False الأعداد الصحيحة $int1 = 12; // => 12 $int2 = -12; // => -12 $int3 = 012; // => 10 (البادئة 0 تدل على عدد ثماني) $int4 = 0x0F; // => 15 (0x تدل على رقم ستة عشري) المحارف الصحيحة الثنائية متاحة اعتبارًا من PHP 5.4.0 $int5 = 0b11111111; // 255 (0b يدل على عدد ثنائي) الأرقام العائمة Floats أو (المضاعفة doubles) $float = 1.234; $float = 1.2e3; $float = 7E-10; حذف متغير unset($int1); رياضيات $sum = 1 + 1; // 2 $difference = 2 - 1; // 1 $product = 2 * 2; // 4 $quotient = 2 / 1; // 2 رياضيات مختزلة $number = 0; $number += 1; // بمقدار 1 $number زيادة echo $number++; // (طباعة 1 (الزيادة بعد التقييم echo ++$number; // (طباعة 3 (الزيادة قبل التقييم $number /= $float; // $number قسمة واسناد ناتج القسمة إلى النصوص يجب أن تكون محدودة ضمن إشارة تنصيص واحدة(’) من كل جانب $sgl_quotes = '$String'; // => '$String' تجنب استخدام علامات التنصيص المزدوجة إلا في حالة تضمين متغيرات أخرى $dbl_quotes = "This is a $sgl_quotes."; // => 'This is a $String.' المحارف الخاصة تحدد حصريًا باقتباسات مزدوجة $escaped = "This contains a \t tab character."; $unescaped = 'This just contains a slash and a t: \t'; قم بإحاطة المتغيرات بالقوسين المائلين عند الحاجة $apples = "I have {$number} apples to eat."; $oranges = "I have ${number} oranges to eat."; $money = "I have $${number} in the bank."; منذ الإصدار الخامس يمكن استخدام nowdocs في حالة عدة أسطر غير مجمعة $nowdoc = <<<'END' Multi line string END; ستقوم heredocs بتجميع النصوص $heredoc = <<<END Multi line $sgl_quotes END; وصل النصوص يتم باستخدام النقطة "." echo 'This string ' . 'is concatenated'; يمكن تمرير النصوص كبارامتر لـ echo echo 'Multiple', 'Parameters', 'Valid';// 'MultipleParametersValid' يعيد الثوابت يعرّف الثابت باستخدام ()define ولا يمكن تغيير قيمته خلال فترة التشغيل. ويجب أن تبدأ أسماء الثوابت الصحيحة بحرف أو تسطيرة سفلية, متبوعة بأية حروف أو أرقام أو تسطيرات سفلية. define("FOO", "something"); الوصول إلى المتغير الثابت متاح دون الحاجة الى استخدام الرمز $ echo FOO; // 'something' يعيد echo 'This outputs ' . FOO; // 'This outputs something' يعيد المصفوفات Arrays كل المصفوفات في PHP هي مصفوفات مترابطة (hashmaps في بعض اللغات البرمجية) وتعمل في جميع اصدارات php $associative = array('One' => 1, 'Two' => 2, 'Three' => 3); تم إدخال تركيب قواعدي syntax جديد في PHP 5.4 $associative = ['One' => 1, 'Two' => 2, 'Three' => 3]; echo $associative['One']; // 1 تطبع إضافة عنصر للمصفوفة المترابطة $associative['Four'] = 4; القوائم المحرفية يسند لها مفاتيح صحيحة حكمًا $array = ['One', 'Two', 'Three']; echo $array[0]; // => "One" إضافة عنصر إلى نهاية المصفوفة $array[] = 'Four'; أو array_push($array, 'Five'); حذف عنصر من مصفوفة unset($array[3]); الخرج Output echo('Hello World!'); طباعة !Hello World على شاشة الاظهار القياسية stdout، وstdout هي صفحة الوب إذا كنت تستخدم متصفحًا print('Hello World!'); // echo مشابه لـ // هي أيضًا من تركيبات اللغة لذلك يمكنك إلغاء الأقواس echo و print echo 'Hello World!'; print 'Hello World!'; $paragraph = 'paragraph'; echo 100; // اطبع المتغيرات العددية مباشرة echo $paragraph; // أو المتغيرات إذا تم إعداد الوسوم القصيرة المفتوحة أو كانت نسخة PHP الخاصة بك 5.4.0 أو أحدث يمكنك استخدام قواعد بناء الجمل القصيرة لـ echo <p><?= $paragraph ?></p> $x = 1; $y = 2; $x = $y; المتغير x$ يحتوي نفس قيمة المتغير y$ $z = &$y; المتغير z$ يحتوي إسناد إلى قيمة y$، وأي تغيير في قيمة z$سيغير قيمة y$ وبالعكس المتغير x$ تبقى قيمته بدون تغيير كقيمة y$ الأصلية echo $x; // => 2 echo $z; // => 2 $y = 0; echo $x; // => 2 echo $z; // => 0 التفريغات Dumps تخرج نوع وقيمة المتحول إلى شاشة العرض القياسية stdout var_dump($z); // int(0) يطبع Print تطبع المتغيرات إلى شاشة الإظهار القياسية stdout بصيغة مقروءة للإنسان print_r($array); // Array ( [0] => One [1] => Two [2] => Three ) يطبع العمليات المنطقية $a = 0; $b = '0'; $c = '1'; $d = '1'; يقوم assert بإصدار تنبيه إذا كانت معطياته غير صحيحة وهذه المقارنة ستكون دومًا صحيحة حتى إذا كانت الأنواع مختلفة assert($a == $b); // equality المساواة assert($c != $a); // inequality عدم المساواة assert($c <> $a); // alternative inequality عدم المساواة بشكل بديل assert($a < $c); assert($c > $b); assert($a <= $b); assert($c >= $d); التالي سيكون صحيحًا فقط في حال كانت القيم متساوية ومن نفس النوع assert($c === $d); assert($a !== $d); assert(1 === '1'); assert(1 !== '1'); المشغل `Spaceship` <=> (منذ PHP 7) يعيد 0 إذا كانت القيم على طرفيه متساوية، ويعيد 1 إذا كانت القيمة على اليسار أكبر، ويعيد -1 إذا كانت القيمة على اليمين أكبر $a = 100; $b = 1000; echo $a <=> $a; // النتيجة 0 كونهما متساويين echo $a <=> $b; // $a < $b النتيجة -1 كون echo $b <=> $a; // $b > $aالنتيجة 1 كون يمكن تحويل المتغيرات إلى أنواع مختلفة بحسب استخدامها $integer = 1; echo $integer + $integer; // => 2 $string = '1'; echo $string + $string; // => 2 (تم تحويل النصوص الى أعداد صحيحة) $string = 'one'; echo $string + $string; // => 0 النتيجة 0 لأن المشغل + لا يستطيع موائمة النص `one` الى رقم. موائمة الأنواع Type casting يمكن استخدامها للتعامل مع متغير من نوع معين كنوع آخر. $boolean = (boolean) 1; // => true $zero = 0; $boolean = (boolean) $zero; // => false يوجد أيضًا توابع مخصصة لموائمة أغلب الأنواع $integer = 5; $string = strval($integer); null هي قيمة خالية $var = null; Control Structures بنى التحكم if (true) { print 'I get printed'; } if (false) { print 'I don\'t'; } else { print 'I get printed'; } if (false) { print 'Does not get printed'; } elseif (true) { print 'Does'; } المشغل الثلاثي ternary print (false ? 'Does not get printed' : 'Does'); المشغل الثلاثي المختصر بدأ من PHP 5.3 وهو مكافئ لـ "$x ? $x : 'Does'"" $x = false; print($x ?: 'Does'); مشغّل دمج القيم الفارغة null coalesce operator بدأ من php 7 $a = null; $b = 'Does print'; echo $a ?? 'a is not set'; // 'a is not set' تطبع echo $b ?? 'b is not set'; // 'Does print' تطبع $x = 0; if ($x === '0') { print 'Does not print'; } elseif ($x == '1') { print 'Does not print'; } else { print 'Does print'; } القواعد البديلة لبناء الجمل مفيدة لبناء النماذج <?php if ($x): ?> This is displayed if the test is truthy. <?php else: ?> This is displayed otherwise. <?php endif; ?> استخدم switch لتوفير قسط من العمليات المنطقية switch ($x) { case '0': print 'Switch does type coercion'; break; // 'two' و'three' وإلا سينتقل الى الحالة break يجب تضمين case 'two': case 'three': // 'two' أو 'three' تساوي $variable قم بعمل شيء ما اذا كانت قيمة break; default: // قم بعمل الاجراء الافتراضي } الحلقات while، do…while، for هي حلقات مألوفة غالبًا $i = 0; while ($i < 5) { echo $i++; } // "01234" اطبع $i = 0; do { echo $i++; } while ($i < 5); // "01234" اطبع for ($x = 0; $x < 10; $x++) { echo $x; } // "0123456789" اطبع $wheels = ['bicycle' => 2, 'car' => 4]; حلقات foreach يمكن أن تعمل على المصفوفة foreach ($wheels as $wheel_count) { echo $wheel_count; } // "24"اطبع يمكنك التكرار فوق المفاتيح أو القيم foreach ($wheels as $vehicle => $wheel_count) { echo "A $vehicle has $wheel_count wheels"; } $i = 0; while ($i < 5) { if ($i === 3) { break; // while اخرج من حلقة } echo $i++; } // "012" اطبع for ($i = 0; $i < 5; $i++) { if ($i === 3) { continue; // تجاوز هذا التكرار من الحلقة } echo $i; } // "0124" اطبع الدوال Functions عرّف الدالة باستخدام function function my_function () { return 'Hello'; } echo my_function(); // => "Hello" الاسم المقبول للدالة يبدأ بحرف أو تسطيرة سفلية متبوعة بأي عدد من الأحرف ،الأرقام، أو التسطيرات السفلية function add ($x, $y = 1) { // اختيارية وقيمتها الإفتراضية تساوي 1 $y $result = $x + $y; return $result; } echo add(4); // => 5 echo add(4, 2); // => 6 المتغير result$ لا يمكن الوصول إليه من خارج الدالة واستخدام الأمر ;print $result سيعطي خطأ منذ النسخة PHP 5.3 يمكنك تعريف دوال مجهولة anonymous functions $inc = function ($x) { return $x + 1; }; echo $inc(2); // => 3 function foo ($x, $y, $z) { echo "$x - $y - $z"; } يمكن للدوال أن تعيد دوالًا أخرى function bar ($x, $y) { // استخدم use لإحضار المتغيرات الخارجية return function ($z) use ($x, $y) { foo($x, $y, $z); }; } $bar = bar('A', 'B'); $bar('C'); // "A - B - C" يطبع يمكنك استدعاء الدوال المسماة named functions باستخدام النصوص $function_name = 'add'; echo $function_name(1, 2); // => 3 وهو هام من أجل تحديد أي دالة يتوجب تشغيلها برمجيًا، أو استخدم الدالة التالية call_user_func (callable $callback [, $parameter [, … ]]); يمكنك الحصول على كل البارمترات الممررّة للدالة function parameters() { $numargs = func_num_args(); if ($numargs > 0) { echo func_get_arg(0) . ' | '; } $args_array = func_get_args(); foreach ($args_array as $key => $arg) { echo $key . ' - ' . $arg . ' | '; } } parameters('Hello', 'World'); // Hello | 0 - Hello | 1 - World | يمكنك الحصول على عدد متغير من المعطيات ابتداء من PHP 5.6 function variable($word, ...$list) { echo $word . " || "; foreach ($list as $item) { echo $item . ' | '; } } variable("Separate", "Hello", "World"); // Separate || Hello | World | التضمين includes يجب أيضًا وضع وسم البداية لـ PHP في الملفات المتضمنة include 'my-file.php'; وبهذا تكون الشفرة ضمن الملف my-file.php متاحة ضمن مجال الرؤية، إذا لم يكن بالإمكان تضمين الملف (وكمثال الملف غير موجود )، يظهر تنبيه. include_once 'my-file.php'; إذا كانت شفرة الملف my-file.php متضمنة في مكان أخر ، لن يتم تضمينها ثانية. وهذا يمنع الاخطاء التي تحدث بسبب تكرار التصريح عن الصفوف require 'my-file.php'; require_once 'my-file.php'; الدالة ()require تقوم بنفس عمل ()include إلا أنه سيتسبب بخطأ فادح إذا لم يتمكن من تضمين الملف. محتويات ملف my-include.php <?php return 'Anything you like.'; الدوال Includes، requires يمكن أيضًا أن تعيد قيمة $value = include 'my-include.php'; يتم تضمين الملفات بالاعتماد على المسار المعطى، وإذا لم يحدد المسار يتم اعتماد مسار توجيه الاعداد include_path فإذا لم يتم إيجاد الملف يتم البحث في مسار استدعاء السكريبت ومسار العمل الحالي قبل الاعلان عن الاخفاق Classes الأصناف يتم تعريف الأصناف باستخدام العبارة class class MyClass { const MY_CONST = 'value'; // ثابت static $staticVar = 'static'; المتغيرات الثابتة Static ومجال رؤيتها public static $publicStaticVar = 'publicStatic'; يمكن الوصول إليها خلال الصنف فقط private static $privateStaticVar = 'privateStatic'; يمكن الوصول اليها من خلال الصنف والأصناف المشتقة protected static $protectedStaticVar = 'protectedStatic'; يجب تحديد مجال الرؤية للخصائص Properties public $property = 'public'; public $instanceProp; protected $prot = 'protected'; يمكن الوصول إليها من الصنف والأصناف الفرعية private $priv = 'private'; // يمكن الوصول إليها من الصنف فقط قم بإنشاء الباني باستخدام __construct public function __construct($instanceProp) { // $this قم بالوصول إلى متغيرات الحالة باستخدام $this->instanceProp = $instanceProp; } الطرق Methods تعرًف كدوال داخل الصنف public function myMethod() { print 'MyClass'; } الكلمة المفتاحية final تجعل الدالة غير قابلة للتحميل الزائد unoverridable final function youCannotOverrideMe() { } طرق سحرية Magic Methods ماذا تفعل إذا تمت معاملة العنصر كنص (سلسلة) public function __toString() { return $property; } ()destruct__ هو عكس الباني ()construct__ ويستدعى عندما لا تعود هنالك حاجة لأن يكون العنصر مشارًا إليه كمرجع public function __destruct() { print "Destroying"; } تعريف خصائص الصنف والطرق كثابت يجعلها قابله للوصول بدون الحاجة إلى تجسيد الصنف. الخاصية المعرّفة بأنها ثابتة لا يمكن الوصول إليها من العنصر المشتق من الصنف (لكن يمكن ذلك في الطرق الثابتة) public static function myStaticMethod() { print 'I am static'; } ثوابت الصنف Class constants يمكن الوصول إليها دائمًا بشكل ثابت echo MyClass::MY_CONST; // 'value' الخرج; echo MyClass::$staticVar; // 'static' الخرج; MyClass::myStaticMethod(); // 'I am static' الخرج; اشتقاق حالات الأصناف instance باستخدام new $my_class = new MyClass('An instance property'); استخدام القوسين اختياري إذا كنت لا تريد تمرير أيّة معطيات يمكننك الوصول إلى أعضاء الصنف class members باستخدام <- echo $my_class->property; // => "public" echo $my_class->instanceProp; // => "An instance property" $my_class->myMethod(); // => "MyClass" قم بتوسيع الصنف باستخدام extends class MyOtherClass extends MyClass { function printProtectedProperty() { echo $this->prot; } // التحميل الزائد للطرق Override function myMethod() { parent::myMethod(); print ' > MyOtherClass'; } } $my_other_class = new MyOtherClass('Instance prop'); $my_other_class->printProtectedProperty(); // => "protected" يطبع $my_other_class->myMethod(); // "MyClass > MyOtherClass" يطبع final class YouCannotExtendMe { } يمكنك استخدام "magic methods" لإنشاء دوال الارجاع getters والاسناد setters class MyMapClass { private $property; public function __get($key) { return $this->$key; } public function __set($key, $value) { $this->$key = $value; } } $x = new MyMapClass(); echo $x->property; // __get() سوف تستخدم طريقة $x->property = 'Something'; // __set() سوف تستخدم طريقة يمكن أن تكون الأصناف تجريدية (باستخدام الكلمة المفتاحية abstract) أو واجهات تنفيذ (باستخدام الكلمة المفتاحية implements). يصرح عن الواجهة بالكلمة المفتاحية interface. interface InterfaceOne { public function doSomething(); } interface InterfaceTwo { public function doSomethingElse(); } يمكن أن توسّع الواجهات interface InterfaceThree extends InterfaceTwo { public function doAnotherContract(); } abstract class MyAbstractClass implements InterfaceOne { public $x = 'doSomething'; } class MyConcreteClass extends MyAbstractClass implements InterfaceTwo { public function doSomething() { echo $x; } public function doSomethingElse() { echo 'doSomethingElse'; } } يمكن أن يكون للأصناف أكثر من واجهة واحدة class SomeOtherClass implements InterfaceOne, InterfaceTwo { public function doSomething() { echo 'doSomething'; } public function doSomethingElse() { echo 'doSomethingElse'; } } Traits السمات trait متوفرة بدءًا من النسخة PHP 5.4.0 ويصرّح عنها باستخدام trait trait MyTrait { public function myTraitMethod() { print 'I have MyTrait'; } } class MyTraitfulClass { use MyTrait; } $cls = new MyTraitfulClass(); $cls->myTraitMethod(); // Prints "I have MyTrait" Namespaces هذا مقطع منفصل, لأن التصريح عن namespace يجب أن يكون أول عبارة في الملف. دعونا نتظاهر بأن هذا ليس هو الحال <?php افتراضيًا, توجد الأصناف في namespace عام, ويمكن أن تستدعى صراحة بـ backslash $cls = new \MyClass(); ضبط namespace لملف namespace My\Namespace; class MyClass { } من ملف آخر $cls = new My\Namespace\MyClass; أو من داخل namespace آخر namespace My\Other\Namespace; use My\Namespace\MyClass; $cls = new MyClass(); أو يمكنك استبدال namespace باسم مستعار namespace My\Other\Namespace; use My\Namespace as SomeOtherNamespace; $cls = new SomeOtherNamespace\MyClass(); Late Static Binding الربط الساكن المتأخر class ParentClass { public static function who() { echo "I'm a " . __CLASS__ . "\n"; } public static function test() { // على الصف الذي عُرّف التابع ضمنه self تؤشر self::who(); // على الصف الذي استدعي التابع منه static تؤشر static::who(); } } ParentClass::test(); /* ParentClass أنا ParentClass أنا */ class ChildClass extends ParentClass { public static function who() { echo "But I'm " . __CLASS__ . "\n"; } } ChildClass::test(); /* ParentClass أنا ChildClass ولكن أنا */ Magic constants الثوابت السحرية الحصول على اسم الصنف الحالي. يجب أن تستخدم داخل تصريح الصنف. echo "Current class name is " . __CLASS__; الحصول على مسار الدليل الكامل لملف echo "Current directory is " . __DIR__; الاستخدام النموذجي require __DIR__ . '/vendor/autoload.php'; الحصول على المسار الكامل للملف echo "Current file path is " . __FILE__; الحصول على اسم الدالة الحالية echo "Current function name is " . __FUNCTION__; الحصول على رقم السطر الحالي echo "Current line number is " . __LINE__; الحصول على اسم الطريقة الحالية. يرجع قيمة فقط عندما يستخدم داخل تصريح سمة أو كائن echo "Current method is " . __METHOD__; الحصول على اسم namespace الحالي echo "Current namespace is " . __NAMESPACE__; الحصول على اسم السمة الحالية. ترجع قيمة فقط عندما تستخدم داخل التصريح عن السمة أو الكائن. echo "Current trait is " . __TRAIT__; Error Handling معالجة الأخطاء يمكن أن تتم معالجة أخطاء بسيطة باستخدام كتلة try catch try { // افعل شيء ما } catch (Exception $e) { // معالجة استثناء } عند استخدام كتلة try catch في بيئة namespace استخدم التالي try { // افعل شيء ما } catch (\Exception $e) { // معالجة استثناء } استثناءات مخصّصة class MyException extends Exception {} try { $condition = true; if ($condition) { throw new MyException('Something just happened'); } } catch (MyException $e) { // معالجة استثنائية } ترجمة -وبتصرّف- للمقال Learn PHP in Y Minutes
  11. كوتلن (Kotlin) هي لغة برمجة مخصّصة لمنصّة جافا الافتراضية (Java Virtual Machine أو اختصارًا JVM)، الأندرويد، والمتّصفح. تنتمي للغات statically typed (التي تفحص الأنواع وقت الترجمة). وهي متوافقة مع جافا 100%. // (//)التعليقات على سطر واحد تبدأ بـ/* التعليقات المؤلفة من عدة أسطر تبدو كهذه */ تعمل الكلمة المفتاحية package بنفس طريقة جافا package com.learnxinyminutes.kotlin نقطة الإدخال لبرامج Kotlin هي دالة(تابع) تسمى main ،يمرر التّابع مصفوفة تحتوي على وسطاء arguments لسطر الأوامر. fun main(args: Array<String>) { التّصريح عن القيم يتم باستخدام إما var أو val ،تصريح val لا يمكن إعادة تعيينه، في حين يمكن ذلك في var val fooVal =10 لا يمكننا لاحقًا إعادة تعيين قيمة fooVal لقيمة أخرى. var fooVar =10 fooVar =20 من الممكن إعادة تعيين قيمة fooVar. في أغلب الحالات، يمكن لكوتلن أن تحدّد ما هو نوع المتغير، لذلك لا داعي لتحديده صراحة في كل مرّة. يمكننا أن نصرّح بنوع المتغير بوضوح كالتالي: val foo:Int=7 يمكن تمثيل السلاسل بطريقة مماثلة في java. يتم الهروب باستخدام backslash. val fooString ="My String Is Here!" val barString ="Printing on a new line?\nNo Problem!" val bazString ="Do you want to add a tab?\tNo Problem!" println(fooString) println(barString) println(bazString) تُحدد السلسلة الخام string raw باستخدام triple quote ("""). ويمكن أن تحتوي أسطر جديدة و أية محارف أخرى. val fooRawString =""" fun helloWorld(val name :String){ println("Hello, world!")}""" println(fooRawString) السلاسل ممكن أن تحتوي تعابير القالب template expressions. تبدأ تعابير القالب بالرمز $. val fooTemplateString ="$fooString has ${fooString.length} characters" println(fooTemplateString)// => My String Is Here! has 18 characters من أجل المتغيرات التي تحوي قيمة فارغة null يجب تحديد ذلك صراحة nullable. يمكن تحديد المتغير قابلاً للقيمة null بإلحاق? بنوعه. ويمكننا الوصول إلى المتحولات القابلة لـ null باستخدام مُعامل التشغيل? ،ويمكننا استخدام عامل التشغيل :? لتحديد قيمة بديلة للاستخدام إذا كان المتغير فارغ null. var fooNullable:String?="abc" println(fooNullable?.length)// => 3 println(fooNullable?.length ?:-1)// => 3 fooNullable = null println(fooNullable?.length)// => null println(fooNullable?.length ?:-1)// => -1 يمكن التصريح عن الدوال باستخدام الكلمة المفتاحية fun. وتحدد وسطاء الدالة بين قوسين بعد اسم الدالة. ويمكن لوسطاء الدالة اختياريًا الاحتواء على قيمة افتراضية. ويحدّد نوع إرجاع الدالة، إذا لزم الامر بعد المعطيات. fun hello(name:String="world"):String{return"Hello, $name!"} println(hello("foo"))// => Hello, foo! println(hello(name ="bar"))// => Hello, bar! println(hello())// => Hello, world! يمكن لبارامتر الدالة أن يوسم بالكلمة المفتاحية vararg للسماح بتمرير عدد متغير من المعطيات إلى الدالة. fun varargExample(vararg names:Int){ println("Argument has ${names.size} elements")} varargExample()// => لا يحوي الوسيط أية عناصر varargExample(1)// => يحوي الوسيط عنصر واحد varargExample(1,2,3)// => يحوي الوسيط 3 عناصر عندما تتكوّن الدّالة من تعبير واحد فقط، يمكن حذف الأقواس المنحنية { } ويتم تحديد الجسم(العملية) بعد رمز = fun odd(x:Int):Boolean= x %2==1 println(odd(6))// => false println(odd(7))// => true إذا كان نوع الاسترجاع يمكن استنتاجه فلسنا بحاجة لتحديده. fun even(x:Int)= x %2==0 println(even(6))// => true println(even(7))// => false الدوال يمكن أن تأخذ دوال كوسطاء وترجع دالة. fun not(f:(Int)->Boolean):(Int)->Boolean{return{n ->!f.invoke(n)}} يمكن للدوال المسمّاة أن تحدّد كوسائط باستخدام معامل التشغيل val notOdd = not(::odd) val notEven = not(::even) يمكن تحديد تعابير Lambda كوسائط val notZero = not {n -> n ==0} إذا احتوت lambda على بارامتر واحد فقط يمكن حذف التصريح عنه (جنبًا إلى جنب مع<- )وسيكون اسم البارامتر الوحيد it. val notPositive = not {it >0}for(i in 0..4){ println("${notOdd(i)} ${notEven(i)} ${notZero(i)} ${notPositive(i)}")} تستخدم الكلمة المفتاحية class للتّصريح عن الأصناف. classExampleClass(val x:Int){ fun memberFunction(y:Int):Int{return x + y } infix fun infixMemberFunction(y:Int):Int{return x * y }} لإنشاء حالة instance جديدة نستدعي الباني. ولاحظ أن Kotlin لا تحوي الكلمة المفتاحية new. val fooExampleClass =ExampleClass(7) يمكن استدعاء دوال المستخدم باستخدام التنويت النقطي . println(fooExampleClass.memberFunction(4))// => 11 إذا وُسمت الدالة بالكلمة المفتاحية infix يمكن عندها أن يستدعى باستخدام التنويت الداخلي println(fooExampleClass infixMemberFunction 4)// => 28 أصناف البيانات Data classes هي طريقة مختصرة لإنشاء الأصناف التي تحتوي بيانات فقط وتنشئ دوال hashCode،equals و toString تلقائيًا. data classDataClassExample(val x:Int, val y:Int, val z:Int) val fooData =DataClassExample(1,2,4) println(fooData)// => DataClassExample(x=1, y=2, z=4) أصناف البيانات لديها دالة copy val fooCopy = fooData.copy(y =100) println(fooCopy)// => DataClassExample(x=1, y=100, z=4) يمكن أن تفكَك الكائنات Objects في متغيرات متعددة val (a, b, c)= fooCopy println("$a $b $c")// => 1 100 4 التفكيك باستخدام حلقة for for((a, b, c) in listOf(fooData)){ println("$a $b $c")// => 1 100 4} val mapData = mapOf("a" to 1,"b" to 2) Map.Entry قابل للتفكيك كذلك for((key, value) in mapData){ println("$key -> $value")} الدالة with مشابهة لعبارة with في جافا data classMutableDataClassExample(var x:Int, var y:Int, var z:Int) val fooMutableData =MutableDataClassExample(7,4,9) with (fooMutableData){ x -=2 y +=2 z--} println(fooMutableData)// => MutableDataClassExample(x=5, y=6, z=8) يمكننا إنشاء قائمة (لائحة) باستخدام الدالة listOf. ستكون القائمة غير قابلة للتغيير ولا يمكن إضافة عناصر أو إزالتها. val fooList = listOf("a","b","c") println(fooList.size)// => 3 println(fooList.first())// => a println(fooList.last())// => c// index يمكن الوصول إلى عناصر القائمة من خلال فهرسها println(fooList[1])// => b يمكن إنشاء قائمة قابلة للتعديل باستخدام الدالة mutableListOf val fooMutableList = mutableListOf("a","b","c") fooMutableList.add("d") println(fooMutableList.last())// => d println(fooMutableList.size)// => 4 يمكن إنشاء تعيين set باستخدام الدّالة setOf val fooSet = setOf("a","b","c") println(fooSet.contains("a"))// => true println(fooSet.contains("z"))// => false يمكننا إنشاء خريطة map باستخدام الدّالة mapOf val fooMap = mapOf("a" to 8,"b" to 7,"c" to 9) يمكن الوصول لقيم الـ Map من خلال مفاتيحها println(fooMap["a"])// => 8 تُمثل المتتالية Sequences مجموعات تقييمها مؤجل إلى حين الحاجة lazily-evaluated collections. ويمكننا إنشاء متتالية باستخدام الدّالة generateSequence. val fooSequence = generateSequence(1,{ it +1}) val x = fooSequence.take(10).toList() println(x)// => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] مثال لاستخدام متتالية لتوليد أرقام فيبانوتشي fibonacci fun fibonacciSequence():Sequence<Long>{ var a =0L var b =1L fun next():Long{ val result = a + b a = b b = result return a }return generateSequence(::next)} val y = fibonacciSequence().take(10).toList() println(y)// => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] تزوّد Kotlin دوال عالية الرتبة للعمل مع المجموعات collections val z =(1..9).map{it *3}.filter {it <20}.groupBy {it %2==0}.mapKeys {if(it.key)"even"else"odd"} println(z)// => {odd=[3, 9, 15], even=[6, 12, 18]} يمكن استخدام حلقة for مع أي شيء يؤمن التكرار. for(c in "hello"){ println(c)} تعمل حلقات while بشكل مشابه لعملها في اللغات الأخرى var ctr =0while(ctr <5){ println(ctr) ctr++}do{ println(ctr) ctr++}while(ctr <10) يمكن استخدام if كتعبير يرجع القيم. لهذا السبب ليس هناك حاجة لمعامل التشغيل :? في Kotlin. val num =5 val message =if(num %2==0)"even"else"odd" println("$num is $message")// => 5 is odd يمكن استخدام when كبديل لسلاسل if-else if val i =10 when { i <7-> println("first block") fooString.startsWith("hello")-> println("second block")else-> println("else block")} يمكن استخدام when مع المعطيات. when (i){0,21-> println("0 or 21") in 1..20-> println("in the range 1 to 20")else-> println("none of the above")} يمكن استخدام when كدالة ترجع القيم. var result = when (i){0,21->"0 or 21" in 1..20->"in the range 1 to 20"else->"none of the above"} println(result) يمكننا التحقق فيما إذا كان الكائن object من نوع محدّد باستخدام معامل التشغيل is. إذا مرر الكائن فحص النوع type check عندها يمكن استخدام هذا النوع دون الموائمة بشكل صريح. fun smartCastExample(x:Any):Boolean{if(x is Boolean){ X توائم أوتوماتيكيًا إلى Boolean return x }elseif(x is Int){ X توائم أوتوماتيكيًا إلى Int return x >0}elseif(x is String){ X توائم أوتوماتيكيًا إلى String return x.isNotEmpty()}else{returnfalse}} println(smartCastExample("Hello, world!"))// => true println(smartCastExample(""))// => false println(smartCastExample(5))// => true println(smartCastExample(0))// => false println(smartCastExample(true))// => true تعمل الموائمة الذكيّة smartcast أيضًا مع كتلة when fun smartCastWhenExample(x:Any)= when (x){ is Boolean-> x is Int-> x >0 is String-> x.isNotEmpty()else->false} الملحقات Extensions هي طريقة لإضافة وظائف جديدة للصنف class. وهي مشابهة لدوال ملحقات #C fun String.remove(c:Char):String{returnthis.filter {it != c}} println("Hello, world!".remove('l'))// => Hello, word! println(EnumExample.A)// => A println(ObjectExample.hello())// => hello أصناف Enum مشابهة لأنواع enum في جافا. enumclassEnumExample{ A, B, C } يمكن استخدام الكلمة المفتاحية object لإنشاء كائنات وحيدة. لا يمكننا تمثيلها ولكن يمكن أن نشير لحالتها الفريدة من خلال اسمها. وهذا مشابه لكائنات Scala singleton object ObjectExample{ fun hello():String{return"hello"}} fun useObject(){ObjectExample.hello() val someRef:Any=ObjectExample//كماهي تمامًا objects نستخدم أسماء الكائنات } ترجمة -وبتصرّف- للمقال Learn kotlin in Y Minutes
  12. جافا هي لغة برمجة حاسوبية للأغراض العامة، المتزامنة، المعتمدة على الصفوف، وغرضية التوجه // يبدأ التعليق المكتوب على خط واحد ب .// /* يبدو التعليق المكتوب على عدة سطور بهذا الشكل. */ /** *تبدو التعليقات في ملفات لغة البرمجة جافا بهذا الشكل *و تستخدم لوصف الصف أو الصفات المختلفة لكائن معين. *:الصفات الرئيسية * *@author- اسم مؤلف الكود. *ويحتوي على معلومات الاتصال كالبريد الالكتروني لمؤلف الكود أو للمؤلفين. *@version- النسخة الحالية من البرنامج. *@since -الوقت الذي تم فيه إضافة هذا الجزء من البرنامج. *@param -من أجل وصف البارامترات المختلفة للمنهج (method). *@return -لوصف القيمة التي يرجعها المنهج. *@deprecated -لإظهار انتهاء صلاحية الكود أو عدم وجوب استخدامه. *@see - روابط إلى جزء آخر من المستندات */ استورد الصف ArrayList بدلاً من استيراد الرزمة java.util كلّها import java.util.ArrayList; استورد جميع الصفوف الموجود داخل الرزمة import java.security.*; يحوي أي ملف جافا على صف عام، على المستوى الخارجي، له نفس اسم الملف public class LearnJava { ليعمل برنامج جافا يجب أن يحوي على تابع رئيسي بمثابة نقطة البدء public static void main(String[] args) { الدخل/الخرج الخرج استخدم ()System.out.println لطباعة السطور النصيّة System.out.println("Hello World!"); System.out.println( "Integer: " + 10 + " Double: " + 3.14 + " Boolean: " + true); استخدم ()System.out.print للطباعة بدون سطر جديد System.out.print("Hello "); System.out.print("World"); استخدم ()System.out.printf لتنسيق الطباعة بسهولة System.out.printf("pi = %.5f", Math.PI); // => pi = 3.14159 الدخل استخدم scanner لقراءة الدخل، يجب استيراد الصف ;java.util.Scanner Scanner scanner = new Scanner(System.in); لقراءة السلاسل المحرفية المُدخلة String name = scanner.next(); لقراءة البايتات المُدخلة byte numByte = scanner.nextByte(); لقراءة العدد الصحيح المُدخل int numInt = scanner.nextInt(); لقراءة العدد الحقيقي المٌدخل float numFloat = scanner.nextFloat(); لقراءة العدد الحقيقي مضاعف الدقة المُدخل double numDouble = scanner.nextDouble(); لقراءة القيمة المنطقية المُدخلة boolean bool = scanner.nextBoolean(); المتغيرات التصريح عن المتغيرات يتم التصريح عن متغير باستخدام // <type> <name> int fooInt; يتم التصريح عن مجموعة من المتغيرات من نفس النوع // <type> <name1>, <name2>, <name3> int fooInt1, fooInt2, fooInt3; تهيئة المتغير يتم تهيئة متغير باستخدام // <type> <name> = <val> int barInt = 1; يتم تهيئة مجموعة من المتغيرات من نفس النوع بنفس القيمة باستخدام // <type> <name1>, <name2>, <name3> // <name1> = <name2> = <name3> = <val> int barInt1, barInt2, barInt3; barInt1 = barInt2 = barInt3 = 1; أنواع المتغير البايت (Byte) : وهو 8bit ويستخدم لترميز الأعداد الصحيحة بين -128 و 127 byte fooByte = 100; إذ كنت ترغب بتفسير البايت كعدد صحيح موجب (بدون إشارة). فإن هذه العملية البسيطة من الممكن أن تساعد int unsignedIntLessThan256 = 0xff & fooByte; هذا يناقض عمل cast الذي من الممكن أن يعطي عدد سالب int signedInt = (int) fooByte; القصير (Short): وهو 16bit ويستخدم لترميز الأعداد الصحيحة بين -32,768 و 32,767 short fooShort = 10000; الصحيح (Integer): وهو 32bit ويستخدم لترميز الأعداد الصحيحة بين -2,147,483,648 و 2,147,483,647 int bazInt = 1; الطويل (Long): وهو 64bit ويستخدم لترميز الأعداد الصحيحة بين -9,223,372,036,854,775,808 و 9,223,372,036,854,775,807 long fooLong = 100000L; يستخدم المحرف L للدلالة على أن قيمة المتحول هي من النوع Long. و أي قيمة مُسندة للمتحول بدون استخدام L هي عبارة عن عدد صحيح int بشكل افتراضي. ملاحظة: إن الأنواع byte، short، int، long، هي أنواع ذات إشارة signed. أي من الممكن أن تحوي على قيم موجبة أو قيم سالبة. لا يوجد متغيرات بقيمة موجبة فحسب. ولكن المحارف تعتبر من نوعية unsigned ذات القيمة الموجبة فقط ذات 16bit. العائم (Float): وهو ذو دقة أحادية 32 bit IEEE 754 ويستخدم لترميز الأعداد الحقيقية ذات الفاصلة العائمة بين 149-^2 و 127^2 - (23-^2-2) float fooFloat = 234.5f; يستخدم المحرف f أو F للدلالة على أن قيمة المتحول هي من النوع Float. و إلا سيعتبر المتغير من النوع الحقيقي المضاعف. المضاعف (Double): وهو ذو دقة مضاعفة 64 bit IEEE 754 ويستخدم لترميز الأعداد الحقيقية ذات الفاصلة العائمة بين 1074-^2 و 1023^2 - (52-^2-2) double fooDouble = 123.4; القيم المنطقية (Boolean) ذات القيمة: true و false boolean fooBoolean = true; boolean barBoolean = false; Char هو محرف يونيكود 16بت أحادي char fooChar = 'A'; لا يمكن أعادة تهيئة المعطيات من النوع final final int HOURS_I_WORK_PER_WEEK = 9001; ولكن من الممكن تهيئتها بعد عملية التصريح عنها final double E; E = 2.71828; BigInteger -عبارة عن نوع الأعداد الصحيحة الثابتة بمستويات دقّة مختلفة. يستخدم نوع المعطيات BigInteger للسماح للمبرمج بالتعامل مع الأعداد الصحيحة التي هي أكبر من 64-بت. حيث تُخزّن الأعداد الصحيحة في مصفوفة من البايتات، التي يمكن التلاعب بها باستخدام التوابع المبنيّة في الصف BigInteger . يمكن تهيئة المتغير من النوع BigInteger بمصفوفة من البايتات أو بمصفوفة من السلاسل المحرفية. BigInteger fooBigInteger = new BigInteger(fooByteArray); BigDecimal عبارة عن نوع الأعداد الحقيقية الثابتة بمستويات دقة مختلفة. ويأخذ المتغير من النوع BigDecimal معاملين: عدد صحيح ذو حجم غير مقّيّد، يمثل مستوى الدقّة، وعدد صحيح أخر بحجم 32 بت. يسمح النوع BigDecimal بالتحكم بتقريب الأعداد الحقيقية. عندما يكون مطلوب مستوى دقة محدد للعدد الحقيقي يُنصح باستخدام BigDecimal . من الممكن تهيئة المتغير من النوع BigDecimal بأحد الأنواع التالية: int ،long ،double ،String ،BigInteger BigDecimal fooBigDecimal = new BigDecimal(fooBigInteger, fooInt); كُن حذرًا عند استخدامك للأنواع float ,double لأن عدم الدقّة في تحديد النوع سوف تُنسخ في الـ BigDecimal ويُفضل استخدام سلسلة محرفية ثابتة عندما تحتاج إلى قيمة دقيقة. BigDecimal tenCents = new BigDecimal("0.1"); String -السلاسل المحرفية String fooString = "My String Is Here!"; الحرف الخاص n\ يُعرف بحرف السطر الجديد الذي يحرك مؤشر الكتابة إلى بداية السطر التالي. String barString = "Printing on a new line?\nNo Problem!"; الحرف الخاص t\ يُعرف بالمسافة الأفقية، يقوم بتحريك مؤشر الكتابة مسافة معينة إلى النقطة التالية في السطر. String bazString = "Do you want to add a tab?\tNo Problem!"; System.out.println(fooString); System.out.println(barString); System.out.println(bazString); بناء السلاسل المحرفية: باستخدام عامل الجمع (+) تُعتبر الطريقة الأساسية (الأمثل) للقيام ببناء السلاسل المحرفية. String plusConcatenated = "Strings can " + "be concatenated " + “via + operator.”; System.out.println(plusConcatenated); // Output: Strings can be concatenated via + operator. باستخدام الصف StringBuilder لا تشكل هذه الطريقة أية سلاسل محرفية وسيطة، فقط تقوم بتخزين قطع السلاسل المحرفية و ربطها مع بعضها عندما يتم استدعاء التابع ()toString. تلميح: لا يعتبر الصف StringBuilder إجرائية آمنة. يوجد صف بديل آمن StringBuffer (مع تأثير بسيط على الأداء). StringBuilder builderConcatenated = new StringBuilder(); builderConcatenated.append("You "); builderConcatenated.append("can use "); builderConcatenated.append("the StringBuilder class."); System.out.println(builderConcatenated.toString()); // فقط الآن تمّ بناء السلسة المحرفية // Output: You can use the StringBuilder class. تكون StringBuilder فعاله عندما السلسلة المحرفية الكاملة المبنيّة مطلوبة في نهاية عملية ما. StringBuilder stringBuilder = new StringBuilder(); String inefficientString = ""; for (int i = 0 ; i < 10; i++) { stringBuilder.append(i).append(" "); inefficientString += i + " "; } System.out.println(inefficientString); System.out.println(stringBuilder.toString()); تتطلب inefficientString عمل أكثر، حيث أنها تنتج سلسلة محرفية عند كل دورة للحلقة. يتم ترجمة تجميع السلاسل المحرفية البسيطة بالعامل (+) إلى: toString() و StringBuilder تجنب استخدام تجميع السلاسل المحرفية داخل الحلقات. لاستخدام منسق السلاسل المحرفية طريقة أخرى بديلة لتوليد السلاسل المحرفية سريعة و قابلة للقراءة. String.format("%s may prefer %s.", “Or you”, “String.format()”); // Output: Or you may prefer String.format(). المصفوفات يجب تحديد حجم المصفوفة بشكل فوري بمجرد التصريح عنها. تستخدم الصيغة التالية للتصريح عن مصفوفة. // <datatype>[] <var name> = new <datatype>[<array size>]; // <datatype> <var name>[] = new <datatype>[<array size>]; int[] intArray = new int[10]; String[] stringArray = new String[1]; boolean boolArray[] = new boolean[100]; طريقة أخرى للتصريح عن مصفوفة و تهيئتها int[] y = {9000, 1000, 1337}; String names[] = {"Bob", "John", "Fred", "Juan Pedro"}; boolean bools[] = {true, false, false}; فهرسة المصفوفة - الوصول إلى عنصر فيها System.out.println("intArray @ 0: " + intArray[0]); تبدأ المصفوفات بالفهرس (0)، و هي قابله للتغيير . intArray[1] = 1; System.out.println("intArray @ 1: " + intArray[1]) ArrayLists; // => 1 مجموعة من أنواع المعطيات الأخرى، التي تستحق التدقيق فيها: ArrayLists : مشابهة للمصفوفات، إلا أنها تحوي على وظائف إضافية، وحجمها قابل للتعديل. LinkedLists : عبارة عن تنفيذ لقائمة مترابطة بشكل مضاعف، التي تنفذ جميع العمليات التي من المتوقع لقائمة مترابطة بشكل مضاعف أن تنفذها. Maps : عبارة عن وصل كائنات المفتاح إلى كائنات القيمة. وهي عبارة عن واجهة، و بالتالي لا يمكن أن يتم تشكيل كائنات منها. يجب أن يتم تحديد نوع المفاتيح و القيم بناءً على الكائن المُشكل من الصف. من الممكن ان يُربط كل مفتاح إلى قيمة واحدة فقط، ومن الممكن أن يظهر كل مفتاح مرة واحدة فقط. (لا يوجد نسخ) لتنفيذ الخريطة/الواجهة Map hashtable : يُستخدم هذا الصف الجدول ، HashMaps وينفذ الخريطة Map ، هذا يسمح بتثبيت زمن العمليات الأساسية، مثل الحصول على عنصر أو إدخال عنصر، حتى في المجموعات الكبيرة. TreeMap: عبارة عن Map ، مصنفة حسب مفاتيحها. يُحافظ كل تعديل على ترتيبه، إما باستخدام المقارن المزود عند عملية توليد الكائن، أو باستخدام المقارنات لكل كائن، اذا كان ينفذ واجهة قابلة للمقارنة. سوف يؤدي الفشل المدمج في تنفيذ واجهة قابلة للمقارنة، مع الفشل في تزويد مقارن إلى رمي ClassCastExceptions تأخذ عمليات إدخال و حذف عناصر زمن من الدرجة ((O(log(n ، لذلك تجنب استخدام بنى المعطيات هذه، إلا أذا كنت ترغب من الاستفادة من ميزة الترتيب. العمليات System.out.println("\n->Operators"); int i1 = 1, i2 = 2; // الطريقة المختصرة للتصريح عن عدة متغيرات في نفس الوقت العمليات الحسابية بسيطة System.out.println("1+2 = " + (i1 + i2)); // => 3 System.out.println("2-1 = " + (i2 - i1)); // => 1 System.out.println("2*1 = " + (i2 * i1)); // => 2 System.out.println("1/2 = " + (i1 / i2)); // => 0 (int يعيد int/int) System.out.println("1/2.0 = " + (i1 / (double)i2)); // => 0.5 باقي القسمة System.out.println("11%3 = "+(11 % 3)); // => 2 عمليات المقارنة System.out.println("3 == 2? " + (3 == 2)); // => false System.out.println("3 != 2? " + (3 != 2)); // => true System.out.println("3 > 2? " + (3 > 2)); // => true System.out.println("3 < 2? " + (3 < 2)); // => false System.out.println("2 <= 2? " + (2 <= 2)); // => true System.out.println("2 >= 2? " + (2 >= 2)); // => true العمليات المنطقية System.out.println("3 > 2 && 2 > 3? " + ((3 > 2) && (2 > 3))); // => false System.out.println("3 > 2 || 2 > 3? " + ((3 > 2) || (2 > 3))); // => true System.out.println("!(3 == 2)? " + (!(3 == 2))); // => true العمليات على مستوى البت ~ عامل إيجاد المتمم على مستولى البتات. << عامل الإزاحة الحسابية نحو اليسار (مع الأخذ بعين الاعتبار بت الإشارة). >> عامل الإزاحة الحسابية نحو اليمين (مع الأخذ بعين الاعتبار بت الإشارة). >>> عامل الإزاحة المنطقية نحو اليمين (بدون الأخذ بعين الاعتبار بت الإشارة). & على مستوى البتّات and العملية المنطقية ^ على مستوى البتّات xor العملية المنطقية | على مستوى البتّات or العملية المنطقية عمليات الزيادة int i = 0; System.out.println("\n->Inc/Dec-rementation"); العامل ++ يقوم بالزيادة بمقدار واحد. العامل – يقوم بالإنقاص بمقدار واحد. إذا تم وضع هذين العاملين قبل المتغير، فإنهن يقومان بالزيادة أو الإنقاص، ومن ثم يعيدان قيمة المتحول الجديدة. أما إذا تم وضع هذين العاملين بعد المتغير، فإنهما يقومان بإعادة قيمة المتحول، ومن ثم يقومان بالزيادة أو الإنقاص. System.out.println(i++); // i = 1, يطبع 0 (زياده لاحقة). System.out.println(++i); // i = 2, يطبع 2 (زيادة سابقة). System.out.println(i--); // i = 1, يطبع 2 (إنقاص لاحق) System.out.println(--i); // i = 0, يطبع 0 (إنقاص سابق) بنى التحكم System.out.println("\n->Control Structures"); عبارة if مشابهة لتلك الموجودة في لغة البرمجة C int j = 10; if (j == 10) { System.out.println("I get printed"); } else if (j > 10) { System.out.println("I don't"); } else { System.out.println("I also don't"); } حلقة While int fooWhile = 0; while(fooWhile < 100) { System.out.println(fooWhile); //زيادة العدّاد //(في المجال (0،1،..99 foowhile مكررة 100 مرة ، حيث أن قيم المتغير fooWhile++; } System.out.println("fooWhile Value: " + fooWhile); حلقة Do While int fooDoWhile = 0; do { System.out.println(fooDoWhile); //زيادة العدّاد //في المجال 0-99 foowhile مكررة 99 مرة ، حيث أن قيم المتغير fooDoWhile++; } while(fooDoWhile < 100); System.out.println("fooDoWhile Value: " + fooDoWhile); حلقة For : هيكلية الحلقة على الشكل التالي: for(<start_statement>; <conditional>; <step>) مثال for (int fooFor = 0; fooFor < 10; fooFor++) { System.out.println(fooFor); // fooFor 0->9 مكررة 10 مرات، حيث } System.out.println("fooFor Value: " + fooFor); //outerيتم الخروج من الحلقة الداخلية باستخدام جملة الهروب المعنونّة بـ outer: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { if (i == 5 && j ==5) { break outer; //يخرج من الحلقة الخارجية أيضا، بدلاً من الخروج فقط من الحلقة الداخلية } } } حلقة For Each : قادرة على العمل مع المصفوفات و الكائنات for إن حلقة التي تنفذ الواجهات القابلة للتكرار. int[] fooList = {1, 2, 3, 4, 5, 6, 7, 8, 9}; هيكلية الحلقة على الشكل التالي: for (<object> : <iterable>) تقرأ هكذا: لكل عنصر في ال iterable ملاحظة: يجب أن يتطابق نوع الكائن مع نوع عناصر ال iterable for (int bar : fooList) { System.out.println(bar); //سوف تتكرر 9 مرات و يطبع 1-9 على سطور جديدة. } Switch تعمل Switch مع أنواع المعطيات: int، char، short ،byte وأيضًا من الممكن أن تعمل مع النوع Enum و String و مجموعة من الصفوف الخاصة التي تجمع الأنواع البدائية: Character, Byte, Short, Integer. بدءًا من جافا 7، من الممكن استخدام النوع String. ملاحظة: تذكر عدم استخدام التعليمة "break" في نهاية حالة جزئية إذا كان هناك يوجد حالة أخرى تستوفي الشرط أيضًا. int month = 3; String monthString; switch (month) { case 1: monthString = "January"; break; case 2: monthString = "February"; break; case 3: monthString = "March"; break; default: monthString = "Some other month"; break; } System.out.println("Switch Case Result: " + monthString); عبارة (Try-with-resources) في Java الإصدار +7 تُستخدم في جافا عبارات Try-catch-finally، و لكن في جافا +7 أيضا ً مُتاح استخدام try-with-resources إن عبارات try-with-resources تُبسط عمل عبارات try-catch-finally عن طريق إغلاق المصادر بشكل أتوماتيكي. لاستخدام try-with-resources ضمّن كائن من صف في تعليمة try. try (BufferedReader br = new BufferedReader(new FileReader("foo.txt"))) { // يمكنك أن تجرّب شيئًا يحتاج إلى استثناء System.out.println(br.readLine()); // في جافا 7 المصادر مغلقة دومًا حتى لو كان هناك استثناء } catch (Exception ex) { //catch سوف يتم إغلاق المصدر قبل أن تنفذ عبارة System.out.println("readLine() failed."); } في هذه الحالة، لا يوجد حاجة إلى عبارة finally حيث أن BufferedReader تم إغلاقه للتو. يتم استخدام هذا لتجنب الحالات الحرجة، عندما عبارة finally لا يمكن استدعاءها. الاختزال الشرطي يمكنك استخدام العامل "?" لسرعة الأسناد . تُقرأ كما يلي: "إذا كانت العبارة صحيحة ، استخدم <أول قيمة> و إلا استخدم <القيمة الثانية> int foo = 5; String bar = (foo < 10) ? "A" : "B"; System.out.println("bar : " + bar); // "bar : A"تطبع // صحيحة (foo < 10) لأن العبارة //أو بشكل مبسط: System.out.println("bar : " + (foo < 10 ? "A" : "B")); التحويل بين أنواع المعطيات تحويل المعطيات تحويل السلاسل المحرفية إلى عدد صحيح Integer.parseInt("123");//يعيد نسخة العدد الصحيح من السلسة المحرفية "123" تحويل العدد الصحيح إلى سلسلة محرفية Integer.toString(123);//يعيد النسخة المحرفية من العدد الصحيح 123 راجع تحويل المعطيات للأنواع التالية من الصفوف: Double Long String الصفوف و التوابع للتصريح عن كائن من الصف Bicycle استخدم الكلمة المفتاحية new Bicycle trek = new Bicycle(); استدعاء توابع الكائن trek.speedUp(3); // setter , getter يجب عليك استخدام توابع الواضع و الآخذ trek.setCadence(100); يُعيد التابع ()toString التمثيل النصي للكائن. System.out.println("trek info: " + trek.toString()); التهيئة مزدوجة الأقواس لا تملك جافا تراكيب لتشكيل مجموعات ساكنة من المعطيات بطريقة سهلة عادةً يتم استخدام الطريقة التالية: private static final Set<String> COUNTRIES = new HashSet<String>(); static { COUNTRIES.add("DENMARK"); COUNTRIES.add("SWEDEN"); COUNTRIES.add("FINLAND"); } ولكن يوجد طريقة أنيقة لإنجاز الشيء نفسه بشكل أسهل، تُدعى هذه الطريقة مزدوجة الأقواس private static final Set<String> COUNTRIES = new HashSet<String>() {{ add("DENMARK"); add("SWEDEN"); add("FINLAND"); }} يولد القوس الاول { } صف داخلي بدون اسم AnonymousInnerClass ويعرّف القوس الثاني{ } كتلة مهيئ الحالة instance. يتم استدعاء هذه الكتلة، عندما يتم توليد الصف الداخلي لا يعمل هذا فقط للمجموعات، إنما يعمل أيضًا لكل الصفوف غير النهائي non-final يمكنك تضمين صفوف أخرى خارجية غير عامة في ملف جافا ، ولكنها ليست بممارسة جيدة. بدلاً من ذلك يفضّل فصل الصفوف في ملفات جافا منفصلة صيغة التصريح عن صف: // <public/private/protected> class <class name> { // } حقول البيانات, أنماط الباني, الوظائف كلها في الداخل تستدعى الوظائف كالدوال في جافا class Bicycle { حقول و متغيرات الصف Bicycle Public: يمكن الوصول إليه من أي مكان public int cadence; Private: يمكن الوصول إليه فقط من داخل الصف private int speed; Protected: يمكن الوصول إليه فقط من داخل الصف و الصفوف الفرعية protected int gear; default: يمكن الوصول إليه فقط من داخل الرزمة. String name; Static متغير صف ساكن static String className; البلوك الساكن Static لا تملك جافا تنفيذ للبواني الساكنة، ولكن جافا تملك كتل برمجية لتعريف متغيرات الصف (المتغيرات لساكنة) سيتم استدعاء هذا البلوك عند تحميل الصف. static { className = "Bicycle"; } الباني هي الطريقة التي يتم فيها توليد الصفوف. هذا هو الباني public Bicycle() { //يمكنك أيضا استدعاء باني آخر: // this(1, 50, 5, "Bontrager"); gear = 1; cadence = 50; speed = 5; name = "Bontrager"; } هذا عبارة عن باني ذو معاملات public Bicycle(int startCadence, int startSpeed, int startGear, String name) { this.gear = startGear; this.cadence = startCadence; this.speed = startSpeed; this.name = name; } صيغة الدالة // <public/private/protected> <return type> <function name>(<args>) أصناف الجافا غالبًا ما تنفّذ getters وsetters في حقولها صيغة التصريح عن الدالة // <access modifier> <return type> <method name>(<args>) public int getCadence() { return cadence; } دوال void لا تحتاج تصريح عودة public void setCadence(int newValue) { cadence = newValue; } public void setGear(int newValue) { gear = newValue; } public void speedUp(int increment) { speed += increment; } public void slowDown(int decrement) { speed -= decrement; } public void setName(String newName) { name = newName; } public String getName() { return name; } دالة لتوليد قيم الصفات لهذا الكائن @Override // موروثة من الصف لهذا الكائن. public String toString() { return "gear: " + gear + " cadence: " + cadence + " speed: " + speed + " name: " + name; } الصف PennyFarthing عبارة عن صنف فرعي من Bicycle class PennyFarthing extends Bicycle { -Penny Farthings //هي عباره عن نوع من الدراجات بعجلات أمامية كبيرة. public PennyFarthing(int startCadence, int startSpeed) { // super استدعي الباني الأب باستخدام الكلمة المفتاحية super(startCadence, startSpeed, 0, "PennyFarthing"); } يجب عليك تعليم المنهج الذي تُعيد كتابته بـ annotation@. @Override public void setGear(int gear) { this.gear = 0; } Object casting بما أن الصف PennyFarthing يرث الصف Bicycle : فمن الممكن القول أن: Bicycle هو PennyFarthing، و يمكن أن نكتب: // Bicycle bicycle = new PennyFarthing(); هذا يُدعى"object casting" حيث يتم تشكيل كائن من كائن آخر. الواجهات صيغة التصريح عن واجهة // <access-level> interface <interface-name> extends <super-interfaces> { // // Constants // // Method declarations // } مثال - الطعام: public interface Edible { public void eat(); //يجب على أي صف ينفذ هذه الواجهة // ان ينفذ هذه الدالة } public interface Digestible { public void digest(); // منذ جافا 8، من الممكن أن تملك الواجهات دالة افتراضية. public default void defaultMethod() { System.out.println("Hi from default method ..."); } } الآن يمكنك تشكيل صف يُنفذ كلا من هاتين الواجهتين. public class Fruit implements Edible, Digestible { @Override public void eat() { // ... } @Override public void digest() { // ... } } في جافا، يمكنك أن تمدد(ترث) صف واحد فقط، ولكن يمكنك أن تنفذ عدّة واجهات . على سبيل المثال: public class ExampleClass extends ExampleClassParent implements InterfaceOne, InterfaceTwo { @Override public void InterfaceOneMethod() { } @Override public void InterfaceTwoMethod() { } } الصفوف التجريدية صيغة التصريح عن صف تجريدي: // <access-level> abstract class <abstract-class-name> extends // <super-abstract-classes> { // // Constants and variables // // Method declarations // } لا يمكن تشكيل كائنات من الصفوف المجردة (تمثيل الصفوف المجردة) يمكن للصفوف المجردة أن تعرف عن دوال مجرّدة. المناهج المجردة لا تحوي على جسم ويجب تعليمها بالكلمة المفتاحية abstract . يجب على الصفوف الأبناء غير المجردة أن تعيد كتابة Override@ جميع الدوال المجردة في صفوفها العليا. من الممكن أن تكون الصفوف المجرّدة مفيدة عند الجمع بين منطق التكرار و السلوك المخصص، ولكن بما أن الصف المجرد يتطلب الوراثة، فإن الصفوف المجردة تنتهك منطق "التركيب عبر الوراثة". لذلك خُذ بعين الاعتبار الطرق الأخرى التي تستخدم هذا التركيب public abstract class Animal { private int age; public abstract void makeSound(); من الممكن أن يحوي المنهج جسم public void eat() { System.out.println("I am an animal and I am Eating."); //(private)ملاحظة: من الممكن هنا الوصول للمتغيرات الخاصة age = 30; } public void printAge() { System.out.println(age); } يمكن أن تحوي الصفوف المجردة على دالة رئيسية public static void main(String[] args) { System.out.println("I am abstract"); } } class Dog extends Animal { لاحظ بأنه لا يزال هناك حاجة لإعادة كتابة الدوال التجريدية في الصف التجريدي // @Override public void makeSound() { System.out.println("Bark"); // age = 30; ==> ERROR! // Animal خاص بالنسبة للصف age خطأ- و ذلك لأن المتغير } ملاحظة: من الممكن أن تحصل على خطأ إذا قمت هنا باستخدام Override@ لأن جافا لا تسمح لك بإعادة كتابة الدوال الساكنة. ما يحدث هنا يُدعى إخفاء الدالة METHOD HIDING public static void main(String[] args) { Dog pluto = new Dog(); pluto.makeSound(); pluto.eat(); pluto.printAge(); } الصفوف النهائية final class صيغة التصريح عن الصفوف النهائية // <access-level> final <final-class-name> { // // Constants and variables // // Method declarations // } الصفوف النهائية هي عبارة عن الصفوف التي لا يمكن وراثتها، (أي هي الولد النهائي). بطريقة ما، تُعد الصفوف النهائية معاكس الصفوف المجردة. لأنه يجب توسيع (وراثة) الصفوف المجردة، أما الصفوف النهائية لا يمكن توسيعها. public final class SaberToothedCat extends Animal { لاحظ بأنه ما يزال يوجد حاجة لإعادة كتابة الدوال المجردة في الصف المجرد.// @Override public void makeSound() { System.out.println("Roar"); } } الدوال النهائية public abstract class Mammal() { // صيغة الدالة النهائية: // <access modifier> final <return type> <function name>(<args>) // لا يمكن إعادة كتابة الدوال النهائية بواسطة صف ابن، // وبالتالي الدالة النهائية هو أخر تنفيذ للدالة . public final boolean isWarmBlooded() { return true; } } النوع Enum еnum هي طريقة تنظيمية للثوابت (Constants) في الكود بحيث تجمع الثوابت التي لها علاقة ببعضها تحت فئة واحدة بطريقة تنظم الوصول إليها .بما أن هذه القيم هي عبارة عن ثوابت، لذلك فإن أسماء الحقول من النوع enum يجب أن تكتب بحروف كبيرة. في لغة جافا يتم تعريف هذا النوع باستخدام الكلمة المفتاحية enum. لتعريف متحول عن يوم من أيام الأسبوع، باستخدام النوع enum : public enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY } من الممكن استخدام متغيرنا Day من النوع enum كما يلي: public class EnumTest { //Enumالمتغير من النوع Day day; public EnumTest(Day day) { this.day = day; } public void tellItLikeItIs() { switch (day) { case MONDAY: System.out.println("Mondays are bad."); break; case FRIDAY: System.out.println("Fridays are better."); break; case SATURDAY: case SUNDAY: System.out.println("Weekends are best."); break; default: System.out.println("Midweek days are so-so."); break; } } public static void main(String[] args) { EnumTest firstDay = new EnumTest(Day.MONDAY); firstDay.tellItLikeItIs(); // => Mondays are bad. EnumTest thirdDay = new EnumTest(Day.WEDNESDAY); thirdDay.tellItLikeItIs(); // => Midweek days are so-so. } } الأنواع enum هي فعالة بشكل أكبر مما تم توضيحه فوق. من الممكن أن يحتوي جسم المتغير enum على دوال و حقول أخرى. ترجمة -وبتصرّف- للمقال Learn Java in Y Minutes
  13. تُظهر هذ الإرشادات كيفية إنشاء تطبيقات JS/HTML Cordova ونشرها على منصّات موبايل أصليّة متنوعة باستخدام واجهة سطر أوامر كوردوفا (cordova (CLI, راجع CLI reference لتفاصيل مرجعية عن واجهة سطر أوامر Cordova. تثبيت Cordova CLI واجهة سطر أوامر Cordova موزّعة كحزمة npm (نظام إدارة حزم). اتبع الخطوات التالية لتثبيت أداة cordova CLI : 1- حمّل وثبّت Node.js. خلال التثبيت يجب أن تكون قادراً على استدعاء node و npm على سطر الأوامر الخاص بك. 2- (اختياري) حمّل وثبّت git client, إذا لم يكن لديك نسخة مسبقًا. قم بتثبيتها, وبعدها يجب أن تكون قادرًا على استدعاء git على سطر الأوامر الخاص بك. حيث يستخدمها CLI لتحميل الموارد عندما يتم الاشارة إليها باستخدام git repo 3- ثبّت cordova باستخدام أداة npm لـ Node.js. حيث سيُحمّل cordova أوتوماتيكيًا باستخدام أداة npm . في OS ولينكس $ sudo npm install -g cordova في أنظمة OSX و LINUX قد يكون الحاق الأمر npm بـ sudo ضروريًا لتثبيت أداة التطوير هذه في الأدلة المقيّدة مثل /usr/local/share إذا كنت تستخدم الأداة الاختيارية nvm/nave أو تمتلك صلاحية الوصول الى دليل التثبيت. يمكنك الاستغناء عن البادئة sudo . في نظام التشغيل ويندوز Windows C:\>npm install -g cordova تخبر العلامة g- الأمر npm بتثبيت cordova بشكل عام. وإذا لم يتم التحديد سيتم التثبيت في الدليل الفرعي node_modules من مسار التثبيت الحالي. بعد إتمام التثبيت يجب أن تتمكن من تشغيل cordova من موجه الأوامر بدون معامِلات، ويجب أن تقوم Cordova بطباعة نص للمساعدة على شاشة موجه الأوامر.. إنشاء التطبيق اذهب الى الدليل الذي تدير فيه شفرتك المصدرية. وأنشئ مشروع Cordova $ cordova create hello com.example.hello HelloWorld هذا ينشئ بنية الدليل المطلوب لتطبيق cordova الخاص بك. افتراضيًا, سكريب cordova create يولد هيكلية تطبيق معتمد على الوب والذي صفحته الرئيسية هي ملف المشروع www/index.html. إضافة منصّات يجب تشغيل جميع الأوامر اللاحقة ضمن الدليل الرئيسي المشروع، أو أي دليل فرعي: $ cd hello أضف المنصّات التي ترد لتطبيقك أن يستهدفها. سنضيف منصّة أندرويد و IOS والتأكد من حفظها الى config.xml و package.json: $ cordova platform add ios $ cordova platform add android للتأكد من مجموعتك الحاليّة للمنصّات: $ cordova platform ls تشغيل أوامر لإضافة أو إزالة المنصّات يؤثّر على محتويات دليل منصّات المشروع، حيث تظهر كل منصّة محدّدة كدليل فرعي. ثبيت المتطلبات المسبقة للبناء لإنشاء التطبيقات وتشغيلها، يلزمك تثبيت حزم SDK لكل منصّة تريد استهدافها. بدلاً من ذلك، إذا كنت تستخدم متصفح للتطوير فيمكنك استخدام منصّة browser التي لا تتطلب أية SDKs للمنصّة. للتحقق مما إذا كنت مستوفيًا لمتطلبات إنشاء المنصّة: $ cordova requirements Requirements check results for android: Java JDK: installed . Android SDK: installed Android target: installed android-19,android-21,android-22,android-23,Google Inc.:Google APIs:19,Google Inc.:Google APIs (x86 System Image):19,Google Inc.:Google APIs:23 Gradle: installed Requirements check results for ios: Apple OS X: not installed Cordova tooling for iOS requires Apple OS X Error: Some of requirements check failed بناء التطبيق افتراضيًا، Cordova تنشئ سكريبت يولد هيكلية تطبيق معتمد على الوب والذي صفحة البداية له هي ملف المشروع www/index.html. يجب تحديد أيّة تهيئة كجزء من معالج حدث deviceready المعرّف في www/js/index.js. قم بتشغيل الأمر التالي لبناء المشروع لجميع المنصّات: $ cordova build يمكنك اختياريًا تحديد المجال في كل بناء لمنصّات محدّدة- في هذه الحالة"ios" $ cordova build ios اختبار التطبيق غالباً ما تأتي حزم SDK لمنصّات الموبايل مع محاكي تشغّل صورة الجهاز, وبذلك يمكنك تشغيل التطبيق من الشاشة الرئيسية ومشاهدة كيفية تفاعله مع العديد من ميزات المنصّة. شغّل أمر مثل التالي لإعادة بناء التطبيق وعرضه ضمن محاكي منصّة معيّنة: $ cordova emulate android تبعاً لأوامر محاكي Cordova تحدّث (refreshes) صورة المحاكي لعرض أحدث تطبيق, والذي قد أصبح متاحاً للوصول من الشاشة الرئيسية: في نفس الوقت يمكنك توصيل الهاتف إلى حاسوبك واختبار التطبيق مباشرةً: $ cordova run android قبل تشغيل هذا الأمر، تحتاج إلى إعداد الجهاز للاختبار، باتباع الإجراءات التي تختلف حسب كل منصّة. إضافة الإضافات Plugins يمكنك تعديل التطبيق المولَّد افتراضياً للاستفادة من ميزات تقنيات الوب المعيارية, ولكن ستكون بحاجة لإضافة Plugins لكي يتمكّن التطبيق من الوصول لميزات على مستوى الجهاز. تعرض الإضافة واجهة برمجة تطبيقات جافا سكربت Javascript API لوظيفة SDK الأصلية. يتم استضافة الإضافات عادةً على npm ويمكنك البحث عنهم في صفحة plugin search. تُزوَّد بعض مفاتيح API من قبل مشروع المصدر المفتوح Apache Cordova ويشار إليها باسم Core Plugin APIs $ cordova plugin search camera لإضافة وحفظ إضافة الكاميرا إلى config.xml و package.json، سنحدّد اسم حزمة لإضافة الكاميرا: $ cordova plugin add cordova-plugin-camera Fetching plugin "cordova-plugin-camera@~2.1.0" via npm Installing "cordova-plugin-camera" for android Installing "cordova-plugin-camera" for ios يمكن أن تضاف الإضافات أيضاً باستخدام الدليل أو باستخدام git repo استخدم plugin ls أو plugin list أو plugin لوحدها لعرض الإضافات المثبّتة حالياً. كلٌ يُعرض من خلال معرّفه الخاص: $ cordova plugin ls cordova-plugin-camera 2.1.0 "Camera" cordova-plugin-whitelist 1.2.1 "Whitelist" استخدام mergesلتخصيص كل منصّة في حين أن Cordova تسمح لك بنشر التطبيق بسهولة على منصّات مختلفة, إلا أنه في بعض الأحيان ستحتاج لإضافة تخصيصات. في هذه الحالة, لن تقوم بتعديل الملفات المصدرية في أدّلة www المتعددة ضمن دليل المستوى العالي platforms , لأنه يتم استبداله بشكل منتظم مع مصدر المنصّات المتعددة لدليل المستوى العالي www بدلاً من ذلك، دليل المستوى الأعلى merges يوفر مكاناً لتحديد الموارد للنشر على منصّات محدّدة. يعكس كل دليل فرعي خاص بالمنصّة ضمن عمليات merges بنية الدليل لشجرة المصدر www، مما يسمح لك بتجاوز أو إضافة ملفات حسب الحاجة. على سبيل المثال، إليك كيفية استخدام عمليات merges لزيادة حجم الخط الافتراضي لأجهزة أندرويد: حرّر ملف www/index.html , مضيفاُ رابط ملف CSS إضافي, overrides.css في هذه الحالة: <link rel="stylesheet" type="text/css" href="css/overrides.css" /> يمكن اختياريا إنشاء ملف www/css/overrides.css فارغ. والذي سيطبق من أجل كل بناء غير مخصص للأندرويد, لمنع خطأ الملف مفقود (missing-file) أنشئ ملف css على دليل فرعي ضمن merges/android, ثم أضف ملف overrides.css المقابل. حدّد CSS الذي يتجاوز حجم الخط الافتراضي 12-نقطة داخل www/css/index.css, على سبيل المثال: body { font-size:14px; } عندما تعيد بناء المشروع, تضمّن نسخة الأندرويد حجم الخط المخصص, بينما تظل البقية دون تغيير. كما يمكن استخدام merges لإضافة ملفات غير موجودة في الدليل الأصلي www. على سبيل المثال, تطبيق يمكنه تضمين back button رسومي داخل واجهة الـ iOS, مخزّن في merges/ios/img/back_button.png , ، في حين أنه يمكن لنسخة الأندرويد بدلاً من ذلك التقاط الأحداث backbutton من زر الأجهزة المقابلة. تحديث كوردوفا وتطبيقك بعد تثبيت أداة Cordova, يمكنك دوماً تحديثها إلى آخر إصدار من خلال تشغيل الأمر $ sudo npm update -g cordova استخدم هذه الصّياغة لتثبيت إصدار محدّد: $ sudo npm install -g cordova@3.1.0-0.2.0 نفّذ cordova -v لمعرفة النسخة الحالية قيد التشغيل. شغّل الأمر التالي لإيجاد آخر نسخة تم إصدارها Cordova: $ npm info cordova version لتحديث المنصّة التي تستهدفها: $ cordova platform update android --save $ cordova platform update ios --save ...etc. ترجمة -وبتصرّف- للمقال Create your first Cordova app للمساهمين في كتابة المقال على GitHub هذا المقال منشور تحت الرخصة Apache License, Version 2.0
  14. نظرة عامة أباتشي كوردوفا (Apache Cordova) هي منصّة مفتوحة المصدر لتطوير تطبيقات الموبايل. تمكّنك من استخدام تقنيات الويب المعياريّة مثل HTML5, CSS3, وJavaScript للتطوير متعدد المنصّات “cross-platform development” حيث تنفذ التطبيقات من خلال محزّم مخصص لكل منصّة، ويعتمد على الواجهات البرمجيّة القياسيّة للوصول إلى موارد الأجهزة كالحسّاسات، البيانات، وحالة الشبكة. قم باستخدام Apache Cordova إذا كنت: مطوّر تطبيقات موبايل وتريد أن توسّع قدرة تطبيقك ليعمل على أكثر من منصّة، بدون الحاجة إلى إعادة تنفيذه بلغة ومجموعة الأدوات الخاصّة بكل منصّة. مطوّر تطبيقات ويب، وتريد أن تنشر تطبيق محزّم للتوزيع على متاجر تطبيقات متنوعة. مطوّر تطبيقات موبايل مهتم بدمج مكونات التطبيق الأصليّة بطريقة عرض الويب WebView (نافذة تصفح خاصّة) يمكنها الوصول إلى الواجهات البرمجية للتطبيقات على مستوى الأجهزة (device-level APIs)، أو إذا كنت تودّ تطوير واجهة إضافة (plugin interface) بين المكونات الأصليّة ومكونات الويب. البنية يتواجد العديد من المكونات لتطبيقات Cordova, يبيّن المخطط التالي نظرة عالية المستوى على بنية تطبيق Cordova. عرض الويب WebView WebViewالمدعم بـ Cordova يمكن أن يزود التطبيق بكل واجهات المستخدم الخاصّة به، كما يمكن أن يكون في بعض المنصّات كمكوّن ضمن تطبيق مختلط أكبر يدمج WebView مع مكوّنات التطبيق الأصليّة تطبيق الويب Web App هو الجزء الذي تتوضع فيه شفرة تطبيقك، التطبيق بحد ذاته ينفذ كصفحة ويب، وبشكل افتراضي هو الملف المسمّى index.html والذي يرتبط بـ JavaScript ، CSS، صور، ملفات وسائط متعددة، أو مصادر أخرى ضرورية لتشغيله. ينفذ التطبيق في WEBVIEW ضمن محزّم البرنامج الأصلي, الذي قمت بتوزيعه على متاجر التطبيقات. ويحتوي أيضًا على ملف مهم للغاية وهو config.xml والذي يؤمّن معلومات عن التطبيق ويحدّد البارامترات التي تؤثر على كيفية عمله، كتحديد فيما إذا كان يستجيب لتغيرات الاتجاه. الإضافات Plugins تشكل الإضافات جزء أساسي من النظام الوظيفي لـ Cordova. فهي تؤمن الواجهة لـ Cordova والمكونات الأساسيّة للاتصال فيما بينها، وعملية التغليف إلى واجهات تطبيقات الجهاز القياسيّة APIS ، وهذا يمكنك من استدعاء الشفرة الأصليّة للبرنامج من خلال Javascript. مشروع Apache Cordova يدير مجموعة من الإضافات تسمّى الإضافات الجوهرية Core Plugins. هذه الإضافات تمكّن تطبيقك من الوصول إلى موارد جهازك (كالبطارية، الكاميرا، جهات الاتصال، ..الخ). وبالإضافة إلى المكونات الجوهريّة يوجد العديد من الإضافات التابعة لجهات أخرى third-party plugins والتي تؤمّن تغليفات إضافية لخصائص قد لا تكون متوافرة بالضرورة في جميع الأجهزة. يمكنك البحث عن إضافات Cordova باستخدام (plugin search(npm، كما يمكنك أيضًا تطوير إضافاتك الخاصة. يمكن أن تكون الإضافات ضروريّة . كمثال، من أجل الاتصال بين Cordova والمكونات الاصليّة العاديّة. لا تؤمن Cordova أي أدوات واجهات UI widgets أو بنى تعتمد عرض النماذج MV* frameworks. تؤمن لها فقط زمن التشغيل الذي يمكنها التنفيذ خلاله. إذا كنت تريد استخدام أدوات الواجهات أو بيئة عرض النماذج، يتوجب عليك اختيارهم وتضمينهم في تطبيقك. مسارات التطوير Development Paths تزودك Cordova بمخططي عمل workflow أساسيين من أجل إنشاء تطبيق موبايل، بينما يمكنك غالبًا استخدام أيّ منهما لإنجاز نفس المهمة، فإنّ كل منهم يقدم خصائص إيجابية: مخطط عمل موجه الأوامر متعدد المنصات (Cross-platform (CLI) workflow) استخدم هذا المخطط إذا كنت تودّ أن يعمل تطبيقك على أنظمة تشغيل مختلفة قدر الامكان. مع حاجة قليلة للتطوير المتعلق بالمنصة (platform-specific development) يركّز مخطط العمل هذا على موجه الأوامر في كوردوفا (Cordova CLI)، والذي هو عبارة عن أداة عالية المستوى تمكنك من بناء مشاريع لمنصّات متعددة في نفس الوقت. تستخرج العديد من خصائص سكربتات شيل(الصدفة) الأقل المستوى lower-level shell .scripts يقوم CLI بنسخ مجموعة من تجهيزات الويب الشائعة إلى مجلدات فرعية لكل منصّة موبايل، القيام بتغيير الإعدادات الضرورية لعمل كل منها، وتشغيل سكريبتات البناء لتوليد الملفات التنفيذية للتطبيقات. يؤمن CLI أيضًا واجهة عامة لتنصيب الإضافات على تطبيقك. إذا لم تكن بحاجة إلى مخطط مخصّص لمنصّة محددة يفضل اعتماد المخطط لمنصّات متعددة. مخطط العمل المتعلق بمنصّة Platform-centered workflow قم باستخدام هذا المخطط إذا كنت تودّ إنشاء تطبيق مخصّص لمنصّة واحدة, ولديك حاجة لأن تكون قادرًا على تعديله بالمستويات الأدنى. وكمثال إذا كنت تريد من تطبيقك أن يدمج المكونات الأصلية العادية مع مكونات Cordova المعتمدة على الويب (web-based Cordova components)، كما نوقش في تضمين WebViews. وكقاعدة متعارف عليها، استخدم هذا المخطط إذا كنت تريد تعديل المشروع من خلال حزمة تطوير النظام الخاصّة به SDK. هذا CLI مجموعة على مجموعة من سكريبتات المستوى الأدنى التي تم تعديلها لتلائم كل من المنصّات المدعومة. بالإضافة إلى أداة منفصلة (Plugman) تمكّنك من تنصيب الإضافات. بالرغم من أنّه يمكنك استخدام هذا المخطط لإنشاء تطبيقات لمنصّات متعددة، لكن ذلك يتم عادة بصعوبة أكبر، وذلك بسبب أن نقص أدوات المستوى الأعلى يعني دورات بناء منفصلة وتعديلات على الإضافة لكل منصّة. في بداية العمل، من الأسهل البدء باستخدام مخطط العمل متعدد المنصّات لإنشاء التطبيق، يمكننا بعدها الانتقال إلى مخطط العمل المخصص لمنصّة إذا كنت تريد تحكم أوسع يتم تأمينه من قبل حزمة تطوير النظام الخاصة بالتطبيق SDK. تدير CLI مجموعة شائعة من الشفرات المصدرية متعددة المنصّات، تستخدمها في كل عمليّة بناء للكتابة فوق الشفرة المخصصة لمنصّة واحدة. للحفاظ على أيّة تعديلات قمت بإجرائها على المكونات المخصصة لمنصّة، يتوجب عليك الانتقال إلى استخدام أدوات شيل المخصصة لتلك المنصّة التي تتجاهل الشفرات المصدريّة متعددة المنصّات وتقوم بدلاً عن ذلك بالاعتماد على شفرات مصدريّة مخصصة لمنصّة واحدة. تنصيب Cordova يختلف تنصيب Cordova بحسب مخطط العمل الذي تختاره. مخطط العمل متعدد المنصّات: (سنتعرّف عليه في الدرس القادم) مخطط العمل المخصص لمنصّة. بعد تنصيب Cordova, يفضل الاطلاع على قسم (Develop for Platforms) لمنصّات الموبايل التي تطوّر التطبيق من أجلها. ترجمة -وبتصرّف- للمقال Architectural overview of Cordova platform للمساهمين في كتابة المقال على GitHub هذا المقال منشور تحت الرخصة Apache License, Version 2.0