31 Temmuz 2008 Perşembe

AmfPHP ile Flash Remoting'e Giriş(Flash ile veri tabanı arasında XML olmadan veri alışverişi yapacağız)

Flash ile ActionScript kullananların şu ana kadarki en büyük korkulu rüyası veri tabanı ile iletişim kurmaktı herhalde. Çünkü Flash doğrudan veri tabanından veri alamaz. Doğrudan veri tabanına veri yazamaz.

Adobe Flex Data Services ürününü çıkardığında işte bu ve benzeri sorunları çözme yoluna gitti. Flex Data Services, Java Programlama Dili ile server taraflı uygulamalaları, class olarak yazdıktan sonra, Flash uygulamalarınızla bu classlardan nesne yaratma olanağı sunuyor idi.

XML ile iletişimde farklı olarak Adobe Flex Data Services ürünü flash ile Binary iletişim kuruyordu. Bu da XML için kullandığınız Tag ‘ları kullanmamanız böylece daha yalın veriler ile alışveriş yapmanız anlamına geliyordu. Adobe iletişimde kullandığı bu mesaj formatına Adobe Messaging Format ismini verdi. Bu şekilde AMF0 ortaya çıktı. Bu gün bu format revize edildi ve AMF3 oldu. Ancak siz haberleşmenizde hala AMF0 ve AMF3 tercihi yapabiliyorsunuz.

Daha sonra adobe firması bu ürünün adını Adobe Live Cycle Data Services olarak değiştirdi. Açık kaynak kod cephesinde de bu ürünün yerini doldurmak amacıyla çeşitli ürünler çıktı. Bu ürünlerden en popüleri olarak RED5 ‘i burada örnek vermek yerinde olur.

Adobe bir boşluğu doldurmuştu ama bu ürünle birlikte önemli bir boşluk daha ortaya çıkmıştı. PHP, ASP.NET dillerini kullanarak server taraflı kod yazan ve Flash’ı bu şekilde veri tabanı ile haberleştiren kişiler için de bu teknikleri kullanabilecekleri bir ürün gerekliydi. Bu amaçla 3. nesil program olarak birkaç çözüm geldi. Bu çözümlerden en popüler ikisinin ismi AmfPHP ve WebOrb.

WebOrb, php,.NET,Java ve Ruby on Rails için 4 ayrı sürüme sahiptir ve .NET için olan sürümü RTMP dahil Adobe Live Cycle Data Services ürününün Java ile yapabildiği herşeyi yapabilir.

AmfPHP ise sadece yazdığınız PHP class dosyasını uzaktan çalıştırmanızı sağlar.

AmfPHP’yi www.amfphp.org adresinden indirebilirsiniz. Yada buraya tıklayarak doğrudan indirebilirsiniz. Şu anki kararlı son sürüm amfphp 1.2 ve son sürüm ise amfphp 1.9 betadır.

AmfPHP ‘yi indirdikten sonra web server’ınızdaki document root klasörüne açınız. yani http://localhost/amfphp

şeklinde AmfPHP’ye erişebilmeliyiz. Eğer herşey yolunda ise

http://localhost/amfphp/gateway.php

adresinden aşağıdaki gibi bir görüntü alırsınız:

MMİstanbul

eğer Load the service browser linkine tıklarsanız. Oluşturduğunuz servisleri görmek ve olarla test sürüşü yapma şansına sahip olursunuz. Ancak ilk kez service browser’ı açıyorsanız o zaman AmfPHP size hangi iletişim kuralını kullanacağınızı sorar.

MMİstanbul

AmfPHP’yi başka bir klasöre kopyalarsanız yada uzak sunucuya atarsanız yine aynı soru ile karşılaşırsınız. Bu soruya bir kez yanıtvermeden de flash yada flex ile AmfPHP’ye bağlantı kuramazsınız

AmfPHP ile bir web servisi oluşturmak için tek yapmanız gereken servisinizi bir class olarak hazırlayıp amfphp klasörü içindeki services klasörüne atmak olacaktır.

