ובכן מה עליך לדעת? זה לא מסובך – פשוט עקוב אחרי הכללים הבסיסיים. כלל מספר 1: עליך תמיד לשים את השורה הבאה בראש הסקריפט שלך –
#!/usr/local/bin/perl
שורה זו אומרת לשרת המריץ את הסקריפט שלך שמה שהולך לרוץ זה לא טורקית עתיקה אלא Perl. השרת אוהב את שפת Perl – הוא רק צריך לדעת שבה אנו עוסקים , לכן אל תשכח לפתוח בשורה זו. אחרת תבזבז שעות בנסיון להבין מה לא בסדר עם הסקריפט הטוב שלך רק בכדי לגלות כי שכחת את הדבר הבסיסי ביותר.
כלל מספר 2: תמיד שים נקודה-פסיק (;) בסופה של כל שורה. אם לא תעשה כן- אין סיכוי כי תצליח להריץ את הסקריפט שלך.
כלל מספר 3: הוסף הערות היכן שרק תוכל. מהן הערות? הערות הן משפט שלם המתאר מה הסקריפט שלך עושה בנקודה מסויימת. כל שורה המתחילה בסימן "#" היא שורת הערה. מלבד חריג אחד שזהו כלל מספר 1. שים לב לדוגמא מתחת על מנת להבין מדוע השימוש בהערות יכול להועיל.
# In the following code, I'm going to create a variable that contains
# the info that will go into a log. But I'm going to keep the
# formatting really simple so it'll be displayed in
# an easy-to-read fashion.
my $in{'logdata'} = <<END;
$in{'name'}
$in{'formelement1'} | $in{'radiobutton2'}
$in{'checkbox1'} | $in{'checkbox2'}
END
כמחבר הסקריפט הזה אתה בוודאי יודע את מטרת המשתנה, אבל מה אם מישהו אחר יצטרך לעבוד עם הסקריפט הזה? אתה לא רוצה שהוא יבזבז את שארית חייו בנסיון לפענח את הקוד חסר ההערות שלך (אלא אם כן משלמים לו לפי שעה…). לכן נסה להקל על האחרים , בעזרת הכנסת הערות.
כלל מספר 4: קוד נקי הוא קוד הניתן לתחזוק. כתיבת קוד נקי הוא מעין חוק אזרחות טובה , כמו כלל מספר 3. רק מפני שאתה יכול לכתוב משהו כמו זה:
for ($i=0;$i<=$#blah;$i++){if ($blah~=/punk boy/g;)
{print "I hate this code";}else { print "nappy";}}
…זה לא אומר שעליך לעשות כן. לא שזה מכיל שגיאות אבל זה קשה לקריאה , מיותר לציין כי זה פשוט מכוער. אפילו עם הערות, יקח למישהו ימים בכדי להבין שיש פה בעצם לולאת for הרצה על פני מערך ה “blah” ומחפשת בו את הצירוף "punk boy". אם הצירוף קיים יודפס "I hate this code" ואם לא- יודפס "nappy". זה יהיה הרבה יותר יפה ופשוט להבנה אם תעשה זאת כך:
for ($i = 0; $i <= $#blah; $i++) {
if ($blah ~= /punk boy/g;) {
print "I hate this code";
}else {
print "nappy";
}
}
קדימה לעניינים
כעת אתה יודע את הדיברות 11 עד 14. ובכן,מספיק עם הכללים , מעולם לא אהבתי יותר מדי חוקים – הם רק גרמו לי להשלח למשרד המנהל כל הזמן. אז בוא ונלמד קצת Perl בסיסי.
אם השתמשת בעבר בשפת תכנות אחרת אז אתה בוודאי מכיר את משפטי התנאי if/else.
אם לא , אז הרי לך הסבר קצר: משפטי התנאי if/else בודקים אם תנאי מסויים הוא נכון או לא , אם הוא נכון אז הסקריפט יבצע את החלק של ה "if" , אחרת יבוצע החלק של ה "else” , די מגניב , הא?
הנה לך דוגמא כיצד יש לרשום משפט תנאי if/else :
if (statement) {
task
} elsif (statement) {
a different task
} else {
a task if all else fails
}
ובכן ברגע שהבנת את הרעיון הבסיסי של משפטי התנאי if/else , אתה מוכן לחקור את העולם המופלא של המשתנים
סקלארים , מערכים ומערכים אסוציאטיבים
כל המשתנים ב Perl הם מאחד הסוגים הבאים: סקלרים , מערכים , או מערכים אסוציאטיבים. ובכן מה ההבדל? סקלאר (scalar) תופס הכל – הוא יכול להכיל מספרים , אותיות , ביטויים , ועוד. תמיד יהיה סימן של $ (דולר) לפניו. לכן אם ברצונך לבצע השמה של ערך למשתנה stuff$ , תעשה זאת כך:
A word: $stuff = "rules";
A phrase: $stuff = "Colin Rules!";
Numbers: $stuff = 2;
אתה אפילו יכלו לחבר ולהחסיר כך:
$stuff = 2 + 2;
$stuff = 4 - 2;
במקרה זה stuff$ יהיה שווה ל 4 ואח"כ ל 2 (בהתאמה).
השמה לתוך משתנים תמיד תתצבע משמאל לימין. – להלן דוגמא לשגיאה קטלנית:
2+2=$stuff;
משתנה מסוג מערך זהו משתנה שמחזיק כמה משתנים מסוג סקאלר בתוך חריצים ממוספרים. ניתן להוסיף חריצים ככל הנדרש כך שהמשתנה יכול לגדול בצורה דינאמית. הוא גם יכול להתכווץ – אבל זה סתם בזבוז זמן. למשתנה מסוג מערך בד"כ יהיה @ (at symbol) לפניו. כאשר מצהירים על חריצים בנפרד כיחידים נשתמש בסימן $.
אתה יכול להצהיר על כמה חריצים שרק תרצה בצורה הבאה:
@stuff = ("1","2","ten","Colin Rules","Perl's for winners");
על מנת להגיע לכל חריץ נקרא לו ע"י המספר שלו. לכן = "2000000";
שים לב כי ל- ,$stuff,$stuff";
}
בלולאת ה for אתה מגדיר משתנה אשר קיים אך ורק בלולאה. זה לא חייב בהכרח להקרא I$, אבל זה נקרא כך בגלל incremental ז"א משתנה הנועד לגדול בכל איטרציה. הגדרתי את המשתנה I$ להיות שווה ל 0. אח"כ אמרתי ללולאה להמשיך לרוץ כל עוד &I קטן או שווה למספר החריצים במערך stuff@. לאחר מכן הוריתי לו להוסיף 1 ל I$ בסוף כל מעבר דרך הלולאה. אח"כ הסקריפט צריך להדפיס את החריץ במערך stuff@ ש I$ מייצג. לכן במעבר הראשון של הלולאה יודפס stuff$ , במעבר השני יודפס stuff$. בצורה זו הלולאה תמשיך עד אשר התנאי לא יתקיים יותר. כמה שאני אוהב את זה , האישה המושלמת בעיניי היא אחת שרושמת לולאות for קטלניות ומקשיבה לשירי ה pixies כל היום.
לולאת ה While: לולאת ה while דומה ללולאת ה for אך אינה "עצמאית" (self-contained) , זה נראה כך:
$stuff = <NAMES>;
while ($stuff ne "bob") {
print "$stuff";
$stuff = <NAMES>;
}
קטע קוד זה מריץ את המשפט שבתוך הלולאה כל עוד המשתנה stuff$ לא שווה ל “bob” . בלולאה מסוג זה ישנו הסיכון הגדול ביותר בכניסה ללולאה אינסופית, כי היא אינה מסתמכת על בדיקת ערך לעצירה כפי שעושה לולאת ה for. יתרה מכך, עליך להגדיר משתנה מחוץ ללולאה ולשנות ערכו בתוך הלולאה איפשהו (טריקי..)
לולאת Foreach:
לולאות Foreach הן די מגניבות , הן מעין גירסה עצלה של לולאת ה for , הנה , תעיף מבט בעצמך:
foreach $slotnum (@stuff) {
print "$slotnum";
}
חריץ, חריץ בכל פעם , לולאה זו לוקחת את הערך הנמוך ביותר ושמה אותו ב slotnum$ אשר ישמש כמשתנה wild-card מאוחר יותר. לכן מערך stuff@ יתחיל מחריץ מספר 0 וילך כל הדרך לחריץ מספר 100 (אם יש כזה). או שיעצר אם יגמרו החריצים. לולאת ה Foreach הינה שימושית להרצה על מערכים אסוציאטיבים מכיוון שהחריצים שם אינם ממוספרים. התבונן בדוגמא הבאה:
foreach $slotname (keys (%stuff)) {
print "$stuff{$slotname}";
}
קטע קוד זה תופס את ערך המפתח של מערך stuff% ומתקדם לערך הבא בכל פעם. (כבר שכחת מהם מערכים אסוציאטיביים? חזור לעמוד 4 ולא תקנס). זה מתבצע בעזרת פונקציה קיימת של Perl הנקראת keys ואז מדפיס החוצה את הערך של כל חריץ. אל דאגה: עוד נגיע להדפסות ,
בינתיים : wax on,wax off,wax on,wax off … מעולה, אתה כמעט ומוכן ל Perl , אבל יש לך עדיין כמה מניפולציות ללמוד.
…קצת מניפולציות
ובכן, ללא חומר עליו ניתן לבצע את כל הפעולות שלמדת היום בעצם חבל לך על הזמן. ובכן כיצד ניתן להשיג חומר כזה? ישנו פתרון קסם מופלא עבור כך ושמו : קלט ופלט (Input and Output). ישנם 2 סוגים עיקריים של קלט ופלט :
א. קלט ופלט המשתמש ב. קובץ קלט ופלט
קלט משתמש הינו קלט המתקבל כאשר המשתמש אומר באופן מפורש לסקריפט שלך לבצע משהו. פלט משתמש זה כאשר הסקריפט "מדבר" ישירות מול המשתמש. וכל זאת מתבצע בעזרת אמצעים הנקראים קלט סטנדרטי ופלט סטנדרטי (Standard Input and Standard Output).
הקלט נקרא ע"י קריאת מזהה הקובץ (File Handle) , למרות שהקלט הסטנדרטי איננו קובץ הוא מטופל בצורה זהה כפי שמטופל קובץ קלט , אתה תראה זאת שנגיע ל קבצי קלט ופלט. קריאה מקלט סטנדרטי מתבצעת כך:
$usersaid = <STDIN>;
מזהי קובץ (file handles) נכתבים תמיד באותיות גדולות ולכן קל לזהות אותם. מזהי הקובץ הינם ייצוג של קובץ פתוח עבור הסקריפט. קלט סטנדרטי ופלט סטנדרטי נחשבים תמיד כפתוחים ולכן אין לך צורך לדאוג לפתוח אותם כפי שעליך לעשות עם קבצים רגילים כפי שתראה בהמשך.
ההצהרה $stuff = <INPUT>; קוראת שורה אחת של קלט לתוך המשתנה $stuff ממזהה הקובץ INPUT.
לעומת זאת השורה $usersaid = <STDIN>; תקרא שורת קלט מן המשתמש ותכניס זאת למשתנה usersaid$. פקודת ה print שאותה ראית בדוגמאות קודמות שלי היא הגישה הסטנדרטית עבור הוצאת המידע. ברירת המחדל עבור פקודת print הינה הדפסה לעבר הפלט הסטנדרטי (standard output) ולכן אין צורך לציין זאת עבורה כפי שמתבצע עבור מזהי קובץ (File Handles) אחרים. בכדי להדפיס למסך בחזרה את מה שהתקבל ממנו נבצע : ;"print "$usersaid
ובכן עם הכלים שכבר יש בידך אתה יכול לחבר סקריפט עבור משחק ניחוש קטנטן:
#!/usr/local/bin/perl
print "\nPlease enter a number: ";
$guess = <STDIN>;
while ($guess != 20) {
print "\nSorry! You guessed wrong sucka! Guess again!";
$guess = <STDIN>;
}
print "Damn! You got it!";
בעזרת השימוש בלולאת ה while אנו בודקים את הקלט מן המשתמש $guess וממשיכים בלולאה עד לניחוש הנכון (20). והאמן לי קוד זה איננו הדבר המרגיז ביותר שביכולתך לכתוב , שים לב כי התו /n משמש עבור שורה חדשה ב unix.
ביכולתך לעבוד גם עם קבצי קלט ופלט , וזאת נראה בשלבים הבאים. תחילה עליך לפתוח את הקובץ ע"י מתן שם למזהה הקובץ ומסירת הנתיב המלא של הקובץ.
לדוגמא- open (NAMES, "/usr/people/ferm/names.txt"); ברגע שהקובץ פתוח אתה יכול להתחיל לקרוא ממנו שורה,שורה כפי שעשית עם קלט המשתמש. וזה מתבצע כך:
$fileinput = <NAMES>;
ע"י אחסון הקלט בכל פעם למשתנה סקאלארי , או שניתן להכניס את כל הקלט כולו לתוך מערך שבכל חריץ תמצא שורה אחרת מהקלט , זה יתבצע כך:
@fileinput = <NAMES>;
בקיצור, עליך לפתוח קובץ קלט , לקרוא ממנו שורה,שורה לתוך משתנים או בבת אחת הכל למערך ובסוף עליך לסגור את מזהה הקובץ – וזה מוביל אותי לכלל מס' 7
כלל מספר 7: אין אפשרות לכתוב ולקרוא מאותו הקובץ באותו הזמן ולכן עליך לבצע סגירה בסיום השימוש בו לקלט\פלט , זה מתבצע כך: close(NAMES);
ישנם 2 מצבי כתיבה לקובץ : מצב אחד נקרא כתיבה (writing) ומצב שני נקרא הוספה (appending). במצב כתיבה אנו מבצעים כתיבה לתוך הקובץ ומוחקים את תוכנו הקיים (המידע "נדרס") ואם הקובץ כלל לא קיים אז הפקודה מייצרת אותו ואז כותבת לתוכו את המידע הנכתב. במצב הוספה הכתיבה מתבצעת בסופו של התוכן של קובץ קיים (לא מתבצעת "דריסה").
כתיבה (Writing) :
open (OUTFILE, ">/usr/people/ferm/perllog.txt");
הוספה (Appending) :
open (OUTFILE, ">>/usr/people/ferm/perllog.txt");
ברגע שהחלטת באיזה מצב ברצונך לכתוב לקובץ עליך להדפיס לתוכו את המידע וזאת מתבצע בעזרת פקודת print בדומה לזאת שביצעת אל מול הפלט הסטנדרטי. השוני היחיד הינו בכך שעליך לציין את מזהה הקובץ אליו אתה רוצה לכתוב בין הפקודה עצמה לבין המידע אותו ברצונך לכתוב.
וזה מתבצע כך:
print OUTFILE "Here's a line of output";
איך שהתינוק שלנו גדל..
מצויין , כמעט ויש לך את זה… הנה כבר הפכת מתינוק לנסיך perl של ממש. אבל בתור נסיך יש לך צורך בסוגי נשק נוספים , הנה כמה "כלי נשק" נוספים שיעזרו לך :
פיצול בבקשה… :
פיצול (splitting) הינה פונקציה אשר תחסוך לך זמן וכסף רב. (טוב , לפחות זמן..)
פונקציית split מחפשת תבנית מסויימת בתוך מחרוזת ומפצלת את המחרוזת לתוך מערך על בסיס אותה תבנית , התבונן בדוגמא הבאה:
#!/usr/local/bin/perl
# I have a string.
$stuff = "Colin is so cool";
# I decide that I want to split it up by spaces into an array.
@stuff = split (/ /, $stuff);
# I then want to print out each slot on a different line.
for ($i = 0; $i <= $#stuff; $i++) {
print "Slot $i: $stuff\n";
}
# Find out how many words there were like this.
print "There were $#stuff words.\n";
שחק קצת עם כלי זה ותיווכח בעצמך כמה יעיל הוא עשוי להיות.
חפש והחלף:
כלי היעיל במיוחד עבור תיקון שגיאות כתיב במחרוזות. וכך זה עובד :
כתוב =~ s/searchstring/replacestring/gi; אחרי המחרוזת עליה ברצונך להריץ חיפוש\החלפה. עליך להחליף את searchstring ואת replacestring במחרוזות עליהן אתה רץ. וזה מתבצע כך:
$stuff =~ s/bad/bad bad leroy brown/gi;
ובכן, אם ברצוני לתקן את כל שגיאות ה "e”-ים שלפני ה "i”-ים אעשה זאת כך:
# I have this string:
$stuff = "beleive releive greive";
# I want to fix all the mistakes.
$stuff =~ s/ei/ie/gi;
# Then I want to print out the output.
print "$stuff";
החלק היפה בכלי זה שניתן להשתמש בו ב 2 צורות שונות. בסוף הפקודה ישנם 2 אותיות : "g" ו "i" – אלו בעצם 2 אופציות: "g" אומר לפקודה לחפש ולהחליף את כל ההופעות של המחרוזת. "i” אומר לפקודה להתעלם מ case sensitive . ישנה אופציה נוספת והיא "o" אשר באה במקום "g" ואומרת להחליף רק את ההופעה הראשונה. ניתן להשתמש באחת, כולם או אף אחת מן האופציות של פקודה זו.
ולבסוף , ביכולתך להשתמש בפקודה זו אפילו על מנת לקבוע אם קיימת תת מחרוזת בתוך מחרוזת כלשהי. נניח שברצונך לבצע משהו אך ורק אם תת המחרוזת "cool" נמצאת במחרוזת שלך, אז הדרך הקשה שאתה כבר מכיר זה לפצל את המחרוזת לכל המילים שבה ע"י התו המפריד ואז לרוץ עם לולאה על גבי המערך עם המילים ולחפש את המילה "cool".
אבל ישנה דרך קלה יותר לחיפוש מהיר :
$stuff =~ /cool/
משפט זה יחזיר ערך אמת אם המילה "cool” נמצאת במחרוזת וערך שקר אם היא איננה נמצאת במחרוזת. כמובן שניתן לבצע את ההיפך על ידי:
$stuff != /cool/
משפט זה יחזיר אמת אם המילה "cool" איננה נמצאת במחרוזת.
אתה יכול לשלב זאת בתנאי if בצורה כזו:
if ($stuff =~ /cool/) {
statements
}
ובכן אתה עדיין פה? זה סימן שאתה מרותק ומוקסם מעולם ה perl , ובכן עדיין לא סיימנו – המשך הלאה על מנת לראות כיצד הופכים את הסקריפט ל CGI.
הפיכת Perl ל CGI.
ובכן כעת יש בידך את הכלים הבסיסיים של שפת פרל (perl) ובוודאי ברצונך ליישם ידע זה בעבודה אמיתית. ובכן עליך לדעת כי הכרת פרל (perl) זה דבר אחד אבל להפוך את זה לסקריפט מגניב של CGI זה כבר דבר אחר לגמרי… אם כך נעבור לחלק השני בעולם הסקריפטים הנפלא של קולינס (מחבר מאמר זה).
כיום ישנם כל מיני ספריות מוכנות מראש ומודולים קיימים של פרל המאפשרים כתיבת סקריפטים של CGI באופן קל ומהיר אך להזכירך אנו עוסקים בכללים הבסיסיים ואותם נלמד. אבא שלי פעם אמר לי "עליך ללמוד תחילה ללכת לפני שאתה מתחיל לרוץ". לכן היום נלמד את הבסיס שכמעט נחשב לפרה-היסטורי אך בכל זאת נותן את הכלים למימוש דברים מורכבים ויפים בפרל עם CGI.
אך לפני שנמשיך עליך לדעת מספר דברים נוספים לפני שאתה קופץ לחלק השני.
עליך לדעת כיצד יוצרים טופס(form) בשפת HTML. אם אינך יודע זאת עליך ללמוד זאת ואח"כ לחזור לכאן בחזרה. זה מאוד פשוט ולא צריך לקחת יותר מ10 דקות.
כתיבת סקריפטים דורשת סוג מסוים של ריכוז , לעיתים ניתן להשיג אותה בעזרת מוסיקת רקע – לי אישית שירים של הפיקסיס (pixies) עושים את זה.
כתיבת סקריפטים ב CGI עלולה להיות מתסכלת ביותר, לכן כדאי שתחזיק לידך שק אגרוף או מחשב ישן שתוכל לפרוק את המתח. כמובן שאם זה לא עוזר לך, תמיד תוכל לגנוב סקריפטים של אנשים אחרים…
ובכן כעת אתה מוכן לקפוץ לשיעור של היום בו נבחן את ההבדלים בין פרל עבור CGI לבין סקריפטים בפרל. כמו כן נכתוב סקריפט קטן ונחמד שידגים את העצמה בשימוש עם CGI.
ההבדל עם CGI.
CGI מעבד את הקלט באופן שונה מהאופן שמתבצע ע"י סקריפטים בשיטה הישנה של פרל וזהו בעצם ההבדל היחיד שתמצא בין השניים. ברגע שסקריפט CGI מעבד את הקלט, הקלט הופך לנתונים (data) אשר מנוהלים בצורה די דומה ע"י CGI וע"י סקריפטים בפרל. קלט בCGI יכול להתקבל ב2 דרכים שונות: "get” ו "post”. אם ידוע לך מראש מהו סוג הקלט שהולך להתקבל אז עליך להשתמש אך ורק בסוג אחד מהנ"ל. אבל אם לא ידוע לך מה יוכנס כקלט אז עליך לכסות את כל האפשרויות של התשובות האפשריות. לכן עליך להשתמש בתהליך המורכב משני צעדים הכולל משפט תנאי if/else.
if ($ENV{'REQUEST_METHOD'} eq "GET") {
$in = $ENV{'QUERY_STRING'};
} else {
$in = <STDIN>;
}
הוראה זו שואלת את השרת האם שיטת הבקשה (הדרך בה השרת מעביר לך את האינפורמציה) היא מסוג "get”. אם כן אז הסקריפט יקרא את המידע ממחרוזת השאילתא לתוך משתנה הנקרא in$ . אחרת , הוא יקרא זאת דרך הקלט הסטנדרטי בדיוק כפי שמתבצע בסקריפט פרל נורמלי.
הפיכת פרל ל-סי.ג'י.איי | בדיוק
כמו בסרטים.
אני מאוד אוהב סרטים ויש לי לומר רבות בנושא. לכן לצורך העניין אלמד אותך כיצד לכתוב סקריפט לחיפוש ביקורות-סרטים. אך אל דאגה , אם סרטים הם לא התחום שלך , נניח שאתה רוקיסט כבד , הסקריפט שלנו יעבוד טוב מאוד גם עם אוסף שירים וכו'.
לפני שנבנה את ה CGI עלינו להגדיר את הקלט. אחד הדברים הראשונים שתלמד בבניית סקריפטים בCGI זה שככל שאתה עושה דבר מסובך יותר כך הסיכוי גדול יותר שהמשתמש לא יבין כיצד להשתמש בו. לכן נשתדל לשמור על עניינים פשוטים ונחמדים ונתחיל עם טופס (form) שמקבל רק סוג אחד של קלט: את כותרת הסרט (movie title). הבה ניתן שם לשדה זה בטופס ונקרא לו "title".(לא מפתיע במיוחד). ולכן זה יופיע בעמוד ה Web שלנו:
Please input the title of the movie you want to hear me rant about. It can be all caps, lowercase, whatever, but leave those "The"s right where they are. So if you're looking for "The 5,000 Fingers of Dr. T," type in the The before 5,000 Fingers of Dr. T. Or if it's "They Live" you seek, you can type in THEY LIVE, they live, They Live, and so on. Got it?
את זה אתה עושה ב HTML כך:
<form action="/cgi-bin/webmonkey/crazymovie.cgi">
<input type="text" length="20" name="title"><br>
<input type="submit" value="Search The Crazy Movie Megabase!">
</form>
כעת נחפש את כותרת הסרט ב"מסד הנתונים" (“database”) שלי. אבל על מנת לא לסבך את הדוגמא ולעשות את הדברים בצורה ברורה ופשוטה לא נשתמש במסד נתונים אמיתי של Oracle או SQL אלא נעשה זאת באמצעות קובץ המייצג את מסד הנתונים (“flat-file”).
הקובץ יהווה אוסף של טקסט מאורגן היטב כך שיהיה קל לסקריפט לבצע עליו parsing (חלוקה לתתי קלטים, אצלנו למילים). קובץ כזה (“flat-file”) איננו טוב לחיפושים מפורטים על כמויות מידע גדולות אך מצד שני גם לא יעלה לך אלפי דולרים עבור חומרה ותוכנה נדרשת למסד נתונים.
על מנת ל"שאוב" מידע מקובץ-"מסד הנתונים" שלנו עלינו לדעת כיצד יראה הקלט ממסד הנתונים של מנת שנדע כיצד לבנות את ה CGI מסביבו. התצורה (format) עבור כל ערך שנשתמש תראה בדיוק כך:
---- movie title ----
movie title
movie description
ובכן , הצהרתי על חוקי התצורה של מסד הנתונים שלי – ולכן גם הנתונים וגם הסקריפט חייבים לפעול על פי החוקים הללו. הם אולי נראים לך מגבילים אך האמן לי , ככל שתגדיר יותר חוקים לפני קליטת המידע כך הדברים יהיו פשוטים יותר בהמשך. כתיבת סקריפטים היא פעילות מובנית, וחוקים עוזרים להגדיר את המבנה.
כעת לאחר שיש לי את "מסד-הנתונים" מוכן אני יכול לגרום לדברים לקרות בהתאם לקלט אשר יתקבל מן המשתמש המועבר דרך טופס ה HTML
עושים סדר בקלט.
על מנת לבצע חיפוש על מידע המתאים לקלט המשתמש "title" , נפתח את מסד הנתונים באותה דרך שאנו פותחים כל קובץ אחר בפרל. לאחר מכן נקרא זאת לתוך מערך של משתנים וכמובן נסגור את הקובץ.
open (DATA, "/usr/people/ferm/movies.dat");
my @data = <DATA>;
close (DATA);
כעת לסקריפט יש את כל המידע ממסד הנתונים והוא מוכן לסרוק ולחפש את המידע אשר תואם את בקשת הקלט של המשתמש. נתנו למשתמש הוראות ברורות כיצד להכניס את כותרת הסרט, למרות זאת אתה תופתע לגלות כמה סוגי קלטים שונים עלולים להתקבל בפועל. לכן נתמודד עם כך בצורה הבאה: (שים לב להערות בגוף הקוד – הן חשובות וגם עליך לנקוט באותה שיטה)
# Always remember to put this line at the top!
#!/usr/local/bin/perl
# This opens the movie database and saves it into the @data variable.
open (DATA, "/usr/people/ferm/movies.dat");
my @data = <DATA>;
close (DATA);
# Have we forgotten already? This gets the input regardless of what
# method was used and stores it into the $in variable.
my $in;
if ($ENV{'REQUEST_METHOD'} eq "GET") {
$in = $ENV{'QUERY_STRING'};
} else {
$in = <STDIN>;
}
כמובן שעלינו לטפל בקלט שהתקבל מן המשתמש , תחילה נרצה לוודא שלא קלטנו כל מיני תווים מוזרים שלעיתים נותרים כאשר קלט מתורגם ל קוד URI (URI הינו קוד אשר מספר שפות מתורגמות אליו כאשר טופס נשלח והדפדפן מחליט להעביר המידע לCGI בצורה זו). על מנת לנקות את ה"זבל" שנוצר כתוצאת לוואי מתהליך זה , נבצע:
$in =~ s/%(..)/pack("c",hex($1))/ge;
זוהי פקודת חפש והחלף (search-and-replace) אשר בודקת אם ישנם תווים המתחילים ב* ומחליפה אותם בתווים אשר ניתן לקרוא. וכך הקלט מקבל ניחוח טוב יותר (ללא ה"זבל"(
אם כן, כעת יש בידך טקסט נורמלי אך עדיין ישנן כמה בעיות. אם הכותרת (title) ארוכה יותר ממילה אחת אז המשתנה $in יכיל סימני "+" היכן שאמורים להיות רווחים (spaces).
ולכן נבצע:
$in =~ s/\+/ /g;
זוהי פונקציה סטנדרטית של פרל אשר מחפשת את סימני ה "+" ומחליפה אותם ברווחים.
ולבסוף , עלינו להוציא את המידע מהמשתנה $in ולהעניק לו שם יותר תיאורי ,
my %movie = split (/=/, $in);
קוד זה מפצל את השורה לתוך המערך האסוציאטיבי %movie.
מכיוון ששם השדה בטופס היה "title" , המידע אוחסן בחריץ $movie{'title'}.
למרות שחלק זה אינו הכרחי, זה עוזר לי לעקוב אחר מה שקורה.
כעת שיש לנו את המידע , הגיע הזמן לעשות משהו עם זה
ביצוע התאמות (תמצית העיקר).
כעת אחרי שריסקת את הקלט של המשתמש הגיע הזמן להחזיר לו משהו בתמורה. הדפסה לעמוד Web היא בדיוק כמו הדפסה לפלט הסטנדרטי , מלבד הזה שאתה יכול להשתמש בתוויות (HTML tags). הדבר היחיד שעליך לעשות כאשר אתה מדפיס לעמוד Web זה לומר לדפדפן מה הוא הולך לקבל. במקרה זה הוא מקבל HTML , ולכן עליך להוסיף:
Content-Type: text/html\n\n
… בקטע הראשון בו אתה הולך להדפיס למשתמש. המשתמש לא יבחין בכך אך הדפדפן כן – וזה דבר חשוב מאוד. (עליך לוודא כי אתה שולח זאת רק בהדפסה הראשונה אחרת המשתמש באמת יראה זאת וזה יהיה די מביך לראות את :
Content-Type: text/html\n\n
מודפס אלפי פעמים על כל העמוד.)
ובכן את הכותרת העליונה (header) של התוצאות שלנו נכתוב כך:
print <<END;
Content-Type: text/html\n\n
<html>
<body bgcolor="#000000" text="#ffffff">
<center>
<h2>Results</h2>
</center>
<p>
END
שים לב כי השתמשתי בHTML בתוך ה CGI שלי. זה בדיוק כמו לכתוב דף HTML נורמלי במקטעים , מלבד הדבר שזה נעשה עם תוייות הדפסה (print tags).
אני יכול לסבך זאת ככל שיעלה על רוחי ולהשתמש בכל תווית (HTML tag) הנמצאת בספר אבל אנו לומדים CGI ולא HTML ולכן לא אעשה זאת אלא רק במינימום ההכרחי.
אוקיי, הרכבנו את הכותרת העליונה (header). אך עדיין לא הגענו לבשר עצמו (או לתפו"א אם אתה צמחוני…) של הסקריפט. עדיין עלינו להציג את האינפורמציה שהמשתמש ביקש. עד כה יש לנו את מידע המשתמש במשתנה אחד ומסד הנתונים מאוחסן במערך משתנים. כעת עלינו לרוץ על המערך ולנסות לבצע התאמה בין הכותרות (titles של הסרט). אם הכותרת מתאימה , נדפיס החוצה את המידע, אם לאו – נדפיס החוצה הודעת שגיאה.
מהי הדרך הטובה ביותר לרוץ על פני מערך? ובכן אתה יכול להשתמש בלולאת for או בלולאת foreach , אני אישית מעדיף את לולאת for ולכן אשתמש בה , למרות ששתיהן אפשריות לצורך כך.
for ($i = 0; $i <= $#data; $i++) {
}
קטע זה רץ על החריצים ב data@ עד אשר לא נותרים יותר חריצים. ואז מסיים. כעת עלינו לבדוק האם הכותרת מאוחסנת במערך.
if ($data =~ /-- $movie{'title'} --/i) {
}
אם ישנה התאמה נשתמש במשהו כזה (בתוך ה if) :
print <<END;
<b><font size="+1">$data</font></b><br>
$data<br>
END
last;
מה שעשינו כאן זה למצוא את הכותרת הנכונה על ידי שימוש בקוים מפרידים (line of dashes) אשר שמתי בתצורה של קבצי מסד הנתונים שלי – זו שורה i$. התוכן האמיתי שנרצה להציג : הכותרת וביקורת הסרט (review) נמצאים 2 שורות אחרי הקו המפריד (dashed line). נדפיס תוכן זה על ידי הוספת 1 או 2 למשתנה i$. שוב אנו עוטפים את הפלט בתצורת HTML על מנת לעשות זאת יפה. ולכן אם הקו המפריד היה בשורה 32 המשתנה i$ יאותחל ל32. על מנת לקבל את כותרת הסרט ללא הקו המפריד עליך להוסיף 1 ל i$ מפני שזה בשורה מתחת:שורה 33. על מנת לקבל את ביקורת הסרט (review) אשר נמצא בשורה השלישית של מסד הנתונים שלי , שורה 34 , עליך להוסיף 2 ל i& באופרטור מתמטי ולא אופרטור השמה. ולכן ערך i$ ישאר שווה ל 32. ברגע שהדפסנו את המידע ישנו שימוש בהוראה "last" על מנת לומר לסקריפט שהוא קיבל מה שהיה צריך. ביסודו "last" אומר ללולאה שהמעבר הבא הוא האחרון ולכן יש לבצע break ולצאת מהלולאה.
כמובן, שהתסריט הנ"ל מניח כי המידע שהתבקש אכן נמצא במסד הנתונים הקטן שבנינו. אך זה לא תמיד המקרה. מה אם המשתמש ביקש איזה סרט גרמני אפל משנת 1928? ובכן יש סיכוי גדול כי הוא אינו במסד הנתונים שלנו. עלינו להוסיף עוד הוראה לטיפול במקרה כזה. מקרה כזה יטופל בצורה יעילה בעזרת הוראת "elsif" אשר תתוסף ל if שכתבנו לעיל. במקרה כזה ההוראה תתבצע רק אם הסקריפט היה במעבר האחרון בלולאה ולא מצא את שחיפש.
if ($data =~ /-- $movie{'title'} --/i) {
print <<END;
<b><font size="+1">$data</font></b><br>
$data<br>
END
last;
} elsif ($i == $#data) {
}
קטע קוד זה אומר שאם i$ שווה למספר החריצים ב data@ והכותרת לא נמצאה בחריץ זה אז עשה כך וכך. אבל מהו כך וכך? תמיד עדיף פשוט לומר למשתמש כי אין לך את מה שהוא חיפש מאשר לשקר לו. כמובן שההחלטה הסופית תלויה בך.ולכן בין הסוגריים זה המקום בו אתה מסביר מדוע החיפוש לא הניב תוצאות.
print "<b><i>Sorry! I haven't reviewed that one yet!</i></b>";
עם הכנסת קטע זה סיימת עם חלק הארי של הסקריפט, כך צריכים להראות כל הדברים ביחד:
for ($i = 0; $i <= $#data; $i++) {
if ($data =~ /-- $movie{'title'} --/i) {
print <<END;
<b><font size="+1">$data</font></b><br>
$data<br>
END
last;
} elsif ($i == $#data) {
print "<b><i>Sorry! I haven't reviewed that one yet!</i></b>";
}
}
ולסיום עליך להוסיף כותרת תחתונה (footer) בדיוק כפי שעשית עם כותרת עליונה (header):
print <<END;
<center><hr size=1 width=50%></center>
</body>
</html>
END
איזהו CGI script נפלא !
כעת שהסקריפט שלך מוכן ומסד הנתונים שלך במקומו , אתה בוודאי משתוקק לראות את זה עובד. אבל הדבר החשוב ביותר לזכור כאשר עובדים עם סקריפטים של CGI זה לוודא כי הם יציבים. תמיד תן למהנדס אמין להעיף מבט על הסקריפט שלך בכדי לוודא שהוא לא עושה משהו שטותי במיוחד. אם המהנדס מתחמק וטוען שאין לו זמן לכך . תאמר לו משהו כזה:"חבל לי להפיל את האתר עם סקריפט שמוחק את הדיסק הקשיח.." – אז הוא לבטח יתפנה במיידית אליך. ברגע שיש לך האישור – קדימה , שים את הסקריפט שלך במקומו ותתחיל להריץ. אם ברצונך לראות את הכל ביחד העף מבט בקוד הסופי -
Sample CGI Script
ובכן הנהו לפניך : חי ונושם – סקריפט ה CGI שלך. כפי שאתה רואה רוב ה CGI הינם סקריפט סטנדרטי של פרל עם כמה וכמה שינויים המוסיפים את הבונוס של ה CGI.
ובכן כאשר עוצמת ה CGI בידך , מה אתה הולך לעשות עם זה? ובכן, זה תלוי בך. הידע הנפלא של ה CGI הצליח להוציא מספר אנשים מדעתם.אני מכיר כמה כותבי סקריפטים אשר רכשו את האומנות והחליטו לעבור לגור ביער ולבנות שם צריף ופצצות. לדעת כיצד לכתוב סקריפט ב CGI זה החלק הקל במשוואה. החלק הקשה הוא להבין כיצד להשתמש בכח זה על מנת לעשות משהו מועיל , תוך כדי שמירה על שפיותך ועל שפיות אנשי ה system אשר אחראים על המחשב שמריץ את הסקריפטים שלך