Skip Navigation

[Resolved] Uploaded files security for current logged user

This support ticket is created 6 years, 1 month ago. There's a good chance that you are reading advice that it now obsolete.

This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.

Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.

Sun Mon Tue Wed Thu Fri Sat
8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 - -
13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 - -

Supporter timezone: America/New_York (GMT-04:00)

Tagged: 

This topic contains 2 replies, has 2 voices.

Last updated by umbertoZ 6 years, 1 month ago.

Assisted by: Christian Cox.

Author
Posts
#1140353

Hi, I've a private area where subscribers can create a "Trader" CPT and upload PDF files in a custom field. What I need is to make PDF privates so that only the logged_in and post author user can open the PDF file using the absolute URL.

I read some posts on the support forum but I didn't find a complete solution. I found "Custom Upload Dir" to create /uploads/ sub-directories for each user, but it hasn't been updated since 3 years and it doesn't fix the security problem.

I tried this code:

function change_upload_dir($dir) {
    if (is_user_logged_in()) {
        global $current_user;
        get_currentuserinfo(); 
        $upload_dir = wp_upload_dir();
        $user_dirname = $upload_dir['basedir'].'/'.$current_user->user_login;
        if ( ! file_exists( $user_dirname ) ) {
            wp_mkdir_p( $user_dirname );
        }
    }
}
add_filter( 'upload_dir', 'change_upload_dir' );

But it is not working, do you see any problem with it?

I also found this approach:
https://wordpress.stackexchange.com/questions/37144/how-to-protect-uploads-if-user-is-not-logged-in

If I can create the users sub-directories, then I could try to intercept URL to /uploads/sub-directories and manage them by PHP to match logged_in current user.

Is this a good approach? Can you help me to set this up?

thanks

#1140598

Hi, Toolset doesn't have any security features built-in for file download restrictions. If someone knows or guesses the URL where the file is stored on your server, they can download it. It's the same way with media files uploaded to the WordPress Media Library. Toolset Access has features built-in that allow you to restrict certain site pages, but not specific files or specific upload URLs. File security is a rather complicated thing to do well. Rather than trying to code a custom solution, I would try a 3rd-party download management plugin. We have a couple of examples available here on the site:
https://toolset.com/learn/create-membership-site-wordpress-using-toolset-plugins/restricting-access-downloadable-files/
https://toolset.com/2015/01/use-toolset-easy-digital-download-plugin-build-e-commerce-site/

I think you'll have better results using a proven 3rd-party system rather than trying to code something from scratch.

#1140669

Hey, I finally made a mixed setup.

I used Custom Upload Dir plugin, it hasn't been updated since 3 years, but it seems that the author is still giving support and it has more then 8.000 active installs. It is a quite simple plugin that uses standard WP functions, so it is not a buggy plugin.

I used it to force the uploads to a specific directory for each user. It gives the option to build a custom path like /uploads/username/, but I wasn't satisfied with it, so I customized a little the plugin. I added a couple of functions to build a path like this: /uploads/user_role/user_id/.

This way I could set different security logic for different roles (for example I wanted administrator files completely public and subscriber files private), then I preferred user_id, so the username of my users is not shared on a public URL.

The second step is based on this code suggestions:

https://wordpress.stackexchange.com/questions/37144/how-to-protect-uploads-if-user-is-not-logged-in

hidden link

To make all subscribers files private I've added this to main .htaccess:

# block directory
<IfModule mod_rewrite.c>
RewriteBase /
RewriteCond %{REQUEST_FILENAME} -s
RewriteRule ^wp-content/uploads/(subscriber/.*)$ dl-file.php?file=$1 [QSA,L]
</IfModule>

And then I added a dl-file.php on the same root directory with this code:

<?php
// Protect uploaded files with login.
require_once('wp-load.php');
require_once ABSPATH . WPINC . '/formatting.php';
require_once ABSPATH . WPINC . '/capabilities.php';
require_once ABSPATH . WPINC . '/user.php';
require_once ABSPATH . WPINC . '/meta.php';
require_once ABSPATH . WPINC . '/post.php';
require_once ABSPATH . WPINC . '/pluggable.php';
wp_cookie_constants();
ob_end_clean();
ob_end_flush();

if ( is_user_logged_in() ) {
list($basedir) = array_values(array_intersect_key(wp_upload_dir(), array('basedir' => 1)))+array(NULL);
$file =  rtrim($basedir,'/').'/'.str_replace('..', '', isset($_GET[ 'file' ])?$_GET[ 'file' ]:'');
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary"); 
header("Content-disposition: attachment; filename=\"" . basename($file) . "\""); 
readfile($file);
}
else {
    wp_redirect( home_url(), 301 );
    exit;
}

Now if an administrator publish any media file on backend or frontend they are public.

If a subscriber uploads files by a Toolset Form on the frontend it is not public and only the subscriber owner can view it using the direct URL.

I also restricted access to guests to media attachments CPTs with Toolset Access.

I finally added WPFront User Role Editor that can easily redirect wp-admin login form to a specific URL and hide admin bar for the selected role.