# Sistem Sayfaları

https://dev.wisecp.com/tr/sistem-sayfalari

Bazı sayfalar uygulama bozukken, isteği reddederken ya da kapalıyken görünmek zorundadır. Bunların tam ikisi hâlâ sizin temanızdan gelebilir.

## Genel Bakış

Bulunamayan sayfa ve kapalı site sıradan durumlardır; ekranda sizin tasarımınız olmalıdır. Ölümcül bir hata ya da engellenmiş adres öyle değil: sayfaları üreten şeyin kendisi arızalı olabilir, o ekranlar kendi kabuklarını taşır.

Temanız `404` ve `maintenance` ekranlarına sahiptir. İkincisi yazacağınız diğer her view'dan farklı: sayfa gövdesi değil, tam bir belge.

## Yapı

| Ekran | Nereden gelir | Ne zaman görünür |
| --- | --- | --- |
| Bulunamadı | Temanız, `views/404` | Eşleşmeyen her adres ve düşen her view kapısı |
| Bakım | Temanız, `views/maintenance` | Bakım modunda her adres; bir yönetici tanınmadıysa |
| Bakım yedeği | Çekirdek, `templates/system/maintenance.php` | Yalnız aktif tema bakım view'ı taşımıyorsa |
| Uygulama hatası | Çekirdek, `templates/system/application-error.php` | AJAX olmayan bir istekte ölümcül hata, HTTP 500 ile cevaplanır |
| Engellenen adres | Çekirdek, `templates/system/blocked-ip.php` | Adres engelleyici isteği yönlendirmeden önce reddetti |

Üç çekirdek sayfası tek bir kabuk paylaşır; bir stil düzeltmesi üçüne birden iner. Her sayfa kabuğun yardımcılarını kullanır, başka hiçbir şeyi değil.

- **templates/system/inc/shell.php**: Her sayfa onu require eder ve aşağıdaki yardımcı haritasını alır.
- **lang, dir**: Kök eleman için. Buraya sabit bir dil kodu yazmayın.
- **e, l**: Kaçış fonksiyonu ve çevirici; çevirici verdiğiniz düz metne düşer.
- **head, mark, brand**: Head bağlantıları, şekle göre gömülü bir ikon ve ürün imzası.
- **mask**: Yönetici dizinini değiştirir. Yazdığınız her metin buradan geçer.

## Adım Adım

### Bulunamadı Sayfasını Kurun

1. Varsayılan layout'u genişletin: bu sayfa normal istek yolundan gelir.
2. İki çıkış yolunu anahtarlarının arkasında sunun: açıksa bilgi bankası, talep sistemine göre destek ya da iletişim formu.
3. Bulunamayan adresi hiç yazmayın; saldırganın verdiği bir metindir.
4. Düşen her view kapısı da buraya iner — yarım kurulmuş bir temanın gösterdiği şey budur.

### Bakım Belgesini Kurun

Layout genişletmeyen tek view budur. Bakım anahtarını açın, yoksa sayfayı göremezsiniz.

1. Kendi doctype'ınız, kök elemanınız ve head'inizle açın; dili ve yönü şablon değişkenlerinden alın.
2. İlk boyama guard'ınızı son yedek değeri dahil birebir kopyalayın.
3. Deri token'larınızı tema ayarlarından yazın.
4. Yalnız logoyu, mesajı ve dil değiştiriciyi koyun — gezinme, sepet ya da hesap menüsü yok.
5. Dört enjeksiyon noktasını koruyun ki bir modül kapalı siteye hâlâ ulaşabilsin.

### Çekirdek Sayfalarına Doğru Dokunun

1. Paylaşılan kabuğu require edin ve yardımcılarını kullanın; stil bloğunu asla kopyalamayın.
2. Metni locale dosyalarından alın: PHP'deki İngilizce dizeler yalnızca çevirici yedekleridir.

## Referans

### Kabuk Yardımcıları

```php
$sys = require __DIR__ . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR . 'shell.php';

// Değerler
$sys['lang'];                       // dil paketinden 'en', 'tr', ...
$sys['dir'];                        // 'ltr' ya da 'rtl'
$sys['app'];                        // sistemin taban adresi

// Çağrılabilirler
$sys['e']($text);                   // htmlspecialchars, tırnaklar dahil, UTF-8
$sys['l']($file, $key, $fallback);  // system/{file}/{key} ya da erişilemezse $fallback
$sys['head']();                     // yerel yazı tipi bağlantısı + paylaşılan stil
$sys['mark']($shape);               // gömülü ikon: 'alert', 'shield' ya da 'tools'
$sys['brand']();                    // ürün imzası + sürüm dosyası
$sys['mask']($text);                // yönetici dizini yer tutucuyla değiştirilir

// Tipik kullanım, sayfa başına locale dosyası bir kez bağlanır:
$e = $sys['e'];
$L = static fn (string $k, string $fallback): string => $sys['l']('error', $k, $fallback);
```

