تعليم لغة بيرل Perl و سي جي آي CGI

 

 

الدرس الرابع

 

 

استعمال بيرل و سي جي آي عملياً :

الشيء الشائع في صفحات الويب هذه الأيام هو عداد زوار بسيط يتابع كل زيارة إلى الموقع و يضع رقمها في مكان ما من الصفحة ، مثلاً في موقعي تجد في الجانب الأيمن السفلي عبارة تقول (أنت الزائر رقم) و تحتها عدد زوار الموقع , حسناً هذا عمل بسيط و سننجزه في هذا الدرس .

ابتكار عداد الزوار هو مشكلة برمجة تحتاج إلى تفكير أولاً ، فالكمبيوتر و الشفرة هما آخر الخطوات في عملية ابتكار البرنامج على الكمبيوتر . كثير من المبرمجين خاصة المبتدئين يتسرعوا و يبدأوا في التحويل إلى شفرة ، مشكلة هذا الأسلوب هو أنه يربطك جداً بالكمبيوتر و أدوات البرمجة التي تحت تصرفك ، و نتيجة لذلك ستنتهي إلى حل يعتمد تماماً على هذه الأدوات .

من الأكثر منطقية أن تنظر للمشكلة من مفهوم أكثر عموماً و تفكر فيها ، مرحلة التفكير هذه تنقسم إلى ثلاث مراحل :

لذلك اختر كرسي مريح بعيداً عن الكمبيوتر في مكان هاديء و خذ معك ورقة أو اثنتين و قلم رصاص ، و ابدأ الرسم التمهيدي .

التحليل :

ما الذي تحتاج أن تفعله لكي تعد زوار صفحة ويب ؟ حسناً أنت تحتاج إلى :

1- تخزين رقم في مكان ما .

2- قدرة على قراءة الرقم .

3- القدرة على زيادة الرقم (إضافة 1)

4- كتابة الرقم الجديد على صفحة ويب .

5- تخزين الرقم مرة أخرى .

التصميم :

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

  1. إذا كانت تلك هي المرة الأولى التي يعمل فيها البرنامج ، فابتكر ملف ، و خزن القيمة 1 فيه ، ثم اذهب إلى الخطوة 3 .

  2. إذا كان الملف موجوداً بالفعل فافتحه و اقرأه و أضف 1 إلى القيمة التي قرأتها .

  3. اعرض القيمة الجديدة على صفحة الويب .

  4. اكتب القيمة الجديدة للملف .

  5. اغلق الملف .

التطبيق :

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

كيف يتعامل بيرل مع الملفات :

كما هو معروف فإننا لنقرأ الملف نحتاج إلى فتحه ثم بعد أن ننتهي منه يجب علينا إغلاقه . و وظائف بيرل التي تسمح بالتعامل مع الملفات هي :

من الأفضل دائماً أن تتعلمهم عن طريق فعلهم ، ادخل الشفرة التالية في محرر نصك :

#!c:/perl/bin

# access.pl

# First version. Creates or opens a file with a number

# in it, increments the number, writes it back.

$CountFile = "counter.dat"; # Name of counter File.

# Open the file and read it. If it doesn't exist, its "contents"

# will be read into a program variable as "0".

open (COUNT, $CountFile);

$Counter = <COUNT>; # Read the contents.

# Close the file, then reopen it for output.

close (COUNT);

open (COUNT, ">$CountFile");

# Increment $Counter, then write it back out. Put up a message

# with the new value. close the file and exit.

$Counter += 1;

print COUNT $Counter;

print "$CountFile has been written to $Counter times.\n";

close (COUNT);

# End access.pl

احفظ هذه العينة من الشفرة بإسم access.pl و شغلها مرات قليلة من نافذة الدوس (هل ما زلت تذكر كيف؟) ، اكتب الأمر perl ثم اترك مسافة ثم اكتب اسم البرنامج المراد تشغيله و تذكر أنك يجب أن تكون في نفس المجلد الذي يوجد فيه البرنامج ، و توضح الصورة التالية ما يجب أن تراه :

