PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.28
Booktics – Appointment Booking Calendar for Service Businesses v1.0.28
1.0.29 1.0.28 1.0.27 1.0.26 1.0.25 1.0.24 1.0.23 1.0.22 1.0.21 1.0.20 1.0.19 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.2 1.0.3 All 31 releases
← All changes | core/cart/cart-session.php +101 -8 1.0.13 → 1.0.28 View file →
@@ -17,21 +17,61 @@
17 17 */
18 18 const SESSION_KEY = 'booktics_cart';
19 19
20 20 /**
21 + * Start a PHP session when one is not running yet.
22 + *
23 + * Sessions are started lazily instead of on every request so that a session
24 + * is never opened after output has already been flushed, which triggers a
25 + * "Session cannot be started after headers have already been sent" warning.
26 + *
27 + * @return bool True when $_SESSION is usable.
28 + */
29 + private static function maybe_start_session(): bool {
30 + if ( PHP_SESSION_ACTIVE === session_status() ) {
31 + return true;
32 + }
33 +
34 + if ( PHP_SESSION_DISABLED === session_status() ) {
35 + return false;
36 + }
37 +
38 + if ( headers_sent() || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
39 + return false;
40 + }
41 +
42 + return session_start();
43 + }
44 +
45 + /**
46 + * Get an empty cart structure
47 + *
48 + * @return array{items: array, total: float, coupon: string}
49 + */
50 + private static function empty_cart(): array {
51 + return array(
52 + 'items' => array(),
53 + 'total' => 0.00,
54 + 'coupon' => '',
55 + );
56 + }
57 +
58 + /**
21 59 * Get cart data from session
22 60 *
23 61 * @return array{items: array, total: float}
24 62 */
25 63 public static function get() {
26 - $session_data = ! empty( $_SESSION[ self::SESSION_KEY ] ) ? $_SESSION[ self::SESSION_KEY ] : null;
64 + if ( ! self::maybe_start_session() ) {
65 + return self::empty_cart();
66 + }
27 67
68 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized via sanitize_session_data() on next line.
69 + $raw_data = ! empty( $_SESSION[ self::SESSION_KEY ] ) ? wp_unslash( $_SESSION[ self::SESSION_KEY ] ) : null;
70 + $session_data = self::sanitize_session_data( $raw_data );
71 +
28 72 if ( ! is_array( $session_data ) ) {
29 - return array(
30 - 'items' => array(),
31 - 'total' => 0.00,
32 - 'coupon' => '',
33 - );
73 + return self::empty_cart();
34 74 }
35 75
36 76 return $session_data;
37 77 }
@@ -36,8 +76,53 @@
36 76 return $session_data;
37 77 }
38 78
39 79 /**
80 + * Sanitize raw cart session data
81 + *
82 + * @param mixed $data Raw data retrieved from the session.
83 + *
84 + * @return mixed Sanitized array or null if input is not an array.
85 + */
86 + private static function sanitize_session_data( $data ) {
87 + if ( ! is_array( $data ) ) {
88 + return null;
89 + }
90 +
91 + $sanitized_items = array();
92 +
93 + if ( ! empty( $data['items'] ) && is_array( $data['items'] ) ) {
94 + foreach ( $data['items'] as $item ) {
95 + if ( ! is_array( $item ) ) {
96 + continue;
97 + }
98 +
99 + $sanitized_item = array(
100 + 'uuid' => sanitize_text_field( $item['uuid'] ?? '' ),
101 + 'service_id' => absint( $item['service_id'] ?? 0 ),
102 + 'team_member_id' => absint( $item['team_member_id'] ?? 0 ),
103 + 'date' => sanitize_text_field( $item['date'] ?? '' ),
104 + 'start_time' => sanitize_text_field( $item['start_time'] ?? '' ),
105 + 'end_time' => sanitize_text_field( $item['end_time'] ?? '' ),
106 + 'price' => floatval( $item['price'] ?? 0 ),
107 + 'subtotal' => floatval( $item['subtotal'] ?? 0 ),
108 + 'total' => floatval( $item['total'] ?? 0 ),
109 + );
110 +
111 + $sanitized_item = apply_filters( 'booktics_pro_sanitize_cart_item', $sanitized_item, $item );
112 +
113 + $sanitized_items[] = $sanitized_item;
114 + }
115 + }
116 +
117 + return array(
118 + 'items' => $sanitized_items,
119 + 'total' => floatval( $data['total'] ?? 0.00 ),
120 + 'coupon' => sanitize_text_field( $data['coupon'] ?? '' ),
121 + );
122 + }
123 +
124 + /**
40 125 * Set cart data in session
41 126 *
42 127 * @param array $cart Cart data to store in session
43 128 *
@@ -43,8 +128,12 @@
43 128 *
44 129 * @return void
45 130 */
46 131 public static function set( array $cart ) {
132 + if ( ! self::maybe_start_session() ) {
133 + return;
134 + }
135 +
47 136 $_SESSION[ self::SESSION_KEY ] = $cart;
48 137 }
49 138
50 139 /**
@@ -52,8 +141,12 @@
52 141 *
53 142 * @return void
54 143 */
55 144 public static function clear() {
145 + if ( ! self::maybe_start_session() ) {
146 + return;
147 + }
148 +
56 149 unset( $_SESSION[ self::SESSION_KEY ] );
57 150 }
58 151
59 152 /**
@@ -65,9 +158,9 @@
65 158 */
66 159 public static function add_item( array $item ): array {
67 160 $cart = self::get();
68 161 $cart['items'][] = $item;
69 - $cart['total'] += $item['subtotal'];
162 + $cart['total'] = floatval( $cart['total'] ?? 0 ) + floatval( $item['subtotal'] ?? $item['price'] ?? 0 );
70 163 $cart = apply_filters( 'booktics_pro_cart_session', $cart );
71 164
72 165 self::set( $cart );
73 166
@@ -116,9 +209,9 @@
116 209 function ( $item ) use ( $uuid, $new_data, &$cart ) {
117 210 if ( $item['uuid'] === $uuid ) {
118 211 $item = array_merge( $item, $new_data );
119 212 }
120 - $cart['total'] += $item['subtotal'];
213 + $cart['total'] += floatval( $item['subtotal'] ?? $item['price'] ?? 0 );
121 214
122 215 return $item;
123 216 }, $cart['items']
124 217 );