### Hata Sayfası Neyi Gösterebilir

| Durum | Mesaj | Teknik blok |
| --- | --- | --- |
| Motor hatası: tip ya da ayrıştırma arızası | Genel: özgün metin geliştirici için yazılmıştır | Yalnız geliştirmede |
| Bilerek fırlatılan bir istisna | Gösterilir: operatörün okuması gerekir | Yalnız geliştirmede |
| Kapanışta yakalanan ölümcül hata, sınıf bilinmiyor | Genel; motor hatası sayılır | Yalnız geliştirmede |
| Hatalı satırın çevresindeki kaynak parçası | Geçerli değil | Yalnız geliştirmede; okunur, okunamaz ya da şifreli ve çok büyük durumları karşılanır |
| İstek verisi | Geçerli değil | Yalnız geliştirmede, parola ve jetonlar önce temizlenir |

### Tema Tarafı Sözleşmesi

```php
// Manifest yüklendiyse VE tema dizini gerçekten oradaysa true.
public function exists(): bool;

// views/<view>.<uzantı> gerçek bir dosyaysa true. Uzantı manifest motorunu izler.
public function viewExists(string $view): bool;

// Bir sistem yüzeyini istek dışında render etmek (CLI sağlık kontrolü, bir probe):
// chose("website") temayı atlar, bu yüzden temayı doğrudan çağırın.
public function render(string $view, array $data = []): string;
```

- **bakım kapısı**: Controller ikisini *de* sorar, sonra çekirdek şablonuna düşer. İkinci denetim olmadan çağrı boş string döner: boş sayfa.
- **ui:client.maintenance.body**: Sayfa kurulduktan sonra kapanış body etiketinden önce eklenir; hem tema view'ına hem çekirdek yedeğine ulaşır. Eklemek istediğiniz HTML'i döndürün, dizeler birleştirilir.
- **views/404**: Kendi dört değişkeni: `$page_title`, `$meta_robots` ve çıkış yollarını seçen `$support_enabled` ile `$kbase_enabled`. Tam müşteri veri paketi burada *hazırlanır*.

### Bakım View'ına Ne Ulaşır

Liste bundan ibaret. Tam müşteri veri paketi hazırlanmaz: menü, sepet, duyurular ve hesap değişkenleri eksiktir; birini okuyan view hiçbir şey göstermez ve log'a uyarı yazar.

- **$ui_lang, $ui_dir**: Kök elemanınız için dil kodu ve `ltr` ya da `rtl`. Bunları şablon motoru her view'a ekler, veri paketi olmayan sayfada da var olurlar.
- **$light_logo_link, $dark_logo_link, $company_name**: İki logo varyantı ve operatörün adı. İkisini de yazıp seçimi stil dosyanıza bırakın; sunucu tarafında tema algılama yok.
- **$lang_list, $lang_count, $selected_lang_key**: Her kayıt `key`, `name`, `link`, `selected` ve `flag-img` taşır. Kontrolü yalnız sayı birden büyükken gösterin.
- **$current_year, $setting**: Telif satırı için yıl ve temanızın ayarları. `$setting` temalı her view'a ulaşır, kapalı site de operatörün renklerini korur.

## Örnek

