PHP Long Polling Örneği

Web ve mobil uygulamaların son zamanlardaki olmazsa olmazlarından birisi de bize olayları bildirimler ile iletmesi. Uygulamalar gelen mesajları, beğenileri vs. sayfanın bir yerinde bizim başka bir sayfaya gitmemize gerek kalmadan bize iletiyorlar. Ben de üzerinde çalıştığım bir uygulama+web sayfasında bildirimleri gösterme ihtiyacı hissettim. İlk etapta bunu web socketler ile yapmaya karar verdim. İlk denemem de gayet güzel bir şekilde çalıştı ama bir de mobil uygulama üzerinde denemeye karar verdiğimde hayal kırıklığına uğradım çünkü android WebView’de web socketler desteklenmiyordu. Bu nedenle daha az verimli, daha sorunlu ama yapması gereken işi platform ayırt etmeden yapan eski yöntem long polling ile yapmaya karar verdim. Belki ihtiyacı olanlar olabilir düşüncesiyle burada bir küçük örneğini paylaşmaya karar verdim, temel mantığı göstermekte faydalı olacaktır.  Öncelikle değişiklik olup olmadığını takip eden php dosyamızı yazalım.

polling.php

<?php
$gonderenId=$_POST["gonderenId"];
$pollMu=$_POST["poll"];
if (file_exists($gonderenId.'.txt') == false)
{
    file_put_contents($gonderenId.'.txt', time());
}

if (isset($pollMu))
{
    set_time_limit(150); // Zaman limitini beliliyoruz

    date_default_timezone_set('Europe/Istanbul');
    $time = time();
    $poll = true;
    while ($poll)
    {
        clearstatcache();
        $mtime = filemtime($gonderenId.'.txt');
        if ($mtime > $time) // Eğer dosyanın eklenme/güncellenme zamanı alınan zamandan büyük mü 
        {
            $poll = false;
            //burada veritabanından ilgili değerler çekilecek.
        }
        sleep(1); // Kaynakları tüketmemek için bir süre bekliyoruz
    }

    $arr = array ('mesaj'=>1,'begeni'=>2,'hediye'=>3); // Bunlar veritabanından alınan sonuçlar olacak
    echo json_encode($arr);
    exit;
}
?>

Bu dosyada öncelikle değişiklikleri takip edilecek kullanıcının idsini alıp, eğer bu idli bir dosya yoksa bir text dosyası oluşturuyoruz.  Daha sonra bir while loop’u içerisinde oluşturulan dosyanın tarihi, while’dan önce alınan tarihten büyük mü diye bakıyoruz. Eğer büyükse dosya güncellenmiştir, dosya güncellemesini ilgili kişiye yapılan işlemlerden önce yapıyoruz. Bir sonraki ekleyeceğimiz dosyada yapılan iş. Eğer bu koşulu sağlıyorsa, while döngüsünden çıkmak için değişkenimize false atıyoruz ve sonrasında veritabanından ilgili sorguları çekiyoruz. Ve bunlarsı json olarak dönüyoruz.

islem.php

<?php

$aliciId=$_POST["aliciId"];
$time = time();
file_put_contents($aliciId.'.txt', $time); // İlgili kullanıcının dosyasına o anı yazıyoruz ki server.php değişikliği yakalayabilsin.
//Burada veritabanında yapacağımız asıl işleri yapıyoruz.

?>

Kodumuzun bu kısmı ise kişileri mesaj attığımızda, beğeni gönderdiğimizde vs çalışacak olan veritabanı kodlarının bulunduğu kısım. Burada veritabanı işlemlerinden hemen önce alıcının idsi ile bulunan dosyaya tarih bilgisini atıyoruz ki dosyanın tarihi güncellensin ve az önce yazdığımız while döngüsündeki koşulu sağlasın.

Son olarak da client sayfamızı yazalım.

client.html

<html>
	<head>
		<title>
			Deneme
		</title>
		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1254">
	<script src="jquery-2.0.3.min.js"></script>
	<script>
		$(document).ready(function() {

			startPolling();

		$("#gonder").click(function(){
			$.ajax({
				type: "POST",
				url: 'islem.php',
				data: {
					aliciId: '123456789' // Diğer kullanıcının bilgisi
				},
				success: function(data) {
					alert("gönderildi.");
				}
			});				
		});	

		});

		function startPolling()
		{
			$.ajax({
				type: "POST",
				url: 'polling.php',
				data: {
					poll: 'evet',
					gonderenId: '123456789' // Login olan kullanıcının bilgisi
				},
				success: function(data) {
					displayNotifications(data);
					startPolling();
				}
			});		
		}

		function displayNotifications(data)
		{
			var obj;
			try {
				obj = jQuery.parseJSON(data);
				if(obj.mesaj > 0)
					$("#mesaj").html("Mesaj="+obj.mesaj);
				if(obj.hediye > 0)
					$("#hediye").html("Hediye="+obj.hediye);
				if(obj.begeni > 0)
					$("#begeni").html("Begeni="+obj.begeni);
			} 
			catch(err)
			{
				return true;
			}

		}
	</script>
	</head>
	<body>
	<div id="mesaj"></div>
	<div id="hediye"></div>
	<div id="begeni"></div>
	<br />
	<input type ="button" id="gonder" value="Etkileşim Gönder" />
	</body>
</html>

Burada öncelikle sayfamız ilk yüklediğinde ajax ile startPolling fonksiyonumuzu çağırıyoruz. gonderenId değişkeni login olan kullanıcıyı, aliciId de mesaj attığımız vs. kullanıcıyı gösterecek. Burada aynı olma sebebi test edebilme amaçlı. Eğer long polling başarı ile tamamlanırsa, yani bir bildirim gelmişse bildirim divlerimizi güncelliyoruz. Sonrasında tekrar startPolling fonksiyonumuzu çağırıyoruz ki dinlemeye devam edebilelim. İşte hepsi bu kadar. İlgili dosyaları lokalinizde oluşturup, kendiniz de deneyebilirsiniz. Jquery dosyasını da aynı dizine koymayı unutmayın.

Bugünlük bu kadar, Çevik Kalın 🙂