]> git.openstreetmap.org Git - nominatim.git/blobdiff - lib/lib.php
Merge remote-tracking branch 'upstream/master'
[nominatim.git] / lib / lib.php
index 069f3e2535da491f7959c92606f41ab29a307a8c..2c335c49eaf6a83fdb3feea45d6775d2e67e6d0e 100644 (file)
@@ -1,5 +1,43 @@
 <?php
 
+       function failInternalError($sError, $sSQL = false, $vDumpVar = false) 
+       {
+               header('HTTP/1.0 500 Internal Server Error');
+               header('Content-type: text/html; charset=utf-8');
+               echo "<html><body><h1>Internal Server Error</h1>";
+               echo '<p>Nominatim has encountered an internal error while processing your request. This is most likely because of a bug in the software.</p>';
+               echo "<p><b>Details:</b> ".$sError,"</p>";
+               echo '<p>Feel free to report the bug in the <a href="http://trac.openstreetmap.org">OSM bug database</a>. Please include the error message above and the URL you used.</p>';
+               if (CONST_Debug)
+               {
+                       echo "<hr><h2>Debugging Information</h2><br>";
+                       if ($sSQL) {
+                               echo "<h3>SQL query</h3><code>".$sSQL."</code>";
+                       }
+                       if ($vDumpVar) {
+                               echo "<h3>Result</h3> <code>";
+                               var_dump($vDumpVar);
+                               echo "</code>";
+                       }
+               }
+               echo "\n</body></html>\n";
+               exit;
+
+       }
+
+       function userError($sError) 
+       {
+               header('HTTP/1.0 400 Bad Request');
+               header('Content-type: text/html; charset=utf-8');
+               echo "<html><body><h1>Bad Request</h1>";
+               echo '<p>Nominatim has encountered an error with your request.</p>';
+               echo "<p><b>Details:</b> ".$sError,"</p>";
+               echo '<p>If you feel this error is incorrect feel free to report the bug in the <a href="http://trac.openstreetmap.org">OSM bug database</a>. Please include the error message above and the URL you used.</p>';
+               echo "\n</body></html>\n";
+               exit;
+
+       }
+
        function fail($sError, $sUserError = false)
        {
                if (!$sUserError) $sUserError = $sError;
@@ -22,7 +60,7 @@
        {
                $sLoadAverage = file_get_contents('/proc/loadavg');
                 $aLoadAverage = explode(' ',$sLoadAverage);
-               return (int)$aLoadAverage[0];
+               return (float)$aLoadAverage[0];
        }
 
        function getProcessorCount()
                return sizeof($aMatches[0]);
        }
 
+       function getTotalMemoryMB()
+       {
+               $sCPU = file_get_contents('/proc/meminfo');
+               preg_match('#MemTotal: +([0-9]+) kB#', $sCPU, $aMatches);
+               return (int)($aMatches[1]/1024);
+       }
+
+       function getCacheMemoryMB()
+       {
+               $sCPU = file_get_contents('/proc/meminfo');
+               preg_match('#Cached: +([0-9]+) kB#', $sCPU, $aMatches);
+               return (int)($aMatches[1]/1024);
+       }
+
        function bySearchRank($a, $b)
        {
                if ($a['iSearchRank'] == $b['iSearchRank']) return 0;
                return ($a['foundorder'] < $b['foundorder']?-1:1);
        }
 
-       function getPrefferedLangauges()
+       function getPreferredLanguages()
        {
                // If we have been provided the value in $_GET it overrides browser value
                if (isset($_GET['accept-language']) && $_GET['accept-language'])
                }
 
                $aLanguages = array();
