Merge branch 'master' into pr-25242
This commit is contained in:
commit
cb85c981ac
|
@ -7,11 +7,12 @@
|
|||
"prefer-stable": true,
|
||||
"minimum-stability": "dev",
|
||||
"require": {
|
||||
"automattic/jetpack-autoloader": "^1.2.0",
|
||||
"php": ">=5.6|>=7.0",
|
||||
"automattic/jetpack-autoloader": "^1.2.0",
|
||||
"composer/installers": "1.7.0",
|
||||
"woocommerce/woocommerce-blocks": "2.5.7",
|
||||
"woocommerce/woocommerce-rest-api": "1.0.5"
|
||||
"maxmind-db/reader": "1.6.0",
|
||||
"woocommerce/woocommerce-blocks": "2.5.10",
|
||||
"woocommerce/woocommerce-rest-api": "1.0.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "7.5.18",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "95355370e5e250e500f8114896d52f7a",
|
||||
"content-hash": "e8edf85437f4ee3362f0447d20314506",
|
||||
"packages": [
|
||||
{
|
||||
"name": "automattic/jetpack-autoloader",
|
||||
|
@ -165,17 +165,77 @@
|
|||
"time": "2019-08-12T15:00:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-blocks",
|
||||
"version": "v2.5.7",
|
||||
"name": "maxmind-db/reader",
|
||||
"version": "v1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/woocommerce/woocommerce-gutenberg-products-block.git",
|
||||
"reference": "24b6552d38204fbbdd87ec5ba76f3ec391b042d0"
|
||||
"url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git",
|
||||
"reference": "febd4920bf17c1da84cef58e56a8227dfb37fbe4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/24b6552d38204fbbdd87ec5ba76f3ec391b042d0",
|
||||
"reference": "24b6552d38204fbbdd87ec5ba76f3ec391b042d0",
|
||||
"url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/febd4920bf17c1da84cef58e56a8227dfb37fbe4",
|
||||
"reference": "febd4920bf17c1da84cef58e56a8227dfb37fbe4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6"
|
||||
},
|
||||
"conflict": {
|
||||
"ext-maxminddb": "<1.6.0,>=2.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "2.*",
|
||||
"php-coveralls/php-coveralls": "^2.1",
|
||||
"phpunit/phpcov": "^3.0",
|
||||
"phpunit/phpunit": "5.*",
|
||||
"squizlabs/php_codesniffer": "3.*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
|
||||
"ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
|
||||
"ext-maxminddb": "A C-based database decoder that provides significantly faster lookups"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"MaxMind\\Db\\": "src/MaxMind/Db"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gregory J. Oschwald",
|
||||
"email": "goschwald@maxmind.com",
|
||||
"homepage": "https://www.maxmind.com/"
|
||||
}
|
||||
],
|
||||
"description": "MaxMind DB Reader API",
|
||||
"homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php",
|
||||
"keywords": [
|
||||
"database",
|
||||
"geoip",
|
||||
"geoip2",
|
||||
"geolocation",
|
||||
"maxmind"
|
||||
],
|
||||
"time": "2019-12-19T22:59:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-blocks",
|
||||
"version": "v2.5.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/woocommerce/woocommerce-gutenberg-products-block.git",
|
||||
"reference": "4a6d993c1df7ccd8581873ee56269efa00d49ddc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/4a6d993c1df7ccd8581873ee56269efa00d49ddc",
|
||||
"reference": "4a6d993c1df7ccd8581873ee56269efa00d49ddc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -209,20 +269,20 @@
|
|||
"gutenberg",
|
||||
"woocommerce"
|
||||
],
|
||||
"time": "2019-12-20T16:26:08+00:00"
|
||||
"time": "2020-01-09T15:29:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-rest-api",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/woocommerce/woocommerce-rest-api.git",
|
||||
"reference": "3be425631faefa61ab8b81011ae8a422b9bfca35"
|
||||
"reference": "78ccf4d4c6bafbc841182b68aa863e7b0caa37c8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-rest-api/zipball/3be425631faefa61ab8b81011ae8a422b9bfca35",
|
||||
"reference": "3be425631faefa61ab8b81011ae8a422b9bfca35",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-rest-api/zipball/78ccf4d4c6bafbc841182b68aa863e7b0caa37c8",
|
||||
"reference": "78ccf4d4c6bafbc841182b68aa863e7b0caa37c8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -249,7 +309,7 @@
|
|||
],
|
||||
"description": "The WooCommerce core REST API.",
|
||||
"homepage": "https://github.com/woocommerce/woocommerce-rest-api",
|
||||
"time": "2019-12-18T22:20:59+00:00"
|
||||
"time": "2020-01-15T23:29:39+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
@ -527,16 +587,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpcompatibility/php-compatibility",
|
||||
"version": "9.3.4",
|
||||
"version": "9.3.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
|
||||
"reference": "1f37659196e4f3113ea506a7efba201c52303bf1"
|
||||
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/1f37659196e4f3113ea506a7efba201c52303bf1",
|
||||
"reference": "1f37659196e4f3113ea506a7efba201c52303bf1",
|
||||
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243",
|
||||
"reference": "9fb324479acf6f39452e0655d2429cc0d3914243",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -581,7 +641,7 @@
|
|||
"phpcs",
|
||||
"standards"
|
||||
],
|
||||
"time": "2019-11-15T04:12:02+00:00"
|
||||
"time": "2019-12-27T09:44:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpcompatibility/phpcompatibility-paragonie",
|
||||
|
@ -739,16 +799,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
"version": "4.3.2",
|
||||
"version": "4.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
||||
"reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e"
|
||||
"reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
|
||||
"reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c",
|
||||
"reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -760,6 +820,7 @@
|
|||
"require-dev": {
|
||||
"doctrine/instantiator": "^1.0.5",
|
||||
"mockery/mockery": "^1.0",
|
||||
"phpdocumentor/type-resolver": "0.4.*",
|
||||
"phpunit/phpunit": "^6.4"
|
||||
},
|
||||
"type": "library",
|
||||
|
@ -786,7 +847,7 @@
|
|||
}
|
||||
],
|
||||
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
|
||||
"time": "2019-09-12T14:27:41+00:00"
|
||||
"time": "2019-12-28T18:55:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
|
@ -837,16 +898,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "1.10.0",
|
||||
"version": "1.10.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "d638ebbb58daba25a6a0dc7969e1358a0e3c6682"
|
||||
"reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/d638ebbb58daba25a6a0dc7969e1358a0e3c6682",
|
||||
"reference": "d638ebbb58daba25a6a0dc7969e1358a0e3c6682",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/cbe1df668b3fe136bcc909126a0f529a78d4cbbc",
|
||||
"reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -896,7 +957,7 @@
|
|||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2019-12-17T16:54:23+00:00"
|
||||
"time": "2019-12-22T21:05:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
|
|
@ -36,6 +36,7 @@ class WC_Admin_Notices {
|
|||
'no_secure_connection' => 'secure_connection_notice',
|
||||
'wc_admin' => 'wc_admin_feature_plugin_notice',
|
||||
WC_PHP_MIN_REQUIREMENTS_NOTICE => 'wp_php_min_requirements_notice',
|
||||
'maxmind_license_key' => 'maxmind_missing_license_key_notice',
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -87,6 +88,7 @@ class WC_Admin_Notices {
|
|||
self::add_wc_admin_feature_plugin_notice();
|
||||
self::add_notice( 'template_files' );
|
||||
self::add_min_version_notice();
|
||||
self::add_maxmind_missing_license_key_notice();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -428,6 +430,41 @@ class WC_Admin_Notices {
|
|||
include dirname( __FILE__ ) . '/views/html-notice-wp-php-minimum-requirements.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add MaxMind missing license key notice.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public static function add_maxmind_missing_license_key_notice() {
|
||||
$default_address = get_option( 'woocommerce_default_customer_address' );
|
||||
|
||||
if ( ! in_array( $default_address, array( 'geolocation', 'geolocation_ajax' ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$integration_options = get_option( 'woocommerce_maxmind_geolocation_settings' );
|
||||
if ( empty( $integration_options['license_key'] ) ) {
|
||||
self::add_notice( 'maxmind_license_key' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display MaxMind missing license key notice.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public static function maxmind_missing_license_key_notice() {
|
||||
$user_dismissed_notice = get_user_meta( get_current_user_id(), 'dismissed_maxmind_license_key_notice', true );
|
||||
$filter_dismissed_notice = ! apply_filters( 'woocommerce_maxmind_geolocation_display_notices', true );
|
||||
|
||||
if ( $user_dismissed_notice || $filter_dismissed_notice ) {
|
||||
self::remove_notice( 'maxmind_license_key' );
|
||||
return;
|
||||
}
|
||||
|
||||
include dirname( __FILE__ ) . '/views/html-notice-maxmind-license-key.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the store is running SSL.
|
||||
*
|
||||
|
|
|
@ -39,17 +39,6 @@ class WC_Settings_General extends WC_Settings_Page {
|
|||
$currency_code_options[ $code ] = $name . ' (' . get_woocommerce_currency_symbol( $code ) . ')';
|
||||
}
|
||||
|
||||
$woocommerce_default_customer_address_options = array(
|
||||
'' => __( 'No location by default', 'woocommerce' ),
|
||||
'base' => __( 'Shop base address', 'woocommerce' ),
|
||||
'geolocation' => __( 'Geolocate', 'woocommerce' ),
|
||||
'geolocation_ajax' => __( 'Geolocate (with page caching support)', 'woocommerce' ),
|
||||
);
|
||||
|
||||
if ( version_compare( PHP_VERSION, '5.4', '<' ) ) {
|
||||
unset( $woocommerce_default_customer_address_options['geolocation'], $woocommerce_default_customer_address_options['geolocation_ajax'] );
|
||||
}
|
||||
|
||||
$settings = apply_filters(
|
||||
'woocommerce_general_settings',
|
||||
array(
|
||||
|
@ -182,10 +171,15 @@ class WC_Settings_General extends WC_Settings_Page {
|
|||
'title' => __( 'Default customer location', 'woocommerce' ),
|
||||
'id' => 'woocommerce_default_customer_address',
|
||||
'desc_tip' => __( 'This option determines a customers default location. The MaxMind GeoLite Database will be periodically downloaded to your wp-content directory if using geolocation.', 'woocommerce' ),
|
||||
'default' => 'geolocation',
|
||||
'default' => 'base',
|
||||
'type' => 'select',
|
||||
'class' => 'wc-enhanced-select',
|
||||
'options' => $woocommerce_default_customer_address_options,
|
||||
'options' => array(
|
||||
'' => __( 'No location by default', 'woocommerce' ),
|
||||
'base' => __( 'Shop base address', 'woocommerce' ),
|
||||
'geolocation' => __( 'Geolocate', 'woocommerce' ),
|
||||
'geolocation_ajax' => __( 'Geolocate (with page caching support)', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
|
||||
array(
|
||||
|
|
|
@ -435,25 +435,6 @@ $untested_plugins = $plugin_updates->get_untested_plugins( WC()->version, 'min
|
|||
</td>
|
||||
</tr>
|
||||
|
||||
<?php if ( $settings['geolocation_enabled'] ) { ?>
|
||||
<tr>
|
||||
<td data-export-label="MaxMind GeoIP Database"><?php esc_html_e( 'MaxMind GeoIP database', 'woocommerce' ); ?>:</td>
|
||||
<td class="help"><?php echo wc_help_tip( esc_html__( 'The GeoIP database from MaxMind is used to geolocate customers.', 'woocommerce' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></td>
|
||||
<td>
|
||||
<?php
|
||||
if ( version_compare( $environment['php_version'], '5.4', '<' ) ) {
|
||||
echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . wp_kses_post( __( 'MaxMind GeoIP database requires at least PHP 5.4.', 'woocommerce' ) ) . '</mark>';
|
||||
} elseif ( file_exists( $database['maxmind_geoip_database'] ) ) {
|
||||
echo '<mark class="yes"><span class="dashicons dashicons-yes"></span> <code class="private">' . esc_html( $database['maxmind_geoip_database'] ) . '</code></mark> ';
|
||||
} else {
|
||||
/* Translators: %1$s: Library url, %2$s: install path. */
|
||||
printf( '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( esc_html__( 'The MaxMind GeoIP Database does not exist - Geolocation will not function. You can download and install it manually from %1$s to the path: %2$s. Scroll down to "Downloads" and download the "MaxMind DB binary, gzipped" file next to "GeoLite2 Country". Please remember to uncompress GeoLite2-Country_xxxxxxxx.tar.gz and upload the GeoLite2-Country.mmdb file only.', 'woocommerce' ), '<a href="https://dev.maxmind.com/geoip/geoip2/geolite2/">https://dev.maxmind.com/geoip/geoip2/geolite2/</a>', '<code class="private">' . esc_html( $database['maxmind_geoip_database'] ) . '</code>' ) . '</mark>', esc_html( WC_LOG_DIR ) );
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ( ! empty( $database['database_size'] ) && ! empty( $database['database_tables'] ) ) : ?>
|
||||
<tr>
|
||||
<td><?php esc_html_e( 'Total Database Size', 'woocommerce' ); ?></td>
|
||||
|
@ -584,7 +565,7 @@ $untested_plugins = $plugin_updates->get_untested_plugins( WC()->version, 'min
|
|||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ( $active_plugins as $plugin ) {
|
||||
foreach ( $active_plugins as $plugin ) { // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
||||
if ( ! empty( $plugin['name'] ) ) {
|
||||
$dirname = dirname( $plugin['plugin'] );
|
||||
|
||||
|
@ -636,7 +617,7 @@ $untested_plugins = $plugin_updates->get_untested_plugins( WC()->version, 'min
|
|||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ( $inactive_plugins as $plugin ) {
|
||||
foreach ( $inactive_plugins as $plugin ) { // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
||||
if ( ! empty( $plugin['name'] ) ) {
|
||||
$dirname = dirname( $plugin['plugin'] );
|
||||
|
||||
|
@ -715,7 +696,7 @@ if ( 0 < count( $dropins_mu_plugins['mu_plugins'] ) ) :
|
|||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ( $dropins_mu_plugins['mu_plugins'] as $mu_plugin ) {
|
||||
foreach ( $dropins_mu_plugins['mu_plugins'] as $mu_plugin ) { // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
||||
$plugin_name = esc_html( $mu_plugin['name'] );
|
||||
if ( ! empty( $mu_plugin['url'] ) ) {
|
||||
$plugin_name = '<a href="' . esc_url( $mu_plugin['url'] ) . '" aria-label="' . esc_attr__( 'Visit plugin homepage', 'woocommerce' ) . '" target="_blank">' . $plugin_name . '</a>';
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin View: Notice - Missing MaxMind license key
|
||||
*
|
||||
* @package WooCommerce\Admin
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
?>
|
||||
|
||||
<div id="message" class="updated woocommerce-message">
|
||||
<a class="woocommerce-message-close notice-dismiss" href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'wc-hide-notice', 'maxmind_license_key' ), 'woocommerce_hide_notices_nonce', '_wc_notice_nonce' ) ); ?>"><?php esc_html_e( 'Dismiss', 'woocommerce' ); ?></a>
|
||||
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'Geolocation has not been configured.', 'woocommerce' ); ?></strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses_post(
|
||||
sprintf(
|
||||
/* translators: %1%s: integration page %2$s: general settings page */
|
||||
__( 'You must enter a valid license key on the <a href="%1$s">MaxMind integration settings page</a> in order to use the geolocation service. If you do not need geolocation for shipping or taxes, you should change the default customer location on the <a href="%2$s">general settings page</a>.', 'woocommerce' ),
|
||||
admin_url( 'admin.php?page=wc-settings&tab=integration§ion=maxmind_geolocation' ),
|
||||
admin_url( 'admin.php?page=wc-settings&tab=general' )
|
||||
)
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
|
@ -88,6 +88,8 @@ class WC_Autoloader {
|
|||
$path = $this->include_path . 'payment-tokens/';
|
||||
} elseif ( 0 === strpos( $class, 'wc_log_handler_' ) ) {
|
||||
$path = $this->include_path . 'log-handlers/';
|
||||
} elseif ( 0 === strpos( $class, 'wc_integration' ) ) {
|
||||
$path = $this->include_path . 'integrations/' . substr( str_replace( '_', '-', $class ), 15 ) . '/';
|
||||
}
|
||||
|
||||
if ( empty( $path ) || ! $this->load_file( $path . $file ) ) {
|
||||
|
|
|
@ -8,12 +8,15 @@
|
|||
*
|
||||
* @package WooCommerce\Classes
|
||||
* @since 3.4.0
|
||||
* @deprecated 3.9.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Geolite integration class.
|
||||
*
|
||||
* @deprecated 3.9.0
|
||||
*/
|
||||
class WC_Geolite_Integration {
|
||||
|
||||
|
@ -38,10 +41,6 @@ class WC_Geolite_Integration {
|
|||
*/
|
||||
public function __construct( $database ) {
|
||||
$this->database = $database;
|
||||
|
||||
if ( ! class_exists( 'MaxMind\\Db\\Reader', false ) ) {
|
||||
$this->require_geolite_library();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,8 +49,11 @@ class WC_Geolite_Integration {
|
|||
*
|
||||
* @param string $ip_address User IP address.
|
||||
* @return string
|
||||
* @deprecated 3.9.0
|
||||
*/
|
||||
public function get_country_iso( $ip_address ) {
|
||||
wc_deprecated_function( 'get_country_iso', '3.9.0' );
|
||||
|
||||
$iso_code = '';
|
||||
|
||||
try {
|
||||
|
@ -87,15 +89,4 @@ class WC_Geolite_Integration {
|
|||
|
||||
$this->log->log( $level, $message, array( 'source' => 'geoip' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Require geolite library.
|
||||
*/
|
||||
private function require_geolite_library() {
|
||||
require_once WC_ABSPATH . 'includes/libraries/geolite2/Reader/Decoder.php';
|
||||
require_once WC_ABSPATH . 'includes/libraries/geolite2/Reader/InvalidDatabaseException.php';
|
||||
require_once WC_ABSPATH . 'includes/libraries/geolite2/Reader/Metadata.php';
|
||||
require_once WC_ABSPATH . 'includes/libraries/geolite2/Reader/Util.php';
|
||||
require_once WC_ABSPATH . 'includes/libraries/geolite2/Reader.php';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com.
|
||||
*
|
||||
* @package WooCommerce/Classes
|
||||
* @version 3.4.0
|
||||
* @version 3.9.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
@ -35,6 +35,7 @@ class WC_Geolocation {
|
|||
* GeoLite2 DB.
|
||||
*
|
||||
* @since 3.4.0
|
||||
* @deprecated 3.9.0
|
||||
*/
|
||||
const GEOLITE2_DB = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz';
|
||||
|
||||
|
@ -60,16 +61,6 @@ class WC_Geolocation {
|
|||
'ip-api.com' => 'http://ip-api.com/json/%s',
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if server supports MaxMind GeoLite2 Reader.
|
||||
*
|
||||
* @since 3.4.0
|
||||
* @return bool
|
||||
*/
|
||||
private static function supports_geolite2() {
|
||||
return version_compare( PHP_VERSION, '5.4.0', '>=' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if geolocation is enabled.
|
||||
*
|
||||
|
@ -81,67 +72,20 @@ class WC_Geolocation {
|
|||
return in_array( $current_settings, array( 'geolocation', 'geolocation_ajax' ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent geolocation via MaxMind when using legacy versions of php.
|
||||
*
|
||||
* @since 3.4.0
|
||||
* @param string $default_customer_address current value.
|
||||
* @return string
|
||||
*/
|
||||
public static function disable_geolocation_on_legacy_php( $default_customer_address ) {
|
||||
if ( self::is_geolocation_enabled( $default_customer_address ) ) {
|
||||
$default_customer_address = 'base';
|
||||
}
|
||||
|
||||
return $default_customer_address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook in geolocation functionality.
|
||||
*/
|
||||
public static function init() {
|
||||
if ( self::supports_geolite2() ) {
|
||||
// Only download the database from MaxMind if the geolocation function is enabled, or a plugin specifically requests it.
|
||||
if ( self::is_geolocation_enabled( get_option( 'woocommerce_default_customer_address' ) ) || apply_filters( 'woocommerce_geolocation_update_database_periodically', false ) ) {
|
||||
add_action( 'woocommerce_geoip_updater', array( __CLASS__, 'update_database' ) );
|
||||
}
|
||||
|
||||
// Trigger database update when settings are changed to enable geolocation.
|
||||
add_filter( 'pre_update_option_woocommerce_default_customer_address', array( __CLASS__, 'maybe_update_database' ), 10, 2 );
|
||||
} else {
|
||||
add_filter( 'pre_option_woocommerce_default_customer_address', array( __CLASS__, 'disable_geolocation_on_legacy_php' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe trigger a DB update for the first time.
|
||||
*
|
||||
* @param string $new_value New value.
|
||||
* @param string $old_value Old value.
|
||||
* @return string
|
||||
*/
|
||||
public static function maybe_update_database( $new_value, $old_value ) {
|
||||
if ( $new_value !== $old_value && self::is_geolocation_enabled( $new_value ) ) {
|
||||
self::update_database();
|
||||
}
|
||||
|
||||
return $new_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
return sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_REAL_IP'] ) ); // WPCS: input var ok, CSRF ok.
|
||||
} elseif ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { // WPCS: input var ok, CSRF ok.
|
||||
if ( isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
|
||||
return sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_REAL_IP'] ) );
|
||||
} elseif ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
|
||||
// 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.
|
||||
return (string) rest_is_ip_address( trim( current( preg_split( '/,/', sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) ) ) ) ); // WPCS: input var ok, CSRF ok.
|
||||
} elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) { // @codingStandardsIgnoreLine
|
||||
return sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ); // @codingStandardsIgnoreLine
|
||||
return (string) rest_is_ip_address( trim( current( preg_split( '/,/', sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) ) ) ) );
|
||||
} elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
|
||||
return sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
@ -195,119 +139,114 @@ class WC_Geolocation {
|
|||
// Filter to allow custom geolocation of the IP address.
|
||||
$country_code = apply_filters( 'woocommerce_geolocate_ip', false, $ip_address, $fallback, $api_fallback );
|
||||
|
||||
if ( false === $country_code ) {
|
||||
// If GEOIP is enabled in CloudFlare, we can use that (Settings -> CloudFlare Settings -> Settings Overview).
|
||||
if ( ! empty( $_SERVER['HTTP_CF_IPCOUNTRY'] ) ) { // WPCS: input var ok, CSRF ok.
|
||||
$country_code = strtoupper( sanitize_text_field( wp_unslash( $_SERVER['HTTP_CF_IPCOUNTRY'] ) ) ); // WPCS: input var ok, CSRF ok.
|
||||
} elseif ( ! empty( $_SERVER['GEOIP_COUNTRY_CODE'] ) ) { // WPCS: input var ok, CSRF ok.
|
||||
// WP.com VIP has a variable available.
|
||||
$country_code = strtoupper( sanitize_text_field( wp_unslash( $_SERVER['GEOIP_COUNTRY_CODE'] ) ) ); // WPCS: input var ok, CSRF ok.
|
||||
} elseif ( ! empty( $_SERVER['HTTP_X_COUNTRY_CODE'] ) ) { // WPCS: input var ok, CSRF ok.
|
||||
// VIP Go has a variable available also.
|
||||
$country_code = strtoupper( sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_COUNTRY_CODE'] ) ) ); // WPCS: input var ok, CSRF ok.
|
||||
} else {
|
||||
$ip_address = $ip_address ? $ip_address : self::get_ip_address();
|
||||
$database = self::get_local_database_path();
|
||||
if ( false !== $country_code ) {
|
||||
return array(
|
||||
'country' => $country_code,
|
||||
'state' => '',
|
||||
'city' => '',
|
||||
'postcode' => '',
|
||||
);
|
||||
}
|
||||
|
||||
if ( self::supports_geolite2() && file_exists( $database ) ) {
|
||||
$country_code = self::geolocate_via_db( $ip_address, $database );
|
||||
} elseif ( $api_fallback ) {
|
||||
$country_code = self::geolocate_via_api( $ip_address );
|
||||
} else {
|
||||
$country_code = '';
|
||||
}
|
||||
if ( empty( $ip_address ) ) {
|
||||
$ip_address = self::get_ip_address();
|
||||
}
|
||||
|
||||
if ( ! $country_code && $fallback ) {
|
||||
// May be a local environment - find external IP.
|
||||
return self::geolocate_ip( self::get_external_ip_address(), false, $api_fallback );
|
||||
}
|
||||
$country_code = self::get_country_code_from_headers();
|
||||
|
||||
/**
|
||||
* Get geolocation filter.
|
||||
*
|
||||
* @since 3.9.0
|
||||
* @param array $geolocation Geolocation data, including country, state, city, and postcode.
|
||||
* @param string $ip_address IP Address.
|
||||
*/
|
||||
$geolocation = apply_filters(
|
||||
'woocommerce_get_geolocation',
|
||||
array(
|
||||
'country' => $country_code,
|
||||
'state' => '',
|
||||
'city' => '',
|
||||
'postcode' => '',
|
||||
),
|
||||
$ip_address
|
||||
);
|
||||
|
||||
// If we still haven't found a country code, let's consider doing an API lookup.
|
||||
if ( '' === $geolocation['country'] && $api_fallback ) {
|
||||
$geolocation['country'] = self::geolocate_via_api( $ip_address );
|
||||
}
|
||||
|
||||
// It's possible that we're in a local environment, in which case the geolocation needs to be done from the
|
||||
// external address.
|
||||
if ( '' === $geolocation['country'] && $fallback ) {
|
||||
$external_ip_address = self::get_external_ip_address();
|
||||
|
||||
// Only bother with this if the external IP differs.
|
||||
if ( '0.0.0.0' !== $external_ip_address && $external_ip_address !== $ip_address ) {
|
||||
return self::geolocate_ip( $external_ip_address, false, $api_fallback );
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'country' => $country_code,
|
||||
'state' => '',
|
||||
'country' => $geolocation['country'],
|
||||
'state' => $geolocation['state'],
|
||||
'city' => $geolocation['city'],
|
||||
'postcode' => $geolocation['postcode'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Path to our local db.
|
||||
*
|
||||
* @deprecated 3.9.0
|
||||
* @param string $deprecated Deprecated since 3.4.0.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_local_database_path( $deprecated = '2' ) {
|
||||
return apply_filters( 'woocommerce_geolocation_local_database_path', WP_CONTENT_DIR . '/uploads/GeoLite2-Country.mmdb', $deprecated );
|
||||
wc_deprecated_function( 'WC_Geolocation::get_local_database_path', '3.9.0' );
|
||||
$integration = wc()->integrations->get_integration( 'maxmind_geolocation' );
|
||||
return $integration->get_database_service()->get_database_path();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update geoip database.
|
||||
*
|
||||
* @deprecated 3.9.0
|
||||
* Extract files with PharData. Tool built into PHP since 5.3.
|
||||
*/
|
||||
public static function update_database() {
|
||||
$logger = wc_get_logger();
|
||||
|
||||
if ( ! self::supports_geolite2() ) {
|
||||
$logger->notice( 'Requires PHP 5.4 to be able to download MaxMind GeoLite2 database', array( 'source' => 'geolocation' ) );
|
||||
return;
|
||||
}
|
||||
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
|
||||
$database = 'GeoLite2-Country.mmdb';
|
||||
$target_database_path = self::get_local_database_path();
|
||||
$tmp_database_path = download_url( self::GEOLITE2_DB );
|
||||
|
||||
if ( ! is_wp_error( $tmp_database_path ) ) {
|
||||
WP_Filesystem();
|
||||
|
||||
global $wp_filesystem;
|
||||
|
||||
try {
|
||||
// Make sure target dir exists.
|
||||
$wp_filesystem->mkdir( dirname( $target_database_path ) );
|
||||
|
||||
// Extract files with PharData. Tool built into PHP since 5.3.
|
||||
$file = new PharData( $tmp_database_path ); // phpcs:ignore PHPCompatibility.Classes.NewClasses.phardataFound
|
||||
$file_path = trailingslashit( $file->current()->getFileName() ) . $database;
|
||||
$file->extractTo( dirname( $tmp_database_path ), $file_path, true );
|
||||
|
||||
// Move file and delete temp.
|
||||
$wp_filesystem->move( trailingslashit( dirname( $tmp_database_path ) ) . $file_path, $target_database_path, true );
|
||||
$wp_filesystem->delete( trailingslashit( dirname( $tmp_database_path ) ) . $file->current()->getFileName() );
|
||||
} catch ( Exception $e ) {
|
||||
$logger->notice( $e->getMessage(), array( 'source' => 'geolocation' ) );
|
||||
|
||||
// Reschedule download of DB.
|
||||
wp_clear_scheduled_hook( 'woocommerce_geoip_updater' );
|
||||
wp_schedule_event( strtotime( 'first tuesday of next month' ), 'monthly', 'woocommerce_geoip_updater' );
|
||||
}
|
||||
// Delete temp file regardless of success.
|
||||
$wp_filesystem->delete( $tmp_database_path );
|
||||
} else {
|
||||
$logger->notice(
|
||||
'Unable to download GeoIP Database: ' . $tmp_database_path->get_error_message(),
|
||||
array( 'source' => 'geolocation' )
|
||||
);
|
||||
}
|
||||
wc_deprecated_function( 'WC_Geolocation::update_database', '3.9.0' );
|
||||
$integration = wc()->integrations->get_integration( 'maxmind_geolocation' );
|
||||
$integration->update_database();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use MAXMIND GeoLite database to geolocation the user.
|
||||
* Fetches the country code from the request headers, if one is available.
|
||||
*
|
||||
* @param string $ip_address IP address.
|
||||
* @param string $database Database path.
|
||||
* @return string
|
||||
* @since 3.9.0
|
||||
* @return string The country code pulled from the headers, or empty string if one was not found.
|
||||
*/
|
||||
private static function geolocate_via_db( $ip_address, $database ) {
|
||||
if ( ! class_exists( 'WC_Geolite_Integration', false ) ) {
|
||||
require_once WC_ABSPATH . 'includes/class-wc-geolite-integration.php';
|
||||
private static function get_country_code_from_headers() {
|
||||
$country_code = '';
|
||||
|
||||
$headers = array(
|
||||
'MM_COUNTRY_CODE',
|
||||
'GEOIP_COUNTRY_CODE',
|
||||
'HTTP_CF_IPCOUNTRY',
|
||||
'HTTP_X_COUNTRY_CODE',
|
||||
);
|
||||
|
||||
foreach ( $headers as $header ) {
|
||||
if ( empty( $_SERVER[ $header ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$country_code = strtoupper( sanitize_text_field( wp_unslash( $_SERVER[ $header ] ) ) );
|
||||
break;
|
||||
}
|
||||
|
||||
$geolite = new WC_Geolite_Integration( $database );
|
||||
|
||||
return $geolite->get_country_iso( $ip_address );
|
||||
return $country_code;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -368,6 +307,50 @@ class WC_Geolocation {
|
|||
|
||||
return $country_code;
|
||||
}
|
||||
}
|
||||
|
||||
WC_Geolocation::init();
|
||||
/**
|
||||
* Hook in geolocation functionality.
|
||||
*
|
||||
* @deprecated 3.9.0
|
||||
* @return null
|
||||
*/
|
||||
public static function init() {
|
||||
wc_deprecated_function( 'WC_Geolocation::init', '3.9.0' );
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent geolocation via MaxMind when using legacy versions of php.
|
||||
*
|
||||
* @deprecated 3.9.0
|
||||
* @since 3.4.0
|
||||
* @param string $default_customer_address current value.
|
||||
* @return string
|
||||
*/
|
||||
public static function disable_geolocation_on_legacy_php( $default_customer_address ) {
|
||||
wc_deprecated_function( 'WC_Geolocation::disable_geolocation_on_legacy_php', '3.9.0' );
|
||||
|
||||
if ( self::is_geolocation_enabled( $default_customer_address ) ) {
|
||||
$default_customer_address = 'base';
|
||||
}
|
||||
|
||||
return $default_customer_address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe trigger a DB update for the first time.
|
||||
*
|
||||
* @deprecated 3.9.0
|
||||
* @param string $new_value New value.
|
||||
* @param string $old_value Old value.
|
||||
* @return string
|
||||
*/
|
||||
public static function maybe_update_database( $new_value, $old_value ) {
|
||||
wc_deprecated_function( 'WC_Geolocation::maybe_update_database', '3.9.0' );
|
||||
if ( $new_value !== $old_value && self::is_geolocation_enabled( $new_value ) ) {
|
||||
self::update_database();
|
||||
}
|
||||
|
||||
return $new_value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,6 +135,11 @@ class WC_Install {
|
|||
'wc_update_370_mro_std_currency',
|
||||
'wc_update_370_db_version',
|
||||
),
|
||||
'3.9.0' => array(
|
||||
'wc_update_390_move_maxmind_database',
|
||||
'wc_update_390_change_geolocation_database_update_cron',
|
||||
'wc_update_390_db_version',
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -421,6 +426,10 @@ class WC_Install {
|
|||
'interval' => 2635200,
|
||||
'display' => __( 'Monthly', 'woocommerce' ),
|
||||
);
|
||||
$schedules['fifteendays'] = array(
|
||||
'interval' => 1296000,
|
||||
'display' => __( 'Every 15 Days', 'woocommerce' ),
|
||||
);
|
||||
return $schedules;
|
||||
}
|
||||
|
||||
|
@ -449,11 +458,8 @@ class WC_Install {
|
|||
wp_schedule_event( time(), 'daily', 'woocommerce_cleanup_personal_data' );
|
||||
wp_schedule_event( time() + ( 3 * HOUR_IN_SECONDS ), 'daily', 'woocommerce_cleanup_logs' );
|
||||
wp_schedule_event( time() + ( 6 * HOUR_IN_SECONDS ), 'twicedaily', 'woocommerce_cleanup_sessions' );
|
||||
wp_schedule_event( strtotime( 'first tuesday of next month' ), 'monthly', 'woocommerce_geoip_updater' );
|
||||
wp_schedule_event( time() + MINUTE_IN_SECONDS, 'fifteendays', 'woocommerce_geoip_updater' );
|
||||
wp_schedule_event( time() + 10, apply_filters( 'woocommerce_tracker_event_recurrence', 'daily' ), 'woocommerce_tracker_send_event' );
|
||||
|
||||
// Trigger GeoLite2 database download after 1 minute.
|
||||
wp_schedule_single_event( time() + ( MINUTE_IN_SECONDS * 1 ), 'woocommerce_geoip_updater' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -970,7 +976,7 @@ CREATE TABLE {$wpdb->prefix}wc_tax_rate_classes (
|
|||
$tables = self::get_tables();
|
||||
|
||||
foreach ( $tables as $table ) {
|
||||
$wpdb->query( "DROP TABLE IF EXISTS {$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
$wpdb->query( "DROP TABLE IF EXISTS {$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* Loads Integrations into WooCommerce.
|
||||
*
|
||||
* @version 2.3.0
|
||||
* @version 3.9.0
|
||||
* @package WooCommerce/Classes/Integrations
|
||||
*/
|
||||
|
||||
|
@ -29,7 +29,11 @@ class WC_Integrations {
|
|||
|
||||
do_action( 'woocommerce_integrations_init' );
|
||||
|
||||
$load_integrations = apply_filters( 'woocommerce_integrations', array() );
|
||||
$load_integrations = array(
|
||||
'WC_Integration_MaxMind_Geolocation',
|
||||
);
|
||||
|
||||
$load_integrations = apply_filters( 'woocommerce_integrations', $load_integrations );
|
||||
|
||||
// Load integration classes.
|
||||
foreach ( $load_integrations as $integration ) {
|
||||
|
@ -48,4 +52,19 @@ class WC_Integrations {
|
|||
public function get_integrations() {
|
||||
return $this->integrations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a desired integration.
|
||||
*
|
||||
* @since 3.9.0
|
||||
* @param string $id The id of the integration to get.
|
||||
* @return mixed|null The integration if one is found, otherwise null.
|
||||
*/
|
||||
public function get_integration( $id ) {
|
||||
if ( isset( $this->integrations[ $id ] ) ) {
|
||||
return $this->integrations[ $id ];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -294,12 +294,7 @@ class WC_Shipping {
|
|||
}
|
||||
|
||||
$states = WC()->countries->get_states( $country );
|
||||
if ( is_array( $states ) && ! isset( $states[ $package['destination']['state'] ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$postcode = wc_format_postcode( $package['destination']['postcode'], $country );
|
||||
if ( ! WC_Validation::is_postcode( $postcode, $country ) ) {
|
||||
if ( is_array( $states ) && ! empty( $states ) && ! isset( $states[ $package['destination']['state'] ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
/**
|
||||
* The database service class file.
|
||||
*
|
||||
* @version 3.9.0
|
||||
* @package WooCommerce/Integrations
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* The service class responsible for interacting with MaxMind databases.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class WC_Integration_MaxMind_Database_Service {
|
||||
|
||||
/**
|
||||
* The name of the MaxMind database to utilize.
|
||||
*/
|
||||
const DATABASE = 'GeoLite2-Country';
|
||||
|
||||
/**
|
||||
* The extension for the MaxMind database.
|
||||
*/
|
||||
const DATABASE_EXTENSION = '.mmdb';
|
||||
|
||||
/**
|
||||
* A prefix for the MaxMind database filename.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $database_prefix;
|
||||
|
||||
/**
|
||||
* WC_Integration_MaxMind_Database_Service constructor.
|
||||
*
|
||||
* @param string|null $database_prefix A prefix for the MaxMind database filename.
|
||||
*/
|
||||
public function __construct( $database_prefix ) {
|
||||
$this->database_prefix = $database_prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the path that the database should be stored.
|
||||
*
|
||||
* @return string The local database path.
|
||||
*/
|
||||
public function get_database_path() {
|
||||
$uploads_dir = wp_upload_dir();
|
||||
|
||||
$database_path = trailingslashit( $uploads_dir['basedir'] ) . 'woocommerce_uploads/';
|
||||
if ( ! empty( $this->database_prefix ) ) {
|
||||
$database_path .= $this->database_prefix . '-';
|
||||
}
|
||||
$database_path .= self::DATABASE . self::DATABASE_EXTENSION;
|
||||
|
||||
/**
|
||||
* Filter the geolocation database storage path.
|
||||
*
|
||||
* @param string $database_path The path to the database.
|
||||
* @param int $version Deprecated since 3.4.0.
|
||||
* @deprecated 3.9.0
|
||||
*/
|
||||
$database_path = apply_filters_deprecated(
|
||||
'woocommerce_geolocation_local_database_path',
|
||||
array( $database_path, 2 ),
|
||||
'3.9.0',
|
||||
'woocommerce_maxmind_geolocation_database_path'
|
||||
);
|
||||
|
||||
/**
|
||||
* Filter the geolocation database storage path.
|
||||
*
|
||||
* @since 3.9.0
|
||||
* @param string $database_path The path to the database.
|
||||
*/
|
||||
return apply_filters( 'woocommerce_maxmind_geolocation_database_path', $database_path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the database from the MaxMind service.
|
||||
*
|
||||
* @param string $license_key The license key to be used when downloading the database.
|
||||
* @return string|WP_Error The path to the database file or an error if invalid.
|
||||
*/
|
||||
public function download_database( $license_key ) {
|
||||
$download_uri = add_query_arg(
|
||||
array(
|
||||
'edition_id' => self::DATABASE,
|
||||
'license_key' => wc_clean( $license_key ),
|
||||
'suffix' => 'tar.gz',
|
||||
),
|
||||
'https://download.maxmind.com/app/geoip_download'
|
||||
);
|
||||
|
||||
// Needed for the download_url call right below.
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
|
||||
$tmp_archive_path = download_url( $download_uri );
|
||||
if ( is_wp_error( $tmp_archive_path ) ) {
|
||||
// Transform the error into something more informative.
|
||||
$error_data = $tmp_archive_path->get_error_data();
|
||||
if ( isset( $error_data['code'] ) ) {
|
||||
switch ( $error_data['code'] ) {
|
||||
case 401:
|
||||
return new WP_Error(
|
||||
'woocommerce_maxmind_geolocation_database_license_key',
|
||||
__( 'The MaxMind license key is invalid.', 'woocommerce' )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new WP_Error( 'woocommerce_maxmind_geolocation_database_download', __( 'Failed to download the MaxMind database.', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
// Extract the database from the archive.
|
||||
try {
|
||||
$file = new PharData( $tmp_archive_path );
|
||||
|
||||
$tmp_database_path = trailingslashit( dirname( $tmp_archive_path ) ) . trailingslashit( $file->current()->getFilename() ) . self::DATABASE . self::DATABASE_EXTENSION;
|
||||
|
||||
$file->extractTo(
|
||||
dirname( $tmp_archive_path ),
|
||||
trailingslashit( $file->current()->getFilename() ) . self::DATABASE . self::DATABASE_EXTENSION,
|
||||
true
|
||||
);
|
||||
} catch ( Exception $exception ) {
|
||||
return new WP_Error( 'woocommerce_maxmind_geolocation_database_archive', $exception->getMessage() );
|
||||
} finally {
|
||||
// Remove the archive since we only care about a single file in it.
|
||||
unlink( $tmp_archive_path );
|
||||
}
|
||||
|
||||
return $tmp_database_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the ISO country code associated with an IP address.
|
||||
*
|
||||
* @param string $ip_address The IP address to find the country code for.
|
||||
* @return string|null The country code for the IP address, or null if none was found.
|
||||
*/
|
||||
public function get_iso_country_code_for_ip( $ip_address ) {
|
||||
$country_code = null;
|
||||
|
||||
if ( ! class_exists( 'MaxMind\Db\Reader' ) ) {
|
||||
wc_get_logger()->notice( __( 'Missing MaxMind Reader library!', 'woocommerce' ), array( 'source' => 'maxmind-geolocation' ) );
|
||||
return $country_code;
|
||||
}
|
||||
|
||||
try {
|
||||
$reader = new MaxMind\Db\Reader( $this->get_database_path() );
|
||||
$data = $reader->get( $ip_address );
|
||||
|
||||
if ( isset( $data['country']['iso_code'] ) ) {
|
||||
$country_code = $data['country']['iso_code'];
|
||||
}
|
||||
|
||||
$reader->close();
|
||||
} catch ( Exception $e ) {
|
||||
wc_get_logger()->notice( $e->getMessage(), array( 'source' => 'maxmind-geolocation' ) );
|
||||
}
|
||||
|
||||
return $country_code;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
<?php
|
||||
/**
|
||||
* MaxMind Geolocation Integration
|
||||
*
|
||||
* @version 3.9.0
|
||||
* @package WooCommerce/Integrations
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
require_once 'class-wc-integration-maxmind-database-service.php';
|
||||
|
||||
/**
|
||||
* WC Integration MaxMind Geolocation
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class WC_Integration_MaxMind_Geolocation extends WC_Integration {
|
||||
|
||||
/**
|
||||
* The service responsible for interacting with the MaxMind database.
|
||||
*
|
||||
* @var WC_Integration_MaxMind_Database_Service
|
||||
*/
|
||||
private $database_service;
|
||||
|
||||
/**
|
||||
* Initialize the integration.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->id = 'maxmind_geolocation';
|
||||
$this->method_title = __( 'WooCommerce MaxMind Geolocation', 'woocommerce' );
|
||||
$this->method_description = __( 'An integration for utilizing MaxMind to do Geolocation lookups. Please note that this integration will only do country lookups.', 'woocommerce' );
|
||||
|
||||
/**
|
||||
* Supports overriding the database service to be used.
|
||||
*
|
||||
* @since 3.9.0
|
||||
* @return mixed|null The geolocation database service.
|
||||
*/
|
||||
$this->database_service = apply_filters( 'woocommerce_maxmind_geolocation_database_service', null );
|
||||
if ( null === $this->database_service ) {
|
||||
$this->database_service = new WC_Integration_MaxMind_Database_Service( $this->get_database_prefix() );
|
||||
}
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
// Bind to the save action for the settings.
|
||||
add_action( 'woocommerce_update_options_integration_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
|
||||
// Trigger notice if license key is missing.
|
||||
add_action( 'update_option_woocommerce_default_customer_address', array( $this, 'display_missing_license_key_notice' ), 1000, 2 );
|
||||
|
||||
/**
|
||||
* Allows for the automatic database update to be disabled.
|
||||
*
|
||||
* @deprecated 3.9.0
|
||||
* @return bool Whether or not the database should be updated periodically.
|
||||
*/
|
||||
$bind_updater = apply_filters_deprecated(
|
||||
'woocommerce_geolocation_update_database_periodically',
|
||||
array( true ),
|
||||
'3.9.0',
|
||||
'woocommerce_maxmind_geolocation_update_database_periodically'
|
||||
);
|
||||
|
||||
/**
|
||||
* Allows for the automatic database update to be disabled.
|
||||
* Note that MaxMind's TOS requires that the databases be updated or removed periodically.
|
||||
*
|
||||
* @since 3.9.0
|
||||
* @param bool $bind_updater Whether or not the database should be updated periodically.
|
||||
*/
|
||||
$bind_updater = apply_filters( 'woocommerce_maxmind_geolocation_update_database_periodically', $bind_updater );
|
||||
|
||||
// Bind to the scheduled updater action.
|
||||
if ( $bind_updater ) {
|
||||
add_action( 'woocommerce_geoip_updater', array( $this, 'update_database' ) );
|
||||
}
|
||||
|
||||
// Bind to the geolocation filter for MaxMind database lookups.
|
||||
add_filter( 'woocommerce_get_geolocation', array( $this, 'get_geolocation' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the normal options so we can print the database file path to the admin,
|
||||
*/
|
||||
public function admin_options() {
|
||||
parent::admin_options();
|
||||
|
||||
include dirname( __FILE__ ) . '/views/html-admin-options.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the settings fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'license_key' => array(
|
||||
'title' => __( 'MaxMind License Key', 'woocommerce' ),
|
||||
'type' => 'password',
|
||||
'description' => sprintf(
|
||||
/* translators: %1$s: Documentation URL */
|
||||
__(
|
||||
'The key that will be used when dealing with MaxMind Geolocation services. You can read how to generate one in <a href="%1$s">MaxMind\'s License Key Documentation</a>.',
|
||||
'woocommerce'
|
||||
),
|
||||
'https://support.maxmind.com/account-faq/account-related/how-do-i-generate-a-license-key/'
|
||||
),
|
||||
'desc_tip' => false,
|
||||
'default' => '',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get database service.
|
||||
*
|
||||
* @return WC_Integration_MaxMind_Database_Service|null
|
||||
*/
|
||||
public function get_database_service() {
|
||||
return $this->database_service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to make sure that the license key is valid.
|
||||
*
|
||||
* @param string $key The key of the field.
|
||||
* @param mixed $value The value of the field.
|
||||
* @return mixed
|
||||
* @throws Exception When the license key is invalid.
|
||||
*/
|
||||
public function validate_license_key_field( $key, $value ) {
|
||||
// Empty license keys have no need to validate the data.
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Check the license key by attempting to download the Geolocation database.
|
||||
$tmp_database_path = $this->database_service->download_database( $value );
|
||||
if ( is_wp_error( $tmp_database_path ) ) {
|
||||
WC_Admin_Settings::add_error( $tmp_database_path->get_error_message() );
|
||||
|
||||
// Throw an exception to keep from changing this value. This will prevent
|
||||
// users from accidentally losing their license key, which cannot
|
||||
// be viewed again after generating.
|
||||
throw new Exception( $tmp_database_path->get_error_message() );
|
||||
}
|
||||
|
||||
// We may as well put this archive to good use, now that we've downloaded one.
|
||||
self::update_database( $tmp_database_path );
|
||||
|
||||
// Remove missing license key notice.
|
||||
$this->remove_missing_license_key_notice();
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the database used for geolocation queries.
|
||||
*
|
||||
* @param string|null $new_database_path The path to the new database file. Null will fetch a new archive.
|
||||
*/
|
||||
public function update_database( $new_database_path = null ) {
|
||||
// Allow us to easily interact with the filesystem.
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
WP_Filesystem();
|
||||
global $wp_filesystem;
|
||||
|
||||
// Remove any existing archives to comply with the MaxMind TOS.
|
||||
$target_database_path = $this->database_service->get_database_path();
|
||||
|
||||
// If there's no database path, we can't store the database.
|
||||
if ( empty( $target_database_path ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $wp_filesystem->exists( $target_database_path ) ) {
|
||||
$wp_filesystem->delete( $target_database_path );
|
||||
}
|
||||
|
||||
if ( isset( $new_database_path ) ) {
|
||||
$tmp_database_path = $new_database_path;
|
||||
} else {
|
||||
// We can't download a database if there's no license key configured.
|
||||
$license_key = $this->get_option( 'license_key' );
|
||||
if ( empty( $license_key ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tmp_database_path = $this->database_service->download_database( $license_key );
|
||||
if ( is_wp_error( $tmp_database_path ) ) {
|
||||
wc_get_logger()->notice( $tmp_database_path->get_error_message(), array( 'source' => 'maxmind-geolocation' ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Move the new database into position.
|
||||
$wp_filesystem->move( $tmp_database_path, $target_database_path, true );
|
||||
$wp_filesystem->delete( dirname( $tmp_database_path ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a geolocation lookup against the MaxMind database for the given IP address.
|
||||
*
|
||||
* @param array $data Geolocation data.
|
||||
* @param string $ip_address The IP address to geolocate.
|
||||
* @return array Geolocation including country code, state, city and postcode based on an IP address.
|
||||
*/
|
||||
public function get_geolocation( $data, $ip_address ) {
|
||||
// WooCommerce look for headers first, and at this moment could be just enough.
|
||||
if ( ! empty( $data['country'] ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ( empty( $ip_address ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$country_code = $this->database_service->get_iso_country_code_for_ip( $ip_address );
|
||||
|
||||
return array(
|
||||
'country' => $country_code ? $country_code : '',
|
||||
'state' => '',
|
||||
'city' => '',
|
||||
'postcode' => '',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the prefix for the MaxMind database file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_database_prefix() {
|
||||
$prefix = $this->get_option( 'database_prefix' );
|
||||
if ( empty( $prefix ) ) {
|
||||
$prefix = wp_generate_password( 32, false );
|
||||
$this->update_option( 'database_prefix', $prefix );
|
||||
}
|
||||
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add missing license key notice.
|
||||
*/
|
||||
private function add_missing_license_key_notice() {
|
||||
if ( ! class_exists( 'WC_Admin_Notices' ) ) {
|
||||
include_once WC_ABSPATH . 'includes/admin/class-wc-admin-notices.php';
|
||||
}
|
||||
WC_Admin_Notices::add_notice( 'maxmind_license_key' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove missing license key notice.
|
||||
*/
|
||||
private function remove_missing_license_key_notice() {
|
||||
if ( ! class_exists( 'WC_Admin_Notices' ) ) {
|
||||
include_once WC_ABSPATH . 'includes/admin/class-wc-admin-notices.php';
|
||||
}
|
||||
WC_Admin_Notices::remove_notice( 'maxmind_license_key' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display notice if license key is missing.
|
||||
*
|
||||
* @param mixed $old_value Option old value.
|
||||
* @param mixed $new_value Current value.
|
||||
*/
|
||||
public function display_missing_license_key_notice( $old_value, $new_value ) {
|
||||
if ( ! apply_filters( 'woocommerce_maxmind_geolocation_display_notices', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! in_array( $new_value, array( 'geolocation', 'geolocation_ajax' ), true ) ) {
|
||||
$this->remove_missing_license_key_notice();
|
||||
return;
|
||||
}
|
||||
|
||||
$license_key = $this->get_option( 'license_key' );
|
||||
if ( ! empty( $license_key ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->add_missing_license_key_notice();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin View: Page - Admin options.
|
||||
*
|
||||
* @package WooCommerce\Integrations
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
?>
|
||||
|
||||
<table class="form-table">
|
||||
<tr valign="top">
|
||||
<th scope="row" class="titledesc">
|
||||
<label><?php esc_html_e( 'Database File Path', 'woocommerce' ); ?></label>
|
||||
</th>
|
||||
<td class="forminp">
|
||||
<fieldset>
|
||||
<legend class="screen-reader-text"><span><?php esc_html_e( 'Database File Path', 'woocommerce' ); ?></span></legend>
|
||||
<input class="input-text regular-input" type="text" value="<?php echo esc_attr( $this->database_service->get_database_path() ); ?>" readonly>
|
||||
<p class="description"><?php esc_html_e( 'The location that the MaxMind database should be stored. By default, the integration will automatically save the database here.', 'woocommerce' ); ?></p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
|
@ -1,309 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace MaxMind\Db;
|
||||
|
||||
use MaxMind\Db\Reader\Decoder;
|
||||
use MaxMind\Db\Reader\InvalidDatabaseException;
|
||||
use MaxMind\Db\Reader\Metadata;
|
||||
use MaxMind\Db\Reader\Util;
|
||||
|
||||
/**
|
||||
* Instances of this class provide a reader for the MaxMind DB format. IP
|
||||
* addresses can be looked up using the <code>get</code> method.
|
||||
*/
|
||||
class Reader
|
||||
{
|
||||
private static $DATA_SECTION_SEPARATOR_SIZE = 16;
|
||||
private static $METADATA_START_MARKER = "\xAB\xCD\xEFMaxMind.com";
|
||||
private static $METADATA_START_MARKER_LENGTH = 14;
|
||||
private static $METADATA_MAX_SIZE = 131072; // 128 * 1024 = 128KB
|
||||
|
||||
private $decoder;
|
||||
private $fileHandle;
|
||||
private $fileSize;
|
||||
private $ipV4Start;
|
||||
private $metadata;
|
||||
|
||||
/**
|
||||
* Constructs a Reader for the MaxMind DB format. The file passed to it must
|
||||
* be a valid MaxMind DB file such as a GeoIp2 database file.
|
||||
*
|
||||
* @param string $database
|
||||
* the MaxMind DB file to use
|
||||
*
|
||||
* @throws \InvalidArgumentException for invalid database path or unknown arguments
|
||||
* @throws \MaxMind\Db\Reader\InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*/
|
||||
public function __construct($database)
|
||||
{
|
||||
if (func_num_args() !== 1) {
|
||||
throw new \InvalidArgumentException(
|
||||
'The constructor takes exactly one argument.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_readable($database)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The file \"$database\" does not exist or is not readable."
|
||||
);
|
||||
}
|
||||
$this->fileHandle = @fopen($database, 'rb');
|
||||
if ($this->fileHandle === false) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Error opening \"$database\"."
|
||||
);
|
||||
}
|
||||
$this->fileSize = @filesize($database);
|
||||
if ($this->fileSize === false) {
|
||||
throw new \UnexpectedValueException(
|
||||
"Error determining the size of \"$database\"."
|
||||
);
|
||||
}
|
||||
|
||||
$start = $this->findMetadataStart($database);
|
||||
$metadataDecoder = new Decoder($this->fileHandle, $start);
|
||||
list($metadataArray) = $metadataDecoder->decode($start);
|
||||
$this->metadata = new Metadata($metadataArray);
|
||||
$this->decoder = new Decoder(
|
||||
$this->fileHandle,
|
||||
$this->metadata->searchTreeSize + self::$DATA_SECTION_SEPARATOR_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the <code>address</code> in the MaxMind DB.
|
||||
*
|
||||
* @param string $ipAddress
|
||||
* the IP address to look up
|
||||
*
|
||||
* @throws \BadMethodCallException if this method is called on a closed database
|
||||
* @throws \InvalidArgumentException if something other than a single IP address is passed to the method
|
||||
* @throws InvalidDatabaseException
|
||||
* if the database is invalid or there is an error reading
|
||||
* from it
|
||||
*
|
||||
* @return array the record for the IP address
|
||||
*/
|
||||
public function get($ipAddress)
|
||||
{
|
||||
if (func_num_args() !== 1) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Method takes exactly one argument.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_resource($this->fileHandle)) {
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!filter_var($ipAddress, FILTER_VALIDATE_IP)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The value \"$ipAddress\" is not a valid IP address."
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->metadata->ipVersion === 4 && strrpos($ipAddress, ':')) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Error looking up $ipAddress. You attempted to look up an"
|
||||
. ' IPv6 address in an IPv4-only database.'
|
||||
);
|
||||
}
|
||||
$pointer = $this->findAddressInTree($ipAddress);
|
||||
if ($pointer === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->resolveDataPointer($pointer);
|
||||
}
|
||||
|
||||
private function findAddressInTree($ipAddress)
|
||||
{
|
||||
// XXX - could simplify. Done as a byte array to ease porting
|
||||
$rawAddress = array_merge(unpack('C*', inet_pton($ipAddress)));
|
||||
|
||||
$bitCount = count($rawAddress) * 8;
|
||||
|
||||
// The first node of the tree is always node 0, at the beginning of the
|
||||
// value
|
||||
$node = $this->startNode($bitCount);
|
||||
|
||||
for ($i = 0; $i < $bitCount; $i++) {
|
||||
if ($node >= $this->metadata->nodeCount) {
|
||||
break;
|
||||
}
|
||||
$tempBit = 0xFF & $rawAddress[$i >> 3];
|
||||
$bit = 1 & ($tempBit >> 7 - ($i % 8));
|
||||
|
||||
$node = $this->readNode($node, $bit);
|
||||
}
|
||||
if ($node === $this->metadata->nodeCount) {
|
||||
// Record is empty
|
||||
return 0;
|
||||
} elseif ($node > $this->metadata->nodeCount) {
|
||||
// Record is a data pointer
|
||||
return $node;
|
||||
}
|
||||
throw new InvalidDatabaseException('Something bad happened');
|
||||
}
|
||||
|
||||
private function startNode($length)
|
||||
{
|
||||
// Check if we are looking up an IPv4 address in an IPv6 tree. If this
|
||||
// is the case, we can skip over the first 96 nodes.
|
||||
if ($this->metadata->ipVersion === 6 && $length === 32) {
|
||||
return $this->ipV4StartNode();
|
||||
}
|
||||
// The first node of the tree is always node 0, at the beginning of the
|
||||
// value
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function ipV4StartNode()
|
||||
{
|
||||
// This is a defensive check. There is no reason to call this when you
|
||||
// have an IPv4 tree.
|
||||
if ($this->metadata->ipVersion === 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($this->ipV4Start) {
|
||||
return $this->ipV4Start;
|
||||
}
|
||||
$node = 0;
|
||||
|
||||
for ($i = 0; $i < 96 && $node < $this->metadata->nodeCount; $i++) {
|
||||
$node = $this->readNode($node, 0);
|
||||
}
|
||||
$this->ipV4Start = $node;
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function readNode($nodeNumber, $index)
|
||||
{
|
||||
$baseOffset = $nodeNumber * $this->metadata->nodeByteSize;
|
||||
|
||||
// XXX - probably could condense this.
|
||||
switch ($this->metadata->recordSize) {
|
||||
case 24:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 3, 3);
|
||||
list(, $node) = unpack('N', "\x00" . $bytes);
|
||||
|
||||
return $node;
|
||||
case 28:
|
||||
$middleByte = Util::read($this->fileHandle, $baseOffset + 3, 1);
|
||||
list(, $middle) = unpack('C', $middleByte);
|
||||
if ($index === 0) {
|
||||
$middle = (0xF0 & $middle) >> 4;
|
||||
} else {
|
||||
$middle = 0x0F & $middle;
|
||||
}
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 3);
|
||||
list(, $node) = unpack('N', chr($middle) . $bytes);
|
||||
|
||||
return $node;
|
||||
case 32:
|
||||
$bytes = Util::read($this->fileHandle, $baseOffset + $index * 4, 4);
|
||||
list(, $node) = unpack('N', $bytes);
|
||||
|
||||
return $node;
|
||||
default:
|
||||
throw new InvalidDatabaseException(
|
||||
'Unknown record size: '
|
||||
. $this->metadata->recordSize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveDataPointer($pointer)
|
||||
{
|
||||
$resolved = $pointer - $this->metadata->nodeCount
|
||||
+ $this->metadata->searchTreeSize;
|
||||
if ($resolved > $this->fileSize) {
|
||||
throw new InvalidDatabaseException(
|
||||
"The MaxMind DB file's search tree is corrupt"
|
||||
);
|
||||
}
|
||||
|
||||
list($data) = $this->decoder->decode($resolved);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is an extremely naive but reasonably readable implementation. There
|
||||
* are much faster algorithms (e.g., Boyer-Moore) for this if speed is ever
|
||||
* an issue, but I suspect it won't be.
|
||||
*/
|
||||
private function findMetadataStart($filename)
|
||||
{
|
||||
$handle = $this->fileHandle;
|
||||
$fstat = fstat($handle);
|
||||
$fileSize = $fstat['size'];
|
||||
$marker = self::$METADATA_START_MARKER;
|
||||
$markerLength = self::$METADATA_START_MARKER_LENGTH;
|
||||
$metadataMaxLengthExcludingMarker
|
||||
= min(self::$METADATA_MAX_SIZE, $fileSize) - $markerLength;
|
||||
|
||||
for ($i = 0; $i <= $metadataMaxLengthExcludingMarker; $i++) {
|
||||
for ($j = 0; $j < $markerLength; $j++) {
|
||||
fseek($handle, $fileSize - $i - $j - 1);
|
||||
$matchBit = fgetc($handle);
|
||||
if ($matchBit !== $marker[$markerLength - $j - 1]) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
return $fileSize - $i;
|
||||
}
|
||||
throw new InvalidDatabaseException(
|
||||
"Error opening database file ($filename). " .
|
||||
'Is this a valid MaxMind DB file?'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException if arguments are passed to the method
|
||||
* @throws \BadMethodCallException if the database has been closed
|
||||
*
|
||||
* @return Metadata object for the database
|
||||
*/
|
||||
public function metadata()
|
||||
{
|
||||
if (func_num_args()) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Method takes no arguments.'
|
||||
);
|
||||
}
|
||||
|
||||
// Not technically required, but this makes it consistent with
|
||||
// C extension and it allows us to change our implementation later.
|
||||
if (!is_resource($this->fileHandle)) {
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to read from a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the MaxMind DB and returns resources to the system.
|
||||
*
|
||||
* @throws \Exception
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (!is_resource($this->fileHandle)) {
|
||||
throw new \BadMethodCallException(
|
||||
'Attempt to close a closed MaxMind DB.'
|
||||
);
|
||||
}
|
||||
fclose($this->fileHandle);
|
||||
}
|
||||
}
|
|
@ -1,311 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
class Decoder
|
||||
{
|
||||
private $fileStream;
|
||||
private $pointerBase;
|
||||
// This is only used for unit testing
|
||||
private $pointerTestHack;
|
||||
private $switchByteOrder;
|
||||
|
||||
private $types = [
|
||||
0 => 'extended',
|
||||
1 => 'pointer',
|
||||
2 => 'utf8_string',
|
||||
3 => 'double',
|
||||
4 => 'bytes',
|
||||
5 => 'uint16',
|
||||
6 => 'uint32',
|
||||
7 => 'map',
|
||||
8 => 'int32',
|
||||
9 => 'uint64',
|
||||
10 => 'uint128',
|
||||
11 => 'array',
|
||||
12 => 'container',
|
||||
13 => 'end_marker',
|
||||
14 => 'boolean',
|
||||
15 => 'float',
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
$fileStream,
|
||||
$pointerBase = 0,
|
||||
$pointerTestHack = false
|
||||
) {
|
||||
$this->fileStream = $fileStream;
|
||||
$this->pointerBase = $pointerBase;
|
||||
$this->pointerTestHack = $pointerTestHack;
|
||||
|
||||
$this->switchByteOrder = $this->isPlatformLittleEndian();
|
||||
}
|
||||
|
||||
public function decode($offset)
|
||||
{
|
||||
list(, $ctrlByte) = unpack(
|
||||
'C',
|
||||
Util::read($this->fileStream, $offset, 1)
|
||||
);
|
||||
$offset++;
|
||||
|
||||
$type = $this->types[$ctrlByte >> 5];
|
||||
|
||||
// Pointers are a special case, we don't read the next $size bytes, we
|
||||
// use the size to determine the length of the pointer and then follow
|
||||
// it.
|
||||
if ($type === 'pointer') {
|
||||
list($pointer, $offset) = $this->decodePointer($ctrlByte, $offset);
|
||||
|
||||
// for unit testing
|
||||
if ($this->pointerTestHack) {
|
||||
return [$pointer];
|
||||
}
|
||||
|
||||
list($result) = $this->decode($pointer);
|
||||
|
||||
return [$result, $offset];
|
||||
}
|
||||
|
||||
if ($type === 'extended') {
|
||||
list(, $nextByte) = unpack(
|
||||
'C',
|
||||
Util::read($this->fileStream, $offset, 1)
|
||||
);
|
||||
|
||||
$typeNum = $nextByte + 7;
|
||||
|
||||
if ($typeNum < 8) {
|
||||
throw new InvalidDatabaseException(
|
||||
'Something went horribly wrong in the decoder. An extended type '
|
||||
. 'resolved to a type number < 8 ('
|
||||
. $this->types[$typeNum]
|
||||
. ')'
|
||||
);
|
||||
}
|
||||
|
||||
$type = $this->types[$typeNum];
|
||||
$offset++;
|
||||
}
|
||||
|
||||
list($size, $offset) = $this->sizeFromCtrlByte($ctrlByte, $offset);
|
||||
|
||||
return $this->decodeByType($type, $offset, $size);
|
||||
}
|
||||
|
||||
private function decodeByType($type, $offset, $size)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'map':
|
||||
return $this->decodeMap($size, $offset);
|
||||
case 'array':
|
||||
return $this->decodeArray($size, $offset);
|
||||
case 'boolean':
|
||||
return [$this->decodeBoolean($size), $offset];
|
||||
}
|
||||
|
||||
$newOffset = $offset + $size;
|
||||
$bytes = Util::read($this->fileStream, $offset, $size);
|
||||
switch ($type) {
|
||||
case 'utf8_string':
|
||||
return [$this->decodeString($bytes), $newOffset];
|
||||
case 'double':
|
||||
$this->verifySize(8, $size);
|
||||
|
||||
return [$this->decodeDouble($bytes), $newOffset];
|
||||
case 'float':
|
||||
$this->verifySize(4, $size);
|
||||
|
||||
return [$this->decodeFloat($bytes), $newOffset];
|
||||
case 'bytes':
|
||||
return [$bytes, $newOffset];
|
||||
case 'uint16':
|
||||
case 'uint32':
|
||||
return [$this->decodeUint($bytes), $newOffset];
|
||||
case 'int32':
|
||||
return [$this->decodeInt32($bytes), $newOffset];
|
||||
case 'uint64':
|
||||
case 'uint128':
|
||||
return [$this->decodeBigUint($bytes, $size), $newOffset];
|
||||
default:
|
||||
throw new InvalidDatabaseException(
|
||||
'Unknown or unexpected type: ' . $type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function verifySize($expected, $actual)
|
||||
{
|
||||
if ($expected !== $actual) {
|
||||
throw new InvalidDatabaseException(
|
||||
"The MaxMind DB file's data section contains bad data (unknown data type or corrupt data)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function decodeArray($size, $offset)
|
||||
{
|
||||
$array = [];
|
||||
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
list($value, $offset) = $this->decode($offset);
|
||||
array_push($array, $value);
|
||||
}
|
||||
|
||||
return [$array, $offset];
|
||||
}
|
||||
|
||||
private function decodeBoolean($size)
|
||||
{
|
||||
return $size === 0 ? false : true;
|
||||
}
|
||||
|
||||
private function decodeDouble($bits)
|
||||
{
|
||||
// XXX - Assumes IEEE 754 double on platform
|
||||
list(, $double) = unpack('d', $this->maybeSwitchByteOrder($bits));
|
||||
|
||||
return $double;
|
||||
}
|
||||
|
||||
private function decodeFloat($bits)
|
||||
{
|
||||
// XXX - Assumes IEEE 754 floats on platform
|
||||
list(, $float) = unpack('f', $this->maybeSwitchByteOrder($bits));
|
||||
|
||||
return $float;
|
||||
}
|
||||
|
||||
private function decodeInt32($bytes)
|
||||
{
|
||||
$bytes = $this->zeroPadLeft($bytes, 4);
|
||||
list(, $int) = unpack('l', $this->maybeSwitchByteOrder($bytes));
|
||||
|
||||
return $int;
|
||||
}
|
||||
|
||||
private function decodeMap($size, $offset)
|
||||
{
|
||||
$map = [];
|
||||
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
list($key, $offset) = $this->decode($offset);
|
||||
list($value, $offset) = $this->decode($offset);
|
||||
$map[$key] = $value;
|
||||
}
|
||||
|
||||
return [$map, $offset];
|
||||
}
|
||||
|
||||
private $pointerValueOffset = [
|
||||
1 => 0,
|
||||
2 => 2048,
|
||||
3 => 526336,
|
||||
4 => 0,
|
||||
];
|
||||
|
||||
private function decodePointer($ctrlByte, $offset)
|
||||
{
|
||||
$pointerSize = (($ctrlByte >> 3) & 0x3) + 1;
|
||||
|
||||
$buffer = Util::read($this->fileStream, $offset, $pointerSize);
|
||||
$offset = $offset + $pointerSize;
|
||||
|
||||
$packed = $pointerSize === 4
|
||||
? $buffer
|
||||
: (pack('C', $ctrlByte & 0x7)) . $buffer;
|
||||
|
||||
$unpacked = $this->decodeUint($packed);
|
||||
$pointer = $unpacked + $this->pointerBase
|
||||
+ $this->pointerValueOffset[$pointerSize];
|
||||
|
||||
return [$pointer, $offset];
|
||||
}
|
||||
|
||||
private function decodeUint($bytes)
|
||||
{
|
||||
list(, $int) = unpack('N', $this->zeroPadLeft($bytes, 4));
|
||||
|
||||
return $int;
|
||||
}
|
||||
|
||||
private function decodeBigUint($bytes, $byteLength)
|
||||
{
|
||||
$maxUintBytes = log(PHP_INT_MAX, 2) / 8;
|
||||
|
||||
if ($byteLength === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$numberOfLongs = ceil($byteLength / 4);
|
||||
$paddedLength = $numberOfLongs * 4;
|
||||
$paddedBytes = $this->zeroPadLeft($bytes, $paddedLength);
|
||||
$unpacked = array_merge(unpack("N$numberOfLongs", $paddedBytes));
|
||||
|
||||
$integer = 0;
|
||||
|
||||
// 2^32
|
||||
$twoTo32 = '4294967296';
|
||||
|
||||
foreach ($unpacked as $part) {
|
||||
// We only use gmp or bcmath if the final value is too big
|
||||
if ($byteLength <= $maxUintBytes) {
|
||||
$integer = ($integer << 32) + $part;
|
||||
} elseif (extension_loaded('gmp')) {
|
||||
$integer = gmp_strval(gmp_add(gmp_mul($integer, $twoTo32), $part));
|
||||
} elseif (extension_loaded('bcmath')) {
|
||||
$integer = bcadd(bcmul($integer, $twoTo32), $part);
|
||||
} else {
|
||||
throw new \RuntimeException(
|
||||
'The gmp or bcmath extension must be installed to read this database.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $integer;
|
||||
}
|
||||
|
||||
private function decodeString($bytes)
|
||||
{
|
||||
// XXX - NOOP. As far as I know, the end user has to explicitly set the
|
||||
// encoding in PHP. Strings are just bytes.
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
private function sizeFromCtrlByte($ctrlByte, $offset)
|
||||
{
|
||||
$size = $ctrlByte & 0x1f;
|
||||
$bytesToRead = $size < 29 ? 0 : $size - 28;
|
||||
$bytes = Util::read($this->fileStream, $offset, $bytesToRead);
|
||||
$decoded = $this->decodeUint($bytes);
|
||||
|
||||
if ($size === 29) {
|
||||
$size = 29 + $decoded;
|
||||
} elseif ($size === 30) {
|
||||
$size = 285 + $decoded;
|
||||
} elseif ($size > 30) {
|
||||
$size = ($decoded & (0x0FFFFFFF >> (32 - (8 * $bytesToRead))))
|
||||
+ 65821;
|
||||
}
|
||||
|
||||
return [$size, $offset + $bytesToRead];
|
||||
}
|
||||
|
||||
private function zeroPadLeft($content, $desiredLength)
|
||||
{
|
||||
return str_pad($content, $desiredLength, "\x00", STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
private function maybeSwitchByteOrder($bytes)
|
||||
{
|
||||
return $this->switchByteOrder ? strrev($bytes) : $bytes;
|
||||
}
|
||||
|
||||
private function isPlatformLittleEndian()
|
||||
{
|
||||
$testint = 0x00FF;
|
||||
$packed = pack('S', $testint);
|
||||
|
||||
return $testint === current(unpack('v', $packed));
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
/**
|
||||
* This class should be thrown when unexpected data is found in the database.
|
||||
*/
|
||||
class InvalidDatabaseException extends \Exception
|
||||
{
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
/**
|
||||
* This class provides the metadata for the MaxMind DB file.
|
||||
*
|
||||
* @property int nodeCount This is an unsigned 32-bit integer indicating
|
||||
* the number of nodes in the search tree.
|
||||
* @property int recordSize This is an unsigned 16-bit integer. It
|
||||
* indicates the number of bits in a record in the search tree. Note that each
|
||||
* node consists of two records.
|
||||
* @property int ipVersion This is an unsigned 16-bit integer which is
|
||||
* always 4 or 6. It indicates whether the database contains IPv4 or IPv6
|
||||
* address data.
|
||||
* @property string databaseType This is a string that indicates the structure
|
||||
* of each data record associated with an IP address. The actual definition of
|
||||
* these structures is left up to the database creator.
|
||||
* @property array languages An array of strings, each of which is a language
|
||||
* code. A given record may contain data items that have been localized to
|
||||
* some or all of these languages. This may be undefined.
|
||||
* @property int binaryFormatMajorVersion This is an unsigned 16-bit
|
||||
* integer indicating the major version number for the database's binary
|
||||
* format.
|
||||
* @property int binaryFormatMinorVersion This is an unsigned 16-bit
|
||||
* integer indicating the minor version number for the database's binary format.
|
||||
* @property int buildEpoch This is an unsigned 64-bit integer that
|
||||
* contains the database build timestamp as a Unix epoch value.
|
||||
* @property array description This key will always point to a map
|
||||
* (associative array). The keys of that map will be language codes, and the
|
||||
* values will be a description in that language as a UTF-8 string. May be
|
||||
* undefined for some databases.
|
||||
*/
|
||||
class Metadata
|
||||
{
|
||||
private $binaryFormatMajorVersion;
|
||||
private $binaryFormatMinorVersion;
|
||||
private $buildEpoch;
|
||||
private $databaseType;
|
||||
private $description;
|
||||
private $ipVersion;
|
||||
private $languages;
|
||||
private $nodeByteSize;
|
||||
private $nodeCount;
|
||||
private $recordSize;
|
||||
private $searchTreeSize;
|
||||
|
||||
public function __construct($metadata)
|
||||
{
|
||||
$this->binaryFormatMajorVersion =
|
||||
$metadata['binary_format_major_version'];
|
||||
$this->binaryFormatMinorVersion =
|
||||
$metadata['binary_format_minor_version'];
|
||||
$this->buildEpoch = $metadata['build_epoch'];
|
||||
$this->databaseType = $metadata['database_type'];
|
||||
$this->languages = $metadata['languages'];
|
||||
$this->description = $metadata['description'];
|
||||
$this->ipVersion = $metadata['ip_version'];
|
||||
$this->nodeCount = $metadata['node_count'];
|
||||
$this->recordSize = $metadata['record_size'];
|
||||
$this->nodeByteSize = $this->recordSize / 4;
|
||||
$this->searchTreeSize = $this->nodeCount * $this->nodeByteSize;
|
||||
}
|
||||
|
||||
public function __get($var)
|
||||
{
|
||||
return $this->$var;
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace MaxMind\Db\Reader;
|
||||
|
||||
class Util
|
||||
{
|
||||
public static function read($stream, $offset, $numberOfBytes)
|
||||
{
|
||||
if ($numberOfBytes === 0) {
|
||||
return '';
|
||||
}
|
||||
if (fseek($stream, $offset) === 0) {
|
||||
$value = fread($stream, $numberOfBytes);
|
||||
|
||||
// We check that the number of bytes read is equal to the number
|
||||
// asked for. We use ftell as getting the length of $value is
|
||||
// much slower.
|
||||
if (ftell($stream) - $offset === $numberOfBytes) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
throw new InvalidDatabaseException(
|
||||
'The MaxMind DB file contains bad data'
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1839,7 +1839,7 @@ function wc_update_343_cleanup_foreign_keys() {
|
|||
|
||||
if ( $results ) {
|
||||
foreach ( $results as $fk ) {
|
||||
$wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_download_log DROP FOREIGN KEY {$fk->CONSTRAINT_NAME}" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
|
||||
$wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_download_log DROP FOREIGN KEY {$fk->CONSTRAINT_NAME}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2046,3 +2046,38 @@ function wc_update_370_mro_std_currency() {
|
|||
function wc_update_370_db_version() {
|
||||
WC_Install::update_db_version( '3.7.0' );
|
||||
}
|
||||
|
||||
/**
|
||||
* We've moved the MaxMind database to a new location, as per the TOS' requirement that the database not
|
||||
* be publicly accessible.
|
||||
*/
|
||||
function wc_update_390_move_maxmind_database() {
|
||||
// Make sure to use all of the correct filters to pull the local database path.
|
||||
$old_path = apply_filters( 'woocommerce_geolocation_local_database_path', WP_CONTENT_DIR . '/uploads/GeoLite2-Country.mmdb', 2 );
|
||||
|
||||
// Generate a prefix for the old file and store it in the integration as it would expect it.
|
||||
$prefix = wp_generate_password( 32, false );
|
||||
update_option( 'woocommerce_maxmind_geolocation_settings', array( 'database_prefix' => $prefix ) );
|
||||
|
||||
// Generate the new path in the same way that the integration will.
|
||||
$uploads_dir = wp_upload_dir();
|
||||
$new_path = trailingslashit( $uploads_dir['basedir'] ) . 'woocommerce_uploads/' . $prefix . '-GeoLite2-Country.mmdb';
|
||||
$new_path = apply_filters( 'woocommerce_geolocation_local_database_path', $new_path, 2 );
|
||||
|
||||
@rename( $old_path, $new_path ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
|
||||
}
|
||||
|
||||
/**
|
||||
* So that we can best meet MaxMind's TOS, the geolocation database update cron should run once per 15 days.
|
||||
*/
|
||||
function wc_update_390_change_geolocation_database_update_cron() {
|
||||
wp_clear_scheduled_hook( 'woocommerce_geoip_updater' );
|
||||
wp_schedule_event( time() + ( DAY_IN_SECONDS * 15 ), 'fifteendays', 'woocommerce_geoip_updater' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update DB version.
|
||||
*/
|
||||
function wc_update_390_db_version() {
|
||||
WC_Install::update_db_version( '3.9.0' );
|
||||
}
|
||||
|
|
|
@ -3608,12 +3608,6 @@
|
|||
"integrity": "sha512-Jrb/x3HT4PTJp6a4avhmJCDEVrPdqLfl3e8GGMbpkGGdwAV5UGlIs4vVEfsHHfylZVOKZWpOqmqFH8CbfOZ6kg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/normalize-package-data": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
||||
"integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||
|
@ -6252,9 +6246,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
|
||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"lru-cache": {
|
||||
|
@ -6876,9 +6870,9 @@
|
|||
}
|
||||
},
|
||||
"fault": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/fault/-/fault-1.0.2.tgz",
|
||||
"integrity": "sha512-o2eo/X2syzzERAtN5LcGbiVQ0WwZSlN3qLtadwAz3X8Bu+XWD16dja/KMsjZLiQr+BLGPDnHGkc4yUJf1Xpkpw==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/fault/-/fault-1.0.3.tgz",
|
||||
"integrity": "sha512-sfFuP4X0hzrbGKjAUNXYvNqsZ5F6ohx/dZ9I0KQud/aiZNwg263r5L9yGB0clvXHCkzXh5W3t7RSHchggYIFmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"format": "^0.2.2"
|
||||
|
@ -7126,9 +7120,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"flatten": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz",
|
||||
"integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz",
|
||||
"integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==",
|
||||
"dev": true
|
||||
},
|
||||
"flow-parser": {
|
||||
|
@ -8679,9 +8673,9 @@
|
|||
}
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
|
||||
"integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
|
||||
"version": "4.5.3",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
|
||||
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"neo-async": "^2.6.0",
|
||||
|
@ -8922,28 +8916,73 @@
|
|||
}
|
||||
},
|
||||
"husky": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/husky/-/husky-3.1.0.tgz",
|
||||
"integrity": "sha512-FJkPoHHB+6s4a+jwPqBudBDvYZsoQW5/HBuMSehC8qDiCe50kpcxeqFoDSlow+9I6wg47YxBoT3WxaURlrDIIQ==",
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/husky/-/husky-4.0.10.tgz",
|
||||
"integrity": "sha512-Ptm4k2DqOwxeK/kzu5RaJmNRoGvESrgDXObFcZ8aJZcyXyMBHhM2FqZj6zYKdetadmP3wCwxEHCBuB9xGlRp8A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"chalk": "^3.0.0",
|
||||
"ci-info": "^2.0.0",
|
||||
"cosmiconfig": "^5.2.1",
|
||||
"execa": "^1.0.0",
|
||||
"get-stdin": "^7.0.0",
|
||||
"cosmiconfig": "^6.0.0",
|
||||
"opencollective-postinstall": "^2.0.2",
|
||||
"pkg-dir": "^4.2.0",
|
||||
"please-upgrade-node": "^3.2.0",
|
||||
"read-pkg": "^5.2.0",
|
||||
"run-node": "^1.0.0",
|
||||
"slash": "^3.0.0"
|
||||
"slash": "^3.0.0",
|
||||
"which-pm-runs": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"get-stdin": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz",
|
||||
"integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==",
|
||||
"ansi-styles": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
||||
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/color-name": "^1.1.1",
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"cosmiconfig": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
|
||||
"integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"import-fresh": "^3.1.0",
|
||||
"parse-json": "^5.0.0",
|
||||
"path-type": "^4.0.0",
|
||||
"yaml": "^1.7.2"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"parse-json": {
|
||||
|
@ -8958,23 +8997,20 @@
|
|||
"lines-and-columns": "^1.1.6"
|
||||
}
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
|
||||
"integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
|
||||
"path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
|
||||
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/normalize-package-data": "^2.4.0",
|
||||
"normalize-package-data": "^2.5.0",
|
||||
"parse-json": "^5.0.0",
|
||||
"type-fest": "^0.6.0"
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"type-fest": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
|
||||
"integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -11662,6 +11698,15 @@
|
|||
"unist-util-visit": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"mem": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
|
||||
"integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mimic-fn": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"memize": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/memize/-/memize-1.0.5.tgz",
|
||||
|
@ -13122,15 +13167,6 @@
|
|||
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
|
||||
"dev": true
|
||||
},
|
||||
"mem": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
|
||||
"integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mimic-fn": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
|
@ -13180,14 +13216,6 @@
|
|||
"requires": {
|
||||
"ansi-regex": "^3.0.0",
|
||||
"ansi-styles": "^3.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"private": {
|
||||
|
@ -13994,12 +14022,6 @@
|
|||
"is-promise": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"run-node": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz",
|
||||
"integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==",
|
||||
"dev": true
|
||||
},
|
||||
"run-parallel": {
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
|
||||
|
@ -16628,6 +16650,12 @@
|
|||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
|
||||
},
|
||||
"which-pm-runs": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
|
||||
"integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=",
|
||||
"dev": true
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
"grunt-shell": "3.0.1",
|
||||
"grunt-stylelint": "0.13.0",
|
||||
"grunt-wp-i18n": "1.0.3",
|
||||
"husky": "3.1.0",
|
||||
"husky": "4.0.10",
|
||||
"istanbul": "1.0.0-alpha.2",
|
||||
"jest": "24.9.0",
|
||||
"jest-puppeteer": "4.4.0",
|
||||
|
|
|
@ -201,6 +201,7 @@ INTERESTED IN DEVELOPMENT?
|
|||
* Tweak - Include processing orders in tracker data when opted in. #25071
|
||||
* Tweak - Centralize check for default themes to fix Storefront appearance in the Setup Wizard. #25216
|
||||
* Tweak - Adds a WordPress version check before recommending the WooCommerce Admin plugin during setup. #25260
|
||||
* Fix - Added license key support recent changes from MaxMind GeoLite2. #25378
|
||||
* Fix - Honor tax rounding preference in edit item and refund flows. #24208
|
||||
* Fix - Prevent incorrect number of decimal points in prices. #24281
|
||||
* Fix - Fixed initial support for Gutenberg's Experimental Legacy Widget block. #24292
|
||||
|
|
Binary file not shown.
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Class Functions.
|
||||
*
|
||||
* @package WooCommerce\Tests\Geolocation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WC_Tests_Integrations
|
||||
*/
|
||||
class WC_Tests_Geolite_Integration extends WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* Test get country ISO.
|
||||
*
|
||||
* @requires PHP 5.4
|
||||
*/
|
||||
public function test_get_country_iso() {
|
||||
require_once dirname( WC_PLUGIN_FILE ) . '/includes/class-wc-geolite-integration.php';
|
||||
|
||||
// Download GeoLite2 database.
|
||||
WC_Geolocation::update_database();
|
||||
|
||||
// OpenDNS IP address.
|
||||
$ipv4 = '208.67.220.220';
|
||||
$ipv6 = '2620:0:ccc::2';
|
||||
|
||||
// Init GeoLite.
|
||||
$geolite = new WC_Geolite_Integration( WC_Geolocation::get_local_database_path() );
|
||||
|
||||
// Check for IPv4.
|
||||
$this->assertEquals( 'US', $geolite->get_country_iso( $ipv4 ) );
|
||||
|
||||
// Check for IPv6.
|
||||
$this->assertEquals( 'US', $geolite->get_country_iso( $ipv6 ) );
|
||||
|
||||
// Check for non-valid IP.
|
||||
$this->assertEquals( '', $geolite->get_country_iso( 'foobar' ) );
|
||||
}
|
||||
}
|
|
@ -30,8 +30,8 @@ class WC_Tests_Integrations extends WC_Unit_Test_Case {
|
|||
*/
|
||||
public function test_filter() {
|
||||
$integrations = new WC_Integrations();
|
||||
$this->assertEquals( array(), $integrations->integrations );
|
||||
$this->assertEquals( array(), $integrations->get_integrations() );
|
||||
$this->assertArrayHasKey( 'maxmind_geolocation', $integrations->integrations );
|
||||
$this->assertArrayHasKey( 'maxmind_geolocation', $integrations->get_integrations() );
|
||||
|
||||
require_once dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'class-dummy-integration.php';
|
||||
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
/**
|
||||
* Class Functions.
|
||||
*
|
||||
* @package WooCommerce\Tests\Integrations
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WC_Tests_MaxMind_Database
|
||||
*/
|
||||
class WC_Tests_MaxMind_Database extends WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* Run setup code for unit tests.
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Callback used by WP_HTTP_TestCase to decide whether to perform HTTP requests or to provide a mocked response.
|
||||
$this->http_responder = array( $this, 'mock_http_responses' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the database path filters work as intended.
|
||||
*
|
||||
* @expectedDeprecated woocommerce_geolocation_local_database_path
|
||||
*/
|
||||
public function test_database_path_filters() {
|
||||
$database_service = new WC_Integration_MaxMind_Database_Service( '' );
|
||||
|
||||
$path = $database_service->get_database_path();
|
||||
$this->assertEquals( WP_CONTENT_DIR . '/uploads/woocommerce_uploads/' . WC_Integration_MaxMind_Database_Service::DATABASE . WC_Integration_MaxMind_Database_Service::DATABASE_EXTENSION, $path );
|
||||
|
||||
add_filter( 'woocommerce_geolocation_local_database_path', array( $this, 'filter_database_path_deprecated' ), 1, 2 );
|
||||
$path = $database_service->get_database_path();
|
||||
remove_filter( 'woocommerce_geolocation_local_database_path', array( $this, 'filter_database_path_deprecated' ), 1 );
|
||||
|
||||
$this->assertEquals( '/deprecated_filter', $path );
|
||||
|
||||
add_filter( 'woocommerce_geolocation_local_database_path', array( $this, 'filter_database_path' ) );
|
||||
$path = $database_service->get_database_path();
|
||||
remove_filter( 'woocommerce_geolocation_local_database_path', array( $this, 'filter_database_path' ) );
|
||||
|
||||
$this->assertEquals( '/filter', $path );
|
||||
|
||||
// Now perform any tests with a database file prefix.
|
||||
$database_service = new WC_Integration_MaxMind_Database_Service( 'testing' );
|
||||
|
||||
$path = $database_service->get_database_path();
|
||||
$this->assertEquals( WP_CONTENT_DIR . '/uploads/woocommerce_uploads/testing-' . WC_Integration_MaxMind_Database_Service::DATABASE . WC_Integration_MaxMind_Database_Service::DATABASE_EXTENSION, $path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the database download works as expected.
|
||||
*/
|
||||
public function test_download_database_works() {
|
||||
$database_service = new WC_Integration_MaxMind_Database_Service( '' );
|
||||
$expected_database = '/tmp/GeoLite2-Country_20200100/GeoLite2-Country.mmdb';
|
||||
|
||||
$result = $database_service->download_database( 'testing_license' );
|
||||
|
||||
$this->assertEquals( $expected_database, $result );
|
||||
|
||||
// Remove the downloaded file and folder.
|
||||
unlink( $expected_database );
|
||||
rmdir( dirname( $expected_database ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the that database download wraps the download and extraction errors.
|
||||
*/
|
||||
public function test_download_database_wraps_errors() {
|
||||
$database_service = new WC_Integration_MaxMind_Database_Service( '' );
|
||||
|
||||
$result = $database_service->download_database( 'invalid_license' );
|
||||
|
||||
$this->assertWPError( $result );
|
||||
$this->assertEquals( 'woocommerce_maxmind_geolocation_database_license_key', $result->get_error_code() );
|
||||
|
||||
$result = $database_service->download_database( 'generic_error' );
|
||||
|
||||
$this->assertWPError( $result );
|
||||
$this->assertEquals( 'woocommerce_maxmind_geolocation_database_download', $result->get_error_code() );
|
||||
|
||||
$result = $database_service->download_database( 'archive_error' );
|
||||
|
||||
$this->assertWPError( $result );
|
||||
$this->assertEquals( 'woocommerce_maxmind_geolocation_database_archive', $result->get_error_code() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for the deprecated database path filter.
|
||||
*
|
||||
* @param string $database_path The path to the database file.
|
||||
* @param string $deprecated Deprecated since 3.4.0.
|
||||
* @return string
|
||||
*/
|
||||
public function filter_database_path_deprecated( $database_path, $deprecated ) {
|
||||
return '/deprecated_filter';
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for the database path filter.
|
||||
*
|
||||
* @param string $database_path The path to the database file.
|
||||
* @return string
|
||||
*/
|
||||
public function filter_database_path( $database_path ) {
|
||||
return '/filter';
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to define mocked HTTP responses using WP_HTTP_TestCase.
|
||||
* Thanks to WP_HTTP_TestCase, it is not necessary to perform a regular request
|
||||
* to an external server which would significantly slow down the tests.
|
||||
*
|
||||
* This function is called by WP_HTTP_TestCase::http_request_listner().
|
||||
*
|
||||
* @param array $request Request arguments.
|
||||
* @param string $url URL of the request.
|
||||
*
|
||||
* @return array|WP_Error|false mocked response, error, or false to let WP perform a regular request.
|
||||
*/
|
||||
protected function mock_http_responses( $request, $url ) {
|
||||
$mocked_response = false;
|
||||
|
||||
if ( 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=testing_license&suffix=tar.gz' === $url ) {
|
||||
// We need to copy the file to where the request is supposed to have streamed it.
|
||||
copy( WC_Unit_Tests_Bootstrap::instance()->tests_dir . '/data/GeoLite2-Country.tar.gz', $request['filename'] );
|
||||
|
||||
$mocked_response = array(
|
||||
'response' => array( 'code' => 200 ),
|
||||
);
|
||||
} elseif ( 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=invalid_license&suffix=tar.gz' === $url ) {
|
||||
return new WP_Error( 'http_404', 'Unauthorized', array( 'code' => 401 ) );
|
||||
} elseif ( 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=generic_error&suffix=tar.gz' === $url ) {
|
||||
return new WP_Error( 'http_404', 'Unauthorized', array( 'code' => 500 ) );
|
||||
} elseif ( 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=archive_error&suffix=tar.gz' === $url ) {
|
||||
$mocked_response = array(
|
||||
'response' => array( 'code' => 200 ),
|
||||
);
|
||||
}
|
||||
|
||||
return $mocked_response;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
/**
|
||||
* Class Functions.
|
||||
*
|
||||
* @package WooCommerce\Tests\Integrations
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WC_Tests_MaxMind_Integration
|
||||
*/
|
||||
class WC_Tests_MaxMind_Integration extends WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* The mock database service that our integration class will utilize.
|
||||
*
|
||||
* @var WC_Integration_MaxMind_Database_Service|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
private $database_service;
|
||||
|
||||
/**
|
||||
* Run setup code for unit tests.
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Override the filesystem method that we're using.
|
||||
add_filter( 'filesystem_method', array( $this, 'override_filesystem_method' ) );
|
||||
|
||||
// Have a mock service be used by all integrations.
|
||||
$this->database_service = $this->getMockBuilder( 'WC_Integration_maxMind_Database_Service' )
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
add_filter( 'woocommerce_maxmind_geolocation_database_service', array( $this, 'override_integration_service' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that the database is not updated if no target database path is given.
|
||||
*/
|
||||
public function test_update_database_does_nothing_without_database_path() {
|
||||
$this->database_service->expects( $this->once() )
|
||||
->method( 'get_database_path' )
|
||||
->willReturn( '' );
|
||||
|
||||
( new WC_Integration_MaxMind_Geolocation() )->update_database();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the database can be updated to a given database.
|
||||
*/
|
||||
public function test_update_database_to_parameter_file() {
|
||||
$this->database_service->expects( $this->once() )
|
||||
->method( 'get_database_path' )
|
||||
->willReturn( '/testing' );
|
||||
|
||||
( new WC_Integration_MaxMind_Geolocation() )->update_database( '/tmp/noop.mmdb' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the integration uses the license key correctly.
|
||||
*/
|
||||
public function test_update_database_uses_license_key() {
|
||||
$this->database_service->expects( $this->once() )
|
||||
->method( 'get_database_path' )
|
||||
->willReturn( '/testing' );
|
||||
$this->database_service->expects( $this->once() )
|
||||
->method( 'download_database' )
|
||||
->with( 'test_license' )
|
||||
->willReturn( '/tmp/' . WC_Integration_MaxMind_Database_Service::DATABASE . '.' . WC_Integration_MaxMind_Database_Service::DATABASE_EXTENSION );
|
||||
|
||||
$integration = new WC_Integration_MaxMind_Geolocation();
|
||||
$integration->update_option( 'license_key', 'test_license' );
|
||||
|
||||
$integration->update_database();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that the geolocate_ip method does not squash existing country codes.
|
||||
*/
|
||||
public function test_geolocate_ip_returns_existing_country_code() {
|
||||
$data = ( new WC_Integration_MaxMind_Geolocation() )->get_geolocation( array( 'country' => 'US' ), '192.168.1.1' );
|
||||
|
||||
$this->assertEquals( 'US', $data['country'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that the geolocate_ip method does nothing if IP is not set.
|
||||
*/
|
||||
public function test_geolocate_ip_returns_empty_without_ip_address() {
|
||||
$data = ( new WC_Integration_MaxMind_Geolocation() )->get_geolocation( array(), '' );
|
||||
|
||||
$this->assertEmpty( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that the geolocate_ip method uses the appropriate service methods..
|
||||
*/
|
||||
public function test_geolocate_ip_uses_service() {
|
||||
$this->database_service->expects( $this->once() )
|
||||
->method( 'get_iso_country_code_for_ip' )
|
||||
->with( '192.168.1.1' )
|
||||
->willReturn( 'US' );
|
||||
|
||||
$data = ( new WC_Integration_MaxMind_Geolocation() )->get_geolocation( array(), '192.168.1.1' );
|
||||
|
||||
$this->assertEquals( 'US', $data['country'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the filesystem method.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function override_filesystem_method() {
|
||||
return 'Base';
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the database service used by the integration.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function override_integration_service() {
|
||||
return $this->database_service;
|
||||
}
|
||||
}
|
|
@ -60,19 +60,6 @@ class WC_Tests_Shipping extends WC_Unit_Test_Case {
|
|||
);
|
||||
$this->assertFalse( $result );
|
||||
|
||||
// Failure for invalid postcode.
|
||||
$result = $shipping->is_package_shippable(
|
||||
array(
|
||||
'destination' => array(
|
||||
'country' => 'US',
|
||||
'state' => 'CA',
|
||||
'postcode' => 'test',
|
||||
'address' => '',
|
||||
),
|
||||
)
|
||||
);
|
||||
$this->assertFalse( $result );
|
||||
|
||||
// Success for correct address.
|
||||
$result = $shipping->is_package_shippable(
|
||||
array(
|
||||
|
|
|
@ -82,8 +82,12 @@ class WC_Tests_API_Functions extends WC_Unit_Test_Case {
|
|||
*/
|
||||
public function test_wc_rest_upload_image_from_url_should_return_error_when_invalid_image_is_passed() {
|
||||
// empty file.
|
||||
$expected_error_message = 'Invalid image: File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.';
|
||||
$result = wc_rest_upload_image_from_url( 'http://somedomain.com/invalid-image-1.png' );
|
||||
if ( version_compare( get_bloginfo( 'version' ), '5.4-alpha', '>=' ) ) {
|
||||
$expected_error_message = 'Invalid image: File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini file or by post_max_size being defined as smaller than upload_max_filesize in php.ini.';
|
||||
} else {
|
||||
$expected_error_message = 'Invalid image: File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.';
|
||||
}
|
||||
$result = wc_rest_upload_image_from_url( 'http://somedomain.com/invalid-image-1.png' );
|
||||
|
||||
$this->assertWPError( $result );
|
||||
$this->assertEquals( $expected_error_message, $result->get_error_message() );
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Plugin Name: WooCommerce
|
||||
* Plugin URI: https://woocommerce.com/
|
||||
* Description: An eCommerce toolkit that helps you sell anything. Beautifully.
|
||||
* Version: 3.9.0-rc.2
|
||||
* Version: 3.9.0-rc.3
|
||||
* Author: Automattic
|
||||
* Author URI: https://woocommerce.com
|
||||
* Text Domain: woocommerce
|
||||
|
|
Loading…
Reference in New Issue