Passed
Push — master ( 1ce22f...41fbb9 )
by Brian
09:44 queued 04:28
created

extract_downloaded_database()   A

Complexity

Conditions 2
Paths 10

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
c 1
b 0
f 0
dl 0
loc 22
rs 9.8666
cc 2
nc 10
nop 1
1
<?php
2
/**
3
 * The MaxMind database service class file.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * The service class responsible for interacting with MaxMind databases.
11
 *
12
 * @since 1.0.19
13
 */
14
class GetPaid_MaxMind_Database_Service {
15
16
	/**
17
	 * The name of the MaxMind database to utilize.
18
	 */
19
	const DATABASE = 'GeoLite2-Country';
20
21
	/**
22
	 * The extension for the MaxMind database.
23
	 */
24
	const DATABASE_EXTENSION = '.mmdb';
25
26
	/**
27
	 * A prefix for the MaxMind database filename.
28
	 *
29
	 * @var string
30
	 */
31
	private $database_prefix;
32
33
	/**
34
	 * Class constructor.
35
	 *
36
	 * @param string|null $database_prefix A prefix for the MaxMind database filename.
37
	 */
38
	public function __construct( $database_prefix ) {
39
		$this->database_prefix = $database_prefix;
40
	}
41
42
	/**
43
	 * Fetches the path that the database should be stored.
44
	 *
45
	 * @return string The local database path.
46
	 */
47
	public function get_database_path() {
48
		$uploads_dir = wp_upload_dir();
49
50
		$database_path = trailingslashit( $uploads_dir['basedir'] ) . 'invoicing/';
51
		if ( ! empty( $this->database_prefix ) ) {
52
			$database_path .= $this->database_prefix . '-';
53
		}
54
		$database_path .= self::DATABASE . self::DATABASE_EXTENSION;
55
56
		// Filter the geolocation database storage path.
57
		return apply_filters( 'getpaid_maxmind_geolocation_database_path', $database_path );
58
	}
59
60
	/**
61
	 * Fetches the database from the MaxMind service.
62
	 *
63
	 * @param string $license_key The license key to be used when downloading the database.
64
	 * @return string|WP_Error The path to the database file or an error if invalid.
65
	 */
66
	public function download_database( $license_key ) {
67
68
		$download_uri = add_query_arg(
69
			array(
70
				'edition_id'  => self::DATABASE,
71
				'license_key' => urlencode( wpinv_clean( $license_key ) ),
72
				'suffix'      => 'tar.gz',
73
			),
74
			'https://download.maxmind.com/app/geoip_download'
75
		);
76
77
		// Needed for the download_url call right below.
78
		require_once ABSPATH . 'wp-admin/includes/file.php';
79
80
		$tmp_archive_path = download_url( esc_url_raw( $download_uri ) );
81
82
		if ( is_wp_error( $tmp_archive_path ) ) {
83
			// Transform the error into something more informative.
84
			$error_data = $tmp_archive_path->get_error_data();
85
			if ( isset( $error_data['code'] ) && $error_data['code'] == 401 ) {
86
				return new WP_Error(
87
					'getpaid_maxmind_geolocation_database_license_key',
88
					__( 'The MaxMind license key is invalid. If you have recently created this key, you may need to wait for it to become active.', 'invoicing' )
89
				);
90
			}
91
92
			return new WP_Error( 'getpaid_maxmind_geolocation_database_download', __( 'Failed to download the MaxMind database.', 'invoicing' ) );
93
		}
94
95
		// Extract the database from the archive.
96
		return $this->extract_downloaded_database( $tmp_archive_path );
0 ignored issues
show
Bug introduced by
$tmp_archive_path of type WP_Error is incompatible with the type string expected by parameter $tmp_archive_path of GetPaid_MaxMind_Database...t_downloaded_database(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

96
		return $this->extract_downloaded_database( /** @scrutinizer ignore-type */ $tmp_archive_path );
Loading history...
97
98
	}
99
100
	/**
101
	 * Extracts the downloaded database.
102
	 *
103
	 * @param string $tmp_archive_path The database archive path.
104
	 * @return string|WP_Error The path to the database file or an error if invalid.
105
	 */
106
	protected function extract_downloaded_database( $tmp_archive_path ) {
107
108
		// Extract the database from the archive.
109
		try {
110
111
			$file              = new PharData( $tmp_archive_path );
112
			$tmp_database_path = trailingslashit( dirname( $tmp_archive_path ) ) . trailingslashit( $file->current()->getFilename() ) . self::DATABASE . self::DATABASE_EXTENSION;
113
114
			$file->extractTo(
115
				dirname( $tmp_archive_path ),
116
				trailingslashit( $file->current()->getFilename() ) . self::DATABASE . self::DATABASE_EXTENSION,
117
				true
118
			);
119
120
		} catch ( Exception $exception ) {
121
			return new WP_Error( 'invoicing_maxmind_geolocation_database_archive', $exception->getMessage() );
122
		} finally {
123
			// Remove the archive since we only care about a single file in it.
124
			unlink( $tmp_archive_path );
125
		}
126
127
		return $tmp_database_path;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tmp_database_path does not seem to be defined for all execution paths leading up to this point.
Loading history...
128
	}
129
130
	/**
131
	 * Fetches the ISO country code associated with an IP address.
132
	 *
133
	 * @param string $ip_address The IP address to find the country code for.
134
	 * @return string The country code for the IP address, or empty if not found.
135
	 */
136
	public function get_iso_country_code_for_ip( $ip_address ) {
137
		$country_code = '';
138
139
		if ( ! class_exists( 'MaxMind\Db\Reader' ) ) {
140
			return $country_code;
141
		}
142
143
		$database_path = $this->get_database_path();
144
		if ( ! file_exists( $database_path ) ) {
145
			return $country_code;
146
		}
147
148
		try {
149
			$reader = new MaxMind\Db\Reader( $database_path );
150
			$data   = $reader->get( $ip_address );
151
152
			if ( isset( $data['country']['iso_code'] ) ) {
153
				$country_code = $data['country']['iso_code'];
154
			}
155
156
			$reader->close();
157
		} catch ( Exception $e ) {
158
			wpinv_error_log( $e->getMessage(), 'SOURCE: MaxMind GeoLocation' );
159
		}
160
161
		return $country_code;
162
	}
163
164
}
165