1: <?php
2: /**
3: * The Horde_Nls:: class provides Native Language Support. This includes
4: * common methods for handling language data, timezones, and hostname->country
5: * lookups.
6: *
7: * Copyright 1999-2012 Horde LLC (http://www.horde.org/)
8: *
9: * See the enclosed file COPYING for license information (LGPL). If you
10: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
11: *
12: * @author Jon Parise <jon@horde.org>
13: * @author Chuck Hagenbuch <chuck@horde.org>
14: * @author Jan Schneider <jan@horde.org>
15: * @author Michael Slusarz <slusarz@horde.org>
16: * @category Horde
17: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
18: * @package Nls
19: */
20: class Horde_Nls
21: {
22: /**
23: * DNS resolver.
24: *
25: * @var Net_DNS2_Resolver
26: */
27: static public $dnsResolver;
28:
29: /**
30: * Cached values.
31: *
32: * @var array
33: */
34: static protected $_cache = array();
35:
36: /**
37: * Check to see if character set is valid for htmlspecialchars() calls.
38: *
39: * @param string $charset The character set to check.
40: *
41: * @return boolean Is charset valid for the current system?
42: */
43: static public function checkCharset($charset)
44: {
45: if (is_null($charset) || empty($charset)) {
46: return false;
47: }
48:
49: $valid = true;
50:
51: ini_set('track_errors', 1);
52: @htmlspecialchars('', ENT_COMPAT, $charset);
53: if (isset($php_errormsg)) {
54: $valid = false;
55: }
56: ini_restore('track_errors');
57:
58: return $valid;
59: }
60:
61: /**
62: * Returns a list of available timezones.
63: *
64: * @return array List of timezones.
65: */
66: static public function getTimezones()
67: {
68: $timezones = DateTimeZone::listIdentifiers();
69: return array_combine($timezones, $timezones);
70: }
71:
72: /**
73: * Get the locale info returned by localeconv(), but cache it, to
74: * avoid repeated calls.
75: *
76: * @return array The results of localeconv().
77: */
78: static public function getLocaleInfo()
79: {
80: if (!isset(self::$_cache['lc_info'])) {
81: self::$_cache['lc_info'] = localeconv();
82: }
83:
84: return self::$_cache['lc_info'];
85: }
86:
87: /**
88: * Get the language info returned by nl_langinfo(), but cache it, to
89: * avoid repeated calls.
90: *
91: * @param const $item The langinfo item to return.
92: *
93: * @return array The results of nl_langinfo().
94: */
95: static public function getLangInfo($item)
96: {
97: if (!function_exists('nl_langinfo')) {
98: return false;
99: }
100:
101: if (!isset(self::$_cache['nl_info'])) {
102: self::$_cache['nl_info'] = array();
103: }
104:
105: if (!isset(self::$_cache['nl_info'][$item])) {
106: self::$_cache['nl_info'][$item] = nl_langinfo($item);
107: }
108:
109: return self::$_cache['nl_info'][$item];
110: }
111:
112: /**
113: * Get country information from a hostname or IP address.
114: *
115: * @param string $host The hostname or IP address.
116: * @param string $datafile The datafile for the GeoIP lookup. If not set,
117: * will skip this lookup.
118: *
119: * @return mixed On success, return an array with the following entries:
120: * 'code' => Country Code
121: * 'name' => Country Name
122: * On failure, return false.
123: */
124: static public function getCountryByHost($host, $datafile = null)
125: {
126: /* List of generic domains that we know is not in the country TLD
127: list. See: http://www.iana.org/gtld/gtld.htm */
128: $generic = array(
129: 'aero', 'biz', 'com', 'coop', 'edu', 'gov', 'info', 'int', 'mil',
130: 'museum', 'name', 'net', 'org', 'pro'
131: );
132:
133: $checkHost = null;
134: if (preg_match('/^\d+\.\d+\.\d+\.\d+$/', $host)) {
135: if (isset(self::$dnsResolver)) {
136: try {
137: $response = self::$dnsResolver->query($host, 'PTR');
138: foreach ($response->answer as $val) {
139: if (isset($val->ptrdname)) {
140: $checkHost = $val->ptrdname;
141: break;
142: }
143: }
144: } catch (Net_DNS2_Exception $e) {}
145: }
146: if (is_null($checkHost)) {
147: $checkHost = @gethostbyaddr($host);
148: }
149: } else {
150: $checkHost = $host;
151: }
152:
153: /* Get the TLD of the hostname. */
154: $pos = strrpos($checkHost, '.');
155: if ($pos === false) {
156: return false;
157: }
158: $domain = Horde_String::lower(substr($checkHost, $pos + 1));
159:
160: /* Try lookup via TLD first. */
161: if (!in_array($domain, $generic)) {
162: $name = self::tldLookup($domain);
163: if ($name) {
164: return array(
165: 'code' => $domain,
166: 'name' => $name
167: );
168: }
169: }
170:
171: /* Try GeoIP lookup next. */
172: $geoip = new Horde_Nls_Geoip($datafile);
173: return $geoip->getCountryInfo($checkHost);
174: }
175:
176: /**
177: * Do a top level domain (TLD) lookup.
178: *
179: * @param string $code A 2-letter country code.
180: *
181: * @return mixed The localized country name, or null if not found.
182: */
183: static public function tldLookup($code)
184: {
185: if (!isset(self::$_cache['tld'])) {
186: include dirname(__FILE__) . '/Nls/Tld.php';
187: self::$_cache['tld'] = $tld;
188: }
189:
190: $code = Horde_String::lower($code);
191:
192: return isset(self::$_cache['tld'][$code])
193: ? self::$_cache['tld'][$code]
194: : null;
195: }
196:
197: /**
198: * Returns either a specific or all ISO-3166 country names.
199: *
200: * @param string $code The ISO 3166 country code.
201: *
202: * @return mixed If a country code has been requested will return the
203: * corresponding country name. If empty will return an
204: * array of all the country codes and their names.
205: */
206: static public function getCountryISO($code = null)
207: {
208: if (!isset(self::$_cache['iso3166'])) {
209: include dirname(__FILE__) . '/Nls/Countries.php';
210: self::$_cache['iso3166'] = $countries;
211: }
212:
213: if (empty($code)) {
214: return self::$_cache['iso3166'];
215: }
216:
217: $code = Horde_String::upper($code);
218:
219: return isset(self::$_cache['iso3166'][$code])
220: ? self::$_cache['iso3166'][$code]
221: : null;
222: }
223:
224: /**
225: * Returns either a specific or all ISO-639 language names.
226: *
227: * @param string $code The ISO 639 language code.
228: *
229: * @return mixed If a language code has been requested will return the
230: * corresponding language name. If empty will return an
231: * array of all the language codes (keys) and their names
232: * (values).
233: */
234: static public function getLanguageISO($code = null)
235: {
236: if (!isset(self::$_cache['iso639'])) {
237: include dirname(__FILE__) . '/Nls/Languages.php';
238: self::$_cache['iso639'] = $languages;
239: }
240:
241: if (empty($code)) {
242: return self::$_cache['iso639'];
243: }
244:
245: $code = substr(Horde_String::lower(trim($code)), 0, 2);
246:
247: return isset(self::$_cache['iso639'][$code])
248: ? self::$_cache['iso639'][$code]
249: : null;
250: }
251:
252: }
253: