قائمة البرمجة > لغة Perl

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

الكاتب:


المصدر: http://www.angelfire.com/rnb/forarabs

الدرس الخامس
الدرس السادس


الدرس الخامس


ابتكار نماذج هتمل فعلية مع CGI و بيرل :

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

بناء النماذج في الهتمل :

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

يمكنك بناء نموذج هتمل بسيط كالآتي :

<html>

<head>

<title>Visitor Information Form</title>

</head>

<body>

<H1 ALIGN="LEFT">Visitor Information Form</H1>

<HR>

<FORM ACTION="perl.htm" METHOD="GET">

<B>

Last Name: <INPUT TYPE="text" NAME="LastName" SIZE=16>

First Name: <INPUT TYPE="text" NAME="FirstName" SIZE=16>

<BR><BR>

Address: <INPUT TYPE="text" NAME="Address" SIZE=32>

City: <INPUT TYPE="text" NAME="City" SIZE=32>

<BR><BR>

<center>

<INPUT TYPE="submit" VALUE="Send Information">

<INPUT TYPE="reset" VALUE="Clear Form Fields"

</B>

</form>

</body>

</html>

احفظ هذه السطور بإسم form1.htm و افتحه بالمتصفح ، يجب أن تبدو النتيجة مشابهة للصورة :


يمكنك أن تجد دليل للواصفات Tags الخاصة بهتمل في موقعي في ركن الهتمل .

يوجد طريقتان لإرسال معلومات النموذج (أي المعلومات التي تم إدخالها في النموذج) و هاتان الطريقتان هما : GET و POST و يتم استعمالهما كوسيلة METHOD في الواصفة <FORM> استعملنا في هذا المثال GET ، و بشكل عام يتم استعمال GET للكميات الصغيرة من المعلومات و POST للكميات الكبيرة أو عندما تريد إخفاء المعلومات من المستخدم .

لكي نخدع المتصفح يمكنك ابتكار ملف اسمه perl.htm ليس فيه أي شيء سوى كلمة perl ، و احفظه في نفس المكان الذي حفظت فيه الملف form1.htm ثم شغل ملف الهتمل من المتصفح ، و املأ النموذج بأي شيء ملائم ثم اضغط على زر Send information . يجب أن ترى صورة مشابهة لهذا :


يستعمل هذا النموذج form1.htm القليل من تقنيات هتمل لأنه للغرض التعليمي ليس إلاّ .

سي جي آي و عناوين URL :

عناوين URL تم تطويرها كطريقة لتحديد المصادر على الإنترنت بسطر واحد من نصوص ASCII قابل للطبع . و ضع 3 خطوط تحت كلمة (قابل للطبع) ، و ستفهمها فيما بعد . و عناوين URL ليست مقيدة بالشبكة العالمية World Wide Web ، فمعظم أنظمة الإنترنت الكبيرة مثل FTP و HTTP و Gopher يمكن أن تقرأ و تفهم عناوين URL فقد تم تأسيسها بحيث تحتوي على :


بروتوكول خادم URL مثل (HTTP و Gopher و FTP) .

اسم مجال الخادم Domain Name .

رقم قناة TCP/IP أو البورت Port Number الخاصة بالخادم ، إذا تم حذفه سنعود إلى القناة الأساسية المعروفة للبروتوكول الذي تم به الاتصال .

مكان المصدر على الخادم Resource Location .

و يمكن تبعاً لذلك أن تقرأ عنوان URL الموجود في سطر العنوان في المتصفح بعد الضغط على زر Send Information كالتالي :


بالطبع المتصفح الخاص بك لن يظهر هذا العنوان عند الضغط على زر Send Information . و هذا لأنك لم تشغله على الإنترنت من موقع له إسم مجال Domain Name . سنناقش العنوان الذي ظهر لك في سطر العنوان في المتصفح في الفقرة التالية .

رموز قابلة للطبع :

