Skip to content

Instantly share code, notes, and snippets.

@martinbkaiser
Forked from ideadude/my_pmpro_getfile.php
Last active April 2, 2019 22:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinbkaiser/3d3fbd356462d34e923dd45acd186246 to your computer and use it in GitHub Desktop.
Save martinbkaiser/3d3fbd356462d34e923dd45acd186246 to your computer and use it in GitHub Desktop.
How to protect non-WordPress files in a subdirectory of your site using Paid Memberships Pro.
<?php
/*
This code handles loading a file from the /protected-directory/ directory.
(!) Be sure to change line 44 below to point to your protected directory if something other than /protected/
(!) Be sure to change line 64 below to check the levels you need.
(!) Add this code to your active theme's functions.php or a custom plugin.
(!) You should have a corresponding bit of code in your Apache .htaccess file to redirect files to this script. e.g.
###
# BEGIN protected folder lock down
APACHE .htaccess
<IfModule mod_rewrite.c>
RewriteBase /
RewriteRule ^protected-directory/(.*)$ /?pmpro_getfile=$1 [L]
</IfModule>
OR
NGINX RULE
location / {
rewrite ^protected-directory/(.*)$ /?pmpro_getfile=$1 redirect;
}
# END protected folder lock down
###
*/
define('PROTECTED_DIR', 'protected-dir'); //change this to the name of the folder to protect
function my_pmpro_getfile()
{
if(isset($_REQUEST['pmpro_getfile']))
{
global $wpdb;
//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_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())
{
//non-members don't have access (checks for level 2 or 3)
if(!pmpro_hasMembershipLevel())
{
//nope
//header('HTTP/1.1 503 Service Unavailable', true, 503);
//echo "HTTP/1.1 503 Service Unavailable";
wp_redirect(wp_login_url());
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_getfile");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment