Daha önce SOAP kullanan web hizmetleri hakkında şu yazıyı yazmıştım.
Aradan vakit geçip, Logipik‘i bir web hizmeti haline getirirken, bu kez REST kullanmayı düşündüm ve “hazır kütüphane olarak ne bulabilirim?” diye araştırırken Ersin Güvenç‘in yazdığı easyREST’e denk geldim.
EasyREST, oldukça düzgün kotarılmış ve gereken her şeyi PEAR kütüphanelerinden bir araya topladığından, “stand-alone” çalışabilen bir REST kütüphanesi. Benim indirdiğim sürüme dahil edilmiş olan PEAR paketleri biraz eski olduğundan, PHP 5.3.x üstünde “#” ile yorumlarda notice döndürüyor ama artık o kadar kusur kadı kızında da olur.
Elbette ben EasyREST’i kendi gereksinimlerim doğrultusunda bir miktar değiştirmek zorunda kaldım, ancak REST’e başlangıç noktası olarak çok doğru bir adres olduğunu söyleyebilir ve tüm PHP programcılarına da gönül rahatlığıyla öneririm.
Ersin Güvenç’e, bu kütüphane için çok teşekkür ederim.
You are currently browsing articles tagged Yazılım.
Ubuntu 10.04 dün yayınlandı ve Karmic’ten altı aydır az çekmemiş olan ben, henüz web sitesinde resmen duyurulmamışken repoda kararlı sürümü görür görmez yükseltme işlemine başladım.
“Vuzuh Vaşak” demek suretiyle herhalde 16.10 sürümü civarına yükseltme yapmış gibi görünmüş oldum.
- Pencerelerde “kapat”, “küçült”, “panele indir” ikonları sola kaymış. Bana güzel göründü ancak hemen belirteyim: alıştığınız sağda görünen duruma dönmek mümkün ve şu belgede anlatılmış.
- Gözle görülür şekilde daha hızlı boot ediyor.
- Karmic’teki bugların hemen hepsi temizlenmiş.
- Skype sorunsuz çalışıyor.
- PHP 5.3.2 ile PHP 5.3.x’li günler başlamış.
- Python 2.6.5
- gcc 4.4
- Multimedia işlerindeki sıkıntılar tarih olmuş.
- Öntanımlı arama motoru Google yerine Yahoo! olmuş, iyi olmamış, ancak yeni kurulum değil yükseltme yapıyorsanız bunu görmüyorsunuz.
- Firefox 3.6.3
- Öntanımlı masaüstü arka planı morarmış.
- Tüm donanımlar sorunsuz tanınıyor.
- Çekirdek 2.6.32-21
- Gwibber entegrasyonuyla sosyal medya desteği iyi olmuş.
Bir günlük deneyimin ardından ön sonuçlar:
- Karmic kullanıyorsanız saniye kaybetmeden yükseltin.
- Ubuntu Karmic’le kaybettiği prestiji tekrar kazanacak gibi görünüyor. Kullanışlı bir Gnu/Linux dağıtımı arıyorsanız Ubuntu 10.04 iyi bir seçim olacaktır.
Bu yazı bir süredir kafamın içinde bir yerlerde yazılmayı bekliyordu; bugünü bekliyormuş.
Öncelikle yazılarını -genel olarak yaklaşım açısını- fevkalade bulduğum, beğendiğim Altan Tanrıverdi’den bir alıntı yapmak isterim:
‘Doğrusu da budur. Diğer taraftan “senin yerinde olsaydım” ibaresi ile başlayan cevaplar da yanlış sayılmaz ki birazdan ben de öyle yapacağım.’
Yazının tamamı da oldukça ilginç ve şuradan okunabilir.
Tanrıverdi yazısında, “deneyimli bir programcıdan çaylağa nasihatler” kabilinden -doğru yorumlayabildiğim ölçüde- diğer unsurların yanında, satır aralarında önyargılardan kaçınmak gerektiğinden de dem vuruyor.
Ben de fikirlerimi bu çerçeveye oturtmak bu buradan yola çıkarak düşüncelerimi geliştirmek isterim:
“Çok bilen çok önyargı sahibi olandır.” genel olarak doğru bir önerme olarak kabul görebilir, ta ki “düzgün fikir sahibi olmak” ile “önyargı sahibi olmak” ayrıştırılabilsin.
Son günlerde heyecanlı gençleri sıkça görüyorum: “Hoca, iyi diyorsun da, falancayı filanca şekilde yapsak daha iyi sonuç alamaz mıydık?”
…ve sıkça yanıtlıyorum: “Ben benchmark severim. Görelim!”
Doğal olarak işbu genç arkadaşlarımızın bir çoğu “Görürüz!” diyor da arkasını -adı üstünde “gençlik” hezeyanının sonucu- bir türlü getiremiyor.
Oysa ben ne söylüyorum? “Disiplinli düşünebilme yetisi en büyük yetenektir.”
“Disiplinli düşünme” ya da “düşünceyi disiplin altına alma” derken bir yöntemler bütününden söz ediyorum; önyargılardan değil.
Devlet dairesinde memur olacak kişiler yazının bundan sonrasını okumayabilirler, ancak gelecek için kendinden bir şeyler bekleyenler okumaya devam etmeli.
- Eğitim sistemimiz ne yazık ki analist yetiştirmek üstüne değil, “vasat adam” yetiştirmek üstüne kurulu. Bu sistemden “ukala papağanlar yetiştirmek” durumundan ötesini -ne yazıktır- elde edemiyoruz. Çocuk pırıl pırıl, harika bir sistem çözümleyicisi olacak, biz ona “hayır!” diyoruz, “önce üniversite bilmemne hadisesini kazan!” ve beynini böylece -o vakte kadar elimizden kurtarabilmişse bile- düdüklüyoruz, dimağının ırzına geçiyoruz. Ondan sonra da oradan mezun olunca adama (bakın artık “adam” oldu) “haydi, sistemlerimiz, kıçımız başımız sana emanet!” diyoruz. (Tabii işin böyle olduğunu bildiğimiz için demiyoruz ama sistem buna yönelik)
- İşbu (artık) “adam” mektebi bitirdikten sonra elimize düşüyor ve dünyanın gerçekte kaç bucak olduğunu biraz olsun görmeye başlıyor: Zaten düdüklenmiş beyniyle (özellikle yazılım sektöründen söz ediyorsak) okulda hoca olmaktan gayrısını başaramamış hocaların elinde, beyni çift kat düdüklenmiş adamdan söz ediyoruz. Söz ediyoruz ve bu adamların sektörde “insan kaynağı” diye ortalıkta dolaştığını da böylece söylüyoruz.
- “Kendini geliştirmek istiyor musun? Unut!” diyoruz, “okulda ne öğrendiysen unut, çünkü hepsi ya önyargılı, ya yanlış, ya eksik ya da düpedüz palavra! Yeni doğmuşsun gibi yap. Aç bak, dokümantasyon orada. En başından oku, hepsini oku. Sonra gel bize anlat ‘ruby fastcgi ile şöyle çalışırmış’, ‘python aslında ne kadar şahaneymiş, php bilmemneymiş’. ama önce oku! Edindiğin bilgiyi sınıflandırmak için, sana uygun gelebilecek bir yöntem geliştir. Bunları yapmıyorsan, ancak devlet dairesinde memur olursun. Çocukların da devlet dairesinde memur olur.”
Bunları söylerken devlet memuru olma durumunu aşağılıyor muyuz? Hayır. Haddimize düşmez. Öte taraftan, bir yazılımcının devlet memuru ya da okulda hoca olmak için hakikaten çok rasyonel gerekçeleri olmalı. Sizin kişisel olarak verebileceklerinizin çok çok sınırlı olduğu bir ekosistemde isterseniz allame-i cihan olun, hiç ama hiç bir şeyi değiştiremezsiniz. Oysa, bir yazılımcı “bir şeyleri daha doğru yapmak” için vardır; öyle yazılımcıdır.
Önceki gün yazdığı kod hakkında (istediği kadar iyi çalışıyor olsun) şüpheye düşmeyen adama dahi artık yazılımcı değil “kod ağası” denir.
Öğrendiklerinizin, uzun süredir eski öğrendiklerinizin yerini almaması durumunu gözlemliyorsanız (yaşınız kaç olursa olsun) kod yazmaktan elinizi-ayağınızı-eteğinizi çekmenin vakti gelmiş demektir.
Yok, aksi durumda diretiyor ve üstelik ukalalık yapmaya kalkıyorsanız, yeri burası değildir!
Etiketler: Akıl-fikir, Yazılım
Her şey Altan Tanrıverdi‘nin Ubuntu üzerine nginx kurulumu yazısını görmemle başladı. Hayır, Nginx’i daha önce görmemiş değildim, ancak Tanrıverdi’yi Apache’den başka bir web sunucusu kurmaya yönelten şey Apache’nin sistem kaynakları açısından “pahalı” sayılabilecek bir sunucu olmasıydı.
Apache’de bir web sunucusundan beklediğimiz her şey ve hatta fazlası var. Apache modül listesine (http://httpd.apache.org/modules/ ve http://modules.apache.org/) daha önce göz atmadıysanız bir bakın; belki de adını bile duymadığınız, hiç işiniz düşmemiş olduğu için kullanmadığınız bir çok modül olduğunu göreceksiniz. Oysa çoğu LAMP/LAPP programcısı, günlük işlerinde php ve rewrite modulleri dışındakileri kullanmaya pek ihtiyaç duymaz.
Elbette asla yılların eskitemediği dost Apache’ye kafa tutmak için değildi, ancak kafama şu soruyu takmadan edemedim:
“Acaba yalnız PHP yorumlayan ve başka hiç bir iş yapmayan bir web sunucusunu yine PHP ile kodlasak nasıl olurdu?”
Tabii bu soru büyük olasılıkla benden başka bir sürü kişinin de aklından geçmişti veAmerika’yı yeniden keşfetmemek için önce Hz. Google’a sordum.
Google bana “Nano Web Server var.” dedi. Bir de baktım ki, gerçekten bu arkadaş Apache’yi neredeyse bire-bir PHP’ye port etmiş. Modüllerine kadar yazmış. Ubuntu için deb paketi bile var ve daemon olarak kuruluyor. Öte taraftan bu çalışma hem benim ölçeğimi aşıyor hem de başlangıçtaki mantığımla ters düşüyor: PHP’den başka şey çalıştırmak istesem zaten “runtime’da yorumlanan” değil “derlenmiş” kod kullanmayı tercih ederim. Benim fikrimin özü, zaten native olarak PHP yorumlayabilen bir kod yapısı kullanarak bir web sunucusu yapmak.
Bunun dışında bir de phpStack‘i buldum. phpStack benim amaçladığım şeye oldukça yakındı ancak bana göre işleri olması gerekenden daha karmaşık hale getiriyordu.
Böylece kendi denememi yapmaya karar verdim. Önce php5-cgi paketini kurdum. PHP Manual’dan jenerik bir soket kodu aldım. Kodu düzenledim, mime türlerine göre gönderilecek header’ları ayarladım, PHP yorumlayıcısı desteği verdim ve sonuç:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | <?php interface server { public function setWebRoot($path); public function setPort($port); public function serve(); } final class webserver implements server { private $_port , $_webroot; public function __construct() { //belki ileride lazım olur. şimdilik dummy } public function setPort($port) { $this->_port = $port; } public function setWebRoot($path) { $this->_webroot = $path; } private function _mimeHandler($input) { $fileinfo = pathinfo($input); switch ($fileinfo['extension']) { case 'png': $mime = "text/png"; break; case 'jpg': case 'jpeg': $mime = "text/jpeg"; break; case 'gif': $mime = "text/gif"; break; case 'css': $mime = "text/css"; break; default: $mime = "text/html; charset=UTF-8"; } return $mime; } private function _handleCode($contents) { //eval() edilecek kodun başında <?php ya da <? varsa çakar. halledelim. $contents = trim($contents); if(substr($contents , 0 , 5) == '<?php') { $contents = substr($contents , 5); } elseif(substr($contents , 0 , 2) == '<?') { $contents = substr($contents , 2); } return $contents; } public function serve() { $socket = @socket_create_listen($this->_port); if (!$socket) { echo "Soket olamiyor!\n"; exit; } while (1) //daire-i ilanihaye! { $client = socket_accept($socket); $input = trim(socket_read ($client, 4096)); echo $input; //tarayıcı ne diyor? bu veriyi ileride $_SERVER array'ini doldurmak için kullanmak lazım. $input = explode(" " , $input); $input = $input[1]; $mime = $this->_mimeHandler($input); if ($input == "" || $input == '/') { $input = "/index.html"; } $input = ".$input"; $inputArray = explode('?' , $input); $input = $this->_webroot . $inputArray[0]; if (file_exists($input) && is_readable($input)) { echo "Dosya: $input\n"; $contents = file_get_contents($input); if(strstr($input , '.php')) { $contents = $this->_handleCode($contents); //PHP çalıştıktan sonra sonucu echo etmesini değil, $contents stringine atmasını istiyoruz. ob_start(); eval($contents); //gidip $contents'in üstüne yazmak doğru alışkanlık değil ama yeni değişken register etmek istemiyorum $contents = ob_get_contents(); ob_end_clean(); } $output = "HTTP/1.0 200 OK\r\nServer: HyperTextServer\r\nConnection: close\r\nContent-Type: $mime\r\n\r\n$contents"; } else { $contents = "<title>UHU 404</title><h2>UHU 404</h2>Iın-ıın-ıın-ıın-cav-cav-cav-cav-oooooo - oooooo - zört - zört - zört -zört (araba alarmı efekti) Çok afedersin müdürüm ama yok öyle bir dosya."; $output = "HTTP/1.0 404 OBJECT NOT FOUND\r\nServer: HyperTextServer\r\nConnection: close\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n$contents"; } socket_write($client, $output); socket_close ($client); } socket_close ($socket); } } $server = new webserver(); $server->setWebRoot('/var/www/'); $server->setPort(8008); $server->serve(); |
Bu kodu (örneğin /var/www altına) hyperTextServer.php adıyla kaydediyoruz.
Daha sonra varsayılan olarak görüntülenmesi için örnek bir /var/www/index.html dosyası oluşturuyoruz.
Son olarak
1 | php-cgi /var/www/hyperTextServer.php |
ile sunucuyu çalıştırdıktan sonra tarayıcıdan
http://localhost:8008
adresini çağırdığımızda oluşturduğumuz index.html dosyasının servis edildiğini görüyoruz.
Artık bir adım daha ileri giderek bir PHP dosyası çağırmayı deneyebiliriz:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Bu kodu da /var/www/test.php adıyla kaydedip tarayıcıdan
http://localhost:8008/test.php adresini çağırdığımızda PHP kodumuzun da gayet başarılı şekilde yorumlandığını görüyoruz.
Gördüğünüz gibi test.php dosyası, serverBencmark.txt dosyasına, çalışmasının ne kadar zaman aldığını yeni bir satır olarak yazıyor. Böylece sevdiğimiz “benchmarkçılık” oyununu oynayabileceğiz.
test.php kodunu arka arkaya yüz kere önce kendi yazdığımız sunucu ile 8008′den, daha sonra da yine yüz kere apache üstünden (default 80.port) çalıştırıp basit bir aritmetik ortalama alacağız.
Benim lokal sistemimdeki sonuçlar söyle:
Apache ortalama: 0,0174917006493 ms
Bizim sunucu ortalama: 0,0098775601387 ms
Görüyoruz ki, beklediğimizin aksine PHP üstünde çalışan bizim sunucu, derlenmiş kod olarak çalışan Apache’den iki kat kadar hızlı çalışıyor. Bu durumun açıklamasının aslında çok da zor olmadığını düşünüyorum: Apache bir sürü kontrol yapıyor, aynı anda birden fazla bağlantı kabul edebiliyor, bir sürü port dinliyor, vs. Öte taraftan bizim sunucumuz yalnız PHP kodunu çalıştırmaya odaklanmış. $_SERVER’a, $_REQUEST’e bir değer atamak için tarayıcı verisini işlemiyor ve tek, basit bir süreç olarak çalışıyor.
Aynı işleri bizim sunucumuza yaptırdığımızda, büyük olasılıkla aradaki hız farkı kapanacak. Yine de şu andaki duruma bakarak iki kat yavaşlayacağını öngörmüyorum sonuç olarak başlangıçta umduğumun çok daha fazlasını alabildiğimi gözlemliyorum.
Bundan sonra yapılacaklar:
1- $_SERVER, $_REQUEST, $_POST, $_GET, $_FILES ve $_COOKIE arraylerinin doldurulması.
2- pcntl eklentisi ile süreçlerin “çatallanması”
Yukarıdaki iki maddelik yapılacaklar listesi de temizlendiğinde elimizde basbayağı düzgün çalışan bir web sunucumuz olacak.
Etiketler: Apache, Gnu/Linux, PHP, Web Server, Yazılım
Don Quijote. Wikipedia arşivinden
Geliştirdiğim “büyük-iri” sayılabilecek türden bir projeyi müşterime göstermek istiyorum. Müşterim de ciddi bir insan; yaptığınız iş kadar, nasıl yaptığınızla da ilgileniyor. Bunun için Active Collab kullanıyoruz ve memnunuz. Kodlamayı da rahatça takip edebilmesi için ona da VPS üstünde bir hesap açtım; her şey iyi.
Kodun bitirdiğim bir kısmını VPS’e yükledim ve test edeceğim. Fakat o da ne! Lokal sistemde şahane çalışan kod, VPS üstünde patlamasın mı!
Lokal sistem ubuntu 9.10/Suhosin-Patch’li PHP 5.2.10-2ubuntu6.4. Sunucu ise ubuntu 9.04/PHP 5.2.6-3ubuntu4.5
Yani ortada çok tuhaf konfigürasyonlar yok. Ubuntu’nun iki ardıl sürümü. Yazdığım kod da öyle “patlayabilir” cinsinden değil, sıradan bir kod.
Yalınlaştırmak gerekirse:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?php class B { public function __construct() { } } class A extends B { public function __construct() { parent::__construct(); //biraz kod } public function index() { //biraz kod $this->_methodPrivate(); //biraz daha kod } private function _methodPrivate() { //burada da biraz iş... } } |
Türünden bir kod. Bakıyorum bakıyorum “hata nerede?” diye, bulamıyorum.
Başkasına sorarak iş yapmayı sevmememe rağmen, “herhalde benim gözüm görmüyor” diyerek friendfeed PHP odasına dahi soruyorum. I-ıh. Çözebilen yok çünkü ortada çözülecek bir şey yok.
Genel olarak bu tür işlerin FTP encoding dertlerinden olduğunu önceki deneyimlerimden (“acılarımdan” diye de okuyabilirsiniz) biliyorum ve kullandığım gFTP’yi bırakıp konsoldan sftp çekiyorum: Sonuç aynı. SSH ile VPS’e geçip nano’ya yapıştırıyorum: “Bana mısın!” demiyor!
Hissel olarak şunu deniyorum:
_methodPrivate()’ı methodprivate() şeklinde denediğimde her ne hikmetse kod çalışıyor! Ancak öyle yarım-yamalak, ne yaptığımı bilmez halde iş yapamam ki!
“Hmm” diyorum, “Bu eski PHP sürümü. Bug vardır bunda!” (Bakınız kaşıntı başlıyor.)
“Sahi, bu Ubuntu 9.04′e nasıl PHP 5.3 kurarım?” (Madem 9.10′da çalışıyor, sürüm yükseltsene be adam! PHP de düzelmiş olur ha? Yook kaşınıyorum ya, 9.04′e kuracağım!)
Vakıa, “Ubuntu 9.04 PHP5.3″ diye arıyorum ve şu yazıyı buluyorum. Bir bakıyorum; abim derlemiş, çalıştırmış phpinfo() ekran görüntüsü bile koymuş.
Bir programcının, Ubuntu kurduktan sonra kuracağı ilk paketlerden biri “build-essential”dır, tamam anladık ama, insan olmanın belki de en kötü taraflarından biri de kişinin mutluluklar kadar acıları da çabuk unutması. Hafızam beni yanıltmıyorsa, en son geçen yıl yine bu aylarda kaynak koddan PHP derlemiştim; demek ki akıllanmamışım!
Abimin yazısından yola çıkarak PHP5.3.0 indirdikten sonra ve kendi işlerime uygun olarak şöyle bir konfigürasyon öngörüyorum:
1 | sudo ./configure --with-apxs2=/usr/bin/apxs2 --with-mysql --with-pdo-mysql --with-zlib --enable-calendar --with-curl --enable-dba --with-enchant --with-gd --enable-gd-native-ttf --with-gmp --with-mcrypt --with-readline --enable-soap --enable-zip --with-pgsql --with-pdo-pgsql |
Tabii Allah’ın emri: “o kütüphane eksik, şu yok, bu yok” uyarıları içinde bir sürem “sudo apt-get install libfalanca-dev” yazmakla geçiyor…
…ve derlemeye başlıyorum.
Amca önce enchant bindingini derlerken çakıyor. “Abim yazısında enchant’ı öve öve bitirememiş ama benim ne işim olacak?” diyorum ve konfigürasyondan önce –with-enchant’ı çıkarıyorum ve biraz daha ilerliyoruz.
Bilahare, Phar derlenirken su koyuveriyor. Gidiyorum, dokümantasyona bir bakıyorum ki adamlar 5.3′ten itibaren PHP-core’a dahil etmişler.
“Behey adam!”, diyorum, “madem core’a dahil edecektin, gcc4.3 ile çakmayanından yapsaydın ya!”… Zaten “warning”ler gırla gidiyor derleme boyunca; üstünde bile durmaya değmez…
Derken, PHP bug raporlarının içinde yama ararken kendimi buluyorum, ancak yama bulamıyorum!
Tek önerdikleri gecelik snapshottan kurulum.
Onu da yapıyorum. İndirdiğim ve üstünde uğraştığım PHP dizinini uçurarak php5.3-201004092030 diye bir sürüm buluyorum ve baştan başlıyorum. Tabii Phar yine derlenmiyor!
“Çok da sevmişim Phar’ını!” diyerek konfigürasyona nihai şeklini veriyorum:
1 | sudo ./configure --with-apxs2=/usr/bin/apxs2 --with-mysql --with-pdo-mysql --with-zlib --enable-calendar --with-curl --enable-dba --with-gd --enable-gd-native-ttf --with-gmp --with-mcrypt --with-readline --enable-soap --enable-zip --with-pgsql --with-pdo-pgsql --disable--phar |
Ve nihayet bu sefer derlenmeyi başarıyor PHP, ama dert burada bitmiyor.
“make install” kısmına geldiğimizde “İlla /etc/apache2/httpd.conf dosyanda ‘LoadModule’ bulacağım!” diye tutturuyor.
“Ya sabır!” çekerek açıyorum dosyayı, elle “#LoadModule tiriviri” yazıyorum ve bunu yutturmayı beceriyorum.
Son olarak apache’yi yeniden başlatıyorum phpinfo() çekince karşımda “PHP5.3.3-dev” yazısını görüyorum.
Artık çakan koduma bakıp çalışmasını keyifle izleyebilirim. Hala açık sayfaya refresh çekiyorum…ve…
Kod yine de çalışmıyor, aynı yerde çakıyor!
“Kesin encoding bu! Kesin encoding bu! Encoding ulan!” diyerek bildiğim son numaraları da deniyorum: lokal makineden bir dizini sshfs ile vps’in ilgili dizinine mount ediyorum, lokaldeki dizinden bağlanmış uzak sistem dizinine kopyala+yapıştır deniyorum… Tabii ki yine olmuyor!
…derken, bir anda ilham geliyor ve methodPrivate() içindeki tarihleri Türkçe bastırmak için kullandığım
1 | setlocale(LC_ALL , 'tr_TR.UTF-8'); |
satırını comment ediyorum, deniyorum, a-aa çalışıyor!
O ana kadar hiç aklıma gelmemiş zira işletim sistemini kurar kurmaz apt-get install language-pack-tr-all gibisinden bir paketi de kurmuşum.
Yukarıdaki satırı
1 | setlocale(LC_TIME , 'tr_TR.UTF-8'); |
yapıyorum (biraz altta tekrar en_GB lokaline çevirmem gerekiyor yoksa PgSQL sorgularım patlıyor) ve iş bitiyor!
Kodda bir kelimelik değişiklik yapabilmiş olmak için sisteme gecelik snapshot bir sürüm kurduğumla kalıyorum… Kendi kendime sinirli sinirli gülüyorum ve bu yazıyı yazmaya başlıyorum!
“Her seçim bir kaybediştir.” Jean-Paul Sartre
Tedrisat itibarıyla dilbilimci/çevirmen sayılabilirim. (“Aşkın Metafiziği” kitabının başlangıcı gibi oldu ancak ben Danzig’li değilim) Doğal dillerle beraber, yapay dillerle tanışmamın da, yaşım/teknoloji karşılaştırmasını yaptığımız vakitte “erken” bir yaşta, televizyonun renkli yayına geçtiği tarihlerde, dokuz ya da on yaşımda (ve kaza eseri) olduğunu söyleyebilirim.
“Yapay dil” derken hem Esperanto, hem de Basic ve Assembly’den söz ediyorum. Aynı zamanda Internet’in kavram olarak bile yaşamımızda bulunmadığı, tüm bilebildiklerimizin, aslında bizden daha fazlasını bilmeyen “Sözde Ermeni Kıyımı” yollu “bilgisayar mühendislerinin” çevirdiği boktan kitaplardan ve bir takım ingilizce metinlerden edinilmeye çalışıldığı zamanlardan da söz ediyorum.
Sinclair ZX Spectrum ve daha sonra anamın zavallı memur maaşına yapılan taksitlerle edinilen Amstrad CPC 6128′den ve Locomotif Basic’ten, Pascal’dan, yetmedikleri yerde Assembly’den de söz ediyorum, zira o zamanlar o makinelerde oyun oynamak kod yazmaktan daha zor, kod yazmak ise deveye hendek atlatmak demekti!
Zaman içinde hasb-el-kader (daha doğrusu “merak” ve “yaşamın akışı”) bir kaç doğal ve yapay dil daha öğrenmek olanağı buldum, fırsat buldukça yenilerini inceleyebilmek ve vaktim oldukça öğrenmek için hala can atıyorum ve bu hevesim, görülebileceği gibi çocukluktan kalma. Diğer yandan, üst cümlede altı çizilecek ayrıntı benim için “vakit”.
Çocukluk hevesim programcılığın, akademik kariyerimin önüne geçip ekmek teknem haline gelmesi, 1999 yılının başlarına ve o vakit başka bir Türk programcıya gönderdiğim, yazdığı kodla ilgili bir soru içeren bir e-postaya gelen yanıta denk gelir: “Hocam, sen hakikaten dilbilimci misin? Benle kafa buluyorsun gibime geliyor. Söylediğin şeyleri ben programcı olarak yazdığım kodda düşünmemiştim.”
Elbet o vakitler çok cahildim ve nasıl bir batağa saplandığımı(!) bilmiyordum ancak kariyer değişikliği için beni tetikleyen bu küçücük “gaz” oldu. O vakitten bu yana durmak dinlenmek bilmeden öğreniyorum, kod yazıyorum, hala yazılım tasarım mantığı üstüne öğrenmeye ve öğretmeye devam ediyorum ve bugün geriye baktığımda utanmadan söyleyebilirim ki, akademik ortamlarda “şu ya da bu programlama dili”, “şu ya da bu kod tasarım örüntüsü” ile beynim düdüklenmediği için çok şanslıyım ve bu sayede aynı fakültelerde derslerde örnek verilen kodlar yazabiliyorum.
Bu uzun sayılabilecek girişi, nasıl düşündüğümü ve fikirlerimin altında yatan geçmiş alışkanlıkları ve önyargıları tanımlayabilmek için yazmak zorundaydım. Şimdiye dönelim.
Güncel durum şudur: İş çok. Buna rağmen gördüğünüz gibi blog yazmaya vakit ayırabiliyorum ve bunu temelde iki programlama diline borçluyum: Python ve PHP. Bana PHP hızlı, Python düzgün ve tertemiz kod yazdırıyor. Son on yıldır PHP ile uğraşmıyor olsam (sorunların nasıl çabucak çözülebileceğine dair deneyimi göz önüne alın) ve Python kütüphaneleri anında işimi PHP ile görebildiğim kadar zengin olsa, bugün tereddüt etmeden her şeyimi Python’a taşırdım. İşin doğrusu şu ki, bugün de çoğu hassas işlerimi Pyton’a yaptırıp, PHP’den çağırıyorum ve son üç yıldır günden güne Python’u daha çok benimsediğimi hissediyorum. Bunu ben koskoca bir PHP framework’ü yazacak derecede PHP’yi seven adam olarak söylüyorum.
Pekiyi, bu kadar vakti nereden bulabiliyorum? Basit: JAVA kodlamıyorum. JAVA biliyor muyum? Herhalde sizden iyi biliyorum(!) ve uzun vakti “Düzgün bir programlama dili nasıl olmalı?” sorusuyla geçmiş kişi olarak JAVA’yı hakikaten çok beğeniyorum ancak söz bana ait değil, anonim: “JAVA ile üç birim vakit harcayan, PHP ile bir birim vakit harcar.” Üstelik JAVA’nın PHP ve Python’a her benchmarkta üstün çıktığı da kılavuz sitemez bir köy.
Müşteri ya da patrona “Hacı bu işi JAVA/Spring ile kodlayalım, süper olur ama iki kat fazla para ve vakit isterim!” diye anlatamazsınız. Adam size fazladan $20.000 vereceğine, iş için kullandığı sunucuyu $500 fazla harcayarak daha iyi hale getirir, olur biter!
Neymiş? Hızlı kod için PHP, düzgün kod için Python, vaktiniz varsa JAVA!
Sudo ilk kez Bob Coggeshall ve Cliff Spencer tarafından, SUNY/Bufalo’da Bilgisayar Bilimlieri Bölümü’nde 1980 yılı civarında tasarlandı.4.1BSD kullanan bir VAX-11/750 üstünde çalışıyordu. Phil Betchel, Cliff Spencer, Gretchen Phillips, John LoVerso ve Don Gworek tarafından 1985 Aralık ayında, güncellenmiş bir sürümü net.sources Usenet haber grubuna gönderildi.
1986 yazında, Garth Snyder sudo’nun genişletilmiş bir sürümünü yayınladı. Sonraki beş yıl boyunca sudo, CU-Boulder’da Bob Coggeshall, Bob Manchek ve Trent Hein’in aralarında bulunduğu bir kaç kişi tarafından beslenip büyütüldü.
1991 yılında, Dave Hieb ve Jeff Nieusma, “The Root Group” adında bir danışmanlık firmasıyla sözleşmeleri kapsamında, sudoers formatı daha da genişletilmiş bir sudo sürümü yazdılar. Bu sürüm daha sonra GNU kamu lisansı altında yayınlandı.
1994 yılında, sudo’yu gayrıresmi olarak CU-Boulder bünyesinde bir süredir geliştirmiş olan Todd Miller, “CU sudo”nun hata düzeltmeleri ve daha fazla işletim sistemi desteği içeren, herkese açık bir sürümünü yayınladı (sürüm 1.3). “CU”, “The Root Group” sürümünden farklılaşmak için eklenmişti.
1995 yılında, Chris Jepeway, sudoers dosyası için yazdığı yeni bir ayrıştırıcıyla katkıda bulundu. Yeni ayrıştırıcının grameri (eskisinin aksine) düzgündü ve hem sudo, hem de visudo ile çalışabiliyordu. (önceleri ayrıştırıcıları birbirinden biraz farklıydı).
1996 yılında, uzun yıllardır boş zamanlarında sudo’yu geliştiren Todd, sudo dağıtımını CU-Boulder ftp sitesinden, kendi domaini olan courtesan.com (“fahişe.com”) adresine taşıdı.
1999′da, “The Root Group” tarafından 1991 yılından beri resmi bir sudo sürümü yayınlanmamış olduğu için (asıl programcılar artık farklı yerlerde çalışıyordu), “CU” öneki düşürüldü. 1.6 sürümünden beri, Sudo’da artık özgün “Root Group” kodundan eser kalmadı ve ISC stili bir lisans altında yayınlanıyor.
2001′de, sudo web sitesi, ftp sitesi ve e-posta listeleri courtesancom’dan sudo.ws adresine taşındı (sudo.org daha öne başkası tarafından tescillenmişti).
2005′te Todd, son on yılda eklenen özellikleri daha iyi destekleyebilmek için sudoers ayrıştırıcısını yeniden yazdı. Yeni sürüm eskisinin bazı sınırlamalarını, sıralama kısıtlamalarını kaldırıyor ve birden çok sudoers dosyası için destek ekliyor.
Sudo, şimdiki haliyle Todd Miller
Todd sudo’yu genişletmeyi ve hataları gidermeyi sürdürüyor.
Özgün Metin:
“A Brief History of Sudo“
VBulletin en çok beğenilen ve kullanılan forum yazılımlarından biri olma özelliğinin yanında, veri madencilerini de oldukça fazla uğraştıran bir forum olmasıyla da biliniyor.
Bu makalede LF’in cURL tabanlı NetClient kütüphanesini kullanarak VBulletin forumlarından veri çekmeyi inceleyeceğiz.
Not1: NetClient kütüphanesinin çalışabilmesi için sisteminizde php-curl eklentisinin kurulu olması gerekir. Çok kullanılan bir eklenti olduğundan genellikle kuruludur.
Not2: Siz kodun içinde görmeyecek olsanız da, cookie kullanacağımız için LF kurulum ana dizinine apache kullanıcısının yazma izni olmalı.
Örneğimizde VB Forumundan bir alt-forum sayfası içeriğini okumayı amaçlıyoruz. Akış diagramımız kabaca aşağıdaki gibi olacak:
- VB forumuna kullanıcı adı ve şifre ile giriş yap
- VB security token’ı al.
- VB sub-forum sayfasını çağır
Önce Controllerımızı oluşturalım, kullanacağımız private değişkenleri deklare edelim. Daha sonra constructor’ımızda NetClient kütüphanesini yükleyelim ve forum kullanıcı adı, şifre ve sayfa içeriğini edinmek istediğimiz alt-forum ID’sini belirlediğimiz bir ayar metodu yazalım.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | class Vbulletin extends LogikitController { private $_forum , $_username , $_password , $_loginUrl , $_loginPageContent , $_securityToken , $_subForumId; public function __construct() { parent::__construct(); //NetClient kütüphanesini yükle $this->load->systemLibrary('NetClient'); //ayarları yükle $this->_config(); //VBulletin forumları için login sayfası $this->_loginPage = 'login.php?do=login'; } private function _config() { $this->_forum = 'http://www.vbforumumuz.org/'; //hedef forum. sondaki bölü işaretini unutmayalım. $this->_username = 'kullaniciAdi'; //forum kullanıcı adı $this->_password = 'kullaniciSifresi'; // şifre $this->_subForumId = 22; //post listesini almak istediğimiz sub-forumun ID'si } } |
Yukarıdaki kodu application/controller altına Vbulletin.php adıyla kaydedelim.
Ardından, login işlemini gerçekleştirerek loginden sonra yönlendirileceğimiz sayfanın içeriğini alan private metodu yazalım:
1 2 3 4 5 | private function _doLogin() { $this->_loginPageContent = $this->NetClient->fetchUrl($this->_forum . $this->_loginUrl , "vb_login_username=" . $this->_username . "&vb_login_password=" . $this->_password . "&s=&do=login&vb_login_md5password=" . $passwordMD5 . "&vb_login_md5password_utf=" . $passwordMD5); sleep(1); } |
Şimdi $this->_loginPageContent içinde login işleminden sonra yönlendirildiğimiz ana sayfanın HTML içeriği var.
Dikkatinizi çekmiştir; işlemden sonra bir saniye bekliyoruz. Bunu yapmadığımız zaman Vbulletin sorun çıkarabiliyor.
Artık Vbulletin forumunda yapacağımız tüm işlemler için bize gerekecek olan security token’ı, anasayfa içeriğindeki
var SECURITYTOKEN = “timestamp-md5token”;
biçiminde bulunan javascriptten çekebiliriz. Bunun için regEx kullanacağız. Yeri gelmişken belirtmekte fayda var: regEx bilmeden olmuyor. Ya iyice regEx öğrenin, ya da benim gibi sürekli cheatsheetlerden kopya çekin!
1 2 3 4 5 | private function _getSecurityToken($content) { preg_match('%(?:var\sSECURITYTOKEN\s\=\s\")(.*?)(\";)%', $content , $result , PREG_OFFSET_CAPTURE , 3); $this->_securityToken = $result[1][0]; } |
Böylece ana sayfa HTML kodundan
var SECURITYTOKEN = ”
ile başlayıp
“;
ile biten kısımda bulacağımız security token’ı da elde etmiş olduk.
Kullanacağımız son araç alt-forum sayfasının içeriğini alan metod olacak:
1 2 3 4 5 | private function _getSubForumContent($subForumId , $page = 1) { $subForumUrl = $this->_forum . "forumdisplay.php?f=$subForumId&order=desc&page=$page"; return $this->NetClient->fetchUrl($subForumUrl , 'securitytoken=' . $this->_securityToken); } |
Artık ana metodumuzu yazabilir ve kodumuzu hazır hale getirebiliriz:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public function scrapeVBCategory() { //login işlemini yap ve login sayfası içeriğini $this->__loginPageContent stringine at $this->_doLogin(); //security token'ı al $this->_getSecurityToken($this->_loginPageContent); //seçtiğimiz alt forumun birinci sayfasını yükle. $subForumPage = $this->_getSubForumContent($this->_subForumId); echo $subForumPage; //template ve view yüklemeden çık. exit; } |
Gördüğünüz gibi oldukça derli-toplu ve gerçekten çok basit. Kodumuzun tamamlanmış hali:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | <?php /** * Logikit::Framework * * Open source development framework for PHP 5 * * @package Logikit Framework * @author Can Ince * @copyright Copyright (c) 2010, Logikit / Can Ince. * @license http://www.opensource.org/licenses/mit-license.php * @link http://framework.logikit.net */ class Vbulletin extends LogikitController { private $_forum , $_username , $_password , $_loginUrl , $_loginPageContent , $_securityToken , $_subForumId; public function __construct() { parent::__construct(); //NetClient kütüphanesini yükle $this->load->systemLibrary('NetClient'); //ayarları yükle $this->_config(); //VBulletin forumları için login sayfası $this->_loginPage = 'login.php?do=login'; } private function _config() { $this->_forum = 'http://www.vbforumumuz.org/'; //hedef forum. sondaki bölü işaretini unutmayalım. $this->_username = 'kullaniciAdi'; //forum kullanıcı adı $this->_password = 'kullaniciSifresi'; // şifre $this->_subForumId = 22; //post listesini almak istediğimiz sub-forumun ID'si } public function index() { //scrapeVBCategory metoduna yönlen. $this->scrapeVBCategory(); } public function scrapeVBCategory() { //login işlemini yap ve login sayfası içeriğini $this->__loginPageContent stringine at $this->_doLogin(); //security token'ı al $this->_getSecurityToken($this->_loginPageContent); //seçtiğimiz alt forumun birinci sayfasını yükle. $subForumPage = $this->_getSubForumContent($this->_subForumId); echo $subForumPage; //template ve view yüklemeden çık. exit; } private function _doLogin() { //ilk parametre URL, ikinci parametre POST verisi $this->_loginPageContent = $this->NetClient->fetchUrl($this->_forum . $this->_loginUrl , "vb_login_username=" . $this->_username . "&vb_login_password=" . $this->_password . "&s=&do=login&vb_login_md5password=" . $passwordMD5 . "&vb_login_md5password_utf=" . $passwordMD5); sleep(1); } private function _getSecurityToken($content) { preg_match('%(?:var\sSECURITYTOKEN\s\=\s\")(.*?)(\";)%', $content , $result , PREG_OFFSET_CAPTURE , 3); $this->_securityToken = $result[1][0]; } private function _getSubForumContent($subForumId , $page = 1) { $subForumUrl = $this->_forum . "forumdisplay.php?f=$subForumId&order=desc&page=$page"; return $this->NetClient->fetchUrl($subForumUrl , 'securitytoken=' . $this->_securityToken); } } // END Vbulletin class /* End of file Vbulletin.php Location: ./system/application/controller/Vbulletin.php */ |
Kodun tamamlanmış hali yorumlar ve boş satırlar hariç 40-45 satır civarında.
NetClient kütüphanesi, bizim için gerekli cURL ayarlarını yaptı. HTTP yönlendirmelerini takip etti, cookie oluşturdu ve bize yalnız “git şu adrese, şunları post et ve gelen veriyi al” demek kaldı.
Veri madencisi arkadaşların işine yaraması dileğiyle.
Etiketler: cURL, Forum, Logikit::Framework, NetClient, PHP, Yazılım
Mongo DB, yeni yeni serpilen fakat şimdiden bir çok kişinin gözdesi haline gelmeyi başarmış bir veritabanı. PHP için de eklentisi mevcut: http://www.php.net/manual/en/intro.mongo.php
Buradan AMD 64 bit için derlediğim Mongo DB .deb paketini edinebilirsiniz.
Logikit::Framework yazılarımı LF blogunda yayınlıyorum ancak Türkçe belgelendirmeye de gereksinim duyuluyor. Bu nedenle LF’le ilgili Türkçe makaleleri bu blogda yayınlıyorum.
Bu makalede “Selectbox bileşen seçeneklerini veritabanından gelen veriyle doldurmak” üstüne çalışacağız.
LF ve MVC örüntüsü üstüne deneyimli kişiler için “Özet” bölümü yeterli olmakla birlikte, “yeni ısınan” arkadaşlar için ayrıntılı açıklamaları da bulacaksınız.
Özet:
Aşağıdaki metodu Controller’ımıza ekliyoruz. Çağırılan model, form ve view ile kullanılan veritabanı tablo yapısını “Ayrıntılar” kısmında bulabilirsiniz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public function mySelectBoxTest() { //formu ilklendir $this->load->form('MySelectBoxTestForm'); //modeli ilklendir $this->load->model('TestModel'); //modelden kategorileri id => name yapısında bir array olarak al $categoryNames = $this->UploaderModel->getCategories(); //formda category ismiyle tanımlanmış selectbox'ın içini veriyle doldur foreach($categoryNames as $key => $val) { $optArray = array($key => $val); $this->CategorySelectForm->addOption('category' , $optArray); } //id'si 1 olan kategoriyi seçili getir $this->CategorySelectForm->setSelected('category' , '1'); //formu oluştur $viewData['formItems'] = $this->MySelectBoxTestForm->renderAll(); // form verisini view'a geç ve view'u çağır $viewData = array(); $this->load->view('categoryselect' , $viewData); } |
Ayrıntılar:
MySQL kullandığımızı varsayarak veritabanı yapımız:
1 2 3 4 | CREATE TABLE `categories` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `name` VARCHAR( 100 ) NOT NULL ) ENGINE = MYISAM ; |
Controller’ımızın adı “Test” olsun:
1 2 3 4 5 6 7 8 | class Test extends LogikitController { public function __construct() { parent::__construct(); } } |
Yukarıdaki kodu application/controller altına “Test.php” adıyla kaydedelim.
Sırasıyla modelimizi ve formumuzu oluşturalım.
1 2 3 4 5 6 7 | class TestModel extends LogikitModel { public function __contruct() { parent::__contruct(); } } |
Bu modelimiz. Yukarıdaki kodu /application/model altına “TestModel.php” adıyla kaydedelim ve formumuza geçelim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class MySelectBoxTestForm extends LogikitForm { public function __construct() { $this->addItem(array( 'name' => 'category' , 'type' => 'selectBox' , 'value' => NULL , 'validation' => array('notNull') , 'properties' => '')); $this->addItem(array( 'name' => 'Go' , 'type' => 'submit' , 'value' => 'Gönder' , 'validation' => NULL , 'properties' => 'class="submit1"')); } } |
Böylece bir selectbox ve bir submit butonundan oluşan formumuzu tanımlamış olduk. Yukarıdaki kodu da application/form/Test altında “MySelectBoxTestForm.php” adıyla kaydedelim.
Böylece view hariç, gerekli dosya ve nesnelerin tamamını hazırlamış olduk.
Bir sonraki adımda, controller’ımıza dönelim (application/controllers/Test.php) ve kullanacağımız metodu yazalım:
1 2 3 4 | public function mySelectBoxTest() { } |
Şimdi de yukarıda oluşturduğumuz form ve modelimizi yükleyelim:
1 2 3 4 5 6 | public function mySelectBoxTest() { $this->load->form('MySelectBoxTestForm'); $this->load->model('TestModel'); } |
Bu andan itibaren form ve model nesneleri ile bu nesnelere bağlı metodlar, controller’ımız içinden $this->TestModel->method() ve $this->MySelectBoxTestForm->method() şeklinde çağırılabilir durumda.
Modelimize (application/model/TestModel.php) geri dönelim ve selectbox’ımızı doldurmak için gerekli veriyi array olarak veritabanından çeken metodu yazalım:
1 2 3 4 | public function getCategories() { return $this->result("SELECT id , name FROM categories"); } |
Controller’ımızdaki mySelectBoxTest() metoduna dönelim ve selectbox’ı veriyle dolduran kodu ekleyelim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public function mySelectBoxTest() { $this->load->form('MySelectBoxTestForm'); $this->load->model('TestModel'); $categoryNames = $this->UploaderModel->getCategories(); foreach($categoryNames as $key => $val) { $optArray = array($key => $val); $this->CategorySelectForm->addOption('category' , $optArray); } //id'si 1 olan kategoriyi seçili getir $this->CategorySelectForm->setSelected('category' , '1'); } |
Contoller’daki son işimiz, form verisini view’a aktarmak olacak ve bu işlemden sonra controller’ın son hali aşağıdaki gibi olmalı:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public function mySelectBoxTest() { $this->load->form('MySelectBoxTestForm'); $this->load->model('TestModel'); $categoryNames = $this->UploaderModel->getCategories(); foreach($categoryNames as $key => $val) { $optArray = array($key => $val); $this->CategorySelectForm->addOption('category' , $optArray); } //id'si 1 olan kategoriyi seçili getir $this->CategorySelectForm->setSelected('category' , '1'); //formu oluştur $viewData['formItems'] = $this->MySelectBoxTestForm->renderAll(); // form verisini view'a geç ve view'u çağır $viewData = array(); $this->load->view('categories' , $viewData); } |
ve son olarak view dosyasını oluşturarak işimizi bitirelim:
1 2 3 4 5 6 | <div id="formDiv" style="display: none;">echo formOpenMultipart('form1' , siteUri(getController() . '/formIslemeMetodu') , 'POST', 'onsubmit="return false;"'); echo $secondFormItems['category'] . " "; echo $secondFormItems['Go'] . " "; formClose();</div> |
Bu dosyayı da application/view/categories.php adıyla kaydedince işimiz bitmiş oluyor.
Artık kodu çalıştırabiliriz:
http://www.testsunucunuz.com/LFDizini/Test/mySelectBoxTest
Etiketler: Logikit::Framework, MVC, PHP, Yazılım



