plugins/geo/modules/yf_geo_content.class.php

Summary

Maintainability
F
6 days
Test Coverage
<?php

// Content display by geo location (ads, pages, etc)
class yf_geo_content
{
    // TODO: need to connect here in all methods where needed
    /** @var bool */
    public $AJAX_USE_CACHE = false;

    // Default method
    public function show()
    {
        return $this->change_location();
    }

    // JavaScript - based city select (3-step) method
    public function _city_select($params = [])
    {
        $STPL_NAME = 'register/city_select';
        if ( ! empty($params['stpl_name'])) {
            $STPL_NAME = $params['stpl_name'];
        }
        // Prepare default values
        if ( ! isset($_POST['country'])) {
            $_POST['country'] = $params['sel_country'];
        }
        if ( ! isset($_POST['region'])) {
            $_POST['region'] = $params['sel_region'];
        }
        if ( ! isset($_POST['city'])) {
            $_POST['city'] = $params['sel_city'];
        }
        // Fill array of countries
        $_countries = main()->get_data('countries');
        // Process featured countries if needed
        if (FEATURED_COUNTRY_SELECT == 1) {
            $_featured_countries = main()->get_data('featured_countries');
            if ( ! empty($_featured_countries)) {
                $_countries = array_merge(['  ' => '  '], $_featured_countries, $_countries);
            }
        }
        // Get regions and cities for selected
        if ( ! empty($_POST['country'])) {
            $_regions[''] = '  --   Please select region   --  ';
            $Q = db()->query(
                'SELECT * 
                FROM ' . db('geo_regions') . " 
                WHERE country = '" . _es($_POST['country']) . "' 
                ORDER BY name ASC"
            );
            while ($A = db()->fetch_assoc($Q)) {
                $_regions[$A['code']] = $A['name'];
            }
            // Maybe country without regions ?
            if (count((array) $_regions) == 1) {
                $have_no_regions = true;
            }
            // Get cities list
            if (strlen($_POST['region'])) {
                $_cities[''] = '  --   Please select city   --  ';
                $Q = db()->query(
                    'SELECT * 
                    FROM ' . db('geo_city_location') . " 
                    WHERE region = '" . _es($_POST['region']) . "' 
                        AND country = '" . _es($_POST['country']) . "' 
                        AND city != ''
                    GROUP BY city
                    ORDER BY city ASC"
                );
                while ($A = db()->fetch_assoc($Q)) {
                    $_cities[$A['city']] = $A['city'];
                }
            }
        }
        // Prepare template
        $replace = [
            'country_box' => common()->select_box('country', $_countries, $_POST['country'], false, 2, '', false),
            'region_box' => common()->select_box('region', $_regions, $_POST['region'], false, 2, '', false),
            'city_box' => common()->select_box('city', $_cities, $_POST['city'], false, 2, '', false),
            'sel_country' => $_POST['country'],
            'sel_region' => $_POST['region'],
            'sel_city' => $_POST['city'],
            'ajax_link' => process_url('./?object=' . 'geo_content' . '&action=ajax_city'),
            'sel_no_regions' => (int) $have_no_regions,
        ];
        return tpl()->parse($STPL_NAME, $replace);
    }

