|
|
@@ -82,6 +82,25 @@ class Studiou_WC_FPP_Upload {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ // Resolve/mint batch token — a stable per-visitor identifier that survives classic
|
|
|
+ // cookie <-> Store API Cart-Token session splits. Write it to the cookie once.
|
|
|
+ $batch_token = self::resolve_or_mint_batch_token();
|
|
|
+
|
|
|
+ // Enforce per-product max-uploads cap on the first chunk of a new file.
|
|
|
+ if ($chunk_index === 0) {
|
|
|
+ $max_uploads = Studiou_WC_FPP_Product::get_product_max_uploads($product_id);
|
|
|
+ if ($max_uploads > 0) {
|
|
|
+ $current_count = $this->db->count_batch_files($batch_token, $product_id);
|
|
|
+ if ($current_count >= $max_uploads) {
|
|
|
+ wp_send_json_error(array('message' => sprintf(
|
|
|
+ __('Maximum number of uploads reached (%d). Remove a photo before uploading another.', 'studiou-wc-free-photo-product'),
|
|
|
+ $max_uploads
|
|
|
+ )));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
$chunks_dir = $this->get_chunks_dir();
|
|
|
if (!file_exists($chunks_dir)) {
|
|
|
wp_mkdir_p($chunks_dir);
|
|
|
@@ -101,7 +120,7 @@ class Studiou_WC_FPP_Upload {
|
|
|
ob_end_clean();
|
|
|
}
|
|
|
|
|
|
- $result = $this->assemble_chunks($upload_id, $total_chunks, $file_name, $product_id);
|
|
|
+ $result = $this->assemble_chunks($upload_id, $total_chunks, $file_name, $product_id, $batch_token);
|
|
|
|
|
|
// Clean again before sending JSON
|
|
|
while (ob_get_level()) {
|
|
|
@@ -145,7 +164,7 @@ class Studiou_WC_FPP_Upload {
|
|
|
));
|
|
|
}
|
|
|
|
|
|
- private function assemble_chunks($upload_id, $total_chunks, $file_name, $product_id) {
|
|
|
+ private function assemble_chunks($upload_id, $total_chunks, $file_name, $product_id, $batch_token = '') {
|
|
|
$chunks_dir = $this->get_chunks_dir();
|
|
|
$upload_dir = wp_upload_dir();
|
|
|
|
|
|
@@ -283,6 +302,7 @@ class Studiou_WC_FPP_Upload {
|
|
|
'attachment_id' => $attachment_id,
|
|
|
'customer_id' => get_current_user_id(),
|
|
|
'session_key' => $session_key,
|
|
|
+ 'batch_token' => $batch_token,
|
|
|
'file_name' => $file_name,
|
|
|
));
|
|
|
|
|
|
@@ -406,8 +426,43 @@ class Studiou_WC_FPP_Upload {
|
|
|
wp_send_json_success(array('message' => __('File removed.', 'studiou-wc-free-photo-product')));
|
|
|
}
|
|
|
|
|
|
- const COOKIE_ATTACHMENT = 'studiou_fpp_att_id';
|
|
|
- const COOKIE_RECORD = 'studiou_fpp_rec_id';
|
|
|
+ const COOKIE_BATCH = 'studiou_fpp_batch';
|
|
|
+ const COOKIE_ATTACHMENT = 'studiou_fpp_att_id'; // legacy — read-fallback only
|
|
|
+ const COOKIE_RECORD = 'studiou_fpp_rec_id'; // legacy — read-fallback only
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Return the current visitor's batch token, minting + persisting a new one if absent.
|
|
|
+ * Reads / writes the studiou_fpp_batch cookie.
|
|
|
+ */
|
|
|
+ public static function resolve_or_mint_batch_token() {
|
|
|
+ if (!empty($_COOKIE[self::COOKIE_BATCH])) {
|
|
|
+ $raw = preg_replace('/[^A-Za-z0-9]/', '', (string) $_COOKIE[self::COOKIE_BATCH]);
|
|
|
+ if (strlen($raw) >= 16 && strlen($raw) <= 64) {
|
|
|
+ return $raw;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $token = wp_generate_password(32, false);
|
|
|
+ $options = self::cookie_options(time() + DAY_IN_SECONDS);
|
|
|
+ @setcookie(self::COOKIE_BATCH, $token, $options);
|
|
|
+ $_COOKIE[self::COOKIE_BATCH] = $token;
|
|
|
+ return $token;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function get_batch_token() {
|
|
|
+ if (!empty($_COOKIE[self::COOKIE_BATCH])) {
|
|
|
+ $raw = preg_replace('/[^A-Za-z0-9]/', '', (string) $_COOKIE[self::COOKIE_BATCH]);
|
|
|
+ if (strlen($raw) >= 16 && strlen($raw) <= 64) {
|
|
|
+ return $raw;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function clear_batch_cookie() {
|
|
|
+ $options = self::cookie_options(time() - DAY_IN_SECONDS);
|
|
|
+ @setcookie(self::COOKIE_BATCH, '', $options);
|
|
|
+ unset($_COOKIE[self::COOKIE_BATCH]);
|
|
|
+ }
|
|
|
|
|
|
public static function set_upload_cookies($attachment_id, $file_record_id) {
|
|
|
$attachment_id = (int) $attachment_id;
|