Ancak buna geçmeden önce AmfPHP ile yapılacak son bir işlemimiz daha var. AmfPHP standart olarak ilk kurulduğunda ISO-8859-1 karakter setiyle çalışmaktadır. Oysaki bu karakter seti ile türkçe karakterleri kullanmamız çok zor olur. Bu karakter seti ayarlamasını UTF-8 ‘e dönüştürmeliyiz. Bunun için amfphp kök dizinindeki gateway.php dosyasını açıp şu satırı bulun:

//Read above large note for explanation of charset handling
//The main contributor (Patrick Mineault) is French,
//so don't be afraid if he forgot to turn off iconv by default!
$gateway->setCharsetHandler("utf8_decode", "ISO-8859-1", "ISO-8859-1");

üstteki üç satır açıklama satırı. Alttaki satır ise karakter setinin belirlendiği satır. Bu satırı şu şekilde yeniden düzenleyin:

$gateway->setCharsetHandler("utf8_decode", "utf-8", "utf-8");

Şimdi Flash Remoting ‘e en basit girişi yapabileceğimiz AmfPHP ‘yi kullanarak, bir veri tabanına kayıt yapalım. Öncelikle MySQL ile bir veri tabanı ve tablo oluşturalım:

CREATE DATABASE `flash_test_db` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

CREATE TABLE `flash_test_db`.`kisiler` (
`id` INT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR( 20 ) NOT NULL ,
`tel` VARCHAR( 11 ) NOT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = InnoDB

veri tabanımızın adı : flashtestdb ve kişi isimleri ve telefon numaralarını tutacağımız tablonun ismi ise kisiler oldu.

Bu veritabanında yetkili kullanıcıyı oluşturalım ve bu veri tabanı üzerinde yetkilendirelim

CREATE USER 'amfphpuser'@'localhost' IDENTIFIED BY 'amfphppass';

GRANT USAGE ON * . * TO 'amfphpuser'@'localhost' IDENTIFIED BY 'amfphppass' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;

GRANT ALL PRIVILEGES ON `flash\_test\_db` . * TO 'amfphpuser'@'localhost' WITH GRANT OPTION ;

bu veri tabanına ulaşacak php class’ını oluşturalım:

dbObj = mysql_pconnect(DATABASE_SERVER, DATABASE_USERNAME, DATABASE_PASSWORD) or (trigger_error(mysql_error(),E_USER_ERROR));
mysql_select_db(DATABASE_NAME, $this->dbObj);
}
private function SQL($sql){
$queryReturn= mysql_query($sql,$this->dbObj) or trigger_error("AMFPHP şu hatayı döndürdü hata oluşan class: 'connect_to_mysql' hata veri tabanında SELECT cümlesi işlenirken oldu. mysql tarafından döndürlen hata :\nError:" . mysql_error());
return $queryReturn;
}
private function insertSQL($table,$fields){
$insertSQL="INSERT INTO `".$this->dbPrepend.$table."` (";
$fieldSQL="";
$valueSQL="";
foreach ($fields as $field=>$value){
if($fieldSQL!="") $fieldSQL.=",";
$fieldSQL.="`".$field."`";
if($valueSQL!="") $valueSQL.=",";
$valueSQL.="'".$value."'";
}
$insertSQL.=$fieldSQL.") VALUES (";
$insertSQL.=$valueSQL.");";
mysql_query($insertSQL,$this->dbObj) or trigger_error("AMFPHP şu hatayı döndürdü hata oluşan class: 'connect_to_mysql' hata veri tabanında INSERT cümlesi işlenirken oldu. mysql tarafından döndürlen hata :\nError:" . mysql_error());
return true;
}
public function insertPerson($person){
$values= array(
'name' =>$person['name'],
'tel' =>$person['tel']
);
$this->insertSQL('kisiler',$values);
}
public function getAllPersons(){
$personSQL="SELECT * FROM `kisiler`";
return $this->SQL($personSQL);
}
}
?>