مثل معظم أنظمة الإنترنت فإن عناوين URL كانت مصممة أصلاً لتأكيد أنه يمكن إرسالهم عن طريق البريد الإلكتروني . و معظم أنظمة البريد القديمة قادرة على التعرف على الرموز ذات 7 بتات فقط ، لذلك فإن الرموز المستعملة في URL يجب أن تخضع لهذا . بالإضافة إلى أن بعض هذه الرموز لها معنى خاص في عناوين URL ، على سبيل المثال الرمز (&) يستعمل لفصل الوسائط في سلسلة العنوان المطلوبة . و إذا اضطررت إلى استعمال مثل هذه الرموز يجب عليك أن تشفرها في شكل nn% حيث أن علامة النسبة المئوية توضح أن الرمزين التاليين لها هما القيمة الست عشرية للرمز الأصلي . مثال ذلك علامة الاستفهام إذا كانت موجودة ضمن المعلومات في النموذج فإنها يتم تشفيرها عند إرسالها كعنوان URL في سطر العنوان في المتصفح كالتالي :

%3f

لأن 3f هي القيمة الست عشرية لعلامة الاستفهام في جدول ASCII . أي أنك إذا كتبت كلمة ما تتضمن علامة الاستفهام فيها مثل Sin?gle سوف تجدها في سطر العنوان كالتالي Sin%3fgle .

الترقيم الست عشري (Hex) هو نظام ترقيم يسمح ب 16 رقم صحيح فقط . الأرقام من صفر إلى 9 تظل كما هي ، أما الأرقام من 10 إلى 15 تمثلها الحروف من A إلى F . مثلاً الرقم الست عشري FF يساوي في الترقيم العشري العادي 225 .

الجدول التالي به القيم الست عشرية المقابلة لبعض الرموز الخاصة في URL :

الرمز

القيمة الست عشرية

Space

20

Tab

09

!

21

"

22

#

23

$

24

%

25

&

26

`

27

(

28

)

29

*

2a

+

2b

,

2c

-

2d

.

2e

/

2f

:

3a

;

3b

<

3c

=

3d

>

3e

?

3f

@

40

[

5b

\

5c

]

5d

^

5e

_

5f

`

60

{

7b

|

7c

}

7d

~

7e


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

الآن إلى العنوان في المتصفح . عندما تستعمل طريقة GET لتمرير المعلومات من النموذج فإن المعلومات يتم إضافتها إلى نهاية عنوان URL كسلسلة لتطبيق CGI و مفصولة عن إسم التطبيق بعلامة الاستفهام ؟ و يتم بناء المعلومات في العنوان كأزواج تتكون من name=value أو الاسم=القيمة ، و يفصل كل زوج عن آخر بعلامة & . و كل المسافات في العنوان يتم استبدالها بعلامة الإضافة + . هذه الرموز الثلاثة ؟ & + بالإضافة إلى علامة النسبة المئوية % التي سوف تميز أي رموز مشفرة ، و علامة المساواة = التي تفصل بين الإسم و القيمة في كل زوج ، هؤلاء هم ما ستحتاج إلى التعامل معهم في برنامج البيرل و السي جي آي الذي ستكتبه .

هل تذكر متغير CGI المحيطي QUERY_STRING ؟ قد تكون لم تفهمه عندما قرأته في جدول المتغيرات في الدرس الثالث ، الآن تستطيع فهمه . إنه يحصل على المعلومات القادمة من نموذج هتمل إلى برنامج سي جي آي من خلال طريقة GET .

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

#!perl/bin

# geturl.pl

# A little perl script to read, decode and print the names

# and values passed to it from an HTML form through CGI.

# Get HTML header, ender, define the page title.

require "html.pl"; # Full path.

$Title="Get Information from a URL";

# Get the query string.

$QueryString = $ENV{'QUERY_STRING'};

# Use split to make an array of name-value pairs broken at

# the ampersand character.

@NameValuePairs = split (/&/, $QueryString);

# Put up an HTML header, page title and a rule.

&HTML_Header ($Title);

print "<body>\n";

print "<H1>$Title</H1>\n";

print "<HR>\n";

# Split each of the name-value pairs and print them on the page.

foreach $NameValue (@NameValuePairs)

{

($Name, $Value) = split (/=/, $NameValue);

print "Name = $Name, Value = $Value<BR>\n"

}

# End the HTML document.

&HTML_Footer;

# End geturl.pl

احفظ البرنامج بإسم geturl.pl في فهرس cgi-bin ثم عدل الجملة ACTION=perl.htm في الملف form1.htm إلى المسار الصحيح إلى geturl.pl أنا مثلاً جعلته :

<FORM ACTION="/cgi-bin/geturl.pl" METHOD="GET">


