Admin
11 months ago
Compatibility
11 months ago
Helpers
11 months ago
Providers
11 months ago
Queue
11 months ago
Reports
11 months ago
Tasks
11 months ago
UsageTracking
11 months ago
AbstractConnection.php
11 months ago
Conflicts.php
11 months ago
Connect.php
11 months ago
Connection.php
11 months ago
ConnectionInterface.php
11 months ago
ConnectionsManager.php
11 months ago
Core.php
11 months ago
DBRepair.php
11 months ago
Debug.php
11 months ago
Geo.php
11 months ago
MailCatcher.php
11 months ago
MailCatcherInterface.php
11 months ago
MailCatcherTrait.php
11 months ago
MailCatcherV6.php
11 months ago
Migration.php
11 months ago
MigrationAbstract.php
11 months ago
Migrations.php
11 months ago
OptimizedEmailSending.php
11 months ago
Options.php
11 months ago
Processor.php
11 months ago
SiteHealth.php
11 months ago
Upgrade.php
11 months ago
Uploads.php
11 months ago
WP.php
11 months ago
WPMailArgs.php
11 months ago
WPMailInitiator.php
11 months ago
Geo.php
226 lines
| 1 | <?php |
| 2 | |
| 3 | namespace WPMailSMTP; |
| 4 | |
| 5 | /** |
| 6 | * Class Geo to work with location, domain, IPs etc. |
| 7 | * |
| 8 | * @since 1.5.0 |
| 9 | */ |
| 10 | class Geo { |
| 11 | |
| 12 | /** |
| 13 | * Get the current site hostname. |
| 14 | * In case of CLI we don't have SERVER_NAME, so use host name instead, may be not a domain name. |
| 15 | * Examples: example.com, localhost. |
| 16 | * |
| 17 | * @since 1.5.0 |
| 18 | * |
| 19 | * @return string |
| 20 | */ |
| 21 | public static function get_site_domain() { |
| 22 | |
| 23 | return ! empty( $_SERVER['SERVER_NAME'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_NAME'] ) ) : wp_parse_url( get_home_url( get_current_blog_id() ), PHP_URL_HOST ); |
| 24 | } |
| 25 | |
| 26 | /** |
| 27 | * Get the domain IP address. |
| 28 | * Uses gethostbyname() which is quite slow, but this is done only one time. |
| 29 | * |
| 30 | * @since 1.5.0 |
| 31 | * |
| 32 | * @param string $domain |
| 33 | * |
| 34 | * @return string |
| 35 | */ |
| 36 | public static function get_ip_by_domain( $domain ) { |
| 37 | |
| 38 | if ( $domain === 'localhost' ) { |
| 39 | return '127.0.0.1'; |
| 40 | } |
| 41 | |
| 42 | return gethostbyname( $domain ); |
| 43 | } |
| 44 | |
| 45 | /** |
| 46 | * Get the location coordinates by IP address. |
| 47 | * We make a request to 3rd party services. |
| 48 | * |
| 49 | * @since 1.5.0 |
| 50 | * @since 1.6.0 Added new geo API endpoint, provided by WPForms. |
| 51 | * @since 2.0.0 Updated the WPForms geo API endpoint to v3. |
| 52 | * |
| 53 | * @param string $ip The IP address. |
| 54 | * |
| 55 | * @return array Empty array for localhost. |
| 56 | */ |
| 57 | public static function get_location_by_ip( $ip ) { |
| 58 | |
| 59 | // Check for a non-local IP. |
| 60 | if ( empty( $ip ) || in_array( $ip, [ '127.0.0.1', '::1' ], true ) ) { |
| 61 | return []; |
| 62 | } |
| 63 | |
| 64 | $request = wp_remote_get( 'https://geo.wpforms.com/v3/geolocate/json/' . $ip ); |
| 65 | |
| 66 | if ( ! is_wp_error( $request ) ) { |
| 67 | $request = json_decode( wp_remote_retrieve_body( $request ), true ); |
| 68 | if ( ! empty( $request['latitude'] ) && ! empty( $request['longitude'] ) ) { |
| 69 | $data = [ |
| 70 | 'latitude' => sanitize_text_field( $request['latitude'] ), |
| 71 | 'longitude' => sanitize_text_field( $request['longitude'] ), |
| 72 | 'city' => isset( $request['city'] ) ? sanitize_text_field( $request['city'] ) : '', |
| 73 | 'region' => isset( $request['region_name'] ) ? sanitize_text_field( $request['region_name'] ) : '', |
| 74 | 'country' => isset( $request['country_iso'] ) ? sanitize_text_field( $request['country_iso'] ) : '', |
| 75 | 'postal' => isset( $request['zip_code'] ) ? sanitize_text_field( $request['zip_code'] ) : '', |
| 76 | ]; |
| 77 | |
| 78 | return $data; |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | $request = wp_remote_get( 'https://ipapi.co/' . $ip . '/json' ); |
| 83 | |
| 84 | if ( ! is_wp_error( $request ) ) { |
| 85 | |
| 86 | $request = json_decode( wp_remote_retrieve_body( $request ), true ); |
| 87 | |
| 88 | if ( ! empty( $request['latitude'] ) && ! empty( $request['longitude'] ) ) { |
| 89 | |
| 90 | $data = [ |
| 91 | 'latitude' => sanitize_text_field( $request['latitude'] ), |
| 92 | 'longitude' => sanitize_text_field( $request['longitude'] ), |
| 93 | 'city' => isset( $request['city'] ) ? sanitize_text_field( $request['city'] ) : '', |
| 94 | 'region' => isset( $request['region'] ) ? sanitize_text_field( $request['region'] ) : '', |
| 95 | 'country' => isset( $request['country'] ) ? sanitize_text_field( $request['country'] ) : '', |
| 96 | 'postal' => isset( $request['postal'] ) ? sanitize_text_field( $request['postal'] ) : '', |
| 97 | ]; |
| 98 | |
| 99 | return $data; |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | $request = wp_remote_get( |
| 104 | 'https://tools.keycdn.com/geo.json?host=' . $ip, |
| 105 | [ |
| 106 | 'user-agent' => 'keycdn-tools:' . get_home_url(), |
| 107 | ] |
| 108 | ); |
| 109 | |
| 110 | if ( ! is_wp_error( $request ) ) { |
| 111 | |
| 112 | $request = json_decode( wp_remote_retrieve_body( $request ), true ); |
| 113 | |
| 114 | if ( ! empty( $request['data']['geo']['latitude'] ) && ! empty( $request['data']['geo']['longitude'] ) ) { |
| 115 | |
| 116 | $data = [ |
| 117 | 'latitude' => sanitize_text_field( $request['data']['geo']['latitude'] ), |
| 118 | 'longitude' => sanitize_text_field( $request['data']['geo']['longitude'] ), |
| 119 | 'city' => isset( $request['data']['geo']['city'] ) ? sanitize_text_field( $request['data']['geo']['city'] ) : '', |
| 120 | 'region' => isset( $request['data']['geo']['region_name'] ) ? sanitize_text_field( $request['data']['geo']['region_name'] ) : '', |
| 121 | 'country' => isset( $request['data']['geo']['country_code'] ) ? sanitize_text_field( $request['data']['geo']['country_code'] ) : '', |
| 122 | 'postal' => isset( $request['data']['geo']['postal_code'] ) ? sanitize_text_field( $request['data']['geo']['postal_code'] ) : '', |
| 123 | ]; |
| 124 | |
| 125 | return $data; |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | return []; |
| 130 | } |
| 131 | |
| 132 | /** |
| 133 | * This routine calculates the distance between two points (given the latitude/longitude of those points). |
| 134 | * Definitions: South latitudes are negative, east longitudes are positive. |
| 135 | * |
| 136 | * @see https://www.geodatasource.com/developers/php |
| 137 | * |
| 138 | * @since 1.5.0 |
| 139 | * |
| 140 | * @param float $lat1 Latitude of point 1 (in decimal degrees). |
| 141 | * @param float $lon1 Longitude of point 1 (in decimal degrees). |
| 142 | * @param float $lat2 Latitude of point 2 (in decimal degrees). |
| 143 | * @param float $lon2 Longitude of point 2 (in decimal degrees). |
| 144 | * @param string $unit Supported values: M, K, N. Miles by default. |
| 145 | * |
| 146 | * @return float|int |
| 147 | */ |
| 148 | public static function get_distance_between( $lat1, $lon1, $lat2, $lon2, $unit = 'M' ) { |
| 149 | |
| 150 | if ( ( $lat1 === $lat2 ) && ( $lon1 === $lon2 ) ) { |
| 151 | return 0; |
| 152 | } |
| 153 | |
| 154 | $theta = $lon1 - $lon2; |
| 155 | $dist = sin( deg2rad( $lat1 ) ) * sin( deg2rad( $lat2 ) ) + cos( deg2rad( $lat1 ) ) * cos( deg2rad( $lat2 ) ) * cos( deg2rad( $theta ) ); |
| 156 | $dist = acos( $dist ); |
| 157 | $dist = rad2deg( $dist ); |
| 158 | $miles = $dist * 60 * 1.1515; |
| 159 | $unit = strtoupper( $unit ); |
| 160 | |
| 161 | if ( $unit === 'K' ) { |
| 162 | return ( $miles * 1.609344 ); |
| 163 | } elseif ( $unit === 'N' ) { |
| 164 | return ( $miles * 0.8684 ); |
| 165 | } |
| 166 | |
| 167 | return $miles; |
| 168 | } |
| 169 | |
| 170 | /** |
| 171 | * Get the user IP address. |
| 172 | * |
| 173 | * @since 3.11.0 |
| 174 | * |
| 175 | * Code based on the: |
| 176 | * - WordPress method \WP_Community_Events::get_unsafe_client_ip |
| 177 | * - Cloudflare documentation https://support.cloudflare.com/hc/en-us/articles/206776727 |
| 178 | * |
| 179 | * @return string |
| 180 | */ |
| 181 | public static function get_ip() { |
| 182 | |
| 183 | $ip = '127.0.0.1'; |
| 184 | |
| 185 | $address_headers = [ |
| 186 | 'HTTP_TRUE_CLIENT_IP', |
| 187 | 'HTTP_CF_CONNECTING_IP', |
| 188 | 'HTTP_X_REAL_IP', |
| 189 | 'HTTP_CLIENT_IP', |
| 190 | 'HTTP_X_FORWARDED_FOR', |
| 191 | 'HTTP_X_FORWARDED', |
| 192 | 'HTTP_X_CLUSTER_CLIENT_IP', |
| 193 | 'HTTP_FORWARDED_FOR', |
| 194 | 'HTTP_FORWARDED', |
| 195 | 'REMOTE_ADDR', |
| 196 | ]; |
| 197 | |
| 198 | foreach ( $address_headers as $header ) { |
| 199 | if ( empty( $_SERVER[ $header ] ) ) { |
| 200 | continue; |
| 201 | } |
| 202 | |
| 203 | /* |
| 204 | * HTTP_X_FORWARDED_FOR can contain a chain of comma-separated addresses, with or without spaces. |
| 205 | * The first address is the original client. It can't be trusted for authenticity, |
| 206 | * but we don't need to for this purpose. |
| 207 | */ |
| 208 | |
| 209 | // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized |
| 210 | $address_chain = explode( ',', wp_unslash( $_SERVER[ $header ] ) ); |
| 211 | $ip = filter_var( trim( $address_chain[0] ), FILTER_VALIDATE_IP ); |
| 212 | |
| 213 | break; |
| 214 | } |
| 215 | |
| 216 | /** |
| 217 | * Filter detected IP address. |
| 218 | * |
| 219 | * @since 3.11.0 |
| 220 | * |
| 221 | * @param string $ip IP address. |
| 222 | */ |
| 223 | return filter_var( apply_filters( 'wp_mail_smtp_geo_get_ip', $ip ), FILTER_VALIDATE_IP ); |
| 224 | } |
| 225 | } |
| 226 |