-
-
Save dwanjuki/3ada1973e38ee8ad57cf26e722260f4b to your computer and use it in GitHub Desktop.
Limit User Fields file uploads access to administrators and uploader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* Restrict access to files uploaded via User Fields | |
* Allow access to only the file uploader and administrators | |
* | |
* Based on: https://www.paidmembershipspro.com/locking-non-wordpress-files-folders-paid-memberships-pro/ | |
* | |
* You can add this recipe to your site by creating a custom plugin | |
* or using the Code Snippets plugin available for free in the WordPress repository. | |
* Read this companion article for step-by-step directions on either method. | |
* https://www.paidmembershipspro.com/create-a-plugin-for-pmpro-customizations/ | |
* | |
*/ | |
/* | |
You should have the following rules at the top of your .htaccess file to redirect files to this script | |
### | |
# BEGIN protected folder lock down | |
<IfModule mod_rewrite.c> | |
RewriteBase / | |
RewriteRule ^wp-content/uploads/pmpro-register-helper/(.*)$ /index.php?pmpro_uf_getfile=$1 [L] | |
</IfModule> | |
# END protected folder lock down | |
### | |
*/ | |
/* | |
If you are running a NGINX server or proxy, include this directive in your site's nginx.conf | |
### | |
# BEGIN protected folder lock down | |
rewrite ^/wp-content/uploads/pmpro-register-helper/(.*)$ /index.php?pmpro_uf_getfile=$1 last; | |
# END protected folder lock down | |
### | |
*/ | |
define('PROTECTED_DIR', 'wp-content/uploads/pmpro-register-helper'); | |
function my_pmpro_user_fields_getfile() | |
{ | |
if(isset($_REQUEST['pmpro_uf_getfile'])) | |
{ | |
global $wpdb, $current_user; | |
//prevent loops when redirecting to .php files | |
if(!empty($_REQUEST['noloop'])) | |
{ | |
status_header( 500 ); | |
die("This file cannot be loaded through the get file script."); | |
} | |
$uri = $_REQUEST['pmpro_uf_getfile']; | |
if(!empty($uri) && $uri[0] == "/") | |
$uri = substr($uri, 1, strlen($uri) - 1); | |
/* | |
Remove ../-like strings from the URI. | |
Actually removes any combination of two or more ., /, and \. | |
This will prevent traversal attacks and loading hidden files. | |
*/ | |
$uri = preg_replace("/[\.\/\\\\]{2,}/", "", $uri); | |
//edit to point at your protected directory | |
$new_uri = PROTECTED_DIR . '/' . $uri; | |
$filename = ABSPATH . $new_uri; | |
$pathParts = pathinfo($filename); | |
//remove params from the end | |
if(strpos($filename, "?") !== false) | |
{ | |
$parts = explode("?", $filename); | |
$filename = $parts[0]; | |
} | |
//add index.html if this is a directory | |
if(is_dir($filename)) | |
$filename .= "index.html"; | |
//only checking if the file is pulled from outside the admin | |
if(!is_admin()) | |
{ | |
$user_upload_path = end(explode('/', $pathParts['dirname'])); | |
// deny access if user is not logged in, or if the logged in user's username does not match the upload path and they aren't an admin | |
if( $current_user->ID == 0 || ( strpos($user_upload_path, $current_user->user_login) === false && !current_user_can( 'manage_options' ) ) ) | |
{ | |
header('HTTP/1.1 403 Forbidden', true, 403); | |
echo 'Access Forbidden'; | |
exit; | |
} | |
} | |
//get mimetype | |
require_once(PMPRO_DIR . '/classes/class.mimetype.php'); | |
$mimetype = new pmpro_mimetype(); | |
$file_mimetype = $mimetype->getType($filename); | |
//in case we want to do something else with the file | |
do_action("pmpro_getfile_before_readfile", $filename, $file_mimetype); | |
//if file is not found, die | |
if(!file_exists($filename)) | |
{ | |
status_header( 404 ); | |
nocache_headers(); | |
die("File not found."); | |
} | |
//if blacklistsed file type, redirect to it instead | |
$basename = basename($filename); | |
$parts = explode('.', $basename); | |
$ext = strtolower($parts[count($parts)-1]); | |
//build blacklist and allow for filtering | |
$blacklist = array("inc", "php", "php3", "php4", "php5", "phps", "phtml"); | |
$blacklist = apply_filters("pmpro_getfile_extension_blacklist", $blacklist); | |
//check | |
if(in_array($ext, $blacklist)) | |
{ | |
//add a noloop param to avoid infinite loops | |
$uri = add_query_arg("noloop", 1, $uri); | |
//guess scheme and add host back to uri | |
if(is_ssl()) | |
$uri = "https://" . $_SERVER['HTTP_HOST'] . "/" . $uri; | |
else | |
$uri = "http://" . $_SERVER['HTTP_HOST'] . "/" . $uri; | |
wp_redirect($uri); | |
exit; | |
} | |
require_once(PMPRO_DIR . '/classes/class.mimetype.php'); | |
//okay show the file | |
header("Content-type: " . $file_mimetype); | |
readfile($filename); | |
exit; | |
} | |
} | |
add_action("init", "my_pmpro_user_fields_getfile"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment