ΚΕΝΤΡΟ ΠΛΗ.ΝΕ.Τ. Ν. ΦΛΩΡΙΝΑΣ

Η Τεχνολογία CGI

 

Τι Είναι το CGI

Το CGI αντιμετωπιζόταν και ακόμα αντιμετωπίζεται σήμερα σαν κάτι το δύσκολο, αλλά στην πραγματικότητα δεν είναι. Είναι εύκολο στην εκμάθηση : αν ξέρουμε HTML, μπορούμε να μάθουμε CGI. Δεν χρειάζεται καμία προηγούμενη εμπειρία στον προγραμματισμό. Αυτές οι σημειώσεις απευθύνονται σ’ οποιονδήποτε γνωρίζει HTML, αλλά δεν ξέρει από Perl ή προγραμματισμό CGI, ίσως και καθόλου από προγραμματισμό.

Ο όρος CGI σημαίνει Common Gateway Interface, αποδίδεται στα ελληνικά με τον όρο Κοινή Διασύνδεση Πύλης, και είναι η μέθοδος με την οποία ένας web server μπορεί να λάβει δεδομένα από ή να στείλει δεδομένα σε βάσεις δεδομένων, έγγραφα και άλλα προγράμματα και να παρουσιάσει αυτά τα δεδομένα μέσω του web. Πιο απλά, το CGI είναι ο προγραμματισμός για το web. Ένα CGI μπορεί να γραφεί σ’ οποιαδήποτε γλώσσα προγραμματισμού, αλλά η Perl είναι η πιο δημοφιλής και είναι αυτή που θα χρησιμοποιήσουμε.

 

Γιατί Πρέπει να Μάθουμε το CGI

Αν πρόκειται να δημιουργήσουμε ιστοσελίδες, τότε κάποια στιγμή θα χρειαστεί να προσθέσουμε έναν μετρητή (counter), μια φόρμα (form) απ’ όπου θα μπορούν οι χρήστες να στέλνουν μηνύματα (e-mails) ή να κάνουν μια παραγγελία κ.ά. Το CGI μάς δίνει τη δυνατότητα να τα κάνουμε όλα αυτά και πολλά περισσότερα. Θα δούμε τα βασικά των CGI scripts, τα στοιχειώδη για τη γλώσσα προγραμματισμού Perl καθώς και τα βασικά για την επεξεργασία φορμών και τη συγγραφή απλών CGIs. Μετά θα δούμε πιο προχωρημένα θέματα, όπως διάβασμα και γράψιμο δεδομένων από και προς αρχεία, αναζήτηση δεδομένων σ’ ένα αρχείο, δημιουργία φορμών για παραγγελίες, χρήση server-side includes, cookies και άλλα χρήσιμα CGI τρικς.

Αυτές οι σημειώσεις είναι γραμμένες για κάποιον που χρησιμοποιεί Perl σ’ ένα σύστημα Unix. Αν, όμως, χρησιμοποιούμε τα Windows NT αντί για το Unix, μπορούμε να χρησιμοποιήσουμε τα περισσότερα από τα προγράμματα και να μάθουμε το ίδιο εύκολα την Perl. Τα περισσότερα μηχανήματα NT τρέχουν τον ίδιο κώδικα Perl με τα μηχανήματα Unix.

 

Εισαγωγή στην Perl

Η Perl είναι μια απλή γλώσσα, εύκολη στην εκμάθηση, αλλά και αρκετά δυνατή για να μπορεί να επιλύει τις πιο δύσκολες εργασίες. Είναι μια γλώσσα διερμήνευσης (interpreted language), που σημαίνει ότι δεν χρειάζεται να μεταγλωττίσουμε τα scripts μας, απλά τα γράφουμε και τα εκτελούμε εμείς ή ο web server. Το ίδιο το script αποτελείται από απλό κείμενο (text code). Ο διερμηνευτής (interpreter) της Perl είναι αυτός που κάνει όλη τη δουλειά.

Μπορούμε να γράψουμε τα προγράμματα της Perl είτε στον υπολογιστή μας μ’ έναν επεξεργαστή κειμένου, όπως είναι το Σημειωματάριο (Notepad) ή το Simpletext ή στο Unix shell. Αν χρησιμοποιούμε το Unix, μπορούμε να χρησιμοποιήσουμε και τον επεξεργαστή κειμένου pico. Δεν πρέπει να χρησιμοποιούμε ειδικούς χαρακτήρες αλλά μόνο καθαρό κείμενο, όπως συμβαίνει και με την HTML. Αφού ανεβάσουμε (upload) το script στον Unix server, πρέπει να σιγουρευτούμε να το τοποθετήσουμε στον κατάλογο public_html ή στον κατάλογο που έχουμε ορίσει για τις ιστοσελίδες. Θα χρειαστεί να αλλάξουμε και τα δικαιώματα (permissions) στο αρχείο ώστε να είναι εκτελέσιμο από το σύστημα. Στο Unix, η σχετική εντολή είναι η εξής :

chmod 755 filename

Αυτό ορίζει τα δικαιώματα του αρχείου έτσι ώστε να μπορούμε να διαβάσουμε, να γράψουμε και να εκτελέσουμε το αρχείο καθώς και όλοι οι άλλοι χρήστες (ανάμεσά τους και ο web server) να μπορούν να το διαβάσουν και να το εκτελέσουν. Δηλαδή τα αρχεία πρέπει να διαβάζονται και να εκτελούνται απ’ όλους και να γράφονται μόνο από εμάς, δηλ. τον ιδιοκτήτη (owner). Πρέπει να έχουμε υπόψη μας ότι τα scripts της Perl, οι εντολές του Unix και τα ονόματα αρχείων διακρίνουν τα πεζά από τα κεφαλαία γράμματα (case-sensitive). Αυτό σημαίνει ότι στο Unix, το perl δεν είναι το ίδιο με το PERL.

 

