public function add_settings_field($field, $section, $option_slug, $option_name, $options, $callback, $str_path, $str_last)
 {
     $dir = $this->get_db_dir();
     add_settings_field($option_name . "_{$field}_ipv4", "{$field} {$str_path} (IPv4)", $callback, $option_slug, $section, array('type' => 'text', 'option' => $option_name, 'field' => $field, 'sub-field' => 'ipv4_path', 'value' => $dir . IP_GEO_BLOCK_MAXMIND_IPV4_DAT, 'disabled' => TRUE, 'after' => '<br /><p id="ip_geo_block_' . $field . '_ipv4" style="margin-left: 0.2em">' . sprintf($str_last, ip_geo_block_localdate($options[$field]['ipv4_last'])) . '</p>'));
     add_settings_field($option_name . "_{$field}_ipv6", "{$field} {$str_path} (IPv6)", $callback, $option_slug, $section, array('type' => 'text', 'option' => $option_name, 'field' => $field, 'sub-field' => 'ipv6_path', 'value' => $dir . IP_GEO_BLOCK_MAXMIND_IPV6_DAT, 'disabled' => TRUE, 'after' => '<br /><p id="ip_geo_block_' . $field . '_ipv6" style="margin-left: 0.2em">' . sprintf($str_last, ip_geo_block_localdate($options[$field]['ipv6_last'])) . '</p>'));
 }
/**
 * Download zip file, uncompress and save it to specified file
 *
 * @param string $url URL of remote file to be downloaded.
 * @param array $args request headers.
 * @param string $filename full path to the downloaded file.
 * @param int $modified time of last modified on the remote server.
 * @return array status message.
 */