-               if (preg_match_all('/(([a-z]{1,8})(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $aLanguagesParse, PREG_SET_ORDER))
-               {
-                       foreach($aLanguagesParse as $iLang => $aLanguage)
+               if (isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])) {
+                       if (preg_match_all('/(([a-z]{1,8})(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $aLanguagesParse, PREG_SET_ORDER))
                        {
-                               $aLanguages[$aLanguage[1]] = isset($aLanguage[5])?(float)$aLanguage[5]:1 - ($iLang/100);
-                               if (!isset($aLanguages[$aLanguage[2]])) $aLanguages[$aLanguage[2]] = $aLanguages[$aLanguage[1]]/10;
+                               foreach($aLanguagesParse as $iLang => $aLanguage)
+                               {
+                                       $aLanguages[$aLanguage[1]] = isset($aLanguage[5])?(float)$aLanguage[5]:1 - ($iLang/100);
+                                       if (!isset($aLanguages[$aLanguage[2]])) $aLanguages[$aLanguage[2]] = $aLanguages[$aLanguage[1]]/10;
+                               }
+                               arsort($aLanguages);
                        }
-                       arsort($aLanguages);
-               }
+        }
                if (!sizeof($aLanguages)) $aLanguages = array(CONST_Default_Language=>1);
                foreach($aLanguages as $sLangauge => $fLangauagePref)
                {
                return false;
 
                /*
-                       $fTotalFac is a suprisingly good indicator of accuracy
+                       $fTotalFac is a surprisingly good indicator of accuracy
                        $iZoom = 18 + round(log($fTotalFac,32));
                        $iZoom = max(13,min(18,$iZoom));
                */
        function getClassTypes()
        {
                return array(
+ 'boundary:administrative:1' => array('label'=>'Continent','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
  'boundary:administrative:2' => array('label'=>'Country','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
  'place:country' => array('label'=>'Country','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>6, 'defdiameter' => 15,),
+ 'boundary:administrative:3' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
  'boundary:administrative:4' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
  'place:state' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 5.12,),
  'boundary:administrative:5' => array('label'=>'State District','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
  'boundary:administrative:6' => array('label'=>'County','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ 'boundary:administrative:7' => array('label'=>'County','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
  'place:county' => array('label'=>'County','frequency'=>108,'icon'=>'poi_boundary_administrative','defzoom'=>10, 'defdiameter' => 1.28,),
  'boundary:administrative:8' => array('label'=>'City','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
  'place:city' => array('label'=>'City','frequency'=>66,'icon'=>'poi_place_city','defzoom'=>12, 'defdiameter' => 0.32,),
  'boundary:administrative:9' => array('label'=>'City District','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
  'boundary:administrative:10' => array('label'=>'Suburb','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
  'boundary:administrative:11' => array('label'=>'Neighbourhood','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
- 'place:region' => array('label'=>'Region','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 5.12,),
+ 'place:region' => array('label'=>'Region','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 0.04,),
  'place:island' => array('label'=>'Island','frequency'=>288,'icon'=>'','defzoom'=>11, 'defdiameter' => 0.64,),
  'boundary:administrative' => array('label'=>'Administrative','frequency'=>413,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
+ 'boundary:postal_code' => array('label'=>'Postcode','frequency'=>413,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
  'place:town' => array('label'=>'Town','frequency'=>1497,'icon'=>'poi_place_town','defzoom'=>14, 'defdiameter' => 0.08,),
  'place:village' => array('label'=>'Village','frequency'=>11230,'icon'=>'poi_place_village','defzoom'=>15, 'defdiameter' => 0.04,),
  'place:hamlet' => array('label'=>'Hamlet','frequency'=>7075,'icon'=>'poi_place_village','defzoom'=>15, 'defdiameter' => 0.04,),
 
  'place:airport' => array('label'=>'Airport','frequency'=>36,'icon'=>'transport_airport2', 'defdiameter' => 0.03,),
  'railway:station' => array('label'=>'Station','frequency'=>3431,'icon'=>'transport_train_station2', 'defdiameter' => 0.01,),
- 'amenity:place_of_worship' => array('label'=>'Place Of Worship','frequency'=>9049,'icon'=>'place_of_worship3',),
+ 'amenity:place_of_worship' => array('label'=>'Place Of Worship','frequency'=>9049,'icon'=>'place_of_worship_unknown3',),
  'amenity:pub' => array('label'=>'Pub','frequency'=>18969,'icon'=>'food_pub',),
  'amenity:bar' => array('label'=>'Bar','frequency'=>164,'icon'=>'food_bar',),
  'amenity:university' => array('label'=>'University','frequency'=>607,'icon'=>'education_university',),
  'tourism:motel' => array('label'=>'Motel','frequency'=>43,'icon'=>'',),
  'amenity:cinema' => array('label'=>'Cinema','frequency'=>277,'icon'=>'tourist_cinema',),
  'tourism:information' => array('label'=>'Information','frequency'=>224,'icon'=>'amenity_information',),
- 'tourism:artwork' => array('label'=>'Artwork','frequency'=>171,'icon'=>'art_gallery2',),
+ 'tourism:artwork' => array('label'=>'Artwork','frequency'=>171,'icon'=>'tourist_art_gallery2',),
  'historic:archaeological_site' => array('label'=>'Archaeological Site','frequency'=>407,'icon'=>'tourist_archaeological2',),
  'amenity:doctors' => array('label'=>'Doctors','frequency'=>581,'icon'=>'health_doctors',),
  'leisure:sports_centre' => array('label'=>'Sports Centre','frequency'=>767,'icon'=>'sport_leisure_centre',),
 
  'leisure:pitch' => array('label'=>'Pitch','frequency'=>762,'icon'=>'',),
  'highway:unsurfaced' => array('label'=>'Unsurfaced','frequency'=>492,'icon'=>'',),
- 'historic:ruins' => array('label'=>'Ruins','frequency'=>483,'icon'=>'shopping_jewelry',),
+ 'historic:ruins' => array('label'=>'Ruins','frequency'=>483,'icon'=>'tourist_ruin',),
  'amenity:college' => array('label'=>'College','frequency'=>473,'icon'=>'education_school',),
  'historic:monument' => array('label'=>'Monument','frequency'=>470,'icon'=>'tourist_monument',),
  'railway:subway' => array('label'=>'Subway','frequency'=>385,'icon'=>'',),
  'railway:disused_station' => array('label'=>'Disused Station','frequency'=>114,'icon'=>'',),
  'railway:abandoned' => array('label'=>'Abandoned','frequency'=>641,'icon'=>'',),
  'railway:disused' => array('label'=>'Disused','frequency'=>72,'icon'=>'',),
-                       );              
+                       );
        }
-       
+
        function getClassTypesWithImportance()
        {
                $aOrders = getClassTypes();
                }
                return $aOrders;
        }
-       
-       
-        function javascript_isarray($xVal)
-        {
-                if (!is_array($xVal)) return false;
-                for($i = 0; $i < sizeof($xVal); $i++)
-                {
-                        if (!array_key_exists($i, $xVal)) return false;
-                }
-                return true;
-        }
 
-        function javascript_renderData($xVal, $bForceHash = false)
-        {
-                if (is_array($xVal))
-                {
-                        $aVals = array();
-                        if (javascript_isarray($xVal) && !$bForceHash)
-                        {
-                                foreach($xVal as $sKey => $xData)
-                                {
-                                        $aVals[] = javascript_renderData($xData);
-                                }
-                                return '['.join(',',$aVals).']';
-                        }
-                        else
-                        {
-                                foreach($xVal as $sKey => $xData)
-                                {
-                                        $aVals[] = '"'.addslashes($sKey).'"'.':'.javascript_renderData($xData);
-                                }
-                                return '{'.join(',',$aVals).'}';
-                        }
-                }
-                else
-                {
-                        if (is_bool($xVal)) return $xVal?'true':'false';
-//                     if (is_numeric($xVal)) return $xVal;
-                        return '"'.str_replace('>','\\>',str_replace(array("\n","\r"),'\\n',str_replace(array("\n\r","\r\n"),'\\n',str_replace('"','\\"',$xVal)))).'"';
-                }
-        }
+    function javascript_renderData($xVal)
+    {
+        header("Access-Control-Allow-Origin: *");
+
+        $jsonout = json_encode($xVal);
+
+               if( ! isset($_GET['json_callback'])) {
+                       header("Content-Type: application/json; charset=UTF-8");
+                       echo $jsonout;
+               } else {
+                       if (preg_match('/^[$_\p{L}][$_\p{L}\p{Nd}.[\]]*$/u',$_GET['json_callback'])) {
+                               header("Content-Type: application/javascript; charset=UTF-8");
+                               echo $_GET['json_callback'].'('.$jsonout.')';
+                       } else {
+                               header('HTTP/1.0 400 Bad Request');
+                       }
+               }
+    }
 
        function _debugDumpGroupedSearches($aData, $aTokens)
        {
                $sSQL = "select *,get_name_by_language(name,$sLanguagePrefArraySQL) as localname from get_addressdata($iPlaceID)";
                IF (!$bRaw) $sSQL .= " WHERE isaddress OR type = 'country_code'";
                $sSQL .= " order by rank_address desc,isaddress desc";
+
                $aAddressLines = $oDB->getAll($sSQL);
                if (PEAR::IsError($aAddressLines))
                {
 //echo "<pre>";
 //var_dump($aAddressLines);
                $aAddress = array();
+               $aFallback = array();
                $aClassType = getClassTypes();
                foreach($aAddressLines as $aLine)
                {
+                       $bFallback = false;
                        $aTypeLabel = false;
                        if (isset($aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']];
                        elseif (isset($aClassType[$aLine['class'].':'.$aLine['type']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type']];
-                       else $aTypeLabel = array('simplelabel'=>$aLine['class']);
-                       if ($aTypeLabel && ($aLine['localname'] || $aLine['housenumber']))
+                       elseif (isset($aClassType['boundary:administrative:'.((int)($aLine['rank_address']/2))]))
                        {
-                               $sTypeLabel = strtolower(isset($aTypeLabel['simplelabel'])?$aTypeLabel['simplelabel']:$aTypeLabel['label']);
-                               $sTypeLabel = str_replace(' ','_',$sTypeLabel);
-                               if (!isset($aAddress[$sTypeLabel]) && $aLine['localname']) $aAddress[$sTypeLabel] = $aLine['localname']?$aLine['localname']:$aLine['housenumber'];
+                               $aTypeLabel = $aClassType['boundary:administrative:'.((int)($aLine['rank_address']/2))];
+                               $bFallback = true;
                        }
-               }
-//var_dump($aAddress);
-//exit;
-               return $aAddress;
-
-               $aHouseNumber = $oDB->getRow('select housenumber, get_name_by_language(name,ARRAY[\'addr:housename\']) as housename,rank_search,postcode from placex where place_id = '.$iPlaceID);
-               $sHouseNumber = $aHouseNumber['housenumber'];
-               $sHouseName = $aHouseNumber['housename'];
-               $sPostcode = $aHouseNumber['postcode'];
-               $iRank = $aHouseNumber['rank_search'];
-
-               // Address
-               $sSQL = "select country_code, placex.place_id, osm_type, osm_id, class, type, housenumber, admin_level, rank_address, rank_search, ";
-               $sSQL .= "get_searchrank_label(rank_search) as rank_search_label, fromarea, isaddress, distance, ";
-               $sSQL .= " CASE WHEN type = 'postcode' THEN postcode ELSE get_name_by_language(name,$sLanguagePrefArraySQL) END as localname, ";
-               $sSQL .= " length(name::text) as namelength ";
-               $sSQL .= " from place_addressline join placex on (address_place_id = placex.place_id)";
-               $sSQL .= " where place_addressline.place_id = $iPlaceID and (rank_address > 0 OR address_place_id = $iPlaceID)";
-               if (!$bRaw) $sSQL .= " and isaddress";
-               $sSQL .= " order by cached_rank_address desc,isaddress desc,fromarea desc,distance asc,rank_search desc,namelength desc";
-//var_dump($sSQL);
-               $aAddressLines = $oDB->getAll($sSQL);
-               if (PEAR::IsError($aAddressLines))
-               {
-                       var_dump($aAddressLines);
-                       exit;
-               }
-               if ($bRaw) return $aAddressLines;
-       
-               $aClassType = getClassTypes();
-
-               $iMinRank = 100;
-               $aAddress = array();
-               if ($iRank >= 28 && $sHouseNumber) $aAddress['house_number'] = $sHouseNumber;
-               if ($iRank >= 28 && $sHouseName) $aAddress['house_name'] = $sHouseName;
-               foreach($aAddressLines as $aLine)
-               {
-                       if (!$sCountryCode) $sCountryCode = $aLine['country_code'];
-                       if ($aLine['rank_address'] < $iMinRank)
+                       else
                        {
-                               $aTypeLabel = false;
-                               if (isset($aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']];
-                               elseif (isset($aClassType[$aLine['class'].':'.$aLine['type']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type']];
-                               else $aTypeLabel = array('simplelabel'=>$aLine['class']);
-                               if ($aTypeLabel && ($aLine['localname'] || $aLine['housenumber']))
-                               {
-                                       $sTypeLabel = strtolower(isset($aTypeLabel['simplelabel'])?$aTypeLabel['simplelabel']:$aTypeLabel['label']);
-                                       $sTypeLabel = str_replace(' ','_',$sTypeLabel);
-                                       if (!isset($aAddress[$sTypeLabel]) && $aLine['localname']) $aAddress[$sTypeLabel] = $aLine['localname']?$aLine['localname']:$aLine['housenumber'];
-                               }
-                               $iMinRank = $aLine['rank_address'];
+                               $aTypeLabel = array('simplelabel'=>'address'.$aLine['rank_address']);
+                               $bFallback = true;
                        }
-               }
-
-               if ($sPostcode)
-               {
-                       $aAddress['postcode'] = $sPostcode;
-               }
-
-               if ($iMinRank > 4 && $sCountryCode)
-               {
-                       $sSQL = "select get_name_by_language(country_name.name,$sLanguagePrefArraySQL) as name";
-                       $sSQL .= " from country_name where country_code = '$sCountryCode'";
-                       $sCountryName = $oDB->getOne($sSQL);
-                       if ($sCountryName)
+                       if ($aTypeLabel && ((isset($aLine['localname']) && $aLine['localname']) || (isset($aLine['housenumber']) && $aLine['housenumber'])))
                        {
-                               $aAddress['country'] = $sCountryName;
+                               $sTypeLabel = strtolower(isset($aTypeLabel['simplelabel'])?$aTypeLabel['simplelabel']:$aTypeLabel['label']);
+                               $sTypeLabel = str_replace(' ','_',$sTypeLabel);
+                               if (!isset($aAddress[$sTypeLabel]) || (isset($aFallback[$sTypeLabel]) && $aFallback[$sTypeLabel]))
+                               {
+                                       $aAddress[$sTypeLabel] = $aLine['localname']?$aLine['localname']:$aLine['housenumber'];
+                               }
+                               $aFallback[$sTypeLabel] = $bFallback;
                        }
                }
-               if ($sCountryCode)
-               {
-                       $aAddress['country_code'] = $sCountryCode;
-               }
-
                return $aAddress;
        }
 
 
                return $iPlaceID;
        }
+
+        function loadStructuredAddressElement(&$aStructuredQuery, &$iMinAddressRank, &$iMaxAddressRank, $aParams, $sKey, $iNewMinAddressRank, $iNewMaxAddressRank)
+        {
+                if (!isset($_GET[$sKey])) return false;
+                $sValue = trim($_GET[$sKey]);
+                if (!$sValue) return false;
+                $aStructuredQuery[$sKey] = $sValue;
+                if ($iMinAddressRank == 0 && $iMaxAddressRank == 30) {
+                        $iMinAddressRank = $iNewMinAddressRank;
+                        $iMaxAddressRank = $iNewMaxAddressRank;
+                }
+                return true;
+        }