PluginProbe
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More / 2.0.0
StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More v2.0.0
2.3.0 2.2.0 2.1.1 2.1.0 2.0.0 1.10.0 1.9.1 1.9.0 1.2.1 1.2.2 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 All 59 releases
storeengine / includes / utils / geolocation.php

geolocation.php in StoreEngine — Complete eCommerce Solution with Memberships, Licensing, Affiliates & More 2.0.0, at includes/utils/geolocation.php

151 lines 4.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * GeoLocation Helper Utility.
4 *
5 * @version 1.0.0
6 * @since 1.5.6
7 *
8 * @package StoreEngine/Utils
9 */
10
11 namespace StoreEngine\Utils;
12
13 use StoreEngine\Classes\Countries;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit;
17 }
18
19 class Geolocation {
20 use \StoreEngine\Utils\traits\Geolocation;
21 use \StoreEngine\Utils\traits\Maxmind;
22
23 /**
24 * Get current user/remote-client IP Address.
25 *
26 * @return string
27 */
28 public static function get_user_ip(): string {
29 if ( isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
30 return sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_REAL_IP'] ) );
31 } elseif ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
32 // Proxy servers can send through this header like this: X-Forwarded-For: client1, proxy1, proxy2
33 // Make sure we always only send through the first IP in the list which should always be the client IP.
34 $value = trim( strtok( sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ), ',' ) );
35 // $value = trim( current( preg_split( '/,/', sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) ) ) );
36 // Account for the '<IPv4 address>:<port>', '[<IPv6>]' and '[<IPv6>]:<port>' cases, removing the port.
37 // The regular expression is oversimplified on purpose, later 'rest_is_ip_address' will do the actual IP address validation.
38 /** @noinspection RegExpRedundantEscape */
39 $value = preg_replace( '/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\:.*|\[([^]]+)\].*/', '$1$2', $value );
40
41 return (string) rest_is_ip_address( $value );
42 } elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
43 // Make sure we always only send through the first IP in the list which should always be the client IP.
44 $value = trim( strtok( sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ), ',' ) );
45
46 return (string) rest_is_ip_address( $value );
47 }
48
49 // Return empty string if no valid IP is found
50 return '';
51 }
52
53 /**
54 * Uses geolocation to get the customer country and state only if they are valid values.
55 *
56 * @param array $fallback Fallback location.
57 *
58 * @return array
59 */
60 public static function get_customer_geolocation( array $fallback = [ 'country' => '', 'state' => '', ] ): array {
61 if ( Helper::is_bot() ) {
62 return $fallback;
63 }
64
65 $geolocation = self::geolocate_ip( '', true, false );
66
67 if ( empty( $geolocation['country'] ) ) {
68 return $fallback;
69 }
70
71 // Ensure geolocation is valid.
72 $allowed_countries = Countries::init()->get_allowed_countries();
73
74 if ( ! isset( $allowed_countries[ $geolocation['country'] ] ) ) {
75 return $fallback;
76 }
77
78 $allowed_states = Countries::init()->get_allowed_country_states();
79 $country_states = $allowed_states[ $geolocation['country'] ] ?? [];
80
81 if ( $country_states && ! isset( $country_states[ $geolocation['state'] ] ) ) {
82 $geolocation['state'] = '';
83 }
84
85 return [
86 'country' => $geolocation['country'],
87 'state' => $geolocation['state'],
88 ];
89 }
90
91 /**
92 * Get the customer's default location.
93 *
94 * Filtered, and set to base location or left blank. If cache-busting,
95 * this should only be used when 'location' is set in the querystring.
96 *
97 * @return array
98 */
99 public static function get_customer_default_location(): array {
100 $set_default_location_to = Helper::get_settings( 'default_customer_address', 'store-base' );
101
102 // Unless the location should be blank, use the base location as the default.
103 if ( '' !== $set_default_location_to ) {
104 $default_location_string = Helper::get_settings( 'store_country' ) . ':' . Helper::get_settings( 'store_state' );
105 }
106
107 /**
108 * Filter the customer default location before geolocation.
109 *
110 * @param string $default_location_string The default location.
111 *
112 * @return string
113 */
114 $default_location_string = apply_filters( 'storeengine/customer_default_location', $default_location_string ?? '' );
115 $default_location = Formatting::format_country_state_string( $default_location_string );
116
117 // Ensure defaults are valid.
118 $allowed_countries = Countries::init()->get_allowed_countries();
119
120 if ( ! in_array( $default_location['country'], array_keys( $allowed_countries ), true ) ) {
121 $default_location = [
122 'country' => '',
123 'state' => '',
124 ];
125 }
126
127 // Geolocation takes priority if geolocation is possible.
128 if ( in_array( $set_default_location_to, [ 'ip-geolocation', 'geolocation' ], true ) ) {
129 $default_location = self::get_customer_geolocation( $default_location );
130 }
131
132 if ( empty( $default_location['country'] ) ) {
133 $default_location = [
134 'country' => Helper::get_settings( 'checkout_default_country' ),
135 'state' => '',
136 ];
137 }
138
139 /**
140 * Filter the customer default location after geolocation.
141 *
142 * @param array $customer_location The customer location with keys 'country' and 'state'.
143 *
144 * @return array
145 */
146 return apply_filters( 'storeengine/customer_default_location_array', $default_location );
147 }
148 }
149
150 // End of file geolocation.php.
151