bu php class’ı PHP5 standarlarına göre yazıldı. Ancak PHP4’e de uygun yazıldı. eğer public ve private bildirimlerini silerseniz PHP4 ile de çalışacaktır. Yazdığımız class dosyasını amfphp klasöründeki services klasörünün altına kaydediyoruz.

Nesne Yönelimli Programlamanın en temel unsurlarından olan public ve private bildirimleri ile çalışmak çok önemlidir. Yazdığımız php cllass’ındaki private yordamlara (fonksiyon) flashRemoting ile erişmemiz mümkün değil. Bu yolla veri tabanını ve uygulamamızı korumuş oluyoruz.

Şimdi de flash dosyamızı oluşturalım:

MMİstanbul

ve action script kodları da şöyle:

btnGonder.addEventListener(MouseEvent.CLICK,btnGonderClicked);
function btnGonderClicked(event:MouseEvent){
var postObj:Object={name:txtAdSoyad.text,tel:txtTelefon.text}
var nc:NetConnection= new NetConnection();
var resp:Responder = new Responder(postSuccessHandler,faultHandler);
nc.connect("http://localhost/amfphp/gateway.php");
nc.call("connect_to_mysql.insertPerson",resp,postObj);
}
function postSuccessHandler(result:Object){
trace("Kayıt Girişi başarılı");
}
function faultHandler(fault:Object){
trace("Bağlantı Hatası");
}

burada yapılan işlem kabaca şöyle:

http://localhost/amfphp/gateway.php adresine bir bağlantı oluşturuluyor. Bu bağlantıyı oluşturan bağlantı nesnesinin türü NetConnection, ismi ise nc. Bu nesnenin call yordamı bizim yazdığımız php class’ına erişmemizi sağlıyor. sınıfadı.yordam_adı şekilnde hangi yordama bağlanacağımızı ilk parametre ile anltoyoruz.

ikinci parametre bu işlem gerçekleştiğinde dönen bilgileri yakalamak için kullanılacak Responder tipinde resp nesnesi. Bu nesne ise iki türlü sonucun olabilirliği ile çalışıyor. Birisi fonksiyonun (yordamın) başarıyla çalışması ve geriye bir değer döndürmesi. Diğeri ise bir hata oluşması.

üçüncü parametre isteğe bağlıdır. Son parametre değildir. Üçüncü parametreden itibaren istediğimiz kadar parametre yazabiliriz. Bu parametreler çağırdığımız yordama geçirilecektir. Bizim yazdığımız insertPerson yordamı bir parametre aldığı için bizde bir parametre göndermeyi tercih ettik. Gönderdiğimiz parametre bir Object idi. Bu türden parametreler göndermeye mecbur değiliz. Sadece öreneğimizin zengin olması bakımından, nesneleri de parametre olarak geçirbileceğimizi göstermek ve geçirdiğimiz nesne parametreleri PHP ile nasıl çözeceğimizi de göstermek amacıyla Object geçirdik.

flash’ı çalıştıralım ve bir veri girişi yapalım :

MMİstanbul

bu işlem sonucunda veri tabanına veri girişi yapılıp yapılmadığını phpmyadmin ile kontrol edelim :

MMİstanbul

service borwser’ı tekrar çalıştıralım:

MMİstanbul

yazdığımız class soltarafta görünüyor. Sağda ise class’daki public fonksiyonlar görünüyor. getAllPersons fonksiyonunu seçip call butonuna bastığımda alt kısımda fonksiyon çaıştığında geriye döndürdüğü değerleri görüyoruz. Eğer Flex ile çalışıyorsanız o zaman aşağıdaki kodu kullanabilirsiniz.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
public function btnGonderClicked(event:MouseEvent):void{
var postObj:Object={name:txtAdSoyad.text,tel:txtTelefon.text}
var nc:NetConnection= new NetConnection();
var resp:Responder = new Responder(postSuccessHandler,faultHandler);
nc.connect("http://localhost/amfphp/gateway.php");
nc.call("connect_to_mysql.insertPerson",resp,postObj);
}
private function postSuccessHandler(result:Object):void{
trace("Kayıt Girişi başarılı");
}
private function faultHandler(fault:Object):void{
trace("Bağlantı Hatası");
}
]]>

