28 Jan

REST Nedir ?

REST, ingilizce Representational State Transfer ( Temsili Durum Transferi) kelimelerinin kısaltması (REST) dır. Temelde, HTTP protokolü ile çalışan, dağıtık hypermedia sistemleri için kullanılan bir yazılım mimarisi biçimidir. REST de SOAP gibi bir servisdir.

SOAP da olduğu gibi , bir sunucu ve bir istemci tarafı vardır. Yalnız SOAP dakinin aksine, bellli bir standardı yoktur. Tek ortak yanları ve standartları HTTP dir. Her ikisi de HTTP protokolü üzerinden haberleşir.

Standartdan kastım, SOAP haberleşirken WSDL denen XML’leri kullanır. Sunucu da istemci de bu XML’lere göre çalışır. Sunucu, WSDL standardına göre oluşturulmuş XML i okuyarak, hangi sorgulara cevap vereceğini, ne sonuçlar döndüreceğini bilir. İstemci ise, bu xml yardımı ile, nereye bağlanacağını, hangi çağrıları yapacağını ve ne sonuçlar alacağını bilir. Böylece bu yazılı kurallar çerçevesinde sunucu ve yazıcı arasında iletişim gerçekleşir.

REST de ise, böyle XML veya benzeri, iletişimi bir standart içerisinde sınırlandıran veya belirleyen bir yapı yok. Sadece şöyle bir standart mevcut : İstemci , sunucuya isteklerini HTTP protokolü üzerinden GET, POST,PUT veya DELETE kullanarak istek yapmalıdır.

REST in SOAP, XML-RPC vb servislerin yerine tercih edilmesinin en önemli sebebi, REST’in birçok platformda, ekstra kütüphaneye ihtiyaç duymadan çalışabilmesidir. Ayrıca diğer birçok servis mimarisine göre daha kolay kullanılabilir, öğrenilebilir ve uygulanabilirdir. Bu ve daha birçok avantajınun dışında en önemli dezavantajı bir standardı olmayışıdır. Her bir REST sunucusu ile iletişim kurmak için farklı yöntemler kullanmanız gerekebilir.
Aynı zamanda bu sunucu tarafında da aynı, REST sunucusunun yazılması tamamen geliştiriciye kalmış.

REST i daha iyi anlatabilmek için küçük bir REST sunucusu ve REST istemcisi yazdım. Yalnız dikkat etmeniz gereken şey, aşağıda yazdığım kodlar, bir ürün içerisinde kullanılmaya uygun olmadığıdır. REST tarafında güvenlik tamamen geliştiriciye kaldığı için, REST sunucunuzu tasarlarken güvenlik işlemlerini ayrıca ve titizlikle yapmalısınız. Aksi taktirde istemediğiniz sonuçlar ile karşılaşma olasılığınız yüksektir.

Burdaki kodların çalışabilmesi için linux bir makinaya sahip olmanız gerekiyor. Windows kullanmadığım için , windows makina üzerindeki kurulumun nasıl yapılacağını anlatmayacağım.

1- Kendi makinanızda bulunan web sunucusunda restex diye bir klasör oluşturun. Ben kendi makinamda /var/www dizini altına oluşturdum. Ve geri kalan ayarları da bu dizin yapısını baz alarak anlatacağım

2- /etc/hosts dosyasını sudo komutu ile açarak şu satırı ekleyin :
127.0.0.1 api.local

3- Apache’de bir sanal host tanımlayın. Bendeki Apache ayarlarının bulunduğu dizin /etc/apache2/sites-enabled/000-default olduğundan, ben bu dosyaya aşağıdaki satırları ekledim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<VirtualHost *:80>
        ServerAdmin webmaster@localhost

        DocumentRoot /var/www/restex
        ServerName api.local
        <Directory />
                Options FollowSymLinks
                AllowOverride All
        </Directory>
        <Directory /var/www/restex/>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride All
                Order allow,deny
                allow from all
        </Directory>
</VirtualHost>

Tabi bunu yapabilmek için sudo ile super user hakları ile açmış olduğum bir editörle yapabileceğimi de vurgulayayım. Gerçi düzenli linux kullanıcıları buna alışkındır, fakat yeni başlayanlar bunu unutur çoğunlukla.

