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

 

 

الدرس السادس

 

 

 

في الدرس السابق قمنا بعمل نموذج هتمل 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 مفتوح لك بالفعل كل ما عليك هو أن تستخدمه . و أخيراً يجب عليك أن تخبر 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) المنطقي . و هذه الجملة تقول أنه إذا لم يكن صندوق اختيار عادل إمام محدداً اطبع كلمة (لا) قبل الجملة الأخيرة أما إذا كان محدداً فإطبع الجملة الأخيرة وحدها .

 

 

 

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