Perl Tadından PHP

PHP programlama diline hakimsiniz ve bu muazzam dilin nimetlerinden komut satırında da yararlanmak istiyorsunuz. İşte şu an okumakta olduğunuz makale bu amaca yönelik harekete geçilerek yazılmış ufak bir dökümantasyondur. Bu yazı dizisini okuduktan sonra artık komut satırında sizin için gerekli çoğu karakter donanımına ulaşmış olup (stdin, stdout, stderr) bunlar ile kullanıcı ile etkileşimli konsol tabanlı php betikleri yazabilecek hale geleceksiniz.


Yasal Uyarı

Bu belgeyi, Free Software Foundation tarafından yayınlanmış bulunan GNU Genel Kamu Lisansının 2 ya da daha sonraki sürümünün koşullarına bağlı kalarak kopyalayabilir, dağıtabilir ve/veya değiştirebilirsiniz. Bu lisansın bir kopyasını http://www.gnu.org/copyleft/gpl.html adresinde bulabilirsiniz.

Bu belgedeki bilgilerin kullanımından doğacak sorumluluklar, ve olası zararlardan belge yazarı sorumlu tutulamaz. Bu belgedeki bilgileri uygulama sorumluluğu uygulayana aittir.

Tüm telif hakları aksi özellikle belirtilmediği sürece sahibine aittir. Belge içinde geçen herhangi bir terim bir ticarî isim yada kuruma itibar kazandırma olarak algılanmamalıdır. Bir ürün ya da markanın kullanılmış olması ona onay verildiği anlamında görülmemelidir.


İçindekiler

I. Neden Komut Satırında PHP?
II. CLI Nasıl?
III. Giriş
III-1. Merhaba, Dünya!
III-2. Çalışma Esnasında Girilen Değerlerin Algılanması
III-3. Program Argümanları
IV. Özet
 
A. Kaynakça

I. Neden Komut Satırında PHP? [Y, A]

