287 lines
8.3 KiB
PHP
287 lines
8.3 KiB
PHP
<?php
|
|
/**
|
|
* Copyright 1999-2016 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* See the enclosed file COPYING for license information (LGPL). If you
|
|
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
|
|
*
|
|
* @author Jon Parise <jon@horde.org>
|
|
* @author Chuck Hagenbuch <chuck@horde.org>
|
|
* @author Jan Schneider <jan@horde.org>
|
|
* @author Michael Slusarz <slusarz@horde.org>
|
|
* @category Horde
|
|
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
|
|
* @package Nls
|
|
*/
|
|
|
|
/**
|
|
* The Horde_Nls class provides Native Language Support.
|
|
*
|
|
* This includes common methods for handling language data, timezones, and
|
|
* hostname->country lookups.
|
|
*
|
|
* @author Jon Parise <jon@horde.org>
|
|
* @author Chuck Hagenbuch <chuck@horde.org>
|
|
* @author Jan Schneider <jan@horde.org>
|
|
* @author Michael Slusarz <slusarz@horde.org>
|
|
* @category Horde
|
|
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
|
|
* @package Nls
|
|
*/
|
|
class Horde_Nls
|
|
{
|
|
/**
|
|
* DNS resolver.
|
|
*
|
|
* @var Net_DNS2_Resolver
|
|
*/
|
|
public static $dnsResolver;
|
|
|
|
/**
|
|
* Cached values.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected static $_cache = array();
|
|
|
|
/**
|
|
* Check to see if character set is valid for htmlspecialchars() calls.
|
|
*
|
|
* @param string $charset The character set to check.
|
|
*
|
|
* @return boolean Is charset valid for the current system?
|
|
*/
|
|
public static function checkCharset($charset)
|
|
{
|
|
if (is_null($charset) || empty($charset)) {
|
|
return false;
|
|
}
|
|
|
|
$valid = true;
|
|
|
|
ini_set('track_errors', 1);
|
|
@htmlspecialchars('', ENT_COMPAT, $charset);
|
|
if (isset($php_errormsg)) {
|
|
$valid = false;
|
|
}
|
|
ini_restore('track_errors');
|
|
|
|
return $valid;
|
|
}
|
|
|
|
/**
|
|
* Returns a list of available timezones.
|
|
*
|
|
* @return array List of timezones.
|
|
*/
|
|
public static function getTimezones()
|
|
{
|
|
$timezones = DateTimeZone::listIdentifiers();
|
|
return array_combine($timezones, $timezones);
|
|
}
|
|
|
|
/**
|
|
* Returns a list of available timezones, including timezone abbreviations.
|
|
*
|
|
* Contrary to getTimezones() the timezone IDs are values and the timezone
|
|
* labels are the keys, to allow multiple labels for the same timezone.
|
|
*
|
|
* @since 2.2.0
|
|
*
|
|
* @return array List of timezones.
|
|
*/
|
|
public static function getTimezonesWithAbbreviations()
|
|
{
|
|
$timezones = array_flip(self::getTimezones());
|
|
foreach (DateTimeZone::listAbbreviations() as $abbreviation => $timezone) {
|
|
$abbreviation = Horde_String::upper($abbreviation);
|
|
if ($abbreviation == 'UTC' || strlen($abbreviation) < 2) {
|
|
continue;
|
|
}
|
|
$timezones[$abbreviation] = $timezone[0]['timezone_id'];
|
|
}
|
|
return $timezones;
|
|
}
|
|
|
|
/**
|
|
* Get the locale info returned by localeconv(), but cache it, to
|
|
* avoid repeated calls.
|
|
*
|
|
* @return array The results of localeconv().
|
|
*/
|
|
public static function getLocaleInfo()
|
|
{
|
|
if (!isset(self::$_cache['lc_info'])) {
|
|
self::$_cache['lc_info'] = localeconv();
|
|
}
|
|
|
|
return self::$_cache['lc_info'];
|
|
}
|
|
|
|
/**
|
|
* Get the language info returned by nl_langinfo(), but cache it, to
|
|
* avoid repeated calls.
|
|
*
|
|
* @param const $item The langinfo item to return.
|
|
*
|
|
* @return array The results of nl_langinfo().
|
|
*/
|
|
public static function getLangInfo($item)
|
|
{
|
|
if (!function_exists('nl_langinfo')) {
|
|
return false;
|
|
}
|
|
|
|
if (!isset(self::$_cache['nl_info'])) {
|
|
self::$_cache['nl_info'] = array();
|
|
}
|
|
|
|
if (!isset(self::$_cache['nl_info'][$item])) {
|
|
self::$_cache['nl_info'][$item] = nl_langinfo($item);
|
|
}
|
|
|
|
return self::$_cache['nl_info'][$item];
|
|
}
|
|
|
|
/**
|
|
* Get country information from a hostname or IP address.
|
|
*
|
|
* @param string $host The hostname or IP address.
|
|
* @param string $datafile The datafile for the GeoIP lookup. If not set,
|
|
* will skip this lookup.
|
|
*
|
|
* @return mixed On success, return an array with the following entries:
|
|
* 'code' => Country Code
|
|
* 'name' => Country Name
|
|
* On failure, return false.
|
|
*/
|
|
public static function getCountryByHost($host, $datafile = null)
|
|
{
|
|
/* List of generic domains that we know is not in the country TLD
|
|
list. See: http://www.iana.org/gtld/gtld.htm */
|
|
$generic = array(
|
|
'aero', 'biz', 'com', 'coop', 'edu', 'gov', 'info', 'int', 'mil',
|
|
'museum', 'name', 'net', 'org', 'pro'
|
|
);
|
|
|
|
$checkHost = null;
|
|
if (preg_match('/^\d+\.\d+\.\d+\.\d+$/', $host)) {
|
|
if (isset(self::$dnsResolver)) {
|
|
try {
|
|
$response = self::$dnsResolver->query($host, 'PTR');
|
|
foreach ($response->answer as $val) {
|
|
if (isset($val->ptrdname)) {
|
|
$checkHost = $val->ptrdname;
|
|
break;
|
|
}
|
|
}
|
|
} catch (Net_DNS2_Exception $e) {}
|
|
}
|
|
if (is_null($checkHost)) {
|
|
$checkHost = @gethostbyaddr($host);
|
|
}
|
|
} else {
|
|
$checkHost = $host;
|
|
}
|
|
|
|
/* Get the TLD of the hostname. */
|
|
$pos = strrpos($checkHost, '.');
|
|
if ($pos === false) {
|
|
return false;
|
|
}
|
|
$domain = Horde_String::lower(substr($checkHost, $pos + 1));
|
|
|
|
/* Try lookup via TLD first. */
|
|
if (!in_array($domain, $generic)) {
|
|
$name = self::tldLookup($domain);
|
|
if ($name) {
|
|
return array(
|
|
'code' => $domain,
|
|
'name' => $name
|
|
);
|
|
}
|
|
}
|
|
|
|
/* Try GeoIP lookup next. */
|
|
$geoip = new Horde_Nls_Geoip($datafile);
|
|
return $geoip->getCountryInfo($checkHost);
|
|
}
|
|
|
|
/**
|
|
* Do a top level domain (TLD) lookup.
|
|
*
|
|
* @param string $code A 2-letter country code.
|
|
*
|
|
* @return mixed The localized country name, or null if not found.
|
|
*/
|
|
public static function tldLookup($code)
|
|
{
|
|
if (!isset(self::$_cache['tld'])) {
|
|
include __DIR__ . '/Nls/Tld.php';
|
|
self::$_cache['tld'] = $tld;
|
|
}
|
|
|
|
$code = Horde_String::lower($code);
|
|
|
|
return isset(self::$_cache['tld'][$code])
|
|
? self::$_cache['tld'][$code]
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* Returns either a specific or all ISO-3166 country names.
|
|
*
|
|
* @param string $code The ISO 3166 country code.
|
|
*
|
|
* @return mixed If a country code has been requested will return the
|
|
* corresponding country name. If empty will return an
|
|
* array of all the country codes and their names.
|
|
*/
|
|
public static function getCountryISO($code = null)
|
|
{
|
|
if (!isset(self::$_cache['iso3166'])) {
|
|
include __DIR__ . '/Nls/Countries.php';
|
|
self::$_cache['iso3166'] = $countries;
|
|
}
|
|
|
|
if (empty($code)) {
|
|
return self::$_cache['iso3166'];
|
|
}
|
|
|
|
$code = Horde_String::upper($code);
|
|
|
|
return isset(self::$_cache['iso3166'][$code])
|
|
? self::$_cache['iso3166'][$code]
|
|
: null;
|
|
}
|
|
|
|
/**
|
|
* Returns either a specific or all ISO-639 language names.
|
|
*
|
|
* @param string $code The ISO 639 language code.
|
|
*
|
|
* @return mixed If a language code has been requested will return the
|
|
* corresponding language name. If empty will return an
|
|
* array of all the language codes (keys) and their names
|
|
* (values).
|
|
*/
|
|
public static function getLanguageISO($code = null)
|
|
{
|
|
if (!isset(self::$_cache['iso639'])) {
|
|
include __DIR__ . '/Nls/Languages.php';
|
|
self::$_cache['iso639'] = $languages;
|
|
}
|
|
|
|
if (empty($code)) {
|
|
return self::$_cache['iso639'];
|
|
}
|
|
|
|
$code = substr(Horde_String::lower(trim($code)), 0, 2);
|
|
|
|
return isset(self::$_cache['iso639'][$code])
|
|
? self::$_cache['iso639'][$code]
|
|
: null;
|
|
}
|
|
|
|
}
|