ثم احفظ الملف في فهرس c:\program files\sambar\docs و شغل sambar server ثم شغل الملف form1.htm في المتصفح و أدخل بعض المعلومات في النموذج و لكن هذه المرة استعمل بعض الرموز التي سيتم تشفيرها عن طريق المتصفح عند شحنها من خلال CGI مثل + و ! ، ثم اضغط زر Send Information . يجب أن تكون النتيجة شبيهة لما هو موضح في الصورة التالية مع اختلاف المعلومات التي أدخلتها إلى النموذج بالطبع :




لاحظت بالطبع أن المعلومات المعروضة بواسطة البرنامج الذي كتبناه مليئة برموز غريبة و فواصل حسناً سوف نهتم بذلك في النسخة المعدلة . الآن دعنا نفحص كيف نقسم عنوان URL من سطر واحد إلى سلاسل من أزواج الأسماء و القيم Name و Value .

البطل في هذا البرنامج هو split ، و هي وظيفة قوية في بيرل شكلها العام هو :

split (/PATTERN/, STRING, LIMIT);

حيث PATTERN هي المحدد أو نقطة الفصل بين الأزواج / و في برنامجنا هي & .

أما STRING فهي السلسلة المراد تقسيمها ، و في برنامجنا هي المتغير QueryString$ .

أما LIMIT فهي اختيارية تخبر split ألا تفعل أكثر من انفصالات محددة .

تنتج split مجموعة من السلاسل منفصلة عن بعضها البعض ب PATTERN . و PATTERN توضع دائماً بين شرطتين مائلتين أماميتين ، و لكن يمكن ترك PATTERN إذا أردنا أن نضع مسافة فارغة للفصل بين السلاسل . كذلك يمكن أن يكون PATTERN تعبيراً منتظماً Regular Expression و هو موضوع سنغطيه بالدراسة لاحقاً .

لقد استعملنا المتغير المحيطي QUERY_STRING للحصول على عنوان URL مقدم من form1.htm و قد قسم إلى أزواج من name=value باستعمال split للفصل عند الرمز & . و قد قسمت الأزواج إلى أجزائهم المكونة لهم و وضعت علامة المساواة = بين كل جزء و الآخر كـ PATTERN .

و مع هذا فإن السلاسل لا يزال لديها رموز URL المشفرة و لكي نزيلهم منها سنعدل البرنامج و نضيف إليه سطرين فقط .

قوة التعبيرات المنتظمة Regular Expressions :

غير دوران foreach في geturl.pl للتالي :

foreach $NameValue (@NameValuePairs)

{

($Name, $Value) = split (/=/, $NameValue);

$Value =~ tr/+//;

$Value =~ s/%([\dA-Fa-f][\dA-Fa-f])/ pack ("C", hex ($1))/eg;

print "Name = $Name, Value = $Value<BR>\n";

}

إذا لم تعمل أبداً مع التعبيرات المنتظمة Regular Expressions فإن السطرين الجديدين من المحتمل أن يكونا أعجب الأشياء التي رأيتها في حياتك . و مع ذلك عدل البرنامج ، و املأ الفراغات في form1.htm باستعمال كل الرموز التي تريدها و النتيجة ستكون مشابهة لهذا :


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

السطر الأول الجديد سهل إلى حد ما :

$Value =~ tr/+//;

التعبير العام لها هو :

"$String =~/PATTERN/"

الرمز ~= هو مشغل Operator التناسب ، و يكون صحيحاً إذا كان المتغير String$ يحتوي على ال PATTERN . و بوجه عام هو يبحث في سلسلة المتغير String$ عن النموذج PATTERN الموجود بين الشرطتين التاليتين .

أما tr فهي وظيفة الترجمة Translate ، التي تحول كل الرموز الموجودة بين أول شرطتين مائلتين أماميتين إلى الرموز الموجودة بعدهما . و شكلها العام هو :

tr/SEARCH_LIST/REPLACE_LIST/


حيث SEARCH_LIST هي الرموز التي نريد استبدالها ، و في حالتنا هنا هي علامة الإضافة + . أما REPLACE_LIST فهي الرموز التي سيتم وضعها مكان SEARCH_LIST , و في حالتنا هي فراغ لأننا لم نضع مكانها شيء .

هناك وسائط إختيارية تأتي بعد الشرطة المائلة الأخيرة لوظيفة tr و هم : c و d و s و U و C . نحن لا نحتاجهم في هذه النقطة . و لكن سنبين معناهم للتوضيح :