Τα Βασικά Ενός Script της Perl

Η Perl είναι πολύ παρόμοια με την HTML, έχει μια ξεκάθαρη σύνταξη και αν ακολουθήσουμε τους συντακτικούς της κανόνες, θα μπορούμε να γράφουμε στην Perl το ίδιο εύκολα με την HTML. Αν γράφουμε τα scripts στο Unix, θα χρειαστούμε μια εντολή στην πρώτη γραμμή του κάθε script, που να ενημερώνει τον server ότι πρόκειται για ένα script της Perl καθώς και το πού να βρει τον διερμηνευτή (interpreter) της Perl. Στα περισσότερα scripts η εντολή αυτή είναι η εξής :

#!/usr/bin/perl

Προς το παρόν, δεν θα γράψουμε τίποτα άλλο στην ίδια γραμμή μ’ αυτή την εντολή. Υπάρχουν μερικές σημαίες (flags) που μπορούμε να χρησιμοποιήσουμε, αλλά θα τις δούμε αργότερα. Αν δεν είμαστε σίγουροι για το πού βρίσκεται η Perl στο σύστημά μας, μπορούμε να δώσουμε μια από τις εξής εντολές :

which perl

ή

whereis perl

Αν την βρει το σύστημα, θα μας αναφέρει τη διαδρομή (path name) της Perl, την οποία πρέπει να γράψουμε στην παραπάνω εντολή. Μετά την παραπάνω γραμμή θα γράψουμε τον κώδικα της Perl, οι περισσότερες γραμμές του οποίου πρέπει να τελειώνουν με το σύμβολο ;, εκτός από τις γραμμές ανοίγματος και κλεισίματος των βρόχων και τα μπλοκς συνθήκης. Θα δούμε ένα απλό πρόγραμμα για αρχή. Γράφουμε τις επόμενες γραμμές σ’ ένα νέο αρχείο και το ονομάζουμε first.pl.

#!/usr/bin/perl
            print "Hello, world!\n";

Το αποθηκεύουμε και στο Unix shell δίνουμε την εξής εντολή :

chmod 755 first.pl

Αυτό αλλάζει τα δικαιώματα του αρχείου ώστε να μπορούμε να εκτελέσουμε το πρόγραμμα. Θα πρέπει να το κάνουμε κάθε φορά που δημιουργούμε ένα script.

Στο Unix shell θα πρέπει να γράψουμε το εξής για να τρέξει το script :

./first.pl

Αν όλα πάνε καλά, θα πρέπει να δούμε το μήνυμα Hello, world! στην οθόνη. Πρέπει να έχουμε υπόψη μας ότι αυτό το πρόγραμμα δεν είναι ένα CGI και δεν θα δουλέψει αν το δοκιμάσουμε από τον φυλλομετρητή μας. Αλλά μπορεί εύκολα να μετατραπεί σε CGI όπως θα δούμε παρακάτω.

 

Τα Βασικά Ενός CGI Script

Ένα πρόγραμμα CGI είναι ένα script της Perl, αλλά μια σημαντική διαφορά είναι ότι ένα CGI συνήθως δημιουργεί μια ιστοσελίδα (web page), όπως για παράδειγμα ένα CGI επεξεργασίας φόρμας, όπως είναι ένα βιβλίο επισκεπτών (guestbook), που συνήθως επιστρέφει μια σελίδα με το μήνυμα "thank you for writing". Αν γράφουμε ένα CGI που πρόκειται να δημιουργήσει μια HTML σελίδα, πρέπει να συμπεριλάβουμε την επόμενη εντολή κάπου στο script, πριν εκτυπώσουμε ο,τιδήποτε άλλο :

print "Content-type:text/html\n\n";

Αυτό είναι ένα content header που ενημερώνει τον φυλλομετρητή για το τι είδους δεδομένα πρόκειται να λάβει, σ’ αυτή την περίπτωση ένα HTML έγγραφο. Αν δεν το συμπεριλάβουμε ή αν εκτυπώσουμε κάτι άλλο πριν εκτυπώσουμε αυτό το header, θα λάβουμε ένα μήνυμα "Internal Server Error" όταν προσπαθήσουμε να αποκτήσουμε πρόσβαση στο CGI. Ένας καλός εμπειρικός κανόνας είναι να γράψουμε τη γραμμή Content-type στην κορυφή του script κάτω ακριβώς από τη γραμμή #!/usr/bin/perl.

Τώρα θα μετατρέψουμε το αρχικό first.pl script σ’ ένα CGI script που θα εμφανίζει μια ιστοσελίδα (web page). Αν το εκτελέσουμε σ’ έναν Unix server που μας επιτρέπει να εκτελούμε CGIs στον κατάλογο public_html, θα χρειαστεί πιθανώς να μετονομάσουμε το αρχείο σε first.cgi, ώστε να τελειώνει με την επέκταση .cgi. Θα πρέπει να είναι κάπως έτσι :

#!/usr/bin/perl
            print "Content-type:text/html\n\n";
            print "<html><head><title>Δοκιμαστική σελίδα</title></head>\n";
            print "<body>\n";
            print "<h2> Hello, world! </h2>\n";
            print "</body></html>\n";