في كل مرة تشغل فيها البرنامج يزيد الرقم واحد . هذا هو ما يسمى بالعداد .

السطر الأول القابل للتنفيذ في البرنامج يؤسس متغير CountFile$ ، هذا المتغير هو اسم الملف الذي يجب أن يحكم إسمه قواعد تسمية الملفات في نظام التشغيل الذي تعمل عليه ، و بالطبع يمكنك تسميته كما تشاء في إطار هذه القواعد ، في هذا المثال أسميناه counter.dat .

توجيهات الملف File Handles :

سطري الشفرة التاليين ، يفتحا الملف و يقرءا أي شيء فيه :

open (COUNT, $CountFile);

$Counter = <COUNT>

الصيغة العامة لوظيفة open هي :

open (HANDLE, Expression);

حيث Expression تكون عادة اسم ملف أو متغير يحتوي على اسم ملف . أما HANDLE فتحتاج إلى شرح بسيط .

عندما تفتح ملف ، فأنت في الواقع تعطي تعليمات لبيرل أن يؤدي سلسلة معقدة نوعاً ما من الخطوات ، المعلومات عن الملف مخزنة في ذاكرة الكمبيوتر حيث تستطيع التعامل معها إذا أردت ، و العمليات التي تسمح لك أن تقرأ منها و تكتب إليها يتم تحميلها ، يحتاج بيرل بعد ذلك إلى طريقة سهلة للإشارة إلى الملف ، لذلك فقد أنشأ handle الذي يمكنك معاملته مثل اسم متغير للملف حتى يتم إغلاق الملف .

يمكن تشبيه handle في موقف كالتالي : أنت في غرفة مظلمة مليئة بالخزانات (جمع خزانة و ليس خزّان) أنت تعرف أن الملف الذي تريده في في الخزانة رقم 13 لكن أين هي الخزنة رقم 13 في هذا الظلام ؟ بيرل يعتبر أن الغرفة المظلمة هي الذاكرة و يريد أن يصل إلى ملف معين و لكنه لا يعرف مكانه بالتحديد ، هو يعرف فقط أنه في هذه الغرفة بالذات ، نحن نضيء له باب الخزانة التي يوجد بها الملف عن طريق توجيه handle فيعرف أن هذا هو مكان الملف فيفتح الخزانة و يأخذ المتغير الموضوع فيها و هو متغير الملف الذي أسسناه في أول البرنامج . توجيه handle في هذا المثال هو COUNT

هل رأيت المعنى الكبير الذي تعبر عنه هذه الجملة الصغيرة .

في السطر التالي :

$Counter = <COUNT>;

يمكن القراءة مباشرة من توجيه الملف بوضع العلامتين <> حوله . و هذا السطر يقرأ محتويات التوجيه COUNT الذي يدل على الملف Counter.dat و في نفس الوقت يضع هذه المحتويات في متغير جديد هو Counter$ .

السطران التاليان هما مصدر ارتباك للمبتدئين :

close (COUNT);

open (COUNT, ">$CountFile");

فلماذا نغلق الملف ثم نعيد فتحه فوراً ، و لماذا نضع المتغير CountFile$ بين علامتي اقتباس مع رمز أكبر من < أمامها ؟

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

الجزء الأخير من الشفرة من access.pl تنتج زوج من المفاهيم الجديدة و المثيرة :

 

$Counter += 1;

print COUNT $Counter;

print "$CountFile has been written to $Counter times.\n";

close (COUNT);

في السطر الأول =+ هو اختصار تمت استعارته من لغة البرمجة C ، في هذا المثال السطر الأول مطابق تماماً لكتابة :

$Counter = $Counter+1;

