【问题标题】:PHP URL Param redirects - with wildcards/regexPHP URL 参数重定向 - 使用通配符/正则表达式
【发布时间】:2021-11-27 14:04:56
【问题描述】:

我最近found this solution 将 php url 变量做为标头位置重定向。

与用于大规模重定向的 htaccess 相比,它更易于管理,但是我接下来要解决的一件事是,我如何使用正则表达式来实现在 request/(.*) 到 destination/$1 的情况下使用 htaccess 可以做的事情.

我的理解是你使用 preg_match 或 preg_replace 什么的。我怎样才能实现类似下面的东西,如果可能的话,最好保持这样的简短。 (顺便说一句,我知道这是错误的,只是为了举例)。

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 行,我在包含的文件中。

【问题讨论】:

  • 仅供参考,isset() 可以接收多个参数。 htmlspecialchars() 是在将数据添加到 html 文档之前应该调用的,对吗?
  • @mickmackusa 是的,你在最后一个答案中提到了哈哈,这很容易知道。 :) 另外,我将它与 htmlspecialchars 一起使用在这里没有任何意义,因为它没有打印在页面上,但如果是,那么是的,所以我用我更新的脚本把它省略了哈哈。感谢您的大力帮助!

标签: php regex redirect parameters wildcard


【解决方案1】:

这是一篇很长的文章,而且这样做的方式很混乱。请参阅我接受的答案以获得更好的方法。

我认为ltrim() 是我想要的,在其他答案中看到,例如,如果我将 0 指定为要删除的内容,01 将变为 1,001 将变为 01,10 将保留为 10,100 为100 以此类推。然而事实并非如此。相反,它会删除所述字符的所有实例。虽然它不是用斜线做的,但很困惑。

不过这样做是正确的:

if (strpos($get, $req) === 0) {
    $get = substr($get, strlen($req));
}
return $get;

Thanks to this answer for this one liner.

我在这里使用此脚本所做的只是将$redirects['request'] 分配给关联的值,就像任何其他变量值分配一样。并且$_GET['req'] 已经完成了无论参数是什么的工作,所以没有复杂的 preg 或 regex 或任何东西。

所以有了substr(),我们可以使用$_GET['req'] 并执行以下操作:

$req = "pics/";
$get = $_GET['req'];
$wild = strpos($get, $req) === 0
    ? substr($get, strlen($req))
    : $get;

$redirects["pics/$wild"] = "$domain/pictures/$wild";