Αποθηκεύουμε αυτό το αρχείο και το εκτελούμε στο Unix shell με την εντολή ./first.cgi. Προσέξτε πώς αυτό το script θα εμφανίσει μια ομάδα εντολών της HTML. Αν υπάρχει κάποιο λάθος στο script, ο διερμηνευτής της Perl θα μας πει σε ποια γραμμή ακριβώς βρίσκεται το λάθος. Τώρα θα καλέσουμε αυτό το CGI από τον φυλλομετρητή μας. Δεν χρειάζεται να το καλέσουμε από μια ιστοσελίδα. Το μετακινούμε στον κατάλογο public_html ή CGI-bin και γράφουμε ολόκληρο το URL για το CGI. Για παράδειγμα :

http://www.cgi101.com/class/ch1/first.cgi

Θα πρέπει να εμφανίσει μια ιστοσελίδα με τη φράση "Hello, world!".

Ένας άλλος τρόπος για να γράψουμε το παραπάνω CGI χωρίς να χρησιμοποιήσουμε πολλές εντολές print είναι ο εξής :

#!/usr/bin/perl
            print "Content-type:text/html\n\n";
            print <<EndOfHTML;
            <html><head><title> Δοκιμαστική σελίδα </title></head>
            <body>
            <h2> Hello, world! </h2>
            </
body></html>

            EndOfHTML

Αυτή είναι η σύνταξη here-doc. Δεν υπάρχουν κενά ανάμεσα στα << και το EndOfHTML στην εντολή :

print <<EndOfHTML;

Επίσης, παρά το ότι το script φαίνεται να έχει εσοχές, η κάθε γραμμή πρέπει να ξεκινάει από τη στήλη 1 στο CGI, ιδιαίτερα η εντολή EndOfHTML που είναι μόνη της. Αν υπάρχει έστω και ένα κενό πριν από την EndOfHTML, θα λάβουμε ένα μήνυμα λάθους και το script δεν θα εκτελεστεί.

Αυτός ο τρόπος εμφάνισης HTML θα μας είναι πιο χρήσιμος στα μελλοντικά CGIs, επειδή δεν χρειάζεται να χρησιμοποιήσουμε τον χαρακτήρα \ για να εμφανίσουμε τα ενσωματωμένα εισαγωγικά, όπως θα κάναμε σε μια κανονική εντολή print :

print "<a href=\"http://lightsphere.com/\"> foo </a>";

Τα εισαγωγικά γύρω από το URL πρέπει να έχουν τον χαρακτήρα \ (backslash) μπροστά τους, εφόσον τα strings της Perl περικλείονται σε διπλά εισαγωγικά.

 

Οι Μεταβλητές της Perl

Η Perl έχει τρεις τύπους μεταβλητών : scalars, arrays και hashes. Μια μεταβλητή scalar αποθηκεύει μία μοναδική (scalar) τιμή. Τα ονόματα των μεταβλητών αυτών στην Perl έχουν σαν πρόθεμα το σύμβολο $. Έτσι για παράδειγμα τα $x, $y, $z, $username και $url είναι όλα παραδείγματα ονομάτων scalar μεταβλητών. Ακολουθούν μερικά παραδείγματα χρήσης τους :

$foo = 1;
            $
name = "Fred";
            $
pi = 3.141592;

Δεν χρειάζεται να δηλώσουμε μια μεταβλητή πριν την χρησιμοποιήσουμε. Μια μεταβλητή scalar μπορεί να περιέχει δεδομένα οποιουδήποτε τύπου, όπως strings, αριθμούς κ.ά. Μπορούμε επίσης να τοποθετήσουμε τα scalars μέσα σε strings με διπλά εισαγωγικά :

$fnord = 23;
            $blee = "Ο μαγικός αριθμός είναι $fnord.";

Τώρα αν τυπώσουμε το $blee, θα δούμε το μήνυμα "Ο μαγικός αριθμός είναι 23.". Τροποποιούμε το first.pl ξανά και προσθέτουμε μερικά scalars :

#!/usr/bin/perl
            $classname = "CGI Programming";
            print "Γεια σου. Ποιο είναι το όνομά σου;\n";
            $you = <STDIN>;
            chomp($you);
            print "Γεια σου $you. Καλωσήρθες στο $classname.\n";

Αποθηκεύουμε και εκτελούμε το script στο Unix shell. Αυτό το πρόγραμμα δεν θα δουλέψει σαν ένα CGI και θα ζητήσει το όνομά μας, το οποίο θα διαβάσει με την εξής εντολή :

$you = <STDIN>;

Το STDIN είναι η στάνταρτ είσοδος (standard input) και αποτελεί το προκαθορισμένο κανάλι εισόδου για το script. Αν εκτελούμε το script στο shell, το STDIN περιέχει ο,τιδήποτε καταχωρούμε καθώς εκτελείται το script. Το πρόγραμμα θα εμφανίσει το μήνυμα "Γεια σου. Ποιο είναι το όνομά σου;" και μετά θα περιμένει να γράψουμε κάτι. Αυτό που θα γράψουμε θα αποθηκευθεί στη scalar μεταβλητή $you. Εφόσον η μεταβλητή $you περιέχει επίσης και τον χαρακτήρα carriage return, χρησιμοποιούμε την εντολή :

chomp($you);

για να αφαιρέσουμε το carriage return από το τέλος του string. Η επόμενη εντολή print :

print "Γεια σου $you. Καλωσήρθες στο $classname.\n";

