diff --git a/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php b/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php index ecbd770..0817dc5 100644 --- a/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php +++ b/03_WordPress/wp-content/plugins/ifnex-bridge/includes/shortcodes.php @@ -1069,22 +1069,9 @@ function ifnex_order_detail_shortcode($atts) { } - // Handle PDF download - - $download_type = sanitize_text_field($_GET['download'] ?? ''); - if ($download_type && in_array($download_type, ['awb', 'invoice', 'label', 'import-invoice'])) { - ifnex_handle_pdf_download($order_id, $download_type); - return ''; - } - - - // Handle commitment form downloads (template / signed) — proxied با توکن لاراول - if (in_array($download_type, ['commitment-template', 'commitment-signed'], true)) { - $form_id = intval($_GET['form_id'] ?? 0); - $type = ($download_type === 'commitment-signed') ? 'signed' : 'template'; - ifnex_handle_commitment_download($order_id, $form_id, $type); - return ''; - } + // ⚠️ هندلر دانلودها (PDF و تعهدنامه) به template_redirect منتقل شده — + // اجرای آن داخل شورت‌کد یعنی بعد از چاپ HTML هدر قالب؛ خروجی باینری به + // HTML می‌چسبد و با Content-Length ناهم‌خوان، PDF نیمه‌تمام دانلود می‌شود. $bridge = new IFNEX_User_Bridge(); $user_id = get_current_user_id(); @@ -1411,6 +1398,32 @@ function uploadCommitmentForm(orderId, formId, input) { return ob_get_clean(); } +// ══════════════════════════════════════════════════════════════ +// رهگیری درخواست‌های دانلود قبل از هر خروجی صفحه (template_redirect) +// اجرای دانلود داخل شورت‌کد یعنی بعد از چاپ HTML هدر قالب — بایت‌های HTML +// به ابتدای فایل می‌چسبند و با Content-Length ناهم‌خوان، فایل ناقص می‌رسد. +// ══════════════════════════════════════════════════════════════ + +add_action('template_redirect', 'ifnex_intercept_download_request', 1); + +function ifnex_intercept_download_request(): void { + $download = sanitize_text_field($_GET['download'] ?? ''); + $order_id = intval($_GET['order_id'] ?? 0); + if (!$download || !$order_id) return; + + if (in_array($download, ['awb', 'invoice', 'label', 'import-invoice'], true)) { + ifnex_handle_pdf_download($order_id, $download); // exit داخل تابع + } + + if (in_array($download, ['commitment-template', 'commitment-signed'], true)) { + ifnex_handle_commitment_download( + $order_id, + intval($_GET['form_id'] ?? 0), + $download === 'commitment-signed' ? 'signed' : 'template' + ); // exit داخل تابع + } +} + // ══════════════════════════════════════════════════════════════ // آیکون‌های SVG مدرن (سبک Heroicons) // ══════════════════════════════════════════════════════════════ @@ -1426,8 +1439,8 @@ function ifnex_handle_pdf_download($order_id, $download_type) { $api_url = get_option('ifnex_api_url', 'http://localhost:8000/api/v1'); $download_url = rtrim($api_url, '/') . "/customer/orders/{$order_id}/pdf/{$download_type}"; - $token = get_user_meta($user_id, 'ifnex_laravel_token', true); - if (!$token) wp_die('توکن احراز هویت یافت نشد.'); + $token = $bridge->get_user_token($user_id); // با تجدید خودکار در صورت انقضا/حذف + if (!$token) wp_die('توکن احراز هویت در دسترس نیست — لطفاً دوباره وارد شوید.'); $response = wp_remote_get($download_url, array( 'headers' => array( @@ -1443,8 +1456,17 @@ function ifnex_handle_pdf_download($order_id, $download_type) { if ($status_code !== 200) wp_die('خطا در دانلود فایل.'); $file_content = wp_remote_retrieve_body($response); + + // پاسخ باید PDF خام باشد؛ وگرنه به‌جای فایل خراب، پیام واضح نمایش بده + if (substr($file_content, 0, 4) !== '%PDF') { + wp_die('پاسخ سرور یک فایل PDF معتبر نبود — لطفاً دوباره تلاش کنید.'); + } + $filename = strtoupper($download_type) . '-' . $order['data']['awb_no'] . '.pdf'; + // پاک‌سازی همه بافرهای خروجی تا جریان فایل تمیز و هم‌طول با Content-Length ارسال شود + while (ob_get_level()) { ob_end_clean(); } + nocache_headers(); header('Content-Type: application/pdf'); header('Content-Disposition: attachment; filename="' . $filename . '"'); @@ -1471,8 +1493,8 @@ function ifnex_handle_commitment_download($order_id, $form_id, $type = 'template $endpoint = ($type === 'signed') ? 'download' : 'template'; $download_url = rtrim($api_url, '/') . "/customer/orders/{$order_id}/commitment-forms/{$form_id}/{$endpoint}"; - $token = get_user_meta($user_id, 'ifnex_laravel_token', true); - if (!$token) wp_die('توکن احراز هویت یافت نشد.'); + $token = $bridge->get_user_token($user_id); // با تجدید خودکار در صورت انقضا/حذف + if (!$token) wp_die('توکن احراز هویت در دسترس نیست — لطفاً دوباره وارد شوید.'); $response = wp_remote_get($download_url, array( 'headers' => array( @@ -1493,6 +1515,12 @@ function ifnex_handle_commitment_download($order_id, $form_id, $type = 'template } $file_content = wp_remote_retrieve_body($response); + + // پاسخ باید فایل باینری باشد؛ شروع با '<' یعنی HTML/خطا برگشته + if ($file_content === '' || $file_content[0] === '<') { + wp_die('پاسخ سرور یک فایل معتبر نبود — لطفاً دوباره تلاش کنید.'); + } + $awb = $order['data']['awb_no'] ?? ('order-' . $order_id); // تشخیص نوع محتوا و نام فایل از روی هدر Laravel @@ -1511,6 +1539,9 @@ function ifnex_handle_commitment_download($order_id, $form_id, $type = 'template $filename .= '.' . $ext; } + // پاک‌سازی همه بافرهای خروجی تا جریان فایل تمیز و هم‌طول با Content-Length ارسال شود + while (ob_get_level()) { ob_end_clean(); } + nocache_headers(); header('Content-Type: ' . $ctype); header('Content-Disposition: attachment; filename="' . $filename . '"'); diff --git a/03_WordPress/wp-content/plugins/ifnex-bridge/includes/user-bridge.php b/03_WordPress/wp-content/plugins/ifnex-bridge/includes/user-bridge.php index 62903a5..05babef 100644 --- a/03_WordPress/wp-content/plugins/ifnex-bridge/includes/user-bridge.php +++ b/03_WordPress/wp-content/plugins/ifnex-bridge/includes/user-bridge.php @@ -855,8 +855,8 @@ function ifnex_download_order_pdf_ajax() { $download_url = rtrim($api_url, '/') . "/customer/orders/{$order_id}/pdf/{$download_type}"; // ارسال درخواست به لاراول با توکن احراز هویت - $token = get_user_meta($user_id, 'ifnex_laravel_token', true); - if (!$token) wp_send_json_error('توکن احراز هویت یافت نشد.'); + $token = $bridge->get_user_token($user_id); // با تجدید خودکار در صورت انقضا/حذف + if (!$token) wp_send_json_error('توکن احراز هویت در دسترس نیست — لطفاً دوباره وارد شوید.'); $response = wp_remote_get($download_url, array( 'headers' => array( @@ -908,8 +908,8 @@ function ifnex_get_commitment_forms_ajax() { $api_url = get_option('ifnex_api_url', 'http://localhost:8000/api/v1'); $url = rtrim($api_url, '/') . "/customer/orders/{$order_id}/commitment-forms"; - $token = get_user_meta($user_id, 'ifnex_laravel_token', true); - if (!$token) wp_send_json_error('توکن احراز هویت یافت نشد.'); + $token = $bridge->get_user_token($user_id); // با تجدید خودکار در صورت انقضا/حذف + if (!$token) wp_send_json_error('توکن احراز هویت در دسترس نیست — لطفاً دوباره وارد شوید.'); $response = wp_remote_get($url, array( 'headers' => array( @@ -973,8 +973,8 @@ function ifnex_upload_commitment_form_ajax() { $api_url = get_option('ifnex_api_url', 'http://localhost:8000/api/v1'); $url = rtrim($api_url, '/') . "/customer/orders/{$order_id}/commitment-forms/{$form_id}/upload"; - $token = get_user_meta($user_id, 'ifnex_laravel_token', true); - if (!$token) wp_send_json_error('توکن احراز هویت یافت نشد.'); + $token = $bridge->get_user_token($user_id); // با تجدید خودکار در صورت انقضا/حذف + if (!$token) wp_send_json_error('توکن احراز هویت در دسترس نیست — لطفاً دوباره وارد شوید.'); $multipart = new CURLFile($upload['file'], $file['type'], $file['name']); $post_fields = array( diff --git a/04_Laravel/app/Http/Controllers/Controller.php b/04_Laravel/app/Http/Controllers/Controller.php index 62b4969..ef916e5 100644 --- a/04_Laravel/app/Http/Controllers/Controller.php +++ b/04_Laravel/app/Http/Controllers/Controller.php @@ -2,12 +2,10 @@ namespace App\Http\Controllers; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; +use Illuminate\Foundation\Validation\ValidatesRequests; + abstract class Controller { - // + use AuthorizesRequests, ValidatesRequests; } - -class CustomerOrderController -{ - // ... -} \ No newline at end of file diff --git a/04_Laravel/storage/real-invoice.pdf b/04_Laravel/storage/real-invoice.pdf new file mode 100644 index 0000000..d5dbe4b Binary files /dev/null and b/04_Laravel/storage/real-invoice.pdf differ