إذن لماذا لا نكتبه هكذا ؟ هذا لأن السطر الأول أقصر و بالتالي هو يتبع مفاهيم الكسل و عدم الصبر ، و في النهاية هي مسألة ذوق يمكنك وضع أي منهما .

يمكنك أيضاً أن تستعمل =- للطرح ، و =* للضرب ، و =/ للقسمة ، و الرقم على الجانب الأيمن لا يشترط أن يكون 1 بل يمكن أن يكون أي عدد صحيح أو متغير عددي .

أما السطر التالي :

print COUNT $Counter;

هذا السطر يخبر البرنامج أن يكتب الرقم الجديد الناتج عن عملية الإضافة في السطر السابق ، أقول يكتب الرقم الجديد في الملف المشار إليه بالتوجيه COUNT ، (اطبع هنا مستخدمة بمعنى اكتب) . أي أن معنى السطر : اطبع في الملف العدد الجديد للزوار بعد أن أضفنا إليه الرقم واحد ، و لذلك لم نضع فاصلة سفلية بعد COUNT لأننا لو وضعناها سيعامل البرنامج التوجيه COUNT كمتغير عددي أو متغير قائمة ، و بما أن COUNT يمثل المخرج لعملية الكتابة أي أن الكتابة سوف تتم في COUNT فإن البرنامج سيكتب إلى المخرج الأساسي أو الشاشة مما يؤدي إلى نتائج غريبة و طلاسم و لن يتم كتابة أي شيء في الملف المشار إليه بتوجيه COUNT . نحن لن نستخدم وظيفة write في أي مثال في هذه الدروس ، لأن print مستخدمة بشيوع أكبر ، و في الغالب هي أكثر صحة من write .

السطور الباقية في البرنامج تكتب رسالة إلى الشاشة تقول أن الملف المشار إليه بالمتغير الذي أسسناه في أول البرنامج CountFile$ قد تم الكتابة إليه عدد ( ) مرة ، طبعاً بدون الأقواس و لكني وضعتها هنا لأوضح أن البرنامج يكتب مكانها محتويات الملف المشار إليها بالمتغير Counter$ . ثم بعد ذلك يغلق الملف و ينتهي البرنامج .

إحضار عدادك إلى الويب :

هذا البرنامج الذي كتبناه سوف يعمل فقط من خلال نافذة الدوس ، و لكي نحوله إلى تطبيق مناسب للويب يجب أن نحوله إلى تطبيق CGI و ملخص الأمر هو :

باتباع هذه القواعد يمكننا أن نعدل البرنامج إلى هذه الكيفية :

 

#!c:/perl/bin

# access.pl

# Second version. Creates or opens a file with a number

# in it, increments the number, writes it back, then displays

# the result in a message on a Web Page.

require "html.pl"; # Get HTML header, ender.

$CountFile = "counter.dat"; # Name of counter File.

$PageTitle = "Web Page Access Counter"; # Web Page title.

# Open the file and read it. If it doesn't exist, its "contents"

# will be read into a program variable as "0".

open (COUNT, $CountFile);

$Counter = <COUNT>; # Read the contents.

# Close the file, then reopen it for output.

close (COUNT);

open (COUNT, ">$CountFile");

# Increment $Counter, then write it back out. Put up a message

# with the new value. close the file.

$Counter += 1;

print COUNT $Counter;

close (COUNT);

# Put the result up in a standard HTML document.

&HTML_Header ($PageTitle); # HTTP header info.

print "<body>\n";

print "<H1>$PageTitle</H1>\n"; # Big heading.

print "<HR>\n"; # Draw A Rule.

print "<H3>You are visitor #$Counter";

print " to our Web Page !</H3>\n";

&HTML_Footer;

# End access.pl