c: تكون لتكملة الرموز التي نريد استبدالها .

d: تحذف الرموز التي وجدت و لم يتم استبدالها .

s: يسحق الرموز التي تم تغييرها مرتين .

U: يحول من و إلى تنسيق UTF-8 .

C: يحول من و إلى رموز 8 بت .

و هكذا يفحص هذا السطر سلسلة المتغير Value$ و تستبدل كل حدوث لعلامة + بمسافة .

السطر الثاني أكثر حيلة و أصعب في الفهم :

$Value =~ s/%([\dA-Fa-f][\dA-Fa-f])/ pack ("C", hex ($1))/eg;

هذا السطر يحول رموز URL المشفرة أي المسبوقة بعلامة % ، إلى رموز قابلة للطبع .

الوظيفة s هي وظيفة الاستبدال في بيرل و هي مثل tr تأخذ كل شيء تجده في سلسلة المتغير Value$ مناسباً للسلسلة بين أول شرطتان مائلتان و تستبدله بما هو موجود بين الشرطتان المائلتان الثانيتان .

في هذا المثال تم إخبار الوظيفة s أن تبحث علامة % متبوعة برمزين ، كل رمز منهم قيمه محددة بين قوسين مربعين [ ] . الآن انظر داخل القوسين المربعين الأولين ، و هو يخبر s أن الرمز الأول بعد علامة النسبة المئوية % ، إما أن يكون رقم صحيح و يرمز له برمز الهروب متبوع بحرف d أي d\ ، و إما أن يكون حرف من A إلى F أو من a إلى f ، و هي أرقام ست عشرية كما عرفنا تدل على الأرقام من 10 إلى 15 . كذلك القوسين المربعين التاليين يحددان قيم الرمز الثاني بعد علامة % مثل قيم الرمز الأول تماماً بدون أي اختلاف . و هكذا فإن الرمزين بعد علامة % في عنوان URL إما أن يكونا رقم صحيح من صفر إلى 9 أو رقم ست عشري من A إلى F أو من a إلى f أو خليط منهما معاً .

وظيفة pack هي وظيفة تأخذ مجموعة من القيم و تحولها إلى سلسلة باستخدام تعليمات القالب المعطى لها كسلسلة بين علامتي اقتباس و هو في هذه الحالة C . و السلسلة الناتجة تكون مرتبة بنفس تسلسل القيم التي أخذتها وظيفة pack . و القالب C يخبر pack أن تعبيء القيمة في رمز .

وظيفة hex تأخذ التعبير التالي لها (و هي تتوقع أن يكون رقم ست عشري) و تحوله إلى رقم عشري صحيح .

($1) تسمى predefined name أي اسم معرف من قبل ، و هو ذي معنى خاص في بيرل . و هو يعود على الأقواس المربعة التي تحدد قيم الرمزين المشفرين بعد علامة % .

الحرف e في نهاية السطر يوضح للوظيفة s أن كل ما هو موجود في REPLACE_LIST إنما هو تعبير expression و ليس سلسلة . و بدون هذا الحرف فإن الرموز بعد علامة % في المتغير Value$ سوف يتم استبدالها حرفياً بـ :

pack ("C", hex ($1))

و لن يتم استبدالها بنتيجة هذا التعبير و إنما بالتعبير نفسه .

الحرف g بعد e يخبر s أن تقوم باستبدال شامل أي أن تستبدل كل مثال من SEARCH_LIST تجده في Value$ بما تم حسابه في التعبير الموجود في REPLACE_LIST . و إذا تركت هذا الوسيط جانباً فإن s قد تقوم بالعملية في أول تكرار ثم تقف .

القاعدة التي ستراها غالباً في التعبيرات المنتظمة هي استخدام 1$ و 2$ , 3$ إلى آخره ، هذه المتغيرات العددية تتطابق من اليسار إلى اليمين مع التعبيرات بين الأقواس في SEARCH_LIST . على سبيل المثال السلسلة :


19 May 1997

قد تنقسم إلى أجزائها كالتالي :

$String =~ /(..)(...)(....)/;

$day = $1;

$month = $2;

$year = $3;

و لكن ضع في اعتبارك أن هذه المتغيرات مساوية للتعبيرات المنتظمة و ليس للحروف و الأعداد ، بل أياً كان الغرض من التعبير المنتظم فإن نتيجته سوف يعبر عنها المتغير 1$ ... إلخ .