4- Apache’yi yeniden başlattım :

1
sudo apache2ctl restart

5- /var/www/restex dizini içerisinde bir .htaccess dosyası oluşturdum ve içine şunları ekledim :

1
2
3
4
5
6
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

Bu satırları eklememdeki amaç, api.local hostuna gelecek tüm çağrıları index.php ye yönlendirmem gerektiğindendir. Böylece api çağrımın ne olduğunu bulabileceğim ( aşağıda ekledğim sunucu kodundaki -RestServer- response metodunu inceleyerek bu işlemi neden yaptığımı daha iyi kavrayabilirsiniz )

6- /var/ww/restex dizini altında index.php oluşturarak şu satırları ekledim (sunucu kodu) :

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
<?php
class RestServer {
  /**
   * Döndürülecek yanıt tipini belirliyoruz
   *
   * @var string $responseType
   */

  protected $responseType;
  /**
   * Classımızın construct metoduna döndürmek istediğimiz
   * farklı bir yanıt tipi varsa bunu verebiliyoruz
   *
   */

  public function __construct($responseType = "text/json"){
    $this->responseType = $responseType;
  }
  /**
   * Sunucumuzun başlatılmasını sağlar
   *
   * @return void
   */

  public function run(){
    // döndürmek istediğimiz yanıt tipini belirtiyoruz.
    header('Content-type: '.$this->responseType);
    // yaptığımız hataları başkaları görsün istemiyoruz :)
    set_error_handler(array($this,'errorHandler'));
    // gelen komutu algılayıp cevabımızı ekrana yazdırıyoruz
    echo $this->response();
  }
  /**
   * Tüm işi burası yapıyor, bizden ne istendiğini
   * anlayarak bir cevap vermemiz gerekiyor.
   *
   * @return mixed
   */
 
  public function response(){
    $request   = substr($_SERVER['REQUEST_URI'],1);
    $request   = explode('/',$request);
    $function  = array_shift($request);

    if(isset($_POST['params'])) {
      $_POST['params'] = json_decode($_POST['params']);
      return call_user_func_array($function,$_POST['params']);
    }else {
      return call_user_func($function);
    }
  }
  /**
   * Hata yakalayıcımız, sistemdeki hataları göstermeyip standart
   * bir mesaj döndürüyoruz. Bu sistemi geliştirerek hata raporlaması vb şeyler de
   * yapılabilir. Fantaziye gerek yok, basit bir örnek sadece :)
   */

  public function errorHandler ($errno, $errstr, $errfile, $errline) {
    echo 'Hatalı veya eksik istek';
    exit;
  }
}
$server = new RestServer('text/html');
$server->run();

Sunucu kodunu açıklama grek yok sanırım, kod üzerindeki açıklamalar yardımcı olacaktır.

7- Şimdi sıra geldi sondan bir önceki adıma. REST istemcimi oluşturmak için , web ana dizininde rest.client.php oluşturdum ( /var/www/rest.client.php) ve içerisine aşağıdaki satırları ekledim :

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
<?php

class RestClient {
  /**
   * Api çağrıların yapmamızı sağlayacak istemcimiz
   * REST çağrıları HTTP protokolü ile yapılacağından
   * curl e ihityaç duyuyoruz
   *
   * @var resource
   */

  protected $client;
  /**
   * Api çağrılarının yapılacağı URL
   *
   * @var string
   */

  protected $url;

  public function __construct($url){
    $this->client = curl_init();
    $this->url = $url;
    curl_setopt($this->client, CURLOPT_RETURNTRANSFER ,1);
  }
  /**
   * Rest sunucumuza istek yapmamızı ve sonucu
   * ekrana yazdırmamızı sağlar.
   *
   * @return void
   */

  public function call($function,$params=null){
    curl_setopt($this->client,CURLOPT_URL,$this->url.'/'.$function);
     curl_setopt($this->client, CURLOPT_POST, 0);
    if(is_array($params)){
      curl_setopt($this->client, CURLOPT_POST, 1);
      curl_setopt($this->client,CURLOPT_POSTFIELDS,$params);
    }
    echo curl_exec($this->client);
  }
}

$client = new RestClient('api.local');
$client->call('date',array('params'=>json_encode(array('d-m-Y H:i:s'))));
$client->call('phpinfo');