احفظ هذا الملف بإسم access.pl أيضاً و لكن في فهرس cgi-bin الموجود في مجلد Sambar لكي تستطيع تشغيله من المتصفح . و إذا كنت قد حفظت النسخة القديمة في نفس المكان فاحفظ فوقها الملف الجديد بنفس الاسم . إذا كان كل شيء سليماً فسوف ترى مثل هذه الصورة بعد تشغيل الملف عدة مرات من المتصفح :

أظن البرنامج واضح و لا يحتاج إلى شرح ، فقط لاحظ أننا لم نعد نضع علامة السطر الجديد n\ بين علامتي اقتباس وحدها ، بل أدخلناها مع السلسلة في نفس العلامات ، و هذا أصح و أقصر .

إدخال تحسينات على البرنامج :

إذا اختبرت صفحات ويب الخاصة بك بعناية - و بالتأكيد سوف تفعل - فإن العداد يمكن أن يزيد إلى ارتفاعات كبيرة في وقت قصير جداً (دعك من أنك تريد هذا ، بل و ترغب فيه بشدة لإظهار كثرة عدد الزوار إلى موقعك ، فنحن هنا نتكلم عن الرجل النزيه) . يمكن أن نحل هذه المشكلة ببساطة إذا ما ابتكرنا شفرة صغيرة نضعها في البرنامج لتقارن عنوان الآي بي IP للزائر بعنوان الآي بي الخاص بك المخزن لديها فإذا كانا مختلفين فإنها تنفذ باقي البرنامج و تزيد الرقم ، أما إذا كانا متفقين فإنها تنهي البرنامج و لا تضيف على الرقم الموجود .

كيف نحصل على عنوان الآي بي ؟ تذكر من الدرس السابق أن الخادم يملأ المحيط الخاص به بمقدار بمقدار كبير من المعلومات حول الكمبيوتر الذي اتصل به . و من هذه المعلومات المتغير المحيطي الذي يحتوي على عنوان آي بي للزائر و يسمى REMOTE_ADDR و يمكنك الوصول إليه باستعمال مجموعة المحيط المترابطة ENV كالتالي :

$VisitorAddress=$ENV {'REMOTE_ADDR'};

أما كيف تحصل على عنوان آي بي الخاص بك فهذا شيء لا أتعقد أنه ممكن إذا كنت تصل إلى الإنترنت عن طريق مقدم خدمة Service Provider فعنوان الآي بي الخاص بك يتغير في كل مرة تتصل فيها بالإنترنت لكن يوجد عدة برامج تستطيع أن تخبرك برقم الآي بي الخاص بك في كل مرة تتصل فيها بمقدم الخدمة . أما إذا كنت تتصل بالإنترنت مباشرة بدون مقدم خدمة فيجب أن يكون لك عنوان آي بي ثابت و المفترض أنك تعرفه بالفعل .

الآن ها هو الجزء المعدل من الشفرة :

 

# Second version. Creates or opens a file with a number

# in it, increments the number, writes it back, then displays

# the result in a message on a Web Page.

require "html.pl"; # Get HTML header, ender.

$CountFile = "counter.dat"; # Name of counter File.

$PageTitle = "Web Page Access Counter"; # Web Page title.

$HomeBase = "198.66.21.24"; # My IP address.

$VisitorAddress = $ENV {'REMOTE_ADDR'}; # Visitor's IP Address.

خزننا هنا رقم الآي بي الخاص بنا في المتغير HomeBase$ أما المتغير VisitorAddress$ فهو يسحب عنوان آي بي للزائر من مجموعة المحيط ENV ، و كالمعتاد يجب أن تستبدل رقم الآي بي الذي تم إعطاؤه في HomeBase$ بعنوان آي بي الخاص بك .

كيف نتمكن من المقارنة إذاً ؟ هنا سنستخدم جمل (إذا) (if) الشرطية التي تشبه جملة while حيث تبدو جملة if مثل هذه :

if (هذه العبارة صحيحة )

{

نفذ;

هذا الجزء;

من الشفرة;

}

