PHP PDO Ajax CRUD Örneği
DataTables, Bootstrap 5 ve modal pencerelerle çalışan, satır satır açıklamalı bir CRUD örneği. SQL enjeksiyonu, XSS ve dosya yükleme açıkları baştan kapatılmış.
Ekran Görüntüleri 4 görsel
Bu Örnek Ne Yapıyor?
- Tam CRUD: listeleme, ekleme, düzenleme, silme ve görsel yükleme
- Sunucu taraflı DataTables ile arama, sıralama ve sayfalama
- Bootstrap 5 modalları: tek modal hem ekleme hem düzenleme için kullanılıyor
- Sorgular hazırlanmış ifadelerle (prepared statement) çalışıyor — SQL enjeksiyonu kapalı
- Çıktı kaçışlama ile XSS, içerikten tür doğrulama ile dosya yükleme açığı kapatılmış
- Görseli olmayan kayıtlar için adın baş harfinden otomatik rozet üretiliyor
- Kodun her satırı Türkçe açıklamalı; Composer, npm ve internet bağlantısı gerekmiyor
Nerede İşe Yarar?
- PHP, Ajax ve DataTables üçlüsünü sıfırdan öğrenmek
- Yeni bir projeye hazır ve güvenli bir CRUD iskeletiyle başlamak
- Müşteri, personel veya ürün listesi gibi klasik yönetim ekranları
- Var olan bir CRUD kodunu güvenlik açısından karşılaştırmak
- Bootstrap 5 üzerine kurulu, tekrar kullanılabilir bir tasarım kalıbı edinmek
Gereksinimler
- PHP 8.0+ (pdo_mysql, gd) · MySQL 5.7+ veya MariaDB 10.3+ · Apache/mod_rewrite
Nasıl Kurulur?
- Proje dosyalarını web köküne kopyalayın (örn. XAMPP'ta htdocs veya kendi web sunucunuzun kök dizini)
- crud.sql dosyasını içe aktarın — tabloyu ve örnek kayıtları oluşturur
- system klasöründeki yapılandırma dosyasında veritabanı bilgilerini düzenleyin
- upload klasörüne yazma izni verin (kayıt görselleri buraya kaydedilir)
- Uygulamayı açın; listeye bir kayıt ekleyip modal üzerinden düzenlemeyi deneyin
Veritabanı şeması projedeki crud.sql dosyasında.
Nasıl Çalışıyor?
PHP PDO MySQL Ajax CRUD
DataTables · Bootstrap 5 · Modal · Çılgın Yazılım Tasarım Kalıbı
Güvenli, açıklamalı ve indirir indirmez çalışan bir CRUD örneği.🇹🇷 Türkçe · 🇬🇧 English
Bu Proje Nedir?
PHP öğrenirken bulunan CRUD örneklerinin çoğu SQL injection, XSS ve dosya yükleme açıkları içerir. Bu proje, aynı işi doğru ve güvenli yapmanın nasıl göründüğünü göstermek için hazırlandı.
Öne çıkan yanı: kodun her satırı açıklamalı. Bir şeyin neden öyle yazıldığını, yanlış yazılsa ne olacağını yorum satırlarında bulacaksınız. PHP'ye yeni başlayan biri bile dosyaları okuyarak neyin ne işe yaradığını kavrayabilir.
Kimler için uygun?
- PHP + AJAX + DataTables üçlüsünü öğrenmek isteyenler
- Kendi projesine hazır ve güvenli bir CRUD iskeleti arayanlar
- Bootstrap 5 üzerine kurulu, tekrar kullanılabilir bir tasarım kalıbı arayanlar
Klonla, crud.sql'i içe aktar, çalıştır. Başka hiçbir kurulum adımı yok. Composer yok, npm yok, internet bağlantısı bile gerekmiyor — tüm kütüphaneler proje içinde.
İçindekiler
- Ekran Görüntüleri
- Neler Var?
- Güvenlik: Neyi, Nasıl Kapattık?
- Kurulum
- Yapılandırma
- Çılgın Yazılım Tasarım Kalıbı
- Dosya Yapısı
- Nasıl Çalışıyor?
- AJAX API Referansı
- Veritabanı Şeması
- Sık Sorulanlar
- Canlı Ortama Alırken
- Sorun Giderme
- Yol Haritası
- Katkı
- Lisans
Ekran Görüntüleri
Kayıt listesi
Gradyanlı marka başlığı, canlı arama, sıralanabilir sütunlar ve tek sütunda toplanmış işlem butonları. Görseli olmayan kayıtlar için adın baş harfinden otomatik rozet üretilir.
Detay modalı
Göz butonuna basıldığında açılır. Büyük profil görseli, kayıt bilgileri ve düzenlemeye geçiş kısayolu içerir.
Ekleme / düzenleme formu
Tek bir modal hem ekleme hem düzenleme için kullanılır. Görsel seçildiğinde canlı önizleme gösterilir, hatalar ilgili alanın altında belirir.
Sunucu taraflı sayfalama
Sayfalama, arama ve sıralama sunucuda yapılır; tarayıcıya yalnızca görüntülenen sayfa gönderilir.
Arama
Ad ve soyad üzerinde arama yapılır.recordsFiltered doğru hesaplandığı için sayfalama filtreye uyum sağlar.

Üç modal:
| Modal | Açılış | İçerik |
|---|---|---|
| 👁 Detay | Göz butonu | Büyük profil görseli, kayıt no, ad, soyad, dosya adı, tarih + "Bu Kaydı Düzenle" kısayolu |
| ✎ Ekle / Düzenle | Yeni Kayıt veya kalem butonu | Form, canlı görsel önizleme, alan bazlı hata mesajları |
| 🗑 Sil | Çöp kutusu butonu | Kimin silineceğini yazan onay ekranı |
Neler Var?
Arayüz- Marka gradyanlı başlık ve modallar
- Üç ayrı modal (detay / form / silme onayı)
- Sağ üstte toast bildirimleri
- Görsel canlı önizleme (yüklemeden önce)
- Görselsiz kayıtlar için baş harf rozeti
- Otomatik koyu tema (işletim sistemi ayarını izler)
- Mobil uyumlu, erişilebilir (ARIA etiketli)
- Tamamı Türkçe — CDN'siz, çevrimdışı çalışır
Altyapı
- Sunucu taraflı (server-side) DataTables
- Tek AJAX uç noktası,
actiontabanlı yönlendirme - Çift katmanlı doğrulama (istemci + sunucu)
- Alan bazlı hata mesajları (HTTP 422)
- Otomatik dosya temizliği (yetim dosya bırakmaz)
- Ortam değişkeni desteği
- 50 hazır örnek kayıt
- Kodun her satırı açıklamalı
Güvenlik: Neyi, Nasıl Kapattık?
İnternetteki benzer örneklerin çoğunda bulunan açıklar ve bu projede nasıl önlendikleri:
| Açık | Tipik hatalı kod | Bu projede |
|---|---|---|
| SQL Injection | "SELECT FROM users WHERE id = '".$_POST['id']."'" | Tüm sorgular prepared statement. EMULATE_PREPARES = false ile gerçek prepared statement zorunlu. Sıralama sütunu/yönü beyaz listeden geçer — order[0][column]=0;DROP TABLE users-- denemesi test edildi, etkisiz. |
| XSS | $sub_array[] = $row["name"]; | Veritabanından gelen her değer e() (htmlspecialchars) ile kaçışlanır. Toast mesajları .text() ile yazılır, .html() ile değil. |
| CSRF | (genelde hiç yok) | Oturuma bağlı 32 baytlık token. ` etiketinden okunup her AJAX isteğine eklenir, hash_equals() ile sabit zamanlı doğrulanır. Token'sız istek → HTTP 419. |
| Kötü amaçlı dosya yükleme | $ext = explode('.', $name)[1]; | Uzantıya güvenilmez: tür getimagesize() ile dosya içeriğinden tespit edilir. Yeni ad random_bytes() ile üretilir, uzantı MIME beyaz listesinden atanır. shell.php.png yükleme denemesi test edildi, reddedildi. |
| Yükleme klasöründe kod çalıştırma | (korumasız klasör)* | upload/.htaccess PHP motorunu kapatır ve çalıştırılabilir uzantılara erişimi engeller. |
| Path Traversal | unlink("../upload/".$_POST['hidden_image']) | Silinecek dosya adı istemciden değil veritabanından okunur, ayrıca basename() ile temizlenir. |
| Tip karmaşası | WHERE id = '$id' | ID'ler filter_input(..., FILTER_VALIDATE_INT) ile doğrulanır. |
| Bilgi sızıntısı | Ekrana basılan MySQL hataları | APP_DEBUG = false iken hata detayı gizlenir, error_log()'a yazılır. |
| LIKE joker karakterleri | LIKE '%$search%' | Arama terimindeki %, _, \ kaçışlanır — kullanıcı % yazınca tüm tablo dönmez. |
| Kaynak tüketimi | LIMIT $length | Sayfa boyutu 500 ile sınırlanır; length=999999` sunucuyu yormaz. |
Kurulum
Gereksinimler
- PHP 8.0+ (
pdo_mysqlvegdeklentileri) - MySQL 5.7+ veya MariaDB 10.3+
- Apache (XAMPP / WAMP / Laragon) — ya da PHP'nin yerleşik sunucusu
Adımlar
1 — Projeyi indiringit clone https://github.com/CilginYazilim/PHP-PDO-MySQL-Ajax-CRUD-DataTables-Bootstrap-5-Modals.git
cd PHP-PDO-MySQL-Ajax-CRUD-DataTables-Bootstrap-5-Modals2 — Veritabanını oluşturun
crud.sql veritabanını da kendisi oluşturur; önceden crud adında bir veritabanı açmanıza gerek yok.
mysql -u root -p < crud.sqlphpMyAdmin ile: İçe Aktar → Dosya seç →
crud.sql → Başlat
3 — Çalıştırın
php -S 127.0.0.1:8000XAMPP kullanıyorsanız projeyi
htdocs altına koymanız ve şu adresi açmanız yeterli:http://localhost/PHP-PDO-MySQL-Ajax-CRUD-DataTables-Bootstrap-5-Modals/
4 — Tarayıcıda açın → http://127.0.0.1:8000/
Karşınıza 50 örnek kayıt dolu, çalışır durumda bir tablo gelecek.
Linux/macOS kullanıcıları:upload/klasörüne yazma izni gerekir →chmod 755 upload
Yapılandırma
Tüm ayarlar system/config.php içinde, açıklamalarıyla birlikte:| Sabit | Varsayılan | Açıklama |
|---|---|---|
DB_HOST | 127.0.0.1 | Veritabanı sunucusu |
DB_NAME | crud | Veritabanı adı |
DB_USER | root | Kullanıcı adı |
DB_PASS | (boş) | Parola |
UPLOAD_MAX_BYTES | 2 MB | Maksimum görsel boyutu |
ALLOWED_IMAGE_TYPES | jpg, png, gif, webp | İzin verilen MIME türleri |
NAME_MIN_LENGTH / NAME_MAX_LENGTH | 2 / 150 | Ad-soyad uzunluk sınırları |
APP_DEBUG | true | Canlıda false yapın |
Şifreyi koda yazmayın
TümDB_* sabitleri ortam değişkeniyle geçersiz kılınabilir. Böylece şifreniz GitHub'a düşmez:
# Linux / macOS
export DB_HOST=localhost DB_USER=uygulama DB_PASS='guclu-sifre'
# Windows (PowerShell)
$env:DB_USER = "uygulama"; $env:DB_PASS = "guclu-sifre"Apache için
.htaccess ya da httpd.conf içinde: SetEnv DB_PASS "guclu-sifre"Çılgın Yazılım Tasarım Kalıbı
assets/css/cilginyazilim.css dosyası, bu projeye değil markaya aittir. Diğer örnek projelerde de aynı görsel dili kullanabilmek için ayrı bir dosya olarak tutulur.
Başka bir projede kullanmak
<!-- 1) Bootstrap'ten SONRA ekleyin -->
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/cilginyazilim.css">
<!-- 2) body'ye tema sınıfını verin -->
<body class="cy-app">
Hazır bileşenler
| Sınıf | Ne işe yarar | ||
|---|---|---|---|
.cy-card / .cy-card__header / .cy-card__body / .cy-card__footer | Gradyan başlıklı ana kart | ||
.cy-brand / .cy-brand__mark | Logo kutusu + başlık bloğu | ||
.cy-btn + .cy-btn--primary \ | --onbrand | Marka butonları | |
.cy-btn-icon + --view \ | --edit \ | --delete | Tablo içi ikon butonları |
.cy-table | Marka görünümlü tablo | ||
.cy-avatar / .cy-avatar--initial / .cy-avatar--lg | Profil görseli ve baş harf rozeti | ||
.cy-badge + --glass \ | --soft | Rozetler | |
.cy-modal | Gradyan başlıklı modal | ||
.cy-detail | Etiket/değer listesi (detay modalı) | ||
.cy-toast + --success \ | --danger \ | --info | Bildirim balonları |
Renkleri değiştirmek
Tüm bileşenler CSS değişkenlerinden beslenir. Tek yeri değiştirmek yeter::root {
--cy-brand-900: #061321; /* Logodaki en koyu lacivert */
--cy-brand-600: #0b5cb5; /* Ana marka mavisi */
--cy-accent: #0ea5e9; /* Vurgu rengi */
--cy-gradient: linear-gradient(135deg, #061321, #0b5cb5 45%, #0284c7);
}Renk paleti cilginyazilim.com logosundan türetilmiştir: koyu lacivertten canlı maviye uzanan geçiş. Logo assets/images/logo.png içinde yer alır ve başlıkta beyaz yuvarlak bir zemine oturtulur.
Koyu tema
Kullanıcının işletim sistemi koyu temadaysa otomatik devreye girer. Zorlamak isterseniz:<html data-cy-theme="dark"> <!-- veya "light" -->Dosya Yapısı
.
├── index.php # Arayüz + tüm JavaScript mantığı
├── crud.sql # Veritabanı şeması + 50 örnek kayıt
├── README.md # Türkçe belgelendirme
├── README.en.md # İngilizce belgelendirme
├── LICENSE # MIT lisansı
├── .gitignore
│
├── docs/
│ └── screenshots/ # README'de kullanılan ekran görüntüleri
│
├── system/
│ ├── config.php # Ayarlar, oturum, PDO bağlantısı
│ ├── function.php # Yardımcı fonksiyonlar
│ └── ajax.php # AJAX uç noktası / CRUD yönlendiricisi
│
├── assets/
│ ├── css/
│ │ ├── bootstrap.min.css
│ │ ├── dataTables.bootstrap5.min.css
│ │ ├── cilginyazilim.css # ★ MARKA TASARIM KALIBI
│ │ └── style.css # Sadece bu sayfaya özel eklemeler
│ └── js/
│ ├── jquery-3.7.0.js
│ ├── bootstrap.bundle.js
│ ├── jquery.dataTables.min.js
│ └── dataTables.bootstrap5.min.js
│
└── upload/
├── .htaccess # Klasörde kod çalıştırmayı engeller
└── *.png # Örnek görsellerYükleme sırası önemlidir:
CSS: bootstrap → dataTables → cilginyazilim → style
JS: jQuery → bootstrap.bundle → dataTables → dataTables.bootstrap5Sıra bozulursa
$ is not defined gibi hatalar alırsınız.Nasıl Çalışıyor?
┌─────────────────────────────────────────────────────────────────────┐
│ TARAYICI (index.php) │
│ │
│ DataTables ──┐ │
│ Form gönder ─┤ │
│ Detay butonu ┼──► jQuery AJAX ──► POST { action, csrf_token, ... } │
│ Sil butonu ──┘ │ │
└──────────────────────────────────────────────┼───────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────┐
│ SUNUCU (system/ajax.php) │
│ │
│ 1. POST mu? → değilse 405 │
│ 2. require_csrf() → geçersizse 419 │
│ 3. action'a göre dağıt: list │ add │ edit │ fetch │ delete │
│ 4. validate_name() → hatalıysa 422 + errors │
│ 5. upload_image() → içerikten tür doğrulama │
│ 6. PDO prepared query → MySQL │
│ 7. json_response() → tek noktadan JSON çıkışı │
│ │
│ Tüm bunlar try/catch içinde: hiçbir hata çıplak PHP mesajı olarak │
│ sızmaz, hepsi düzgün JSON'a çevrilir. │
└─────────────────────────────────────────────────────────────────────┘Sorumluluk dağılımı
| Dosya | Görevi |
|---|---|
| index.php | Sadece sunum. CSRF token üretir, DataTables'ı kurar, modalları ve toast'ları yönetir. Veritabanına dokunmaz. |
| system/ajax.php | Yönlendirici. action değerine göre işleyicilere dağıtır. Tüm güvenlik kontrolleri ve hata yakalama burada tek noktada. |
| system/function.php | Saf yardımcı fonksiyonlar. Veritabanına ihtiyaç duyanlar PDO'yu parametre olarak alır — her çağrıda yeni bağlantı açılmaz. |
| system/config.php | Oturum, sabitler ve tek bir PDO örneği. |
Öğrenirken dikkat çeken noktalar
Kod içindeki yorumlarda ayrıntısıyla anlatılan, yeni başlayanların sık takıldığı konular:serverSide: truene demek? — 50 kayıtta fark etmez ama 100.000 kayıtta tarayıcıya tüm veriyi göndermemenizi sağlar.- Event delegation — AJAX ile sonradan gelen butonlara neden
$('.js-edit').click()çalışmaz,$('#user_data').on('click', '.js-edit', ...)neden çalışır. EMULATE_PREPARES = falsetuzağı — aynı isimli yer tutucu (:search) neden iki kez kullanılamaz,Invalid parameter numberhatası nereden gelir.contentType: false, processData: false— dosya yüklerken bu ikisi neden zorunlu.- Sütun adı neden bind edilemez — ve bu yüzden neden beyaz liste şart.
AJAX API Referansı
Tüm isteklerPOST ile system/ajax.php adresine yapılır ve geçerli bir csrf_token içermelidir. Yanıtlar application/json türündedir.
action=list — DataTables listeleme
İstek: draw, start, length, search[value], order[0][column], order[0][dir]
Yanıt:
{
"draw": 1,
"recordsTotal": 50,
"recordsFiltered": 50,
"data": [[50, "<img …>", "Ozan", "TOPAL", "<span…>23.02.2025 23:28</span>", "<div class=\"cy-actions\">…</div>"]]
}Sıralanabilir sütunlar beyaz listeyle sınırlıdır:
0 → id, 2 → name, 3 → surname, 4 → tarih.Foto (1) ve İşlemler (5) sütunları veritabanı sütunu olmadıkları için sıralanamaz.
action=add — Yeni kayıt
İstek: name, surname, image_user (opsiyonel, multipart/form-data)
Başarılı (200):
{ "success": true, "type": "success", "description": "Kayıt başarıyla eklendi.", "id": 51 }Doğrulama hatası (422):
{
"success": false,
"type": "danger",
"description": "Lütfen formdaki hataları düzeltin.",
"errors": { "name": "Ad alanı boş bırakılamaz." }
}errors nesnesinin anahtarları form alanlarının id'leriyle birebir aynıdır; JavaScript mesajı doğrudan ilgili alanın altına yazar.
action=edit — Güncelleme
İstek: user_id, name, surname, image_user (opsiyonel)
Yeni görsel gönderilmezse mevcut görsel korunur. Gönderilirse yenisi kaydedilir ve eski dosya diskten silinir.
action=fetch — Tek kayıt (detay + düzenleme)
İstek: id
{
"success": true,
"id": 1,
"name": "Evren",
"surname": "ÇILGIN",
"image": "2090273627.png",
"image_url": "upload/2090273627.png",
"tarih": "06.01.2025 19:34"
}Hazır HTML değil ham veri döner; ekranı JavaScript
.text() ile doldurduğu için XSS riski oluşmaz.
action=delete — Silme
İstek: id
Kayıt ve ilişkili görsel dosyası birlikte silinir. Kayıt yoksa 404 döner.
HTTP durum kodları
| Kod | Anlamı |
|---|---|
200 | İşlem başarılı |
400 | Geçersiz parametre (örn. hatalı ID) |
404 | Kayıt bulunamadı |
405 | POST dışı istek |
419 | CSRF token geçersiz veya oturum düşmüş |
422 | Form doğrulama hatası (errors alanı döner) |
500 | Sunucu / veritabanı hatası |
Veritabanı Şeması
CREATE TABLE `users` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(150) NOT NULL,
`surname` VARCHAR(150) NOT NULL,
`image` VARCHAR(191) NOT NULL DEFAULT '', -- sadece dosya adı, tam yol değil
`tarih` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_users_name` (`name`), -- arama ve sıralama için
KEY `idx_users_surname` (`surname`),
KEY `idx_users_tarih` (`tarih`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
| Karar | Neden |
|---|---|
| InnoDB (MyISAM değil) | Transaction ve foreign key desteği, satır bazlı kilitleme |
| utf8mb4 (utf8mb3 değil) | Türkçe karakterler + emoji; eski utf8 bazı karakterleri saklayamaz |
| İndeksler | Arama/sıralama yapılan sütunlar; tablo büyüdükçe fark katlanarak açılır |
| Sadece dosya adı | Klasör yapısı değişirse veritabanına dokunmak gerekmez |
Mevcut (eski) bir kurulumu veri kaybetmeden yükseltmek için crud.sql dosyasının sonundaki ALTER TABLE komutlarını kullanın.
Sık Sorulanlar
Bu kodu kendi projemde kullanabilir miyim?
Evet. MIT lisanslı — ticari projeler dahil serbestçe kullanabilir, değiştirebilir, dağıtabilirsiniz. Atıf zorunlu değil ama sevindirir.
Tabloya yeni bir sütun eklemek istiyorum, nereleri değiştirmeliyim?
Örnek: email sütunu eklemek için beş nokta:
crud.sql→ tabloya sütunu ekleyinindex.php→ forma input, `'eekleyin- system/function.php
→find_user()içindekiSELECTlistesine ekleyin - system/ajax.php
→handle_save()içinde doğrulama +INSERT/UPDATE,handle_list()içinde$data[]dizisine yeni hücre - system/ajax.php
→ sütun eklediyseniz$sortableColumns` indekslerini kaydırmayı unutmayın
` sayısı ile $data[]` dizisinin uzunluğu aynı olmak zorundadır, aksi halde DataTables hata verir.
Görsel boyutu sınırını nasıl artırırım?
system/config.php içinde UPLOAD_MAX_BYTES değerini değiştirin. Ayrıca php.ini içindeki upload_max_filesize ve post_max_size değerlerini de artırın — PHP'nin limiti sizinkinden düşükse dosya sunucuya hiç ulaşmaz.
Neden hem istemcide hem sunucuda doğrulama var?
İstemci doğrulaması kullanıcı deneyimi içindir: kullanıcı sunucuya gitmeden anında geri bildirim alır. Ama JavaScript kapatılabilir veya istek doğrudan curl ile atılabilir. Bu yüzden gerçek koruma her zaman sunucudadır. İkisi birlikte kullanılır.
DataTables'ın serverSide: true ayarını kapatabilir miyim?
Kapatabilirsiniz ama o zaman tüm kayıtlar tek seferde tarayıcıya gönderilir. 50 kayıtta sorun olmaz; 50.000 kayıtta sayfa donar. Bu örnekte gerçek dünya senaryosunu göstermek için açık bırakıldı.
Bootstrap 5 sürümünü güncelleyebilir miyim?
Evet, assets/ altındaki dosyaları değiştirmeniz yeterli. Tasarım kalıbı Bootstrap'in üzerine ekleme yapar, onu değiştirmez — bu yüzden sürüm yükseltmeleri sorunsuz geçer.
Canlı Ortama Alırken
- [ ]
APP_DEBUGdeğerinifalseyapın - [ ] Veritabanı için
rootyerine sınırlı yetkili bir kullanıcı oluşturun - [ ] Kimlik bilgilerini ortam değişkeni olarak tanımlayın, koda gömmeyin
- [ ] HTTPS kullanın;
session.cookie_secure = 1vesession.cookie_httponly = 1ayarlayın - [ ] Nginx kullanıyorsanız
.htaccessçalışmaz — yükleme klasöründe PHP'yi sunucu yapılandırmasından kapatın:
```nginx
location ^~ /upload/ {
location ~ \.php$ { deny all; }
}
```
- [ ]
upload/klasörünü düzenli yedekleyin - [ ] Giriş sistemi ekleyin — bu örnekte kimlik doğrulama yoktur, herkes tüm kayıtları düzenleyebilir
Sorun Giderme
| Belirti | Çözüm |
|---|---|
| "Veritabanına bağlanılamadı" | MySQL çalışmıyor veya DB_* bilgileri hatalı. XAMPP panelinden MySQL'i başlatın. |
| Tablo boş, "Yükleniyor…" takılı | Tarayıcı konsolunu (F12) açın. Genelde system/ajax.php bir PHP hatası döndürüyordur; APP_DEBUG = true yapıp Network sekmesinden yanıtı okuyun. |
| HTTP 419 hatası | Oturum düşmüş — sayfayı yenileyin. Sunucuda session.save_path yazılabilir olmalıdır. |
Invalid parameter number | Aynı isimli yer tutucuyu bir sorguda iki kez kullanmışsınız. EMULATE_PREPARES = false iken buna izin verilmez; farklı isimler verin. |
$ is not defined | JavaScript yükleme sırası bozulmuş. jQuery her zaman en başta gelmelidir. |
| "Görsel kaydedilemedi" | upload/ klasörü yok veya yazma izni yok → chmod 755 upload |
| Türkçe karakterler bozuk | Veritabanı utf8mb4 değil. crud.sql sonundaki CONVERT TO CHARACTER SET utf8mb4 komutunu çalıştırın. |
| Büyük dosya yüklenmiyor | php.ini içindeki upload_max_filesize ve post_max_size değerlerini artırın. |
| DataTables "Requested unknown parameter" | `` sayısı ile sunucudan dönen dizi uzunluğu farklı. İkisini eşitleyin. |
Yol Haritası
- [ ] Kullanıcı girişi ve rol tabanlı yetkilendirme
- [ ] Toplu silme (checkbox ile çoklu seçim)
- [ ] Excel / CSV / PDF dışa aktarma (DataTables Buttons)
- [ ] Sunucu tarafında görsel yeniden boyutlandırma ve thumbnail
- [ ] REST API katmanı (JWT ile)
- [ ] Soft delete + işlem geçmişi (audit log)
- [ ] PHPUnit ile birim testleri
- [ ] Koyu tema için elle açma/kapama düğmesi
Katkı
Bu proje herkese açıktır — dilediğiniz geliştirmeyle katkı sağlayabilirsiniz.
📦 Depo: github.com/CilginYazilim/PHP-PDO-MySQL-Ajax-CRUD-DataTables-Bootstrap-5-Modals
| Nasıl katkı sağlarım? | Nereden |
|---|---|
| 🐛 Hata bildir | Issues |
| 💡 Özellik öner | Issues |
| 🔧 Kod gönder | Pull Requests |
| ❓ Soru sor | Discussions |
Pull request adımları
# 1) Depoyu çatallayın (GitHub'da "Fork" butonu), sonra kendi kopyanızı indirin
git clone https://github.com/KULLANICI-ADINIZ/PHP-PDO-MySQL-Ajax-CRUD-DataTables-Bootstrap-5-Modals.git
cd PHP-PDO-MySQL-Ajax-CRUD-DataTables-Bootstrap-5-Modals
# 2) Değişikliğiniz için yeni bir dal açın
git checkout -b ozellik/yeni-ozellik
# 3) Kodunuzu yazın, sonra kaydedin
git add .
git commit -m "Yeni özellik: kısa ve açıklayıcı bir başlık"
# 4) Kendi çatalınıza gönderin
git push origin ozellik/yeni-ozellik
# 5) GitHub'da "Compare & pull request" butonuna tıklayın
Katkı ölçütleri
- Kod açıklamalı olsun. Bu projenin temel amacı öğretmek; yorumsuz kod PR'ı geri döner.
- Güvenlik kontrollerini atlamayın. Prepared statement,
e()ile kaçışlama verequire_csrf()her yeni işlemde de olmalı. - Tasarım değişikliklerini
cilginyazilim.cssüzerinden yapın, satır içistyle="..."kullanmayın. - Sütun eklerken `
sayısı ile$data[]` uzunluğunu eşitlemeyi unutmayın. - Yeni bir dış kütüphane eklemeden önce issue açıp tartışalım — proje bilinçli olarak bağımlılıksızdır.
Lisans
MIT — ticari kullanım dahil serbesttir.cilginyazilim.com tarafından ❤ ile geliştirildi
Faydalı bulduysanız ⭐ vermeyi unutmayın.
Kaynak Kod soldaki ağaçtan bir dosya seçin
-
assets
-
css
- bootstrap.css 232.4 KB
- bootstrap.min.css 227.5 KB
- cilginyazilim.css 19.4 KB
- dataTables.bootstrap5.min.css 11.7 KB
- style.css 2 KB
-
images
- logo.png 70.4 KB
-
js
- bootstrap.bundle.js 203.2 KB
- bootstrap.js 142.3 KB
- dataTables.bootstrap5.min.js 2.3 KB
- jquery-3.7.0.js 278.3 KB
- jquery.dataTables.min.js 85.1 KB
-
-
docs
-
screenshots
- 01-liste.png 172.4 KB
- 02-detay-modali.png 175.4 KB
- 03-form-modali.png 168.7 KB
- 04-sayfalama.png 201.5 KB
- 05-arama.png 148.8 KB
- README.md 987 B
-
-
system
- .htaccess 1.9 KB
- ajax.php 19.9 KB
- config.local.php 143 B
- config.local.php.example 1.3 KB
- config.php 8.4 KB
- function.php 16.7 KB
-
upload
- .htaccess 357 B
- 1130289535.png 3.1 KB
- 1131702286.png 4.1 KB
- 1832783644.png 70.4 KB
- 2090273627.png 3.6 KB
- .gitignore 1.1 KB
- crud.sql 7 KB
- index.php 36.8 KB
- LICENSE 1.1 KB
- README.en.md 27.2 KB
- README.md 27.2 KB
Güvenlik gereği kaynak dosyalardaki parola, API anahtarı ve benzeri gizli
değerler gösterilmeden önce maskelenir (••••••••).
Sık Sorulan Sorular
Kullanıcıdan gelen hiçbir değer sorgu metnine yazılmaz. Tüm sorgular PDO'nun hazırlanmış ifadeleriyle çalışır: sorgunun yapısı önce veritabanına gönderilir, değerler ayrı parametre olarak bağlanır. Böylece bir değerin içindeki tırnak ya da SQL anahtar kelimesi sorgunun anlamını değiştiremez.
Veritabanından gelen her metin ekrana basılmadan önce kaçışlanır (htmlspecialchars). Böylece bir kaydın içine yazılmış HTML ya da betik, sayfada çalışacak kod olarak değil düz metin olarak görünür. Kaçışlama girişte değil çıkışta yapılır; veriyi bozmadan doğru katmanda çözmenin yolu budur.
Hayır. Klonlayın, crud.sql dosyasını içe aktarın, çalıştırın. Başka hiçbir kurulum adımı yoktur; Composer, npm ve hatta internet bağlantısı bile gerekmez, çünkü tüm kütüphaneler proje içinde durur. Paylaşımlı hostinglerde de doğrudan çalışır.
Yüklenen dosyanın türü, tarayıcının gönderdiği başlığa değil dosyanın gerçek içeriğine bakılarak doğrulanır ve yalnızca izin verilen görsel türleri kabul edilir. Dosya adı yeniden üretilir, böylece kullanıcının verdiği ad diske yazılan adı belirlemez. Daha derin bir savunma isterseniz kütüphanedeki güvenli dosya yükleme örneği on iki katmanlı sürümü anlatır.
Evet, MIT lisanslıdır ve tam olarak bunun için hazırlanmıştır. Tablo adını ve alanları kendi verinize göre değiştirip aynı kalıbı sürdürebilirsiniz: sunucu taraflı liste, modal form, Ajax uçları ve doğrulama akışı aynen kalır. Canlıya alırken hata gösterimini kapatmayı unutmayın.
Yorumlar 0 konuşma
Bu kod örneğine henüz yorum yapılmamış. Takıldığınız bir yer veya merak ettiğiniz bir ayrıntı varsa ilk soruyu siz sorun.
Soru Sor veya Yorum Yaz
Yorumunuz onaylandıktan sonra yayınlanır. Teknik sorularınıza ekibimiz yanıt verir.