Internet ortamında programlama ile biraz uğraşmış ve bir miktar PHP öğrenmiş biri olarak, GNU/Linux ortamında, ufak tefek ve konsoldan çalışabilen programlar yazmak istediğimde Perl ve C üzerine pek fazla bilgim olmadığından her seferinde yaptığım ufak programcıklar için sayısız deveye hendek atlatıyordum. Ama geçenlerde yaptığım bir araştırma üzerine (IRC'de, irc.freenode.net sunucusundaki #fazlamesai kanalında) bir de baktım ki PHP programlama dili Apache web sunucusunun bir bileşeni olarak kullanılmasının yanı sıra tıpkı Perl ya da C gibi komut satırından çalıştırılabiliyormuş (CLI - Command Line Interface / Komut Satırı Arayüzü). Bu sayede hiç Perl ya da Python gibi güçlü betik-programlama dillerine gerek kalmadan aynı işi PHP ile de yapabilmiş olacağız, kaldı ki bu benim gibi öyle pek de usta olmayan programcılar, ama bunlara her an ihtiyaç duyan yaramaz ev kullanıcıları için de bire bir ;-)

PHP 4.2.0 ve sonrası, size yeni bir SAPI (Server Application Programming Interface / Sunucu Uygulama Geliştirme Arayüzü) olan CLI özelliğini de beraberinde sunmuş oluyor. CLI'nin sağladığı en büyük avantaj, PHP ile komut satırı ve masaüstü için programlar yazabilecek olmanız. Hem de fazladan hiçbir kütüphaneye gereksinim duymadan.

II. CLI Nasıl? [Y, A]

4.3.0 versiyonuna kadar CLI'yi kurulum esnasından aktif hale getirmek zorundaydınız (--enable-cli). Fakat 4.3.0'dan itibaren bu özellik normal olarak aktif edilmiş durumda geliyor PHP sisteminde.

Burada dikkat edilmesi gereken şöyle ufak bir nokta var: Eğer sunucunuzdaki PHP desteğini Apache mödülü şeklinde kurulu ise sistem komut satırında PHP dosyalarını çalıştırmanız için size yeterli olmayacaktır. Bunun için çalıştırılabilir bir "binary" şeklinde PHP'ye ihtiyacımız var. Eğer source tarball'dan kurduysanız sorun yok (çünkü büyük olasılıkla kendi CLI özelliği aktif halde gelecektir). Modül şeklinde kurduysanız bunun binary'si için genel olarak çoğu önceden derlenmiş paket sunan dağıtımlarda (apt gibi) php-cgi şeklinde ayrıca bir paket gelmektedir. CLI için bu da işinizi gayet güzel bir şekilde görecektir.

III. Giriş [Y, A]

Komut satırından çalıştıracağımız çoğu PHP programı için bize gerekli olacak en önemli özelliklerden biri kullanıcının çalışma esnasında atadığı değerlerin algılanmasıdır: Kısacası STDIN (Standart Input). Bunun için iki yolumuz var: Birincisi progamın adı yazılırken girilen argümanlar. Bu tabii ki yeterli bir çözüm sun(a)mayacağından bir de programın çalısma esnasında girilen argümanları var. Hepsine birer örnek vererek konuyu açıklığa kavuşturalım...

1. Merhaba, Dünya! [III, Y, A]

Bir programlama dilin en vazgeçilmez örneğini kullanmadan edemezdik sanırım. Basit ve yumuşak(!) bir giriş yapalım bu PHP-CLI olayına...

shell$
shell$ cat > ornek1.php << EOF
#!/usr/bin/php4
<?php print "Merhaba Dünya!\n"; ?>
EOF
shell$ chmod u+x ornek1.php
shell$ ./ornek1.php
X-Powered-By: PHP/4.3.0
Content-type: text/html
Merhaba, Dünya!
shell$ _

III-2. Çalışma Esnasında Girilen Değerlerin Algılanması [III, Y, A]

Bizim için en çok önem teşkil eden noktanın burası olduğu şüphe götürmez sanırım. Kullanıcıya program esnasında yöneltilen sorular karşısında alınan değerlerin değişkenlerde tutulması veya kullanılarak fonksiyon içinde çalıştırılması için olmazsa olmazlar:

shell$ cat > ornek2.php << EOF
#!/usr/bin/php4
<?php
    print "Lütfen isminizi buraya girin: ";

    /*
     * Burada buffer için gerekli olan 1024 değeri size öntanımlı olarak
     * atanmıştır. Daha ayrıntılı bilgi için fgets komutunun dökümantasyonuna
     * bakmanız yeterli olacaktir.
     */
    $uname = fgets(fopen("php://stdin", "r"), 256);

    print "Merhaba, $uname!\n";
?>
EOF
shell$ chmod u+x ./ornek2.php && ./ornek2.php
Lütfen isminizi buraya girin: Volkan YAZICI
Merhaba, Volkan YAZICI!
shell$ _

STDIN (girdi)'in dışında STDOUT (çıktı) ve STDERR (hata çıktısı) gibi standard I/O stream'lere de (standart giriş/çıkış kanallarına da) sahipsiniz. Ayrınıtılı bilgi için yazının sonunda yer alan kaynakçaya göz atmanız yeterli (Ya da hemen komut satırında man 3 stdin mücizesine de erebilirsiniz). Yine de bunlar hakkında şöyle ufak bir alıntı yapmak gerekirse:

$stdin = fopen('php://stdin', 'r');
$stdout = fopen('php://stdout', 'w');
$stderr = fopen('php://stderr', 'w');

III-3. Program Argümanları [III, Y, A]

PHP, bilindiği üzere C'ye (doğal olarak da Perl'e) çok benzer bir dil (teorik olarak pek fazla C ve Perl bilmediğimden sizleri bu konuda fazla aydınlatamayacağım). Bu yüzden başlangıçta at(tığımız|acağımız) ilk adımlar C bilenlere çok tanıdık gelecektir sanırım...

shell$ cat > ornek3.php << EOF
#!/usr/bin/php4 -q
<?php

    /*
     * Yukarıya eklediğimiz -q parametresi ile başlangıçta yer alan
     * X-Powered-By: PHP... satırlarından kurtulmuş oluyoruz
     */
    print "Toplam Argüman Sayısı = $argc\n";

    // burada print_r() fonksiyonuna da başvurulabilir
    var_dump($argv);

?>
EOF
shell$ chmod u+x ornek3.php
shell$ ./ornek3.php -arg1 -arg2 abc
Toplam Argüman Sayısı = 4
array(4) {
	[0]=>
		string(12) "./ornek3.php"
	[1]=>
		string(5) "-arg1"
	[2]=>
		string(5) "-arg2"
	[3]=>
		string(3) "abc"
}
shell$ _