    // Get selected array
    public function ajax_city()
    {
        main()->NO_GRAPHICS = true;
        // Check input
        if (isset($_REQUEST['country'])) {
            // Process featured countries
            if (FEATURED_COUNTRY_SELECT && substr($_REQUEST['country'], 0, 2) == 'f_') {
                $_REQUEST['country'] = substr($_REQUEST['country'], 2);
            }
            if ( ! preg_match('/^[a-z]{2}$/i', $_REQUEST['country'])) {
                unset($_REQUEST['country']);
            }
        }
        if (isset($_REQUEST['region'])) {
            if ( ! preg_match('/^[a-z0-9]{2}$/i', $_REQUEST['region'])) {
                $_REQUEST['region'] = '';
            }
        }
        // Get Zip code
        if ( ! empty($_REQUEST['city']) && strlen($_REQUEST['region']) && strtoupper($_REQUEST['country']) == 'US') {
            $Q = db()->query(
                'SELECT postal_code 
                FROM ' . db('geo_city_location') . " 
                WHERE region = '" . _es($_REQUEST['region']) . "' 
                    AND country = '" . _es($_REQUEST['country']) . "' 
                    AND city = '" . _es($_REQUEST['city']) . "' 
                    AND postal_code != '' 
                GROUP BY postal_code 
                ORDER BY postal_code ASC"
            );
            while ($A = db()->fetch_assoc($Q)) {
                $body .= '<option value="' . _prepare_html($A['postal_code']) . '">' . _prepare_html($A['postal_code']) . "</option>\n";
            }
            if ( ! empty($body)) {
                $body = "<option name=\"\">  --   Please select zip code   --  </option>\n" . $body;
            }
            // Get city
        } elseif (strlen($_REQUEST['region']) && ! empty($_REQUEST['country'])) {
            if ($this->AJAX_USE_CACHE && main()->USE_SYSTEM_CACHE) {
                $CACHE_NAME = 'cities_' . $_REQUEST['country'] . '_' . $_REQUEST['region'];
                // TODO: need to add "_mkdir_m" in "sys_cahe->put" (to allow sub-folders "/" in cache names)
                $cities = main()->get_data($CACHE_NAME);
            }
            if (empty($cities)) {
                $Q = db()->query(
                    'SELECT * 
                    FROM ' . db('geo_city_location') . " 
                    WHERE region = '" . _es($_REQUEST['region']) . "' 
                        AND country = '" . _es($_REQUEST['country']) . "'
                        AND city != ''
                    GROUP BY city
                    ORDER BY city ASC"
                );
                while ($A = db()->fetch_assoc($Q)) {
                    $cities[$A['loc_id']] = $A['city'];
                }
                if ($this->AJAX_USE_CACHE && main()->USE_SYSTEM_CACHE) {
                    cache_set($CACHE_NAME, $cities);
                }
            }
            foreach ((array) $cities as $_city_name) {
                // We need UTF-8 here
                $city_utf8 = common()->_convert_charset($_city_name);
                if (strlen($city_utf8)) {
                    $_city_name = $city_utf8;
                }
                $body .= '<option value="' . _prepare_html($_city_name) . '">' . _prepare_html($_city_name) . "</option>\n";
            }
            if ( ! empty($body)) {
                $body = "<option name=\"\">  --   Please select city   --  </option>\n" . $body;
            }
            // Get region
        } elseif ( ! empty($_REQUEST['country'])) {
            $Q = db()->query(
                'SELECT * 
                FROM ' . db('geo_regions') . " 
                WHERE country = '" . _es($_REQUEST['country']) . "'
                ORDER BY name ASC"
            );
            while ($A = db()->fetch_assoc($Q)) {
                $body .= '<option value="' . $A['code'] . '">' . _prepare_html($A['name']) . "</option>\n";
            }
            if ( ! empty($body)) {
                $body = "<option name=\"\">  --   Please select region   --  </option>\n" . $body;
            }
        }
        echo $body;
    }

