1<?php 2 3/* 4 5 This script tries to guess what language to use for 6 language dependent operations (lookup, search, books 7 page display, etc.), considering all possible factors 8 affecting language selection. 9 10 After this script run, $LANG is set to the preferred 11 language, or is the empty string, if no manual is 12 available on the current mirror site. 13 14 $EXPL_LANG will also be set to the explicitly provided 15 language, or will not exist if there are only implications 16 on the preferred language. 17 18 $UA_LANGS will contain the user agent language settings 19 parsed as an array. The language names are corrected for 20 php.net usage in this array. This is just to present to 21 the user in case he would like to get information on the 22 parsed language information (see /my.php). 23 24 The $_SERVER['STRIPPED_URI'] var is also set to the 25 stripped request URI (in case of a shortcut, the 26 language is stipped, so the shortcut handling code 27 is not bothered with it). 28 29*/ 30 31// Default STRIPPED_URI 32$_SERVER['STRIPPED_URI'] = htmlspecialchars($_SERVER['REQUEST_URI'], ENT_QUOTES, 'UTF-8'); 33 34// The code is encapsulated in a function, 35// so the variable namespace is not polluted 36list($LANG, $EXPL_LANG, $UA_LANGS) = language_choose_code(); 37 38// Compatibility 39if ($EXPL_LANG == '') { unset($EXPL_LANG); } 40 41function language_choose_code() 42{ 43 // Contains all the languages picked up by the 44 // process in priority order (without repeating codes) 45 $languages = []; 46 47 // Default values for languages 48 $explicitly_specified = ''; $selected = ''; 49 50 // Specified for the request (GET/POST parameter) 51 if (!empty($_REQUEST['lang']) && is_string($_REQUEST['lang'])) { 52 $explicitly_specified = language_add(htmlspecialchars($_REQUEST['lang'], ENT_QUOTES, 'UTF-8'), $languages); 53 54 // Set the language in a cookie for a year 55 mirror_setcookie("LAST_LANG", $explicitly_specified, 60 * 60 * 24 * 365); 56 } 57 58 // Specified in a shortcut URL (eg. /en/echo or /pt_br/echo) 59 if (preg_match("!^/(\\w{2}(_\\w{2})?)/!", htmlspecialchars($_SERVER['REQUEST_URI'],ENT_QUOTES, 'UTF-8'), $flang)) { 60 61 // Put language into preference list 62 $rlang = language_add($flang[1], $languages); 63 64 // Set explicity specified language 65 if (empty($explicitly_specified)) { 66 $explicitly_specified = $rlang; 67 } 68 69 // Drop out langauge specification from URL, as this is already handled 70 $_SERVER['STRIPPED_URI'] = preg_replace( 71 "!^/$flang[1]/!", "/", htmlspecialchars($_SERVER['REQUEST_URI'], ENT_QUOTES, 'UTF-8'), 72 ); 73 74 } 75 76 // Specified in a manual URL (eg. manual/en/ or manual/pt_br/) 77 if (preg_match("!^/manual/(\\w{2}(_\\w{2})?)(/|$)!", htmlspecialchars($_SERVER['REQUEST_URI'], ENT_QUOTES, 'UTF-8'), $flang)) { 78 79 $flang = language_add($flang[1], $languages); 80 81 // Set explicity specified language 82 if (empty($explicitly_specified)) { 83 $explicitly_specified = $flang; 84 } 85 86 // Set the language in a cookie for a year 87 mirror_setcookie("LAST_LANG", $flang, 60 * 60 * 24 * 365); 88 } 89 90 // Honor the users own language setting (if available) 91 if (myphpnet_language()) { 92 language_add(myphpnet_language(), $languages); 93 } 94 95 // Specified by the user via the browser's Accept Language setting 96 // Samples: "hu, en-us;q=0.66, en;q=0.33", "hu,en-us;q=0.5" 97 $browser_langs = []; $parsed_langs = []; 98 99 // Check if we have $_SERVER['HTTP_ACCEPT_LANGUAGE'] set and 100 // it no longer breaks if you only have one language set :) 101 if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { 102 $browser_accept = explode(",", $_SERVER['HTTP_ACCEPT_LANGUAGE']); 103 104 // Go through all language preference specs 105 foreach ($browser_accept as $value) { 106 // The language part is either a code or a code with a quality 107 // We cannot do anything with a * code, so it is skipped 108 // If the quality is missing, it is assumed to be 1 according to the RFC 109 if (preg_match("!([a-z-]+)(;q=([0-9\\.]+))?!", trim($value), $found)) { 110 $quality = (isset($found[3]) ? (float) $found[3] : 1.0); 111 $browser_langs[] = [$found[1], $quality]; 112 } 113 unset($found); 114 } 115 } 116 117 // Order the codes by quality 118 usort($browser_langs, "language_accept_order"); 119 120 // For all languages found in the accept-language 121 foreach ($browser_langs as $langdata) { 122 123 // Translation table for accept-language codes and phpdoc codes 124 switch ($langdata[0]) { 125 case "pt-br": 126 $langdata[0] = 'pt_br'; 127 break; 128 case "zh-cn": 129 $langdata[0] = 'zh'; 130 break; 131 case "zh-hk": 132 $langdata[0] = 'hk'; 133 break; 134 case "zh-tw": 135 $langdata[0] = 'tw'; 136 break; 137 } 138 139 // We do not support flavors of languages (except the ones above) 140 // This is not in conformance to the RFC, but it here for user 141 // convinience reasons 142 if (preg_match("!^(.+)-!", $langdata[0], $match)) { 143 $langdata[0] = $match[1]; 144 } 145 146 // Add language to priority order 147 $parsed_langs[] = language_add($langdata[0], $languages); 148 } 149 150 // Language preferred by this mirror site 151 language_add(default_language(), $languages); 152 153 // Last default language is English 154 language_add("en", $languages); 155 156 // Try to find out what language is available on this mirror. 157 // As most of the language dependant operations involve manual 158 // page display (lookup, search, shortcuts), we will check for 159 // the index file of manuals. 160/* 161 foreach ($languages as $language) { 162 if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/manual/$language/index.php")) { 163 $selected = $language; 164 break; 165 } 166 } 167*/ 168 $selected = $languages[0]; 169 170 // Return with all found data 171 return [$selected, $explicitly_specified, $parsed_langs]; 172} 173 174// Add a language to the possible languages' list 175function language_add($langcode, &$langs) 176{ 177 global $LANGUAGES, $INACTIVE_ONLINE_LANGUAGES; 178 179 // Make language code lowercase, html encode special chars and remove slashes 180 $langcode = strtolower(htmlspecialchars($langcode)); 181 182 // The Brazilian Portuguese code needs special attention 183 if ($langcode == 'pt_br') { $langcode = 'pt_BR'; } 184 185 // Append language code in priority order if it is not 186 // there already and supported by the PHP site. Try to 187 // lower number of file_exists() calls to the minumum... 188 if (!in_array($langcode, $langs, false) && isset($LANGUAGES[$langcode]) 189 && !isset($INACTIVE_ONLINE_LANGUAGES[$langcode])) { 190 $langs[] = $langcode; 191 } 192 193 // Return with language code 194 return $langcode; 195} 196 197// Order the array of compiled 198// accept-language codes by quality value 199function language_accept_order($a, $b) 200{ 201 if ($a[1] == $b[1]) { return 0; } 202 return ($a[1] > $b[1]) ? -1 : 1; 203} 204