PluginProbe ʕ •ᴥ•ʔ
WooCommerce Square / 5.4.2
WooCommerce Square v5.4.2
5.4.2 5.4.1 5.4.0 trunk 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.7.0 2.8.0 2.9.0 2.9.1 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.2.0 3.3.0 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.7.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 4.0.0 4.1.0 4.2.0 4.2.1 4.2.2 4.2.3 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.4.2 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.6.2 4.6.3 4.6.4 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.8.4 4.8.5 4.8.6 4.8.7 4.8.8 4.9.0 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.6 4.9.7 4.9.8 4.9.9 5.0.0 5.0.1 5.1.0 5.1.1 5.1.2 5.2.0 5.3.0 5.3.1 5.3.2 5.3.3
woocommerce-square / includes / Framework / Square_Helper.php
woocommerce-square / includes / Framework Last commit date
Addresses 3 years ago Api 1 year ago Compatibility 2 years ago PaymentGateway 1 day ago Utilities 1 year ago Admin_Message_Handler.php 3 years ago Admin_Notice_Handler.php 3 months ago Lifecycle.php 2 years ago Plugin.php 11 months ago Plugin_Compatibility.php 2 years ago Plugin_Dependencies.php 1 year ago Square_Helper.php 8 months ago
Square_Helper.php
419 lines
1 <?php
2
3 namespace WooCommerce\Square\Framework;
4
5 use WooCommerce\Square\Framework\Plugin_Compatibility;
6
7 defined( 'ABSPATH' ) || exit;
8
9 /**
10 * Square Helper Class
11 *
12 * The purpose of this class is to centralize common utility functions.
13 *
14 * @since 3.0.0
15 */
16 class Square_Helper {
17
18
19 /** encoding used for mb_*() string functions */
20 const MB_ENCODING = 'UTF-8';
21
22
23 /** String manipulation functions (all multi-byte safe) ***************/
24
25 /**
26 * Returns true if the haystack string starts with needle
27 *
28 * Note: case-sensitive
29 *
30 * @since 3.0.0
31 * @param string $haystack
32 * @param string $needle
33 * @return bool
34 */
35 public static function str_starts_with( $haystack, $needle ) {
36
37 if ( self::multibyte_loaded() ) {
38
39 if ( '' === $needle ) {
40 return true;
41 }
42
43 return 0 === mb_strpos( $haystack, $needle, 0, self::MB_ENCODING );
44
45 } else {
46
47 $needle = self::str_to_ascii( $needle );
48
49 if ( '' === $needle ) {
50 return true;
51 }
52
53 return 0 === strpos( self::str_to_ascii( $haystack ), self::str_to_ascii( $needle ) );
54 }
55 }
56
57 /**
58 * Returns true if the needle exists in haystack
59 *
60 * Note: case-sensitive
61 *
62 * @since 3.0.0
63 * @param string $haystack
64 * @param string $needle
65 * @return bool
66 */
67 public static function str_exists( $haystack, $needle ) {
68
69 if ( self::multibyte_loaded() ) {
70
71 if ( '' === $needle ) {
72 return false;
73 }
74
75 return false !== mb_strpos( $haystack, $needle, 0, self::MB_ENCODING );
76
77 } else {
78
79 $needle = self::str_to_ascii( $needle );
80
81 if ( '' === $needle ) {
82 return false;
83 }
84
85 return false !== strpos( self::str_to_ascii( $haystack ), self::str_to_ascii( $needle ) );
86 }
87 }
88
89 /**
90 * Returns a string with all non-ASCII characters removed. This is useful
91 * for any string functions that expect only ASCII chars and can't
92 * safely handle UTF-8. Note this only allows ASCII chars in the range
93 * 33-126 (newlines/carriage returns are stripped)
94 *
95 * @since 3.0.0
96 * @param string $string string to make ASCII
97 * @return string
98 */
99 public static function str_to_ascii( $string ) {
100
101 // Remove HTML tags.
102 $string = wp_strip_all_tags( $string );
103
104 // Encode HTML special characters.
105 $string = htmlspecialchars( $string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
106
107 // strip ASCII chars 32 and under; 127 and higher
108 return filter_var( $string, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH );
109 }
110
111 /**
112 * Truncates a given $string after a given $length if string is longer than
113 * $length. The last characters will be replaced with the $omission string
114 * for a total length not exceeding $length
115 *
116 * @since 3.0.0
117 * @param string $string text to truncate
118 * @param int $length total desired length of string, including omission
119 * @param string $omission omission text, defaults to '...'
120 * @return string
121 */
122 public static function str_truncate( $string, $length, $omission = '...' ) {
123
124 if ( self::multibyte_loaded() ) {
125
126 // bail if string doesn't need to be truncated
127 if ( mb_strlen( $string, self::MB_ENCODING ) <= $length ) {
128 return $string;
129 }
130
131 $length -= mb_strlen( $omission, self::MB_ENCODING );
132
133 return mb_substr( $string, 0, $length, self::MB_ENCODING ) . $omission;
134
135 } else {
136
137 $string = self::str_to_ascii( $string );
138
139 // bail if string doesn't need to be truncated
140 if ( strlen( $string ) <= $length ) {
141 return $string;
142 }
143
144 $length -= strlen( $omission );
145
146 return substr( $string, 0, $length ) . $omission;
147 }
148 }
149
150 /**
151 * Helper method to check if the multibyte extension is loaded, which
152 * indicates it's safe to use the mb_*() string methods
153 *
154 * @since 3.0.0
155 * @return bool
156 */
157 protected static function multibyte_loaded() {
158
159 return extension_loaded( 'mbstring' );
160 }
161
162
163 /** Array functions ***************************************************/
164
165
166 /**
167 * Insert the given element after the given key in the array
168 *
169 * Sample usage:
170 *
171 * given
172 *
173 * array( 'item_1' => 'foo', 'item_2' => 'bar' )
174 *
175 * array_insert_after( $array, 'item_1', array( 'item_1.5' => 'w00t' ) )
176 *
177 * becomes
178 *
179 * array( 'item_1' => 'foo', 'item_1.5' => 'w00t', 'item_2' => 'bar' )
180 *
181 * @since 3.0.0
182 * @param array $array array to insert the given element into
183 * @param string $insert_key key to insert given element after
184 * @param array $element element to insert into array
185 * @return array
186 */
187 public static function array_insert_after( array $array, $insert_key, array $element ) {
188
189 $new_array = array();
190
191 foreach ( $array as $key => $value ) {
192
193 $new_array[ $key ] = $value;
194
195 if ( $insert_key === $key ) {
196
197 foreach ( $element as $k => $v ) {
198 $new_array[ $k ] = $v;
199 }
200 }
201 }
202
203 return $new_array;
204 }
205
206 /**
207 * Lists an array as text.
208 *
209 * Takes an array and returns a list like "one, two, three, and four"
210 * with a (mandatory) oxford comma.
211 *
212 * @since 3.0.0
213 *
214 * @param array $items items to list
215 * @param string|null $conjunction coordinating conjunction, like "or" or "and"
216 * @param string $separator list separator, like a comma
217 * @return string
218 */
219 public static function list_array_items( array $items, $conjunction = null, $separator = '' ) {
220
221 if ( ! is_string( $conjunction ) ) {
222 $conjunction = _x( 'and', 'coordinating conjunction for a list of items: a, b, and c', 'woocommerce-square' );
223 }
224
225 // append the conjunction to the last item
226 if ( count( $items ) > 1 ) {
227
228 $last_item = array_pop( $items );
229
230 array_push( $items, trim( "{$conjunction} {$last_item}" ) );
231
232 // only use a comma if needed and no separator was passed
233 if ( count( $items ) < 3 ) {
234 $separator = ' ';
235 } elseif ( ! is_string( $separator ) || '' === $separator ) {
236 $separator = ', ';
237 }
238 }
239
240 return implode( $separator, $items );
241 }
242
243
244 /** Number helper functions *******************************************/
245
246
247 /**
248 * Format a number with 2 decimal points, using a period for the decimal
249 * separator and no thousands separator.
250 *
251 * Commonly used for payment gateways which require amounts in this format.
252 *
253 * @since 3.0.0
254 * @param float $number
255 * @return string
256 */
257 public static function number_format( $number ) {
258
259 return number_format( (float) $number, 2, '.', '' );
260 }
261
262 /**
263 * Determines if an order contains only virtual products.
264 *
265 * @since 3.0.0
266 * @param \WC_Order $order the order object
267 * @return bool
268 */
269 public static function is_order_virtual( \WC_Order $order ) {
270
271 $is_virtual = true;
272
273 foreach ( $order->get_items() as $item ) {
274 $product = $item->get_product();
275
276 // once we've found one non-virtual product we know we're done, break out of the loop
277 if ( $product && ! $product->is_virtual() ) {
278 $is_virtual = false;
279 break;
280 }
281 }
282
283 return $is_virtual;
284 }
285
286
287 /**
288 * Safely get sanitized data from $_POST
289 *
290 * @since 3.0.0
291 * @param string $key Array key to get from $_POST array.
292 * @param string $sanitize_callback Name of the sanitization callback function.
293 *
294 * @return string value from $_POST or blank string if $_POST[ $key ] is not set
295 */
296 public static function get_post( $key = '', $sanitize_callback = 'sanitize_text_field' ) {
297 if ( ! is_callable( $sanitize_callback ) ) {
298 $sanitize_callback = 'sanitize_text_field';
299 }
300
301 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
302 return isset( $_POST[ $key ] ) ? call_user_func( $sanitize_callback, wp_unslash( $_POST[ $key ] ) ) : '';
303 }
304
305
306 /**
307 * Safely get and trim data from $_REQUEST
308 *
309 * @since 3.0.0
310 * @param string $key Array key to get from $_REQUEST array.
311 * @param string $sanitize_callback Name of the sanitization callback function.
312 *
313 * @return string value from $_REQUEST or blank string if $_REQUEST[ $key ] is not set
314 */
315 public static function get_request( $key, $sanitize_callback = 'sanitize_text_field' ) {
316
317 if ( ! is_callable( $sanitize_callback ) ) {
318 $sanitize_callback = 'sanitize_text_field';
319 }
320
321 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
322 return isset( $_REQUEST[ $key ] ) ? call_user_func( $sanitize_callback, wp_unslash( $_REQUEST[ $key ] ) ) : '';
323 }
324
325 /**
326 * Add and store a notice.
327 *
328 * WC notice functions are not available in the admin
329 *
330 * @since 3.0.0
331 * @param string $message The text to display in the notice.
332 * @param string $notice_type The singular name of the notice type - either error, success or notice. [optional]
333 */
334 public static function wc_add_notice( $message, $notice_type = 'success' ) {
335
336 if ( function_exists( 'wc_add_notice' ) ) {
337 wc_add_notice( $message, $notice_type );
338 }
339 }
340
341 /**
342 * Gets the full URL to the log file for a given $handle
343 *
344 * @since 3.0.0
345 * @param string $handle log handle
346 * @return string URL to the WC log file identified by $handle
347 */
348 public static function get_wc_log_file_url( $handle ) {
349 return admin_url( sprintf( 'admin.php?page=wc-status&tab=logs&log_file=%s-%s-log', $handle, sanitize_file_name( wp_hash( $handle ) ) ) );
350 }
351
352
353 /**
354 * Gets the current WordPress site name.
355 *
356 * This is helpful for retrieving the actual site name instead of the
357 * network name on multisite installations.
358 *
359 * @since 3.0.0
360 * @return string
361 */
362 public static function get_site_name() {
363 return ( is_multisite() ) ? get_blog_details()->blogname : get_bloginfo( 'name' );
364 }
365
366 /**
367 * Displays a notice if the provided hook has not yet run.
368 *
369 * @since 3.0.0
370 *
371 * @param string $hook action hook to check
372 * @param string $method method/function name
373 * @param string $version version the notice was added
374 */
375 public static function maybe_doing_it_early( $hook, $method, $version ) {
376
377 if ( ! did_action( $hook ) ) {
378 Plugin_Compatibility::wc_doing_it_wrong( $method, "This should only be called after '{$hook}'", $version );
379 }
380 }
381
382 /**
383 * Triggers a PHP error.
384 *
385 * This wrapper method ensures AJAX isn't broken in the process.
386 *
387 * @since 3.0.0
388 * @param string $message the error message
389 * @param int $type Optional. The error type. Defaults to E_USER_NOTICE
390 */
391 public static function trigger_error( $message, $type = E_USER_NOTICE ) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
392 wc_deprecated_function( __METHOD__, '3.9.0' );
393
394 if ( wp_doing_ajax() ) {
395
396 switch ( $type ) {
397
398 case E_USER_NOTICE:
399 $prefix = 'Notice: ';
400 break;
401
402 case E_USER_WARNING:
403 $prefix = 'Warning: ';
404 break;
405
406 default:
407 $prefix = '';
408 }
409
410 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
411 error_log( $prefix . $message );
412
413 } else {
414 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
415 trigger_error( $message, $type );
416 }
417 }
418 }
419