Skip to content

Instantly share code, notes, and snippets.

@nullvariable
Created September 29, 2020 18:43
Show Gist options
  • Select an option

  • Save nullvariable/2bad7687be2cf2897d86aebc82003d3f to your computer and use it in GitHub Desktop.

Select an option

Save nullvariable/2bad7687be2cf2897d86aebc82003d3f to your computer and use it in GitHub Desktop.
Private Files Example for Pantheon
<?php
/**
* Plugin Name: Example Private Files
* Author: Doug Cone
* Description: Auth for Pantheon Private files
* Version: 0.1.0
*/
/**
* This doesn't protect direct access, you must move your files to a folder not accessible to the public, but accessible to this script.
* On Pantheon, that location is: `/wp-content/uploads/private` (See docs: https://pantheon.io/docs/private-paths)
*
* You will need to move any files uploaded prior to adding this plugin, or fallback to checking the old upload path.
*
* This plugin is all or nothing, you could likely add a per file option leveraging different filters/hooks and the file meta data.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// location that private files will live in.
define( 'PF_UPLOADS', WP_CONTENT_DIR . '/uploads/private' );
// Modify the upload folder to ensure that files cannot be accessed directly.
add_filter( 'upload_dir', 'pf_upload_dir' );
add_action(
'init',
function () {
add_feed( 'priv_files', 'pf_handle' );
}
);
/**
* Filter the upload directory to our private files location.
*
* @param array $uploads the uploads array, see web/wp-includes/functions.php.
* @return array
*/
function pf_upload_dir( $uploads ) {
$path = str_replace( $uploads['basedir'], '', $uploads['path'] );
$uploads['basedir'] = PF_UPLOADS;
$uploads['path'] = PF_UPLOADS . $path;
$uploads['url'] = site_url( '/priv_files?file=' . $path );
$uploads['baseurl'] = site_url( '/priv_files?file=' );
return $uploads;
}
/**
* Add feed handler. Checks auth status and responds accordingly.
*
* @return void
*/
function pf_handle() {
// Something like `current_user_can( 'manage_options' )` here would restrict all file access to admins. `is_user_logged_in()` would just require a user to be logged in.
if ( true === true ) {
$file_to_check = isset( $_GET['file'] ) ? PF_UPLOADS . sanitize_text_field( $_GET[ 'file' ] ) : '';
if ( file_exists( $file_to_check ) ) {
header( 'Content-Type: ' . mime_content_type( $file_to_check ), true, 200 );
// you could/should add a caching header here to encourage the browser to hold on to this file longer.
readfile( $file_to_check ); // phpcs:ignore
exit;
} else {
global $wp_query;
status_header( 404 );
$wp_query->set_404();
nocache_headers();
$template = get_query_template( '404' );
if ( $template ) {
header( 'Content-Type: text/html' );
include $template;
}
exit;
}
} else {
status_header( 403 );
nocache_headers();
// or maybe `wp_safe_redirect( wp_login_url(), 302, 'Private Files' );` instead.
}
}
@nullvariable
Copy link
Copy Markdown
Author

Note that on Pantheon static assets don't count towards your traffic, but requests to php scripts like this do.

@twfahey1
Copy link
Copy Markdown

twfahey1 commented Nov 3, 2020

Awesome, thank you!

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