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


User friendly URLs - mod rewrite and php redirections

到目前为止,我已经完成了以下操作:

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/

但如果你把它作为url键入,重写会把[username]/gallery/读成一个部分,这意味着$load = [username]/gallery,这会给我一个"404"。

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

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

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

此外,需要注意的是,在注册帐户时,任何与dashboardabout等字符串匹配的用户名都不允许他们使用,这会阻止用户名和$load if/else语句及其包含内容混淆等

编辑

我忘了注意的另一件事是,由于他们可以随心所欲地调用画廊,因此需要进行搜索以查看该画廊是否存在,例如:

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

它首先需要检查用户名是否存在,然后检查相册是否存在,如果存在则显示,如果不存在则404/重定向到任何位置。因此,基本上,两个参数/查询都是动态的。不仅如此,相册中的个人照片也需要同样的工作,例如:

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

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

一个简单的解决方案是:编辑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;
}

希望它能有所帮助:)

你想要的是所谓的URL路由器,这需要你分析URL并根据内容做出决定。大多数系统都是通过让你提供一个url模板,以及一个在url匹配时调用的函数来实现这一点的。该函数通常传递给模板url中的任何子匹配项。

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

如果这对你的需求来说太复杂了,那么你可以使用特定的正则表达式来解析url,你的图库案例是:

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

然后,您可以随心所欲地使用CCD_ 9和CCD_ 10。

注意

以上假设它将匹配,您需要检查preg_match的返回值以确保匹配。此外,我还没有检查regex,它可能是错误的,或者使用了此语法中没有的功能。

参考

  • 正则表达式
  • PHP PCRE函数文档(PCRE=Perl兼容正则表达式)

在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文件,而是被发送到请求的目录,就像正常情况一样。

现在在我的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_two)中的特定图片($var_three),例如/sub/folder/joe/holiday/beach/,那么通过显示结果的类似查询运行它。

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

下面是一个简单的例子:

.htaccess

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

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

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