Skip to content

Instantly share code, notes, and snippets.

@dwanjuki
Forked from ideadude/my_pmpro_getfile.php
Last active May 9, 2024 09:25
Show Gist options
  • Save dwanjuki/3ada1973e38ee8ad57cf26e722260f4b to your computer and use it in GitHub Desktop.
Save dwanjuki/3ada1973e38ee8ad57cf26e722260f4b to your computer and use it in GitHub Desktop.
Limit User Fields file uploads access to administrators and uploader
<?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