أنت محق : التعبيرات المنتظمة صعبة :

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


الدرس السادس



في الدرس السابق قمنا بعمل نموذج هتمل HTML Form يمكن لزائريك إدخال المعلومات فيه وإرسالها إلى برنامج بيرل عبر السي جي آي . و مع ذلك فقد كان هذا تدريب بسيط ، فأنت قد أرجعت المعلومات كما هي للزائر .

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

أفضل طريقة لتتعلم شيئاً ما هي أن تفعله بنفسك ، دعنا نقوم بعمل نموذج استفهام بسيط و بذلك يمكننا رؤية كيف يعمل . اكتب صفحة هتمل التالية و احفظها بإسم quiz.htm :

<html dir="rtl">

<head>

<title>Quiz Form</title>

</head>

<body>

<H1 ALIGN="CENTER">A Little Quiz Form</H1>

<HR>

<H3 ALIGN="RIGHT">في كل فئة اختر ما يناسبك أو يناسب تفضيلاتك</H3>

<FORM ACTION="/cgi-bin/quiz.pl" METHOD="POST">

<table>

<tr>

<td VALIGN="top">

<B>الجنس</B><BR>

<INPUT TYPE="radio" NAME="gender" VALUE="0">ذكر<BR>

<INPUT TYPE="radio" NAME="gender" VALUE="1">أنثى<BR>

<INPUT TYPE="radio" NAME="gender" VALUE="2">غيرهما<BR>

</td>

<td VALIGN="top">

<B>العمر</B><BR>

<INPUT TYPE="radio" NAME="age" VALUE="0">12-18<BR>

<INPUT TYPE="radio" NAME="age" VALUE="1">19-25<BR>

<INPUT TYPE="radio" NAME="age" VALUE="2">26-30<BR>

<INPUT TYPE="radio" NAME="age" VALUE="3">أكبر من 30<BR>

<INPUT TYPE="radio" NAME="age" VALUE="4">شيخ قبيلة<BR>

</td>

<td VALIGN="top">

<B>فيلمك المفضل</B><BR>

<INPUT TYPE="radio" NAME="film" VALUE="0">Matirx<BR>

<INPUT TYPE="radio" NAME="film" VALUE="1">Gladiator<BR>

<INPUT TYPE="radio" NAME="film" VALUE="2">Mission Impossible2<BR>

<INPUT TYPE="radio" NAME="film" VALUE="3">الكيت كات<BR>

<INPUT TYPE="radio" NAME="film" VALUE="4">الإرهاب و الكباب<BR>

<INPUT TYPE="radio" NAME="film" VALUE="5">ليس فيهم<BR>

</td>

<td VALIGN="top">

<B>هل تعتقد أن عادل إمام قد صار كبيراً على التمثيل</B>

<INPUT TYPE="checkbox" NAME="OldAdil">

</td>

</tr>

</table>

<h3 ALIGN="RIGHT">معلومات اختيارية</h3>

<B>الإسم</B><BR>

الأول<INPUT TYPE="text" NAME="firstname" SIZE="16">

الأخير<INPUT TYPE="text" NAME="lastname" SIZE="16"><BR>

<BR>

<CENTER>

<INPUT TYPE="submit" VALUE="إرسل">

<INPUT TYPE="reset" VALUE="إمسح">

</CENTER>

</form>

</body>

</html>

المفترض أن يبدو الشكل كما في الصورة :


هذا الشكل يستعمل أزرار راديو و صندوق اختيار و صندوقين للنص ، و لذلك سيعطي برنامج بيرل مزيج جيد نوعاً ما من أنواع المداخل المختلفة ، بالإضافة إلى أنه يستعمل طريقة POST لتمرير المعلومات بدلاً من طريقة GET التي استعملناها في الدرس السابق . و كما ترى فقد حفظته في فهرس Docs في Sambar في Program files .

الآن سنقوم بعمل تعديلات بسيطة على برنامج geturl الذي كتبناه في الدرس السابق . الفرق الرئيسي بين طريقتي GET و POST هو في كيفية تمرير المعلومات ، GET تضع المعلومات في عنوان URL بالفعل و تشحنها إلى المحيط و يمكنك رؤيتها في صندوق العنوان في المتصفح ، بينما POST تضع المعلومات في مجرى مدخل برنامج بيرل ، كما لو كنت تكتب المعلومات في الداخل من لوحة المفاتيح . لذلك فإن برنامج geturl سوف يحتاج إلى تعديلين لمجاراة الاختلافات :

