0

我已经开始深入研究用户页面的干净 URL,我的大部分灵感来自 Stack Overflow 的做法。用户可以只输入他们希望查看的用户的用户 ID,然后将他们重定向到正确的 URL,包括显示名称。例如,如果我有 id 为 1 的帐户,则访问users/1将重定向到users/1/JosephDuffy,假设我的显示名称是JospehDuffy。从这里,可以执行额外的操作,例如编辑自己,users/1/JosephDuffy/edit编辑用户 1.users/1/username/edit也会重定向到users/1/JosephDuffy/edit. 上述所有示例都可以在完美的世界中运行,但很容易被破坏。
用户可以对其他人执行操作,例如users/2/Player2/befriend. 显然,你不想和自己交朋友,所以users/1/JospehDuffy/befriend什么也不做。但是,输入一个 URL,例如users/1/1/1/1/JosephDuffy/befriend似乎触发了动作 as befriend,显示名称 asJosephDuffy和用户 id as 1/1/1/1。我猜这就是 mod_rewrite 的工作原理,但它似乎给我扔了一些曲线球。
现在,我intval()在用户 ID 上使用,这似乎有效但不太理想;我仍然有多个提供相同信息的 URL,虽然我找不到任何其他“漏洞”,但可能仍然存在一些。我不确定问题出在哪里,所以我将发布我的 .htaccess 和 PHP 脚本。
.htaccess

RewriteEngine On

# Rewrite /users to provide the script with the GET variables it requires to function properly, whilst having clean URLs
# 3 variables were provided
RewriteRule ^users/([^.]+)/([^.]+)/([^.]+)/$ users.php?userid=$1&displayname=$2&action=$3
RewriteRule ^users/([^.]+)/([^.]+)/([^.]+)$ users.php?userid=$1&displayname=$2&action=$3

# 2 variables were provided
RewriteRule ^users/([^.]+)/([^.]+)/$ users.php?userid=$1&displayname=$2
RewriteRule ^users/([^.]+)/([^.]+)$ users.php?userid=$1&displayname=$2

#1 variable was provided
RewriteRule ^users/([^.]+)/$ users.php?userid=$1
RewriteRule ^users/([^.]+)$ users.php?userid=$1

我认为如果我在这个阶段的某个阶段使用或类似的东西也会更好[R=301,L],但我不确定在哪里,或者为什么真的。
users.php(有些部分被简化了,几乎是伪代码,以便于理解)

if (isset($_GET['userid'])) {
    $profileUserid = intval($_GET['userid']);
} else {
    $profileUserid = 0;
}
if (isset($_GET['displayname'])){
    $profileDisplayName = $_GET['displayname'];
} else {
    $profileDisplayName = '';
}
if (isset($_GET['action'])) {
    $action = $_GET['action'];
} else {
    $action = false;
}
$actualDisplayName = GetDisplayNameFromDBWhereid($profileUserid);
if ($actualDisplayName != $profileDisplayName) {
        header('Location: /users/' . $profileUserid . '/' . $actualDisplayName . '/' . $action);
        exit;
    } else if (substr($_SERVER['REQUEST_URI'], -1) != '/') {
        // There is no trailing slash, so add it
        header('Location: ' . $_SERVER['REQUEST_URI'] . '/');
        exit;
    }
    if ($currentUsersid == $profileUserid) {
        // Player is viewing themselves
        if ($action == 'edit') {
            echo 'Editing your profile';
        } else {
            // User viewing self, but not editing
            echo '<a href="edit">Edit your profile</a><br>';
        }
    } else {
        if ($action) {
            // Interact with the user whos profile is being viewed
        } else {
        }
    }

如果不使用intval($_GET['userid']),当我输入 时users/1/1/1/1/JosephDuffy/action,它会action像我在其他用户的位置一样执行,同时1/JosephDuffy/action显示“编辑您的个人资料”链接,忽略该操作,因为它不等于“编辑”。
希望这是一件愚蠢的事情(我猜这是我写得不好的 RewriteRules 的错),但绝不是这样,谢谢你的阅读。

4

1 回答 1

1

为什么它会这样工作?

正则表达式是贪婪的,它们试图尽可能地适合您的正则表达式,因此您users/1/1/1/1/JosephDuffy/befriend非常适合 pattern users/([^.]+)/([^.]+)/([^.]+)。TBH 我不知道为什么[^.]+似乎与.+符号相同,这让我最想知道,但是......


怎么修

如果你想解决这个问题,使它只适合users/1/JosephDuffy/befriend你需要把正则表达式模式作为

^users/([^/]+)/([^/]+)/([^/]+)$ users.php?userid=$1&displayname=$2&action=$3

并分别更改所有其余的重写。注意([^/]+)那里的符号,这意味着我们找到之前的所有字符/


我会做什么

如上所述,我仍然会考虑接受“任何类型的 URL”,然后在 PHP 端进行解析(使用preg_split)。所以 URL 重写将非常简单:

RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)$ users.php?url=$1 [QSA,L]

然后在代码中我会

$paramsAndValues = preg_split('#/#',$_GET['url']);

这是最简单的,但当然你要检查是否$_GET['url']存在等等。

于 2012-06-04T13:53:33.607 回答