8- Ve geldik son adıma, tarayıcıdan localhost/rest.client.php çağırıyoruz. Eğer eksiksiz yaptı iseniz bu adımları, ekranınıza tarih ve php bilgisi dökülmeli. RestClient kodunu da açıklamaya gerek yok sanırım.

Görüldüğü gibi, REST adı ile korkutucu ve karmaşık görünmesine rağmen. Çok da zor olmayan bir yapıya sahip. Yukarıda yaptığımız örnekte sunucumuza istek olarak, php fonksiyonlarını gönderdik. Sunucumuzda kendinde bu php kodlarını çalıştırdı ve bize sonucu döndürdü.
Normal şartlarda sunucu böyle bodoslama her çağrıyı yerine getirmez. Twitter veya Flickr gibi sosyal medya sitelerinin API lerini incelerseniz, Rest sunucusu için kullanılabilecek güvenlik sisteminin nasıl olması gerektiğini kafanızda daha iyi oturtabilirsiniz.

22 Jan

Sphinx Kurulumu

Sphinx kurulumu için aşağıdaki adımları takip etmek gerekiyor. Öncelikle adımları yazıyorum, sonra bunları açıklamaya çalışacağım :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
mkdir sphinx-base
cd sphinx-base
wget http://pecl.php.net/get/sphinx -o /dev/null -O  sphinx.tar.gz
svn checkout http://sphinxsearch.googlecode.com/svn/trunk
cd trunk/api/libsphinxclient/
./configure --prefix=/usr/local
make
make install
cd ~/sphinx-base
tar -zxvf sphinx.tar.gz
cd sphinx-1.1.0/
phpize
/configure --prefix=/usr/local --with-sphinx
make
make install
nano /etc/php5/conf.d/sphinx.ini
extension=sphinx.so
cd ~/sphinx-base/trunk
configure --prefix=/usr/local
make
make install

(1-2) İndirdiğimiz dosyaların derli toplu olabilmesi için bir dizin oluşturdum, bu dizini home klasörümde oluşturdum. Siz de aynı şekilde home dizininizde sphinx-base diye bir klasör oluşturursanız , burdaki örneğin çalışabilmesi mümkün olur. Klasörü oluşturduktan sonra klasöre giriyoruz

(3-4) PHP sphinx eklentisini, sonrasında da sphinx kodlarını sitelerinden indiriyoruz

(5-6-7-8) PHP eklentimizin çalışabilmesi için, libsphinxclient kütüphanesine ihityaç var. Bu yüzden öncelikle bunu derliyoruz.

(9-10-11-12-13-14-15-16-17) Bu uzun adımlarda da php eklentisini derliyoruz.

(18-19-20-21) Bu adımlarda da sphinxi derliyoruz.

Yuakrıdaki adımlarda mutlaka dikkat etmeniz gereken şeyler var. Bunlardan ilki, yukarıda belirttiğim gibi home klasörünüzde sphinx-base diye bir klasör
oluştrumuş olmanız gerekli.
Anlattığım tarih ititbari ile, php sitesinden indirdiğim (3) dosyayı indirememiş olabilirsiniz. Dosyanın doğru yolunu bularak sphinx-base klasöürne indirin ve yukarıda belirttiğim şekilde (10) sphinx-base klasörü içerisine açın. İndirdiğim versiyondaki klasör ismi sphinx-1.1.0 . Sizin edindiğiniz dosyanın ismi farklı olabilir, bu yüzden 11. adımda doğru klasöre giriş yapmalısınız.

Sisteminizde, derlemeler için gerekli kütüphaneler mevcutsa, kurulumu sorunsuz olarak tamamlanacaktır. Bir sonraki yazıda, sphinx ile gelen örnek veritabanı ve örnek ayarlar ile basit bir örnek kod ekleyeceğim.

Bu seriye ait diğer yazılar :

Metin Bazlı Arama ? Site İçi Arama Motoru
Aramanın Yapılması ? Site İçi Arama Motoru
Sphinx nedir ?
Sphinx Kurulumu
Sphinx’in Ayarlanması ve Kullanımı

22 Jan

Aramanın Yapılması – Site İçi Arama Motoru