# Get HTML header, ender, define the page title.

require "/cgi-bin/html.pl"; # Full path.

$Title = "GEt POST Information From a URL";

# Get the length of the data.

$DataLen = $ُENV{'CONTENT_LENGTH'};

# Read the data from standard input.

read (STDIN, $QueryString, $DataLen);

# Use split to make an array of name-value pairs broken at

# the ampersand character.

@NameValuePairs = split (/&/, $QueryString);


أضف السطور السابقة الموضوع أمامها السهم إلى الملف و احذف السطرين :

# Get the query string.
$QueryString = $ENV{'QUERY_STRING'};

و احفظه بإسم quiz.pl في cgi-bin بالطبع .

STDIN و POST :

لأن معلومات النموذج تأتي من المدخل الأساسي بطريقة POST فيمكنك استعمال وظيفة read لتدخلها في برنامجك . و للاختصار وظيفة read تأحذ هذا الشكل :

read (HANDLE, BUFFER, LENGTH);

حيث HANDLE هو توجيه الملف كما عرفنا . و BUFFER هو متغير عددي للإمساك بأي شيء يقرأه . و LENGTH هو عدد الرموز أو البايتات التي ستقرأ في الذاكرة المؤقتة . و لكي تحصل على قيمة HANDLE فإن بيرل يجعل هذا سهلاً ، ففي كل مرة تشغل فيها برنامج بيرل يعلن مسبقاً عن وجود مجموعة من توجيهات الملف التي تسمح لبرنامجك بالتفاعل مع نظام التشغيل و فتح و إغلاق الملفات ، و من بين هذه التوجيهات :


STDIN و هو طريق المدخل الرئيسي .

STDOUT و هو طريق المخرج الرئيسي .

و كما ترى فإن STDIN مفتوح لك بالفعل كل ما عليك هو أن تستخدمه . و أخيراً يجب عليك أن تخبر read بعدد البايتات الموجودة ليقرأها ، و لحسن الحظ فإن محيط CGI يحتوي على متغير به نفس المعلومات المطلوبة في read و هو المتغير CONTENT_LENGTH . و نتيجة لكل هذه المساعدة من بيرل و سي جي آي يصبح لديك القليل لتفعله في تعديل البرنامج ، عليك أن تحصل أولاً على طول المعلومات و هذا يتم بالسطر :

$DataLen = $ُENV{'CONTENT_LENGTH'};


ثم تستعمل هذا الطول في قراءة المعلومات من المدخل الرئيسي في متغير محلي عددي (و هو BUFFER في الصيغة العامة أو QueryString في برنامجنا) :

read (STDIN, $QueryString, $DataLen);

الآن بعد أن فهمت عمل ما أضفت من سطور ، شغل المتصفح (تأكد من تشغيل Sambar Server) و في صندوق العنوان اكتب localhost/docs/quiz.htm ثم املأ النموذج بما ترغب و اضغط زر إرسل ، و سوف تكون النتيجة في الغالب مشابهة لهذه :


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

#!perl/bin

# quiz.pl

# A little perl program script to read, decode and print the names
# and values passed to it from an HTML form through CGI.

# Get HTML header, ender, define the page title.



require "htmlara.pl"; # Full Path.

$Title = "تفضيلاتك الشخصية";

$MaxData = 6;

# Assign names to indexes to make them more descriptive.

($Sex, $HowOld, $FaveFilm, $OldAdil, $LastName, $FirstName) = (0..5);

# Set up a flag for the OldAdil checkbox.

$OldAdil = 1;

# Set up a series of arrays to handle the form data.

@Gender = ("ذكر", "أنثى", "غيرهما");

@Age = ("12-18", "19-25", "26-30","أكبر من 30", "شيخ قبيلة");

@Film =

(

"Matrix",

"Gladiator",

"Mission Impossible2",

"الكيت كات",

"الإرهاب و الكباب",

"ليس فيهم"

);

# Get the length of the data.

$DataLen = $ENV{'CONTENT_LENGTH'};

# Read the data from standard input.

read (STDIN, $QueryString, $DataLen);