و المعنى العام : إذا كانت العبارة بين الأقواس صحيحة ، نفذ الجزء التالي من الشفرة .

و صحة أو خطأ العبارة بين الأقواس تحدد نتيجة المقارنة التي يوجد منها نظامان : الأول خاص بالأعداد ، و الثاني خاص بالسلاسل و الجدول التالي يوضحهما :

عددي

سلسلة

معناه

==

eq

مساوي لـ

=!

ne

ليس مساوياً لـ

<

gt

أكبر من

>

lt

أصغر من

=<

ge

أكبر من أو يساوي

=>

le

أصغر من أو يساوي

<=>

cmp

لا يساوي ، نتيجة لها علامة

صحيح أن عنوان الآي بي عددي ، إلا أننا وضعناه في سلسلة و بالتالي لا يمكن أن نعامله كعدد بل سنقارنه كسلسلة أي باستخدام أدوات مقارنة السلسة الحرفية . الآن غير السطر الذي يضيف واحد إلى قيمة الملف في البرنامج access.pl و هو :

$Counter += 1;

غيره إلى التالي :

if ($VisitorAddress ne $HomeBase)

{

$Counter += 1;

}

إنه يقارن عنوان الآي بي للزائر بعنوان الآي بي المخزن عنده ، فإذا كانا لا يتساويان سوف يضيف واحد إلى العداد .

استعمال الإطارات لوضع العداد :

لتستطيع تشغيل العداد يجب أن تكون صفحة الويب بعنوان access.pl لأن البرنامج هو الذي يرسم صفحة الويب و ليس العكس . إذن لو كنت تضع العداد في الصفحة الأولى من موقعك فسيكون اسم موقعك كالتالي :

www.mysite.com/cgi-bin/access.pl

عنوان صعب أليس كذلك ، و الحل البديل هو أن تضع الصفحة الأولى في موقعك بدون عداد و هذه الصفحة تخبر الزوار أن ينقروا على وصلة link لدخول الموقع ، و بالطبع الوصلة سوف تشير إلى عنوان البرنامج www.mysite.com/cgi-bin/access.pl و هذا ليس حلاً سيئاً ، و لكنه يتطلب خطوة إضافية نوعاً ما .

أما الحل الآخر فهو تصميم الصفحة بطريقة الإطارات . و الإطارات عبارة عن تصميم الصفحة الأولى بحيث تكون مجرد هيكل يضم عدة نوافذ قد تكون اثنتان أو ثلاثة أو أي عدد تريده ، كل نافذة منهم تعرض صفحة ويب مختلفة عن الأخرى و يمكنك أن ترى مثال لصفحة الإطارات في موقعي الذي صممته بهذه الطريقة http://forarabs.8m.com . حيث تجد فيه إطارين : الأول على اليمين و فيه محتويات الموقع و العداد ، أما الثاني ففيه كلمة افتتاحية للموقع و يتم عرض المحتويات في النافذة اليسرى عند الضغط على عنوانها في النافذة اليمنى .

المهم أن الصفحة الأولى في الموقع سوف تكون منفصلة عن الصفحات الأخرى ، هي فقط تشير إلى صفحتين أخرتين ليملآ الفراغ . و يمكنك أن تجعل برنامج العداد access.pl هو إحدى النافذتين بدون أن تتكلف تغيير عنوان موقعك أو حتى رؤية الزوار لهذا الإسم الغريب بالنسبة لهم . و الصورة التالية توضح وضع برنامج العداد access.pl في صفحة إطارات :

فقط تأكد من أنك أشرت إلى برنامج العداد بمسار كامل ، أنا مثلاً أشرت إليه بالمسار :

http://localhost/cgi-bin/access.pl

أما بالنسبة للإطار الآخر فلا داعي لذكر المسار كاملاً ما دام في نفس المكان مع صفحة الإطارات الرئيسية التي أشارت إليه .

 

 

استفسار ؟ راسلني

الدرس الخامس