这需要pics/*stuff* 并删除pics/,所以$wild 的值等于*stuff*,所以我只是在重定向中使用它来制作通配符和taadaa。

这完全是功能性的,但让我们让它变得更好,以节省每次都记住这段代码。

在重定向上方创建一个这样的函数:

function wildcard($req) {
    $get = $_GET['req'];
    return strpos($get, $req) === 0
        ? substr($get, strlen($req))
        : $get;
}

通过调用wildcard('pics/');$req 等于pics/

我们可以在以下重定向中使用它:

$req = "pics/";
$wild = wildcard($req);
$redirects[$req.$wild] = "$domain/pictures/$wild";

这仍然比我希望的要多一些,所以我的想法是在函数中将$req 作为全局调用,如下所示:

function wild() {
    $get = $_GET['req']; global $req;
    return strpos($get, $req) === 0
        ? substr($get, strlen($req))
        : $get;
}

然后像这样进行重定向:

$req = "pics/";
$redirects[$req.wild()] = "$domain/pictures/".wild();

这变成了一个更短的单行。尽管在使用全局变量方面存在冲突,但我只是将其恢复为以前的状态,而不是重复分配 $wild,而是将 $req 放回 wild() 中并让它像这样:

$req = "pics/";    $redirects[$req.wild($req)] = "$domain/pictures/".wild($req);

无论如何,它仍然更短,而且括号为空并没有太大影响。

P.S,这种方法,你想在参数上包含斜杠,这样结果就不会乱了。 为了实现能够将pics 发送到$domain/pictures,我们希望在参数末尾有一个斜杠。在 htaccess 中的重定向规则中,将请求作为参数发送到脚本,在末尾添加一个斜杠。因此,如果您使用的是 Apache 或 Litespeed,您可以在 htaccess 中执行以下操作,将所有请求作为参数发送到您的脚本,并带有斜杠,例如:

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

确保它位于底部,这样它就不会优先于其他规则。

还在脚本中添加了一个预防性rtrim() 以删除标题位置中的尾部斜杠,因此如果您想要链接任何不删除文件链接上的尾部斜杠的内容,它不会进入死链接.同样,斜线没有受到我在顶部发现的行为的影响,这很好。

这是你现在可以拥有的东西。

function wild($req) {
    $get = $_GET['req'];
    return strpos($get, $req) === 0
        ? substr($get, strlen($req))
        : $get;
}

$domain = "http://domain.tld";

// Redirects
$req = "request1/";    $redirects[$req.wild($req)] = "$domain/dest1/".wild($req);
$req = "request2/";    $redirects[$req.wild($req)] = "$domain/dest2/".wild($req);
$req = "request3/";    $redirects[$req.wild($req)] = "$domain/dest3/".wild($req);

// Run Script
if (isset($_GET['req'], $redirects[$_GET['req']])) {
    $loc = htmlspecialchars($redirects[$_GET['req']]);
    header("Location: " . rtrim($loc,"/"));
    exit();
}

// If no match in the redirects, redirect to this location.
header("Location: $domain");

现在,如果目标向脚本发送不存在的请求,则存在一个缺陷,如果将使用通配符保证的目标对于请求不存在,那么返回它会转到脚本并bam 你有一个重定向循环。

我解决此问题的方法是将?referer=doma.in 添加到标头位置的末尾,并在 domain.tld 上的 htaccess 中,使用该查询字符串排除不存在的请求,使其不会重定向回脚本。

所以看起来像:

$loc = htmlspecialchars($redirects[$_GET['req']]).'?referer=doma.in';

并且在 domain.tld 的 htaccess 中,在现有规则上方放置一个 rewritecond 以排除查询字符串:

# Ignore these referer queries
RewriteCond %{QUERY_STRING} !referer=doma.in [NC]

# Send dead requests to doma.in with uri as query
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ http://doma.in/?referer=domain.tld&req=$1/ [R=301,L]

为了更好地衡量,我还在 domain.tld 的重定向上添加了一个引用。

现在,作为奖励,为了隐藏对整理请求的引用查询,让我们在下面添加:

# Send dead requests with referer query to home (or 404 or wherever)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{QUERY_STRING} "referer=" [NC]
RewriteRule (.*) /?req=$1 [R=301,L]

# Remove referer query from requests
RewriteCond %{QUERY_STRING} "referer=" [NC]
RewriteRule (.*) /$1/? [R=301,L]

在删除查询之前,我们需要在某处发送无效的引用查询请求,否则我们会回到第一步。我将请求 uri 作为参数发送到我的主页,以便仍然可以知道请求 url 是什么。

工作完成了。但作为额外的奖励,让我们让外部/非通配符重定向没有查询。所以回到脚本中,把脚本改成这样:

$get = $_GET['req'];
$loc = $redirects[$get];
$wildloc = $wildcards[$get];

// Run Script
if(isset($get) && isset($loc) || isset($wildloc)) {
    if(isset($wildcards[$get])) {
    $loc = rtrim($wildloc,'/').'?referer=hwl.li'; }
    $loc = rtrim(htmlspecialchars($loc),'/');
    header("Location: ".$loc);
    exit();
}

在这里,我将$_GET['req'] 分配给$get$redirects[$get] 分配给$loc$wildcards[$get] 分配给$wildloc 移动了一些东西,并在 issets 中调用它们,以及一个: 之后的额外 isset,又名 OR for $wildloc

然后有一个 if 语句,所以$wildcards 重定向使用分配给$wildloc$loc,而$redirects 使用上面的一个。

这样,我们可以有整洁的重定向。

所以现在情况如下:

// Wildcard function
function wild($req) {
    $get = $_GET['req'];
    return strpos($get, $req) === 0
        ? substr($get, strlen($req))
        : $get;
}

$domain = "http://domain.tld";

// Redirects
$req = "request1/";   $wildcards[$req.wild($req)] = "$domain/dest1/".wild($req);  // A wildcard redirect
$req = "request2/";    $wildcards[$req.wild($req)] = "$domain/dest2/".wild($req);  // A wildcard redirect
$redirects['request3/'] = "$domain/dest3/"; // Not a wildcard redirect

$get = $_GET['req'];
$loc = $redirects[$get];
$wildloc = $wildcards[$get];

// Run Script
if(isset($get) && isset($loc) || isset($wildloc)) {
    if(isset($wildcards[$get])) {
    $loc = rtrim($wildloc,'/').'?referer=hwl.li';}
    $loc = rtrim(htmlspecialchars($loc),'/');
    header("Location: ".$loc);
    exit();
}

// If no match in the redirects, redirect to this location.
header("Location: $domain/?req=$get");

这大大改善了事情并解决了重定向循环。

再次稍微编辑了这个,就像我在这里所做的那样,添加了查询字符串。因此,rtrim() 之后正在寻找一个不存在的斜杠,而不是我们之前希望它在哪里做的。所以现在rtrim() 出现在前面。加倍它有点烦人,但至少它现在可以完成这项工作。

【讨论】:

  • 请注意,isset() 可以接收多个参数。 isset($_GET['req'], $redirects[$_GET['req']])。此外,使用 strpos() 而不明确检查 === false 可能会导致边缘情况下的错误结果。
  • 是的,这也做了想要的事情,从外观上看,它实际上做了同样的事情。 if (strpos($get, $req) === 0) $get = substr($get, strlen($req)); {return $get;}
  • 我在 bad 帖子下留下了评论,并指出了它的问题所在。我也投了反对票并投票删除了旧答案,因为它误导了研究人员。我们绝对不希望将不稳定的答案复制粘贴到新答案中。
  • 我已对您的帖子进行了实质性编辑,以提高编码标准。请查看更改以确保它仍然在说您最初想说的话。如果需要,欢迎您重新编辑。
  • 一般/专业建议是不要使用global。如果您需要一个变量在函数范围内可用,请将其作为参数传递,而不是使用 global
【解决方案2】:

更新脚本

我已经彻底修改了这个脚本,现在我更加意识到这是一个数组,我们在这里所做的每个重定向只是添加到它。我也学到了很多关于函数的知识,现在它非常便携,同时还能做更多的事情。

这是完整的新脚本。和之前比起来简直是一头野兽,但是之前实在是太乱了。

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";

让我们把它分成块,看看每个部分在做什么:


  1. 配置:

首先,我们以$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

我们有两个用于引用的变量,一个用于引用值,第二个作为完整的参数连接起来用于重定向。


  1. 推荐人检查

我首先检查了请求中是否存在此脚本的引用参数,只需简单地说"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
    }

  1. 数组和包含

接下来,如果请求中的referer参数不匹配,当req参数存在且不为空时,我们打开一个if for,创建空数组,然后包含我们在配置中声明的位置'正在放置我们的重定向。

    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 工作方式的理解,这实际上有一个好处,将包含放在 if 中,如果不满足条件,当请求没有 req 参数时,包含不会'甚至没有得到处理。


  1. 前导和尾随斜杠

按照之前脚本的情况,我们必须确保在重定向键的末尾添加斜杠,并在参数末尾使用斜杠向脚本发送请求。让我们通过使用 trim(); 来消除这样做的需要'狗/'。

        // 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 来修改这些键,然后将它们放回原始数组中,替换原来的键。


  1. 目标域检查是否需要引用参数

如果我们将目标的 404 请求发送到脚本,我们希望停止重定向循环以重定向到以 404 结尾的目标。我们可以只添加referer 参数,但这可能会根据该目的地的网站配置对查询字符串的处理而冒出错误的风险。所以让我们做一个函数来检查传递的目的地是否到达$domain,如果为真则添加引用者并将其返回。

        // 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
        }

  1. 重定向

接下来我们有将重定向放在一起的部分。首先,我们有简单的重定向。首先,我们通过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();来寻找匹配的key,得到匹配后的所有东西为$wild,只得到匹配为$req,检查$req 值作为键存在于数组中,获取该键的目的地,附加 $wild,然后运行检查是否需要引用者,重定向和 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(); 的代码实在是太尴尬了。


  1. 404

然后我们有 404 重定向,它将任何与请求不匹配的请求作为 req 参数发送回脚本,或者如果没有 req 参数或如果它为空,则仅与引用参数匹配。

        // 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 / Openlitespeed (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,因为出现了一个 Nginx 根本没有的奇怪问题,因此不再使用 OpenLitespeed。所以弄清楚 Nginx conf 的做事方式很有趣。我注意到的一件事是,通过将扩展请求重写为无扩展,发送到其他地方的请求会在最后添加 .php。因此,我必须在此处的重写中排除扩展名。同样在error_page 404 的位置执行这些通配符重定向,比尝试在if 中设置以忽略现有文件/文件夹要容易得多。


删除目标请求的引用参数。


在尝试对 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。所以我创建了空数组,因此它们将始终存在并且不会导致错误。


更新了脚本,稍微移动了数组键变量分配,因此如果您没有将它们设置为忽略未定义数组和变量等的警告,它们不会向日志发送垃圾邮件。我现在将这些日志设置为关键,因为它很烦人,但在这里对这个脚本懒惰。在意识到嵌套函数仍然可以很好地作为全局定义它们时,还将editkeys函数名称编辑为redir_editkeys。 grr php 有它的怪癖。

【讨论】:

  • 天啊,这是一篇大文章。我需要两杯咖啡,我想我在阅读时错过了一个生日。你已经付出了很大的努力。 if (isset($_GET[$param]) !== false) { 可以是 if (isset($_GET[$param])) {,因为 isset() 只返回一个布尔值。
  • if (strpos($redir, $domain) !==false) { $redir = $redir.'?'.$referer; return $redir; } return $redir; 不需要内部的return -- 条件之后的return 就可以了。此外,$value = '/'.ltrim($value, '/'); $value = rtrim($value, '/').'/'; 可以是 $value = '/' . trim($value, '/') . '/';。您无需覆盖$array,只需覆盖return array_combine($keys, $array);
  • 啊,是的,这是有道理的!不知道我的想法是什么,哈哈,但是是的,完全没有必要加倍,因为如果满足条件,它将作为编辑后的$redir 返回,但是如果不满足,它将是原始的。有点ifs xd
  • 哦,谢谢trim。甜的!而且是的,这对数组组合也很有意义。谢谢你!
  • 我已经更新了您提出的改进,将参数检查更改为 !empty 而不是 isset,因为这样更有意义,所以我可以编辑里面的 $req 值底部的那个条件是完整的参数,所以我只需要一个 404 重定向,所以如果不满足条件,则 no req 参数将被添加到该重定向中。另外,我添加了这样的数组,即使您不执行任何相关的重定向,也会创建数组,否则最终会变成 500,我发现了大声笑。
猜你喜欢
  • 1970-01-01
  • 2019-07-02
  • 1970-01-01
  • 1970-01-01
  • 2015-10-02
  • 1970-01-01
  • 2011-08-04
  • 2020-03-28
  • 2017-01-05
相关资源
最近更新 更多