Bölüm 6: Dosya İşlemleri
Daha ileri seviye CGI uygulamaları hazırlamaya başladığınızda bilgileri daha sonra kullanmak üzere dosyalara yazarak saklamak isteyeceksiniz. Mesela bir misafir defteri (guestbook) programınız olabilir ve isim, e-mail gibi bilgileri bir log dosyasına kaydetmek isteyebilirsiniz. Ya da bir sayac programının bir dosyadaki sayıyı arttırmasını isteyebilirsiniz. Hatta bir veritabanı dosyasından bilgi tarayarak bulup web sayfasına yazdıran bir program yapmak isteyebilirsiniz. Bütün bunları yapabilmek için dosya işlemlerini yani dosyadan bilgi okuma ve dosyaya bilgi yazmayı öğrenmelisiniz.
Çoğu server minimum erişim yetkileriyle çalışır. Bu server'ın güvenliği açısından önemlidir fakat dosyalara yazmayı güçleştirir. CGI programının yeni dosyalar oluşturmaya yetkisi yoktur. CGI programının dosyaya bilgi yazabilmesi için dosyanın erişim yetkilerinin aşağıdaki komutla "herkes tarafından yazılabilir" yapılması gerekir.
chmod 666 <dosya adı>
Bu komut dosyanın herkes tarafından okunabilir ve yazılabilir olmasını sağlar. Yalnız işin bir de kötü tarafı var. Server'ınızdaki diğer kullanıcılar rahatlıkla dosyanızı silebilirler. Ve malesef bu konuda diğer kullanıcılara güvenmekten başka yapabileceğiniz birşey yok
Eğer dosyayı sadece içinden bilgi okumak için kullanacaksanız aşağıdaki komutula sadece okuma yetkisi verebilirsiniz.
chmod 644 <dosya adı>
Dosyaları Açma
Dosyaları açmak için open komutunu kullanırız.
open(dosyadegiskeni,dosyaadi);
Şimdi bunu açıklamak için birkaç örnek verelim.
open(DOSYA,"bilgi.txt"); # bilgi.txt dosyasını okumak için açar
open(DOSYA,">bilgi.txt"); # bilgi.txt dosyasını üstüne yazmak için açar
open(DOSYA,">>bilgi.txt"); # bilgi.txt dosyasını eklemek için açar
Dosya değişkeni, dosyanın programda kullanılacak olan adıdır diyebiliriz. Yani dosyayı açtıktan sonra programın bir yerinde dosyaya erişmek için dosyanın sistemdeki adını değil dosya değişkenini kullanırız. Bu örneklerde dosya değişkeni "DOSYA" olarak seçilmiştir. Fakat dosya değişkeni olarak istediğiniz şeyi yazabilirsiniz.
Dosyanın adının başında eğer > işareti varsa dosya üstüne yazılmak için açılmıştır yani dosyada bulunan bütün bilgiler silinir ve yerine yenileri yazılır. Dosyanın adının başında eğer >> işareti varsa dosya sonuna bilgi eklemek için açılmıştır yani dosyada bulunan bilgiler silinmeden yeni yazacaklarımız dosyadaki bilgilerin sonuna eklenir.
Bu arada bir konuda sizi uyarmak istiyorum: CGI programınız eğer tam yolunu yazmamışsanız dosyanızı bulamayabilir. Bu yüzden sadece "bilgi.txt" yazmak yerine "/home/httpd/cgi-bin/bilgi.txt" şeklinde dosyanın tam yolunu yazmanız gerekebilir.
Dosya açmak için yukarıda kullandığımız kodun eksik bir yönü var: Hata kontrolü. Dosyanın açıldığından emin olmak için dosyayı aşağıda gösterildiği şekilde açmalısınız.
open(DOSYA,">bilgi.txt") or &hata("bilgi.txt dosyası bulunamadı...");
Burada 4. bölümdeki hata alt programı kullanılarak dosya açılmadığı takdirde programın gerekli açıklamayı yazdırarak Perl'den çıkması sağlanır.
Şimdi geçen bölümde yazdığımız "form.cgi" programında bazı değişiklikler yaparak form bilgilerini bir dosyaya yazdıralım. Aşağıdaki kodları "form2.cgi" adıyla kaydedin.
#!/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;
$deger =~ s/\n/ /g; # satır sonu işaretlerini yok etmek için eklendi
$FORM{$isim} = $deger;
}
open(DOSYA,">>formbilgileri.txt") or &hata("formbilgileri.txt dosyası açılamadı. Lütfen silyas\@esentepe.sau.edu.tr adresine mail atarak webmaster'ı uyarınız.");
print DOSYA "$FORM{'isim'}|$FORM{'email'}|$FORM{'nasilulasti'}|$FORM{'puan'}|";
%secim = ("wds" => "Web Design",
"wsy" => "Web Server Yöneticiliği",
"tic" => "Electronic Commerce",
"als" => "Elektronik Ticaret",
"egt" => "İnternet Aracılığıyla Eğitim" );
foreach $anahtar (keys %secim) {
if ($FORM{$anahtar} == 1) {
print DOSYA "$anahtar,";
}
}
print DOSYA "|$FORM{'yorum'}\n";
close(DOSYA);
print <<HTMLSonu;
<html><head><title>Teşekkürler</title></head>
<body>
<h2>Teşekkürler</h2>
Gönderdiğiniz bilgiler kaydedildi.
</body></html>
HTMLSonu
;
sub hata {
($hatamesaji) = @_;
print "<h2>Hata!</h2>\n";
print $hatamesaji;
exit;
}
Şimdi bilgilerin yazılacağı dosyayı oluşturup "yazılabilir" yapmalısınız. Bunun için programı kaydettiğiniz dizinde şu komutları yazın:
touch formbilgileri.txt
chmod 666 formbilgileri.txt
touch komutu ile yeni ve boş bir dosya oluşturulur ve chmod komutu ile herkesin dosyaya yazabilmesi sağlanır.
Şimdi "form.html" dosyasını açın ve formu "form2.cgi" ile göndermesi için gerekli değişikliği yapın. Sonra da "form2.html" adıyla kaydedin. Formu doldurup gönderdiğinizde herşey yolunda gitmişse "formbilgileri.txt" dosyasının içeriği aşağıdaki gibi olacaktır.
sinan ilyas|silyas@esentepe.sau.edu.tr|1|5|wds,egt,|siteniz harika
Bu şekilde text dosyasından oluşan ve her satırı yeni bir kayıt olan veritabanı dosyalarına "flat-file database" denir. Bu örnekte alanlar pipe (|) işareti ile ayrılmıştır. İsterseniz gönderilen bilgide bulunmacak başka bir karakter kullanabilirsiniz.
Yukarıdaki kodla ilgili bir şeyi daha açıklayalım.
$deger =~ s/\n/ /g;
Bu satırla ifadelerin sonlarındaki satır sonu işarertlerini yok ediyoruz çünkü veritabanı dosyamızda her kaydın tek satırda olması gerekiyor. Ayrıca, dikkat etmişseniz peşpeşe birkaç print komutu kullanmamıza rağmen herşey tek bir satıra yazdırıldı. Bunun nedeni son print komutuna kadar \n ifadesini kullanmamış olmamız.
Buna bir örnek verirsek sanırım daha iyi anlaşılır.
print "Merhaba, ";
print "ben ";
print "Sinan.\n";
Kodları aşağıdaki gibi bir çıktı verir.
Merhaba, ben Sinan.
Dosyaları Kapatma
Dosya ile işiniz bittiği zaman dosyayı kapatmalısınız. Bunu aşağıdaki komutla yapabilirsiniz.
close(dosyadegiskeni);
Dosyalardan Bilgi Okuma
Bir gün merak edip formla gönderilen bilgilerin bir özetini görmek isteyebilirsiniz. Bunun için programda bilgilerin kaydedildiği dosyayı açtırıp bütün kayıtları okutup gereken hesapları yaptırmalısınız.
Bir dosyadan bilgiyi okuturken ister tek bir satırı, isterseniz bütün dosyayı okuyabilirsiniz. İşte bir örnek:
open(DOSYA,"formbilgileri.txt") or &hata("Dosya açılamadı.");
$a = <DOSYA>; # $a değişkenine dosyadan bir tek satır okur
@b = <DOSYA>; # @b değişkenine dosyanın tamamını okur
close(DOSYA);
Bu kodlar "formbilgileri.txt" dosyasının ilk satırını $a scalar değişkenine, geri kalan satırları @b dizisine okur. Bu durumda @b disizinin her bir elemanı bir satır olur. Her iki kod satırında da okutma işi <DOSYA> koduyla yapılıyor. Dosyadan ne kadar bilgi okunacağını atanacağı değişkenin tipi belirliyor.
Aşağıdaki dosyanın tamamını bir diziye okuduktan sonra dosyanın içeriğini satır satır ekrana yazdırır.
open(DOSYA,"formbilgileri.txt") or &hata("Dosya açılamadı.");
@bilgiler = <DOSYA>;
close(DOSYA);
foreach $satir (@bilgiler) {
chomp($satir);
print "$satir\n";
}
Bu kodlar dosyanın açık kalma süresini en aza indirir. Bu yüzden dosyadan bilgi okurken bu metodu kullanmanızı tavsiye ederim.
Şimdi "formbilgileri.txt" dosyasından bilgileri okuyup kaç kişinin formu gönderdiğini, siteye en çok hangi yolla ulaşıldığını, siteye verilen puanların ortalamasını, hangi bilgisayar alanıyla kaç kişinin ilgilendiğini ve yapılan yorumların listesi yazdıran bir CGI programı yazalım.
Şimdi "özet.cgi" adında yeni bir dosya oluşturun ve içine şu kodları yazın:
#!/usr/bin/perl
print "Content-type:text/html\n\n";
open(DOSYA,"formbilgileri.txt") or &hata("formbilgileri.txt dosyası açılamadı. Lütfen silyas\@esentepe.sau.edu.tr adresine mail atarak webmaster'a haber verin.");
@bilgiler = <DOSYA>;
close(DOSYA);
# Bilgileri özetlemek için önce bazı değişkenler hazırlanıyor.
$sayi = 0; # Formu gönderenlerin sayısı
$toplampuan = 0; # Verilen puanların toplamı
$yorumlar = ""; # Gönderilen bütün yorumlar
%nasilulasti_sayisi = (); # Hangi şekilde kaç kişinin ulaştığı
%ilgi = (); # Hangi bilgisayar alanıyla kaç kişinin ilgilendiğinin sayısı
%nasilulasti = ( 0 => "",
1 => "Direk adresini yazdım",
2 => "Siteyi bookmark etmiştim",
3 => "Arama motorundan buldum",
4 => "Başka bir siteden",
5 => "Adresi bir kitaptan aldım",
6 => "Diğer" );
foreach $i (@bilgiler) {
chomp($i);
($isim,$email,$nasil,$puan,$secim,$yorum) = split(/\|/,$i);
# Bu satır "$sayi = $sayi + 1" ile aynı işi görür.
$sayi++;
$toplampuan = $toplampuan + $puan;
# Bu satır $yorumlar değişkeninin sonuna $yorum değişkeninin
# içeriğini ekler.
$yorumlar .= "$yorum\n";
$nasilulasti_sayisi{$nasil}++;
@ilgilistesi = split(/,/,$secim);
foreach $j (@ilgilistesi) {
$ilgi{$j}++;
}
}
# Verilen puanlarınn ortalaması bulunuyor.
if ($sayi > 0) { # Sıfıra bölmemek için
$ort_puan = int($toplampuan / $sayi);
} else {
$ort_puan = 0;
}
# Sonuçları bildiren web sayfası hazırlanıyor.
print <<HTMLSonu;
<html><head><title>Özet</title></head>
<body>
<h2>Özet</h2>
Gönderilen form sayısı: $sayi<p>
Verilen puanların ortalaması: $ort_puan<p>
Siteye kaç kişinin ne şekilde ulaştığı:<br>
<ul>
<li>(yanıtlamayan) - $nasilulasti_sayisi{0}
<li>$nasilulasti{1} - $nasilulasti_sayisi{1}
<li>$nasilulasti{2} - $nasilulasti_sayisi{2}
<li>$nasilulasti{3} - $nasilulasti_sayisi{3}
<li>$nasilulasti{4} - $nasilulasti_sayisi{4}
<li>$nasilulasti{5} - $nasilulasti_sayisi{5}
<li>$nasilulasti{6} - $nasilulasti_sayisi{6}
</ul>
Kaç kişinin hangi bilgisayar alanıyla ilgili olduğu:<br>
<ul>
<li>Web Design: $ilgi{'wds'}
<li>Web Server Yöneticiliği: $ilgi{'wsy'}
<li>Electronic Commerce: $ilgi{'tic'}
<li>Elektronik Ticaret: $ilgi{'tic'}
<li>İnternet Aracılığıyla Eğitim: $ilgi{'egt'}
</ul><p>
Sayfa Hakkında Yorumlar:<p>
$yorumlar
HTMLSonu
;
sub hata {
($hatamesaji) = @_;
print "<h2>Hata!</h2>\n";
print $hatamesaji;
exit;
}