Okunabilir bir URL, sayfanın konusunu kullanıcıya anlatabilir; tek başına arama sıralaması garantisi değildir. Çalışan ve indekslenmiş adresleri sırf daha güzel görünsün diye topluca değiştirmeyin. Yeni bir PHP uygulamasında slug yapısını baştan belirlemek, mevcut sitede URL göçü yapmaktan farklı bir iştir.
Apache üzerinde küçük bir yönlendirme örneği
Aşağıdaki kural Apache 2.4, etkin mod_rewrite ve gerekli AllowOverride izni varsayar. Web kökündeki .htaccess içindir; alt dizin veya mevcut uygulama yönlendiricisi varsa uyarlanmalıdır. LoadModule satırını .htaccess içine koymayın; modül yönetimi sunucu yapılandırmasının işidir.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^blog/([a-z0-9]+(?:-[a-z0-9]+)*)/?$ blog.php?slug=$1 [END]
Örneğin /blog/php-dizileri isteği içeride blog.php?slug=php-dizileri olarak işlenir. Bu bir dış yönlendirme değildir; tarayıcı adresi değişmez. Hedefte zaten sorgu bulunduğu ve QSA kullanılmadığı için gelen sorgu dizisi eklenmez. Böylece ?slug=baska-yazi ile yolun seçtiği slug'ın üzerine yazılması önlenir. Takip parametreleri de aktarılmaz; böyle parametreler gerekiyorsa açık bir politika belirleyin.
PHP tarafında tür ve kayıt kontrolü
Rewrite kuralı veritabanı güvenliği sağlamaz. blog.php doğrudan çağrılabileceği için girdiyi yine doğrulayın. Örnek, güvenilir yapılandırmadan oluşturulmuş PDO bağlantısını ve posts(slug, title, status) şemasını varsayar; kendi tablo adınıza uyarlayın.
<?php
// $pdo: uygulamanın utf8mb4 kullanan PDO bağlantısı.
$slug = $_GET['slug'] ?? '';
if (!is_string($slug) || strlen($slug) > 160
|| !preg_match('/\A[a-z0-9]+(?:-[a-z0-9]+)*\z/', $slug)) {
http_response_code(404);
exit('Sayfa bulunamadı.');
}
$stmt = $pdo->prepare(
'SELECT title FROM posts WHERE slug = :slug AND status = :status LIMIT 1'
);
$stmt->execute(['slug' => $slug, 'status' => 'published']);
$post = $stmt->fetch(PDO::FETCH_ASSOC);
if ($post === false) {
http_response_code(404);
exit('Sayfa bulunamadı.');
}
echo htmlspecialchars($post['title'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
Çok dilli sistemde sorguya dil koşulu da eklenmeli ve slug benzersizliği dil ile birlikte tasarlanmalıdır. Taslak veya ileri tarihli içeriği filtrelemek uygulamanın yayın kurallarına bağlıdır; yalnızca URL'nin düzgün görünmesine güvenmeyin.
Türkçe başlıktan slug üretmek
Karakterleri sırayla yanlış eşleyen bir düzenli ifade yerine açık dönüşüm tablosu kullanın. Bu örnek yeni kayıtlar içindir; mevcut URL'leri yeniden üretip değiştirmez. Türkçe dışındaki bütün alfabeler için genel bir çeviri çözümü değildir.
<?php
function makeSlug(string $title): string {
$text = strtr($title, [
'Ç' => 'C', 'Ğ' => 'G', 'İ' => 'I',
'Ö' => 'O', 'Ş' => 'S', 'Ü' => 'U',
'ç' => 'c', 'ğ' => 'g', 'ı' => 'i',
'ö' => 'o', 'ş' => 's', 'ü' => 'u',
]);
$slug = trim((string) preg_replace('/[^a-z0-9]+/', '-', strtolower($text)), '-');
if ($slug === '' || strlen($slug) > 160) {
throw new InvalidArgumentException('Slug boş veya çok uzun.');
}
return $slug;
}
echo makeSlug('İçerik Yönetimi: Çığ, Şube ve Ölçü');
// icerik-yonetimi-cig-sube-ve-olcu
Aynı başlık aynı slug'ı üretebilir. Uygulamada kontrol etmek tek başına eşzamanlı kayıt yarışını çözmez; uygun benzersiz indeks ve çakışma yönetimi gerekir. Yalnızca yeni kayıtta, belirlenmiş bir ek veya kimlik politikasıyla çakışmayı çözün.
Yayına almadan adres davranışını sınayın
Geçerli bir slug'ın doğru yazıyı, bilinmeyen slug'ın gerçek 404 durum kodunu döndürdüğünü kontrol edin. Dizi türündeki slug[]=x girdisi hata sayfasına düşmeli, SQL hatası üretmemelidir. Sonunda eğik çizgi bulunan ve bulunmayan adresler için tek bir tercih belirleyin. Gerçek bir URL değişikliği yapılacaksa eski adresi karşılık gelen yeni adrese 301 ile yönlendirin; bütün eski sayfaları ana sayfaya göndermeyin. Canonical adresi doğrulanmış site kökünden üretin, isteğin Host başlığına körlemesine güvenmeyin.
Başvuru: Apache RewriteRule bayrakları ve PHP strtr.