αντικαθιστά την τιμή του $you που καταχωρήσαμε. Το "\n" στο τέλος της γραμμής είναι η σύνταξη που χρησιμοποιεί η perl για το carriage return.

 

Οι Πίνακες (Arrays)

Ένας πίνακας (array) αποθηκεύει μια λίστα τιμών. Ενώ μια μεταβλητή scalar μπορεί να αποθηκεύσει μόνο μία τιμή, ένας πίνακας μπορεί να αποθηκεύσει πολλές τιμές. Τα ονόματα των πινάκων της Perl έχουν σαν πρόθεμα το σύμβολο @. Ακολουθεί ένα παράδειγμα :

@colors = ("red", "green", "blue");

Στην Perl, οι δείκτες των πινάκων αρχίζουν από το 0, έτσι για να αναφερθούμε στο πρώτο στοιχείο του πίνακα @colors, χρησιμοποιούμε το $colors[0]. Βλέπουμε ότι όταν αναφερόμαστε σ’ ένα μεμονωμένο στοιχείο ενός πίνακα, χρησιμοποιούμε σαν πρόθεμα το $ αντί για το @. Το σύμβολο $ δείχνει ότι πρόκειται για μια μοναδική (scalar) τιμή, ενώ το σύμβολο @ σημαίνει ότι αναφερόμαστε σ’ ολόκληρο τον πίνακα.

Αν θέλουμε να κάνουμε βρόχο μέσα σ’ έναν πίνακα, εκτυπώνοντας όλες τις τιμές του, μπορούμε να εκτυπώσουμε το κάθε στοιχείο ξεχωριστά :

#!/usr/bin/perl
            # αυτό είναι ένα σχόλιο (
comment)
            @colors = ("red", "green", "blue");
            print "$colors[0]\n";
            print "$colors[1]\n";
            print "$colors[2]\n";

Ένας πιο βολικός τρόπος για να κάνουμε την ίδια δουλειά είναι να χρησιμοποιήσουμε τη δομή (construct) foreach :

          #!/usr/bin/perl
          # αυτό είναι ένα σχόλιο (
comment)
          @colors = ("red", "green", "blue");
           foreach $i (@colors) {
                print "$i\n";
          }

Για κάθε επανάληψη του βρόχου foreach, η Perl θέτει το $i ίσο μ’ ένα στοιχείο του πίνακα @colors. Οι αγκύλες { } ορίζουν από πού ξεκινά και πού τελειώνει ο βρόχος.

 

Οι Συναρτήσεις Πινάκων (Array Functions)

Εφόσον ένας πίνακας είναι μια αριθμημένη λίστα στοιχείων, υπάρχουν πολλές συναρτήσεις που μπορούμε να χρησιμοποιήσουμε για να εξάγουμε δεδομένα από ή να εισάγουμε δεδομένα στη λίστα :

@colors = ("red", "green", "blue", "cyan", "magenta", "black", "yellow");
            $
elt = pop(@colors);           # επιστρέφει "yellow", την τελευταία τιμή του πίνακα
            $
elt = shift(@colors);          # επιστρέφει "red", την πρώτη τιμή του πίνακα

Σ’ αυτά τα παραδείγματα, θέσαμε τη μεταβλητή $elt ίση με την τιμή που επιστρέφεται, αλλά δεν είμαστε υποχρεωμένοι να το κάνουμε αυτό. Αν θέλουμε απλώς να απαλλαγούμε από την πρώτη τιμή ενός πίνακα, για παράδειγμα, δίνουμε την εντολή shift(@arrayname).

Και οι δύο εντολές shift και pop επηρεάζουν τον ίδιο τον πίνακα, απομακρύνοντας ένα στοιχείο του. Στο παραπάνω παράδειγμα, αφού αφαιρέσουμε (pop) το στοιχείο "yellow" από το τέλος του πίνακα @colors, ο πίνακας θα είναι ίσος με ("red", "green", "blue", "cyan", "magenta", "black") και αφού αφαιρέσουμε (shift) το "red" από την αρχή του πίνακα, ο πίνακας θα είναι ίσος με ("green", "blue", "cyan", "magenta", "black").

Μπορούμε επίσης να προσθέσουμε δεδομένα σ’ έναν πίνακα με τον εξής τρόπο : 

@colors = ("green", "blue", "cyan", "magenta", "black");
            push(@colors, "orange");   # προσθέτει το "orange" στο τέλος του πίνακα @colors

Ο πίνακας @colors γίνεται τώρα ίσος με ("green", "blue", "cyan", "magenta", "black", "orange").

@morecolors = ("purple", "teal", "azure");
            push(@colors, @morecolors);       # προσθέτει τις τιμές του @morecolors στο τέλος του πίνακα @colors

Ο πίνακας @colors γίνεται τώρα ίσος με ("green", "blue", "cyan", "magenta", "black", "orange", "purple", "teal", "azure").

Ακολουθούν μερικές άλλες χρήσιμες συναρτήσεις για τον χειρισμό πινάκων :

@colors = ("green", "blue", "cyan", "magenta", "black");
            sort(@colors)            # ταξινομεί τις τιμές του πίνακα @colors αλφαβητικά

Ο πίνακας @colors γίνεται τώρα ίσος με ("black", "blue", "cyan", "green", "magenta"). Πρέπει να έχουμε υπόψη μας ότι η εντολή sort δεν αλλάζει τις τιμές του πίνακα, έτσι αν θελήσουμε να αποθηκεύσουμε τον ταξινομημένο πίνακα, πρέπει να κάνουμε κάτι σαν το επόμενο :

@sortedlist = sort(@colors);