</mx:Script>
<mx:Panel x="10" y="10" width="370" height="238" layout="absolute">

<mx:Form right="0" left="0" bottom="50" top="0">
<mx:FormItem label="Adı Soyadı">
<mx:TextInput id="txtAdSoyad"/>

</mx:FormItem>
<mx:FormItem label="Telefonu">
<mx:TextInput id="txtTelefon"/>
</mx:FormItem>
</mx:Form>
<mx:Button x="187" y="156" label="Gönder" id="btnGonder" click="btnGonderClicked(event)"/>

</mx:Panel>

</mx:Application>


php class’ındaki fonksiyondan geriye dönen değerler Responder clasından tanımladığımız nesnenin result olayına atadığımız fonksiyona parametre olarak döner. Yani yukarıdaki iki örnekte de eğer fonksiyon bir değer döndürüyorsa

private function postSuccessHandler(result:Object):void{

fonksiyonundaki result bu dönen değeri alabilir. result ismi ile tanımladığımız nesne illaki Object olmak zorunda değildir. php class’ından hangi türde değer dönüyorsa ona göre ihtiyaç duyduğunuz tipte tanımlayabilirsiniz.

Flex'de swf Dosya Boyutu Problemi ve Çözüm İpuçları

Flex ile kod yazmaya başladığınız ilk anda büyük bir heyecan içerisinde şimdiye kadar yapmak isteyip de yapamadığınız projeler aniden yeniden bir projeye dönüşüverir. Ancak biraz kod yazdıktan sonra gittikçe büyüyen swf dosyasıyla nasıl başa çıkacağınızı kara kara düşünmeye başlarsınız.

Hele amacınız bir internet uygulaması geliştirmekse, bir türlü yüklenmek bilmeyen sayfa projenizi yeniden, daha ileri bir teknolojinin olacağı bir tarihe doğru, ertelemenize bile neden olabilir. Oturup kara kara swf dosyasının boyutunu nasıl düşüreceğinizi düşünmeye balarsınız.

Bu yazımızda flex ile optimizasyon problemini inceleyeceğiz.

1-Flex derleyicisine optimizasyon talimatı verilmesi:

İlk yapılması gereken işlem flex derleyicisine optimizasyon talimatı vermektir. Bunun için Flex Navigator Panlinden projenizin üzerine sağ tıklayın ve properties seçeneğine tıklayın (yada Project menüsünden properties’i seçin) Sağda bulunan flex compiler seçeneğine tıklayın ve Aditional compiler arguments bağlıklı kutuya "-locale en_US" parametresinden sonra bir boşluk bırakarak:

-optimize=true

Yazın. Bu seçenek ile swf dosyanızın boyutu %40 ‘a kadar düşebilir.

2- mxml yerine Action Script kullanımı:

mxml dili ile oluşturulan program Action Script ile oluşturulandan daha şişkin olmaktadır. Mümkün olduğunca Action Script kullanmakta fayda var. Elbette tüm programı ActionScript ile oluşturmak hem çok zaman alır hem de tasarımı zorlaştırır. Proje süresinin ve harcanan emeğin de optimize edilmesi söz konusu olduğu için benim kişisel tercihim görüntülenmeyen sınıflar için ve nesnelere ait olayları kontrol eden Listener fonksiyonların atanması için Action Script ile yazılması yönündedir.

3-Modül kullanımı:

Proje içindeki tüm bölümler programın her oturumunda kullanılmayabilir. Bu nedenle mümkün olduğunca birbirinden bağımsız bölümleri ayrı moduller halinde hazırlamak ve gerektiğinde çağırmak daha verimli olacaktır. Ayrıca bu yolla takım çalışması yapmakta kolay olur. Yine benim kişisel tercihim tüm modulleri kontrol eden ana bir Application yazılması ve geriye kalan her şeyin modul olarak yazılması yönündedir.

4-Amaca uygun class geliştirme:

Her yazılım için geçerli bir kural vardır ki, o da gereksiz kod tekrarından kaçınmak gerektiğidir. Programı mümkün olan en yapısal ve nesne yönelimli şekilde oluşturmak gerekir. Bu hem o anda yazdığınız programda gereksiz kod tekrarını ortadan kaldırır. Hem de yazdığınız kodların başka projelerde de kullanılabilmesini sağlar.

24 Temmuz 2008 Perşembe

AmfPHP vs WebORB

Bu yazıda iki popüler flash remoting teknolojisini inceleyeceğiz. AmfPHP ve WebOrb.

Ancak incelemeye geçmeden önce bu iki ürünün yerine geçmeye çalıştıkları Flex Data Services yada Adobe firmasının yeni verdiği isimle Live Cycle Data Services ‘in Actionscript ile yazılım geliştirmekte olanlara sunduğu teknolojilerden bahsedelim.

RTMP: Adobe Real Time Messaging Protocol anlamına gelir. Pek çok uygulama bu protokol için farklı portlar kullanılar. Örneğin Adobe Flash Media Server 1935 numaralı portu kullanırken WebOrb 2037 numaralı portu kullanır. Adıdan da anlaşılacağı gibi gerçek zamanlı mesajlaşma için kullanılır ve hem server’dan client uygulamaya hemde client uygulamadan server uygulamaya, hemde client uygulamadan client uygulamaya data gönderimini sağlar.

SharedObject Sınıfı: Adından da anlaşılacağı gibi paylaştırılmış bir nesnedir. Bu sınıftan türetişmiş nesneler aynı server alanına bağlı diğer kopyalarıyla senkronize çalışlır. Özellikle çok kullanıcılı oyun uygulamaları ve chat uygulamalarında kullanılabilecek ideal bir yöntemdir.

RemoteObject Sınıfı : Flash remoting’in özü Remote Object’tir. Server taraflı yazılmış bir class’tan flash tarafında nesne oluşturmakta kullanılır. Remote Object sınfından Actionscript ile türetilmiş tüm nesneler server’daki class’ın tüm public yordamlarına(fonksiyon) ve nesnelerine erişebilir.

NetStream Sınıfı : Client tarafından diğer clientlara dağıtılacak stream veriler için kullanılan sınıftır. Görüntü , ses verileri bu tür verilerdir.

Live Cycle Data Services ‘in yukardaki sınıfara destek vermek amacıyla sunduğu yardımcı bazı yöntemlerde vardır. AsyncToken Sınıfı, Producer ve Consumer bileşenleri ve DataTransferObject sınıfı bu yardımcı sınıflardandır.

Şimdi bir tablo halinde AmfPHP ve WebOrb ‘un destek verdiği özellikleri inceleyelim:

                    AmfPHP   WebOrb PHP      WebOrb.NET
Net Connection Sinifi + + +
RemoteObject - + +
SharedObject Sinifi - - +
NetStream Sinifi - - +
RTMP - - +
Producer Bileseni - + +
Consumer Bileseni - + +
AsyncToken - + +

Bu tablo ışığında hangi teknolojiyi kullanacağınıza karar verebilirsiniz. Ancak şunu belirtmekte fayda var; bir sistem ne kadar çok özelliğe sahipse o kadar karmaşıktır. Bu nedenle genel Türk düşüncesi olan "Bir tane olsun en iyisi olsun" mantığıyla değil projemizin ihtiyaçlarını karşılayabilecek minimum özellikte olanı tercih etmek gerekir. Örneğin sadece client-server arası veri alışverişi yapılacaksa AmfPHP , WebORB’a göre daha iyidir.

Eğer clilent-client veri alışvarişi yapılacaksa o zaman RTMP özelliğini aramak gerekir.