function ip_geo_block_download_zip($url, $args, $filename, $modified)
{
    // check file
    if (!file_exists($filename)) {
        $modified = 0;
    }
    // set 'If-Modified-Since' request header
    $args += array('headers' => array('If-Modified-Since' => gmdate(DATE_RFC1123, (int) $modified)));
    // fetch file and get response code & message
    $res = wp_remote_head($url = esc_url_raw($url), $args);
    if (is_wp_error($res)) {
        return array('code' => $res->get_error_code(), 'message' => $res->get_error_message());
    }
    $code = wp_remote_retrieve_response_code($res);
    $mssg = wp_remote_retrieve_response_message($res);
    $data = wp_remote_retrieve_header($res, 'last-modified');
    $modified = $data ? strtotime($data) : $modified;
    if (304 == $code) {
        return array('code' => $code, 'message' => __('Your database file is up-to-date.', IP_Geo_Block::TEXT_DOMAIN), 'filename' => $filename, 'modified' => $modified);
    } elseif (200 != $code) {
        return array('code' => $code, 'message' => "{$code} {$mssg}");
    }
    // downloaded and unzip
    try {
        // download file
        $res = download_url($url);
        if (is_wp_error($res)) {
            throw new Exception($res->get_error_code() . ' ' . $res->get_error_message());
        }
        // get extension
        $args = strtolower(pathinfo($url, PATHINFO_EXTENSION));
        // unzip file
        if ('gz' === $args && function_exists('gzopen')) {
            if (FALSE === ($gz = gzopen($res, 'r'))) {
                throw new Exception(sprintf(__('Cannot open %s to read. Please check permission.', IP_Geo_Block::TEXT_DOMAIN), $res));
            }
            if (FALSE === ($fp = fopen($filename, 'wb'))) {
                throw new Exception(sprintf(__('Cannot open %s to write. Please check permission.', IP_Geo_Block::TEXT_DOMAIN), $filename));
            }
            // same block size in wp-includes/class-http.php
            while ($data = gzread($gz, 4096)) {
                fwrite($fp, $data, strlen($data));
            }
            gzclose($gz);
            fclose($fp);
        } elseif ('zip' === $args && class_exists('ZipArchive')) {
            $zip = new ZipArchive();
            if (TRUE === $zip->open($res)) {
                $zip->extractTo(dirname($filename));
                $zip->close();
            } else {
                throw new Exception(sprintf(__('Failed to open %s. Please check permission.', IP_Geo_Block::TEXT_DOMAIN), $res));
            }
        }
        @unlink($res);
    } catch (Exception $e) {
        if ('gz' === $args && function_exists('gzopen')) {
            !empty($gz) && gzclose($gz);
            !empty($fp) && fclose($fp);
        }
        !is_wp_error($res) && @unlink($res);
        return array('code' => $e->getCode(), 'message' => $e->getMessage());
    }
    return array('code' => $code, 'message' => sprintf(__('Last update: %s', IP_Geo_Block::TEXT_DOMAIN), ip_geo_block_localdate($modified)), 'filename' => $filename, 'modified' => $modified);
}
 /**
  * Ajax callback function
  *
  * @link http://codex.wordpress.org/AJAX_in_Plugins
  * @link http://codex.wordpress.org/Function_Reference/check_ajax_referer
  * @link http://core.trac.wordpress.org/browser/trunk/wp-admin/admin-ajax.php
  */
 public function admin_ajax_callback()
 {
     // Check request origin, nonce, capability.
     if (!check_admin_referer($this->get_ajax_action(), 'nonce') || !current_user_can('manage_options') || empty($_POST)) {
         // @since 2.0
         status_header(403);
         // Forbidden @since 2.0.0
     }
     $which = isset($_POST['which']) ? $_POST['which'] : NULL;
     switch (isset($_POST['cmd']) ? $_POST['cmd'] : NULL) {
         case 'download':
             $res = IP_Geo_Block::download_database();
             break;
         case 'search':
             require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-apis.php';
             // check format
             if (filter_var($ip = $_POST['ip'], FILTER_VALIDATE_IP)) {
                 // get option settings and compose request headers
                 $options = IP_Geo_Block::get_option('settings');
                 $args = IP_Geo_Block::get_request_headers($options);
                 // create object for provider and get location
                 if ($geo = IP_Geo_Block_API::get_instance($which, $options)) {
                     $res = $geo->get_location($ip, $args);
                 } else {
                     $res = array('errorMessage' => 'Unknown service.');
                 }
             } else {
                 $res = array('errorMessage' => 'Invalid IP address.');
             }
             break;
         case 'scan-code':
             require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-apis.php';
             // scan all the country code using selected APIs
             $ip = IP_Geo_Block::get_ip_address();
             $options = IP_Geo_Block::get_option('settings');
             $args = IP_Geo_Block::get_request_headers($options);
             $type = IP_Geo_Block_Provider::get_providers('type', FALSE, FALSE);
             $providers = IP_Geo_Block_Provider::get_valid_providers($options['providers'], FALSE, FALSE);
             $res['IP address'] = esc_html($ip);
             foreach ($providers as $provider) {
                 if ($geo = IP_Geo_Block_API::get_instance($provider, $options)) {
                     $ret = $geo->get_location($ip, $args);
                     $res[$provider] = array('type' => $type[$provider], 'code' => esc_html(FALSE === $ret ? __('n/a', IP_Geo_Block::TEXT_DOMAIN) : (!empty($ret['errorMessage']) ? $ret['errorMessage'] : (!empty($ret['countryCode']) ? $ret['countryCode'] : __('UNKNOWN', IP_Geo_Block::TEXT_DOMAIN)))));
                 }
             }
             break;
         case 'clear-statistics':
             // set default values
             update_option($this->option_name['statistics'], IP_Geo_Block::get_default('statistics'));
             $res = array('page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_SLUG, 'tab' => 'tab=1');
             break;
         case 'clear-cache':
             // delete cache of IP address
             delete_transient(IP_Geo_Block::CACHE_KEY);
             // @since 2.8
             $res = array('page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_SLUG, 'tab' => 'tab=1');
             break;
         case 'clear-logs':
             require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-logs.php';
             $hook = array('comment', 'login', 'admin', 'xmlrpc');
             $which = in_array($which, $hook) ? $which : NULL;
             IP_Geo_Block_Logs::clean_log($which);
             $res = array('page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_SLUG, 'tab' => 'tab=4');
             break;
         case 'restore':
             require_once IP_GEO_BLOCK_PATH . 'includes/localdate.php';
             require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-logs.php';
             // if js is slow then limit the number of rows
             $limit = IP_Geo_Block_Logs::limit_rows(@$_POST['time']);
             // compose html with sanitization
             $which = IP_Geo_Block_Logs::restore_log($which);
             foreach ($which as $hook => $rows) {
                 $html = '';
                 $n = 0;
                 foreach ($rows as $logs) {
                     $log = (int) array_shift($logs);
                     $html .= "<tr><td data-value={$log}>";
                     $html .= ip_geo_block_localdate($log, 'Y-m-d H:i:s') . "</td>";
                     foreach ($logs as $log) {
                         $log = esc_html($log);
                         $html .= "<td>{$log}</td>";
                     }
                     $html .= "</tr>";
                     if (++$n >= $limit) {
                         break;
                     }
                 }
                 $res[$hook] = $html;
             }
             break;
         case 'create_table':
         case 'delete_table':
             require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-logs.php';
             if ('create_table' === $_POST['cmd']) {
                 IP_Geo_Block_Logs::create_log();
             } else {
                 IP_Geo_Block_Logs::delete_log();
             }
             $res = array('page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_SLUG);
     }
     if (isset($res)) {
         // wp_send_json_{success,error}() @since 3.5.0
         wp_send_json($res);
     }
     // @since 3.5.0
     die;
     // End of ajax
 }