Orta
guvenlik/php-audit-log
İşlem Geçmişi (Audit Log)
- PHP 8
- PDO
- MySQL
- Ajax
- +2
102 inceleme 22 canlı açılış 1 beğeni
Güvenlik İleri
Sıfır bağımlılıklı, OOP mimarili bir yönetim paneli: rol tabanlı yetkilendirme, sunucu taraflı DataTables, CSRF korumalı Ajax, modal CRUD ve açık/koyu tema.
Veritabanı şeması projedeki cy_login.sql dosyasında.
PHP öğrenirken en çok takılınan yer, "çalışan kod" ile "doğru kod" arasındaki
farktır. Bu depo, klasik bir CRUD örneğini alıp gerçek bir projede olması
gereken hâline getiriyor: katmanlı mimari, rol tabanlı yetkilendirme,
oturum yönetimi ve baştan sona güvenlik.
Composer yok, framework yok, CDN yok. İndirin, cy_login.sql dosyasını içe
aktarın, çalışır. Tüm kod satır satır Türkçe açıklamalıdır; amaç kopyalamak
değil, neden öyle yazıldığını anlamaktır.
Bu depo daha önce tek dosyalık bir CRUD örneğiydi.
Yeni sürümde tam bir yönetim paneline dönüştürüldü.
Eski kurulumdan geçiş içincy_login.sqldosyasının sonundaki
"6) ESKİ SÜRÜMDEN YÜKSELTME" bölümüne bakın.
özetlenmiş saklanır, anahtar tek kullanımlıktır ve her otomatik girişte yenilenir
/login, /users (mod_rewrite kapalıysa tek ayarla eski biçime döner)safe-area desteği| Rol | E-posta | Parola |
|---|---|---|
| Yönetici | [email protected] | Admin1234 |
| Editör | [email protected] | Editor1234 |
| Üye | [email protected] | Uye12345 |
| Örnek 50 kullanıcı | [email protected] | Demo1234 |
Giriş ekranındaki demo kartlarına tıklayarak formu tek hamlede doldurabilirsiniz.
⚠️ Canlı sunucuda bu hesapları silin veya parolalarını değiştirin.
Giriş ekranındaki demo kartı bloğunu da kaldırın:
views/auth/login.phpiçindeki$demoAccountsdizisi vecy-demobloğu.
├── index.php ← TEK giriş noktası (front controller)
├── .env.example ← Ortam değişkeni şablonu
├── cy_login.sql ← Veritabanı kurulum dosyası
│
├── config/
│ └── config.php ← Tüm ayarlar tek dizide
│
├── routes/
│ └── web.php ← Rota tablosu + yetki kuralları
│
├── app/
│ ├── Core/ ← Çatı sınıfları
│ │ ├── Autoloader.php Sınıf otomatik yükleyici
│ │ ├── Env.php .env okuyucu
│ │ ├── Config.php Nokta notasyonlu ayar erişimi
│ │ ├── Database.php PDO bağlantısı (tembel tekil)
│ │ ├── Session.php Sertleştirilmiş oturum
│ │ ├── Csrf.php Sahte istek koruması
│ │ ├── Auth.php Kimlik doğrulama
│ │ ├── Middleware.php Rota öncesi kontroller
│ │ ├── Router.php İstek yönlendirme
│ │ ├── Request.php Girdi okuma ve temizleme
│ │ ├── Response.php JSON / yönlendirme / güvenlik başlıkları
│ │ ├── Validator.php Form doğrulama
│ │ ├── Uploader.php Güvenli görsel yükleme
│ │ ├── RateLimiter.php Kaba kuvvet koruması
│ │ ├── Flash.php Tek seferlik bildirimler
│ │ └── View.php Şablon motoru
│ │
│ ├── Models/
│ │ ├── User.php ← Kullanıcı varlığı (entity)
│ │ └── Role.php ← Roller ve yetki tablosu
│ │
│ ├── Repositories/
│ │ ├── UserRepository.php ← users tablosunun TEK kapısı
│ │ ├── RememberTokenRepository.php ← "Beni hatırla" anahtarları
│ │ └── ActivityRepository.php ← İşlem günlüğü
│ │
│ ├── Http/
│ │ ├── Controller.php
│ │ └── Controllers/
│ │ ├── HomeController.php ← Herkese açık tanıtım
│ │ ├── AuthController.php
│ │ ├── DashboardController.php
│ │ ├── UserController.php
│ │ ├── RoleController.php ← Roller ve yetkiler
│ │ ├── ProfileController.php
│ │ ├── SettingsController.php
│ │ └── Api/
│ │ ├── UserApiController.php ← AJAX CRUD
│ │ └── PreferenceApiController.php ← Tema tercihi
│ │
│ └── Support/helpers.php ← e(), url(), can(), icon() …
│
├── views/
│ ├── layouts/ ← admin · auth · public · plain
│ ├── partials/ ← sidebar · topbar
│ ├── home/ auth/ dashboard/ users/ roles/ profile/ settings/ errors/
│
├── assets/
│ ├── css/ cilginyazilim.css (tasarım kalıbı) · admin.css (panel)
│ └── js/ app.js (kabuk) · users.js (CRUD) · login.js
│
├── docs/screenshots/ ← README'deki ekran görüntüleri
└── upload/ ← Yüklenen görseller (PHP çalıştırma kapalı)
Tarayıcı
│
▼
index.php ────────── Autoloader · .env · Config · Session · Güvenlik başlıkları
│
▼
routes/web.php ───── Rota eşleştirme
│
▼
Middleware ───────── auth · csrf · can:users.delete (başarısızsa DURUR)
│
▼
Controller ───────── Girdiyi al · doğrula · yetkiyi kontrol et
│
▼
Repository ───────── Prepared statement ile veritabanı
│
▼
View / JSON ──────── Ekrana bas veya AJAX yanıtı döndür
| Katman | Sorumluluk | İçinde ne olmaz? |
|---|---|---|
| Controller | Akışı yönetir | SQL, HTML |
| Repository | Veritabanı erişimi | Yetki kararı, HTML |
| Model | Veri + davranış | SQL |
| View | Ekrana basma | İş mantığı, sorgu |
Tüm SQL'in tek dosyada olması, güvenlik denetimini de tek dosyaya indirir.
Varsayılan temiz adrestir; kökteki .htaccess bununla birlikte gelir:
/login
/users
/api/users/listmod_rewrite yoksa .env içinde APP_PRETTY_URLS=false yapın:
index.php?r=users
index.php?r=api/users/listurl() yardımcısıyla ve mutlak üretilir (Router::basePath()),htdocs/rbac-login-system) de, alan adının kökünde.htaccessiçinde bilerekRewriteBaseyoktur. Alt klasör kurulumunda
RewriteBase /yazmak, isteği yanlışlıklahtdocskökündekiindex.php'ye
gönderir (XAMPP'ta karşılama sayfasına düşersiniz).
Yetkiler app/Models/Role.php içinde tek bir tabloda tanımlıdır.
Kodda rol adı değil yetki adı kullanılır:
Auth::can('users.delete') // ✔ doğru
Auth::user()->role === 'admin' // ✘ kırılgan
| Yetki | Yönetici | Editör | Üye |
|---|---|---|---|
| Kontrol panelini görme | ✔ | ✔ | ✔ |
| Özet istatistikler | ✔ | ✔ | — |
| Kullanıcı listesi | ✔ | ✔ | — |
| Kullanıcı ekleme | ✔ | ✔ | — |
| Kullanıcı düzenleme | ✔ | ✔ | — |
| Kullanıcı silme | ✔ | — | — |
| Rol atama | ✔ | — | — |
| Hesap aktif/pasif | ✔ | — | — |
| Kendi profili | ✔ | ✔ | ✔ |
| Sistem sayfası | ✔ | — | — |
Rol tablosunun üstünde, kazaları ve yetki yükseltmeyi önleyen kurallar vardır:
role gönderirse değer sessizce yok sayılırYeni rol eklemek için Role::ABILITIES dizisine bir satır eklemek ve
cy_login.sql içindeki ENUM değerini genişletmek yeterlidir.
| Tehdit | Önlem | Dosya |
|---|---|---|
| SQL Injection | Tüm sorgular prepared statement; sıralama sütunu beyaz listeden | UserRepository.php |
| XSS | Her çıktı e() ile kaçışlanır; JS'te .text() kullanılır | helpers.php |
| XSS (2. hat) | Content-Security-Policy; satır içi ` yok | Response.php |
| CSRF | Oturum bazlı anahtar, hash_equals ile sabit süreli karşılaştırma | Csrf.php |
| Kaba kuvvet | 5 hatalı denemede 15 dakika kilit; sayaç veritabanında | RateLimiter.php |
| Kullanıcı sayımı | Tek ve aynı hata mesajı + geçerli bir sahte bcrypt özetiyle oyalama (ölçüldü: her iki yol da ~115 ms) | Auth.php |
| Kalıcı oturum çalınması | "Beni hatırla" anahtarı iki parçalıdır; sır veritabanında SHA-256 özeti olarak durur, anahtar tek kullanımlıktır ve her girişte döner | RememberTokenRepository.php |
| Parola değişiminde artık oturum | Parola değişince kullanıcının tüm cihazlarındaki kalıcı anahtarlar iptal edilir | ProfileController.php |
| Session fixation | Girişte ve periyodik olarak oturum kimliği yenilenir | Session.php |
| Session hijacking | httponly + samesite + secure çerez, tarayıcı parmak izi | Session.php |
| Yetki yükseltme | Rol/durum alanları yetki olmadan okunmaz; güncellemede beyaz liste | UserApiController.php |
| IDOR | Profil güncellemede ID formdan değil oturumdan alınır | ProfileController.php |
| Mass assignment | UserRepository::update() yalnızca izinli sütunları yazar | UserRepository.php |
| Kötü amaçlı dosya | İçerik doğrulaması (getimagesize), uzantıyı sunucu belirler, görsel yeniden üretilir | Uploader.php |
| Path traversal | basename() + realpath() ile klasör dışına çıkış engeli | Uploader.php |
| Parola saklama | password_hash() / bcrypt, girişte otomatik needs_rehash | User.php |
| Bilgi sızıntısı | Canlıda hata detayı gizlenir, X-Powered-By kaldırılır | index.php |
| Clickjacking | X-Frame-Options: DENY, frame-ancestors 'none' | Response.php |
| Kod dosyasına erişim | app/, config/, views/, routes/ için .htaccess engeli | .htaccess` |
Sistem sayfası (yalnızca yönetici) bu önlemlerin kurulumunuzda aktif olup
olmadığını canlı olarak denetler.
Üç adım:
1 — Denetleyiciyi yazın · app/Http/Controllers/ReportController.php
namespace App\Http\Controllers;
use App\Core\Request;
use App\Http\Controller;
final class ReportController extends Controller
{
public function index(Request $request): void
{
$this->view('reports/index', [
'title' => 'Raporlar',
'total' => $this->users()->countAll(),
]);
}
}routes/web.php
$router->get('reports', ReportController::class, 'index', ['auth', 'can:reports.view']);views/reports/index.php
<div class="cy-card">
<div class="cy-card__body">Toplam kullanıcı: <?= (int) $total ?></div>
</div>views/partials/sidebar.php içindeki $menu dizisineapp/Models/Role.php içine'reports.view' eklemeniz yeterlidir.
.env içinde APP_DEBUG=falseviews/auth/login.php içindeki demo kartı bloğunu kaldırınsecure olur).env, app/, config/, views/, routes/ tarayıcıdan erişilemez olsunupload/ klasöründe PHP çalıştırma kapalı olsunerror_log) bir dosyaya yönlendirin.htaccess dosyaları yok sayılır. Sunucu bloğunuza ekleyin:
location ~ ^/(app|config|views|routes)/ { deny all; return 404; }
location ~ /\. { deny all; return 404; }
location ~ \.(sql|md|log|ini|bak)$ { deny all; return 404; }
location ^~ /upload/ { location ~ \.php$ { deny all; } }
"Veritabanına bağlanılamadı" hatası
.env dosyanızdaki DB_USER / DB_PASS değerlerini kontrol edin.
XAMPP varsayılanı root ve boş paroladır. MySQL servisinin çalıştığından
emin olun.
Giriş yapıyorum ama sürekli giriş ekranına dönüyorum
Oturum klasörü yazılabilir değildir. php.ini içindeki session.save_path
değerini kontrol edin. Ayrıca tarayıcı çerezlerinin açık olduğundan emin olun.
"Çok fazla hatalı deneme" — kendimi kilitledim
DELETE FROM login_attempts;Görsel yükleniyor ama görünmüyor
upload/ klasörünün yazma izni olmalıdır (755). Ayrıca php.ini içindeki
upload_max_filesize ve post_max_size değerleri en az 2 MB olmalıdır.
Türkçe karakterler bozuk görünüyor
Veritabanı ve tablolar utf8mb4_unicode_ci olmalıdır. cy_login.sql bunu
zaten ayarlar; eski bir tabloyu dönüştürmek için:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Sayfa stilsiz görünüyor / JS çalışmıyor
Tarayıcı konsolunu açın. Content-Security-Policy hatası görüyorsanız
kendi eklediğiniz satır içi bir `` veya dış CDN bağlantısı olabilir.
Tüm JavaScript ayrı dosyada olmalıdır. Geçici olarak config/config.php
içinden security.csp_enabled değerini false yapabilirsiniz.
Görseller küçültülmüyor
PHP'nin gd eklentisi kurulu değildir. Zorunlu değildir; eklenti yoksa
görsel olduğu gibi kaydedilir, diğer güvenlik kontrolleri yine çalışır.
XAMPP'ta php.ini içinde extension=gd satırını açın.
Katkılara açığız. Depoyu çatallayın (fork), bir dal açın, değişikliğinizi
gönderin. Kod yazarken mevcut üslubu koruyun: **Türkçe açıklamalar,
declare(strict_types=1), katman ayrımına saygı.**
MIT Lisansı — dilediğiniz gibi indirip kullanabilir, değiştirebilir,
ticari projelerinizde kullanabilirsiniz.
cilginyazilim.com ile geliştirildi
Faydalı bulduysanız ⭐ vermeyi unutmayın.
İncelemek istediğiniz dosyayı ağaçtan seçin.
Güvenlik gereği kaynak dosyalardaki parola, API anahtarı ve benzeri gizli değerler gösterilmeden önce maskelenir (••••••••).
Yetkinin kullanıcıya değil role bağlandığı modeldir: kullanıcı bir role atanır, rol bir yetki kümesine sahiptir. Yeni bir kullanıcı eklendiğinde tek tek yetki vermek yerine rol seçilir; bir yetki değiştiğinde o roldeki herkes için aynı anda değişir. Bu panelde roller ve yetkiler tek bir tabloda tutulur ve hangi rolün neyi yapabildiği tek ekrandan görülür.
Hayır. Arayüzde bir bağlantıyı gizlemek yalnızca görsel bir kolaylıktır; adresi bilen biri doğrudan istek gönderebilir. Bu yüzden yetki kontrolü her istekte sunucu tarafında yapılır ve yetkisiz istek arayüzden bağımsız olarak reddedilir. Menü gizleme, o kontrolün yerine değil üstüne konur.
Hayır. Proje sıfır bağımlılıkla çalışır: Composer, framework ve CDN kullanılmaz, tüm kütüphaneler proje içindedir. İndirip cy_login.sql dosyasını içe aktarmanız ve veritabanı bilgilerini yazmanız yeterlidir. Paylaşımlı hostinglerde de ek kurulum gerektirmez.
Parolalar hiçbir zaman düz metin olarak tutulmaz; PHP'nin password_hash fonksiyonuyla hashlenir ve doğrulama password_verify ile yapılır. Ayrıca ard arda başarısız giriş denemelerine karşı kaba kuvvet koruması ve sertleştirilmiş oturum ayarları vardır.
README'deki "Yeni sayfa nasıl eklenir?" bölümü adım adım anlatır: rota tanımlanır, denetleyici metodu yazılır, görünüm dosyası eklenir ve sayfanın gerektirdiği yetki rol tablosuna işlenir. Yetki tanımlanmadığı sürece sayfa hiçbir rolde görünmez — varsayılan davranış reddetmektir.
Bu örneğin daha gelişmişi projenizde mi lazım?
İhtiyacınızı anlatın; bu yapıyı sizin sisteminize uyarlayalım ya da size özel geliştirelim.
Henüz yorum yok. Takıldığınız bir yer varsa ilk soruyu siz sorun.
Yorumunuz onaylandıktan sonra yayınlanır. Teknik sorularınıza ekibimiz yanıt verir.
Orta
guvenlik/php-audit-log
102 inceleme 22 canlı açılış 1 beğeni
İleri
guvenlik/guvenli-dosya-yukleme
92 inceleme 50 canlı açılış 1 beğeni
İleri
guvenlik/php-rest-api-jwt
74 inceleme 23 canlı açılış 1 beğeni