PluginProbe ʕ •ᴥ•ʔ
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress / trunk
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress vtrunk
4.16.18 4.16.17 4.16.16 trunk 1.0 1.0.1 1.0.2 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5a 1.1.6 1.1.7 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4 1.4.1 1.4.2 1.5 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 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.7 1.7.1 1.7.2 1.8 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.1.9 2.2.10 2.2.11 2.2.12 2.2.13 2.2.14 2.2.15 2.2.16 2.2.2 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 3.0 3.1 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 4.0.0 4.0.1 4.0.2 4.0.3 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.10.2 4.10.3 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.13.3 4.13.4 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.15.0 4.15.1 4.15.10 4.15.11 4.15.12 4.15.13 4.15.14 4.15.15 4.15.16 4.15.17 4.15.18 4.15.19 4.15.2 4.15.20 4.15.20.1 4.15.21 4.15.22 4.15.23 4.15.24 4.15.25 4.15.3 4.15.4 4.15.5 4.15.6 4.15.7 4.15.8 4.15.9 4.16.0 4.16.1 4.16.10 4.16.11 4.16.12 4.16.13 4.16.14 4.16.15 4.16.2 4.16.3 4.16.4 4.16.5 4.16.6 4.16.7 4.16.8 4.16.9 4.2.0 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.7.0 4.8.0 4.9.0
wp-user-avatar / src / Classes / Geolocation.php
wp-user-avatar / src / Classes Last commit date
Installer 3 years ago AdminNotices.php 1 month ago AjaxHandler.php 1 year ago Autologin.php 9 months ago BlockRegistrations.php 10 months ago BuddyPressBbPress.php 3 years ago DisableConcurrentLogins.php 2 years ago EditUserProfile.php 5 months ago ExtensionManager.php 1 month ago FileUploader.php 3 months ago FormPreviewHandler.php 5 months ago FormRepository.php 1 year ago FormShortcodeDefaults.php 1 month ago GDPR.php 3 years ago Geolocation.php 3 years ago GlobalSiteAccess.php 3 years ago ImageUploader.php 1 year ago LoginAuth.php 1 year ago Miscellaneous.php 3 years ago ModifyRedirectDefaultLinks.php 5 months ago PPRESS_Session.php 1 year ago PROFILEPRESS_sql.php 1 year ago PasswordReset.php 1 year ago ProfileUrlRewrite.php 4 years ago RegistrationAuth.php 1 week ago SendEmail.php 3 years ago ShortcodeThemeFactory.php 5 years ago UserAvatar.php 1 year ago UserSignupLocationListingPage.php 3 years ago UsernameEmailRestrictLogin.php 4 years ago WPProfileFieldParserTrait.php 1 year ago WelcomeEmailAfterSignup.php 1 year ago default-email-template.php 1 year ago index.php 3 years ago
Geolocation.php
246 lines
1 <?php
2
3 namespace ProfilePress\Core\Classes;
4 /** @todo needed? */
5 class Geolocation
6 {
7 /**
8 * API endpoints for looking up user IP address.
9 *
10 * @var array
11 */
12 private static $ip_lookup_apis = array(
13 'ipify' => 'http://api.ipify.org/',
14 'ipecho' => 'http://ipecho.net/plain',
15 'ident' => 'http://ident.me',
16 'whatismyipaddress' => 'http://bot.whatismyipaddress.com',
17 );
18
19 /**
20 * API endpoints for geolocating an IP address
21 *
22 * @var array
23 */
24 private static $geoip_apis = array(
25 'ipinfo.io' => 'https://ipinfo.io/%s/json',
26 'ip-api.com' => 'http://ip-api.com/json/%s',
27 );
28
29 /**
30 * Get current user IP Address.
31 *
32 * @return string
33 */
34 public static function get_ip_address()
35 {
36 if (isset($_SERVER['HTTP_X_REAL_IP'])) {
37 return sanitize_text_field(wp_unslash($_SERVER['HTTP_X_REAL_IP']));
38 } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
39 // Proxy servers can send through this header like this: X-Forwarded-For: client1, proxy1, proxy2
40 // Make sure we always only send through the first IP in the list which should always be the client IP.
41 return (string)rest_is_ip_address(trim(current(preg_split('/,/', sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR']))))));
42 } elseif (isset($_SERVER['REMOTE_ADDR'])) {
43 return sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR']));
44 }
45
46 return '';
47 }
48
49 /**
50 * Get user IP Address using an external service.
51 * This can be used as a fallback for users on localhost where
52 * get_ip_address() will be a local IP and non-geolocatable.
53 *
54 * @return string
55 */
56 public static function get_external_ip_address()
57 {
58 $external_ip_address = '0.0.0.0';
59
60 if ('' !== self::get_ip_address()) {
61 $transient_name = 'external_ip_address_' . self::get_ip_address();
62 $external_ip_address = get_transient($transient_name);
63 }
64
65 if (false === $external_ip_address) {
66 $external_ip_address = '0.0.0.0';
67 $ip_lookup_services = apply_filters('ppress_geolocation_ip_lookup_apis', self::$ip_lookup_apis);
68 $ip_lookup_services_keys = array_keys($ip_lookup_services);
69 shuffle($ip_lookup_services_keys);
70
71 foreach ($ip_lookup_services_keys as $service_name) {
72 $service_endpoint = $ip_lookup_services[$service_name];
73 $response = wp_safe_remote_get($service_endpoint, array('timeout' => 2));
74
75 if ( ! is_wp_error($response) && rest_is_ip_address($response['body'])) {
76 $external_ip_address = apply_filters('ppress_geolocation_ip_lookup_api_response', ppress_clean($response['body']), $service_name);
77 break;
78 }
79 }
80
81 if (isset($transient_name)) {
82 set_transient($transient_name, $external_ip_address, DAY_IN_SECONDS);
83 }
84 }
85
86 return $external_ip_address;
87 }
88
89 /**
90 * Geolocate an IP address.
91 *
92 * @param string $ip_address IP Address.
93 * @param bool $fallback If true, fallbacks to alternative IP detection (can be slower).
94 * @param bool $api_fallback If true, uses geolocation APIs if the database file doesn't exist (can be slower).
95 *
96 * @return array
97 */
98 public static function geolocate_ip($ip_address = '', $fallback = false, $api_fallback = true)
99 {
100 // Filter to allow custom geolocation of the IP address.
101 $country_code = apply_filters('ppress_geolocate_ip', false, $ip_address, $fallback, $api_fallback);
102
103 if (false !== $country_code) {
104 return array(
105 'country' => $country_code,
106 'state' => '',
107 'city' => '',
108 'postcode' => '',
109 );
110 }
111
112 if (empty($ip_address)) {
113 $ip_address = self::get_ip_address();
114 $country_code = self::get_country_code_from_headers();
115 }
116
117 /**
118 * Get geolocation filter.
119 *
120 * @param array $geolocation Geolocation data, including country, state, city, and postcode.
121 * @param string $ip_address IP Address.
122 */
123 $geolocation = apply_filters(
124 'ppress_get_geolocation',
125 array(
126 'country' => $country_code,
127 'state' => '',
128 'city' => '',
129 'postcode' => '',
130 ),
131 $ip_address
132 );
133
134 // If we still haven't found a country code, let's consider doing an API lookup.
135 if ('' === $geolocation['country'] && $api_fallback) {
136 $geolocation['country'] = self::geolocate_via_api($ip_address);
137 }
138
139 // It's possible that we're in a local environment, in which case the geolocation needs to be done from the
140 // external address.
141 if ('' === $geolocation['country'] && $fallback) {
142 $external_ip_address = self::get_external_ip_address();
143
144 // Only bother with this if the external IP differs.
145 if ('0.0.0.0' !== $external_ip_address && $external_ip_address !== $ip_address) {
146 return self::geolocate_ip($external_ip_address, false, $api_fallback);
147 }
148 }
149
150 return array(
151 'country' => $geolocation['country'],
152 'state' => $geolocation['state'],
153 'city' => $geolocation['city'],
154 'postcode' => $geolocation['postcode'],
155 );
156 }
157
158 /**
159 * Fetches the country code from the request headers, if one is available.
160 *
161 * @return string The country code pulled from the headers, or empty string if one was not found.
162 */
163 private static function get_country_code_from_headers()
164 {
165 $country_code = '';
166
167 $headers = array(
168 'MM_COUNTRY_CODE',
169 'GEOIP_COUNTRY_CODE',
170 'HTTP_CF_IPCOUNTRY',
171 'HTTP_X_COUNTRY_CODE',
172 );
173
174 foreach ($headers as $header) {
175 if (empty($_SERVER[$header])) {
176 continue;
177 }
178
179 $country_code = strtoupper(sanitize_text_field(wp_unslash($_SERVER[$header])));
180 break;
181 }
182
183 return $country_code;
184 }
185
186 /**
187 * Use APIs to Geolocate the user.
188 *
189 * Geolocation APIs can be added through the use of the ppress_geolocation_geoip_apis filter.
190 * Provide a name=>value pair for service-slug=>endpoint.
191 *
192 * If APIs are defined, one will be chosen at random to fulfil the request. After completing, the result
193 * will be cached in a transient.
194 *
195 * @param string $ip_address IP address.
196 *
197 * @return string
198 */
199 private static function geolocate_via_api($ip_address)
200 {
201 $country_code = get_transient('geoip_' . $ip_address);
202
203 if (false === $country_code) {
204 $geoip_services = apply_filters('ppress_geolocation_geoip_apis', self::$geoip_apis);
205
206 if (empty($geoip_services)) {
207 return '';
208 }
209
210 $geoip_services_keys = array_keys($geoip_services);
211
212 shuffle($geoip_services_keys);
213
214 foreach ($geoip_services_keys as $service_name) {
215 $service_endpoint = $geoip_services[$service_name];
216 $response = wp_safe_remote_get(sprintf($service_endpoint, $ip_address), array('timeout' => 2));
217
218 if ( ! is_wp_error($response) && $response['body']) {
219 switch ($service_name) {
220 case 'ipinfo.io':
221 $data = json_decode($response['body']);
222 $country_code = isset($data->country) ? $data->country : '';
223 break;
224 case 'ip-api.com':
225 $data = json_decode($response['body']);
226 $country_code = isset($data->countryCode) ? $data->countryCode : ''; // @codingStandardsIgnoreLine
227 break;
228 default:
229 $country_code = apply_filters('ppress_geolocation_geoip_response_' . $service_name, '', $response['body']);
230 break;
231 }
232
233 $country_code = sanitize_text_field(strtoupper($country_code));
234
235 if ($country_code) {
236 break;
237 }
238 }
239 }
240
241 set_transient('geoip_' . $ip_address, $country_code, DAY_IN_SECONDS);
242 }
243
244 return $country_code;
245 }
246 }