IV. Özet [Y, A]

Özet olarak fazla söze ne gerek, hepsinin karşımı olan güzel bir program var burada sizler için yazdığım:

shell$ cat > ornek4.php << EOF
#!/usr/bin/php4 -q
<?php

    // Timeout olmaması için var olan zaman sınırını kaldırıyoruz
    set_time_limit(0);

    // Bakalım kullanıcımız ismini girmiş mi?
    if ( $argc == 1 ) {
        print ">>> İsminizi girmeyi unuttunuz!\n" .
              ">>> Kullanım: " . $argv[0] . " Your Name\n";
        exit();
    } else {
        for ( $n = 1; $n < $argc; $n++ )
            $uname .= $argv[$n] . " ";
    }

    /*
     * Asıl nokta olan komut satırına girilen değerleri almak için
     * kullandığımız stdin değerini STDIN'e atıyoruz. Aksi halde her
     * seferinde fopen("php://stdin", "r") satırını yazmak zorunda kalırız.
     */
    define("STDIN", fopen("php://stdin","r"));

    /*
     * İşlem giriş çıkışlarının herbiri için teker teker bir fonksiyon
     * tanımlamak yerine hepsini bir class içine attım.
     * Eh biraz da OOP (Object Oriented Programming) armutundan yiyelim ;)
     */
    class process {
        var $menu, $key;

        // Varolan menüyü listelemk için kullanacağımız fonksiyon.
        function listMenu() {
            $this->menu = array( array("s", "Sistem Bilgisi"),
                                 array("d", "Geçerli Tarih"),
                                 array("q", "Çıkış") );
            print ">>> Please select your process below...\n\n";
            for ( $i = 0; $i < count($this->menu); $i++ )
                print " [" . $this->menu[$i][0] . "] " . $this->menu[$i][1] . "\n";

            print "\n";
        }

        /*
         * Menü ekrana yazdırıldıktan sonra girilen tuşa göre açacağımız
         * menüyü algılayacak olan fonksiyon
         */
        function getKey() {
            // Menüyü listeliyoruz
            $this->listMenu();

            // İstenilen göreve göre gerekli yere dallaniyor
            print ">>> Process No: ";

            // STDIN algılanıyor
            switch ( trim(fgets(STDIN,256)) ) {
                case "s":
                    $this->clrscr();
                    print ">>> " . trim(shell_exec("uname -a")) . "";
                    break;

                case "d":
                    $this->clrscr();
                    print ">>> " . date("Y-m-d") . "";
                    break;

                /*
                 * Eğer kullanıcı çıkmak istediyse onu fazla tutmayıp STDIN'i
                 * kapattıktan sonra programa son veriyoruz
                 */
                case "q":
                    fclose(STDIN);
                    print ">>> Kendinize iyi bakın ;)";
                    exit();

                default:
                    this->clrscr();
                    print ">>> Hatalı giriş yaptınız!" .
                          ">>> Lütfen tekrar deneyin.";
                          break;
            }
            $this->getKey();

        }

        /*
         * Ekranın temizlemenin en kolay yolu sanırım şimdilik bu olsa gerek.
         * Aksi halde ncurses kütüphanesine de el atmamız gerekebilir.
         */
        function clrscr() { system("clear"); }
    }

    /*
     * Bahsettiğim class'ı tanımlıyoruz ilk defa menümüzü klavyeden basılan
     * tuşu algılayacak şekilde çağırıyoruz.
     */
    $proc = new process;

    // Ekranı temizle...
    $proc->clrscr();

    // Kullanıcımıza bi merhaba diyelim...
    print ">>> Merhaba, $uname.\n";

    // İlk defa menümüzü klavyeden basılan tuşu algılayacak şekilde çağırıyoruz.
    $proc->getKey();

?>
EOF
shell$ _

Bunların dışında komut satırında yazdığınız programlar için de bir UI (User Interface / Kullanıcı Arayüzü) istiyorsanız her zaman, her yerde olduğu gibi burada da NCURSES yardımınıza koşuyor. Ben henüz NCURSES teknolojisine geçemediğimden; onu kavradığım zaman, ona da değinen bir yazı hazırlayacağım.

A. Kaynakça [Y, A]