Το ίδιο ισχύει και για τη συνάρτηση reverse :

@colors = ("green", "blue", "cyan", "magenta", "black");
            reverse(@colors)            # αντιστρέφει τον πίνακα @colors

Ο πίνακας @colors γίνεται τώρα ίσος με ("black", "magenta", "cyan", "blue", "green").

Επίσης, αν θελήσουμε να αποθηκεύσουμε την αντεστραμμένη λίστα, πρέπει να την εκχωρήσουμε σ’ έναν άλλον πίνακα.

$#colors         # length-1 του πίνακα @colors ή ο τελευταίος δείκτης (index) του πίνακα

Σ’ αυτό το παράδειγμα, το $#colors είναι ίσο με 4. Το πραγματικό μήκος του πίνακα είναι 5, αλλά εφόσον οι λίστες της Perl ξεκινούν από το 0, ο δείκτης (index) του τελευταίου στοιχείου είναι ίσος με length – 1. Αν θέλουμε το πραγματικό μήκος του πίνακα (δηλ. τον αριθμό των στοιχείων), μπορούμε να χρησιμοποιήσουμε τη συνάρτηση scalar :

scalar(@colors);      # το πραγματικό μήκος του πίνακα

Σ’ αυτή την περίπτωση, το scalar(@colors) είναι ίσο με 5.

join(", ", @colors)    # ενώνει τα στοιχεία του πίνακα @colors σ’ ένα string χωρισμένα με το ,

Ο πίνακας @colors γίνεται τώρα ίσος μ’ ένα απλό string : "black, magenta, cyan, blue, green".

 

Μια Απλή Query Form

Υπάρχουν δύο τρόποι για να στείλουμε δεδομένα από μια φόρμα HTML σ’ ένα CGI : η GET και η POST. Αυτές οι μέθοδοι καθορίζουν το πώς τα δεδομένα της φόρμας στέλνονται στον server. Στη μέθοδο GET, οι τιμές εισόδου από τη φόρμα στέλνονται σαν μέρος του URL και αποθηκεύονται στη μεταβλητή περιβάλλοντος QUERY_STRING. Στη μέθοδο POST, τα δεδομένα στέλνονται σαν μια ροή εισόδου (input stream) στο πρόγραμμα. Θα καλύψουμε τη μέθοδο POST αργότερα, ενώ τώρα θα δούμε τη μέθοδο GET.

Μπορούμε να ορίσουμε την τιμή QUERY_STRING με πολλούς τρόπους. Για παράδειγμα, υπάρχει ένας αριθμός απευθείας δεσμών προς το script env.cgi :

http://www.cgi101.com/class/ch3/env.cgi?test1

http://www.cgi101.com/class/ch3/env.cgi?test2

http://www.cgi101.com/class/ch3/env.cgi?test3

Αν προσπαθήσουμε να ανοίξουμε καθεμία από τις παραπάνω ιστοσελίδες, θα προσέξουμε ότι η QUERY_STRING γίνεται ίση μ’ ο,τιδήποτε υπάρχει μετά το ? στο URL. Στα παραπάνω παραδείγματα, γίνεται ίση με "test1", "test2" και "test3" αντίστοιχα. Μπορούμε να προχωρήσουμε παραπέρα, δημιουργώντας μια απλή φόρμα με τη μέθοδο GET.

<form action="env.cgi" method="GET">

Γράψτε κάποιο κείμενο εδώ : <input type="text" name="sample_text" size=30>

<input type="submit"><p>

</form>

Δημιουργούμε την παραπάνω φόρμα με όνομα form.html και την καλούμε από τον φυλλομετρητή. Γράφουμε κάτι στο πλαίσιο κειμένου και πατάμε return. Θα πάρουμε την ίδια έξοδο env.cgi, αλλά αυτή τη φορά θα προσέξουμε ότι η query string έχει δύο μέρη και πρέπει να είναι ως εξής :

sample_text=αυτό+που+γράψατε

Η τιμή στα αριστερά είναι το όνομα του πλαισίου κειμένου ενώ η τιμή στα δεξιά είναι αυτό που έχουμε καταχωρήσει, αλλά απ’ ό,τι βλέπουμε αν έχουμε γράψει κενούς χαρακτήρες στο string, θα αντικατασταθούν με το +. Παρόμοια, τα σύμβολα στίξης και άλλοι ειδικοί μη αλφαριθμητικοί χαρακτήρες αντικαθίστανται μ’ έναν κωδικό %. Αυτό αποκαλείται κωδικοποίηση URL (URL-encoding) και λαμβάνει χώρα με δεδομένα που υποβάλλονται με μια από τις μεθόδους GET ή POST.

Το Perl script μπορεί να μετατρέψει αυτά τα δεδομένα, αλλά είναι συχνά ευκολότερο να χρησιμοποιούμε τη μέθοδο POST όταν στέλνουμε μεγάλα ή πολύπλοκα δεδομένα. Η μέθοδος GET είναι κυρίως χρήσιμη για μικρά ερωτήματα (queries), μ’ ένα πεδίο, ιδιαίτερα για αναζητήσεις σε βάσεις δεδομένων.

Μπορούμε επίσης να στείλουμε πολλές τιμές εισόδου με την GET ως εξής :

<form action="env.cgi" method="GET">

Όνομα : <input type="text" name="fname" size=30><p>

Επώνυμο : <input type="text" name="lname" size=30><p>

<input type="submit">

</form>

Αυτό θα περάσει στο script env.cgi ως εξής :

$ENV{'QUERY_STRING'} = fname=joe&lname=smith

