# MutlakCMS — Belgeler · [sürüm geçmişi](https://mutlaksoft.com/surum-gecmisi.md) Kurulu sürümünüzü öğrenmek için: `php mutlak.php bilgi` Bağımlılıksız, Türkçe bir içerik yönetim sistemi. PHP 8.2+ ile yazıldı; Composer, npm ya da derleme adımı gerektirmez. Bu belgenin güncel hâli: --- ## İçindekiler 1. [Hızlı kurulum (otomasyon / ajan için)](#1-hızlı-kurulum-otomasyon--ajan-için) 2. [Gereksinimler](#2-gereksinimler) 3. [Kurulum](#3-kurulum) 4. [Komut satırı aracı](#4-komut-satırı-aracı) 5. [Klasör yapısı](#5-klasör-yapısı) 6. [Yapılandırma](#6-yapılandırma) 7. [Zamanlanmış görev (cron)](#7-zamanlanmış-görev-cron) 8. [Güncelleme](#8-güncelleme) 9. [Tema geliştirme](#9-tema-geliştirme) 10. [Eklenti geliştirme](#10-eklenti-geliştirme) 11. [Kanca listesi](#11-kanca-listesi) 12. [Veritabanı şeması](#12-veritabanı-şeması) 13. [Güvenlik](#13-güvenlik) 14. [Sorun giderme](#14-sorun-giderme) --- ## 1. Hızlı kurulum (otomasyon / ajan için) Sıfırdan çalışır bir siteye giden en kısa yol. Tarayıcı gerekmez. ```bash # 1) Paketi indir ve aç cd /var/www/siteniz curl -fsSLO https://mutlaksoft.com/indir/mutlakcms-son.zip unzip -q mutlakcms-son.zip mv mutlakcms/* mutlakcms/.[!.]* . && rmdir mutlakcms && rm mutlakcms-son.zip # 2) Sunucuyu denetle (0 = uygun) php mutlak.php kontrol # 3) Kur php mutlak.php kur \ --db-ad=veritabani_adi \ --db-kullanici=kullanici \ --db-sifre='sifre' \ --site-adi="Site Adı" \ --site-url="https://siteniz.com" \ --yonetici-ad="Ad Soyad" \ --yonetici-eposta=admin@siteniz.com \ --yonetici-sifre='Guclu2026Sifre' \ --ornek-icerik # 4) Tema kur ve etkinleştir (isteğe bağlı) php mutlak.php tema:yukle https://mutlaksoft.com/indir/tema-tez-danismanlik-1.0.0.zip --etkinlestir # 5) Durumu doğrula php mutlak.php bilgi ``` `kur` komutu başarılı olursa `install.php` dosyasını kendisi siler ve cron satırını çıktı olarak verir. Çıkış kodu 0 = başarılı, 1 = hata. **Makine okunur çıktı** için her komuta `--json` ekleyin: ```bash php mutlak.php kontrol --json # {"ok":true,"kontroller":[...],"engeller":[]} php mutlak.php kur --json ... # {"ok":true,"panel":"...","cron":"..."} php mutlak.php bilgi --json # {"ok":true,"bilgi":{...}} ``` **Dosya sahipliği:** dosyaları web sunucusunun kullanıcısına verin, yoksa yükleme ve güncelleme çalışmaz: ```bash chown -R www-data:www-data /var/www/siteniz # Debian/Ubuntu find /var/www/siteniz -type d -exec chmod 755 {} \; find /var/www/siteniz -type f -exec chmod 644 {} \; chmod 640 /var/www/siteniz/config/config.php ``` --- ## 2. Gereksinimler | | En az | Not | |---|---|---| | PHP | 8.2 | 8.3 / 8.4 de desteklenir | | MySQL | 5.7 | ya da MariaDB 10.3+ | | Web sunucusu | Apache `mod_rewrite` | nginx için aşağıya bakın | **Zorunlu PHP eklentileri:** `pdo_mysql`, `mbstring`, `json`, `openssl` **Önerilen:** `zip` (güncelleme ve paket kurulumu), `gd` (görsel küçültme), `curl` (güncelleme merkezi), `fileinfo` (yükleme güvenliği) `php mutlak.php kontrol` hepsini tek seferde denetler. ### nginx kullanıyorsanız Paketle gelen `.htaccess` yalnızca Apache'de çalışır. nginx için sunucu bloğuna şunu ekleyin: ```nginx location / { try_files $uri $uri/ /index.php?$query_string; } location ~ ^/(config|storage|core)/ { deny all; return 404; } location ~ ^/content/uploads/.*\.(php|phtml|phar|pl|py|cgi|sh)$ { deny all; return 404; } location ~ /\. { deny all; } ``` --- ## 3. Kurulum ### Komut satırından (önerilen) Yukarıdaki [hızlı kurulum](#1-hızlı-kurulum-otomasyon--ajan-için) bölümüne bakın. ### Tarayıcıdan 1. Boş bir MySQL/MariaDB veritabanı ve kullanıcı oluşturun. 2. Paket içeriğini sitenizin kök dizinine yükleyin. 3. `https://siteniz.com/install.php` adresine gidin. 4. Dört adımı tamamlayın. 5. **`install.php` dosyasını silin.** Her iki yol da aynı kodu (`Mutlak\Setup\Installer`) çalıştırır; sonuç birebir aynıdır. ### Alt dizine kurulum `https://siteniz.com/blog` gibi bir alt dizine kurabilirsiniz; taban adres otomatik tespit edilir. Apache'de yeniden yazma sorun çıkarırsa `.htaccess` içindeki `RewriteBase` satırını açın: ```apache RewriteBase /blog/ ``` --- ## 4. Komut satırı aracı ``` php mutlak.php [argümanlar] [--bayraklar] ``` | Komut | Açıklama | |---|---| | `kontrol` | Sunucu gereksinimlerini denetler | | `kur` | Kurulumu yapar | | `bilgi` | Sürüm, veritabanı, tema, eklenti ve içerik özeti | | `tema:liste` | Kurulu temaları listeler | | `tema:yukle ` | Tema kurar. `--etkinlestir` ile hemen etkinleştirir | | `tema:etkinlestir ` | Temayı etkinleştirir | | `eklenti:liste` | Kurulu eklentileri listeler | | `eklenti:yukle ` | Eklenti kurar. `--etkinlestir` destekler | | `eklenti:etkinlestir ` | Eklentiyi etkinleştirir | | `eklenti:pasiflestir ` | Eklentiyi pasife alır | | `guncelle:kontrol` | Yeni sürüm var mı diye merkeze sorar | | `guncelle:uygula` | Güncellemeyi indirir, doğrular ve uygular | | `guncelle:gecmis` | Güncelleme geçmişi | | `ayar:oku ` | Ayar değerini yazdırır | | `ayar:yaz ` | Ayar değerini kaydeder | | `kullanici:liste` | Kullanıcıları listeler | | `kullanici:sifre <şifre>` | Şifre değiştirir | | `bakim:ac` / `bakim:kapat` | Bakım modu | | `onbellek:temizle` | Önbelleği boşaltır | ### `kur` seçenekleri | Bayrak | Varsayılan | | |---|---|---| | `--db-sunucu` | `localhost` | | | `--db-port` | `3306` | | | `--db-ad` | — | **zorunlu** | | `--db-kullanici` | — | **zorunlu** | | `--db-sifre` | boş | | | `--db-onek` | `mtl_` | Aynı veritabanında birden fazla kurulum için değiştirin | | `--site-adi` | — | **zorunlu** | | `--site-slogan` | boş | | | `--site-url` | — | **zorunlu**, `https://` ile başlamalı | | `--yonetici-ad` | `Yönetici` | | | `--yonetici-eposta` | — | **zorunlu** | | `--yonetici-sifre` | — | **zorunlu**, en az 8 karakter + büyük/küçük harf + rakam | | `--panel-yolu` | `yonetim` | Panel adresi | | `--hub` | `https://mutlaksoft.com` | Güncelleme merkezi | | `--zaman-dilimi` | `Europe/Istanbul` | | | `--ornek-icerik` | kapalı | Örnek yazı, sayfa ve menü | | `--otomatik-guncelleme` | kapalı | Tüm güncellemeleri otomatik uygula | | `--force` | kapalı | Dolu veritabanının üzerine yaz | --- ## 5. Klasör yapısı ``` ├── index.php ön denetleyici ├── mutlak.php komut satırı aracı ├── install.php kurulum sihirbazı (kurulumdan sonra silin) ├── guncelle.php cron / görev çalıştırıcı ├── htaccess.dist örnek Apache yapılandırması ├── core/ ÇEKİRDEK — güncellemede DEĞİŞİR, elle düzenlemeyin ├── assets/ panel CSS/JS — güncellemede DEĞİŞİR ├── config/ yapılandırma — güncellemede korunur ├── content/ │ ├── themes/ temalar — korunur │ ├── plugins/ eklentiler — korunur │ ├── uploads/ yüklenen dosyalar — korunur │ └── languages/ └── storage/ önbellek, günlük, yedek, geçici — korunur ``` **Güncelleme, pakette ne varsa onu tazeler; şu yollara asla dokunmaz:** `config/`, `content/`, `storage/`, `.htaccess`, `.user.ini`, `php.ini`, `robots.txt`, `favicon.ico`, `.well-known/`. `install.php` de güncellemede bilerek atlanır — silinmiş bir kurulum sihirbazı güncellemeyle geri gelmemeli. Yani yapılandırmanız, temalarınız, eklentileriniz ve yüklediğiniz dosyalar sizindir; sürüm atladığınızda hiçbiri etkilenmez. --- ## 6. Yapılandırma `config/config.php` bir PHP dizisi döndürür. Buradaki değerler `core/config-defaults.php` içindeki varsayılanların üzerine yazılır; yeni bir sürümde eklenen ayar anahtarı eski `config.php` dosyanızı bozmaz. ```php return [ 'app' => [ 'name' => 'Site Adı', 'url' => 'https://siteniz.com', // boş ise istekten tespit edilir 'debug' => false, // YAYINDA MUTLAKA false 'timezone' => 'Europe/Istanbul', 'key' => '…', // cron anahtarı; değiştirmeyin ], 'db' => [ 'host' => 'localhost', 'port' => 3306, 'name' => '…', 'user' => '…', 'pass' => '…', 'prefix' => 'mtl_', 'socket' => '', // unix soketi kullanılacaksa ], 'security' => [ 'admin_path' => 'yonetim', // panel adresi 'force_https' => true, 'login_throttle' => 5, // hatalı giriş sınırı 'login_lockout' => 900, // kilit süresi (saniye) ], 'update' => [ 'hub' => 'https://mutlaksoft.com', 'channel' => 'stable', // stable | beta 'auto' => false, // tüm güncellemeleri otomatik uygula 'auto_security' => true, // güvenlik yamalarını her hâlükârda uygula 'public_key' => "-----BEGIN PUBLIC KEY-----\n…", ], 'mail' => [ 'driver' => 'smtp', // mail | smtp 'host' => '…', 'port' => 587, 'user' => '…', 'pass' => '…', 'encryption' => 'tls', // tls | ssl | '' 'from' => 'bilgi@siteniz.com', 'from_name' => 'Site Adı', ], 'media' => [ 'max_size' => 8388608, // 8 MB 'allowed' => ['jpg', 'png', 'webp', 'pdf', '…'], 'image_sizes' => [ 'kucuk' => [320, 320], 'orta' => [768, 768], 'buyuk' => [1600, 1600], ], ], ]; ``` Site adı, slogan, iletişim bilgisi gibi **içerik ayarları** dosyada değil veritabanındadır; panelden ya da `mutlak.php ayar:yaz` ile değişir. --- ## 7. Zamanlanmış görev (cron) Zamanlanmış yazıların yayına alınması, önbellek temizliği ve otomatik güncelleme bu göreve bağlıdır: ``` */15 * * * * php /site/yolu/guncelle.php --anahtar=CONFIG_ICINDEKI_APP_KEY ``` Anahtarı öğrenmek için: ```bash php -r '$c = require "config/config.php"; echo $c["app"]["key"], "\n";' ``` Sunucuda cron yoksa aynı adresi harici bir cron servisiyle çağırabilirsiniz: ``` https://siteniz.com/guncelle.php?anahtar=CONFIG_ICINDEKI_APP_KEY ``` Anahtarsız çağrılar 403 döner. --- ## 8. Güncelleme ### Nasıl çalışır 1. Site `/api/v1/surum` ucuna kurulu sürümünü sorar. 2. Dönen manifestin **RSA-SHA256 imzası** `update.public_key` ile doğrulanır. 3. ZIP indirilir, **SHA-256 özeti** manifesttekiyle karşılaştırılır. 4. Paket açılır, içindeki sürüm numarası manifestle karşılaştırılır. 5. Site bakım moduna alınır, mevcut çekirdek `storage/backups/` altına yedeklenir. 6. Dosyalar değiştirilir, veritabanı göçleri çalıştırılır. 7. Herhangi bir adım başarısız olursa **yedekten otomatik geri dönülür**. İmza ya da özet doğrulanamazsa hiçbir dosyaya dokunulmaz ve deneme `mtl_update_log` tablosuna `reddedildi` olarak yazılır. ### Elle güncelleme ```bash php mutlak.php guncelle:kontrol php mutlak.php guncelle:uygula ``` Ya da panelden **Güncelleme** bölümü. ### Kendi güncelleme merkezinizi kurmak Kurumsal kurulumlarda güncellemeleri kendi sunucunuzdan dağıtabilirsiniz: 1. Bir RSA anahtar çifti üretin: ```bash openssl genrsa -out ozel.pem 4096 openssl rsa -in ozel.pem -pubout -out acik.pem ``` **Özel anahtarı asla web kökü altına koymayın.** 2. Merkez sunucunuzda şu iki adresi yayınlayın: - `GET /api/v1/surum?surum=&build=&kanal=&php=` → imzalı manifest JSON'u - `GET /indir/.zip` → paketin kendisi (aynı alan adında olmalı) 3. Manifest şu alanları içerir ve `imza` alanı diğerlerinden üretilir: ```json { "surum": "1.1.0", "build": 100100, "kanal": "stable", "sha256": "…", "boyut": 283000, "php_min": "8.2.0", "yayin_tarihi": "2026-08-11", "guvenlik": false, "indirme": "https://merkeziniz.com/indir/mutlakcms-1.1.0.zip", "notlar": "…", "imza": "base64…" } ``` İmzalanan metin `Mutlak\Update\Signature::canonical()` çıktısıdır: `surum`, `build`, `kanal`, `sha256`, `boyut`, `php_min`, `yayin_tarihi`, `guvenlik`, `indirme` alanları `anahtar=değer` biçiminde satır satır birleştirilir. 4. Kurulu sitelerde `config/config.php` içinde `update.hub` ve `update.public_key` değerlerini kendi merkezinizle değiştirin. --- ## 9. Tema geliştirme ### En küçük tema ``` content/themes/temam/ ├── tema.json └── layout/ana.php ``` `tema.json`: ```json { "slug": "temam", "ad": "Temam", "surum": "1.0.0", "yazar": "Adınız", "cekirdek_min": "1.0.0", "menu_konumlari": { "ana": "Üst menü", "alt": "Alt menü" } } ``` ### Şablon hiyerarşisi Çekirdek şu sırayla arar; bulduğu ilkini kullanır: | Ekran | Aranan şablonlar | |---|---| | Anasayfa | `anasayfa` → `arsiv` | | Tekil yazı | `yazi-` → `yazi-kategori-` → `yazi` → `tekil` | | Sayfa | `sablonlar/` → `sayfa-` → `sayfa` → `tekil` | | Kategori | `kategori-` → `kategori` → `arsiv` | | Etiket | `etiket-` → `etiket` → `arsiv` | | Blog / yazar / arama | `blog` / `yazar` / `arama` → `arsiv` | | Hata | `hata-` → `hata` | Hiçbiri yoksa çekirdeğin yedek şablonu devreye girer; eksik bir tema siteyi düşürmez. `sablonlar/` altındaki dosyalar panelde sayfa şablonu olarak seçilebilir hâle gelir. ### Şablon yardımcıları ```php $this->extend('layout/ana'); // yerleşim seç $this->section('baslik', 'Metin'); // bölüm ata $this->section('icerik'); … $this->endSection(); $this->yield('icerik', 'varsayılan'); // bölümü bas $this->include('partials/kart', ['yazi' => $yazi]); $this->push('scripts'); … $this->endPush(); $this->stack('scripts'); $this->e($metin); // kaçışlama $this->json($dizi); //