    // Change user location
    public function change_location()
    {
        if ( ! main()->USE_GEO_IP) {
            return false;
        }
        // Current system selected
        $sel_data = main()->_USER_GEO_DATA;
        // Detected by IP
        $cur_ip = common()->get_ip();
        $ip_data = common()->_get_geo_data_from_db($cur_ip);
        // Fill array of countries
        $_countries = main()->get_data('countries');
        // Process featured countries if needed
        if (FEATURED_COUNTRY_SELECT == 1) {
            $_featured_countries = main()->get_data('featured_countries');
            if ( ! empty($_featured_countries)) {
                $_countries = array_merge(['  ' => '  '], $_featured_countries, $_countries);
            }
        }
        // Get regions and cities for selected
        if ( ! empty($sel_data['country_code'])) {
            $_regions[''] = '  --   Please select region   --  ';
            $Q = db()->query(
                'SELECT * 
                FROM ' . db('geo_regions') . " 
                WHERE country = '" . _es($sel_data['country_code']) . "' 
                ORDER BY name ASC"
            );
            while ($A = db()->fetch_assoc($Q)) {
                $_regions[$A['code']] = $A['name'];
            }
            // Maybe country without regions ?
            if (count((array) $_regions) == 1) {
                $have_no_regions = true;
            }
            // Get cities list
            if (strlen($sel_data['region_code'])) {
                $_cities[''] = '  --   Please select city   --  ';
                $Q = db()->query(
                    'SELECT * 
                    FROM ' . db('geo_city_location') . " 
                    WHERE region = '" . _es($sel_data['region_code']) . "' 
                        AND country = '" . _es($sel_data['country_code']) . "' 
                        AND city != ''
                    GROUP BY city
                    ORDER BY city ASC"
                );
                while ($A = db()->fetch_assoc($Q)) {
                    $_cities[$A['city']] = $A['city'];
                }
            }
            // Get zip codes list
            if (strtoupper($sel_data['country_code']) == 'US' && strlen($sel_data['region_code']) && ! empty($sel_data['city_name']) && ! empty($sel_data['zip_code'])) {
                $_zip_codes[''] = '  --   Please select zip code   --  ';
                $Q = db()->query(
                    'SELECT postal_code 
                    FROM ' . db('geo_city_location') . " 
                    WHERE region = '" . _es($sel_data['region_code']) . "' 
                        AND country = '" . _es($sel_data['country_code']) . "' 
                        AND city = '" . _es($sel_data['city_name']) . "' 
                        AND postal_code != '' 
                    GROUP BY postal_code 
                    ORDER BY postal_code ASC"
                );
                while ($A = db()->fetch_assoc($Q)) {
                    $_zip_codes[$A['postal_code']] = $A['postal_code'];
                }
            }
        }
        // Check if user profile's city is in our db
        if ( ! empty($this->_user_info['country']) && strlen($this->_user_info['state']) && ! empty($this->_user_info['city'])) {
            $check_profile_city = db()->query_fetch(
                'SELECT * 
                FROM ' . db('geo_city_location') . " 
                WHERE region = '" . _es($this->_user_info['state']) . "' 
                    AND country = '" . _es($this->_user_info['country']) . "' 
                    AND city = '" . _es($this->_user_info['city']) . "' 
                LIMIT 1"
            );
            if (empty($check_profile_city)) {
                $this->_user_info['city'] = '';
            }
        }
        // Save data
        if (main()->is_post()) {
            // Update user info
            if (isset($_POST['update_2']) && main()->USER_ID && ! empty($_POST['update_profile']) && ! empty($sel_data['city_name'])) {
                if ($sel_data['country_code'] != $this->_user_info['country']
                    || $sel_data['region_code'] != $this->_user_info['state']
                    || strtolower($sel_data['city_name']) != strtolower($this->_user_info['city'])
                ) {
                    $sql_array = [
                        'country' => _es($sel_data['country_code']),
                        'state' => _es($sel_data['region_code']),
                    ];
                    if ( ! empty($sel_data['city_name'])) {
                        $sql_array['city'] = _es($sel_data['city_name']);
                    }
                    if ( ! empty($sel_data['zip_code']) && is_numeric($sel_data['zip_code'])) {
                        $sql_array['zip_code'] = _es($sel_data['zip_code']);
                    }
                    db()->update('user', $sql_array, main()->USER_ID);
                }
                return js_redirect('./?object=account');
            }
            // Update current geo location
            $something_changed = false;
            // Switch between selected
            if ($_POST['geo_type'] == 'by_ip') {
                $data_to_save = [
                    'country_code' => $ip_data['country_code'],
                    'country_name' => $ip_data['country_name'],
                    'region_code' => $ip_data['region_code'],
                    'city_name' => $ip_data['city_name'],
                    'longitude' => $ip_data['longitude'],
                    'latitude' => $ip_data['latitude'],
                    'zip_code' => strtoupper($ip_data['country_code']) == 'US' ? $ip_data['zip_code'] : '',
                ];
            } elseif ($_POST['geo_type'] == 'by_profile') {
                $data_to_save = [
                    'country_code' => $this->_user_info['country'],
                    'country_name' => _country_name($this->_user_info['country']),
                    'region_code' => $this->_user_info['state'],
                    'city_name' => $this->_user_info['city'],
                    'longitude' => $this->_user_info['lon'],
                    'latitude' => $this->_user_info['lat'],
                    'zip_code' => strtoupper($this->_user_info['country']) == 'US' ? $this->_user_info['zip_code'] : '',
                ];
            } elseif ($_POST['geo_type'] == 'by_other') {
                if (FEATURED_COUNTRY_SELECT == 1 && substr($_POST['country'], 0, 2) == 'f_') {
                    $_POST['country'] = substr($_REQUEST['country'], 2);
                }
                if (strtoupper($_POST['country']) != 'US') {
                    $_POST['zip_code'] = '';
                }
                if (false !== strpos(strtolower($_POST['city']), 'please select city')) {
                    $_POST['city'] = '';
                }
                // Check if city is in our db
                if ( ! empty($_POST['country']) && strlen($_POST['region']) && ! empty($_POST['city'])) {
                    $CITY_EXISTS = db()->query_fetch(
                        'SELECT * 
                        FROM ' . db('geo_city_location') . " 
                        WHERE country = '" . _es($_POST['country']) . "' 
                            AND region = '" . _es($_POST['region']) . "'
                            AND city = '" . _es($_POST['city']) . "'
                        LIMIT 1 "
                    );
                    if (empty($CITY_EXISTS)) {
                        $_POST['city'] = '';
                    }
                }
                $VERIFY_OK = false;
                // Get lon and lat for the given data (also verify posted data)
                if ( ! empty($_POST['country'])) {
                    // Check if we have country without known regions
                    list($have_regions) = db()->query_fetch(
                        'SELECT COUNT(*) AS `0` 
                        FROM ' . db('geo_regions') . " 
                        WHERE country='" . _es($_POST['country']) . "'"
                    );
                    if ($have_regions && strlen($_POST['region'])) {
                        $city_lon_lat = db()->query_fetch(
                            'SELECT * 
                            FROM ' . db('geo_city_location') . " 
                            WHERE country = '" . _es($_POST['country']) . "' 
                                AND region = '" . _es($_POST['region']) . "'
                                " . ( ! empty($_POST['city']) ? " AND city = '" . _es($_POST['city']) . "' " : '') . '
                                ' . ($_POST['zip_code'] ? " AND (postal_code='" . _es($_POST['zip_code']) . "' OR postal_code = '') " : '') . '
                            LIMIT 1 '
                        );
                    }
                    // Try to get lon and lat from region
                    if (empty($city_lon_lat)) {
                        $city_lon_lat = db()->query_fetch(
                            'SELECT * 
                            FROM ' . db('geo_city_location') . " 
                            WHERE country = '" . _es($_POST['country']) . "' 
                                " . (strlen($_POST['region']) ? " AND region = '" . _es($_POST['region']) . "' " : '') . '
                            LIMIT 1 '
                        );
                    }
                    if ( ! empty($city_lon_lat)) {
                        $lon = $city_lon_lat['longitude'];
                        $lat = $city_lon_lat['latitude'];
                        $VERIFY_OK = true;
                    }
                }
                if ($VERIFY_OK) {
                    $data_to_save = [
                        'country_code' => $_POST['country'],
                        'country_name' => _country_name($_POST['country']),
                        'region_code' => $_POST['region'],
                        'city_name' => $_POST['city'],
                        'longitude' => $lon,
                        'latitude' => $lat,
                        'zip_code' => strtoupper($_POST['country']) == 'US' ? $_POST['zip_code'] : '',
                    ];
                }
            }
            // Save preferences inside cookie
            if ( ! empty($data_to_save)) {
                if ( ! is_numeric($data_to_save['zip_code'])) {
                    $data_to_save['zip_code'] = '';
                }
                $result = setcookie('geo_selected', serialize($data_to_save), time() + 2592000, '/');
            }
            return js_redirect('./?object=' . 'geo_content' . '&action=change_location_result');
        }
        // Prepare template
        $replace = [
            'form_action' => './?object=' . 'geo_content' . '&action=' . __FUNCTION__,
            'ajax_link' => process_url('./?object=' . 'geo_content' . '&action=ajax_city'),

            'country_box' => common()->select_box('country', $_countries, $sel_data['country_code'], false, 2, '', false),
            'region_box' => common()->select_box('region', $_regions, $sel_data['region_code'], false, 2, '', false),
            'city_box' => common()->select_box('city', $_cities, $sel_data['city_name'], false, 2, '', false),
            'zip_box' => common()->select_box('zip_code', $_zip_codes, $sel_data['zip_code'], false, 2, '', false),

            'sel_country' => _prepare_html($sel_data['country_name']),
            'sel_country_code' => _prepare_html($sel_data['country_code']),
            'sel_region' => _prepare_html(_region_name($sel_data['region_code'], $sel_data['country_code'])),
            'sel_region_code' => _prepare_html($sel_data['region_code']),
            'sel_city' => _prepare_html($sel_data['city_name']),
            'sel_zip_code' => _prepare_html($sel_data['zip_code']),

            'ip_country' => _prepare_html($ip_data['country_name']),
            'ip_country_code' => _prepare_html($ip_data['country_code']),
            'ip_region' => _prepare_html(_region_name($ip_data['region_code'], $ip_data['country_code'])),
            'ip_region_code' => _prepare_html($ip_data['region_code']),
            'ip_city' => _prepare_html($ip_data['city_name']),
            'ip_zip_code' => _prepare_html($ip_data['zip_code']),

            'p_country' => $this->_user_info['country'] ? _prepare_html(_country_name($this->_user_info['country'])) : '',
            'p_country_code' => $this->_user_info['country'] ? _prepare_html($this->_user_info['country']) : '',
            'p_region' => $this->_user_info['state'] ? _prepare_html(_region_name($this->_user_info['state'], $this->_user_info['country'])) : '',
            'p_region_code' => $this->_user_info['state'] ? _prepare_html($this->_user_info['state']) : '',
            'p_city' => $this->_user_info['city'] ? _prepare_html($this->_user_info['city']) : '',
            'p_zip_code' => $this->_user_info['zip_code'] ? _prepare_html($this->_user_info['zip_code']) : '',

            'sel_by_cookie' => ! empty($sel_data) && $sel_data['_source'] == 'sel_cookie' ? 1 : 0,
            'sel_no_regions' => (int) $have_no_regions,
            'empty_selection' => empty($sel_data['country_code']) && empty($sel_data['region_code']) && empty($sel_data['city_name']) ? 1 : 0,
        ];
        return tpl()->parse('geo_content' . '/change_location_form', $replace);
    }