Οι τιμές ξεχωρίζουν με το σύμβολο &. Για να το αναλύσουμε αυτό, θα πρέπει να διαχωρίσουμε την query string με τη συνάρτηση split της Perl :

@values = split(/&/, $ENV{'QUERY_STRING'});

foreach $i (@values) {

    ($varname, $mydata) = split(/=/, $i);

    print "$varname = $mydata\n";

}

Με τη split μπορούμε να διαχωρίσουμε (break up) ένα string σ’ έναν πίνακα από διαφορετικά strings, σ’ έναν συγκεκριμένο χαρακτήρα. Στην πρώτη περίπτωση, διαχωρίσαμε στον χαρακτήρα & και πήραμε δύο τιμές : "fname=joe" και "lname=smith", οι οποίες αποθηκεύθηκαν στον πίνακα @values. Μετά, μ’ έναν βρόχο foreach, διαχωρίζουμε περαιτέρω το κάθε string στο σύμβολο = και εκτυπώνουμε το όνομα του πεδίου και τα δεδομένα που καταχωρήθηκαν σ’ αυτό το πεδίο στη φόρμα.

Μερικές προειδοποιήσεις για την GET : δεν  πρόκειται για μια απολύτως ασφαλή μέθοδο αποστολής δεδομένων, έτσι δεν πρέπει να την χρησιμοποιούμε για να στέλνουμε συνθηματικά (passwords), στοιχεία πιστωτικών καρτών ή άλλες ευαίσθητες πληροφορίες. Εφόσον τα δεδομένα μεταβιβάζονται σαν μέρος του URL, θα φανούν στο αρχείο καταγραφής (log file) του web server και αν αυτό το αρχείο καταγραφής μπορεί να διαβαστεί από έναν οποιονδήποτε χρήστη, τότε είναι σαν να παραδίδουμε τα στοιχεία αυτά σ’ οποιονδήποτε ενδέχεται να παρακολουθεί.

Οι ιδιωτικές πληροφορίες πρέπει πάντα να στέλνονται με τη μέθοδο POST, που θα την δούμε αργότερα. Φυσικά, αν ζητάμε από τους επισκέπτες να στείλουν ευαίσθητες πληροφορίες, όπως αριθμούς πιστωτικών καρτών, θα πρέπει επίσης να χρησιμοποιήσουμε έναν ασφαλή server, εκτός από τη μέθοδο POST. Τα GETs είναι πιο χρήσιμα επειδή μπορούν να ενσωματωθούν σ’ έναν δεσμό (link) χωρίς να χρειάζεται ένα στοιχείο φόρμας. Αυτό χρησιμοποιείται συχνά σε συνδυασμό με βάσεις δεδομένων ή σε περιπτώσεις όπου θέλουμε ένα μόνο CGI να χειρίζεται ένα σαφώς ορισμένο σύνολο επιλογών.

Για παράδειγμα, μπορεί να έχουμε μια βάση δεδομένων από άρθρα, το καθένα μ’ έναν μοναδικό αριθμό αναγνώρισης (article ID). Μπορούμε να γράψουμε ένα μόνο article.cgi και το CGI απλά θα φαίνεται στο query string για να βρει ποιο άρθρο να εμφανίσει. Για παράδειγμα, κάνοντας κλικ στο :

<a href="article.cgi?22"> Article Header </a>

θα εμφανισθεί το article #22.

 

Remote Host ID

Έχουμε πιθανώς συναντήσει ιστοσελίδες που μας χαιρετάνε μ’ ένα μήνυμα σαν το εξής "Γεια σου επισκέπτη από το (yourhost)!", όπου το yourhost είναι το δικό μας hostname ή η δική μας ΙΡ διεύθυνση. Ακολουθεί ένα παράδειγμα για το πώς μπορεί να γίνει αυτό :

#!/usr/bin/perl
            print "Content-type:text/html\n\n";
            print <<EndHTML
            <html><head><title> Hello! </title></head>
            <body>
            <h2> Γεια σας! </h2>
            Καλωσήρθατε από το $ENV{'REMOTE_HOST'}!<p>

            </body></html>

            EndHTML

Αυτό το CGI δημιουργεί μια νέα σελίδα αλλά είναι πιθανό να θέλουμε να χρησιμοποιήσουμε ένα server-side include (SSI), αντί να ενσωματώσουμε τα στοιχεία σε μια άλλη σελίδα.

Μια προειδοποίηση : δεν θα δουλέψει αν ο server μας δεν είναι ρυθμισμένος να κάνει αναζητήσεις για host name. Μια εναλλακτική λύση θα ήταν να εμφανίσουμε την ΙΡ διεύθυνση του επισκέπτη :

Καλωσήρθατε από το $ENV{'REMOTE_ADDR'}!<p>

 

Τελευταία Σελίδα Επίσκεψης

Αποτελεί μια παραλλαγή του remote host ID script, όπου εμφανίζουμε την τελευταία σελίδα που έχουμε επισκεφθεί, δηλ. τη σελίδα από την οποία ήρθαμε στην τρέχουσα σελίδα.

#!/usr/bin/perl

print "Content-type:text/html\n\n";

print <<EndHTML

<html><head><title> Hello! </title></head>

<body>

<h2> Γεια σας! </h2>

Μόλις ήρθατε από $ENV{'HTTP_REFERER'}!<p>

</body>

</html>

EndHTML

