One solution might be to directly restrict access to the file on the server, but utilize a url rewrite
to display the content — only if the id matches in the request. Obviously this doesn’t answer every question in the scenario but it does provide a proof-of-concept to indirectly convert a url into a file.
When you upload a file you could store a reference in the user metadata
instead of having to track custom folders of content.
This essentially provides access to this file:
http://example.dev/wp-content/uploads/2015/12/8-1200x675.jpg
If user ID 1 is requesting access and is logged in
http://example.dev/api/file/1/2015/12/8-1200x675.jpg
<?php
if ( ! class_exists( 'FileRequest' ) ):
class FileRequest {
const ENDPOINT_QUERY_NAME = 'api/file';
const ENDPOINT_QUERY_PARAM = '__api_file';
// WordPress hooks
public function init() {
add_filter( 'query_vars', array ( $this, 'add_query_vars' ), 0 );
add_action( 'parse_request', array ( $this, 'sniff_requests' ), 0 );
add_action( 'init', array ( $this, 'add_endpoint' ), 0 );
}
// Add public query vars
public function add_query_vars( $vars ) {
// add all the things we know we'll use
$vars[] = static::ENDPOINT_QUERY_PARAM;
$vars[] = 'file';
$vars[] = 'user';
return $vars;
}
// Add API Endpoint
public function add_endpoint() {
add_rewrite_rule( '^' . static::ENDPOINT_QUERY_NAME . '/([^/]*)/(\S+)/?', 'index.php?' . static::ENDPOINT_QUERY_PARAM . '=1&user=$matches[1]&file=$matches[2]', 'top' );
//////////////////////////////////
flush_rewrite_rules( false ); //// <---------- REMOVE THIS WHEN DONE
//////////////////////////////////
}
// Sniff Requests
public function sniff_requests( $wp_query ) {
global $wp;
if ( isset(
$wp->query_vars[ static::ENDPOINT_QUERY_PARAM ],
$wp->query_vars[ 'file' ],
$wp->query_vars[ 'user' ] ) ) {
$this->handle_request(); // handle it
}
}
// Handle Requests
protected function handle_request() {
global $wp;
$file = $wp->query_vars[ 'file' ];
$user = $wp->query_vars[ 'user' ];
// make sure the request ID is the same as the logged in user
if ( ''.get_current_user_id() !== $user ){
wp_send_json_error( array (
'message' => 'Unauthorized',
'error' => '401',
) );
}
else {
// add the file request to the uploads directory
$upload_dir = wp_upload_dir();
$path = $upload_dir['basedir']."https://wordpress.stackexchange.com/".$file;
// make sure url is readable -- if not, stop!
if ( ! is_readable( $path ) ) {
wp_send_json_error( array (
'message' => 'Bad Request',
'error' => '400',
) );
}
// get files contents
$file_content = file_get_contents( $path );
// get the mime type for headers
$type = get_post_mime_type( $file_content );
// output headers
nocache_headers();
header( "Content-type: $type;" );
header( "Content-Length: " . strlen( $file_content ) );
// output file data
echo $file_content;
}
die();
}
}
$wpFileRequest = new FileRequest();
$wpFileRequest->init();
endif; // FileRequest