例如我的主域www.example.com
这是一个文件共享网站,我们将文件保存在子域中,如server1.example.com
和server2.example.com
与访客共享。我的问题是如何保护子域(子域可能指向不同的服务器或主机)上的文件直接下载而无需在wordpress / mainsite中进行身份验证。
我目前的代码归功于http://wordpress.stackexchange.com/a/37743/12438
.htaccess文件
RewriteCond %{REQUEST_FILENAME} -s
RewriteRule ^wp-content/uploads/(.*)$ dl-file.php?file=$1 [QSA,L]
所以我的整个.htaccess代码看起来像
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
# BEGIN THIS DL-FILE.PHP ADDITION
RewriteCond %{REQUEST_URI} ^.*wp-content/uploads/.*
RewriteRule ^wp-content/uploads/(.*)$ dl-file.php?file=$1 [QSA,L]
# END THIS DL-FILE.PHP ADDITION
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Options -Indexes
但它只能保护wp-content/uploads/*
里面的文件是dl-file.php
<?php
ob_start();
require_once('wp-load.php');
require_once ABSPATH . WPINC . '/formatting.php';
require_once ABSPATH . WPINC . '/capabilities.php';
require_once ABSPATH . WPINC . '/user.php';
require_once ABSPATH . WPINC . '/meta.php';
require_once ABSPATH . WPINC . '/post.php';
require_once ABSPATH . WPINC . '/pluggable.php';
wp_cookie_constants();
$discard = ob_get_clean();
is_user_logged_in() || auth_redirect();
list($basedir) = array_values(array_intersect_key(wp_upload_dir(), array('basedir' => 1)))+array(NULL);
$file = rtrim($basedir, '/') . '/' . (isset($_GET['file']) ? $_GET['file'] : '');
$file = realpath($file);
if ($file === FALSE || !$basedir || !is_file($file)) {
status_header(404);
die('404 — File not found.');
}
if (strpos($file, $basedir) !== 0) {
status_header(403);
die('403 — Access denied.');
}
$mime = wp_check_filetype($file);
if( false === $mime[ 'type' ] && function_exists( 'mime_content_type' ) )
$mime[ 'type' ] = mime_content_type( $file );
if( $mime[ 'type' ] )
$mimetype = $mime[ 'type' ];
else
$mimetype = 'image/' . substr( $file, strrpos( $file, '.' ) + 1 );
header( 'Content-Type: ' . $mimetype ); // always send this
if ( false === strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS' ) )
header( 'Content-Length: ' . filesize( $file ) );
$last_modified = gmdate( 'D, d M Y H:i:s', filemtime( $file ) );
$etag = '"' . md5( $last_modified ) . '"';
header( "Last-Modified: $last_modified GMT" );
header( 'ETag: ' . $etag );
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 100000000 ) . ' GMT' );
// Support for Conditional GET
$client_etag = isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ? stripslashes( $_SERVER['HTTP_IF_NONE_MATCH'] ) : false;
if( ! isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) )
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = false;
$client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
// If string is empty, return 0. If not, attempt to parse into a timestamp
$client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;
// Make a timestamp for our most recent modification...
$modified_timestamp = strtotime($last_modified);
if ( ( $client_last_modified && $client_etag )
? ( ( $client_modified_timestamp >= $modified_timestamp) && ( $client_etag == $etag ) )
: ( ( $client_modified_timestamp >= $modified_timestamp) || ( $client_etag == $etag ) )
) {
status_header( 304 );
exit;
}
// If we made it this far, just serve the file
readfile( $file );
步骤1:
将以下内容添加到所有子域的“.htaccess”中。
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s
RewriteCond %{QUERY_STRING} !key=(FgTyUeL)
RewriteRule ^(.*)$ http://www.example.com/?dwnld_file=server1/$1 [QSA,L]
在上面的代码中,我们将所有文件重定向到主域,除非post参数设置。例如,http://server1.example.com/file.pdf
将被重定向到http://www.example.com/?dwnld_file=server1/file.pdf
。这里server1
是您的子域名,以便识别是否有多个子域名。
在重写条件 - RewriteCond %{QUERY_STRING} !key=(FgTyUeL)
,key
及其值FgTyUeL
应保密,并随意更改为更复杂的字符串。我们将使用它来访问WordPress中的文件。
第2步:
将这些添加到您主题的主域的'functions.php'中。
/* init hook to check whether user logged-in and pass to download function */
add_action( 'init', 'file_init' );
function file_init() {
if ($_REQUEST[ 'dwnld_file' ] != '') {
if ( ! is_user_logged_in() ) { // if not logged-in
auth_redirect(); //redirect to login page
// wp_redirect( 'http://www.example.com/login' ); // or some other page
exit;
}
else {
$spliturl = explode("/",$_REQUEST[ 'dwnld_file' ]);
$originalurl = "http://".$spliturl[0].".example.com/".substr($_REQUEST[ 'dwnld_file' ], strpos($_REQUEST[ 'dwnld_file' ], "/") + 1);
check_download_file( $originalurl ); // if logged-in pass file to download
}
}
}
/* function to download file */
function check_download_file( $url ) {
$key='?key=FgTyUeL'; // secure post key same as .htaccess
$file = basename($url);
$mime = wp_check_filetype( $file );
if( false === $mime[ 'type' ] && function_exists( 'mime_content_type' ) )
$mime[ 'type' ] = mime_content_type( $file );
if( $mime[ 'type' ] )
{
set_time_limit(0);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url.$key);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$curl_response = curl_exec($ch);
curl_close($ch);
header('Expires: 0'); // no cache
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
header('Cache-Control: private', false);
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename="' . basename($url) . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . strlen($curl_response)); // provide file size
header('Connection: close');
echo $curl_response;
die();
}
}
上述功能不言自明 - 我们正在检查WordPress身份验证,如果登录用户,我们将附加安全密钥并使用cURL下载文件。请注意,安全密钥应与子域的“.htaccess”文件中的密钥相同。
如果文件位于子域的任何文件夹中,甚至跨越不同的域(但应该可公开访问),则上述逻辑将起作用。
将受保护的文件放在网站公共可访问区域之外的私人文件夹中。然后,创建一个下载页面,其中包含url中的文件名或其他内容。然后在该页面上,进行身份验证:
is_user_logged_in() || auth_redirect();
// open file
// send headers
// echo contents