491 lines
20 KiB
PHP
491 lines
20 KiB
PHP
<?php
|
|
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
class WPDD_Ajax {
|
|
|
|
public static function init() {
|
|
add_action('wp_ajax_wpdd_process_free_download', array(__CLASS__, 'process_free_download'));
|
|
add_action('wp_ajax_nopriv_wpdd_process_free_download', array(__CLASS__, 'process_free_download'));
|
|
|
|
add_action('wp_ajax_wpdd_add_to_cart', array(__CLASS__, 'add_to_cart'));
|
|
add_action('wp_ajax_nopriv_wpdd_add_to_cart', array(__CLASS__, 'add_to_cart'));
|
|
|
|
add_action('wp_ajax_wpdd_get_product_details', array(__CLASS__, 'get_product_details'));
|
|
add_action('wp_ajax_nopriv_wpdd_get_product_details', array(__CLASS__, 'get_product_details'));
|
|
|
|
add_action('wp_ajax_wpdd_check_download_status', array(__CLASS__, 'check_download_status'));
|
|
add_action('wp_ajax_nopriv_wpdd_check_download_status', array(__CLASS__, 'check_download_status'));
|
|
|
|
add_action('wp_ajax_wpdd_move_to_protected', array(__CLASS__, 'move_to_protected'));
|
|
add_action('wp_ajax_wpdd_upload_protected_file', array(__CLASS__, 'upload_protected_file'));
|
|
|
|
// Customer management actions
|
|
add_action('wp_ajax_wpdd_change_password', array(__CLASS__, 'change_password'));
|
|
}
|
|
|
|
public static function process_free_download() {
|
|
check_ajax_referer('wpdd-ajax-nonce', 'nonce');
|
|
|
|
$product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0;
|
|
|
|
if (!$product_id) {
|
|
wp_send_json_error(__('Invalid product.', 'wp-digital-download'));
|
|
}
|
|
|
|
$product = get_post($product_id);
|
|
if (!$product || $product->post_type !== 'wpdd_product') {
|
|
wp_send_json_error(__('Product not found.', 'wp-digital-download'));
|
|
}
|
|
|
|
// IMPORTANT: Always check the actual database values, never trust client input
|
|
$is_free = get_post_meta($product_id, '_wpdd_is_free', true);
|
|
$price = get_post_meta($product_id, '_wpdd_price', true);
|
|
$sale_price = get_post_meta($product_id, '_wpdd_sale_price', true);
|
|
|
|
// Calculate actual price
|
|
$actual_price = ($sale_price && $sale_price < $price) ? $sale_price : $price;
|
|
|
|
// Security check: Verify this is actually a free product
|
|
if (!$is_free && $actual_price > 0) {
|
|
// Log potential security breach attempt
|
|
error_log('WPDD Security: Attempted to download paid product ' . $product_id . ' as free from IP: ' . $_SERVER['REMOTE_ADDR']);
|
|
wp_send_json_error(__('This product is not available for free download.', 'wp-digital-download'));
|
|
}
|
|
|
|
$customer_data = array(
|
|
'email' => sanitize_email($_POST['customer_email'] ?? ''),
|
|
'name' => sanitize_text_field($_POST['customer_name'] ?? '')
|
|
);
|
|
|
|
if (!is_user_logged_in() && empty($customer_data['email'])) {
|
|
wp_send_json_error(__('Please provide your email address.', 'wp-digital-download'));
|
|
}
|
|
|
|
// Create account if requested
|
|
if (!is_user_logged_in() && isset($_POST['create_account']) && $_POST['create_account'] == '1') {
|
|
$user_id = wp_create_user(
|
|
$customer_data['email'],
|
|
wp_generate_password(),
|
|
$customer_data['email']
|
|
);
|
|
|
|
if (!is_wp_error($user_id)) {
|
|
wp_update_user(array(
|
|
'ID' => $user_id,
|
|
'display_name' => $customer_data['name'],
|
|
'first_name' => $customer_data['name']
|
|
));
|
|
|
|
// Set customer role (remove default role first)
|
|
$user = new WP_User($user_id);
|
|
$user->remove_role('subscriber'); // Remove default WordPress role
|
|
$user->add_role('wpdd_customer');
|
|
|
|
// Send new account email
|
|
wp_new_user_notification($user_id, null, 'user');
|
|
|
|
// Log them in
|
|
wp_set_current_user($user_id);
|
|
wp_set_auth_cookie($user_id);
|
|
}
|
|
}
|
|
|
|
$order_id = WPDD_Orders::create_order($product_id, $customer_data, 'free');
|
|
|
|
if ($order_id) {
|
|
$order = WPDD_Orders::get_order($order_id);
|
|
|
|
wp_send_json_success(array(
|
|
'redirect_url' => add_query_arg(
|
|
'order_id',
|
|
$order->order_number,
|
|
get_permalink(get_option('wpdd_thank_you_page_id'))
|
|
)
|
|
));
|
|
} else {
|
|
wp_send_json_error(__('Failed to process download. Please try again.', 'wp-digital-download'));
|
|
}
|
|
}
|
|
|
|
public static function add_to_cart() {
|
|
check_ajax_referer('wpdd-ajax-nonce', 'nonce');
|
|
|
|
$product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0;
|
|
|
|
if (!$product_id) {
|
|
wp_send_json_error(__('Invalid product.', 'wp-digital-download'));
|
|
}
|
|
|
|
$product = get_post($product_id);
|
|
if (!$product || $product->post_type !== 'wpdd_product') {
|
|
wp_send_json_error(__('Product not found.', 'wp-digital-download'));
|
|
}
|
|
|
|
if (!isset($_SESSION['wpdd_cart'])) {
|
|
$_SESSION['wpdd_cart'] = array();
|
|
}
|
|
|
|
if (in_array($product_id, $_SESSION['wpdd_cart'])) {
|
|
wp_send_json_error(__('Product already in cart.', 'wp-digital-download'));
|
|
}
|
|
|
|
$_SESSION['wpdd_cart'][] = $product_id;
|
|
|
|
wp_send_json_success(array(
|
|
'message' => __('Product added to cart.', 'wp-digital-download'),
|
|
'cart_count' => count($_SESSION['wpdd_cart']),
|
|
'checkout_url' => add_query_arg(
|
|
'product_id',
|
|
$product_id,
|
|
get_permalink(get_option('wpdd_checkout_page_id'))
|
|
)
|
|
));
|
|
}
|
|
|
|
public static function get_product_details() {
|
|
check_ajax_referer('wpdd-ajax-nonce', 'nonce');
|
|
|
|
$product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0;
|
|
|
|
if (!$product_id) {
|
|
wp_send_json_error(__('Invalid product.', 'wp-digital-download'));
|
|
}
|
|
|
|
$product = get_post($product_id);
|
|
if (!$product || $product->post_type !== 'wpdd_product') {
|
|
wp_send_json_error(__('Product not found.', 'wp-digital-download'));
|
|
}
|
|
|
|
$price = get_post_meta($product_id, '_wpdd_price', true);
|
|
$sale_price = get_post_meta($product_id, '_wpdd_sale_price', true);
|
|
$is_free = get_post_meta($product_id, '_wpdd_is_free', true);
|
|
$files = get_post_meta($product_id, '_wpdd_files', true);
|
|
$download_limit = get_post_meta($product_id, '_wpdd_download_limit', true);
|
|
$download_expiry = get_post_meta($product_id, '_wpdd_download_expiry', true);
|
|
|
|
$creator = get_userdata($product->post_author);
|
|
|
|
$data = array(
|
|
'id' => $product_id,
|
|
'title' => $product->post_title,
|
|
'description' => $product->post_content,
|
|
'excerpt' => $product->post_excerpt,
|
|
'price' => $price,
|
|
'sale_price' => $sale_price,
|
|
'is_free' => $is_free,
|
|
'final_price' => $is_free ? 0 : (($sale_price && $sale_price < $price) ? $sale_price : $price),
|
|
'creator' => array(
|
|
'id' => $creator->ID,
|
|
'name' => $creator->display_name,
|
|
'avatar' => get_avatar_url($creator->ID)
|
|
),
|
|
'files_count' => is_array($files) ? count($files) : 0,
|
|
'download_limit' => $download_limit ?: __('Unlimited', 'wp-digital-download'),
|
|
'download_expiry' => $download_expiry ? sprintf(__('%d days', 'wp-digital-download'), $download_expiry) : __('Never expires', 'wp-digital-download'),
|
|
'thumbnail' => get_the_post_thumbnail_url($product_id, 'full'),
|
|
'categories' => wp_get_post_terms($product_id, 'wpdd_product_category', array('fields' => 'names')),
|
|
'tags' => wp_get_post_terms($product_id, 'wpdd_product_tag', array('fields' => 'names'))
|
|
);
|
|
|
|
if (is_user_logged_in()) {
|
|
$current_user = wp_get_current_user();
|
|
$data['can_download'] = WPDD_Customer::can_download_product($current_user->ID, $product_id);
|
|
}
|
|
|
|
wp_send_json_success($data);
|
|
}
|
|
|
|
public static function check_download_status() {
|
|
check_ajax_referer('wpdd-ajax-nonce', 'nonce');
|
|
|
|
if (!is_user_logged_in()) {
|
|
wp_send_json_error(__('Please login to check download status.', 'wp-digital-download'));
|
|
}
|
|
|
|
$product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0;
|
|
|
|
if (!$product_id) {
|
|
wp_send_json_error(__('Invalid product.', 'wp-digital-download'));
|
|
}
|
|
|
|
$current_user = wp_get_current_user();
|
|
|
|
global $wpdb;
|
|
$order = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT * FROM {$wpdb->prefix}wpdd_orders
|
|
WHERE customer_id = %d
|
|
AND product_id = %d
|
|
AND status = 'completed'
|
|
ORDER BY purchase_date DESC
|
|
LIMIT 1",
|
|
$current_user->ID,
|
|
$product_id
|
|
));
|
|
|
|
if (!$order) {
|
|
wp_send_json_success(array(
|
|
'has_purchased' => false,
|
|
'message' => __('You have not purchased this product.', 'wp-digital-download')
|
|
));
|
|
}
|
|
|
|
$download_limit = get_post_meta($product_id, '_wpdd_download_limit', true);
|
|
$download_expiry = get_post_meta($product_id, '_wpdd_download_expiry', true);
|
|
|
|
$can_download = true;
|
|
$message = '';
|
|
|
|
if ($download_expiry > 0) {
|
|
$expiry_date = date('Y-m-d H:i:s', strtotime($order->purchase_date . ' + ' . $download_expiry . ' days'));
|
|
if (current_time('mysql') > $expiry_date) {
|
|
$can_download = false;
|
|
$message = __('Your download period has expired.', 'wp-digital-download');
|
|
}
|
|
}
|
|
|
|
if ($can_download && $download_limit > 0 && $order->download_count >= $download_limit) {
|
|
$can_download = false;
|
|
$message = __('You have reached the download limit.', 'wp-digital-download');
|
|
}
|
|
|
|
wp_send_json_success(array(
|
|
'has_purchased' => true,
|
|
'can_download' => $can_download,
|
|
'download_count' => $order->download_count,
|
|
'download_limit' => $download_limit ?: 0,
|
|
'purchase_date' => $order->purchase_date,
|
|
'message' => $message ?: __('You can download this product.', 'wp-digital-download'),
|
|
'download_url' => $can_download ? wp_nonce_url(
|
|
add_query_arg(array('wpdd_download' => $order->id)),
|
|
'wpdd_download_' . $order->id
|
|
) : ''
|
|
));
|
|
}
|
|
|
|
public static function move_to_protected() {
|
|
check_ajax_referer('wpdd-admin-nonce', 'nonce');
|
|
|
|
if (!current_user_can('edit_wpdd_products')) {
|
|
wp_send_json_error(__('You do not have permission to perform this action.', 'wp-digital-download'));
|
|
}
|
|
|
|
$attachment_id = isset($_POST['attachment_id']) ? intval($_POST['attachment_id']) : 0;
|
|
|
|
if (!$attachment_id) {
|
|
wp_send_json_error(__('Invalid attachment ID.', 'wp-digital-download'));
|
|
}
|
|
|
|
$file_path = get_attached_file($attachment_id);
|
|
if (!$file_path || !file_exists($file_path)) {
|
|
wp_send_json_error(__('File not found.', 'wp-digital-download'));
|
|
}
|
|
|
|
// Create protected directory if it doesn't exist
|
|
$upload_dir = wp_upload_dir();
|
|
$protected_dir = trailingslashit($upload_dir['basedir']) . WPDD_UPLOADS_DIR;
|
|
|
|
if (!file_exists($protected_dir)) {
|
|
wp_mkdir_p($protected_dir);
|
|
|
|
// Add .htaccess protection
|
|
$htaccess_content = "Options -Indexes\ndeny from all\n";
|
|
file_put_contents($protected_dir . '/.htaccess', $htaccess_content);
|
|
|
|
// Add index.php protection
|
|
$index_content = "<?php\n// Silence is golden.\n";
|
|
file_put_contents($protected_dir . '/index.php', $index_content);
|
|
}
|
|
|
|
// Create subdirectory based on year/month
|
|
$time = current_time('mysql');
|
|
$y = substr($time, 0, 4);
|
|
$m = substr($time, 5, 2);
|
|
$subdir = "$y/$m";
|
|
$protected_subdir = trailingslashit($protected_dir) . $subdir;
|
|
|
|
if (!file_exists($protected_subdir)) {
|
|
wp_mkdir_p($protected_subdir);
|
|
}
|
|
|
|
// Generate unique filename
|
|
$filename = basename($file_path);
|
|
$unique_filename = wp_unique_filename($protected_subdir, $filename);
|
|
$new_file_path = trailingslashit($protected_subdir) . $unique_filename;
|
|
|
|
// Move file to protected directory
|
|
if (rename($file_path, $new_file_path)) {
|
|
// Update attachment metadata
|
|
update_attached_file($attachment_id, $new_file_path);
|
|
|
|
// Store protected path reference
|
|
update_post_meta($attachment_id, '_wpdd_protected_path', $new_file_path);
|
|
|
|
// Generate secure token for download URL
|
|
$token = wp_generate_password(32, false);
|
|
update_post_meta($attachment_id, '_wpdd_download_token', $token);
|
|
|
|
wp_send_json_success(array(
|
|
'protected_url' => home_url('?wpdd_file_download=' . $attachment_id . '&token=' . $token),
|
|
'protected_path' => $new_file_path,
|
|
'message' => __('File moved to protected directory.', 'wp-digital-download')
|
|
));
|
|
} else {
|
|
wp_send_json_error(__('Failed to move file to protected directory.', 'wp-digital-download'));
|
|
}
|
|
}
|
|
|
|
public static function upload_protected_file() {
|
|
check_ajax_referer('wpdd-admin-nonce', 'nonce');
|
|
|
|
if (!current_user_can('edit_wpdd_products')) {
|
|
wp_send_json_error(__('You do not have permission to upload files.', 'wp-digital-download'));
|
|
}
|
|
|
|
if (!isset($_FILES['file'])) {
|
|
wp_send_json_error(__('No file uploaded.', 'wp-digital-download'));
|
|
}
|
|
|
|
$uploaded_file = $_FILES['file'];
|
|
|
|
// Check for upload errors
|
|
if ($uploaded_file['error'] !== UPLOAD_ERR_OK) {
|
|
wp_send_json_error(__('Upload failed.', 'wp-digital-download'));
|
|
}
|
|
|
|
// Validate file type
|
|
$allowed_types = array(
|
|
'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
|
|
'zip', 'rar', '7z', 'tar', 'gz',
|
|
'jpg', 'jpeg', 'png', 'gif', 'svg', 'webp',
|
|
'mp3', 'wav', 'flac', 'aac', 'ogg',
|
|
'mp4', 'avi', 'mkv', 'mov', 'wmv',
|
|
'txt', 'rtf', 'epub', 'mobi'
|
|
);
|
|
|
|
$file_ext = strtolower(pathinfo($uploaded_file['name'], PATHINFO_EXTENSION));
|
|
if (!in_array($file_ext, $allowed_types)) {
|
|
wp_send_json_error(__('File type not allowed.', 'wp-digital-download'));
|
|
}
|
|
|
|
// Create protected directory structure
|
|
$upload_dir = wp_upload_dir();
|
|
$protected_dir = trailingslashit($upload_dir['basedir']) . WPDD_UPLOADS_DIR;
|
|
|
|
if (!file_exists($protected_dir)) {
|
|
wp_mkdir_p($protected_dir);
|
|
|
|
// Add .htaccess protection
|
|
$htaccess_content = "Options -Indexes\ndeny from all\n";
|
|
file_put_contents($protected_dir . '/.htaccess', $htaccess_content);
|
|
|
|
// Add index.php protection
|
|
$index_content = "<?php\n// Silence is golden.\n";
|
|
file_put_contents($protected_dir . '/index.php', $index_content);
|
|
}
|
|
|
|
// Create subdirectory based on year/month
|
|
$time = current_time('mysql');
|
|
$y = substr($time, 0, 4);
|
|
$m = substr($time, 5, 2);
|
|
$subdir = "$y/$m";
|
|
$protected_subdir = trailingslashit($protected_dir) . $subdir;
|
|
|
|
if (!file_exists($protected_subdir)) {
|
|
wp_mkdir_p($protected_subdir);
|
|
}
|
|
|
|
// Generate unique filename
|
|
$filename = sanitize_file_name($uploaded_file['name']);
|
|
$unique_filename = wp_unique_filename($protected_subdir, $filename);
|
|
$file_path = trailingslashit($protected_subdir) . $unique_filename;
|
|
|
|
// Move uploaded file to protected directory
|
|
if (move_uploaded_file($uploaded_file['tmp_name'], $file_path)) {
|
|
// Generate secure token for download URL
|
|
$token = wp_generate_password(32, false);
|
|
$file_id = 'wpdd_' . uniqid();
|
|
|
|
// Store file metadata
|
|
$file_meta = array(
|
|
'file_path' => $file_path,
|
|
'file_name' => $unique_filename,
|
|
'original_name' => $uploaded_file['name'],
|
|
'file_size' => filesize($file_path),
|
|
'file_type' => $uploaded_file['type'],
|
|
'upload_date' => current_time('mysql'),
|
|
'token' => $token
|
|
);
|
|
|
|
// Store in options table (in production, consider custom table)
|
|
update_option('wpdd_protected_file_' . $file_id, $file_meta);
|
|
|
|
wp_send_json_success(array(
|
|
'protected_url' => home_url('?wpdd_protected_download=' . $file_id . '&token=' . $token),
|
|
'file_id' => $file_id,
|
|
'file_name' => $unique_filename,
|
|
'file_size' => size_format($file_meta['file_size']),
|
|
'message' => __('File uploaded successfully to protected directory.', 'wp-digital-download')
|
|
));
|
|
} else {
|
|
wp_send_json_error(__('Failed to save uploaded file.', 'wp-digital-download'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle password change for customers
|
|
*/
|
|
public static function change_password() {
|
|
check_ajax_referer('wpdd_change_password', 'nonce');
|
|
|
|
if (!is_user_logged_in()) {
|
|
wp_send_json_error(__('You must be logged in to change your password.', 'wp-digital-download'));
|
|
}
|
|
|
|
$current_user = wp_get_current_user();
|
|
|
|
// Only allow customers to change their own password this way
|
|
if (!in_array('wpdd_customer', $current_user->roles)) {
|
|
wp_send_json_error(__('This function is only available for customers.', 'wp-digital-download'));
|
|
}
|
|
|
|
$current_password = sanitize_text_field($_POST['current_password'] ?? '');
|
|
$new_password = sanitize_text_field($_POST['new_password'] ?? '');
|
|
$confirm_password = sanitize_text_field($_POST['confirm_password'] ?? '');
|
|
|
|
if (empty($current_password) || empty($new_password) || empty($confirm_password)) {
|
|
wp_send_json_error(__('All password fields are required.', 'wp-digital-download'));
|
|
}
|
|
|
|
if ($new_password !== $confirm_password) {
|
|
wp_send_json_error(__('New passwords do not match.', 'wp-digital-download'));
|
|
}
|
|
|
|
if (strlen($new_password) < 8) {
|
|
wp_send_json_error(__('New password must be at least 8 characters long.', 'wp-digital-download'));
|
|
}
|
|
|
|
// Verify current password
|
|
if (!wp_check_password($current_password, $current_user->user_pass, $current_user->ID)) {
|
|
wp_send_json_error(__('Current password is incorrect.', 'wp-digital-download'));
|
|
}
|
|
|
|
// Update password
|
|
$result = wp_update_user(array(
|
|
'ID' => $current_user->ID,
|
|
'user_pass' => $new_password
|
|
));
|
|
|
|
if (is_wp_error($result)) {
|
|
wp_send_json_error(__('Failed to update password. Please try again.', 'wp-digital-download'));
|
|
}
|
|
|
|
// Re-authenticate user to prevent logout
|
|
wp_set_current_user($current_user->ID);
|
|
wp_set_auth_cookie($current_user->ID);
|
|
|
|
wp_send_json_success(__('Password changed successfully!', 'wp-digital-download'));
|
|
}
|
|
} |