forms

I love WordPress. I like Gravity Forms. The only trouble with Gravity forms is if you add a file upload field to your form it is stored within your /wp-content/uploads directory and as such is publicly accessible.

Now the link that Gravity Forms generates is fairly long (mywebsite.com/wp-content/uploads/gravity_forms/reallylongstringofnumbers10239812039802193/year/month/filename) however that just isn’t secure enough for me. The worst part os they don’t seem to care.

After a week or two of searching I have found a way of securing it! The following method secures the folder in question so that only Logged in users can access them. It is also probably possible to modify this method to account for different user roles etc, but for now a little security is better than none!

Ok so we need to do 2 things.

  1. Tell our website that all files in a certain directory need to be passed to a special file for processing before downloading.
  2. Use our special file to check if the user is logged in!
First things first. Create a new file in the ROOT of your WordPress install called dl-file.php and paste in the following:
<?php
require_once('wp-load.php');
is_user_logged_in() || auth_redirect();
$upload_dir = wp_upload_dir();
//Set your path below I am using /gravity_forms/
$basedir = $upload_dir[ 'basedir' ] . '/gravity_forms/';

$file = rtrim( $basedir, '/' ) . '/' . str_replace( '..', '', isset( $_GET[ 'file' ] ) ? $_GET[ 'file' ] : '' );
if ( ! $basedir || ! is_file( $file ) ) {
 status_header( 404 );
 die( '404 &#8212; File not found.' );
}

$mime = wp_check_filetype( $file );
if( false === $mime[ 'type' ] && function_exists( 'mime_content_type' ) )
 $mime[ 'type' ] = mime_content_type( $file );

if( $mime[ 'type' ] )
 $mimetype = $mime[ 'type' ];
else
 $mimetype = 'image/' . substr( $file, strrpos( $file, '.' ) + 1 );

header( 'Content-Type: ' . $mimetype ); // always send this
if ( false === strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS' ) )
 header( 'Content-Length: ' . filesize( $file ) );

$last_modified = gmdate( 'D, d M Y H:i:s', filemtime( $file ) );
$etag = '"' . md5( $last_modified ) . '"';
header( "Last-Modified: $last_modified GMT" );
header( 'ETag: ' . $etag );
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 100000000 ) . ' GMT' );

// Support for Conditional GET
$client_etag = isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ? stripslashes( $_SERVER['HTTP_IF_NONE_MATCH'] ) : false;

if( ! isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) )
 $_SERVER['HTTP_IF_MODIFIED_SINCE'] = false;

$client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
// If string is empty, return 0. If not, attempt to parse into a timestamp
$client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;

// Make a timestamp for our most recent modification...
$modified_timestamp = strtotime($last_modified);

if ( ( $client_last_modified && $client_etag )
 ? ( ( $client_modified_timestamp >= $modified_timestamp) && ( $client_etag == $etag ) )
 : ( ( $client_modified_timestamp >= $modified_timestamp) || ( $client_etag == $etag ) )
 ) {
 status_header( 304 );
 exit;
}

// If we made it this far, just serve the file
readfile( $file );

Looks kinda scary doesn’t it! Don’t worry about it! The only thing you need to pay attention to is line 8. This is where you set which folder you are protecting, for this I am using /gravity_forms/ the path is relative to your uploads directory.

Second in your .htaccess file you need to add the following:


#Gravity Forms Upload Protection
RewriteCond %{REQUEST_FILENAME} -s
RewriteRule ^wp-content/uploads/gravity_forms/(.*)$ dl-file.php?file=$1 [QSA,L]

The RewriteRule path needs to match the path you set in your dl-file.php so here you can see gravity_forms is mentioned again.

So what happens.

When a file is requested from within the Gravity Forms folder the request is passed via the .htaccess file to our dl-file.php. This file then checks to see if the user is logged in. If not logged in they are forwarded to the login page, after logging in the file is downloaded. If they don’t login. No file. Simple!

There are probably loads of improvements that can be made to this but it is a great start.

The credit goes entirely to http://wordpress.stackexchange.com/a/37743/12438 I simply took the code and made it work for me! Let me know what improvements you make to it!

40 thoughts on “Secure your Gravity Forms uploads

Leave a Reply

Mojowill Avatar

Who the Hell am I?

I'm Will, a full time web developer, geek and musician. I develop using PHP and MySQL and spend most of my time working with WordPress or CakePHP. When I'm not buried in code I'm gaming, cooking or writing and recording music in my studio. I like sci-fi, pancakes and coffee and am totally prepared for the zombie apocalypse...

Stalk me on these other sites...

Why not be super creepy and check me out on all these other sites, I think they call it social media?