```smarty
<!DOCTYPE html>
{* layouts/default.tpl DEĞİL: site kapalıdır, yani hiçbir gezinme, sepet ya da
   hesap kabuğu oraya geri bağlanamaz. Dil değiştirici tek kontroldür ve BU
   sayfayı seçilen dilde yeniden render eder. *}
<html lang="{$ui_lang|default:'en'}" dir="{$ui_dir|default:'ltr'}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="robots" content="noindex, nofollow">
    <title>{lang key='system/maintenance/meta'}</title>

    {* Guard'ı ana layout'tan BİREBİR kopyalayın. Son yedek değeri tema script'inin
       değeriyle eşleşmelidir; yoksa sayfa bir modda boyanır ve bir kare sonra
       diğerine döner. Hata yalnız hiç kayıtlı değeri olmayan ziyaretçide görünür;
       geliştiricinin kendi tarayıcısının onu hiç üretememesinin sebebi budur. *}
    <script>
      var t = localStorage.getItem('wstyle-theme') || 'light';
      document.documentElement.setAttribute('data-bs-theme', t);
    </script>

    <link rel="stylesheet" href="{asset path='css/theme.css'}">
    <link rel="stylesheet" href="{asset path='css/maintenance.css'}">

    {* Kapalı sitede de operatörün renkleri geçerlidir. *}
    <style>:root { --brand: {$setting.primary_color}; }</style>

    {hook name='ui:client.head.css'}
    {hook name='ui:client.head.js'}
</head>
<body class="maintenance-page">
{hook name='ui:client.body.begin'}

<header>
    <a href="{link route='home'}"><span>{$company_name}</span></a>

    {* Sayfadaki TEK kontrol. *}
    {if $lang_count > 1}
      {foreach $lang_list as $l}
        <a href="{$l.link}">{$l.name}</a>
      {/foreach}
    {/if}
</header>

<main id="maintenance-content">
    <p>{lang key='system/maintenance/text'}</p>
</main>

{hook name='ui:client.body.end'}
</body>
</html>
```

```php
public function main(): void
{
    // Bilerek asgari: kapalı bir sayfanın menüye, sepete ya da duyuruya ihtiyacı yok.
    $this->takeDatas(["language", "website_logos", "company_name", "lang_list"]);
    $this->addData("current_year", date("Y"));

    // İKİ denetim de gerekli. viewExists olmadan, bakım view'ı taşımayan bir tema
    // düz PHP yoluna düşer, hiçbir dosya bulamaz ve boş string döner: hiçbir yerde
    // hata olmadan boş bir sayfa.
    $theme = \Theme::active();
    if ($theme->exists() && $theme->viewExists("maintenance"))
        $html = $this->view->chose("website")->render("maintenance", $this->data, true);
    else
        $html = $this->view->chose("system")->render("maintenance", $this->data, true);

    // Render sonrası enjekte edilir, böylece hem tema view'ına hem yedeğe ulaşır.
    $injection = implode('', \Hook::run('ui:client.maintenance.body', $this->data));
    if ($injection) $html = preg_replace('/<\/body>/i', $injection . '</body>', $html, 1);

    echo $html;
}
```

## Tuzaklar

> **İlk boyama guard'ı tema script'iyle eşleşmeli**
> 
> İkisi de aynı kayıtlı değeri okur ve aynı son yedeğe ihtiyaç duyar. Ayrıştıklarında sayfa bir modda boyanır, bir kare sonra döner; bunu yalnız hiç tercih kaydetmemiş ziyaretçi görür.

> **Yönetici dizini işaretlemeye ulaşmamalıdır**
> 
> İstek adresinde, dökülen istek verisinde ve tekrar dene butonunun hedefinde görünür; ekran görüntüsü onu da taşır. Her şeyi maskeden geçirin, tekrar dene bağlantısı boş kalsın.

> **Çekirdek sistem sayfasında dış istek olmaz**
> 
> Bu sayfalar sunucu rahatsızken görünür; içerik ağını beklemek boşa zamandır. İkonlar gömülüdür, yazı tipi sistem yedeğiyle yereldir ve hiç çerçeve yoktur.

> **Mesajı gizlemek ile ayrıntıyı gizlemek farklı**
> 
> Motor arızası geliştirici metni taşır, genel bir cümleyle değişir. Bilerek fırlatılan istisna ise gösterilir: operatörün onu okuması gerekir.

> **Sistem sayfasında hiçbir şey katlanmaz**
> 
> Her bölüm açık gelir: okuyan kişi sorunu burada çözer. Gövdeyi otomatik kenar boşluklarıyla ortalayın; ortalama hizalaması içerik uzayınca üst kenarı kırpar.

## İlgili Makaleler

- [Sayfa Ekranları](https://dev.wisecp.com/tr/sayfa-yuzeyleri)
- [Tema Varlıkları](https://dev.wisecp.com/tr/tema-varliklari)
- [Hata Yönetimi](https://dev.wisecp.com/tr/hata-yonetimi)
- [Tema Kancaları ve Çıktı Filtreleri](https://dev.wisecp.com/tr/tema-kancalari-ve-cikti-filtreleri)
- [Hata Ayıklama ve Loglar](https://dev.wisecp.com/tr/hata-ayiklama-ve-loglar)