Η τιμή της HTTP_REFERER ορίζεται μόνο όταν ένας επισκέπτης κάνει κλικ σ’ έναν δεσμό (link) προς τη σελίδα μας. Αυτό σημαίνει ότι αν έχει γράψει απευθείας το URL, τότε η HTTP_REFERER θα είναι κενή.

 

Έλεγχος του Τύπου του Φυλλομετρητή

Με το επόμενο script μπορούμε να δούμε ποιον τύπο φυλλομετρητή χρησιμοποιεί ο επισκέπτης της ιστοσελίδας μας και να εμφανίσουμε ένα διαφορετικό μήνυμα ανάλογα με τον τύπο του φυλλομετρητή του.

#!/usr/bin/perl

print "Content-type:text/html\n\n";

print "<html><head><title> Welcome </title></head>\n";

print "<body>\n";

print "Browser: $ENV{'HTTP_USER_AGENT'}<p>\n";

if ($ENV{'HTTP_USER_AGENT'} =~ /MSIE/) {

    print "Φαίνεται ότι χρησιμοποιείτε <b> Internet Explorer!

    </b><p>\n";

} elsif ($ENV{'HTTP_USER_AGENT'} =~ /Mozilla/) {

    print " Φαίνεται ότι χρησιμοποιείτε <b>Netscape!</b><p>\n";

} else {

    print " Φαίνεται ότι χρησιμοποιείτε κάτι διαφορετικό από Netscape ή IE. <p>\n";

}

print "</body></html>\n";

Με τον τελεστή =~ μπορούμε να ελέγξουμε για να δούμε αν το /pattern/ περιέχεται κάπου στο string. Μπορούμε επίσης να χρησιμοποιήσουμε τον τελεστή =~ για να κάνουμε αντικαταστάσεις, όπως θα δούμε αργότερα. Οι περισσότερες φόρμες που θα χρησιμοποιήσουμε θα στέλνουν τα δεδομένα τους με τη μέθοδο POST, η οποία είναι ασφαλέστερη από τη μέθοδο GET, εφόσον τα δεδομένα δεν στέλνονται σαν μέρος του URL και μπορούμε ακόμη να στείλουμε περισσότερα δεδομένα με τη μέθοδο POST.

Επίσης, ο browser, ο web server ή ο proxy server μπορούν να αποθηκεύσουν σε μνήμη (cache) τα GET queries, αλλά τα δεδομένα με τη μέθοδο POST στέλνονται κάθε φορά. Όμως, εφόσον τα δεδομένα που στέλνονται με τη μέθοδο POST από τις περισσότερες φόρμες είναι συχνά πιο περίπλοκα από μια απλή λέξη, η αποκωδικοποίησή τους απαιτεί λίγη περισσότερη δουλειά.

 

Κωδικοποίηση και Αποκωδικοποίηση Χαρακτήρων

Ο web server, όταν στέλνει δεδομένα φόρμας στο CGI, τα κωδικοποιεί. Οι αλφαριθμητικοί χαρακτήρες στέλνονται ίδιοι, τα κενά μετατρέπονται σε σύμβολα +, ενώ οι άλλοι χαρακτήρες όπως τα tabs, τα εισαγωγικά κ.ά. μετατρέπονται σε %HH, δηλ. ένα σύμβολο % και δύο 16δικά ψηφία που αντιπροσωπεύουν τον κώδικα ASCII του χαρακτήρα. Αυτό αποκαλείται κωδικοποίηση URL (URL encoding).

Ακολουθεί ένας πίνακας μερικών χαρακτήρων που κωδικοποιούνται συχνά :

Κανονικός Χαρακτήρας      String Κωδικοποιημένο με URL Encoding

\t (tab)                                    %09

\n (return)                              %0A

/                                               %2F

~                                              %7E

:                                               %3A

;                                               %3B

@                                            %40

&                                             %26

Για να μπορέσουμε να κάνουμε κάτι χρήσιμο με τα δεδομένα, το CGI πρέπει να τα αποκωδικοποιήσει πρώτα. Ευτυχώς, αυτό είναι αρκετά εύκολο να γίνει στην Perl με τις εντολές substitute και translate. Η Perl έχει ισχυρές δυνατότητες σύγκρισης και αντικατάστασης, όπως θα δούμε αναλυτικά αργότερα. Η βασική σύνταξη για την αντικατάσταση (substitution) είναι η εξής :

$mystring =~ s/pattern/replacement/;

Αυτή η εντολή αντικαθιστά το pattern με το replacement στη μεταβλητή scalar $mystring. Ο τελεστής είναι ο =~, που είναι ένας ειδικός τελεστής της Perl, που την ενημερώνει ότι πρόκειται να κάνει μια σύγκριση ή μια αντικατάσταση. Ακολουθεί ένα παράδειγμα :

$greetings = "Hello. My name is xnamex.\n";

$greetings =~ s/xnamex/Bob/;

print $greetings;

Ο παραπάνω κώδικας θα τυπώσει το μήνυμα "Hello. My name is Bob.". Έχει αντικατασταθεί το xnamex με το Bob στο string $greetings.

Μια παρόμοια αλλά λίγο διαφορετική είναι η εντολή translate :

$mystring =~ tr/searchlist/replacementlist/;

Αυτή η εντολή μετατρέπει (translates) τον κάθε χαρακτήρα που υπάρχει στην searchlist στον αντίστοιχό του χαρακτήρα στην replacementlist σ’ όλη την έκταση του $mystring. Μια κοινή χρήση αυτής της εντολής είναι για να μετατρέψουμε όλους τους χαρακτήρες ενός string από κεφαλαία σε πεζά :

$lowerc =~ tr/[A-Z]/[a-z]/;

