180 lines
6.3 KiB
PHP
180 lines
6.3 KiB
PHP
<?php
|
|
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
class WPDD_File_Protection {
|
|
|
|
public static function init() {
|
|
add_action('template_redirect', array(__CLASS__, 'protect_direct_access'));
|
|
add_filter('mod_rewrite_rules', array(__CLASS__, 'add_rewrite_rules'));
|
|
add_action('init', array(__CLASS__, 'add_download_endpoint'));
|
|
}
|
|
|
|
public static function protect_direct_access() {
|
|
$request_uri = $_SERVER['REQUEST_URI'];
|
|
$upload_dir = wp_upload_dir();
|
|
$protected_dir = '/' . WPDD_UPLOADS_DIR . '/';
|
|
|
|
if (strpos($request_uri, $protected_dir) !== false) {
|
|
wp_die(__('Direct access to this file is not allowed.', 'wp-digital-download'), 403);
|
|
}
|
|
}
|
|
|
|
public static function add_rewrite_rules($rules) {
|
|
$upload_dir = wp_upload_dir();
|
|
$protected_path = str_replace(ABSPATH, '', $upload_dir['basedir']) . '/' . WPDD_UPLOADS_DIR;
|
|
|
|
$new_rules = "# WP Digital Download Protection\n";
|
|
$new_rules .= "<IfModule mod_rewrite.c>\n";
|
|
$new_rules .= "RewriteRule ^" . $protected_path . "/.*$ - [F,L]\n";
|
|
$new_rules .= "</IfModule>\n\n";
|
|
|
|
return $new_rules . $rules;
|
|
}
|
|
|
|
public static function add_download_endpoint() {
|
|
add_rewrite_endpoint('wpdd-download', EP_ROOT);
|
|
}
|
|
|
|
public static function move_to_protected_directory($attachment_id) {
|
|
$upload_dir = wp_upload_dir();
|
|
$protected_dir = trailingslashit($upload_dir['basedir']) . WPDD_UPLOADS_DIR;
|
|
|
|
if (!file_exists($protected_dir)) {
|
|
wp_mkdir_p($protected_dir);
|
|
self::create_protection_files($protected_dir);
|
|
}
|
|
|
|
$file_path = get_attached_file($attachment_id);
|
|
|
|
if (!file_exists($file_path)) {
|
|
return false;
|
|
}
|
|
|
|
$filename = basename($file_path);
|
|
$unique_filename = wp_unique_filename($protected_dir, $filename);
|
|
$new_path = trailingslashit($protected_dir) . $unique_filename;
|
|
|
|
if (copy($file_path, $new_path)) {
|
|
$protected_url = trailingslashit($upload_dir['baseurl']) . WPDD_UPLOADS_DIR . '/' . $unique_filename;
|
|
|
|
update_post_meta($attachment_id, '_wpdd_protected_file', $new_path);
|
|
update_post_meta($attachment_id, '_wpdd_protected_url', $protected_url);
|
|
|
|
return array(
|
|
'path' => $new_path,
|
|
'url' => $protected_url
|
|
);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static function create_protection_files($directory) {
|
|
$htaccess_content = "Options -Indexes\n";
|
|
$htaccess_content .= "deny from all\n";
|
|
|
|
$htaccess_file = trailingslashit($directory) . '.htaccess';
|
|
if (!file_exists($htaccess_file)) {
|
|
file_put_contents($htaccess_file, $htaccess_content);
|
|
}
|
|
|
|
$index_content = "<?php\n// Silence is golden.\n";
|
|
$index_file = trailingslashit($directory) . 'index.php';
|
|
if (!file_exists($index_file)) {
|
|
file_put_contents($index_file, $index_content);
|
|
}
|
|
|
|
$nginx_content = "location ~* ^/wp-content/uploads/" . WPDD_UPLOADS_DIR . " {\n";
|
|
$nginx_content .= " deny all;\n";
|
|
$nginx_content .= " return 403;\n";
|
|
$nginx_content .= "}\n";
|
|
|
|
$nginx_file = trailingslashit($directory) . 'nginx.conf';
|
|
if (!file_exists($nginx_file)) {
|
|
file_put_contents($nginx_file, $nginx_content);
|
|
}
|
|
}
|
|
|
|
public static function get_protected_file_url($file_path) {
|
|
$upload_dir = wp_upload_dir();
|
|
$protected_dir = trailingslashit($upload_dir['basedir']) . WPDD_UPLOADS_DIR;
|
|
|
|
if (strpos($file_path, $protected_dir) === 0) {
|
|
$relative_path = str_replace($protected_dir, '', $file_path);
|
|
return trailingslashit($upload_dir['baseurl']) . WPDD_UPLOADS_DIR . $relative_path;
|
|
}
|
|
|
|
return $file_path;
|
|
}
|
|
|
|
public static function is_protected_file($file_path) {
|
|
$upload_dir = wp_upload_dir();
|
|
$protected_dir = trailingslashit($upload_dir['basedir']) . WPDD_UPLOADS_DIR;
|
|
|
|
return strpos($file_path, $protected_dir) === 0;
|
|
}
|
|
|
|
public static function generate_secure_download_url($file_path, $order_id, $expiry_hours = 24) {
|
|
$token = wp_hash($file_path . $order_id . time());
|
|
$expiry = time() + ($expiry_hours * 3600);
|
|
|
|
set_transient('wpdd_download_' . $token, array(
|
|
'file_path' => $file_path,
|
|
'order_id' => $order_id,
|
|
'expiry' => $expiry
|
|
), $expiry_hours * 3600);
|
|
|
|
return add_query_arg(array(
|
|
'wpdd_secure_download' => $token
|
|
), home_url());
|
|
}
|
|
|
|
public static function handle_secure_download() {
|
|
if (!isset($_GET['wpdd_secure_download'])) {
|
|
return;
|
|
}
|
|
|
|
$token = sanitize_text_field($_GET['wpdd_secure_download']);
|
|
$data = get_transient('wpdd_download_' . $token);
|
|
|
|
if (!$data) {
|
|
wp_die(__('Invalid or expired download link.', 'wp-digital-download'));
|
|
}
|
|
|
|
if ($data['expiry'] < time()) {
|
|
delete_transient('wpdd_download_' . $token);
|
|
wp_die(__('This download link has expired.', 'wp-digital-download'));
|
|
}
|
|
|
|
if (!file_exists($data['file_path'])) {
|
|
wp_die(__('File not found.', 'wp-digital-download'));
|
|
}
|
|
|
|
delete_transient('wpdd_download_' . $token);
|
|
|
|
self::serve_download($data['file_path']);
|
|
}
|
|
|
|
private static function serve_download($file_path) {
|
|
$file_name = basename($file_path);
|
|
$file_size = filesize($file_path);
|
|
$file_type = wp_check_filetype($file_path);
|
|
|
|
nocache_headers();
|
|
|
|
header('Content-Type: ' . ($file_type['type'] ?: 'application/octet-stream'));
|
|
header('Content-Disposition: attachment; filename="' . $file_name . '"');
|
|
header('Content-Length: ' . $file_size);
|
|
header('Content-Transfer-Encoding: binary');
|
|
|
|
if (ob_get_level()) {
|
|
ob_end_clean();
|
|
}
|
|
|
|
readfile($file_path);
|
|
exit;
|
|
}
|
|
} |