diff --git a/autoload/front/Controllers/ShopBasketController.php b/autoload/front/Controllers/ShopBasketController.php index 7f2405b..e26e7fa 100644 --- a/autoload/front/Controllers/ShopBasketController.php +++ b/autoload/front/Controllers/ShopBasketController.php @@ -5,6 +5,7 @@ class ShopBasketController { private const ORDER_SUBMIT_TOKEN_SESSION_KEY = 'order-submit-token'; private const ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY = 'order-submit-last-order-id'; + private const ORDER_SUBMIT_TOKEN_TTL = 1800; public static $title = [ 'mainView' => 'Koszyk' @@ -276,19 +277,6 @@ class ShopBasketController exit; } - $existingOrderId = isset( $_SESSION[ self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ] ) - ? (int)$_SESSION[ self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ] - : 0; - if ( $existingOrderId > 0 ) - { - $existingOrderHash = $this->orderRepository->findHashById( $existingOrderId ); - if ( $existingOrderHash ) - { - header( 'Location: /zamowienie/' . $existingOrderHash ); - exit; - } - } - $client = \Shared\Helpers\Helpers::get_session( 'client' ); $orderSubmitToken = $this->createOrderSubmitToken(); @@ -311,20 +299,23 @@ class ShopBasketController $orderSubmitToken = (string)\Shared\Helpers\Helpers::get( 'order_submit_token', true ); $existingOrderId = isset( $_SESSION[ self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ] ) ? (int)$_SESSION[ self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ] : 0; + $basket = \Shared\Helpers\Helpers::get_session( 'basket' ); + if ( empty( $basket ) && $existingOrderId > 0 ) + { + $existingOrderHash = $this->orderRepository->findHashById( $existingOrderId ); + if ( $existingOrderHash ) + { + $this->logOrder( 'Double-submit detected, redirecting to existing order id=' . $existingOrderId ); + header( 'Location: /zamowienie/' . $existingOrderHash ); + exit; + } + } + if ( !$this->isValidOrderSubmitToken( $orderSubmitToken ) ) { - if ( $existingOrderId > 0 ) - { - $existingOrderHash = $this->orderRepository->findHashById( $existingOrderId ); - if ( $existingOrderHash ) - { - header( 'Location: /zamowienie/' . $existingOrderHash ); - exit; - } - } - + $this->logOrder( 'Token validation failed. formToken=' . $orderSubmitToken . ' existingOrderId=' . $existingOrderId ); \Shared\Helpers\Helpers::error( \Shared\Helpers\Helpers::lang( 'zamowienie-zostalo-zlozone-komunikat-blad' ) ); - header( 'Location: /koszyk' ); + header( 'Location: /koszyk-podsumowanie' ); exit; } @@ -367,6 +358,7 @@ class ShopBasketController } catch ( \Exception $e ) { + $this->logOrder( 'createFromBasket exception: ' . $e->getMessage() ); error_log( '[basketSave] createFromBasket exception: ' . $e->getMessage() ); \Shared\Helpers\Helpers::error( \Shared\Helpers\Helpers::lang( 'zamowienie-zostalo-zlozone-komunikat-blad' ) ); header( 'Location: /koszyk' ); @@ -400,6 +392,7 @@ class ShopBasketController } else { + $this->logOrder( 'createFromBasket returned falsy order_id. client_id=' . ( $client['id'] ?? '?' ) . ' email=' . ( \Shared\Helpers\Helpers::get( 'email', true ) ?: '?' ) ); \Shared\Helpers\Helpers::error( \Shared\Helpers\Helpers::lang( 'zamowienie-zostalo-zlozone-komunikat-blad' ) ); header( 'Location: /koszyk' ); exit; @@ -544,8 +537,23 @@ class ShopBasketController private function createOrderSubmitToken() { + $sessionData = isset( $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] ) + ? $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] + : null; + + if ( is_array( $sessionData ) && isset( $sessionData['token'], $sessionData['created_at'] ) ) + { + if ( ( time() - $sessionData['created_at'] ) < self::ORDER_SUBMIT_TOKEN_TTL ) + { + return $sessionData['token']; + } + } + $token = $this->generateOrderSubmitToken(); - \Shared\Helpers\Helpers::set_session( self::ORDER_SUBMIT_TOKEN_SESSION_KEY, $token ); + \Shared\Helpers\Helpers::set_session( self::ORDER_SUBMIT_TOKEN_SESSION_KEY, [ + 'token' => $token, + 'created_at' => time() + ] ); \Shared\Helpers\Helpers::delete_session( self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ); return $token; @@ -568,10 +576,29 @@ class ShopBasketController if ( !$token ) return false; - $sessionToken = isset( $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] ) ? (string)$_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] : ''; - if ( !$sessionToken ) + $sessionData = isset( $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] ) + ? $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] + : null; + + if ( !$sessionData ) return false; + // Backward compatibility: stary format (plain string) + if ( is_string( $sessionData ) ) + { + $sessionToken = $sessionData; + } + elseif ( is_array( $sessionData ) && isset( $sessionData['token'], $sessionData['created_at'] ) ) + { + if ( ( time() - $sessionData['created_at'] ) >= self::ORDER_SUBMIT_TOKEN_TTL ) + return false; + $sessionToken = $sessionData['token']; + } + else + { + return false; + } + if ( function_exists( 'hash_equals' ) ) return hash_equals( $sessionToken, $token ); @@ -582,4 +609,11 @@ class ShopBasketController { \Shared\Helpers\Helpers::delete_session( self::ORDER_SUBMIT_TOKEN_SESSION_KEY ); } + + private function logOrder( $message ) + { + $logFile = __DIR__ . '/../../../logs/logs-order-' . date( 'Y-m-d' ) . '.log'; + $line = '[' . date( 'Y-m-d H:i:s' ) . '] ' . $message . "\n"; + @file_put_contents( $logFile, $line, FILE_APPEND ); + } } diff --git a/templates/shop-basket/basket.php b/templates/shop-basket/basket.php index 479b2e3..a7f7db5 100644 --- a/templates/shop-basket/basket.php +++ b/templates/shop-basket/basket.php @@ -1,4 +1,46 @@ global $settings; ?> + + if ( $settings['google_tag_manager_id'] && is_array( $this -> basket ) && count( $this -> basket ) ): + $view_cart_items = ''; + $view_cart_value = 0; + + foreach ( $this -> basket as $position ): + $vc_product = (new \Domain\Product\ProductRepository($GLOBALS['mdb']))->findCached( (int)$position['product-id'], (new \Domain\Languages\LanguagesRepository($GLOBALS['mdb']))->defaultLanguage() ); + + if ( !$vc_product ) + continue; + + $vc_price = (float)$vc_product['price_brutto_promo'] > 0 && (float)$vc_product['price_brutto_promo'] < (float)$vc_product['price_brutto'] + ? (float)$vc_product['price_brutto_promo'] + : (float)$vc_product['price_brutto']; + + $vc_qty = (int)$position['quantity']; + $view_cart_value += $vc_price * $vc_qty; + + if ( $view_cart_items ) + $view_cart_items .= ','; + + $view_cart_items .= '{'; + $view_cart_items .= 'item_id: "' . $vc_product['id'] . '",'; + $view_cart_items .= 'item_name: "' . str_replace( '"', '', $vc_product['language']['name'] ) . '",'; + $view_cart_items .= 'price: ' . \Shared\Helpers\Helpers::normalize_decimal( $vc_price ) . ','; + $view_cart_items .= 'quantity: ' . $vc_qty . ','; + $view_cart_items .= 'google_business_vertical: "retail"'; + $view_cart_items .= '}'; + endforeach; +?> + + endif; ?>