PHP ile URL yeniden yazma


139

Şuna benzeyen bir URL var:

url.com/picture.php?id=51

Bu URL'yi şu biçime dönüştürmeye nasıl giderim:

picture.php/Some-text-goes-here/51

Bence WordPress de aynısını yapıyor.

PHP'de kolay URL'ler yapmaya nasıl devam edebilirim?


1
Apache dosyalarının konfigürasyonunda çok fazla ayar yapmanız gerekiyor ... gerçekten ihtiyacınız olana bir örnek verin? Bu metni nasıl eklersiniz? önceden tanımlanmış mı yoksa dinamik olarak mı oluşturulmuş? doğru cevabı almak için olabildiğince çok bilgi verin ... ve evet url biraz daha açıklayıcı olabilir :)
user123_456

1
Neden PHP? Apache's mod_rewritebunun için ihtiyacınız olan tek şey ve burada SO ile ilgili birçok soru var. Ve bu wordpress'in de aynı şeyi "düşündüğünü" düşünüyorsanız, neden sadece bakmıyorsunuz ? ;)
nietonfir


Bunu neden yapıyorsun? Hedef, URL'leri yeniden yazmaktır. Öyleyse .htaccess veya benzeri bir şey kullanın. Hedef sadece dizeyi değiştirmekse, $ _GET sadece querystring?
adeneo

Metin bir görüntünün başlığı ve sonra eğik çizgi sonra id :) :) apache mod_rewrite neler sunabileceğini bakmak zorunda kalacağım. Umarım çok zor değildir: D
Jazerix

Yanıtlar:


194

Bunu aslında 2 yolla yapabilirsiniz:

Mod_rewrite ile .htaccess yolu

.htaccessKök klasörünüzde adlandırılan bir dosya ekleyin ve buna benzer bir şey ekleyin:

RewriteEngine on
RewriteRule ^/?Some-text-goes-here/([0-9]+)$ /picture.php?id=$1

Bu, Apache'ye bu klasör için mod_rewrite özelliğini etkinleştirmesini söyler ve normal ifadeyle eşleşen bir URL sorulursa dahili olarak yeniden yazar , son kullanıcı görmeden onu olarak istediğiniz . Kolay, ancak esnek değil, bu yüzden daha fazla güce ihtiyacınız varsa:

PHP yolu

Bunun yerine .htaccess'inize şunu koyun: (baştaki eğik çizgiye dikkat edin)

FallbackResource /index.php

Bu, index.phpnormalde sitenizde bulamadığı tüm dosyalar için çalıştırmanızı söyleyecektir . Orada örneğin şunları yapabilirsiniz:

$path = ltrim($_SERVER['REQUEST_URI'], '/');    // Trim leading slash(es)
$elements = explode('/', $path);                // Split path on slashes
if(empty($elements[0])) {                       // No path elements means home
    ShowHomepage();
} else switch(array_shift($elements))             // Pop off first item and switch
{
    case 'Some-text-goes-here':
        ShowPicture($elements); // passes rest of parameters to internal function
        break;
    case 'more':
        ...
    default:
        header('HTTP/1.1 404 Not Found');
        Show404Error();
}

URL'ler, yapılandırma ve veritabanına bağımlı URL'ler vb. Ayrıştırılmasında çok daha fazla esneklik sağladığı için büyük siteler ve CMS sistemleri bunu .htaccessyapar.


Sabit kodlamak yerine, dizeyi tamamen yok saymak için regex'i kullanabilirsiniz. Başka bir deyişle, önemli olan tek şey kimlik kısmıdır. Adresine gitmek picture.php/invalid-text/51de aynı yere yönlendirir. Dizenin doğru olup olmadığını görmek için bir kontrol ekleyebilir ve değilse doğru konuma yeniden yönlendirebilirsiniz. Bunu htaccess kullanarak sitelerimden birinde yaptım.
Mike

7
Eğer ayrıştırmak varsa gerçekten pratik küçük siteler için elverişli değil, /blog/25aynı zamanda /picture/51ve /download/684. Ayrıca, rastgele oluşturulan tüm URL'ler düzgün bir şekilde 404 döndürmezse, çok kötü bir uygulama olarak kabul edilir (ve Google
PR'ı

