Completed
Push — add/gdpr-ads-compliance-2 ( 2d78bf )
by
unknown
09:47
created

Jetpack_Geolocation::remove_geolite_db()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Class Jetpack_Geolocation
5
 */
6
class Jetpack_Geolocation {
7
8
	protected $geolite_folder;
9
10
	protected $geolite_files = array (
11
		'ipv4'      => 'GeoLite2-Country-Blocks-IPv4.csv',
12
		'ipv6'      => 'GeoLite2-Country-Blocks-IPv6.csv',
13
		'countries' => 'GeoLite2-Country-Locations-en.csv',
14
	);
15
16
	protected $geolite_download_url = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country-CSV.zip';
17
18
	function __construct() {
19
		$upload_dir = wp_upload_dir();
20
		$this->geolite_folder = apply_filters( 'jetpack_geolocation_local_database_path', $upload_dir['basedir'] . '/geolite2/' );
21
		add_filter( 'cron_schedules', array( $this, 'add_monthly_cron_schedule' ) );
22
		add_action( 'jetpack_download_geolite2_ip_db', array( $this, 'download_geolite_db' ) );
23
24
		if ( ! wp_next_scheduled( 'jetpack_download_geolite2_ip_db' ) ) {
25
			wp_schedule_event( strtotime( '1 minute' ), 'monthly', 'jetpack_download_geolite2_ip_db' );
26
		}
27
	}
28
29
	/**
30
	 * This function is adapted from WP Core's WP_Community_Events::get_unsafe_client_ip()
31
	 *
32
	 * Determines the user's actual IP address and attempts to partially
33
	 * anonymize an IP address by converting it to a network ID.
34
	 *
35
	 * Geolocating the network ID usually returns a similar location as the
36
	 * actual IP, but provides some privacy for the user.
37
	 *
38
	 * $_SERVER['REMOTE_ADDR'] cannot be used in all cases, such as when the user
39
	 * is making their request through a proxy, or when the web server is behind
40
	 * a proxy. In those cases, $_SERVER['REMOTE_ADDR'] is set to the proxy address rather
41
	 * than the user's actual address.
42
	 *
43
	 * Modified from https://stackoverflow.com/a/2031935/450127, MIT license.
44
	 * Modified from https://github.com/geertw/php-ip-anonymizer, MIT license.
45
	 *
46
	 * @since 4.8.0
47
	 *
48
	 * @return false|string The anonymized address on success; the given address
49
	 *                      or false on failure.
50
	 */
51
	public static function get_visitor_ip_address() {
52
		$client_ip = false;
53
		// In order of preference, with the best ones for this purpose first.
54
		$address_headers = array(
55
			'HTTP_CLIENT_IP',
56
			'HTTP_X_FORWARDED_FOR',
57
			'HTTP_X_FORWARDED',
58
			'HTTP_X_CLUSTER_CLIENT_IP',
59
			'HTTP_FORWARDED_FOR',
60
			'HTTP_FORWARDED',
61
			'REMOTE_ADDR',
62
		);
63
		foreach ( $address_headers as $header ) {
64
			if ( array_key_exists( $header, $_SERVER ) ) {
65
				/*
66
				 * HTTP_X_FORWARDED_FOR can contain a chain of comma-separated
67
				 * addresses. The first one is the original client. It can't be
68
				 * trusted for authenticity, but we don't need to for this purpose.
69
				 */
70
				$address_chain = explode( ',', $_SERVER[ $header ] );
71
				$client_ip     = trim( $address_chain[0] );
72
				break;
73
			}
74
		}
75
		return $client_ip;
76
	}
77
78
	function get_ip_country( $ip_address = false ) {
79
		$country_headers = array(
80
			'HTTP_CF_IPCOUNTRY',
81
			'GEOIP_COUNTRY_CODE',
82
			'HTTP_X_COUNTRY_CODE',
83
		);
84
85
		if ( ! $ip_address ) {
86
			$ip_address = $this->get_visitor_ip_address();
87
		}
88
89
		foreach ( $country_headers as $header ) {
90
			if ( array_key_exists( $header, $_SERVER ) ) {
91
				$country_code = sanitize_text_field( stripslashes( $_SERVER[ $header ] ) );
92
				break;
93
			}
94
		}
95
96
		if ( ! isset( $country_code ) ) {
97
			$country_code = geolite_ip_lookup( $ip_address );
98
		}
99
100
		return $country_code;
101
	}
102
103
	function geolite_ip_lookup( $ip_address = false ) {
104
105
		if ( ! $ip_address ) {
106
			$ip_address = $this->get_visitor_ip_address();
107
		}
108
109
		// If any of our geolite2 files are missing, download the db and return false.
110
		foreach ( $this->geolite_files as $geolite_file ) {
111
			if ( ! file_exists( $this->geolite_folder . '/' . $geolite_file ) ) {
112
				$this->download_geolite_db();
113
				return false;
114
			}
115
		}
116
117
		// Determine ip address type. Default to ipv6 because the database is much smaller (faster lookup).
118
		if ( filter_var( $ip_address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
119
			$ip_type = array(
0 ignored issues
show
Unused Code introduced by
$ip_type is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
120
				'type'      => 'ipv6',
121
				'delimiter' => ':',
122
			);
123
		} elseif ( filter_var( $ip_address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
124
			$ip_type =  array(
0 ignored issues
show
Unused Code introduced by
$ip_type is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
125
				'type'      => 'ipv4',
126
				'delimiter' => '.',
127
			);
128
		} else {
129
			return false;
130
		}
131
132
		// @TODO Lookup IP in the csv files.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
133
	}
134
135
	function download_geolite_db() {
136
		require_once ABSPATH . 'wp-admin/includes/file.php';
137
		require_once ABSPATH . WPINC . '/pluggable.php';
138
		WP_Filesystem();
139
		global $wp_filesystem;
140
141
		try {
142
			// Download the geolite2 database and save it to a temp folder.
143
			$tmp_geolite_path = download_url( $this->geolite_download_url );
144
			$unzip_action = unzip_file( $tmp_geolite_path, $this->geolite_folder . 'tmp/' );
0 ignored issues
show
Unused Code introduced by
$unzip_action is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
145
146
			// The zip contents contain a dated folder with the files inside. Find the folder name (dated for the current release).
147
			$unzipped_files = scandir( $this->geolite_folder . 'tmp/' );
148
			foreach ( $unzipped_files as $tmp_folder ) {
149
150
				if ( false !== strpos( $tmp_folder, 'GeoLite2-Country-CSV' ) ) {
151
					$files = scandir( $this->geolite_folder . 'tmp/' . $tmp_folder );
152
153
					// Move the files out of the temp folder, overwriting previous version if they exist.
154
					foreach ( $files as $file ) {
155
						if ( is_file( $file ) ) {
156
							$wp_filesystem->move( $this->geolite_folder . 'tmp/' . $tmp_folder . '/' . $file, $this->geolite_folder . '/' . $file, true );
157
						}
158
					}
159
				}
160
			}
161
162
			// Delete the tmp folder.
163
			$wp_filesystem->delete( $this->geolite_folder . 'tmp/', true );
164
165
		} catch ( Exception $e ) {
166
			error_log( $e->getMessage() );
167
		}
168
169
		@unlink( $tmp_geolite_path );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
170
	}
171
172
	function remove_geolite_db() {
173
		global $wp_filesystem;
174
		$wp_filesystem->delete( $this->geolite_folder, true );
175
		wp_clear_scheduled_hook( 'jetpack_download_geolite2_ip_db' );
176
	}
177
178
	/**
179
	 * Add a 'monthly' cron schedule.
180
	 *
181
	 * @param  array $schedules List of WP scheduled cron jobs.
0 ignored issues
show
Documentation introduced by
There is no parameter named $schedules. Did you maybe mean $cron_schedules?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
182
	 * @return array
183
	 */
184
	public static function add_monthly_cron_schedule( $cron_schedules ) {
185
		$cron_schedules['monthly'] = array(
186
			'interval' => 2635200,
187
			'display'  => __( 'Monthly', 'jetpack' ),
188
		);
189
		return $cron_schedules;
190
	}
191
192
} // class Jetpack_Geolocation
193
194
$Jetpack_Geolocation = new Jetpack_Geolocation();
195
register_activation_hook( __FILE__, array( 'Jetpack_Geolocation', 'download_geolite_db' ) );
196
register_deactivation_hook( __FILE__, array( 'Jetpack_Geolocation', 'remove_geolite_db' ) );
197