<?php
/**
 * Detect IP and location of Visitors
 *
 * @class Class_DateBook_IP
 * @author Pagick Themes
 * @since 3.6
 */
	 

/**
 * Location detection class.
 */
class Class_DateBook_IP {


	/**
	 * Hook actions and filters.
	 * 
	 * @since 3.6
	 * @access public
	 */
	public static function init() {

		add_action( 'init', array( __CLASS__, 'set_setcookie') );
		add_action( 'datebook_ip_location', array( __CLASS__, 'get_details_from_IP_providers' ), 10, 1 );

	}


	/**
	 * Get current user IP Address.
	 *
	 * @return string
	 */
	public static function get_ip_address(){

		if (isset($_SERVER['HTTP_X_REAL_IP'])){ // WPCS: input var ok, CSRF ok.
			$ipaddress = wp_unslash($_SERVER['HTTP_X_REAL_IP']);  // WPCS: input var ok, CSRF ok.
		} else if (isset($_SERVER['HTTP_CLIENT_IP'])){
			$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
		} else if ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { // WPCS: input var ok, CSRF ok.
			// Proxy servers can send through this header like this: X-Forwarded-For: client1, proxy1, proxy2
			// Make sure we always only send through the first IP in the list which should always be the client IP.
			$ipaddress = (string) rest_is_ip_address( trim( current( preg_split( '/,/', wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR']))))); // WPCS: input var ok, CSRF ok.
		} else if(isset($_SERVER['HTTP_X_FORWARDED'])){
			$ipaddress = $_SERVER['HTTP_X_FORWARDED'];
		} else if(isset($_SERVER['HTTP_FORWARDED_FOR'])){
			$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
		} else if(isset($_SERVER['HTTP_FORWARDED'])){
			$ipaddress = $_SERVER['HTTP_FORWARDED'];
		} else if(isset($_SERVER['REMOTE_ADDR'])){
			$ipaddress = wp_unslash($_SERVER['REMOTE_ADDR']); // getenv('REMOTE_ADDR')
		} else {
			$ipaddress = '';
		}

		return trim($ipaddress);

	}


	/**
	 * Retrieve data from online provider
	 *
	 * @access private
	 * @return void
	 */
	private static function retrieve_from_location_provider($ip_service_url, $what_location_provider = '') {

		$response = '';

		if(in_array ('curl', get_loaded_extensions()) || function_exists('curl_init') !== false) {

			$ch = curl_init();
			curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
			curl_setopt($ch, CURLOPT_HEADER, 0);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($ch, CURLOPT_URL, $ip_service_url);
			curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
			$response = curl_exec($ch);
			curl_close($ch);

		} else if(ini_get('allow_url_fopen')){

			if($what_location_provider == 'geoplugin'){

				$response = unserialize(file_get_contents($ip_service_url));

			} else {

				$response = file_get_contents($ip_service_url);

			}

		}

		$data = json_decode($response,true);

		return $data;
			
	}


	/**
	 * Set and get cookie with local timezone of visitor
	 *
	 * @access public
	 */
	private static function detect_local_timezone(){

		$localtimezone = '';

		$datebook_visitor_timezone = isset( $_COOKIE['datebook_visitor_timezone'] ) ? $_COOKIE['datebook_visitor_timezone'] : '';

		if($datebook_visitor_timezone !== ''){

			$localtimezone = $datebook_visitor_timezone;

		} else {

			// Convert Timezone Offset in Minutes to a Timezone Name
			$timezone_offset_minutes = isset( $_COOKIE['datebook_visitor_timezone_set'] ) ? $_COOKIE['datebook_visitor_timezone_set'] : '';

			if($timezone_offset_minutes !== ''){

				// Convert minutes to seconds
				$timezone_name = timezone_name_from_abbr('', $timezone_offset_minutes * 60, false);

				date_default_timezone_set($timezone_name);

				$localtimezone = date_default_timezone_get();

			} else {
			
				$what_location_provider = of_get_option('localtime_providers') ? of_get_option('localtime_providers') : '';

				if($what_location_provider !== ''){

					$get_ip_address = self::get_ip_address();

					if ($get_ip_address !== ''){

						if($what_location_provider == 'ipinfo'){

							$ip_service_url = 'https://ipinfo.io/' . $get_ip_address . '/json';

						} else if($what_location_provider == 'iplocate'){

							$ip_service_url = 'https://www.iplocate.io/api/lookup/' . $get_ip_address;

						} else if($what_location_provider == 'geoplugin'){

							$ip_service_url = 'http://www.geoplugin.net/php.gp?ip=' . $get_ip_address;

						} else if($what_location_provider == 'ipinfodb'){

							$location_provider_apikey = of_get_option('location_apikey_ipinfodb') ? of_get_option('location_apikey_ipinfodb') : 0;

							$ip_service_url = 'http://api.ipinfodb.com/v3/ip-city/?key=' . $location_provider_apikey . '&ip=' . $get_ip_address . '&format=json';

						}

						$data = self::retrieve_from_location_provider($ip_service_url, $what_location_provider);

						if(isset($data['error']) && $data['error'] !== ''){

							// IPinfo.io - https://www.ipinfo.io/
							$what_location_provider = 'ipinfo';
							$ip_service_url = 'https://ipinfo.io/' . $get_ip_address . '/json';
							$data = self::retrieve_from_location_provider($ip_service_url, $what_location_provider);

							if(isset($data['error']) && $data['error'] !== ''){

								// IPlocate.io - https://www.iplocate.io/
								$what_location_provider = 'iplocate';
								$ip_service_url = 'https://www.iplocate.io/api/lookup/' . $get_ip_address;
								$data = self::retrieve_from_location_provider($ip_service_url, $what_location_provider);

								if(isset($data['error']) && $data['error'] !== ''){

									// geoplugin.net - https://www.geoplugin.net/
									$what_location_provider = 'geoplugin';
									$ip_service_url = 'http://www.geoplugin.net/php.gp?ip=' . $get_ip_address;
									$data = self::retrieve_from_location_provider($ip_service_url, $what_location_provider);

									if(isset($data['error']) && $data['error'] !== ''){

										// ipinfodb.com - https://www.ipinfodb.com
										$what_location_provider = 'ipinfodb';
										$location_provider_apikey = of_get_option('location_apikey_ipinfodb') ? of_get_option('location_apikey_ipinfodb') : 0;
										$ip_service_url = 'http://api.ipinfodb.com/v3/ip-city/?key=' . $location_provider_apikey . '&ip=' . $get_ip_address . '&format=json';
										$data = self::retrieve_from_location_provider($ip_service_url, $what_location_provider);

									}
								}
							}

						}
					
						if(isset($data['error']) && $data['error'] !== ''){
						
						} else {

							switch($what_location_provider) {
								case 'ipinfo' : $timezone = isset($data['timezone']) ? $data['timezone'] : ''; break;
								case 'iplocate' : $timezone = isset($data['time_zone']) ? $data['time_zone'] : ''; break;
								case 'geoplugin' : $timezone = isset($data['geoplugin_timezone']) ? $data['geoplugin_timezone'] : ''; break;
								case 'ipinfodb' : $timezone = isset($data['timeZone']) ? $data['timeZone'] : ''; break;
								default: $timezone = ''; break;
							}

							if(isset($timezone) && $timezone !== ''){

								$localtimezone = $timezone;

							}
						}
					}
				}
			}
		}

		return $localtimezone;

	}
	

	/**
	 * Set and get cookie with local timezone of visitor
	 *
	 * @access public
	 */
	public static function set_setcookie(){

		$datebook_visitor_timezone = isset($_COOKIE['datebook_visitor_timezone']) ? $_COOKIE['datebook_visitor_timezone'] : '';

		$cookie_timezone_detected = ($datebook_visitor_timezone !== '') ? 1 : 0;

		if($cookie_timezone_detected == 0){

			$timezone = self::detect_local_timezone();

			if($timezone !== ''){

				// Local timzone of visitor
				setcookie('datebook_visitor_timezone', $timezone, strtotime('+12 hours'), '/');  /* expires in 12 hours */

			}
		}
	}


	/**
	 * Get local time of user
	 *
	 * @access public
	 */
	public static function local_timezone($time){

		if ($time !== ''){

			$localtime = $time;

			$timezone = isset( $_COOKIE['datebook_visitor_timezone'] ) ? $_COOKIE['datebook_visitor_timezone'] : '';

			if($timezone !== ''){

				// Get local time and covert date of message to local time.
				$dt = new DateTime($time, new DateTimeZone('UTC'));
				$dt->setTimezone(new DateTimeZone($timezone));
				$localtime = $dt->format('Y-m-d H:i:s');

			}

			return strtotime($localtime);

		}

		return strtotime($time);

	}


	/**
	 * Select location providers
	 *
	 * @access public
	 * @return void
	 */
	private static function select_IP_providers($ip) {

		if(isset($ip)){

			$details_array = array();

			$what_location_provider = of_get_option('location_providers') ? of_get_option('location_providers') : 1;

			if($what_location_provider == 1){

				//  IPLocate.io - https://www.iplocate.io/
				$ip_service_url = 'https://www.iplocate.io/api/lookup/' . $ip;

			} else if($what_location_provider == 2){

				// GEOIP DB - https://geoip-db.com/
				$ip_service_url = 'https://geolocation-db.com/json/' . $ip;

			} else if($what_location_provider == 3){

				// IPInfoDB - http://ipinfodb.com/
				$location_provider_apikey = of_get_option('location_apikey_ipinfodb') ? of_get_option('location_apikey_ipinfodb') : '';

				$ip_service_url = 'http://api.ipinfodb.com/v3/ip-city?key=' . $location_provider_apikey . '&ip=' . $ip . '&format=json';

			} else {
				
				// db-ip.com - https://db-ip.com/
				$ip_service_url = 'http://api.db-ip.com/v2/free/' . $ip;
				
			}

			$data = self::retrieve_from_location_provider($ip_service_url);

			if(empty($data['city'])){

				// IPLocate.io - https://www.iplocate.io/
				$what_location_provider = 1;
				$ip_service_url = 'https://www.iplocate.io/api/lookup/' . $ip;
				$data = self::retrieve_from_location_provider($ip_service_url);
				
				if(empty($data['city'])){

					// GEOIP DB - https://geoip-db.com/
					$what_location_provider = 2;
					$ip_service_url = 'https://geolocation-db.com/json/' . $ip;
					$data = self::retrieve_from_location_provider($ip_service_url);
					
					if(empty($data['city'])){

						// IPInfoDB - http://ipinfodb.com/
						$what_location_provider = 3;
						$location_provider_apikey = of_get_option('location_apikey_ipinfodb') ? of_get_option('location_apikey_ipinfodb') : '';

						$ip_service_url = 'http://api.ipinfodb.com/v3/ip-city?key=' . $location_provider_apikey . '&ip=' . $ip . '&format=json';
						$data = self::retrieve_from_location_provider($ip_service_url);

						if(empty($data['city'])){

							// db-ip.com - https://db-ip.com/
							$what_location_provider = 4;
							$ip_service_url = 'http://api.db-ip.com/v2/free/' . $ip;
							$data = self::retrieve_from_location_provider($ip_service_url);

						}
					}
				}
			}

			if($what_location_provider == 1){

				// IPLocate.io - https://www.iplocate.io
				$details_array['ip'] = $ip;
				$details_array['country'] = $data['country'];
				$details_array['country_code'] = $data['country_code'];
				$details_array['state'] = $data['subdivision'];
				$details_array['city'] = $data['city'];
				$details_array['timezone'] = $data['time_zone'];

			} else if($what_location_provider == 2){

				// GEOIP DB - https://geolocation-db.com
				$details_array['ip'] = $ip;
				$details_array['country'] = $data['country_name'];
				$details_array['country_code'] = $data['country_code'];
				$details_array['state'] = $data['state'];
				$details_array['city'] = $data['city'];

			} else if($what_location_provider == 3){

				// IPInfoDB - https://ipinfodb.com
				$details_array['ip'] = $ip;
				$details_array['country'] = $data['countryName'];
				$details_array['country_code'] = $data['countryCode'];
				$details_array['state'] = $data['regionName'];
				$details_array['city'] = $data['cityName'];
				$details_array['timezone'] = $data['timeZone'];

			} else {
				
				// db-ip.com - https://db-ip.com/
				$details_array['ip'] = $ip;
				$details_array['country'] = $data['countryName'];
				$details_array['country_code'] = $data['countryCode'];
				$details_array['state'] = $data['stateProv'];
				$details_array['city'] = $data['city'];

			}

			return $details_array;

		}
	}


	/**
	 * Process location details
	 *
	 * @access public
	 * @return void
	 */
	public static function get_details_from_IP_providers($datebook_get_data) {
		
		$ip = isset($datebook_get_data['ip']) ? $datebook_get_data['ip'] : '';

		if($ip){

			$get_location_city = '';

			if(isset($datebook_get_data['ip_location_details']['ip']) && $datebook_get_data['ip_location_details']['ip'] == $ip){

				$get_location_ip = $ip;
				$get_location_country = isset($datebook_get_data['ip_location_details']['country']) ? $datebook_get_data['ip_location_details']['country'] : '';
				$get_location_country_code = isset($datebook_get_data['ip_location_details']['country_code']) ? $datebook_get_data['ip_location_details']['country_code'] : '';
				$get_location_state = isset($datebook_get_data['ip_location_details']['state']) ? $datebook_get_data['ip_location_details']['state'] : '';
				$get_location_city = isset($datebook_get_data['ip_location_details']['city']) ? $datebook_get_data['ip_location_details']['city'] : '';

			}
			
			if($get_location_city == '') {

				$get_location_details = self::select_IP_providers($ip);

				$get_location_ip = isset($get_location_details['ip']) ? $get_location_details['ip'] : '';
				$get_location_country = isset($get_location_details['country']) ? $get_location_details['country'] : '';
				$get_location_country_code = isset($get_location_details['country_code']) ? $get_location_details['country_code'] : '';
				$get_location_state = isset($get_location_details['state']) ? $get_location_details['state'] : '';
				$get_location_city = isset($get_location_details['city']) ? $get_location_details['city'] : '';

				// Save the location details to profile meta
				$get_location_array = array('ip' => $get_location_ip, 'country' => $get_location_country, 'country_code' => $get_location_country_code, 'state' => $get_location_state, 'city' => $get_location_city);

				$datebook_get_data['ip_location_details'] = $get_location_array;
				
				$profile_id = isset($datebook_get_data['profile_id']) ? $datebook_get_data['profile_id'] : get_the_ID();

				update_post_meta($profile_id, 'profile_personal_data', $datebook_get_data);

			}

			// Display location details to administrator
			if($get_location_ip || $get_location_country || $get_location_country_code || $get_location_state || $get_location_city){

				$country = $region = $city = '';
				if(isset($get_location_city)){
					$get_city = isset($datebook_get_data['city']) ? $datebook_get_data['city'] : 0;
					$term_data = DateBook_Utilities::datebook_get_term_by( 'id', $get_city );
					$country = isset($term_data->country) ? $term_data->country : '';
					$region = isset($term_data->region) ? $term_data->region : '';
					$city = isset($term_data->city) ? $term_data->city : '';
				}

				echo 'IP: ' . esc_attr($get_location_ip) . '<br>';

				echo esc_html__( 'Country', 'datebook' ) . ': ' . esc_attr($get_location_country . ' (' . $get_location_country_code) . ')<br>';

				echo esc_html__( 'State', 'datebook' ) . ': ' . esc_attr($get_location_state) . '<br>';

				echo esc_html__( 'City', 'datebook' ) . ': ' . esc_attr($get_location_city);

				echo '<hr />';

				if(isset($city) && isset($get_location_city) && $get_location_city != 'Not found'){
					if($city == $get_location_city){

						echo '<span class="badge badge-success float-right">' . esc_html__( 'Good', 'datebook' ) . '</span>';

					} else {

						echo '<span class="badge badge-danger float-right">' . esc_html__( 'Suspicious', 'datebook' ) . '</span>';

					}
				}

				echo esc_html__( 'City in profile', 'datebook' ) . ': ' . esc_attr($city);
				
			} else {
				
				echo '<div class="alert alert-warning">';
				echo esc_html__( 'Failed to get location information for several reasons: location provider is not selected in the theme options, location provider is not working', 'datebook' );
				echo '</div>';

			}

		} else {

			echo esc_html__( 'IP of this user has not been detected', 'datebook' );

		}
	}

}

Class_DateBook_IP::init();