5
en azından benim sistemimde, öyleydi FallbackResource /index.php(
Jack James

4
@olli: Kötü uygulama yorumu özellikle cevabın kendisinde bulunan çözüm tarafından çözülen "var olmayan URL'ler için 404'lerin döndürülmemesi" anlamına gelir. İlk soruya gelince - FallbackResourcesadece dosya sisteminde gerçekten bulunmayan dosyalar için devreye girer, bu nedenle geri dönüş . Dolayısıyla, bir dosyanız varsa /static/styles.cssve http://mydomain.tld/static/styles.csskodun hiçbir zaman yürütülmediği anlamına gelirse , saydam olarak beklendiği ve amaçlandığı gibi çalışmasını sağlayın.
Niels Keurentjes

if($elements[0] === NULL)bunun yerine, $elementsboş olsa bile yine de bir sayım döndüreceği için kullanmalısınız .
fireinspace

57

Sadece rotayı değiştirmek için rotayı değiştirmek istiyorsanız, picture.phpyeniden yazma kuralı eklemek .htaccessihtiyaçlarınızı karşılayacaktır, ancak URL'nin Wordpress'teki gibi yeniden yazılmasını istiyorsanız, PHP yoludur. Başlamak için basit bir örnek.

Klasör yapısı

Orada kök klasöründe ihtiyaç vardır iki dosyalardır, .htaccessve index.php, ve geri kalan kısmını yerleştirin iyi olurdu .phpgibi ayrı klasördeki dosyaların inc/.

root/
  inc/
  .htaccess
  index.php

.htaccess

RewriteEngine On
RewriteRule ^inc/.*$ index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]

Bu dosyanın dört yönergesi vardır:

  1. RewriteEngine - yeniden yazma motorunu etkinleştir
  2. RewriteRule- inc/klasördeki tüm dosyalara erişimi reddet , herhangi bir çağrıyı bu klasöre yönlendirindex.php
  3. RewriteCond - diğer tüm dosyalara (resimler, css veya komut dosyaları gibi) doğrudan erişime izin ver
  4. RewriteRule - başka bir şeyi yönlendirin index.php

index.php

Artık her şey index.php'ye yönlendirildiğinden, url'nin doğru olup olmadığı, tüm parametrelerin mevcut olup olmadığı ve parametrelerin türü doğru olup olmadığı belirlenecektir.

URL'yi test etmek için bir dizi kuralımız olmalı ve bunun için en iyi araç düzenli bir ifadedir. Düzenli ifadeler kullanarak iki sinek tek bir darbe ile öldüreceğiz. Url, bu testi geçmek için izin verilen karakterlerde test edilen tüm gerekli parametrelere sahip olmalıdır. İşte bazı kural örnekleri.

$rules = array( 
    'picture'   => "/picture/(?'text'[^/]+)/(?'id'\d+)",    // '/picture/some-text/51'
    'album'     => "/album/(?'album'[\w\-]+)",              // '/album/album-slug'
    'category'  => "/category/(?'category'[\w\-]+)",        // '/category/category-slug'
    'page'      => "/page/(?'page'about|contact)",          // '/page/about', '/page/contact'
    'post'      => "/(?'post'[\w\-]+)",                     // '/post-slug'
    'home'      => "/"                                      // '/'
);

Sonra uri isteğini hazırlamaktır.

$uri = rtrim( dirname($_SERVER["SCRIPT_NAME"]), '/' );
$uri = '/' . trim( str_replace( $uri, '', $_SERVER['REQUEST_URI'] ), '/' );
$uri = urldecode( $uri );

Şimdi uri isteğine sahip olduğumuza göre, son adım uri'yi normal ifade kuralları üzerinde test etmektir.

foreach ( $rules as $action => $rule ) {
    if ( preg_match( '~^'.$rule.'$~i', $uri, $params ) ) {
        /* now you know the action and parameters so you can 
         * include appropriate template file ( or proceed in some other way )
         */
    }
}

Regex'te adlandırılmış alt kalıplar kullandığımızdan, $paramsdiziyi PHP'nin diziyi doldurmasıyla neredeyse aynı şekilde dolduracağımızdan başarılı bir eşleşme olacaktır $_GET. Bununla birlikte, dinamik bir url kullanıldığında, $_GETdizi parametreler kontrol edilmeden doldurulur.

    / Resim / bazı + metin / 51

    Dizi
    (
        [0] => / resim / bazı metinler / 51
        [text] => bazı metinler
        [1] => bazı metinler
        [id] => 51
        [2] => 51
    )

    picture.php? metni bazı + metin & id = = 51

    Dizi
    (
        [text] => bazı metinler
        [id] => 51
    )

Bu birkaç kod satırı ve düzenli ifadeleri temel olarak bilmek, sağlam bir yönlendirme sistemi oluşturmaya başlamak için yeterlidir.

Komple kaynak

define( 'INCLUDE_DIR', dirname( __FILE__ ) . '/inc/' );

$rules = array( 
    'picture'   => "/picture/(?'text'[^/]+)/(?'id'\d+)",    // '/picture/some-text/51'
    'album'     => "/album/(?'album'[\w\-]+)",              // '/album/album-slug'
    'category'  => "/category/(?'category'[\w\-]+)",        // '/category/category-slug'
    'page'      => "/page/(?'page'about|contact)",          // '/page/about', '/page/contact'
    'post'      => "/(?'post'[\w\-]+)",                     // '/post-slug'
    'home'      => "/"                                      // '/'
);

$uri = rtrim( dirname($_SERVER["SCRIPT_NAME"]), '/' );
$uri = '/' . trim( str_replace( $uri, '', $_SERVER['REQUEST_URI'] ), '/' );
$uri = urldecode( $uri );

foreach ( $rules as $action => $rule ) {
    if ( preg_match( '~^'.$rule.'$~i', $uri, $params ) ) {
        /* now you know the action and parameters so you can 
         * include appropriate template file ( or proceed in some other way )
         */
        include( INCLUDE_DIR . $action . '.php' );

        // exit to avoid the 404 message 
        exit();
    }
}

// nothing is found so handle the 404 error
include( INCLUDE_DIR . '404.php' );

2
Parametreleri nasıl okuyorsunuz? $ Post_id = htmlentities ($ _ GET ['post']) ile çalışmaz;
andrebruton

@Danijel Tam bir kaynak kod alabilir miyim? Yukarıdaki kodu denedim ama sadece metin çıktı, CSS etkisi yok. Teşekkür ederim.
4 Kapağı

6

Bu hemen hemen tümünü index.php'ye yönlendiren bir .htaccess dosyasıdır

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} !-l
RewriteCond %{REQUEST_FILENAME} !\.(ico|css|png|jpg|gif|js)$ [NC]
# otherwise forward it to index.php
RewriteRule . index.php

$ _SERVER ["REQUEST_URI"] 'i ayrıştırıp size picture.php veya başka bir yol


8
Apache, FallbackResourcebirkaç büyük sürümden önce yönergeyi tanıttı; bu, şimdi tüm yeniden yazma motorunu başlatması gerekmediği için bu davranışı daha düşük performans maliyetiyle uygulamanın tercih edilen yoludur. Belgeler burada . Dizinlerinize ( !-d) başvurmadığınız ve tüm uzantı filtreleri geçersiz olduğu için kurallarınız da kusurludur - -fzaten yakalamanız gerekir.
Niels Keurentjes


2

Her ne kadar zaten cevaplanmış olsa da ve yazarın amacı bir ön kontrolör tipi uygulaması oluşturmaktır, ancak sorulan sorun için gerçek bir kural gönderiyorum. Birisi aynı sorunu yaşıyorsa.

RewriteEngine On
RewriteRule ^([^/]+)/([^/]+)/([\d]+)$ $1?id=$3 [L]

Yukarıdaki url için çalışmalıdır picture.php/Some-text-goes-here/51. bir yönlendirme uygulaması olarak index.php kullanmadan.


Href'de hangi URL'yi yazmamız gerektiğini bilmem gerekiyor mu? çünkü 404 alıyorum
questionbank
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.