Bölüm 3: CGI Ortam Değişkenleri
Ortam değişkenleri CGI programı çalıştırılıdığı zaman browser'ınızın (ve web server'ınızın) programa gönderdiği bilgilerdir. Ortam değişkenleri %ENV isimli Hash değişkende saklanır.
CGI Ortam Değişkenleri
DOCUMENT_ROOT Server'ınızın kök dizinini verir.
HTTP_COOKIE Eğer varsa ziyaretçinin "cookie"sini verir.
HTTP_HOST Server'ınızın "hostname"ini verir.
HTTP_REFERER Scriptin çağrıldığı sayfanın adresini verir.
HTTP_USER_AGENT Ziyaretçinin browser'ının tipini verir.
PATH Server'ınızın "system path"ini verir. (Genelde /bin, /usr/sbin vs.)
QUERY_STRING GET metodu ile yollanan bilgiyi verir.
REMOTE_ADDR Ziyaretçinin IP adresini verir.
REMOTE_HOST Ziyaretçinin "hostname"ini verir. (*)
REMOTE_PORT Ziyaretçinin web server'ınıza bağlandığı portu verir.
REMOTE_USER Ziyaretçinin kullanıcı adını verir. (.htaccess korumalı sayfalar için)
REQUEST_METHOD Bilgi gönderme metodunu verir. (GET ya da POST)
SCRIPT_FILENAME Scriptin tam yolunu verir.
SERVER_ADMIN Server'ınızın webadmin'inin e-mail adresini verir.
SERVER_NAME Server'ınızın tam domain adını verir. (Örn: cc.sau.edu.tr)
SERVER_PORT Server'ınızın dinlemede olduğu portu verir.
SERVER_SOFTWARE Serverdaki web server programını verir. (Örn: Apache 1.3)
(*) Eğer server'ınızda "reverse-name-lookups" yoksa REMOTE_HOST ziyaretçinin IP adresini verir.
Bazı server'larda bunlardan başka değişkenler de olabiliyor. Daha fazla bilgi için server'ınızın dökümanlarını inceleyiniz. Farketmişseniz bazı değişkenler server'la ilgili, bazıları ise ziyaretçi ile ilgili bilgileri içeriyor. Server'la ilgili olanların programa bildirdiği bilgiler o server'da çalışan bütün CGI programları için aynı olacaktır. Fakat ziyaretçi ile ilgili bilgiler program her çalıştırıldığında farklı olabilir.
Her CGI çalıştırıldığında bütün ortam değişkenleri atanmaz. REMOTE_USER değişkeni sadece .htaccess dosyası ile korunan dizin ya da altdizinler için atanır. Bu durumda REMOTE_USER değişkeninin alacağı değer .htaccess dosyasındaki kullanıcı adıdır.
%ENV değişkeni CGI çalıştırıldığında otomatik olarak atanır ve isterseniz tamamını isterseniz sadece belli değerleri kullanabilirsiniz. Mesela aşağıdaki kod ile ziyaretçinin IP adresini yazdırabilirsiniz.
print "IP adresiniz: $ENV{'REMOTE_ADDR'}\n";
Şimdi bütün ortam değişkenlerini yazdıran bir CGI yazalım. Yeni bir dosya oluşturun, "ortam.cgi" adıyla kaydedin ve içine şunları yazın:
#!/usr/bin/perl
print "Content-type:text/html\n\n";
print <<HTMLSonu;
<html><head><title>Ortam Değişkenleri</title></head>
<body>
HTMLSonu
;
foreach $anahtar (sort(keys %ENV)) {
print "$anahtar = $ENV{$anahtar}<br>\n";
}
print "</body></html>";
Scripti kaydedin, erişim yetkilerini 755 olarak ayarlayın ve browser'ınızdan çağırın. Eğer hata mesajı alırsanız programı UNIX'te çalışmayı deneyip hatanın nerede olduğunu öğrenebileceğinizi hatırlayın.
Bu örnekte sort fonksiyonu kullanılarak %ENV değişkeninin anahtarları alfabetik sıraya koyduk. Perl'ün sort fonksiyonu karakter değerlerini karşılaştırdığı için sayıları düzgün bir şekilde sıraya koyamaz.
Basit Bir Sorgu Formu
Bir HTML formundan CGI'a bilgi göndermek için iki yol vardır. GET ve POST. Form bilgisinin server'a nasıl yollandığını bu metodlar belirler. GET metodunda formla gönderilen bilgiler URL'in bir parçası olarak gönderilir ve QUERY_STRING ortam değişkenine atanır. POST metodunda nasıl gönderildiğini bir sonraki bölümde anlatacağız.
QUERY_STRING değişkenine birkaç değişik yolla atama yapabiliriz. Birinci yöntem aşağıda görüldüğü gibidir.
http://hammer.prohosting.com/cgi-bin/ortam.cgi?deneme1 http://hammer.prohosting.com/cgi-bin/ortam.cgi?deneme2 http://hammer.prohosting.com/cgi-bin/ortam.cgi?deneme3 Yukarıdaki linklerin her birine tıklayın. QUERY_STRING değişkeninin değerinin soru işaretinden sonra gelen yazı olduğunu göreceksiniz. Bu örneklerde QUERY_STRING değişkeni "deneme1","deneme2" ve "deneme3" değerlerini alır.
Bir başka yöntem de aşağıdaki gibi basit bir form hazırlamaktır.
<form action="http://hammer.prohosting.com/~sinan/cgi-bin/ornek/ortam.cgi" method="GET">
Buraya birşeyler yazın: <input type="text" name="ornek_yazi" size=30><p>
</form>
"Gönder" düğmesinin olmadığını farketmişsinizdir sanırım. GET metodu ile sadece enter'a basarsınız ve form gönderilir. (Bu yöntem sadece bir tane girdi alanı olduğu zaman işe yarar. Birden fazla girdi alanını göndermek için mutlaka "Gönder" düğmesi koymalısınız.)
Yukarıdaki kodları kullanarak bir HTML dosyası hazırlayın ve "get.html" adıyla kaydedip browser'ınızla açın. Daha sonra form alanına birşeyler yazın ve enter'a basın. QUERY_STRING değişkeninin değeri aşağıdaki gibi olur.
$ENV{'QUERY_STRING'} = ornek_yazi=iste+yazdiginiz+yazi
Eşittir (=) işaretinin solundaki yazı form alanının adıdır. Sağındaki yazı ise formdaki kutucuğa yazdığınız yazıdır. FAKAT farkettiğiniz gibi boşlukların yerini artı (+) işareti almış. Hatta çeşitli noktalama işaretleri ve özel karakterlerin yerine %-kod şeklinde özel kodlar çıkmış.
Buna "URL Kodlama" denir ve ister GET metodu ister POST metodu kullanılsın, herhangi bir form ile bilgi gönderildiği zaman meydana gelir.
Perl scriptiniz bu bilgiyi eski haline getirebilir fakan uzun ve karmaşık bilgiler yollandığında POST metodunu kullanmak daha iyidir. GET metodu daha çok veritabanından bilgi aratma gibi tek alanlı formlar için elverişlidir.
GET metodu ile birden fazla alanlı formları da gönderebilirsiniz.
<form action="http://hammer.prohosting.com/~sinan/cgi-bin/ornek/ortam.cgi" method="GET">
Adınız: <input type="text" name="ad" size=30><p>
Soyadınız: <input type="text" name="soyad" size=30><p>
<input type="submit" value="Gönder">
</form>
Bo formla gönderilen bilgiler aşağıdaki gibi görünür.
$ENV{'QUERY_STRING'} = ad=umut+baris&soyad=ruzgar
Değerler & işareti ile ayrılmıştır. Bu iki değeri birbirinden ayırmak için Perl'ün split fonksiyonunu kullanacağız.
@degerler = split(/\&/,$ENV{'QUERY_STRING'});
foreach $i (@degerler) {
($alanadi, $deger) = split(/=/,$i);
print "$alanadi = $deger\n";
}
split fonksiyonu bir karakter sırasını, belirtilen karakter ya da karakterlerden ayırarak bir dizi oluşturur. Örneğimizin ilk satırında QUERY_STRING değişkeninin değeri & işaretinden ikiye ayrılmıştır. & işaretinden önce \ kullanılmasının nedeni & işaretinin Perl'de özel bir anlamı olmasıdır. (Perl'de bazı özel karakterleri kullanırken başına \ işareti koymamız gerekebilir). Bu ayırma işlemi sonucu @degerler dizisine iki değer atanır: ad=umut+baris ve soyad=ruzgar. foreach döngüsünde önce = işaretinden alan adı ve alanlara yazılan yazılar birbirinden ayrılarak $alanadi ve deger değişkenlerine atanır. Sonra da birbirinden ayrılmış olan bu değerler yazdırılır.
GET metodu hakkında bazı uyarılar: Bu metod bilgi göndermek için güvenli değildir. Bu yüzden şifre ve kredi kartı bilgileri gibi gizli bilgileri gönderirken asla bu metodu kullanmayınız. Gönderilen bilgi URL'in bir parçası olarak gönderildiği için server'ın log dosyalarında kaydedilir ve log dosyaları da server'daki bütün kullanıcılar tarafından okunabilir. Gizli bilgiler bir sonraki bölümde göreceğimiz POST metodu ile güvenli bir biçimde gönderilebilir.
Bölüm 4: Form İşleme
POST metodunda bilgiler URL ile birlikte gönderilmediği GET metodundan daha güvenlidir. POST metodunun GET metoduna bir diğer üstünlüğü de daha fazla bilgi gönderebilmesidir. Ayrıca, GET metodu ile gönderilen bilgiler web browser, web server ya da proxy server'ın kaşe belleğinde (cache) saklanabilir fakat POST metodu ile bilgiler her defasında yeniden gönderilir. Dezavantajı ise POST ile gönderilen bilgiler daha karmaşık olacağından dolayı bu bilgileri çözmek için daha biraz daha karmaşık bir kod yazmamız gerekir.
Web server, form bilgilerini CGI programına kodlayarak gönderir. Alfanumerik karakterler olduğu gibi gönderilir; boşluklar artı (+) işaretine çevrilir; tab, çift tırnak (") gibi özel işaretler de "%HH" şeklinde kodlanır. Burada "HH" karakterin ASCII karşılığının hexadesimal (16'lık sistemdeki) değeridir. Bu kodlama işlemine "URL kodlama" denir. Aşağıdaki tabloda sık kullanılan bazı karakterlerin kodlanmış karşılıklarını görebilirsiniz.
Normal
Karakter Kodlanmış
Hali
\n (enter) %0A
\t (tab) %09
/ %2F
~ %7E
: %3A
; %3B
@ %40
& %26
Gönderilen bilgiyle işe yarar şeyler yapabilmek için CGI bu kodlanmış bilgiyi çözmelidir. Neyse ki Perl'de substitute ve translate komutlarıyla bunu yapmak oldukça kolaydır. Perl, karakter içerisinde arama yapma ve değiştirme konusunda oldukça yeteneklidir. substitute komutunun temel yazılış biçimi aşağıdaki gibidir.
$yazi =~ s/aranan/yerinekonan/;
Bu örnek $yazi scalar değişkeninde aranan kelimesinin yerine yerinekonan kelimesini koyar. Araya konan operatör =~ (eşittir ve yanında tilde) işaretidir.
Daha iyi anlaşılacağını düşündüğüm başka bir örnek:
$selamlama = "Merhaba. Benim adım xisimx.\n";
$selamlama =~ s/xnamex/Sinan/;
print $selamlama;
Yukarıdaki örnek "Merhaba. Benim adım Sinan." yazdıracaktır. $selamlama değişkeninde "xisimx"in yerini "Sinan"ın aldığına dikkat edin.
Buna yakın fakat bir parça farklı bir komut da translate komutudur.
$yazi =~ tr/arananlistesi/yerinekonanlistesi/;
Bu komut "arananlistesi"ndeki bütün karakterleri "yerinekonan" listesindekilerle değiştirir. İşte bir örnek:
$kucukh =~ tr/[A-Z]/[a-z]/;
Bu örnek bütün yazıyı küçük harfe çevirir. [A-Z]'deki parantezler karşılaştırılacak karakter sınıfını belirtir.
Şimdi tekrar formlara dönelim. Formla gönderilen bilginin kodunu çözmeniz için bilgide iki değişiklik yapmalısınız:
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
İlk satırda + işaretleri boşluğa çevrilir. İkinci satırda ise pack() fonksiyonu kullanılarak %HH hex çiftleri ASCII karşılıklarına çevrilir.
Şimdi "post.cgi" adında yeni bir CGI hazırlayalım.
#!/usr/bin/perl
print "Content-type:text/html\n\n";
read(STDIN, $tampon, $ENV{'CONTENT_LENGTH'});
@ciftler = split(/&/, $tampon);
foreach $cift (@ciftler) {
($isim, $deger) = split(/=/, $cift);
$deger =~ tr/+/ /;
$deger =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$FORM{$isim} = $deger;
}
print "<html><head><title>Form Bilgileri</title></head><body>";
print "<h2>Formla gönderilen bilgiler:</h2>\n";
foreach $anahtar (keys(%FORM)) {
print "$anahtar = $FORM{$anahtar}<br>";
}
print "</body></html>";
Şimdi yukarıdaki kodları açıklayalım. Form ile gönderilen bilgi önce $tampon scalar değişkenine okunuyor. Sonra & işaretlerinden ayrılarak elde edilen "formdegiskeni=deger" şeklindeki form alanı bilgileri @ciftler dizisine yerleştiriliyor. Sonra foreach döngüsünde herbir form alanı bilgisi = işaretinden ayrılıyor ve URL kodu çözülerek %FORM Hash değişkenine atanıyor. %FORM değişkenindeki anahtar adları form alanının adıdır. Mesela <input type="text" name="ad" size=30> HTML kodunda koyu yazılan "ad" değeri form alanının adıdır. Formunuzda "ad" ve "soyad" isimli iki form alanı varsa scriptinizde bu değerleri $FORM{'ad'} ve $FORM{'soyad'} şeklinde kullanabilirsiniz.
Aşağıdaki örneği inceleyerek split fonksiyonunun nasıl çalıştığını hatırlayalım.
$yazi = "sari&kirmizi&yesil";
@renkler = split(/&/,$yazi);
@renkler değişkeninin yeni değeri ("sari","kirmizi","yesil") olur.
Şimdi de scriptimizi denemeye geldi sıra. Form için aşağıdaki kodları kullanarak bir HTML dosyası oluşturun ve "post.html" adıyla kaydedin.
<form action="http://hammer.prohosting.com/~sinan/cgi-bin/ornek/post.cgi" method="POST">
<pre>
Adınız: <input type="text" name="ad" size=30><br>
Soyadınız: <input type="text" name="soyad" size=30><br>
</pre>
<input type="submit" value="Gönder">
<input type="reset" value="Tümünü Sil">
</form>
İsterseniz scriptimizi biraz daha geliştirelim. Scriptimiz form bilgilerini mail adresimize göndersin. İlk önce sistemimizde sendmail programının nerede olduğunu bulalım. Bunu öğrenmek için which sendmail ya da whereis sendmail komutunu kullanabilirsiniz. (benim kullandığım serverda bu programın yeri /usr/sbin/sendmail olduğundan örneklerimizde bu şekilde kullanacağız. Eğer sizin server'ınızda farklı bir yerde ise kendi server'ınızdaki yerini yazmanız gerekir.)
Not: @ işaretini çift tırnak arasında ya da print <<HTMLSonu bloğunda kullanırken önüne "silyas\@esentepe.sau.edu.tr" örneğindeki gibi \ işareti koymalısınız. Tek tırnak arasında 'silyas@esentepe.sau.edu.tr' örneğinde olduğu gibi \ işareti koymadan güvenle kullanabilirsiniz.
#!/usr/bin/perl
print "Content-type:text/html\n\n";
read(STDIN, $tampon, $ENV{'CONTENT_LENGTH'});
@ciftler = split(/&/, $tampon);
foreach $cift (@ciftler) {
($isim, $deger) = split(/=/, $cift);
$deger =~ tr/+/ /;
$deger =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$FORM{$isim} = $deger;
}
$mailprog = '/usr/sbin/sendmail';
# bunu kendi mail adresinizle değiştirin
$gonderilen = 'silyas@esentepe.sau.edu.tr';
# burada maili göndermek üzere sendmail programı açılıyor
# eğer sendmail programı bulunamazsa hata alt programı (en altta)
# işletilerek programın bulunamadığı yazıyor
open (MAIL, "|$mailprog -t") or &hata("$mailprog bulunamadı!\n");
# sendmail programına mailin kime gönderileceği bildiriliyor
print MAIL "To: $gonderilen\n";
# sendmail programına ziyaretçinin email adresi bildiriliyor.
# bu "Yanıtla" tuşuna bastığınızda işe yarar
# kullanmak zorunda değilsiniz
# formunuzda 'email' ve 'isim' kutularının bulunduğu varsayılmıştır.
print MAIL "Reply-to: $FORM{'email'} ($FORM{'isim'})\n";
# sendmail programına mailin konusu gönderiliyor
# konudan sonra iki tane \n olduğuna dikkat edin
print MAIL "Subject: Form Bilgileri\n\n";
# sendmail programına form bilgileri gönderiliyor
foreach $anahtar (keys(%FORM)) {
print MAIL "$anahtar = $FORM{$anahtar}\n";
}
# bilgiler gönderildikten sonra sendmail programını kapatmayı unutmayın
close(MAIL);
# teşekkür sayfası oluşturuluyor
print <<HTMLSonu;
<html><head><title>Teşekkürler</title></head><body>
<h2>Teşekkürler</h2>
Mailiniz gönderildi. Formu gönderdiğiniz için teşekkürler<p>
</body></html>
HTMLSonu
;
# hata alt programı
sub hata {
($hatamesaji) = @_;
print "<html><head><title>Hata!</title></head><body>"
print "<h2>Hata</h2>\n";
print "$hatamesaji<p>\n";
print "</body></html>\n";
exit;
}
Yukarıdaki scriptte yeni bir yapı kullandık: hata isimli bir "alt program". Alt programlar programların sadece çağırıldıkları zaman işletilen komutlarıdır diyebiliriz. Örneğimizde hata alt programı sadece sendmail programı bulunamazsa çalıştırılır. Programınızın bu durumda size bir server hatası vermesi yerine neyin yanlış gittiğine dair bilgi vermesini istersiniz. hata alt programıyla bu yapılıyor. sendmail programının bulunmadığını bildiren bir web sayfası gösteriyor ve Perl'den çıkıyor. Perl'de alt programlar &altprogramadi ya da &atlprogramadi (argümanlar) şeklinde çağrılır. Argümanlar alt programa gönderilen değerlerdir.
Şimdi aşağıdaki kodlarla bir form oluşturun ve scripti deneyin.
<form action="http://hammer.prohosting.com/~sinan/cgi-bin/ornek/mail.cgi" method="POST">
<pre>
Adınız: <input type="text" name="isim" size=30>
E-mail adresiniz: <input type="text" name="email" size=30>
Web sayfanız: <input type="text" name="web_sayfasi" size=30>
Yaşınız: <input type="text" name="yas" size=3>
</pre>
<input type="submit" value="Gönder">
<input type="reset" value="Tümünü Sil">
</form>
Eğer herşey yolunda giderse birkaç dakika sonra form bilgileri e-mail adresine gelecektir.
Eğer form bilgilerini birkaç adrese birden göndermek istiyorsanız adresleri aşağıdaki gibi aralarına virgül koyarak yazabilirsiniz.
$gonderilen = 'silyas@esentepe.sau.edu.tr',
zeytinbey@bbs.ege.edu.tr,
sinanilyas@hotmail.com';