PHP URL参数重定向-使用通配符/正则表达式
我最近found this solution做php url变量到头位置重定向。
与用于批量重定向的htaccess相比,它更易于管理,然而,我接下来要解决的一件事是,我如何使用正则表达式来实现您可以使用htaccess在请求/(.*)去往目的地/$1的情况下所能做的事情。
我的理解是您使用了preg_Match或preg_place或其他什么。我如何才能做到下面这样的事情,如果可能的话,最好是这样简短。(我知道这是错误的,顺便说一句,只是为了说明原因)。
preg_match($redirects['request(.*)'] = "$domain/destination/1");
基本上,假设我要将doma.in/pics
重定向到domain.tld/pictures
,我让htaccess将其重定向到doma.in/index?req=pics
,其中index是脚本文件,req是使用的参数。
然后使用脚本,我有一行类似$redirects['pics'] = "$domain/pictures";
的代码,其中$domain
变量绑定到http://domain.tld
。
这很好用,但是我想用正则表达式更进一步,将pics/*stuff*
,也就是doma.in/index?req=pics/*stuff*
发送到$domain/pictures/*stuff*
。
这里有一个使用此脚本执行多次重定向的示例。
$redirects['request'] = "$domain/dest";
$redirects['request2'] = "$domain/dest2";
$redirects['request3'] = "$domain/dest3";
尽管我已经链接了顶部的帖子,我得到了我正在使用的脚本,但以下是代码:
if(isset($_GET['req']) && isset($redirects[$_GET['req']])) {
$loc = htmlspecialchars($redirects[$_GET['req']]);
header("Location: " . $loc);
exit();
}
header("Location: $domain");
我在包含的文件中包含了$reDirects行,这些行包含在这上面。
解决方案
已更新脚本
我彻底修改了这个脚本,现在我更多地意识到这是我们在这里做的所有数组,每个重定向都只是添加到它上面。此外,我还学到了更多关于函数的知识,现在它非常便携,同时还可以做更多的事情。
这里是完整的新脚本。和前一次相比,这是一只野兽,但前一次太乱了。
function redirects($config) { // Create a redirects(); function with the inputted array set as $config
// Config Variables
$req = $config['param']; // Assign $req to the $config param value
$dir = $config['dir']; // Assign $dir to the $config dir value
$domain = $config['domain']; // Assign $domain to the $config domain value
$_404 = $config['404']; // Assign $_404 to this $config 404 value
$_referer = $config['referer']; // Assign $referer_ to the referer value
$referer = 'referer='.$_referer; // Assign $referer to the full referer param
if (isset($_GET[$_referer])) {
if ($_GET[$_referer] == $_referer) { // If this script's referer exists,
echo "Do not loop back to the script!"; // Throw a warning
exit(); // & exit
} // Otherwise continue
}
if (isset($_GET[$req]) && !empty($_GET[$req])) { // If a req parameter exists & isn't empty, continue
$req = $_GET[$req]; // Assign $req to $_GET[$req]
// Create the arrays
$redirects = $wildcards = $halfwilds = array(); // Create the arrays needed, so if there's not at least one redirect done, which would be what creates the array otherwise, there won't be a 500 error due to it.
// Redirect includes
foreach (glob($dir) as $filename) { // Search for all redirect php files at $dir location
include $filename; // Include those files
}
// Leading & Trailing Slashes
$req = '/'.trim($req, '/').'/'; // Add a leading & trailing slash to $req param if non existent
function redir_editkeys($array) { // Create an editkeys(); function and pass the specified array as $array
$keys = array_keys($array); // Extract the keys of the array as values of $keys array
foreach ($keys as &$value) {
$value = '/'.trim($value, '/').'/'; // Add a leading & trailing slash to $keys values if non existent
}
return array_combine($keys, $array); // Replace the original array's keys with the modified keys & return
}
// Referer
function referer($redir, $referer, $domain) { // Create a referer(); function and pass to it $redir, $referer, & $domain.
if (strpos($redir, $domain) !==false) { // Using $domain, check $redir for a match.
$redir = $redir.'?'.$referer; // If there's a match, add the referer param
} return $redir; // Return the edited $redir, or if no match, return without editing
}
// Redirects
$redirects = redir_editkeys($redirects); // Edit $redirects keys using editkeys();
if (isset($redirects[$req])) { // Check that $redirects[$req] exists
$redir = $redirects[$req]; // Assign $redir to $redirects[$req];
$redir = referer($redir, $referer, $domain); // If it does, run referer();
header("Location: $redir"); // & Redirect
exit();
}
// Wildcards
$wildcards = redir_editkeys($wildcards); // Edit $wildcards keys using editkeys();
foreach ($wildcards as $key => $value) { // Assign variables to $wildcards keys & values
if (strpos($req, $key) !== false) { // Using $key, check $req for a match
$wild = substr($req, strlen($key)); // Extract everything after the match as $wild
$req = substr($req, 0, strlen($key)); // Extract the matching part at the beginning as $req
if (isset($wildcards[$req])) { // Check that $wildcards[$req] exists
$redir = $wildcards[$req]; // Assign $redir to $wildcards[$req]
$redir = $redir.$wild; // Attach $wild onto $redir
$redir = referer($redir, $referer, $domain); // If it does, run referer();
header("Location: $redir"); // & Redirect
exit();
}
}
}
// Half Wilds
$halfwilds = redir_editkeys($halfwilds); // Edit $halfwilds keys using editkeys();
foreach ($halfwilds as $key => $value) { // Assign variables to $halfwilds keys & values
if (strpos($req, $key) !== false) { // Using $key, check $req for a match
$req = substr($req, 0, strlen($key)); // Extract the matching part at the beginning as $req
if (isset($halfcards[$req])) { // Check that $halfwilds[$req] exists
$redir = $halfwilds[$req]; // Assign $redir to $halfwilds[$req]
$redir = referer($redir, $referer, $domain); // If it does, run referer();
header("Location: $redir"); // & Redirect
exit();
}
}
}
// 404
$req = "req=".trim($req,'/')."&"; // Attach the param name to the $req value for the 404 redirect if it's not empty and remove the slashes.
}
else { $req = ''; } // If no req param, or if empty, unset $req
header("Location: ".$domain.$_404."?".$req.$referer); // If there's no match, redirect to this location.
}
我们按以下条件调用此脚本:
redirects(
array( // Config
'param' => 'req', // Param name || Set the name of the url param. Here it is "req".
'dir' => 'redirects/*/*.php', // Redirect file(s) location || Set the location to look for the file(s) you store your redirects. Here I have my files in sub folders of a rediects folder. Do not put a leading slash infront, use "../" etc as it must be relative, not absolute..
'domain' => 'http://domain.tld', // Your domain || Set your website's domain name here. This'll be used to check whether redirects go to it and if the referer is needed.
'404' => '/', // 404 location || Set the location 404s will go to. Hereit is just my homepage, so I've put "/".
'referer' => 'redirector' // Referer param || Set the value of the referer param that will be used in redirects to the same site so we can stop 404s resulting in a loop.
)
);
要执行简单的重定向,我们可以这样做:
$redirects['request1'] = "$domain/dest1";
$redirects['request2'] = "$domain/dest2";
要使用通配符,我们可以这样做:(确保在末尾添加尾随斜杠,除非它是目标,如查询字符串)
$wildcards['request3'] = "$domain/dest3/";
$wildcards['request4'] = "$domain/dest4/";
和我还添加了半个通配符,所以如果您只想将request5/anypath
发送到$domain/dest5
,而不是dest5/anypath
,我们可以这样做:
$halfwilds['request5'] = "$domain/dest5";
$halfwilds['request6'] = "$domain/dest6";
让我们将其分成块,看看每个部分都在做什么:
- 配置:
首先,我们使用
$config
数组作为参数启动redirects();
函数。然后我们将变量分配给每个设置。
function redirects($config) { // Create a redirects(); function with the inputted array set as $config
// Config Variables
$req = $config['param']; // Assign $req to the $config param value
$dir = $config['dir']; // Assign $dir to the $config dir value
$domain = $config['domain']; // Assign $domain to the $config domain value
$_404 = $config['404']; // Assign $_404 to this $config 404 value
$_referer = $config['referer']; // Assign $referer_ to the referer value
$referer = 'referer='.$_referer; // Assign $referer to the full referer param
我们有两个用于Referer的变量,一个用于Referer值,另一个作为完整参数加入以在重定向中使用。
- 推荐人检查
我首先检查请求中是否存在此脚本的引用参数,只需说"Do not loop back to the script!"
,然后exit();
脚本。
if (isset($_GET[$_referer])) {
if ($_GET[$_referer] == $_referer) { // If this script's referer exists,
echo "Do not loop back to the script!"; // Throw a warning
exit(); // & exit
} // Otherwise continue
}
- 数组和包含
接下来,如果请求中的Referer参数没有匹配项,当请求参数存在且不为空时,我们打开一个if,创建空数组,然后包括我们在配置中声明的放置重定向的位置。
if (isset($_GET[$req]) && !empty($_GET[$req])) { // If a req parameter exists & isn't empty, continue
$req = $_GET[$req]; // Assign $req to $_GET[$req]
// Create the arrays
$redirects = $wildcards = $halfwilds = array(); // Create the arrays needed, so if there's not at least one redirect done, which would be what creates the array otherwise, there won't be a 500 error due to it.
// Redirect includes
foreach (glob($dir) as $filename) { // Search for all redirect php files at $dir location
include $filename; // Include those files
}
根据我对php工作方式的理解,将Includes放在IF中实际上有一个好处,即如果不满足条件,则甚至不会处理Includes。
- 前导&;尾随斜杠
对于前面的脚本,我们必须确保在重定向键的末尾添加了斜杠,并在参数末尾添加了斜杠向脚本发送请求。让我们通过使用trim();
来消除这样做的需要,因为如果它存在,则将其与添加回来混合在一起,并加上一个前导斜杠,以确保当我们想要查找‘Dog/’时,strpos();
不会与‘CAT-Dog/’匹配。
// Leading & Trailing Slashes
$req = '/'.trim($req, '/').'/'; // Add a leading & trailing slash to $req param if non existent
function redir_editkeys($array) { // Create an editkeys(); function and pass the specified array as $array
$keys = array_keys($array); // Extract the keys of the array as values of $keys array
foreach ($keys as &$value) {
$value = '/'.trim($value, '/').'/'; // Add a leading & trailing slash to $keys values if non existent
}
return array_combine($keys, $array); // Replace the original array's keys with the modified keys & return
}
这里我们创建了一个名为editkeys();
的函数,它为您传递给它的任何数组的键创建一个新的数组,执行Foreach来修改这些键,然后将它们放回原始数组中,替换原始的键。
- 目标域检查是否需要引用参数
如果我们将目的地的404请求发送到脚本,我们希望停止以404结尾的到该目的地的重定向循环。我们可以只添加Referer参数,但这可能会根据目的地的网站配置对查询字符串的处理而出现问题。因此,让我们做一个函数来检查传递的目的地是否去往
$domain
,如果为真,则向其添加Referer并返回它。
// Referer
function referer($redir, $referer, $domain) { // Create a referer(); function and pass to it $redir, $referer, & $domain.
if (strpos($redir, $domain) !==false) { // Using $domain, check $redir for a match.
$redir = $redir.'?'.$referer; // If there's a match, add the referer param
} return $redir; // Return the edited $redir, or if no match, return without editing
}
- 重定向
下一步是将重定向组合在一起。首先,我们有简单的重定向。首先,我们通过editkeys();
函数运行$redirects
数组,然后它检查匹配的键是否在数组中,在目标上运行上面的referer();
函数,然后重定向到它。
// Redirects
$redirects = redir_editkeys($redirects); // Edit $redirects keys using editkeys();
if (isset($redirects[$req])) { // Check that $redirects[$req] exists
$redir = $redirects[$req]; // Assign $redir to $redirects[$req];
$redir = referer($redir, $referer, $domain); // If it does, run referer();
header("Location: $redir"); // & Redirect
exit();
}
第二个是通配符。我们通过editkeys();
函数运行$wildcards
数组,对该数组运行foreach();
以查找匹配键,将匹配后的所有内容获取为$wild
,仅获取匹配的$req
,检查$req
值是否作为数组中的键存在,获取该键的目的地,附加$WildOn,然后运行检查以确定是否需要Referer、重定向和bam。
// Wildcards
$wildcards = redir_editkeys($wildcards); // Edit $wildcards keys using editkeys();
foreach ($wildcards as $key => $value) { // Assign variables to $wildcards keys & values
if (strpos($req, $key) !== false) { // Using $key, check $req for a match
$wild = substr($req, strlen($key)); // Extract everything after the match as $wild
$req = substr($req, 0, strlen($key)); // Extract the matching part at the beginning as $req
if (isset($wildcards[$req])) { // Check that $wildcards[$req] exists
$redir = $wildcards[$req]; // Assign $redir to $wildcards[$req]
$redir = $redir.$wild; // Attach $wild onto $redir
$redir = referer($redir, $referer, $domain); // If it does, run referer();
header("Location: $redir"); // & Redirect
exit();
}
}
}
然后我们有一半的通配符,它们的作用大致相同。我自己真的没有任何真正的理由这样做,但肯定有原因,比如你已经摆脱了整个投资组合图库,想要发送请求到那个和子请求的图像等回到投资组合,这将完成工作。因此它是脚本中包含的一部分。
// Half Wilds
$halfwilds = redir_editkeys($halfwilds); // Edit $halfwilds keys using editkeys();
foreach ($halfwilds as $key => $value) { // Assign variables to $halfwilds keys & values
if (strpos($req, $key) !== false) { // Using $key, check $req for a match
$req = substr($req, 0, strlen($key)); // Extract the matching part at the beginning as $req
if (isset($halfcards[$req])) { // Check that $halfwilds[$req] exists
$redir = $halfwilds[$req]; // Assign $redir to $halfwilds[$req]
$redir = referer($redir, $referer, $domain); // If it does, run referer();
header("Location: $redir"); // & Redirect
exit();
}
}
}
我确实想试着做一个函数来保存这个大量重复的代码,但foreach();
太笨拙了。
- 404
然后,我们有404重定向,它将任何与请求参数不匹配的请求发回给脚本,或者如果没有请求参数或它是空的,则只与Referer参数匹配。
// 404
$req = "req=".trim($req,'/')."&"; // Attach the param name to the $req value for the 404 redirect if it's not empty and remove the slashes.
}
else { $req = ''; } // If no req param, or if empty, unset $req
header("Location: ".$domain.$_404."?".$req.$referer); // If there's no match, redirect to this location.
}
这就是剧本。
现在,将死请求发送到脚本。
apache/litespeed/oplitespeed(Htaccess)
在您的htaccess底部添加以下内容:
############# Rewrite dead requests to redirector with uri as query
RewriteCond %{QUERY_STRING} !referer=redirector [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /redirect.php?req=$1 [R=301,L]
#############
Nginx
将此代码添加到服务器的(Vhost)conf:
############# Send dead requests to redirector with uri as query
error_page 404 = @redirects;
location @redirects {
if ($query_string !~ referer=redirector {
rewrite ^/(.*)(.php?) /redirect.php?req=$1 redirect;
}
}
#############
我现在使用nginx,不再使用OpenLitespeed,因为出现了一个奇怪的问题,而nginx根本没有这个问题。所以,弄清楚Nginx Conf的做事方式是很有趣的。我注意到的一件事是,通过重写没有扩展的扩展请求,发送到其他地方的请求在末尾添加了.php。所以我在重写时排除了这个扩展名。与尝试在if
中设置忽略现有文件/文件夹相比,在error_page 404
的位置执行这些通配符重定向要容易得多。
正在目标上删除请求的引用参数。
在尝试对nginx执行与我对htaccess所做的相同操作时,删除引用参数,这是我尝试尝试的乐趣所在,但我意识到这无论如何都是一个有一点缺陷的解决方案,因为它删除了整个查询。 取而代之的是使用PHP,此函数就是为了实现这一点,删除了单个参数:
function strip_param($url,$param) {
if (isset($_GET[$param])) { // Check that param exists
$base_url = strtok($url,'?'); // Get the base url
$parsed_url = parse_url($url); // Parse it
$query = $parsed_url['query']; // Get the query string
parse_str($query,$params); // Convert parameters into array
unset($params[$param]); // Delete the one you want
$new_query = http_build_query($params); // Rebuild query string
$new_url = $base_url.'?'.$new_query; // Rebuild the url
$url = rtrim($new_url,'?'); // If now no query, remove ending ?
return header("Location: $url"); // Redirect
}
}
// How to use
//
// Place the above function anywhere you include above content of where you need it, such as a functions file.
// The below, put this somewhere at the top before content.
// Strip params from requests
strip_param($webpage_URI,'referer'); // The $webpage_URI value is: "https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
此函数我们可以give props to this person for。 这就是为什么我开始按照评论的方式克隆它。这是一种如此整洁、可读性强的做事方式。尽管我以前的剧本很短,但它并不整洁,也不是很甜蜜。但是,哦,我很高兴现在有了功能。非常推荐!!
再次感谢Mick提供的几条改进这一点的技巧。
我对500个错误有一点兴趣,因为当我决定将这一半通配符命名为$half_wildcards
而不是$wildcards_half
时,我搞砸了,我没有更新所有的通配符。我现在将其更改为$halfwilds
,因为我突然想到它,这是与$wildcards
和$redirects
相同的字符数,所以这是非常好的一致性。它也使它更具区分性,这反过来只会让事情变得不那么混乱。
$wildcards
或$redirects
使用这个词,或者在我的情况下,两者都使用,但不是$halfwilds
..如果不存在关联数组的重定向,则不会创建该数组,这将导致500。因此,我已经创建了空数组,因此它们将始终存在,不会导致错误。
更新了脚本,稍微移动了数组键变量赋值,如果您没有将它们设置为忽略未定义数组和变量等的警告,则它们不会向日志发送垃圾邮件。我现在已将这些日志设置为Critical,因为使用此脚本懒惰是令人讨厌的,但在这里不是这样。在意识到嵌套函数仍然很好地作为全局函数定义它们时,还将编辑键函数名称编辑为
redir_editkeys
。Grr php有它的怪癖。
相关文章