PHP Tip Güvenliği
Hakan DAMAR Tarih: 13/06/2009 Yorum: 3 adet
Okunma : 2038 Tutanlar: Bu yazıyı 2 kişi tuttu.
Merhaba,
Bildiğiniz üzere PHP , C# gibi type güvenliği olan dillerden değildir. Değişkenler tipi belirtilmeden yaratılır ve ona göre kullanılır. Peki tip güvenliği dedimiz olay nedir?
Tip güvenli bir değişken oluşturalım.
[C#]
int sayi = 1535;
float fSayi = 15.4;
string yazi = "Microsoft Windows 7″;
Tip güvenliği olmadan oluşturalım.
[PHP]
$sayi = 1535;
$fSayi = 14.45;
$yazi = "I lost control. :)";
Şimdi bu iki tanımlama arasındaki fark sizinde tahmin ettiğiniz gibi birisinde oluşturulan değişkenin tipi baştan belirtilerek oluşturuluyor böylece ileride kullandığımızda programımız her birini tipine uygun çalıştırıyor veya hata veriyor. Diğerinde ise tip belirtmeden bunu dilin kendisinin anlamasını tercih ediyoruz. Gerçi PHP 5.2.x sürümünden sonra bu ayrımı çok daha iyi yapıyor fakat büyük programlarda tür dönüşümleri ve değer tip değişikliklerinden çok büyük problemler çıkabilmektedir.
Peki PHP bunun için ne yapıyor? Tabii ki bir çözümümüz var. Yukarıdaki aynı tanımlamayı şu şekilde de yapabiliriz.
[PHP]
$sayi = (int)1535;
$fsayi = (double)14.45;
$yazi = (string)"I lost control";
Böylece hem değişken tanımlamış hem de aynı zamanda bir convert işlemi ile değişkenlerin türlerini istediğimiz türe çevirdik. PHP ile değişken tanımlama seviyesinde yapabileceğimiz maximum budur diye tahmin ediyorum. Peki biz önemli projelerimizde bu tipleri nasıl kontrol edeceğiz. Büyük bir program geliştirdiğimizde, değişkenin nerelerden geçtiğini ve son değişken değerinin, bizim istediğimiz tipten olup olmadığını anlamak güçtür. Ayrietten bunu run time'da denetlemek daha da zordur. Çünkü, gelen veriler kullanıcılardan veya farklı 3. bir web servisinden olabilir. Bu nedenle bizim bunu program içinde denetlememiz gerekmektedir. Böylece runtime'da gelen datalar kontrol fonksiyonu tarafından denetlenerek olası problemler öngörülecektir.
İlgili fonksiyonu aşağıda veriyorum. Kendi class'larınıza ekleyebilirsiniz.
<?php
class foo {
protected $type;
/**
* Type Controller
* @var any type
*/
public function typeControl($type) {
$this->type = $type;
is_string($type) ? $type = "String" : null;
is_int($type) ? $type = "Int" : null;
is_double($type) ? $type = "Double" : null;
is_bool($type) ? $type = "Bool" : null;
is_array($type) ? $type = "Array" : null;
is_float($type) ? $type = "Float" : null;
is_object($type) ? $type = "Object" : null;
$type = "Bu değişken ".$type." türündendir.<br>";
return print $type;
}
}
// Variables
$control = new foo();
$int = 3;
$str = "test";
$double = 7.9;
$bool = false;
$arr = array("Hakan",9,"Arda",7,"Atilla",3);
$object = new foo();
// Type Controller
$control->typeControl($bool);
$control->typeControl($double);
$control->typeControl($str);
$control->typeControl($int);
$control->typeControl($arr);
$control->typeControl($object);
?>
İyi Çalışmalar.
Hakan DAMAR
Öncelikle okumak için zaman ayırdığından dolayı teşekkür ediyorum.
Büyük uygulamalarda tip kontrolü olmadan ilerlediğimde hep başıma bu tip değişikliklerinden sorun çıkmıştır. Yazdığımızda o an bir sorun yok. Sorunsuz çalışıyor fakat senkron iş yapan class'lar bir birlerine veri aktardıklarında atıyorum $int_logRows; değişkeni bir anda 102.1 değeri gelerek int'ten double'a dönebiliyor. Belki çoğu uygulamada olmaz ama finans modülü olan bir uygulamada her türü tek bir değer tipi döndürmeye zorlamayamıyoruz ( Örn: intval() ). Eğer böyle bir convert işlemi yaparsak küsüratları kaybedebiliriz.
PHP'nin source kodlarından gettype() fonksiyonunu incelemedim ama php.net'te yazılana göre bu fonksiyonu kritik karşılaştırmalarda kullanmamamızı söylüyorlar ve yavaş olduğunuda belirtiryorlar. Bu açıklamayı yaptıktan sonra madem düzgün çalışmıyor ve yavaş, neden yazıldığını sorguladım. :) İlgili Açıklama: http://us3.php.net/manual/en/function.gettype.php
Diğer class'lar için ya bir interface'in içine gömerdim. Yada main class'lardan birine(Base'de implimente edilen.) protected olarak yazardım.
Saygılarımla.
Makale için teşekkürler...
Ben de bu noktada veri tiplerinin çağırılması gibi sınıfa ihtiyaç duymadım.
Mesela diyelim ki girilen veri:
$degisken = '2';
Benim ise ihtiyacım olan tam sayı 2... Pekala bunun için sırf
if ($control->typeControl($degisken) != 'int') { triggererror('Geçersiz veri tipi', EUSER_ERROR); }
Biraz saçma olabilirdi :) Bunun yerine ihtiyacımız olan o veri tipine zorlamak daha mantıklı... Mesela bu başlık için basit bir sınıf yazdım...
<?php
class Datatype_Forcing
{
const FORCE_STR = 1;
const FORCE_INT = 2;
const FORCE_FLOAT = 4;
const FORCE_BOOL = 8;
const FORCE_ARRAY = 16;
/*
İstenildiği taktirde Uzatılabilir....
const FORCE_UINT = 16; // Doğal Sayı (0 ve 0 'dan Büyük Tam Sayılar)
const FORCE_MD5 = 32; // MD5 olması zorunlu string ^[a-f0-9]{32}$
.
.
.
.
.
vs. vs..
*/
public function __construct()
{
// doğrudan oluşturulamaz sınıf
}
public function apply($data, $forcetype = self::FORCE_STR)
{
if (!$this->verify_forcetype($forcetype))
{
trigger_error('Datatype_Forcing::force() fonksiyonu için geçersiz zorlama tipi', E_USER_ERROR);
}
switch (true)
{
case (($forcetype & self::FORCE_ARRAY) == self::FORCE_ARRAY):
$data = is_array($data) ? $data : array();
$forcetype = $forcetype = $forcetype & ~self::FORCE_ARRAY;
// Dizi değerleri içinde kısa yoldan doğrulama?
if (!empty($data) AND $forcetype > 0)
{
foreach ($data AS $key => $subdata)
{
$data["$key"] = $this->apply($subdata, $forcetype);
}
}
break;
case (($forcetype & self::FORCE_STR) == self::FORCE_STR):
$data = trim(strval($data));
break;
case (($forcetype & self::FORCE_INT) == self::FORCE_INT):
$data = intval($data);
break;
case (($forcetype & self::FORCE_FLOAT) == self::FORCE_FLOAT):
$data = floatval($data);
break;
case (($forcetype & self::FORCE_BOOL) == self::FORCE_BOOL):
$data = !empty($data) ? 1 : 0;
break;
}
return $data;
}
public function verify_forcetype($forcetype)
{
// tip içerisinde FORCE_ARRAY mevcutse çıkar...
if ($forcetype & self::FORCE_ARRAY)
{
$forcetype = $forcetype & ~self::FORCE_ARRAY;
if (empty($forcetype))
{
return true;
}
}
return in_array($forcetype, array(self::FORCE_STR, self::FORCE_INT, self::FORCE_FLOAT, self::FORCE_BOOL));
}
}
$force =& new Datatype_Forcing();
$test1 = ' Test 1 ';
$test2 = '26.1';
$test3 = false;
$test4 = array(
' sdf asdf ',
'12',
16.5
);
echo "
<style type=\"text/css\"> html { font: 10pt Verdana } </style>
Karakter Testleri <br /><p>";
echo "Test1: " . $force->apply($test1, Datatype_Forcing::FORCE_STR) . "<br />\n";
echo "Test2: " . $force->apply($test1, Datatype_Forcing::FORCE_INT) . "<br />\n";
echo "Test3: " . $force->apply($test1, Datatype_Forcing::FORCE_FLOAT) . "<br />\n";
echo "Test4: " . print_r($force->apply($test1, Datatype_Forcing::FORCE_ARRAY), true) . "<br />\n";
echo "Test5: " . $force->apply($test1, Datatype_Forcing::FORCE_BOOL) . "</p>\n";
echo "Tam Sayı Testleri <br /><p>";
echo "Test1: " . $force->apply($test2, Datatype_Forcing::FORCE_STR) . "<br />\n";
echo "Test2: " . $force->apply($test2, Datatype_Forcing::FORCE_INT) . "<br />\n";
echo "Test3: " . $force->apply($test2, Datatype_Forcing::FORCE_FLOAT) . "<br />\n";
echo "Test4: " . print_r($force->apply($test2, Datatype_Forcing::FORCE_ARRAY), true) . "<br />\n";
echo "Test5: " . $force->apply($test2, Datatype_Forcing::FORCE_BOOL) . "</p>\n";
echo "Reel Sayı Testleri <br /><p>";
echo "Test1: " . $force->apply($test3, Datatype_Forcing::FORCE_STR) . "<br />\n";
echo "Test2: " . $force->apply($test3, Datatype_Forcing::FORCE_INT) . "<br />\n";
echo "Test3: " . $force->apply($test3, Datatype_Forcing::FORCE_FLOAT) . "<br />\n";
echo "Test4: " . print_r($force->apply($test3, Datatype_Forcing::FORCE_ARRAY), true) . "<br />\n";
echo "Test5: " . $force->apply($test3, Datatype_Forcing::FORCE_BOOL) . "</p>\n";
echo "Dizi Testleri <br /><p>";
echo "Test1: " . $force->apply($test4, Datatype_Forcing::FORCE_STR) . "<br />\n";
echo "Test2: " . $force->apply($test4, Datatype_Forcing::FORCE_INT) . "<br />\n";
echo "Test3: " . $force->apply($test4, Datatype_Forcing::FORCE_FLOAT) . "<br />\n";
echo "Test4: " . print_r($force->apply($test4, Datatype_Forcing::FORCE_ARRAY), true) . "<br />\n";
echo "Test5: " . $force->apply($test4, Datatype_Forcing::FORCE_BOOL) . "</p>\n";
echo "Dizi-Karakter Testleri <br /><p>";
echo "Test4: " . print_r($force->apply($test4, Datatype_Forcing::FORCE_ARRAY | Datatype_Forcing::FORCE_STR), true) . "<br />\n";
echo "Dizi-Tam sayı Testleri <br /><p>";
echo "Test4: " . print_r($force->apply($test4, Datatype_Forcing::FORCE_ARRAY | Datatype_Forcing::FORCE_INT), true) . "<br />\n";
echo "Dizi-Reel Sayı Testleri <br /><p>";
echo "Test4: " . print_r($force->apply($test4, Datatype_Forcing::FORCE_ARRAY | Datatype_Forcing::FORCE_FLOAT), true) . "<br />\n";
?>
Çıktı Sonucu
<style type="text/css"> html { font: 10pt Verdana } </style>
Karakter Testleri <br /><p>Test1: Test 1<br />
Test2: 0<br />
Test3: 0<br />
Test4: Array
(
)
<br />
Test5: 1</p>
Tam Sayı Testleri <br /><p>Test1: 26.1<br />
Test2: 26<br />
Test3: 26.1<br />
Test4: Array
(
)
<br />
Test5: 1</p>
Reel Sayı Testleri <br /><p>Test1: <br />
Test2: 0<br />
Test3: 0<br />
Test4: Array
(
)
<br />
Test5: 0</p>
Dizi Testleri <br /><p>Test1: Array<br />
Test2: 1<br />
Test3: 1<br />
Test4: Array
(
[0] => sdf asdf
[1] => 12
[2] => 16.5
)
<br />
Test5: 1</p>
Dizi-Karakter Testleri <br /><p>Test4: Array
(
[0] => sdf asdf
[1] => 12
[2] => 16.5
)
<br />
Dizi-Tam sayı Testleri <br /><p>Test4: Array
(
[0] => 0
[1] => 12
[2] => 16
)
<br />
Dizi-Reel Sayı Testleri <br /><p>Test4: Array
(
[0] => 0
[1] => 12
[2] => 16.5
)
<br />
Böylece veri tipi kontrolü yapmaktansa veriyi her ne olursa olsun istediğimiz veri tipine zorlayabilir ve geçerli aralıklarla olup olmadığını doğrulayabiliriz. Dolayısıyla işlemleri yarıda kesmemiş oluruz. Bana göre bu şekilde bir yönlendirme daha mantıklı olacaktır.
Kolay gelsin.
Haber
İlişkili haber bulunamadı.
Ders
İlişkili ders bulunamadı.
Etkinlikler
Konferans
XII. Akademik Bilisim Konferansı
XII. Akademik Bilisim Konferansı
II. AB'10
XII. Akademik Bilisim Konferansı 10-12 Şubat
Mugla Üniversitesi
Üniversitelerde bilgi teknolojileri konusunda ilgili grupları biraraya
...
Kategori:
Konferans
Kimler Burada? 
Son 1 dakika içinde MMIstanbul' da 194 (0 kayıtlı, 194 ziyaretçi) kullanıcı varmış. Login durumda olanlar aşağıda:
MMIstanbul Blog'undan
Blog Bölümü Blogevi.com'a Taşınıyor
Selam arkadaşlar MMIstanbul'da , tasarımcı ve programcıların blog yazılarını "feedleyerek" MMIstanbul okurlarını MMIstanbul dışın ...
7.500'üncü üyemiz Cem Koç!
Neler Yapılabilir?
500 Hatası Hakkında!
Reklam, MMIstanbul ve Yeni Projeler (Durumumuz Bu Tarzında)









dinamik-statik dil tartismasina girmek istemiyorum ama dinamik bir dilde eger degisken turu tanimlamak gerekmiyorsa, bence bunun guvenli olmadigini o andan sonra "sorgulamamak" lazim diye dusunuyorum.
benim sormak istedigim iki sey var.
birincisi bu yazdigin metodu sadece primitif turler icin yazmadan butun siniflar ve kullanici tanimli siniflar icin nasil yazardin?
ikincisi, PHP'de varolan gettype(), get_class() metodlarindan yararlanarak tur denetimi yapmak daha iyi degil mi? (illaki yapmak gerekiyorsa ki ben bunu gereksiz goruyorum hala)
makale icin tesekkurler.