Skip to content

Instantly share code, notes, and snippets.

@strangerstudios
Last active September 13, 2018 15:19
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save strangerstudios/6599510 to your computer and use it in GitHub Desktop.
Save strangerstudios/6599510 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
<IfModule mod_rewrite.c>
RewriteBase /
RewriteRule ^protected-directory/(.*)$ /?pmpro_getfile=$1 [L]
</IfModule>
# END protected folder lock down
###
*/
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($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-directory/" . $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");
@creativebeacon
Copy link

Question, for line 64 you say to say what levels to check, so between the () do you put the number of the level, or the name of the level? For example, mine is named Pro and that is the only level.

@creativebeacon
Copy link

Nevermind, I looked at your revisions and got my answer. So is this the most updated version?

@ideadude
Copy link

Forked here for updates: https://gist.github.com/ideadude/137bb0d06f8f49fc262c2fad3010c440

Since we changed the strangerstudios GitHub account to an organization, I lost the ability to edit old gists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment