用户友好的URL - mod_rewrite和php重定向

时间:2012-02-02 01:34:57

标签: php mod-rewrite url-rewriting friendly-url

到目前为止,我已经这样做了:

RewriteBase /
RewriteCond  %{REQUEST_FILENAME} !-f
RewriteCond  %{REQUEST_FILENAME} !-d
RewriteRule  ^(.*)$ index.php?load=$1 [QSA,L]

然后在我的索引页面(在根目录中)我正在使用PHP来确定要加载的页面:

// Swap to variables
    $load = $_GET['load'];

// Home page
    if (!$load || $load == "") { include('home.php'); exit(); }

// Dashboard
    if ($load == "dashboard") { include('dashboard.php'); exit(); }

// About
    if ($load == "about") { include('about.php'); exit(); }

// Username
    $data_array = array(':username' => $load);
    $select_account = $connect->prepare("SELECT * FROM `users` WHERE `username` = :username");
    $select_account-> execute($data_array);
    $account_amount = $select_account->rowCount();
    if ($account_amount > 0) { include('profile.php?name=$load'); exit(); }

// Redirect to 404 if there are no results
    include('404.php'); exit();

到目前为止,所有内容都有效,但用户可以将照片上传到图库,我希望他们能够像这样查看:

www.mysite.com/[username]/gallery/

但是如果您要将其作为网址输入,则重写会将[username]/gallery/作为一个部分显示为$load = [username]/gallery,这意味着会给我一个'404'。

获得理想的结果可能是一个更好的解决方案,但我对.htaccess和重写并不太好。我想补充一点,我也喜欢这个重写,因为我有一个名为signupsignin的子目录,它们都有子目录,但如果我转到URL:

www.mysite.com/signup
www.mysite.com/signin

它忽略了重写并转到目录而不是通过我想要的$load语句运行它。

