我已经开始深入研究用户页面的干净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
似乎会触发操作befriend
,显示名称为 JosephDuffy
,用户 ID 为 1/1/1/1
。我猜这就是mod_rewrite的工作方式,但它似乎在扔给我一些曲线球。
目前,我在用户 id 上使用 intval()
,这似乎有效但不太理想;我仍然留下多个提供相同信息的 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]
或类似的东西也会更好,但我不确定在哪里,或者为什么真的。
用户.php(有些部分被简化,几乎是psudocode,以使其更容易理解)
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的错),但无论如何,感谢您的阅读。
为什么它会这样工作?
正则表达式是贪婪的,它们试图尽可能适合您的正则表达式,因此您的users/1/1/1/1/JosephDuffy/befriend
非常适合模式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']
是否存在等等。