9. Veritabanı ve Veri

DLE'nin veritabanı katmanı engine/classes/mysql.php içindeki db sınıfıdır (366 satır). mysqli üzerine kuruludur ve MySQL 5.6.4 veya üstünü gerektirir. Modüllerinizde bu nesne $db olarak hazırdır.

db sınıfının metotları

MetotNe yapar?
query($sql, $show_error = true, $log_query = true)Sorgu çalıştırır, sonuç kaynağını döndürür.
multi_query($sql, $show_error = true, $log_query = true)Noktalı virgülle ayrılmış çoklu sorgu çalıştırır.
super_query($sql, $multi = false, …)Sorguyu çalıştırıp sonucu doğrudan döndürür.
get_row($query_id = null)Sonuçtan tek satır, yalnızca isimli indeksle.
get_array($query_id = null)Sonuçtan tek satır, hem isimli hem sayısal indeksle.
num_rows($query_id = null)Sonuçtaki satır sayısı.
insert_id()Son INSERT'in otomatik artan ID'si.
get_affected_rows()Etkilenen satır sayısı.
safesql($source)Metni SQL için kaçırır. Tek parametrelidir.
free($query_id = null)Sonuç belleğini serbest bırakır.
close()Bağlantıyı kapatır.
get_result_fields()Sonuç alanlarının bilgisi.
get_real_time()Mikrosaniyeli zaman (performans ölçümü).
!
Beklediğiniz bazı metotlar YOK select(), insert(), update(), delete() ve count() diye metotlar bulunmaz. Bu sınıf ham SQL çalıştırır; soyutlama (ORM) katmanı yoktur. Ayrıca begin/commit/rollback gibi hazır bir işlem (transaction) arayüzü de sunmaz.

super_query — en çok kullanacağınız metot

super_query($query, $multi = false, $show_error = true, $log_query = true)
  • $multi = false (varsayılan): tek satır ilişkisel dizi döner.
  • $multi = true: satır dizisi döner (her satır ilişkisel dizi).
// Tek satır
$row = $db->super_query("SELECT COUNT(*) as count FROM " . PREFIX . "_post");
echo $row['count'];

// Birden çok satır
$rows = $db->super_query("SELECT id, title FROM " . PREFIX . "_post LIMIT 5", true);
foreach ($rows as $row) {
    echo $row['title'];
}

Klasik döngü kalıbı

DLE'nin kendi modüllerinde en sık görülen kalıp query() + get_row() döngüsü ve sonunda free()'dir:

$db->query("SELECT id, title FROM " . PREFIX . "_post ORDER BY id DESC LIMIT 10");

while ($row = $db->get_row()) {
    $rows[] = $row;
}

$db->free();

Gerçek örnek — engine/modules/stats.php:

$db->query( "SHOW TABLE STATUS FROM `" . DBNAME . "`" );
while ( $r = $db->get_row() ) {
    // …
}
$db->free();
i
free() sırası önemli num_rows() çağrısı free()'den önce yapılmalıdır; çünkü free() sonucu yok eder ve query_id'yi null yapar.

get_row() ile get_array() farkı

Altta kullanılanErişim
get_row()mysqli_fetch_assocYalnızca $row['title']
get_array()mysqli_fetch_arrayHem $row['title'] hem $row[0]

İkisi de tek satır döndürür; tüm sonucu değil. Çoğu durumda get_row() tercih edilir çünkü bellek kullanımı daha azdır.

SQL güvenliği

✕
Kullanıcı girdisini ASLA doğrudan sorguya koymayın "… WHERE id = '{$_GET['id']}'" gibi bir kullanım SQL enjeksiyonuna açıktır.
// Sayısal değerler: intval ile zorla
$id = intval($_GET['id']);
$db->query("SELECT * FROM " . PREFIX . "_post WHERE id = '{$id}'");

// Metin değerler: safesql ile kaçır
$name = $db->safesql($_POST['name']);
$db->query("SELECT * FROM " . PREFIX . "_benim_tablom WHERE baslik = '{$name}'");

safesql() tek parametre alır ve mysqli_real_escape_string kullanır. Tablo/sütun adları için safesql() kullanmayın; onlar sabit olmalıdır.

PREFIX ve USERPREFIX

Tablo ön ekleri kurulumda engine/data/dbconfig.php içinde tanımlanır:

define ("PREFIX", "{$dbprefix}");
define ("USERPREFIX", "{$dbprefix}");
define ("COLLATE", "utf8mb4");
define('SECURE_AUTH_KEY', '{$auth_key}');
SabitNerede kullanılır?
PREFIXİçerik tabloları: _post, _comments, _category …
USERPREFIXÜye tabloları: _users, _usergroups, _banned …

Varsayılan kurulumda ikisi aynı değere sahiptir, ama ayrı sabitlerdir. Doğru olanı kullanmak, ön eki farklı kurulumlarda da sorunsuz çalışmanızı sağlar.

Eklenti tablonuzu oluşturmak

Tabloyu manifestin mysqlinstall bloğunda oluşturun. SQL içinde PREFIX kullanılmaz; onun yerine servis etiketi {prefix} yazılır:

<mysqlinstall><![CDATA[
CREATE TABLE IF NOT EXISTS `{prefix}_benim_kutum` (
  `id`     INT(11)      NOT NULL AUTO_INCREMENT,
  `baslik` VARCHAR(255) NOT NULL DEFAULT '',
  `sira`   INT(11)      NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `sira` (`sira`)
) ENGINE={engine} DEFAULT CHARSET={charset};
]]></mysqlinstall>

<mysqlupgrade><![CDATA[
-- Güncellemede SADECE tekrar çalıştırılabilir (idempotent) SQL yazın.
-- MySQL'de "ADD COLUMN IF NOT EXISTS" YOKTUR!
-- Kolon ekleme işini phpupgrade bloğuna bırakın (aşağıda).
CREATE TABLE IF NOT EXISTS `{prefix}_benim_kutum_log` (
  `id`     INT(11) NOT NULL AUTO_INCREMENT,
  `mesaj`  TEXT    NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE={engine} DEFAULT CHARSET={charset};
]]></mysqlupgrade>

<phpupgrade><![CDATA[
// Var olan tabloya kolon ekleme: önce var mı diye bak, yoksa ekle.
// (MySQL'de IF NOT EXISTS desteği olmadığı için tekrar çalıştırma güvenliği böyle sağlanır.)
$col = $db->super_query("SHOW COLUMNS FROM " . PREFIX . "_benim_kutum LIKE 'aktif'", false, false);

if (!$col) {
    $db->query("ALTER TABLE " . PREFIX . "_benim_kutum ADD `aktif` TINYINT(1) NOT NULL DEFAULT '1'");
}
]]></phpupgrade>

<mysqldelete><![CDATA[
DROP TABLE IF EXISTS `{prefix}_benim_kutum`;
DROP TABLE IF EXISTS `{prefix}_benim_kutum_log`;
]]></mysqldelete>
Servis etiketiYerine geçen
{prefix}PREFIX sabiti
{userprefix}USERPREFIX sabiti
{charset}COLLATE — temiz kurulumda utf8mb4
{engine}InnoDB
✓
Tablo adınızı mutlaka ön ekli yapın {prefix}_benim_kutum gibi. Ön eksiz bir tablo adı (benim_kutum) başka eklentilerle çakışır ve DLE'nin yedek/geri yükleme araçlarınca bulunmaz.

Sessiz hata yakalama

query() metodunun ikinci parametresi $show_error'dır. Varsayılan true iken bir SQL hatası sayfayı öldürür. false verirseniz hata toplanır ve çalışma devam eder:

$db->query_errors_list = array();
$db->query("SELECT * FROM " . PREFIX . "_olmayan_tablo", false);

if (count($db->query_errors_list)) {
    foreach ($db->query_errors_list as $err) {
        // $err['query'] ve $err['error']
    }
}

DLE, eklenti SQL bloklarını (mysqlinstall vb.) işte bu yöntemle çalıştırır ve hataları _plugins_logs tablosuna type = 'mysql' olarak yazar. Yani kendi SQL'inizde bir hata varsa Eklentiler → Hataları göster ekranında görürsünüz.

Veritabanı kontrol listesi

  • Tüm tablo adları PREFIX (ya da USERPREFIX) ile başlıyor.
  • Manifest SQL'inde {prefix} / {engine} / {charset} kullanılmış.
  • Tablo CREATE TABLE IF NOT EXISTS ile kuruluyor.
  • mysqlupgrade bloğu da yazılmış (güncellemede mysqlinstall çalışmaz).
  • mysqldelete tabloyu düşürüyor.
  • Metin girdileri safesql(), sayısal girdiler intval() ile süzülüyor.
  • Döngü sonunda $db->free() çağrılıyor.
  • Kurulum sonrası Hataları göster ekranı temiz.

Sırada: Ek Alanlar (xfields).