# Use split to make an array of name-value pairs broken at

# the ampersand character. then get the values.

@NameValuePairs = split (/&/, $QueryString);

$n = 0;

foreach $NameValue (@NameValuePairs)

{

($Name, $Value[$n]) = split (/=/, $NameValue);

$n++;

}

# Set or clear $OldAdil flag based on the number of pairs

# counted in $n. The checkbox value won't be sent if it's

# not checked. Adjust indexes too.

if ($n != $MaxData)

{

$OldAdil = 0;

$FirstName--;

$LastName--;

}

# Put up an HTML header, page title and a rule.

&HTML_Header ($Title);

print "<body>\n";

print "<H1>$Title</H1>\n";

print "<HR>\n";

# Print the information in a friendly manner.

print "<H3>اسمك ";

# See if anything has been entered in the name.

if (($Value[$LastName] eq "") && ($Value[$FirstName] eq ""))

{

print "غير معروف\n";

}

else

{

print "$Value[$FirstName] $Value[$LastName]\n";

}

print "</H3>\n";

print "<H3>جنسك $Gender[$Value[$Sex]]</H3>\n";

print "<H3>عمرك $Age[$Value[$HowOld]]</H3>\n";

print "<H3>فيلمك المفضل هو ";

print "\"$Film[$Value[$FaveFilm]]\"</H3>\n";

print "<H3>أنت ";

if (!$OldAdil)

{

print "لا ";

}

print "ترى أن عادل إمام قد صار كبيراً على التمثيل </H3>\n";

# End the HTML document.

&HTML_Footer;

# End quiz.pl



احفظه بإسم quiz.pl في فهرس cgi-bin ثم شغل النموذج من المتصفح و املأه و اضغط على زر إرسل ، سترى شيئاً مثل هذا :


هذا هو أكبر برنامج نكتبه حتى الآن ، و الآن إلى الشرح :

في أول البرنامج استدعينا الملف htmlara.pl و هو نفس الملف html.pl ما عدا أن واصفة <html> فيه تدعم العربية أي تجعل اتجاه الصفحة من اليمين إلى اليسار ، و هذا مهم لكي يستطيع البرنامج أن يرسم صفحة ويب عربية ، كل ما عليك هو أن تفتح الملف html.pl و تعدل الواصفة <html> في أوله إلى :

<html dir="rtl">

و احفظه بإسم htmlara.pl .

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

أول سطر جديد في البرنامج يعكس جزءاً هاماً من المعلومات التي تحتاجها ، و هو عدد الفئات التي تتوقع استقبالها . أي عدد فئات أزرار الراديو التي تتوقعها :

$MaxData = 6;

فأنت تبحث عن الفئات التالية :

1- الجنس . 2- العمر . 3- الفيلم المفضل .

4- رأيه في عادل إمام . 5- الإسم الأول . 6- الإسم الأخير .

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

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

($Sex, $HowOld, $FaveFilm, $OldAdil, $LastName, $FirstName) = (0..5);


و لاحظ أننا وضعنا اختصار للأرقام بدلاً من كتابة كل رقم أمام اسم المتغير الخاص به . هكذا يمكنك فهم لماذا يجب أن نتأكد من الرقم الفعلي للفئات المرسلة ، لأن صندوق الاختيار إذا لم يتم تحديده لن يرسل أي شيء و بالتالي فإن المتغير التالي عليه سيأخذ رقمه و تصبح النتيجة أن يكتب البرنامج في النهاية مثلاً أن العمر = الكيت كات .

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

$OldAdil = 1;

مــلــحــوظــة : العلم Flag في لغة البرمجة هو قيمة إما صحيحة أي تساوي واحد و إما خاطئة أي تساوي صفر ، تعرف هذه القيم بإسم قيم Boolean و هي على إسم عالم رياضيات بريطاني يسمى George Boole عاش في القرن التاسع عشر و اخترع جبراً مبنياً على المنطق الرمزي .

الجزء التالي من الشفرة سهل فهمه :



@Gender = ("ذكر", "أنثى", "غيرهما");

@Age = ("12-18", "19-25", "26-30","أكبر من 30", "شيخ قبيلة");

@Film =

(

"Matrix",

"Gladiator",

"Mission Impossible2",

"الكيت كات",

"الإرهاب و الكباب",

"ليس فيهم"

);