    // Change user location
    public function change_location_result()
    {
        if ( ! main()->USE_GEO_IP) {
            return false;
        }
        // Current system selected
        $sel_data = main()->_USER_GEO_DATA;
        if (empty($sel_data)) {
            return _e(t('Internal error #036. Please contact site admin.'));
        }
        // Check if something has changed
        if (main()->USER_ID && ! empty($sel_data)) {
            if (($sel_data['country_code'] && $sel_data['country_code'] != $this->_user_info['country'])
                || ($sel_data['region_code'] && $sel_data['region_code'] != $this->_user_info['state'])
                || ($sel_data['city_name'] && strtolower($sel_data['city_name']) != strtolower($this->_user_info['city']))
                || ($sel_data['zip_code'] && $sel_data['zip_code'] != $this->_user_info['zip_code'])
            ) {
                $something_changed = 1;
            }
        }
        // Prepare template
        $replace2 = [
            'form_action' => './?object=' . 'geo_content' . '&action=change_location',
            'show_update_form' => main()->USER_ID && $something_changed ? 1 : 0,
            'city' => _prepare_html($sel_data['city_name']),
            'region' => _prepare_html(_region_name($sel_data['region_code'], $sel_data['country_code'])),
            'country' => _prepare_html(_country_name($sel_data['country_code'])),
            'zip' => _prepare_html($sel_data['zip_code']),
        ];
        return tpl()->parse('geo_content' . '/change_location_success', $replace2);
    }
}