WordPress: Force Download
<!-- PUT IN download.php: -->
<?php
/*
* This code delivers a file, specified in the URL parameter, as a forced "Save As" download.
*/
// First, get WordPress loaded
require_once('../../../wp-load.php'); // Modify this if necessary
// Grab the requested URL
$request_file = $_REQUEST['url'];
// Get WordPress's upload directory details - this returns an array of things - see the Codex for details
$upload_path_info = wp_upload_dir();
// Translate the requested URL into a local file path
$request_file_path = str_replace( $upload_path_info['baseurl'], $upload_path_info['basedir'], $request_file );
// Because you could ask for, say, /wp-content/uploads/2013/01/../../../../wp-config.php we need a security check
// to make sure we're actually getting a file form /uploads. The canonical directory of the request MUST be the
// basedir of the uploads directory.
$realdir = realpath(dirname($request_file_path));
// Make sure this is a === test as a successful result will be 0 !!
if (strpos($realdir, $upload_path_info['basedir']) === false) {
echo "Haha! Nice try. I don't think so.";
exit;
}
// Check if the file exists
if (file_exists($request_file_path)) {
// Send appropriate headers (this from the examples here: http://php.net/manual/en/function.readfile.php);
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($request_file_path));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($request_file_path));
ob_clean();
flush();
readfile($request_file_path);
exit;
}
?>
<!-- PUT IN TEMPLATE: -->
<?php
if ($resource_url):
$download_url = get_template_directory_uri() . '/download.php?url=' . urlencode($resource_url);
?>
<a href="<?php echo $download_url; ?>">Download</a>
<?php
endif;
?>