笔者借助宝塔面板,通过反向代理,使得 http://www.bbb.com/
单独对应博客页 http://www.aaa.com/ccc/
💬相关
详情可以查看前一篇博客《不同域名对应WordPress网站不同页面》
https://blog.csdn.net/weixin_42077074/article/details/123134062
但随后笔者发现,WordPress 网站需要密码的文章无法核对密码了,输入密码提交后直接白屏
折腾了半天,终于发现了两个问题
- 页面跳转——涉及 PHP 获取请求 URL 和 WordPress 跳转函数
- 密码核对——涉及 cookie 作用域机制
在服务器上找到 WordPress 站点目录,如笔者的是 /www/wwwroot/[站点文件名]
输入密码并提交后,WordPress 会到目录下 wp-login.php
中通过 case 'postpass':
底下的代码进行后续处理,本文将从此处入手
页面跳转——涉及 PHP 获取请求 URL 和 WordPress 跳转函数
输入文章密码并提交后,WordPress 会跳转到 wp-login.php
进行后续处理,并通过PHP 中 $_SERVER['HTTP_REFERER']
获取请求 URL(跳转前的 URL)
然而,经反向代理后,$_SERVER['HTTP_REFERER']
只能获取到 http://www.bbb.com
,没法获取到 http://www.bbb.com/[页面名及其他参数]
,笔者也不太懂是什么原因
那就需要添加代码获取完整的请求 URL,因而我们需要对文章填写密码的表单相关代码进行简单的修改
其对应于 wp-includes/post-template.php
中的 get_the_password_form()
函数,我们将整段函数替换成下面的代码
function get_the_password_form( $post = 0 ) {
$_request_uri=substr($_SERVER['REQUEST_URI'],strpos($_SERVER['REQUEST_URI'],'/',1)+1);
$post = get_post( $post );
$label = 'pwbox-' . ( empty( $post->ID ) ? rand() : $post->ID );
$output = '<form action="' . esc_url( site_url( 'wp-login.php?action=postpass' . '&requri=' . $_request_uri, 'login_post' ) ) . '" class="post-password-form" method="post">
<p>' . __( 'This content is password protected. To view it please enter your password below:' ) . '</p>
<p><label for="' . $label . '">' . __( 'Password:' ) . ' <input name="post_password" id="' . $label . '" type="password" size="20" /></label> <input type="submit" name="Submit" value="' . esc_attr_x( 'Enter', 'post password form' ) . '" /></p></form>
';
/**
* Filters the HTML output for the protected post password form.
*
* If modifying the password field, please note that the core database schema
* limits the password field to 20 characters regardless of the value of the
* size attribute in the form input.
*
* @since 2.7.0
* @since 5.8.0 Added the `$post` parameter.
*
* @param string $output The password form HTML output.
* @param WP_Post $post Post object.
*/
return apply_filters( 'the_password_form', $output, $post );
}
笔者做出的修改是,$_request_uri
获取 [页面名及其他参数]
,随后作为参数将其附加在表单跳转到 wp-login.php
的 URL 中
随后找到 wp-login.php
,在 case 'postpass':
底下,找到 $referer = wp_get_referer();
代码并删掉,再在 case 'postpass':
底下开头添加下面的代码
$pos1=strpos($_SERVER['HTTP_REFERER'],'/')+2;
$pos2=strpos($_SERVER['HTTP_REFERER'],'.');
$pos3=strpos($_SERVER['HTTP_REFERER'],'/',$pos1);
$refer_domain=substr($_SERVER['HTTP_REFERER'],$pos1,$pos3-$pos1);//获取请求域名
$refer_page_name=substr($refer_domain,0,$pos2-$pos1);//获取请求域名中最低级的域名作为页面名
$request_uri=$_REQUEST['requri'];
if($refer_page_name =='blog') $isDomainAllowed=true;//此处blog可以换成任意你域名中最低级的域名作为页面名
else $isDomainAllowed=false;
这意为从通过 $_REQUEST[]
获取此前附加在 URL 里的参数 [页面名及其他参数]
,并将原先的 $referer
经过处理,变成完整的请求 URL
随后你还能在 case 'postpass':
底下找到两处 wp_safe_redirect($referer);
wp_safe_redirect()
是 WordPress 的跳转函数,它跳转时会判断 URL 是否在同一域名下,因而我们需要将两处它都替换成以下代码
if($isDomainAllowed) wp_redirect($referer);
else wp_safe_redirect( $referer);
💬相关
详细
wp_safe_redirect()
介绍可查看博客《wordpress安全重定向跳转函数wp_safe_redirect()》http://www.thefox.cn/wordpress-security-redirection-jump-fu.shtml
密码核对——涉及 cookie 作用域机制
假如一篇文章需要密码,那当你输入文章密码并提交后,WordPress 会将其记录在 cookie 中,随后读取 cookie 记录进行判断,以便让你在一段时间 expire
内不需要重复输入密码
具体则是在 wp-login.php
中 case 'postpass':
底下的这段代码
setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure );
cookie 中有一项 domain
,规定了 cookie 的作用域,默认是当前域,且只能设置为当前域或当前域的上级域
举个例子,一个在 yyy.xxx.com
的页面,可以设置 cookie 的 domain
为 yyy.xxx.com
或 xxx.com
,domain
为 yyy.xxx.com
的 cookie 只能被访问于 yyy.xxx.com
,若 domain
为 xxx.com
的 cookie,则可以在 xxx.com
的任意下级域被访问
💬相关
详细 cookie 作用域机制可以查看博客《php怎么设置cookie作用域?》
https://www.php.cn/php-ask-456517.html
假如反向代理使用 http://ddd.aaa.com/
单独对应博客页 http://www.aaa.com/ccc/
,但实际上还是相当于 www.aaa.com
在访问页面,在 PHP 中使用 setcookie()
函数设置 cookie 时无法将 cookie 的 domain
设置为 ddd.aaa.com
, domain
还是 www.aaa.com
WordPress 密码核对涉及在 wp-includes/post-template.php
中的post_password_required()
函数,其中有相关访问cookie的代码,经查阅代码发现ddd.aaa.com
根本访问不到domain
为www.aaa.com
的cookie
那应该怎么改?那就只能在最开始设置cookie时,不默认设置为当前域www.aaa.com
,而设置为上级域 aaa.com
,那 ddd.aaa.com
也就可以访问到该 cookie 了
那我们需要将 setcookie()
替换成下述代码
if($isDomainAllowed) $cookie_domain=substr($_SERVER['SERVER_NAME'],strpos($_SERVER['SERVER_NAME'],'.')+1);//获取当前域的上级域
else $cookie_domain=COOKIE_DOMAIN;
setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, $cookie_domain, $secure );
随后,折腾许久,终于解决反向代理后,WordPress 网站需要密码的文章无法核对密码的问题了,大!功!告!成!
最后,附上经本文修改后,wp-login.php
中 case 'postpass':
到 case 'logout':
这一段完整代码
case 'postpass':
$pos1=strpos($_SERVER['HTTP_REFERER'],'/')+2;
$pos2=strpos($_SERVER['HTTP_REFERER'],'.');
$pos3=strpos($_SERVER['HTTP_REFERER'],'/',$pos1);
$refer_domain=substr($_SERVER['HTTP_REFERER'],$pos1,$pos3-$pos1);//获取请求域名
$refer_page_name=substr($refer_domain,0,$pos2-$pos1);//获取请求域名中最低级的域名作为页面名
$request_uri=$_REQUEST['requri'];
if($refer_page_name =='blog') $isDomainAllowed=true;
else $isDomainAllowed=false;
if($isDomainAllowed) $referer = $_SERVER['HTTP_REFERER'] . $request_uri;
else $referer = wp_get_referer();
if ( ! array_key_exists( 'post_password', $_POST ) ) {
if($isDomainAllowed) wp_redirect( $referer);
else wp_safe_redirect( $referer);
exit;
}
require_once ABSPATH . WPINC . '/class-phpass.php';
$hasher = new PasswordHash( 8, true );
/**
* Filters the life span of the post password cookie.
*
* By default, the cookie expires 10 days from creation. To turn this
* into a session cookie, return 0.
*
* @since 3.7.0
*
* @param int $expires The expiry time, as passed to setcookie().
*/
$expire = apply_filters( 'post_password_expires', time() + 10 * DAY_IN_SECONDS );
if ( $referer ) {
$secure = ( 'https' === parse_url( $referer, PHP_URL_SCHEME ) );
} else {
$secure = false;
}
if($isDomainAllowed) $cookie_domain=substr($_SERVER['SERVER_NAME'],strpos($_SERVER['SERVER_NAME'],'.')+1);//获取当前域的上级域
else $cookie_domain=COOKIE_DOMAIN;
setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, $cookie_domain, $secure );
if($isDomainAllowed) wp_redirect( $referer);
else wp_safe_redirect( $referer);
exit;
case 'logout':