1
2
3
4
5
6
7
8
$sphinx = new SphinxClient;
$sphinx->setServer('localhost',9312);
$sphinx->setMatchMode(SPH_MATCH_EXTENDED);
$sphinx->setMaxQueryTime(30);
$sphinx->setLimits(1,6);  
echo '<pre>',
          print_r($sphinx->query($arananKelime,"indexAdi"),true),
          '</pre>';

Sphinx ile yapılan aramalar direkt veritabanı tabloları üzerinde olmamaktadır, Sphinx kurulumunda belirttiğimiz index üzerinde bir SQL oluştururuz. Bu SQL, Sphinx in indeksleyeceği verileri veritabanından almasını sağlar, bu verileri bizim belirleyeceğiniz aralıklarda alarak indeksi günceller.

Arama işlemini yapmak için yukarıdaki kodlar çalıştırılmalıdır. Kodlar sade ve anlaşılır.
Sınıfımızı oluşturuyor,sunucu adresimizi ve portunu ayarlıyoruz (genelde yukarıda belirtilen portta çalışır, siz farklı bir port belirtmedikçe). Sonrasında arama modu, toplam sorgu zamanı ve limit değerlerini ayarladıktan sonra sorgumuzu çalıştırıyoruz.

Bu sorgu sonucunda aşağıdakine benzer bir sonuç elde edersiniz (eğer aramanızdan sonuç dönmezse null döner) :

Array
(
    [error] => 
    [warning] => 
    [status] => 0
    [fields] => Array
        (
            [0] => name
            [1] => short_description
            [2] => description
            [3] => meta_description
        )

    [attrs] => Array
        (
            [type_id] => 1
            [language] => 1
        )

    [matches] => Array
        (
            [507] => Array
                (
                    [weight] => 1
                    [attrs] => Array
                        (
                            [type_id] => 1
                            [language] => 1
                        )

                )

            [508] => Array
                (
                    [weight] => 1
                    [attrs] => Array
                        (
                            [type_id] => 12
                            [language] => 1
                        )

                )

            [509] => Array
                (
                    [weight] => 1
                    [attrs] => Array
                        (
                            [type_id] => 1
                            [language] => 1
                        )

                )

            [510] => Array
                (
                    [weight] => 1
                    [attrs] => Array
                        (
                            [type_id] => 1
                            [language] => 1
                        )

                )

            [511] => Array
                (
                    [weight] => 1
                    [attrs] => Array
                        (
                            [type_id] => 12
                            [language] => 1
                        )

                )

            [512] => Array
                (
                    [weight] => 1
                    [attrs] => Array
                        (
                            [type_id] => 1
                            [language] => 4
                        )

                )

        )

    [total] => 1000
    [total_found] => 28214
    [time] => 0
)

Yukarıda dönen sonucu açıklayayım :
error, warning, status, fields, attrs alanlarını açıkalamaya gerek yok şimdilik, çünkü adlarından anlaşıldığı gibi, sorgu ile ilgili gerekli bazı bilgilerin döndürülmesini sağlar.
Burda en önemli anahtar matches dır. Bu anahtar altında, aranan kelimeye uygun kayıtların ID’leri döndürülür.

 [511] => Array
                (
                    [weight] => 1
                    [attrs] => Array
                        (
                            [type_id] => 12
                            [language] => 1
                        )

                )

Burdaki kaydın anlatmaya çalıştığı şey şudur : aradığınız kelime 511 nolu kayıtda mevcut ve bu kaydın attributleri şunlardır, bu kelimenin arama ağırlığı şudur vb. Burdaki attrs, index oluşturulması sırasında bizim tarafımızdan belirlenir. Eğer herhangi bir attribute belirtmezsek buradaki attrs anahtarı altında hiçbir kayıt olmayacaktır.
Attribute tanımlamanın temel amacı, aranan kelimeyi filtereleyebilmektir.

Bunların dışında kalan total kısmı, bir defada listelenebilecek veri miktarını.
Total found, arama sonucu bulunan toplam kayıt miktarını temsil eder.

