我最近遇到了一个相关问题,并撰写了有关此问题的文章。
我假定下载是通过WordPress的媒体处理上传的,否则您将拥有下载的附件ID。
解决方案概要
- 使上传目录“安全”(在这个意义上,我只是意味着使用
.htaccess
以阻止任何企图在上传目录直接文件的访问(或其子目录) -例如,通过mysite.com/wp-content/uploads/conf/2012/09/myconfidentialfile.pdf
)
- 创建一个包含附件ID的下载链接-这将通过WordPress检查用户的权限,以查看附件允许/拒绝访问。
注意事项
- 这利用
.htaccess
提供安全性。如果此功能不可用/未启用(例如nginx服务器),那么您将不会获得太大的安全性。您可以防止用户浏览 uplods目录。但是直接访问将起作用。
- 如上所述。如果您需要绝对的安全性,则不应在分发中使用它。如果您的特定设置可行,那就很好-但总的来说,不能保证。我的链接文章部分试图解决此问题。
- 您将松开缩略图。阻止直接访问文件夹或子文件夹将意味着无法查看该文件夹中文件的缩略图。我的链接文章部分试图解决此问题。
阻止直接访问
为此,请在您的上载文件夹(或子文件夹-所有机密材料必须位于该文件夹内的任何深度)内。.htaccess
使用以下文件放置文件:
Order Deny,Allow
Deny from all
在下文中,我假设您将在“客户”类型后附加机密材料。在客户端编辑页面上上传的所有媒体都将存储在该uploads/conf/
文件夹中
设置受保护的上传目录的功能
function wpse26342_setup_uploads_dir(){
$wp_upload_dir = wp_upload_dir();
$protected_folder = trailingslashit($wp_upload_dir['basedir']) . 'conf';
// Do not allow direct access to files in protected folder
// Add rules to /uploads/conf/.htacess
$rules = "Order Deny,Allow\n";
$rules .= "Deny from all";
if( ! @file_get_contents( trailingslashit($protected_folder).'.htaccess' ) ) {
//Protected directory doesn't exist - create it.
wp_mkdir_p( $protected_folder);
}
@file_put_contents( trailingslashit($protected_folder).'.htaccess', $rules );
//Optional add blank index.php file to each sub-folder of protected folder.
}
上载机密资料
/**
* Checks if content is being uploaded on the client edit-page
* Calls a function to ensure the protected file has the .htaccess rules
* Filters the upload destination to the protected file
*/
add_action('admin_init', 'wpse26342_maybe_change_uploads_dir', 999);
function wpse26342_maybe_change_uploads_dir() {
global $pagenow;
if ( ! empty( $_POST['post_id'] ) && ( 'async-upload.php' == $pagenow || 'media-upload.php' == $pagenow ) ) {
if ( 'client' == get_post_type( $_REQUEST['post_id'] ) ) {
//Uploading content on the edit-client page
//Make sure uploads directory is protected
wpse26342_setup_uploads_dir();
//Change the destination of the uploaded file to protected directory.
add_filter( 'upload_dir', 'wpse26342_set_uploads_dir' );
}
}
}
完成此操作后,上传的内容应位于其中,uploads/conf
并且尝试使用浏览器直接访问它应该不起作用。
下载内容
这很容易。下载网址可以是某些内容www.site.com?wpse26342download=5
(其中5是上传内容的附件ID)。我们使用它来识别附件,检查当前用户的权限并允许他们下载。
首先,设置查询变量
/**
* Adds wpse26342download to the public query variables
* This is used for the public download url
*/
add_action('query_vars','wpse26342_add_download_qv');
function wpse26342_add_download_qv( $qv ){
$qv[] = 'wpse26342download';
return $qv;
}}
现在设置一个监听器来(也许)触发下载...
add_action('request','wpse26342_trigger_download');
function wpse26342_trigger_download( $query_vars ){
//Only continue if the query variable set and user is logged in...
if( !empty($query_vars['wpse26342download']) && is_user_logged_in() ){
//Get attachment download path
$attachment = (int) $query_vars['wpse26342download'];
$file = get_attached_file($attachment);
if( !$file )
return;
//Check if user has permission to download. If not abort.
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit();
}
return $query_vars;
}
最后评论
上面的代码可能包含错误/语法错误,并且未经测试,使用时需要您自担风险:)。
可以使用重写“美化”下载URL。如评论中所述,您可以index.php
在受保护的文件夹的每个子文件夹中添加一个空格以防止浏览-但这仍应由.htaccess
规则来防止。
一种更安全的方法是将公共文件存储在公共目录之外。或者在外部服务(如Amazon S3)上。对于后者,您需要生成一个有效的URL才能从Amazon获取文件(使用私钥)。两者都需要对您的主机/第三方服务有一定程度的信任。
我会警惕使用任何暗示它们提供“受保护的下载”的插件。我还没有找到能够提供足够安全性的产品。也请不要对此解决方案提出警告-我欢迎任何建议或批评。