Files
roi-theme/wp-content/plugins/advanced-ads-pro/modules/geo/classes/admin.php
root a22573bf0b Commit inicial - WordPress Análisis de Precios Unitarios
- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 21:04:30 -06:00

848 lines
31 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php // phpcs:ignore WordPress.Files.FileName
/**
* Dashboard helper class
*
* @package AdvancedAds\Pro
* @author Advanced Ads <info@wpadvancedads.com>
*/
use AdvancedAds\Utilities\Conditional;
use AdvancedAds\Framework\Utilities\Params;
use GeoIp2\Exception\AddressNotFoundException;
/**
* WP Admin class for Geo Targeting.
*/
class Advanced_Ads_Geo_Admin {
/**
* Path to view files
*
* @var string
*/
private $views_path;
/**
* Initialize the plugin by loading admin scripts & styles and adding a
* settings page and menu.
*
* @since 1.0.0
*/
public function __construct() {
$this->views_path = plugin_dir_path( __FILE__ ) . '../admin/views';
add_action( 'advanced-ads-settings-init', [ $this, 'settings_init' ] );
// ajax request to download the database.
add_action( 'wp_ajax_advads_download_geolite_database', [ $this, 'download_database' ] );
// Add assets.
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] );
}
/**
* Add settings to settings page
*/
public function settings_init() {
// add new section.
add_settings_section(
'advanced_ads_geo_setting_section',
__( 'Geo Targeting', 'advanced-ads-pro' ),
'__return_empty_string',
Advanced_Ads_Pro::OPTION_KEY . '-settings'
);
// Add license key field.
add_settings_field(
'geo-maxmind-license-key',
__( 'MaxMind license key', 'advanced-ads-pro' ),
[ $this, 'render_settings_license_key_callback' ],
Advanced_Ads_Pro::OPTION_KEY . '-settings',
'advanced_ads_geo_setting_section'
);
// Add database field.
add_settings_field(
'geo-database-update',
__( 'MaxMind Database', 'advanced-ads-pro' ),
[ $this, 'render_settings_database' ],
Advanced_Ads_Pro::OPTION_KEY . '-settings',
'advanced_ads_geo_setting_section'
);
// add field for the targeting method.
if ( count( Advanced_Ads_Geo_Plugin::get_instance()->get_targeting_methods() ) > 1 ) {
add_settings_field(
'geo-license',
__( 'Method', 'advanced-ads-pro' ),
[ $this, 'render_settings_method_callback' ],
Advanced_Ads_Pro::OPTION_KEY . '-settings',
'advanced_ads_geo_setting_section'
);
}
// add assistant setting field.
add_settings_field(
'geo-locale',
__( 'Language of names', 'advanced-ads-pro' ),
[ $this, 'render_settings_locale_option_callback' ],
Advanced_Ads_Pro::OPTION_KEY . '-settings',
'advanced_ads_geo_setting_section'
);
}
/**
* Render MaxMind license key field.
*/
public function render_settings_license_key_callback() {
$use_filters = $this->is_using_custom_database();
$license_key = Advanced_Ads_Geo_Plugin::get_instance()->options( 'maxmind-license-key', '' );
include $this->views_path . '/setting-maxmind-license-key.php';
}
/**
* Render MaxMind database field.
*
* @return void
*/
public function render_settings_database() {
$last_update = get_option( ADVADS_SLUG . '-' . Advanced_Ads_Geo_Plugin::OPTIONS_SLUG . '-last-update-geolite2', false );
$next_update = $this->get_next_first_tuesday_timestamp();
// Check if the database files exist and do not contain errors.
$api = Advanced_Ads_Geo_Api::get_instance();
$correct_databases = $api->get_geo_ip2_city_reader() && $api->get_geo_ip2_country_reader();
$use_filters = $this->is_using_custom_database();
// Render download of the geo database.
include $this->views_path . '/setting-download.php';
}
/**
* Render option for the geo targeting method
*/
public function render_settings_method_callback() {
$method = Advanced_Ads_Geo_Plugin::get_instance()->options( 'method', 'default' );
$methods = Advanced_Ads_Geo_Plugin::get_instance()->get_targeting_methods();
include $this->views_path . '/setting-method.php';
}
/**
* Render option for language of the geo information
*/
public function render_settings_locale_option_callback() {
$locale = Advanced_Ads_Geo_Plugin::get_instance()->options( 'locale', 'en' );
include $this->views_path . '/setting-locale.php';
}
/**
* Allow static method call as visitor condition callback.
*
* @param string $name method name.
* @param mixed $arguments functions arguments.
*/
public static function __callStatic( $name, $arguments ) {
if ( 'metabox_geo' === $name ) {
( new self() )->metabox_geo( ...$arguments );
}
// else fail silently.
}
/**
* Add visitor condition box
*
* @param array $options ad options.
* @param int $index current index in conditions list.
* @param string $form_name form name of current condition.
*
* @return void
* @throws \MaxMind\Db\Reader\InvalidDatabaseException Corrupted DB files.
*/
private function metabox_geo( $options, $index = 0, $form_name = '' ) {
if ( empty( $options['type'] ) ) {
return;
}
$type_options = Advanced_Ads_Visitor_Conditions::get_instance()->conditions;
if ( ! isset( $type_options[ $options['type'] ] ) ) {
return;
}
$method = Advanced_Ads_Geo_Plugin::get_current_targeting_method();
$countries = Advanced_Ads_Geo_Api::get_countries();
// set defaults for all variables.
$my_country = '';
$my_country_iso_code = '';
$my_city = '';
$my_region = '';
$my_lat = 0.0;
$my_lon = 0.0;
switch ( $method ) {
case 'sucuri':
$my_country_iso_code = Advanced_Ads_Geo_Plugin::get_sucuri_country();
$my_country = $countries[ $my_country_iso_code ] ?? ' ';
$current_location = sprintf( '%s (%s)', $my_country, $my_country_iso_code );
break;
default:
// get information from the current user to help him debugging issues.
$api = Advanced_Ads_Geo_Api::get_instance();
$ip = $api->get_real_ip_address();
$error = false;
// get locale.
$locale = Advanced_Ads_Geo_Plugin::get_instance()->options( 'locale', 'en' );
if ( $ip ) {
try {
$reader = $api->get_geo_ip2_city_reader();
if ( $reader ) {
// Look up the IP address.
$record = $reader->city( $ip );
if ( ! empty( $record ) ) {
$my_city = ( $record->city->name ) ? $record->city->name : __( '(unknown city)', 'advanced-ads-pro' );
if ( isset( $record->city->names[ $locale ] ) && $record->city->names[ $locale ] ) {
$my_city = $record->city->names[ $locale ];
}
$my_country = ( isset( $record->country->names[ $locale ] ) && $record->country->names[ $locale ] )
? $record->country->names[ $locale ]
: $record->country->names['en'];
$my_country_iso_code = $record->country->isoCode;
// get first subdivision (region/state).
$my_region = ( isset( $record->subdivisions[0] ) && $record->subdivisions[0]->name ) ? $record->subdivisions[0]->name : __( '(unknown region)', 'advanced-ads-pro' );
if ( isset( $record->subdivisions[0] ) && isset( $record->subdivisions[0]->names[ $locale ] ) && $record->subdivisions[0]->names[ $locale ] ) {
$my_region = $record->subdivisions[0]->names[ $locale ];
}
if ( isset( $record->location ) && isset( $record->location->latitude ) && isset( $record->location->longitude ) ) {
$my_lat = $record->location->latitude;
$my_lon = $record->location->longitude;
}
}
} else {
$error = sprintf(
'%1$s %2$s',
__( 'Geo Databases not found.', 'advanced-ads-pro' ),
sprintf(
/* translators: 1: opening <a>-tag to Advanced Ads manual, 2: closing <a>-tag */
__( 'Please read the %1$sinstallation instructions%2$s.', 'advanced-ads-pro' ),
'<a href="https://wpadvancedads.com/manual/geo-targeting-condition/#Enabling_Geo-Targeting" target="_blank">',
'</a>'
)
);
}
} catch ( AddressNotFoundException $e ) {
$error = $e->getMessage() . ' ' . __( 'Maybe you are working on a local or secured environment.', 'advanced-ads-pro' );
}
} else {
$raw_ip = $api->get_raw_ip_address();
$error = '<span class="advads-notice-inline advads-error">' . __( 'Your IP address format is incorrect', 'advanced-ads-pro' ) . ' (' . $raw_ip . ')</span>';
}
if ( $error ) {
$current_location = '<span class="advads-notice-inline advads-error">' . $error . '</span>';
} else {
$current_location = $ip . ', ' . $my_country . ', ' . $my_region . ', ' . $my_city;
$current_location .= '<br/>' . __( 'Coordinates', 'advanced-ads-pro' ) . ': (' . $my_lat . ' / ' . $my_lon . ')';
}
}
// form name basis.
if ( method_exists( 'Advanced_Ads_Visitor_Conditions', 'get_form_name_with_index' ) ) {
$name = Advanced_Ads_Visitor_Conditions::get_form_name_with_index( $form_name, $index );
} else {
$name = Advanced_Ads_Visitor_Conditions::FORM_NAME . '[' . $index . ']';
}
$operator = isset( $options['operator'] ) ? $options['operator'] : 'is';
$geo_mode = isset( $options['geo_mode'] ) ? $options['geo_mode'] : 'classic';
?>
<input type="hidden" name="<?php echo esc_attr( $name ); ?>[type]" value="<?php echo esc_attr( $options['type'] ); ?>"/>
<input type="hidden" name="<?php echo esc_attr( $name ); ?>[value]" value="1"/>
<style type="text/css">
span.geomode {
display: inline-block;
clear: both;
margin: 0px 0px 5px 0px;
}
span.geomode input[type=radio] {
display: block;
float: left;
margin: 0px 5px 0px 5px;
}
</style>
<div style="margin-bottom: 10pt;">
<span class="geomode">
<?php // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<input id="radio_classic_<?php echo esc_attr( $index ); ?>" type="radio" name="<?php echo esc_attr( $name ); ?>[geo_mode]" <?php checked( $geo_mode, 'classic' ); ?> value="classic" onclick="advads_geo_admin.set_mode(<?php echo $index; ?>, this.value);">
<?php // phpcs:enable ?>
<label for="radio_classic_<?php echo esc_attr( $index ); ?>"><?php esc_html_e( 'by specific location', 'advanced-ads-pro' ); ?></label>
</span>
<span class="geomode">
<?php // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<input class="geomode" id="radio_latlon_<?php echo esc_attr( $index ); ?>" type="radio" name="<?php echo esc_attr( $name ); ?>[geo_mode]" <?php checked( $geo_mode, 'latlon' ); ?> value="latlon" onclick="advads_geo_admin.set_mode(<?php echo $index; ?>, this.value);">
<?php // phpcs:enable ?>
<label for="radio_latlon_<?php echo esc_attr( $index ); ?>"><?php esc_html_e( 'by radius', 'advanced-ads-pro' ); ?></label>
</span>
</div>
<div class="geomode" id="advads_geo_classic_<?php echo esc_attr( $index ); ?>"
<?php
if ( 'classic' !== $geo_mode ) {
echo ' style="display:none;"';
}
?>
>
<select name="<?php echo esc_attr( $name ); ?>[operator]">
<option value="is" <?php selected( 'is', $operator ); ?>><?php esc_html_e( 'is', 'advanced-ads-pro' ); ?></option>
<option value="is_not" <?php selected( 'is_not', $operator ); ?>><?php esc_html_e( 'is not', 'advanced-ads-pro' ); ?></option>
</select>
<?php
switch ( $method ) :
case 'sucuri':
$country = isset( $options['country'] ) ? $options['country'] : $my_country_iso_code;
?>
<div class="advads-conditions-select-wrap"><select name="<?php echo esc_attr( $name ); ?>[country]"><?php foreach ( $countries as $_code => $_title ) : ?>
<option value="<?php echo esc_attr( $_code ); ?>" <?php selected( $_code, $country ); ?>><?php echo esc_html( $_title ); ?></option>
<?php
endforeach;
?>
</select></div>
<?php
break;
default:
$country = isset( $options['country'] ) ? $options['country'] : $my_country_iso_code;
$region = isset( $options['region'] ) ? $options['region'] : '';
$city = isset( $options['city'] ) ? $options['city'] : '';
?>
<div class="advads-conditions-select-wrap"><select name="<?php echo esc_attr( $name ); ?>[country]"><?php foreach ( $countries as $_code => $_title ) : ?>
<option value="<?php echo esc_attr( $_code ); ?>" <?php selected( $_code, $country ); ?>><?php echo esc_html( $_title ); ?></option>
<?php endforeach; ?>
</select></div> <?php esc_html_e( 'or', 'advanced-ads-pro' ); ?>
<input type="text" name="<?php echo esc_attr( $name ); ?>[region]" value="<?php echo esc_attr( $region ); ?>" placeholder="<?php esc_html_e( 'State/Region', 'advanced-ads-pro' ); ?>"/>
<?php esc_html_e( 'or', 'advanced-ads-pro' ); ?>
<input type="text" name="<?php echo esc_attr( $name ); ?>[city]" value="<?php echo esc_attr( $city ); ?>" placeholder="<?php esc_html_e( 'City', 'advanced-ads-pro' ); ?>"/>
<?php
break;
endswitch;
?>
</div>
<div id="advads_geo_latlon_<?php echo esc_attr( $index ); ?>"
<?php
if ( 'latlon' !== $geo_mode ) {
echo ' style="display:none;"';
}
?>
>
<?php
switch ( $method ) :
case 'sucuri':
esc_html_e( 'This option cant be used if your site is using sucuri.net.', 'advanced-ads-pro' );
break;
default:
$lat = isset( $options['lat'] ) ? $options['lat'] : '';
$lon = isset( $options['lon'] ) ? $options['lon'] : '';
$distance = isset( $options['distance'] ) ? $options['distance'] : '';
$distance_condition = isset( $options['distance_condition'] ) ? $options['distance_condition'] : '';
$distance_unit = isset( $options['distance_unit'] ) ? $options['distance_unit'] : '';
?>
<select name="<?php echo esc_attr( $name ); ?>[distance_condition]">
<option value="lte" <?php selected( $distance_condition, 'lte' ); ?>><?php esc_html_e( 'Distance is less than or equal to', 'advanced-ads-pro' ); ?></option>
<option value="gt" <?php selected( $distance_condition, 'gt' ); ?>><?php esc_html_e( 'Distance is greater than', 'advanced-ads-pro' ); ?></option>
</select>
<input type="number" name="<?php echo esc_attr( $name ); ?>[distance]" maxlength="8" style="width:80pt;" value="<?php echo esc_attr( $distance ); ?>" placeholder="<?php esc_attr_e( 'Distance', 'advanced-ads-pro' ); ?>"/>
<select name="<?php echo esc_attr( $name ); ?>[distance_unit]">
<option value="km" <?php selected( $distance_unit, 'km' ); ?>><?php esc_html_e( 'kilometers (km)', 'advanced-ads-pro' ); ?></option>
<option value="mi" <?php selected( $distance_unit, 'mi' ); ?>><?php esc_html_e( 'miles (mi)', 'advanced-ads-pro' ); ?></option>
</select><br/><?php esc_html_e( 'from', 'advanced-ads-pro' ); ?><br/>
<?php // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<button type="button" class="button" onclick="advads_geo_admin.click_locname(<?php echo $index; ?>)"><?php esc_html_e( 'get coordinates', 'advanced-ads-pro' ); ?></button>
<?php // phpcs:enable ?>
<input type="number" step="any" id="advads_geo_input_lat_<?php echo esc_attr( $index ); ?>" style="width:80pt; text-align:right;" name="<?php echo esc_attr( $name ); ?>[lat]" value="<?php echo esc_attr( $lat ); ?>" placeholder="<?php esc_attr_e( 'Latitude', 'advanced-ads-pro' ); ?>" title="<?php esc_attr_e( 'Latitude', 'advanced-ads-pro' ); ?>"/> /
<input type="number" step="any" id="advads_geo_input_lon_<?php echo esc_attr( $index ); ?>" style="width:80pt; text-align:right;" name="<?php echo esc_attr( $name ); ?>[lon]" value="<?php echo esc_attr( $lon ); ?>" placeholder="<?php esc_attr_e( 'Longitude', 'advanced-ads-pro' ); ?>" title="<?php esc_attr_e( 'Longitude', 'advanced-ads-pro' ); ?>"/>
<br>
<?php
if ( '' !== $lat && '' !== $lon && $my_lat && $my_lon ) {
$distance = Advanced_Ads_Geo::calculate_distance( $my_lat, $my_lon, $lat, $lon, $distance_unit );
$current_location .= '<br/>' . esc_html__( 'Distance to center', 'advanced-ads-pro' ) . ' ( ' . $lat . ' / ' . $lon . ' ): ' . round( $distance, 1 ) . ' ' . $distance_unit;
}
break;
endswitch;
?>
</div>
<?php
$latlon_city = isset( $options['latlon_city'] ) ? $options['latlon_city'] : '';
?>
<div id="advads_geo_latlon_by_city_<?php echo esc_attr( $index ); ?>" style="display: none; margin:3pt; padding:3pt;">
<input id="advads_geo_input_search_city_<?php echo esc_attr( $index ); ?>" type="text" name="<?php echo esc_attr( $name ); ?>[latlon_city]" value="<?php echo esc_attr( $latlon_city ); ?>" placeholder="<?php esc_attr_e( 'City', 'advanced-ads-pro' ); ?>">
<?php // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<button type="button" class="button button-primary" onclick="advads_geo_admin.search_loc(<?php echo $index; ?>)"><?php esc_html_e( 'Search', 'advanced-ads-pro' ); ?></button>
<button type="button" class="button" onclick="advads_geo_admin.search_loc_close(<?php echo $index; ?>)"><?php esc_html_e( 'Cancel', 'advanced-ads-pro' ); ?></button>
<?php // phpcs:enable ?>
<p class="description"><?php esc_html_e( 'Enter the name of the city, click the search button and pick one of the results to set the coordinates of the center.', 'advanced-ads-pro' ); ?></p>
<div id="advads_geo_latlon_loading_<?php echo esc_attr( $index ); ?>" class="spinner is-active" style="display:none; float: none;"></div>
<div id="advads_geo_latlon_results_<?php echo esc_attr( $index ); ?>"></div>
</div>
<p class="description">
<?php echo esc_html( $type_options[ $options['type'] ]['description'] ); ?>
<a href="https://wpadvancedads.com/manual/geo-targeting-condition/?utm_source=advanced-ads&utm_medium=link&utm_campaign=condition-geo-location" class="advads-manual-link" target="_blank">
<?php esc_html_e( 'Manual', 'advanced-ads-pro' ); ?>
</a>
</p>
<div class="description">
<p>
<strong><?php esc_html_e( 'Location based on your IP address', 'advanced-ads-pro' ); ?>:</strong>
<br>
<?php
echo wp_kses(
$current_location,
[
'br' => [],
'span' => [ 'class' => true ],
'a' => [
'href' => true,
'target' => true,
],
]
);
?>
</p>
<?php $this->render_visitor_profile_information( $my_lat, $my_lon ); ?>
</div>
<?php
}
/**
* Download database
*
* @since 1.0.0
*/
public function download_database() {
check_ajax_referer( 'advanced-ads-admin-ajax-nonce', 'nonce' );
if ( ! Conditional::user_can( 'advanced_ads_manage_options' ) ) {
wp_send_json_error( __( 'You are not allowed to do this.', 'advanced-ads-pro' ), 400 );
}
$upload_full = Advanced_Ads_Geo_Plugin::get_instance()->get_upload_full();
if ( ! $upload_full ) {
wp_send_json_error( __( 'The upload dir is not available', 'advanced-ads-pro' ), 400 );
}
$license_key = sanitize_text_field( wp_unslash( Params::request( 'license_key', '' ) ) );
if ( empty( $license_key ) ) {
wp_send_json_error( __( 'Please provide a MaxMind license key', 'advanced-ads-pro' ), 400 );
}
$file_prefix = Advanced_Ads_Geo_Plugin::get_maxmind_file_prefix();
if ( '' === $file_prefix ) {
$file_prefix = $this->create_new_prefix();
$this->remove_obsolete_files();
}
// download source.
$download_urls = [
'city' => 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&suffix=tar.gz&license_key=' . $license_key,
'country' => 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&suffix=tar.gz&license_key=' . $license_key,
];
// Paths where we will save files.
$filepaths = [
'city' => $upload_full . $file_prefix . '-GeoLite2-City.mmdb',
'country' => $upload_full . $file_prefix . '-GeoLite2-Country.mmdb',
];
// Names in the `tar.gz` archives.
$filenames_in_archive = [
'city' => 'GeoLite2-City.mmdb',
'country' => 'GeoLite2-Country.mmdb',
];
// create upload directory if not exists yet.
if ( ! file_exists( $upload_full ) ) {
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_mkdir
mkdir( $upload_full );
// phpcs:enable
}
// Prevent directory listing.
if ( ! file_exists( $upload_full . 'index.html' ) ) {
// phpcs:disable WordPress.WP.AlternativeFunctions,WordPress.PHP.NoSilencedErrors.Discouraged
$handle = @fopen( $upload_full . 'index.html', 'w' );
fwrite( $handle, '' );
fclose( $handle );
// phpcs:enable
}
if ( function_exists( 'wp_raise_memory_limit' ) ) {
wp_raise_memory_limit();
}
$this->maybe_replace_tmp_dir();
foreach ( $download_urls as $key => $download_url ) {
// variable with the name of the database file to download.
$db_file = $filepaths[ $key ];
$filename = $filenames_in_archive[ $key ];
$result = $this->download_geolite2_database( $download_url, $db_file, $filename );
if ( ! isset( $result['state'] ) || ! $result['state'] ) {
wp_send_json_error( $result['message'], 400 );
}
}
// save geo options on db update.
$pro_plugin = Advanced_Ads_Pro::get_instance();
$pro_options = $pro_plugin->get_options();
if ( ! array_key_exists( Advanced_Ads_Geo_Plugin::OPTIONS_SLUG, $pro_options ) ) {
$pro_options[ Advanced_Ads_Geo_Plugin::OPTIONS_SLUG ] = [];
}
$pro_options[ Advanced_Ads_Geo_Plugin::OPTIONS_SLUG ]['maxmind-license-key'] = $license_key;
$pro_options[ Advanced_Ads_Geo_Plugin::OPTIONS_SLUG ]['locale'] = sanitize_text_field( wp_unslash( Params::request( 'locale', '' ) ) );
$pro_plugin->update_options( $pro_options );
update_option( ADVADS_SLUG . '-' . Advanced_Ads_Geo_Plugin::OPTIONS_SLUG . '-last-update-geolite2', time() );
wp_send_json_success( __( 'Database updated successfully!', 'advanced-ads-pro' ) );
}
/**
* Download GeoLite2 databases
*
* @param string $download_url The download url.
* @param string $db_file The target file.
* @param string $filename The target filename in the archive.
*
* @return array
*/
private function download_geolite2_database( $download_url, $db_file, $filename ) {
// download the file from MaxMind, this places into temporary location.
$temp_file = download_url( $download_url );
$result['state'] = false;
$result['message'] = __( 'Database update failed', 'advanced-ads-pro' );
// If we failed, through a message, otherwise proceed.
if ( is_wp_error( $temp_file ) ) {
$error_code = $temp_file->get_error_data()['code'] ?? '';
$error_body = $temp_file->get_error_data()['body'] ?? '';
$result['message'] = sprintf(
/* translators: 1: The download URL, 2: The HTTP error code, 3: The HTTP header title, 4: The response body */
__( 'Error downloading database from: %1$s - %2$s %3$s - %4$s', 'advanced-ads-pro' ),
wp_parse_url( $download_url, PHP_URL_HOST ), // Do not expose the license key from query string.
$error_code,
$temp_file->get_error_message(),
$error_body
);
error_log( 'Advanced Ads Geo: ' . $result['message'] ); // phpcs:ignore
} else {
// The dir where the archive was downloaded.
$temp_file_dir = dirname( $temp_file );
try {
$archive = new PharData( $temp_file );
// The dir extracted from the archive.
$extracted_dir = trailingslashit( $archive->current()->getFilename() );
// Full path to the dir extracted from the archive.
$extracted_dir_full = trailingslashit( $temp_file_dir ) . $extracted_dir;
$archive->extractTo(
$temp_file_dir,
$extracted_dir . $filename,
true
);
} catch ( Exception $e ) {
$result['message'] = sprintf(
/* translators: an error mesage. */
esc_html__( 'Could not open downloaded database for reading: %s', 'advanced-ads-pro' ),
$temp_file . ', ' . $e->getMessage()
);
error_log( 'Advanced Ads Geo: ' . $result['message'] ); // phpcs:ignore
return $result;
} finally {
wp_delete_file( $temp_file );
}
add_filter( 'filesystem_method', [ $this, 'set_direct_filesystem_method' ] );
WP_Filesystem();
global $wp_filesystem;
if ( ! isset( $wp_filesystem->method ) || 'direct' !== $wp_filesystem->method ) {
$result['message'] = __( 'Could not access filesystem', 'advanced-ads-pro' );
error_log( 'Advanced Ads Geo: ' . $result['message'] ); // phpcs:ignore
return $result;
}
// Move the file.
$renamed = $wp_filesystem->move( $extracted_dir_full . $filename, $db_file, true );
$wp_filesystem->delete( $extracted_dir_full, false, 'd' );
if ( ! $renamed ) {
/* translators: MaxMind database file name. */
$result['message'] = sprintf( __( 'Could not open database for writing %s', 'advanced-ads-pro' ), $db_file );
// Remove corrupted file.
$wp_filesystem->delete( $db_file, false, 'f' );
} else {
$result['message'] = '';
$result['state'] = true;
}
remove_filter( 'filesystem_method', [ $this, 'set_direct_filesystem_method' ] );
}
return $result;
}
/**
* Get timestamp of the next first Tuesday of a month (either this month or the next)
*
* @param string $time timestamp from which to get the next available Tuesday.
*
* @return int of the next Tuesday (midnight GMT)
* @since 1.0.0
*/
public function get_next_first_tuesday_timestamp( $time = 0 ) {
// we actually use Wednesday since it returns midnight.
if ( ! $time ) {
$time = time();
}
// current month.
// phpcs:disable WordPress.DateTime.RestrictedFunctions.date_date
$month = date( 'F', $time );
$year = date( 'Y', $time );
$next_tuesday_t = strtotime( "first Wednesday of $month $year" );
// if this is the past, get first Tuesday of next month.
if ( $next_tuesday_t < time() ) {
$next_month_t = strtotime( 'next month' );
$month = date( 'F', $next_month_t );
$year = date( 'Y', $next_month_t );
$next_tuesday_t = strtotime( "first Tuesday of $month $year" );
}
// phpcs:enable
return $next_tuesday_t;
}
/**
* Check if the databases are working
*/
public function check_database() {
$api = Advanced_Ads_Geo_Api::get_instance();
return $api->get_geo_lite_country_filename() && $api->get_geo_lite_city_filename();
}
/**
* Check if an updated version of the database might already be available
* we use the timestamp of the last update that actually happened and check,
* if the next first Tuesday of a month that followed is already in the past
*
* @return bool true, if update should be available
* @since 1.0.0
*/
public function is_update_available() {
// check if database is available.
if ( ! $this->check_database() ) {
return true;
}
// current time.
$now_t = time();
// get last update from the database.
$last_update_t = get_option( ADVADS_SLUG . '-' . Advanced_Ads_Geo_Plugin::OPTIONS_SLUG . '-last-update-geolite2', $now_t );
// return true, if last update is more than 31 days ago.
$month_in_seconds = 31 * DAY_IN_SECONDS;
if ( $month_in_seconds <= $now_t - $last_update_t ) {
return true;
}
// get next Tuesday following the update.
$next_tuesday_t = $this->get_next_first_tuesday_timestamp( $last_update_t );
if ( $next_tuesday_t < $now_t ) {
return true;
}
return false;
}
/**
* Check if license is valid
*
* @return bool true if license is valid
* @since 1.0.0
*/
public function license_valid() {
$status = Advanced_Ads_Admin_Licenses::get_instance()->get_license_status( 'advanced-ads-geo' );
if ( 'valid' === $status ) {
return true;
}
return false;
}
/**
* Register and enqueue admin-specific scripts.
*
* @return void
*/
public function enqueue_admin_scripts() {
if ( ! Conditional::is_screen_advanced_ads() ) {
return;
}
$handle = ADVADS_SLUG . '-' . Advanced_Ads_Geo_Plugin::OPTIONS_SLUG . '-admin-script';
wp_enqueue_script( $handle, plugin_dir_url( __FILE__ ) . '../admin/assets/admin.js', [], AAP_VERSION, true );
wp_localize_script(
$handle,
'advads_geo_translation',
[
/* translators: 1: The number of search results. */
'found_results' => __( 'Found %1$d results. Please pick the one, you want to use.', 'advanced-ads-pro' ),
'no_results' => __( 'Your search did not return any results.', 'advanced-ads-pro' ),
'could_not_retrieve_city' => __( 'There was an error connecting to the search service.', 'advanced-ads-pro' ),
/* translators: 1: A link to the geo location service. */
'manual_geo_search' => sprintf( __( 'You can search for the geo coordinates manually at %1$s.', 'advanced-ads-pro' ), '<a href="https://nominatim.openstreetmap.org/">nominatim.openstreetmap.org</a>' ),
'COOKIEPATH' => COOKIEPATH,
'COOKIE_DOMAIN' => COOKIE_DOMAIN,
'nonce' => wp_create_nonce( 'advanced-ads-admin-ajax-nonce' ),
]
);
}
/**
* As per MaxMind TOS, databases should not be puclicly accessible. Create a random prefix for that.
*/
private function create_new_prefix() {
$new_prefix = wp_generate_password( 32, false );
update_option( 'advanced-ads-geo-maxmind-file-prefix', $new_prefix );
return $new_prefix;
}
/**
* Remove files prefixed with an obsolete prefix.
*/
public function remove_obsolete_files() {
require_once ABSPATH . 'wp-admin/includes/file.php';
add_filter( 'filesystem_method', [ $this, 'set_direct_filesystem_method' ] );
WP_Filesystem();
global $wp_filesystem;
if ( ! isset( $wp_filesystem->method ) || 'direct' !== $wp_filesystem->method ) {
return;
}
$upload_full = Advanced_Ads_Geo_Plugin::get_instance()->get_upload_full();
if ( ! $upload_full ) {
return;
}
$files = $wp_filesystem->dirlist( $upload_full );
if ( ! $files ) {
return;
}
foreach ( $files as $file ) {
if ( preg_match( '/GeoLite2-.*?\.mmdb$/', $file['name'] )
|| 'tmp-' === substr( $file['name'], 0, 4 )
) {
$wp_filesystem->delete( $upload_full . $file['name'] );
}
}
remove_filter( 'filesystem_method', [ $this, 'set_direct_filesystem_method' ] );
}
/**
* Set direct filesystem method.
*/
public function set_direct_filesystem_method() {
return 'direct';
}
/**
* Create a new tmp dir inside the upload dir if the existing one does not contain enought space.
*/
private function maybe_replace_tmp_dir() {
if ( defined( 'WP_TEMP_DIR' ) ) {
return;
}
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
$available_tmp_space = @disk_free_space( get_temp_dir() );
// We need > 200 MB.
if ( ! $available_tmp_space || ( $available_tmp_space / MB_IN_BYTES ) < 200 ) {
$tmp_dir = Advanced_Ads_Geo_Plugin::get_instance()->get_upload_full()
. 'tmp-'
. Advanced_Ads_Geo_Plugin::get_maxmind_file_prefix();
if ( ! file_exists( $tmp_dir ) ) {
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir,WordPress.PHP.NoSilencedErrors.Discouraged
@mkdir( $tmp_dir );
}
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
if ( @is_dir( $tmp_dir ) && wp_is_writable( $tmp_dir ) ) {
define( 'WP_TEMP_DIR', $tmp_dir );
}
}
}
/**
* Render a table with the current visitor profile cookie information if available.
*
* @param float $lat User's latitude.
* @param float $lon User's longitude.
*
* @return void
*/
private function render_visitor_profile_information( $lat, $lon ) {
$visitor_profile = new Advanced_Ads_Geo_Visitor_Profile();
if ( $visitor_profile->has_visitor_profile && $visitor_profile->is_different_from_current_location( $lat, $lon ) ) {
require $this->views_path . '/visitor-profile.php';
}
}
/**
* Check if custom database files are used via filters
*
* @return bool
*/
private function is_using_custom_database() {
$api = Advanced_Ads_Geo_Api::get_instance();
return has_filter( 'advanced-ads-geo-maxmind-geolite2-country-db-filepath' )
&& has_filter( 'advanced-ads-geo-maxmind-geolite2-city-db-filepath' )
&& $api->get_geo_ip2_city_reader()
&& $api->get_geo_ip2_country_reader();
}
}