另外,要注意,在注册帐户时,任何与dashboardabout等字符串匹配的用户名都不允许他们使用它,这会停止用户名和{{1 if / else语句和它们包含混合等等

修改

我忘记注意的另一件事是,因为他们可以随意调用图库,所以需要搜索以查看该图库是否存在,例如:

$load

首先需要检查用户名是否存在,然后检查相册是否存在,然后显示它是否存在,如果不存在,则显示404 /重定向到任何地方。所以基本上,两个参数/查询都是动态的。不仅如此,那么该专辑​​中的单张照片也需要相同的工作,例如:

www.mysite.com/username/my+first+album

我希望这是有道理的......

4 个答案:

答案 0 :(得分:3)

一个简单的解决方案是: 编辑HTACCESS

RewriteBase /
RewriteCond %{REQUEST_URI}  !/signup
RewriteCond %{REQUEST_URI}  !/signin
RewriteRule ^([^/]*)/([^/]*)$ index.php?load=gallery&username=$1&gallery=$2
RewriteCond  %{REQUEST_FILENAME} !-f
RewriteCond  %{REQUEST_FILENAME} !-d
RewriteRule  ^(.*)$ index.php?load=$1 [QSA,L]

现在PHP部分(对于index.php):

$load = $_GET['load'];
switch ($load){
    default:
        include('home.php');
        exit();
    break;
    case 'dashboard':
        include('dashboard.php');
        exit();
    break;
    case 'about':
        include('about.php');
        exit();
    break;
    case 'gallery':
        $username = $_GET['username'];
        $gallery = $_GET['gallery'];

        //check for the username and gallery

        header("Location: your-gallery-location-goes-here");
    break;
}

希望它会有所帮助:)。

答案 1 :(得分:2)

您想要的是所谓的URL路由器,这需要您分析网址并根据内容做出决策。大多数系统通过让您提供url模板以及在url匹配时调用的函数来完成此操作。该函数通常在模板URL中传递任何子匹配。

例如,Django使用正则表达式作为其url路由,并将命名匹配作为参数传递给给定的函数(或类)。

如果这对您的需求来说过于复杂,那么您可以使用特定的正则表来解析网址,您的图库就是:

$matches = array();
$re = "/\/([\w\d])+\/([\w\d+%])+\/?/";
preg_match($re, $load, $matches);
$username = $matches[0];
$gallery  = $matches[1];

然后,您可以随意使用$username$gallery

注意

以上假设它会匹配,您需要检查preg_match的返回值以确保。另外,我没有检查正则表达式,它可能是错误的,或使用不在此语法中的功能。

<强>参考

答案 2 :(得分:0)

在Aatch和Sally的帮助下以及一些关于URL路由的搜索结果中,我有以下方法来实现我的目标,所以我想我会与所有人分享,以防任何人想要使用它...

首先,我需要提一下我正在处理的网站是在根文件夹mysite.com/sub/folder/index.php的2个子目录中,因此为什么在数组上我从[3]开始

据说我的.htaccess文件如下:

RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . sub/folder/index.php [QSA,L]

就我而言,这将获取sub/folder/之后编写的所有内容,并将页面直接重定向回index.php,但是,它会屏蔽地址栏中的URL。

唯一忽略这一点的是子目录实际存在。所以例如我有一个文件夹/sub/folder/signup/如果我要在地址栏中键入它,因为该目录存在,那么你不会被重定向到index.php文件,而是发送到请求的目录,就像正常一样。 / p>

现在在我的index.php文件上(请记住我从$ uri开始[3]因为我在子文件夹中!)

$uri = $_SERVER['REQUEST_URI']; // This brings back /sub/folder/foo/bar/test/
$uri = explode("/", $uri); // Separate each one

$var_one = $uri[3]; // foo
$var_two = $uri[4]; // bar
$var_three = $uri[5]; // test

switch ($var_one) {

    case '':
    case 'home':
        include('home.php');
        exit();
        break;

    case 'signout':
    case 'logout':
        include('signout.php');
        exit();
        break;

    case 'dashboard':
    case 'dash':
        include('dashboard.php');
        exit();
    break;

}

// By Username
    $data_array = array(':username' => $var_one);
    $select_account = $connect->prepare("SELECT * FROM `users` WHERE `username` = :username");
    $select_account -> execute($data_array);
    $account_amount = $select_account->rowCount();
    if ($account_amount > 0) { include('profile.php'); exit(); }

// By Account ID
    $data_array = array(':id' => $var_one);
    $select_account = $connect->prepare("SELECT * FROM `users` WHERE `id` = :id");
    $select_account -> execute($data_array);
    $account_amount = $select_account->rowCount();
    if ($account_amount > 0) { include('profile.php'); exit(); }

include('page_not_found.php');

开关案例很简单,如果url是:/ sub / folder / dashboard /则显示dashboard.php。如果没有一个案例匹配,那么我们可能会查看个人资料。第一个检查是否可以是用户名,如果存在,则显示视图配置文件页面。然后,它会检查它是否可能是该配置文件的唯一ID号,并进行相同的检查。

最后,如果没有任何结果从中找回,那么我们会看到404页面找不到页面。

如果是个人资料页面,在profile.php文件中,我可以运行$var_two的检查,看看他们是否已经使用该名称上传了相册,例如/sub/folder/joe/holiday/如果是,然后运行查询以获取所有内容,如果没有,则显示消息/重定向或其他。

然后,如果还有更多,请说明该文件夹($var_three)中的特定图片($var_two),例如/sub/folder/joe/holiday/beach/ - 然后通过显示结果的类似查询运行它

这可能不是最好的方法,但它非常直接,而且一切都按照我的意愿行事,所以我不能抱怨。

答案 3 :(得分:0)

这是一个简单的例子:

<强>的.htaccess

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

首先,您必须拒绝直接访问.php文件,您可以将它们放在单独的文件夹中,如'/ includes',并将对该文件夹的任何调用重定向到index.php。 其次,允许直接访问文件(如图像或javascripts)。 最后一条规则,将其他任何内容重定向到index.php。

<强> PHP

基本上你必须有一组规则来测试URL和一些控制器来处理结果。

define( 'WEB_ROOT', rtrim( dirname($_SERVER["SCRIPT_NAME"]), '/' ) );
define( 'INCLUDES_ROOT', 'includes/' );

// examples of rewrite rules ( $key = action, $value = regular expression )
$rules = array( 
    'pages' => "/(?'page'dashboard|about|signin|signup)",   // e.g. '/about'
    'gallery' => "/(?'username'[\w\-]+)/gallery",   // e.g. '/some-user/gallery'
    'album' => "/(?'username'[\w\-]+)/(?'album'[\w\-]+)",   // e.g. '/some-user/some-album'
    'picture' => "/(?'username'[\w\-]+)/(?'album'[\w\-]+)/(?'picture'[\w\-]+)",     // e.g. '/some-user/some-album/some-picture'
    'home' => "/"   // e.g. '/'
    );

// get uri
$uri = '/' . trim( str_replace( WEB_ROOT, '', $_SERVER['REQUEST_URI'] ), '/' );

// test uri
foreach ( $rules as $action => $rule ) {
    $pattern = '/^'.str_replace( '/', '\/', $rule ).'$/';

    if ( preg_match( $pattern, $uri, $params ) ) {
        /* now you know the action and parameters so you can 
         * include appropriate template file ( or proceed in some other way )
         * NOTE: variable $params vill be visible in template ( use print_r( $params ) to see result )
         */
        include( INCLUDES_ROOT . $action . '.php' );
        // exit to avoid the 404 message 
        exit();
    }
}

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

下一步是检查收到的参数。