فأنت تريد أن تطبع أوصاف القيم التي أدخلها زائرك في النموذج لذلك فأنت تضاعف النموذج في مجموعات لكل فئة زر راديو .

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

بعد ذلك يشحن البرنامج أزواج الإسم = القيمة Name = Value من المعلومات المرسلة له و لكن هناك اختلاف بسيط :

@NameValuePairs = split (/&/, $QueryString);

$n = 0;

foreach $NameValue (@NameValuePairs)

{

($Name, $Value[$n]) = split (/=/, $NameValue);

$n++;

}

هنا أسسنا متغير جديد هو n$ أعددنا قيمته تساوي صفر ، و هو عداد بيس فقط لعد رقم الفئات المرسلة إلى البرنامج و لكن كفهرس في مجموعة من كل القيم في أزواج Name = Value . أنت لا تحتاج للأسماء لأنك بالفعل تعرفهم ، و لكنك تحتاج متغير زائف لكي يمسك مكان الجانب الأيسر من الانقسام من NameValue$ . و بالتالي تكون Value[$n$] أول عنصر عددي من مجموعة Value@ على أول مرور من خلال كتلة foreach .

السطر التالي عليها يضيف n$ مع المشغل ++ لذلك فسوف تكون مساوية لواحد على المرور الثاني و 2 على الثالث و هكذا ، الآن أنت لديك مجموعة مليئة بكل القيم التي تم إرسالها من النموذج . و كذلك لديك تعداد للقيم في n$ و هذا التعداد هو كيفية تحديد ما إذا كان صندوق الاختيار الخاص بعادل إمام قد تم تحديده أو لا .

الجزء التالي يقول :



if ($n != $MaxData)

{

$OldAdil = 0;

$FirstName--;

$LastName--;

}

إنه إذا كان n$ لا يساوي MaxData$ راجع الدرس الرابع لتذكر مشغلات المقارنة فصندوق تحديد عادل إمام سوف يكون قيمته صفر أي أنه غير محدد و بالتالي سينقص FirstName$ و LastName$ واحد في الأرقام المقابلة لهم في النموذج حتى يشيرا إلى الفئة الملائمة لهم و لا يحدث خطأ ، و هذا بمشغل التناقص -- .

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



print "<H3>اسمك ";

# See if anything has been entered in the name.

if (($Value[$LastName] eq "") && ($Value[$FirstName] eq ""))

{

print "غير معروف\n";

}

else

{

print "$Value[$FirstName] $Value[$LastName]\n";

}

جملة if تختبر عناصر FirstName$ و LastName$ في مجموعة Value@ لكي ترى إذا كانوا خاليين (السلاسل الفارغة يشار إليها بعلامتي اقتباس لا شيء بينهما "" و علامة المقارنة eq التي تعني يساوي راجع الدرس الرابع و كل جملة موجودة بين قوسين ، و يربط بين الجملتين العلامة && التي تعني مشغل (و) (AND) المنطقي . و بالتالي يكون معنى الجملة : إذا كانت الجملة الأولى صحيحة و الثانية صحيحة إذاً نفذ الشفرة التي في الكتلة .

مــلــحــوظــة : يوجد في بيرل كذلك مشغل (أو) (OR) المنطقي و يمثله العلامة || .

الجملة التالية else تقول أنه في حالة كذب جملة أو جمل if بأعلى نفذ كتلة شفرتي . هناك تنوع else يمزج الجملتين الشرطيتين و يبدو مثل هذا :

if (هذا صحيح)

{

افعل هذا;

}

elseif (ذلك صحيح)

{

نفذ ذلك;

}

else

{

نفذ شيئاً آخر;

}

الجدير بالاهتمام في كتلة if-else أيضاً هو الطريقة التي يتم بها طبع الأسماء :

print "$Value[$FirstName] $Value[$LastName]\n";

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

$Value[$LastName]

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

$Gender [$Value [$sex]]=$Gender[1]="أنثى"

لاحظ أن جملة print التي تطبع فيلمك المفضل بها علامات اقتباس هاربة "\ لأننا نريد لعلامات الاقتباس أن تظهر حول اسم الفيلم في صفحة هتمل .

أخر كتلة شفرة ننظر فيها هي :



print "<H3>أنت ";

if (!$OldAdil)

{

print "لا ";

}

print "ترى أن عادل إمام قد صار كبيراً على التمثيل </H3>\n";


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