Η εντολή αυτή κάνει όλα τα γράμματα του $lowerc να είναι πεζά. Οι αγκύλες [A-Z] δηλώνουν μια τάξη χαρακτήρων που θα ταιριάζει.

 

Αποκωδικοποίηση Δεδομένων Φόρμας

Με τη μέθοδο POST, τα δεδομένα φόρμας στέλνονται σαν μια ροή εισόδου (input stream) από τον server στο CGI. Για να πάρουμε αυτά τα δεδομένα, να τα αποθηκεύσουμε και να τα αποκωδικοποιήσουμε, θα χρησιμοποιήσουμε τον εξής κώδικα :

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});

@pairs = split(/&/, $buffer);

foreach $pair (@pairs) {

    ($name, $value) = split(/=/, $pair);

    $value =~ tr/+/ /;

    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

    $FORM{$name} = $value;

}

Πρώτα, διαβάζουμε το input stream με την εξής εντολή :

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});

Το input stream έρχεται με την στάνταρτ είσοδο STDIN (standard input) και χρησιμοποιούμε τη συνάρτηση διαβάσματος της Perl για να αποθηκεύσουμε τα δεδομένα στη μεταβλητή scalar $buffer. Η τρίτη παράμετρος της συνάρτησης read καθορίζει το μήκος των δεδομένων που θα διαβαστούν. Θέλουμε να διαβάσουμε μέχρι το τέλος της CONTENT_LENGTH, που είναι ορισμένη σαν μια μεταβλητή περιβάλλοντος από τον server.

Μετά χωρίζουμε το buffer σ’ έναν πίνακα από ζευγάρια :

@pairs = split(/&/, $buffer);

Όπως και με τη μέθοδο GET, τα ζευγάρια δεδομένων μιας φόρμας χωρίζονται με τους χαρακτήρες & όταν μεταδίδονται, όπως π.χ. fname=joe& lname=smith. Τώρα θα χρησιμοποιήσουμε έναν βρόχο foreach για να διαχωρίσουμε επιπλέον το κάθε ζευγάρι στα σύμβολα = :

foreach $pair (@pairs) {

    ($name, $value) = split(/=/, $pair);

Η επόμενη εντολή μετατρέπει το κάθε σύμβολο + ξανά σε κενό :

$value =~ tr/+/ /;

Ακολουθεί μια μάλλον περίπλοκη έκφραση που αντικαθιστά το κάθε 16δικό ζευγάρι %HH πίσω στο ισοδύναμό του σύνολο χαρακτήρων ASCII, με τη συνάρτηση pack(). Θα δούμε πώς ακριβώς λειτουργεί αυτό αργότερα, αλλά προς το παρόν θα το χρησιμοποιήσουμε για να αναλύσουμε (parse) τα δεδομένα της φόρμας :

$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

Τέλος, αποθηκεύουμε τις τιμές σ’ ένα hash με όνομα %FORM :

$FORM{$name} = $value;

}

Τα keys του %FORM είναι τα ίδια τα ονόματα των πεδίων input της φόρμας. Έτσι, για παράδειγμα, αν έχουμε τρία πεδία κειμένου στη φόρμα, με ονόματα name, email-address και age, θα μπορούμε να αναφερόμαστε σ’ αυτά στο script χρησιμοποιώντας τα $FORM{'name'}, $FORM{'email-address'} και $FORM{'age'}.

Για να το δοκιμάσουμε, ξεκινάμε ένα καινούργιο CGI και το ονομάζουμε post.cgi. Γράφουμε τα ακόλουθα, τα αποθηκεύουμε και εκτελούμε την εντολή chmod :

#!/usr/bin/perl

print "Content-type:text/html\n\n";

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});

@pairs = split(/&/, $buffer);

foreach $pair (@pairs) {

    ($name, $value) = split(/=/, $pair);

    $value =~ tr/+/ /;

    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

    $FORM{$name} = $value;

}

print "<html><head><title> Form Output </title> </head><body>";

print "<h2> Results from FORM post </h2>\n";

foreach $key (keys(%FORM)) {

    print "$key = $FORM{$key}<br>";

}

print "</body></html>";

Αυτός ο κώδικας μπορεί να χρησιμοποιηθεί για να διαχειριστούμε σχεδόν οποιαδήποτε φόρμα, από μια απλή φόρμα βιβλίου επισκεπτών (guest-book form) μέχρι μια περισσότερο πολύπλοκη φόρμα παραγγελίας. Όποιες μεταβλητές έχουμε στη φόρμα, αυτό το CGI θα τις εκτυπώσει μαζί με τα δεδομένα που καταχωρήθηκαν.

Για να δοκιμάσουμε το script, δημιουργούμε μια HTML φόρμα με τα εξής πεδία :

<form action="post.cgi" method="POST">

    Όνομα : <input type="text" name="name">

    Email : <input type="text" name="email">

    Ηλικία : <input type="text" name="age">

    Αγαπημένο Χρώμα : <input type="text" name="favorite_color">

    <input type="submit" value="Αποστολή">

    <input type="reset" value="Καθάρισμα Φόρμας">

</form>

Εισάγουμε κάποια στοιχεία στα πεδία και κάνουμε κλικ στο πλήκτρο Αποστολή όταν είμαστε έτοιμοι. Η έξοδος θα αποτελείται από τα ονόματα των μεταβλητών αυτών των πλαισίων κειμένου μαζί με τα δεδομένα που καταχωρήσαμε σε κάθε πεδίο.

 

back.gif (9867 bytes)

Επιστροφή