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

 

 

الدرس الخامس

 

 

 

ابتكار نماذج هتمل فعلية مع 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 الموجود في سطر العنوان في المتصفح بعد الضغط على زر 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$ ... إلخ .

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

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

و سوف تتعلم بعض التفاصيل الصعبة للتعبيرات المنتظمة في هذا المقال الذي وجدته على الإنترنت في هذا الموقع و هو أسهل مقال تعليمي عن التعبيرات المنتظمة وجدته حتى الآن و قد ترجمته إلى العربية لتعم الفائدة بإذن الله .

 

 

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

الدرس السادس