Daha önce belirttiğimiz gibi, sorgu direkt olarak veritabanı üzerindeki tablo üzerinde çalıştırılmaz, arama motoru sunucusu verileri aldıktan sonra bağımsız olarak çalışarak, bu verileri en hızlı sonuç verecek şekilde indeksler. Sonra siz sorgu yaptığınızda, belirtmiş olduğunuz tabloda, aradığınız metne uyan kayıdın ID sini ve yaptığınız ayarlamaya göre diğer sonuçları döndürür (yukarıdaki örnek sonuç gibi).

Sonrasında yapmanız gereken, dönen SPhinx sonuçlarından IDleri ayıklayarak veritabanı üzerindeki tabloya sorgu yapmak :

$sorgu='SELECT*FROM books where id in(507,508,509,510,511,512)';

Burda vermiş olduğum örnek döküm, bilgisayarımda çalışan Sphinx sunucusunda oluşturduğum indexde yapılan arama sonucu dönen veridir. Sizin oluşturacağınız indexlerde yapacağınız aramalarda, yukarıdakine benzer sonuç alamayabilirsiniz. Ama ana bölümler aynıdır.

Bu seriye ait diğer yazılar :

Metin Bazlı Arama ? Site İçi Arama Motoru
Aramanın Yapılması ? Site İçi Arama Motoru
Sphinx nedir ?
Sphinx Kurulumu
Sphinx’in Ayarlanması ve Kullanımı

22 Jan

Metin Bazlı Arama – Site İçi Arama Motoru

Aslında burda anlatmaya çalışacağım şey, bir site içi arama motorunun nasıl oluşturulcağından öte, bu iş için kullanılabilecek, metin bazlı bir arama motorunu (Sphinx) anlatmak.

Basit anlamda bir site içi arama motoru, site içerisine eklenmiş bütün metinleri arayabilecek bir SQL sorgusu ile yapılır. Bunun için basit SQL ler veya daha iyi sonuç alabilmek için kompleks SQL lerde kullanılabilir.

Ama ne yazık ki, başarılı bir metin bazlı arama için bunlar yetmiyor. Arama yapacak tablo veya tabloların boyutu arttıkça sorgularımızın yavaş çalışması kaçınılmaz olacak. İşte burda devreye metin bazlı arama motorları devreye giriyor.

Bu arama motorları, kullanılan veritabanlarından bağımsız olarak çalışarak, istenilen tablo veya tablolardan metinlerin alınıp indekslenmesi ile, daha hızlı ve daha başarılı arama sonuçları alınmasını sağlıyor.

Açık kaynak kodlu ve ücretsiz bazı arama motorları şunlar :

DataparkSearch
Ferret
Ht-//Dig
Hyper Estraier
Lemur/Indri
Lucene
mnoGoSearch
Sphinx
Swish-e
Xapian

Bunlardan sadece Sphinx ve Lucene’i inceleme fırsatı bulabildim. Lucene in dağıtık sistemler için uygun olmaması ve (benim için) anlaşılması zor bir yapısı olması sebebi ile Sphinx ile çalışmalarıma devam ettim. Sphinx iyi bir dökümantasyona sahip, kolayca kurup ayarlama yapabiliyorsunuz.

Normalde öncelikle kurulumundan başlayarak anlatmam gerekirdi, ama bu sefer tersinden anlatmaya çalışacağım :

– Aramanın yapılması
– İstemcinin kurulması
– Sunucunun kurulması ve yapılandırılması

şeklinde anlatmaya çalışacağım.

Sphinxin PHP için hazırlanmış bir eklentisi mevcut, eklenti kurmak istemiyorsanız, Sphinx işlemlerini yapabilmek için hazırlanmış hazır bir sınıf da mevcut. Ben eklentiyi kullanmayı tercih ediyorum, ama eklentinin kurulmasının mümkün olmadığı zamanlarda bu sınıf iyi bir çözüm olabilir.

Burda eklentiyi baz alarak anlatacağım, bu yüzden burda yazdığım kodlar ile API classını kullanırken hata alırsanız, bunun API classından kaynaklanabileceğini unutmayın. Böyle bir ihtimal düşük olmakla birlikte belirtmekte fayda var.

Bu seriye ait diğer yazılar :
Metin Bazlı Arama ? Site İçi Arama Motoru
Aramanın Yapılması ? Site İçi Arama Motoru
Sphinx nedir ?
Sphinx Kurulumu
Sphinx’in Ayarlanması ve Kullanımı