/** * Check if input (an array of $_FILES) are .tar or .zip files, if they * are then these get unpacked and returns an managed as $_FILES (returning * an array with the same structure $_FILES uses and move pics to /tmp) * * @access public * @param array $files $_FILES * @return array $_FILES format */ function UnpackFiles($files) { if (!is_array($files)) { return array(); } $cleanFiles = array(); $tmpDir = sys_get_temp_dir(); $counter = 1; require_once PEAR_PATH . 'File/Archive.php'; foreach ($files as $key => $file) { if (empty($file['tmp_name'])) { continue; } $ext = strrchr($file['name'], '.'); switch ($ext) { case '.gz': $ext = '.tgz'; break; case '.bz2': case '.bzip2': $ext = '.tbz'; break; } $ext = strtolower(ltrim($ext, '.')); if (File_Archive::isKnownExtension($ext)) { $tmpArchiveName = $tmpDir . DIRECTORY_SEPARATOR . $file['name']; if (!move_uploaded_file($file['tmp_name'], $tmpArchiveName)) { continue; } $reader = File_Archive::read($tmpArchiveName); $source = File_Archive::readArchive($ext, $reader); if (!PEAR::isError($source)) { while ($source->next()) { $destFile = $tmpDir . DIRECTORY_SEPARATOR . basename($source->getFilename()); $sourceFile = $tmpArchiveName . '/' . $source->getFilename(); $extract = File_Archive::extract($sourceFile, $tmpDir); if (PEAR::IsError($extract)) { continue; } $cleanFiles['photo' . $counter] = array('name' => basename($source->getFilename()), 'type' => $source->getMime(), 'tmp_name' => $destFile, 'size' => @filesize($destFile), 'error' => 0); $counter++; } } } else { $cleanFiles['photo' . $counter] = $file; $counter++; } } return $cleanFiles; }
function &getDB($bNew = false, $bPersistent = false) { // Get the database object $oDB =& DB::connect(CONST_Database_DSN . ($bNew ? '?new_link=true' : ''), $bPersistent); if (PEAR::IsError($oDB)) { var_dump(CONST_Database_DSN); var_Dump($oDB); fail($oDB->getMessage()); } $oDB->setFetchMode(DB_FETCHMODE_ASSOC); $oDB->query("SET DateStyle TO 'sql,european'"); $oDB->query("SET client_encoding TO 'utf-8'"); return $oDB; }
//var_dump($sSQL); $aPlace = $oDB->getRow($sSQL); $iPlaceID = $aPlace['place_id']; $iParentPlaceID = $aPlace['parent_place_id']; if (PEAR::IsError($iPlaceID)) { failInternalError("Could not determine closest place.", $sSQL, $iPlaceID); } } // The point we found might be too small - use the address to find what it is a child of if ($iPlaceID && $iMaxRank < 28) { if ($aPlace['rank_search'] > 28 && $iParentPlaceID) { $iPlaceID = $iParentPlaceID; } $sSQL = "select address_place_id from place_addressline where place_id = {$iPlaceID} order by abs(cached_rank_address - {$iMaxRank}) asc,cached_rank_address desc,isaddress desc,distance desc limit 1"; $iPlaceID = $oDB->getOne($sSQL); if (PEAR::IsError($iPlaceID)) { failInternalError("Could not get parent for place.", $sSQL, $iPlaceID); } if (!$iPlaceID) { $iPlaceID = $aPlace['place_id']; } } } if ($iPlaceID) { $sSQL = "select placex.*,"; $sSQL .= " get_address_by_language(place_id, {$sLanguagePrefArraySQL}) as langaddress,"; $sSQL .= " get_name_by_language(name, {$sLanguagePrefArraySQL}) as placename,"; $sSQL .= " get_name_by_language(name, ARRAY['ref']) as ref,"; $sSQL .= " st_y(st_centroid(geometry)) as lat, st_x(st_centroid(geometry)) as lon"; $sSQL .= " from placex where place_id = {$iPlaceID} "; //var_dump($sSQL);
/** * Get the stucture of a field into an array * * @param string $table name of table that should be used in method * @param string $field_name name of field that should be used in method * @return mixed data array on success, a MDB2 error on failure. * The returned array contains an array for each field definition, * with (some of) these indices: * [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type] * @access public */ function getTableFieldDefinition($table, $field_name) { $db =& $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } $result = $db->loadModule('Datatype', null, true); if (PEAR::isError($result)) { return $result; } $query = "SELECT sql FROM sqlite_master WHERE type='table' AND "; if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { $query .= 'LOWER(name)=' . $db->quote(strtolower($table), 'text'); } else { $query .= 'name=' . $db->quote($table, 'text'); } $sql = $db->queryOne($query); if (PEAR::isError($sql)) { return $sql; } $columns = $this->_getTableColumns($sql); foreach ($columns as $column) { if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { if ($db->options['field_case'] == CASE_LOWER) { $column['name'] = strtolower($column['name']); } else { $column['name'] = strtoupper($column['name']); } } else { $column = array_change_key_case($column, $db->options['field_case']); } if ($field_name == $column['name']) { $mapped_datatype = $db->datatype->mapNativeDatatype($column); if (PEAR::IsError($mapped_datatype)) { return $mapped_datatype; } list($types, $length, $unsigned, $fixed) = $mapped_datatype; $notnull = false; if (!empty($column['notnull'])) { $notnull = $column['notnull']; } $default = false; if (array_key_exists('default', $column)) { $default = $column['default']; if (is_null($default) && $notnull) { $default = ''; } } $autoincrement = false; if (!empty($column['autoincrement'])) { $autoincrement = true; } $definition[0] = array('notnull' => $notnull, 'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])); if (!is_null($length)) { $definition[0]['length'] = $length; } if (!is_null($unsigned)) { $definition[0]['unsigned'] = $unsigned; } if (!is_null($fixed)) { $definition[0]['fixed'] = $fixed; } if ($default !== false) { $definition[0]['default'] = $default; } if ($autoincrement !== false) { $definition[0]['autoincrement'] = $autoincrement; } foreach ($types as $key => $type) { $definition[$key] = $definition[0]; if ($type == 'clob' || $type == 'blob') { unset($definition[$key]['default']); } $definition[$key]['type'] = $type; $definition[$key]['mdb2type'] = $type; } return $definition; } } return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, 'it was not specified an existing table column', __FUNCTION__); }
function getAddressDetails($bAll = false) { if (!$this->iPlaceID) { return null; } $sLanguagePrefArraySQL = "ARRAY[" . join(',', array_map("getDBQuoted", $this->aLangPrefOrder)) . "]"; $sSQL = "select *,get_name_by_language(name,{$sLanguagePrefArraySQL}) as localname from get_addressdata(" . $this->iPlaceID . ")"; if (!$bAll) { $sSQL .= " WHERE isaddress OR type = 'country_code'"; } $sSQL .= " order by rank_address desc,isaddress desc"; $aAddressLines = $this->oDB->getAll($sSQL); if (PEAR::IsError($aAddressLines)) { var_dump($aAddressLines); exit; } return $aAddressLines; }
$iZoom = 14; $aClassType = getClassTypesWithImportance(); $aPointDetails['icon'] = $aClassType[$aPointDetails['class'] . ':' . $aPointDetails['type']]['icon']; // Get all alternative names (languages, etc) $sSQL = "select (each(name)).key,(each(name)).value from placex where place_id = {$iPlaceID} order by (each(name)).key"; $aPointDetails['aNames'] = $oDB->getAssoc($sSQL); // Extra tags $sSQL = "select (each(extratags)).key,(each(extratags)).value from placex where place_id = {$iPlaceID} order by (each(extratags)).key"; $aPointDetails['aExtraTags'] = $oDB->getAssoc($sSQL); // Get the bounding box and outline polygon $sSQL = "select ST_AsText(geometry) as outlinestring,"; $sSQL .= "ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,"; $sSQL .= "ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon"; $sSQL .= " from placex where place_id = {$iPlaceID}"; $aPointPolygon = $oDB->getRow($sSQL); if (PEAR::IsError($aPointPolygon)) { failInternalError("Could not get bounding box of place object.", $sSQL, $aPointPolygon); } if (preg_match('#POLYGON\\(\\(([- 0-9.,]+)#', $aPointPolygon['outlinestring'], $aMatch)) { preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER); } elseif (preg_match('#MULTIPOLYGON\\(\\(\\(([- 0-9.,]+)#', $aPointPolygon['outlinestring'], $aMatch)) { // TODO: this just takes the first ring preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER); } elseif (preg_match('#POINT\\((-?[0-9.]+) (-?[0-9.]+)\\)#', $aPointPolygon['outlinestring'], $aMatch)) { $fRadius = 0.01; if ($aPointDetails['rank_search'] > 20) { $fRadius = 0.0001; } $iSteps = min(max($fRadius * 40000 ^ 2, 16), 100); $fStepSize = 2 * pi() / $iSteps; $aPolyPoints = array();
/** * Get the structure of a field into an array * * @param string $table name of table that should be used in method * @param string $field_name name of field that should be used in method * @return mixed data array on success, a MDB2 error on failure * @access public */ function getTableFieldDefinition($table, $field_name) { $db =& $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } $result = $db->loadModule('Datatype', null, true); if (PEAR::isError($result)) { return $result; } $query = "SELECT a.attname AS name,\r\n t.typname AS type,\r\n CASE a.attlen\r\n WHEN -1 THEN\r\n\t CASE t.typname\r\n\t WHEN 'numeric' THEN (a.atttypmod / 65536)\r\n\t WHEN 'decimal' THEN (a.atttypmod / 65536)\r\n\t WHEN 'money' THEN (a.atttypmod / 65536)\r\n\t ELSE CASE a.atttypmod\r\n WHEN -1 THEN NULL\r\n\t ELSE a.atttypmod - 4\r\n\t END\r\n END\r\n\t ELSE a.attlen\r\n END AS length,\r\n\t CASE t.typname\r\n\t WHEN 'numeric' THEN (a.atttypmod % 65536) - 4\r\n\t WHEN 'decimal' THEN (a.atttypmod % 65536) - 4\r\n\t WHEN 'money' THEN (a.atttypmod % 65536) - 4\r\n\t ELSE 0\r\n END AS scale,\r\n a.attnotnull,\r\n a.atttypmod,\r\n a.atthasdef,\r\n (SELECT substring(pg_get_expr(d.adbin, d.adrelid) for 128)\r\n FROM pg_attrdef d\r\n WHERE d.adrelid = a.attrelid\r\n AND d.adnum = a.attnum\r\n AND a.atthasdef\r\n ) as default\r\n FROM pg_attribute a,\r\n pg_class c,\r\n pg_type t\r\n WHERE c.relname = " . $db->quote($table, 'text') . "\r\n AND a.atttypid = t.oid\r\n AND c.oid = a.attrelid\r\n AND NOT a.attisdropped\r\n AND a.attnum > 0\r\n AND a.attname = " . $db->quote($field_name, 'text') . "\r\n ORDER BY a.attnum"; $column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); if (PEAR::isError($column)) { return $column; } if (empty($column)) { return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, 'it was not specified an existing table column', __FUNCTION__); } $column = array_change_key_case($column, CASE_LOWER); $mapped_datatype = $db->datatype->mapNativeDatatype($column); if (PEAR::IsError($mapped_datatype)) { return $mapped_datatype; } list($types, $length, $unsigned, $fixed) = $mapped_datatype; $notnull = false; if (!empty($column['attnotnull']) && $column['attnotnull'] == 't') { $notnull = true; } $default = null; if ($column['atthasdef'] === 't' && !preg_match("/nextval\\('([^']+)'/", $column['default'])) { $default = $column['default']; #substr($column['adsrc'], 1, -1); if (is_null($default) && $notnull) { $default = ''; } } $autoincrement = false; if (preg_match("/nextval\\('([^']+)'/", $column['default'], $nextvals)) { $autoincrement = true; } $definition[0] = array('notnull' => $notnull, 'nativetype' => $column['type']); if (!is_null($length)) { $definition[0]['length'] = $length; } if (!is_null($unsigned)) { $definition[0]['unsigned'] = $unsigned; } if (!is_null($fixed)) { $definition[0]['fixed'] = $fixed; } if ($default !== false) { $definition[0]['default'] = $default; } if ($autoincrement !== false) { $definition[0]['autoincrement'] = $autoincrement; } foreach ($types as $key => $type) { $definition[$key] = $definition[0]; if ($type == 'clob' || $type == 'blob') { unset($definition[$key]['default']); } $definition[$key]['type'] = $type; $definition[$key]['mdb2type'] = $type; } return $definition; }
/** * Get the structure of a field into an array * * @param string $table name of table that should be used in method * @param string $field_name name of field that should be used in method * @return mixed data array on success, a MDB2 error on failure * @access public */ function getTableFieldDefinition($table, $field_name) { $db =& $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } $result = $db->loadModule('Datatype', null, true); if (PEAR::isError($result)) { return $result; } $table = $db->quoteIdentifier($table, true); $query = "SHOW COLUMNS FROM {$table} LIKE " . $db->quote($field_name); $columns = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC); if (PEAR::isError($columns)) { return $columns; } foreach ($columns as $column) { $column = array_change_key_case($column, CASE_LOWER); $column['name'] = $column['field']; unset($column['field']); if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { if ($db->options['field_case'] == CASE_LOWER) { $column['name'] = strtolower($column['name']); } else { $column['name'] = strtoupper($column['name']); } } else { $column = array_change_key_case($column, $db->options['field_case']); } if ($field_name == $column['name']) { $mapped_datatype = $db->datatype->mapNativeDatatype($column); if (PEAR::IsError($mapped_datatype)) { return $mapped_datatype; } list($types, $length, $unsigned, $fixed) = $mapped_datatype; $notnull = false; if (empty($column['null']) || $column['null'] !== 'YES') { $notnull = true; } $default = false; if (array_key_exists('default', $column)) { $default = $column['default']; if (is_null($default) && $notnull) { $default = ''; } } $autoincrement = false; if (!empty($column['extra']) && $column['extra'] == 'auto_increment') { $autoincrement = true; } $definition[0] = array('notnull' => $notnull, 'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])); if (!is_null($length)) { $definition[0]['length'] = $length; } if (!is_null($unsigned)) { $definition[0]['unsigned'] = $unsigned; } if (!is_null($fixed)) { $definition[0]['fixed'] = $fixed; } if ($default !== false) { $definition[0]['default'] = $default; } if ($autoincrement !== false) { $definition[0]['autoincrement'] = $autoincrement; } foreach ($types as $key => $type) { $definition[$key] = $definition[0]; if ($type == 'clob' || $type == 'blob') { unset($definition[$key]['default']); } $definition[$key]['type'] = $type; $definition[$key]['mdb2type'] = $type; } return $definition; } } return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, 'it was not specified an existing table column', __FUNCTION__); }
/** * Get the structure of a field into an array * * @param string $table name of table that should be used in method * @param string $field_name name of field that should be used in method * @return mixed data array on success, a MDB2 error on failure * @access public */ function getTableFieldDefinition($table, $field_name) { $db =& $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } $result = $db->loadModule('Datatype', null, true); if (PEAR::isError($result)) { return $result; } $table = $db->quoteIdentifier($table, true); $fldname = $db->quoteIdentifier($field_name, true); $query = "SELECT t.table_name,\n c.column_name 'name',\n c.data_type 'type',\n CASE c.is_nullable WHEN 'YES' THEN 1 ELSE 0 END AS 'is_nullable',\n \t\t c.column_default,\n \t\t c.character_maximum_length 'length',\n c.numeric_precision,\n c.numeric_scale,\n c.character_set_name,\n c.collation_name\n FROM INFORMATION_SCHEMA.TABLES t,\n INFORMATION_SCHEMA.COLUMNS c\n WHERE t.table_name = c.table_name\n AND t.table_name = '{$table}'\n AND c.column_name = '{$fldname}'\n ORDER BY t.table_name"; $column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); if (PEAR::isError($column)) { return $column; } if (empty($column)) { return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, 'it was not specified an existing table column', __FUNCTION__); } if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { if ($db->options['field_case'] == CASE_LOWER) { $column['name'] = strtolower($column['name']); } else { $column['name'] = strtoupper($column['name']); } } else { $column = array_change_key_case($column, $db->options['field_case']); } $mapped_datatype = $db->datatype->mapNativeDatatype($column); if (PEAR::IsError($mapped_datatype)) { return $mapped_datatype; } list($types, $length, $unsigned, $fixed) = $mapped_datatype; $notnull = true; if ($column['is_nullable']) { $notnull = false; } $default = false; if (array_key_exists('column_default', $column)) { $default = $column['column_default']; if (is_null($default) && $notnull) { $default = ''; } elseif (strlen($default) > 4 && substr($default, 0, 1) == '(' && substr($default, -1, 1) == ')') { //mssql wraps the default value in parentheses: "((1234))", "(NULL)" $default = trim($default, '()'); if ($default == 'NULL') { $default = null; } } } $definition[0] = array('notnull' => $notnull, 'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])); if (!is_null($length)) { $definition[0]['length'] = $length; } if (!is_null($unsigned)) { $definition[0]['unsigned'] = $unsigned; } if (!is_null($fixed)) { $definition[0]['fixed'] = $fixed; } if ($default !== false) { $definition[0]['default'] = $default; } foreach ($types as $key => $type) { $definition[$key] = $definition[0]; if ($type == 'clob' || $type == 'blob') { unset($definition[$key]['default']); } $definition[$key]['type'] = $type; $definition[$key]['mdb2type'] = $type; } return $definition; }
/** * Get the structure of a field into an array * * @param string $table name of table that should be used in method * @param string $field_name name of field that should be used in method * @return mixed data array on success, a MDB2 error on failure * @access public */ function getTableFieldDefinition($table, $field_name) { $db =& $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } $result = $db->loadModule('Datatype', null, true); if (PEAR::isError($result)) { return $result; } $table = $db->quote(strtoupper($table), 'text'); $field_name = $db->quote(strtoupper($field_name), 'text'); $query = "SELECT RDB\$RELATION_FIELDS.RDB\$FIELD_NAME AS name,\n RDB\$FIELDS.RDB\$FIELD_LENGTH AS \"length\",\n RDB\$FIELDS.RDB\$FIELD_PRECISION AS \"precision\",\n (RDB\$FIELDS.RDB\$FIELD_SCALE * -1) AS \"scale\",\n RDB\$FIELDS.RDB\$FIELD_TYPE AS field_type_code,\n RDB\$FIELDS.RDB\$FIELD_SUB_TYPE AS field_sub_type_code,\n RDB\$RELATION_FIELDS.RDB\$DESCRIPTION AS description,\n RDB\$RELATION_FIELDS.RDB\$NULL_FLAG AS null_flag,\n RDB\$FIELDS.RDB\$DEFAULT_SOURCE AS default_source\n FROM RDB\$FIELDS\n LEFT JOIN RDB\$RELATION_FIELDS ON RDB\$FIELDS.RDB\$FIELD_NAME = RDB\$RELATION_FIELDS.RDB\$FIELD_SOURCE\n WHERE UPPER(RDB\$RELATION_FIELDS.RDB\$RELATION_NAME)={$table}\n AND UPPER(RDB\$RELATION_FIELDS.RDB\$FIELD_NAME)={$field_name};"; $column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); if (PEAR::isError($column)) { return $column; } if (empty($column)) { return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, 'it was not specified an existing table column', __FUNCTION__); } $column = array_change_key_case($column, CASE_LOWER); if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { if ($db->options['field_case'] == CASE_LOWER) { $column['name'] = strtolower($column['name']); } else { $column['name'] = strtoupper($column['name']); } } $column['type'] = array_key_exists((int) $column['field_type_code'], $this->types) ? $this->types[(int) $column['field_type_code']] : 'undefined'; if ($column['field_sub_type_code'] && array_key_exists((int) $column['field_type_code'], $this->subtypes) && array_key_exists($column['field_sub_type_code'], $this->subtypes[(int) $column['field_type_code']])) { $column['field_sub_type'] = $this->subtypes[(int) $column['field_type_code']][$column['field_sub_type_code']]; } else { $column['field_sub_type'] = null; } $mapped_datatype = $db->datatype->mapNativeDatatype($column); if (PEAR::IsError($mapped_datatype)) { return $mapped_datatype; } list($types, $length, $unsigned, $fixed) = $mapped_datatype; $notnull = !empty($column['null_flag']); $default = $column['default_source']; if (is_null($default) && $notnull) { $default = $types[0] == 'integer' ? 0 : ''; } $definition[0] = array('notnull' => $notnull, 'nativetype' => $column['type']); if (!is_null($length)) { $definition[0]['length'] = $length; } if (!is_null($unsigned)) { $definition[0]['unsigned'] = $unsigned; } if (!is_null($fixed)) { $definition[0]['fixed'] = $fixed; } if ($default !== false) { $definition[0]['default'] = $default; } foreach ($types as $key => $type) { $definition[$key] = $definition[0]; if ($type == 'clob' || $type == 'blob') { unset($definition[$key]['default']); } $definition[$key]['type'] = $type; $definition[$key]['mdb2type'] = $type; } return $definition; }
function getOutlines($iPlaceID, $fLon = null, $fLat = null, $fRadius = null) { $aOutlineResult = array(); if (!$iPlaceID) { return $aOutlineResult; } if (CONST_Search_AreaPolygons) { // Get the bounding box and outline polygon $sSQL = "select place_id,0 as numfeatures,st_area(geometry) as area,"; $sSQL .= "ST_Y(centroid) as centrelat,ST_X(centroid) as centrelon,"; $sSQL .= "ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,"; $sSQL .= "ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon"; if ($this->bIncludePolygonAsGeoJSON) { $sSQL .= ",ST_AsGeoJSON(geometry) as asgeojson"; } if ($this->bIncludePolygonAsKML) { $sSQL .= ",ST_AsKML(geometry) as askml"; } if ($this->bIncludePolygonAsSVG) { $sSQL .= ",ST_AsSVG(geometry) as assvg"; } if ($this->bIncludePolygonAsText || $this->bIncludePolygonAsPoints) { $sSQL .= ",ST_AsText(geometry) as astext"; } $sFrom = " from placex where place_id = " . $iPlaceID; if ($this->fPolygonSimplificationThreshold > 0) { $sSQL .= " from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry," . $this->fPolygonSimplificationThreshold . ") as geometry" . $sFrom . ") as plx"; } else { $sSQL .= $sFrom; } $aPointPolygon = $this->oDB->getRow($sSQL); if (PEAR::IsError($aPointPolygon)) { echo var_dump($aPointPolygon); failInternalError("Could not get outline.", $sSQL, $aPointPolygon); } if ($aPointPolygon['place_id']) { if ($aPointPolygon['centrelon'] !== null && $aPointPolygon['centrelat'] !== null) { $aOutlineResult['lat'] = $aPointPolygon['centrelat']; $aOutlineResult['lon'] = $aPointPolygon['centrelon']; } if ($this->bIncludePolygonAsGeoJSON) { $aOutlineResult['asgeojson'] = $aPointPolygon['asgeojson']; } if ($this->bIncludePolygonAsKML) { $aOutlineResult['askml'] = $aPointPolygon['askml']; } if ($this->bIncludePolygonAsSVG) { $aOutlineResult['assvg'] = $aPointPolygon['assvg']; } if ($this->bIncludePolygonAsText) { $aOutlineResult['astext'] = $aPointPolygon['astext']; } if ($this->bIncludePolygonAsPoints) { $aOutlineResult['aPolyPoints'] = geometryText2Points($aPointPolygon['astext'], $fRadius); } if (abs($aPointPolygon['minlat'] - $aPointPolygon['maxlat']) < 1.0E-7) { $aPointPolygon['minlat'] = $aPointPolygon['minlat'] - $fRadius; $aPointPolygon['maxlat'] = $aPointPolygon['maxlat'] + $fRadius; } if (abs($aPointPolygon['minlon'] - $aPointPolygon['maxlon']) < 1.0E-7) { $aPointPolygon['minlon'] = $aPointPolygon['minlon'] - $fRadius; $aPointPolygon['maxlon'] = $aPointPolygon['maxlon'] + $fRadius; } $aOutlineResult['aBoundingBox'] = array((string) $aPointPolygon['minlat'], (string) $aPointPolygon['maxlat'], (string) $aPointPolygon['minlon'], (string) $aPointPolygon['maxlon']); } } // CONST_Search_AreaPolygons // as a fallback we generate a bounding box without knowing the size of the geometry if (!isset($aOutlineResult['aBoundingBox']) && isset($fLon)) { if ($this->bIncludePolygonAsPoints) { $sGeometryText = 'POINT(' . $fLon . ',' . $fLat . ')'; $aOutlineResult['aPolyPoints'] = geometryText2Points($sGeometryText, $fRadius); } $aBounds = array(); $aBounds['minlat'] = $fLat - $fRadius; $aBounds['maxlat'] = $fLat + $fRadius; $aBounds['minlon'] = $fLon - $fRadius; $aBounds['maxlon'] = $fLon + $fRadius; $aOutlineResult['aBoundingBox'] = array((string) $aBounds['minlat'], (string) $aBounds['maxlat'], (string) $aBounds['minlon'], (string) $aBounds['maxlon']); } return $aOutlineResult; }
# http://pear.php.net/manual/en/package.mail.mail-mime.php ##--------------------------------------------------- ## OBSERVAÇÃO: Caso deseje um exemplo de como enviar arquivos em anexo, ## gere um script com "Formato do e-mail" igual a "HTML". # Faz o include do PEAR Mail. include "Mail.php"; # E-mail de destino. Caso seja mais de um destino, crie um array de e-mails. # *OBRIGATÓRIO* $recipients = '*****@*****.**'; # Cabeçalho do e-mail. $headers = array('From' => '*****@*****.**', 'To' => '*****@*****.**', 'Subject' => $motivo, 'Date' => date('r'), 'Reply-To' => $email); # Utilize esta opção caso deseje definir o e-mail de resposta # $headers['Reply-To'] = '*****@*****.**'; # Utilize esta opção caso deseje definir o e-mail de retorno em caso de erro de envio # $headers['Errors-To'] = '*****@*****.**'; # Utilize esta opção caso deseje definir a prioridade do e-mail # $headers['X-Priority'] = '3'; # 1 UrgentMessage, 3 Normal # Corpo da Mensagem $body = $txt; # Parâmetros para o SMTP. *OBRIGATÓRIO* $params = array('auth' => true, 'host' => 'smtp.funcionalstudio.com.br', 'username' => 'contato=funcionalstudio.com.br', 'password' => 'contato5535'); # Define o método de envio! queremos 'smtp'. *OBRIGATÓRIO* $mail_object =& Mail::factory('smtp', $params); # Envia o email. Se não ocorrer erro, retorna TRUE caso contrário, retorna um # objeto PEAR_Error. Para ler a mensagem de erro, use o método 'getMessage()'. $result = $mail_object->send($recipients, $headers, $body); if (PEAR::IsError($result)) { echo "<script>alert('Erro ao enviar o e-mail. Tente novamente por favor.');window.location.href='http://'+window.location.hostname+'/contato.html';</script>"; } else { echo "<script>alert('E-mail enviado com sucesso!');window.location.href='http://'+window.location.hostname+'/contato.html';</script>"; }
function lookup() { $sPointSQL = 'ST_SetSRID(ST_Point(' . $this->fLon . ',' . $this->fLat . '),4326)'; $iMaxRank = $this->iMaxRank; $iMaxRank_orig = $this->iMaxRank; // Find the nearest point $fSearchDiam = 0.0004; $iPlaceID = null; $aArea = false; $fMaxAreaDistance = 1; $bIsInUnitedStates = false; $bPlaceIsTiger = false; while (!$iPlaceID && $fSearchDiam < $fMaxAreaDistance) { $fSearchDiam = $fSearchDiam * 2; // If we have to expand the search area by a large amount then we need a larger feature // then there is a limit to how small the feature should be if ($fSearchDiam > 2 && $iMaxRank > 4) { $iMaxRank = 4; } if ($fSearchDiam > 1 && $iMaxRank > 9) { $iMaxRank = 8; } if ($fSearchDiam > 0.8 && $iMaxRank > 10) { $iMaxRank = 10; } if ($fSearchDiam > 0.6 && $iMaxRank > 12) { $iMaxRank = 12; } if ($fSearchDiam > 0.2 && $iMaxRank > 17) { $iMaxRank = 17; } if ($fSearchDiam > 0.1 && $iMaxRank > 18) { $iMaxRank = 18; } if ($fSearchDiam > 0.008 && $iMaxRank > 22) { $iMaxRank = 22; } if ($fSearchDiam > 0.001 && $iMaxRank > 26) { $iMaxRank = 26; } $sSQL = 'select place_id,parent_place_id,rank_search,calculated_country_code from placex'; $sSQL .= ' WHERE ST_DWithin(' . $sPointSQL . ', geometry, ' . $fSearchDiam . ')'; $sSQL .= ' and rank_search != 28 and rank_search >= ' . $iMaxRank; $sSQL .= ' and (name is not null or housenumber is not null)'; $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')'; $sSQL .= ' and indexed_status = 0 '; $sSQL .= ' and (ST_GeometryType(geometry) not in (\'ST_Polygon\',\'ST_MultiPolygon\') '; $sSQL .= ' OR ST_DWithin(' . $sPointSQL . ', centroid, ' . $fSearchDiam . '))'; $sSQL .= ' ORDER BY ST_distance(' . $sPointSQL . ', geometry) ASC limit 1'; if (CONST_Debug) { var_dump($sSQL); } $aPlace = $this->oDB->getRow($sSQL); if (PEAR::IsError($aPlace)) { failInternalError("Could not determine closest place.", $sSQL, $aPlace); } $iPlaceID = $aPlace['place_id']; $iParentPlaceID = $aPlace['parent_place_id']; $bIsInUnitedStates = $aPlace['calculated_country_code'] == 'us'; } // Only street found? If it's in the US we can check TIGER data for nearest housenumber if ($bIsInUnitedStates && $iMaxRank_orig >= 28 && $iPlaceID && ($aPlace['rank_search'] == 26 || $aPlace['rank_search'] == 27)) { $fSearchDiam = 0.001; $sSQL = 'SELECT place_id,parent_place_id,30 as rank_search '; if (CONST_Debug) { $sSQL .= ', housenumber, ST_distance(' . $sPointSQL . ', centroid) as distance, st_y(centroid) as lat, st_x(centroid) as lon'; } $sSQL .= ' FROM location_property_tiger WHERE parent_place_id = ' . $iPlaceID; $sSQL .= ' AND ST_DWithin(' . $sPointSQL . ', centroid, ' . $fSearchDiam . ')'; $sSQL .= ' ORDER BY ST_distance(' . $sPointSQL . ', centroid) ASC limit 1'; // print all house numbers in the parent (street) if (CONST_Debug) { $sSQL = preg_replace('/limit 1/', 'limit 100', $sSQL); var_dump($sSQL); $aAllHouses = $this->oDB->getAll($sSQL); foreach ($aAllHouses as $i) { echo $i['housenumber'] . ' | ' . $i['distance'] * 1000 . ' | ' . $i['lat'] . ' | ' . $i['lon'] . ' | ' . "<br>\n"; } } $aPlaceTiger = $this->oDB->getRow($sSQL); if (PEAR::IsError($aPlace)) { failInternalError("Could not determine closest Tiger place.", $sSQL, $aPlaceTiger); } if ($aPlaceTiger) { if (CONST_Debug) { var_dump('found Tiger place', $aPlaceTiger); } $bPlaceIsTiger = true; $aPlace = $aPlaceTiger; $iPlaceID = $aPlaceTiger['place_id']; $iParentPlaceID = $aPlaceTiger['parent_place_id']; // the street } } // The point we found might be too small - use the address to find what it is a child of if ($iPlaceID && $iMaxRank < 28) { if ($aPlace['rank_search'] > 28 && $iParentPlaceID && !$bPlaceIsTiger) { $iPlaceID = $iParentPlaceID; } $sSQL = "select address_place_id from place_addressline where place_id = {$iPlaceID} order by abs(cached_rank_address - {$iMaxRank}) asc,cached_rank_address desc,isaddress desc,distance desc limit 1"; $iPlaceID = $this->oDB->getOne($sSQL); if (PEAR::IsError($iPlaceID)) { failInternalError("Could not get parent for place.", $sSQL, $iPlaceID); } if (!$iPlaceID) { $iPlaceID = $aPlace['place_id']; } } return array('place_id' => $iPlaceID, 'type' => $bPlaceIsTiger ? 'tiger' : 'osm'); }
/** * send() * * Method to send the prepared email, the prepare method * must be called prior to calling this function. * * %attachments must be an associative array with the * following stucture. * $attachments['data'] = The actual attachment data * $attachments['name'] = The filename of the attachment * $attachments['type'] = The mime content type, defaults to application/octet-stream * $attachments['encoding'] = The type of encoding to be used, defaults to base64 * * $headers must be an associative array with the * key being the header name like so. * $header['Reply-To'] = "*****@*****.**" * * If you include values for Subject or From in the $headers * array they will be used instead of the respective values * from the prepared notification * * @param array $attachments Array of items to attach * @param array $headers Array of additonal headers to be included * @return boolean TRUE on success, FALSE on error. See getLastError() for the reason */ function send($attachments = NULL, $headers = NULL){ if($this->active == 'N'){ $this->error = "Notification::send(): Skipping inactive message!"; return TRUE; } if(empty($this->prepared_body) || empty($this->prepared_addresses)){ $this->error = "Notification::send(): Skipping message with empty body or addresses!"; var_dump($this); var_dump($this->parameters); return FALSE; } if($headers != NULL && !is_array($headers)){ $this->error = "Notification::send(): Invalid headers provided!"; return FALSE; }else{ $found_from = FALSE; $found_subject = FALSE; foreach($headers as $header => $value){ if(strtolower($header) == "from") $found_from = TRUE; elseif(strtolower($header) == "subject") $found_subject = TRUE; } if(!$found_from) $headers['From'] = $this->prepared_from; if(!$found_subject) $headers['Subject'] = $this->prepared_subject; } $mime = new Mail_mime(); $mime->setTXTBody($this->prepared_body); if(is_array($attachments) && count($attachments) > 0){ foreach($attachments as $attach){ if(empty($attach['data']) || empty($attach['name'])){ $this->error = "Notification::send(): Invalid attachment!"; return FALSE; } if(!isset($attach['type'])) $attach['type'] = 'application/octet-stream'; if(!isset($attach['encoding'])) $attach['encoding'] = 'base64'; $result = $mime->addAttachment($attach['data'], $attach['type'], $attach['name'], FALSE, $attach['encoding']); if(PEAR::IsError($result)){ $this->error = "Notification::send(): Error adding attachment: ".$result->getMessage(); return FALSE; } } } $message = $mime->get(); $headers = $mime->headers($headers); $mailer = Mail::factory('mail'); $result = $mailer->send($this->prepared_addresses, $headers, $message); if(PEAR::IsError($result)){ $this->error = "Notification::send(): Error sending message: ".$result->getMessage(); return FALSE; } return TRUE; }
/** * Get the structure of a field into an array * * @param string $table name of table that should be used in method * @param string $field_name name of field that should be used in method * @return mixed data array on success, a MDB2 error on failure * @access public */ function getTableFieldDefinition($table, $field_name) { $db =& $this->getDBInstance(); if (PEAR::isError($db)) { return $db; } $result = $db->loadModule('Datatype', null, true); if (PEAR::isError($result)) { return $result; } $query = 'SELECT column_name name, data_type "type", nullable, data_default "default"'; $query .= ', COALESCE(data_precision, data_length) "length", data_scale "scale"'; $query .= ' FROM user_tab_columns'; $query .= ' WHERE (table_name=' . $db->quote($table, 'text') . ' OR table_name=' . $db->quote(strtoupper($table), 'text') . ')'; $query .= ' AND (column_name=' . $db->quote($field_name, 'text') . ' OR column_name=' . $db->quote(strtoupper($field_name), 'text') . ')'; $query .= ' ORDER BY column_id'; $column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC); if (PEAR::isError($column)) { return $column; } if (empty($column)) { return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, 'it was not specified an existing table column', __FUNCTION__); } $column = array_change_key_case($column, CASE_LOWER); if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { if ($db->options['field_case'] == CASE_LOWER) { $column['name'] = strtolower($column['name']); } else { $column['name'] = strtoupper($column['name']); } } $mapped_datatype = $db->datatype->mapNativeDatatype($column); if (PEAR::IsError($mapped_datatype)) { return $mapped_datatype; } list($types, $length, $unsigned, $fixed) = $mapped_datatype; $notnull = false; if (!empty($column['nullable']) && $column['nullable'] == 'N') { $notnull = true; } $default = false; if (array_key_exists('default', $column)) { $default = $column['default']; if ($default === 'NULL') { $default = null; } if (is_null($default) && $notnull) { $default = ''; } } $definition[0] = array('notnull' => $notnull, 'nativetype' => $column['type']); if (!is_null($length)) { $definition[0]['length'] = $length; } if (!is_null($unsigned)) { $definition[0]['unsigned'] = $unsigned; } if (!is_null($fixed)) { $definition[0]['fixed'] = $fixed; } if ($default !== false) { $definition[0]['default'] = $default; } foreach ($types as $key => $type) { $definition[$key] = $definition[0]; if ($type == 'clob' || $type == 'blob') { unset($definition[$key]['default']); } $definition[$key]['type'] = $type; $definition[$key]['mdb2type'] = $type; } if ($type == 'integer') { $query = "SELECT DISTINCT name\r\n FROM all_source\r\n WHERE type='TRIGGER'\r\n AND UPPER(text) like '%ON " . strtoupper($db->escape($table, 'text')) . "%'"; $result = $db->query($query); if (!PEAR::isError($result)) { while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) { $row = array_change_key_case($row, CASE_LOWER); $trquery = 'SELECT text FROM all_source WHERE name=' . $db->quote($row['name'], 'text') . ' ORDER BY line'; $triggersth = $db->query($trquery); $triggerstr = ''; while ($triggerline = $triggersth->fetchRow(MDB2_FETCHMODE_ASSOC)) { $triggerline = array_change_key_case($triggerline, CASE_LOWER); $triggerstr .= $triggerline['text'] . ' '; } $matches = array(); if (preg_match('/.*\\W(.+)\\.nextval into :NEW\\.' . $field_name . ' FROM dual/i', $triggerstr, $matches)) { // we reckon it's an autoincrementing trigger on field_name // there will be other pcre patterns needed here for other ways of mimicking auto_increment in ora. $definition[0]['autoincrement'] = $matches[1]; } } } } return $definition; }
function indexSector($oDB, $aSector, $fMaxBlocking, $fMaxLoad) { $iNum = $aSector['count']; $iRank = $aSector['rank']; $fNumSteps = ceil(sqrt($iNum) / 10); $iNumSteps = $fNumSteps * $fNumSteps; if ($fNumSteps > 1) { $iStepNum = 1; echo "Spliting into " . $fNumSteps * $fNumSteps . " steps\n"; // Convert sector number back to lat lon $fLon = 500 - floor($aSector['geometry_index'] / 1000) - 0.5; $fLat = 500 - $aSector['geometry_index'] % 1000 - 0.5; $fStepSize = 1 / $fNumSteps; for ($fStepLat = $fLat; $fStepLat < $fLat + 1; $fStepLat += $fStepSize) { for ($fStepLon = $fLon; $fStepLon < $fLon + 1; $fStepLon += $fStepSize) { while (getBlockingProcesses() > $fMaxBlocking || getLoadAverage() > $fMaxLoad) { echo "System busy, pausing indexing...\n"; sleep(60); } $fStepLonTop = $fStepLon + $fStepSize; $fStepLatTop = $fStepLat + $fStepSize; echo " Step {$iStepNum} of {$iNumSteps}: ({$fStepLon},{$fStepLat},{$fStepLonTop},{$fStepLatTop})\n"; $sSQL = 'update placex set indexed = true where geometry_index(geometry,indexed,name) = ' . $aSector['geometry_index'] . ' and rank_search = ' . $iRank; $sSQL .= " and ST_Contains(ST_SetSRID(ST_MakeBox2D(ST_SetSRID(ST_POINT({$fStepLon},{$fStepLat}),4326),ST_SetSRID(ST_POINT({$fStepLonTop},{$fStepLatTop}),4326)),4326),geometry)"; if (PEAR::IsError($xError = $oDB->query($sSQL))) { var_dump($xError); exit; } $iStepNum++; } } } $sSQL = 'update placex set indexed = true where geometry_index(geometry,indexed,name) = ' . $aSector['geometry_index'] . ' and rank_search = ' . $iRank; if (PEAR::IsError($xError = $oDB->query($sSQL))) { var_dump($xError); exit; } $oDB->query($sSQL); }
} $hLog = logStart($oDB, 'details', $_SERVER['QUERY_STRING'], $aLangPrefOrder); // Make sure the point we are reporting on is fully indexed //$sSQL = "UPDATE placex set indexed = true where indexed = false and place_id = $iPlaceID"; //$oDB->query($sSQL); // Get the details for this point $sSQL = "select place_id, osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, calculated_country_code as country_code, importance, wikipedia,"; $sSQL .= " to_char(indexed_date, 'YYYY-MM-DD HH24:MI') as indexed_date, parent_place_id, rank_address, rank_search, get_searchrank_label(rank_search) as rank_search_label, get_name_by_language(name,{$sLanguagePrefArraySQL}) as localname, "; $sSQL .= " ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') as isarea, "; //$sSQL .= " ST_Area(geometry::geography) as area, "; $sSQL .= " ST_y(centroid) as lat, ST_x(centroid) as lon,"; $sSQL .= " case when importance = 0 OR importance IS NULL then 0.75-(rank_search::float/40) else importance end as calculated_importance, "; $sSQL .= " ST_AsText(CASE WHEN ST_NPoints(geometry) > 5000 THEN ST_SimplifyPreserveTopology(geometry, 0.0001) ELSE geometry END) as outlinestring"; $sSQL .= " from placex where place_id = {$iPlaceID}"; $aPointDetails = $oDB->getRow($sSQL); if (PEAR::IsError($aPointDetails)) { failInternalError("Could not get details of place object.", $sSQL, $aPointDetails); } $aPointDetails['localname'] = $aPointDetails['localname'] ? $aPointDetails['localname'] : $aPointDetails['housenumber']; $aClassType = getClassTypesWithImportance(); $aPointDetails['icon'] = $aClassType[$aPointDetails['class'] . ':' . $aPointDetails['type']]['icon']; // Get all alternative names (languages, etc) $sSQL = "select (each(name)).key,(each(name)).value from placex where place_id = {$iPlaceID} order by (each(name)).key"; $aPointDetails['aNames'] = $oDB->getAssoc($sSQL); // Extra tags $sSQL = "select (each(extratags)).key,(each(extratags)).value from placex where place_id = {$iPlaceID} order by (each(extratags)).key"; $aPointDetails['aExtraTags'] = $oDB->getAssoc($sSQL); // Address $aAddressLines = getAddressDetails($oDB, $sLanguagePrefArraySQL, $iPlaceID, $aPointDetails['country_code'], true); // Linked places $sSQL = "select placex.place_id, osm_type, osm_id, class, type, housenumber, admin_level, rank_address, ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') as isarea, st_distance(geometry, placegeometry) as distance, ";
<?php require_once 'settings.php'; require_once 'lib.php'; require_once 'DB.php'; if (get_magic_quotes_gpc()) { echo "Please disable magic quotes in your php.ini configuration"; exit; } if (CONST_ClosedForIndexing && strpos(CONST_ClosedForIndexingExceptionIPs, ',' . $_SERVER["REMOTE_ADDR"] . ',') === false) { echo "Closed for re-indexing..."; exit; } if (strpos(CONST_BlockedIPs, ',' . $_SERVER["REMOTE_ADDR"] . ',') !== false) { echo "Your IP has been blocked. \n"; echo "Please create a nominatim trac ticket (http://trac.openstreetmap.org/newticket?component=nominatim) to request this to be removed. \n"; echo "Information on the Nominatim usage policy can be found here: http://wiki.openstreetmap.org/wiki/Nominatim#Usage_Policy \n"; exit; } // Get the database object $oDB =& DB::connect(CONST_Database_DSN, false); if (PEAR::IsError($oDB)) { fail($oDB->getMessage(), 'Unable to connect to the database'); } $oDB->setFetchMode(DB_FETCHMODE_ASSOC); $oDB->query("SET DateStyle TO 'sql,european'"); $oDB->query("SET client_encoding TO 'utf-8'"); header('Content-type: text/html; charset=utf-8');
function geocodeReverse($fLat, $fLon, $iZoom = 18) { $oDB =& getDB(); $sPointSQL = "ST_SetSRID(ST_Point({$fLon},{$fLat}),4326)"; // Zoom to rank, this could probably be calculated but a lookup gives fine control $aZoomRank = array(0 => 2, 1 => 2, 2 => 2, 3 => 4, 4 => 4, 5 => 8, 6 => 10, 7 => 10, 8 => 12, 9 => 12, 10 => 17, 11 => 17, 12 => 18, 13 => 18, 14 => 22, 15 => 22, 16 => 26, 17 => 26, 18 => 30, 19 => 30); $iMaxRank = isset($aZoomRank[$iZoom]) ? $aZoomRank[$iZoom] : 28; // Find the nearest point $fSearchDiam = 0.0001; $iPlaceID = null; $aArea = false; $fMaxAreaDistance = 1; while (!$iPlaceID && $fSearchDiam < $fMaxAreaDistance) { $fSearchDiam = $fSearchDiam * 2; // If we have to expand the search area by a large amount then we need a larger feature // then there is a limit to how small the feature should be if ($fSearchDiam > 2 && $iMaxRank > 4) { $iMaxRank = 4; } if ($fSearchDiam > 1 && $iMaxRank > 9) { $iMaxRank = 8; } if ($fSearchDiam > 0.8 && $iMaxRank > 10) { $iMaxRank = 10; } if ($fSearchDiam > 0.6 && $iMaxRank > 12) { $iMaxRank = 12; } if ($fSearchDiam > 0.2 && $iMaxRank > 17) { $iMaxRank = 17; } if ($fSearchDiam > 0.1 && $iMaxRank > 18) { $iMaxRank = 18; } if ($fSearchDiam > 0.008 && $iMaxRank > 22) { $iMaxRank = 22; } if ($fSearchDiam > 0.001 && $iMaxRank > 26) { $iMaxRank = 26; } $sSQL = 'select place_id,parent_place_id from placex'; $sSQL .= ' WHERE ST_DWithin(' . $sPointSQL . ', geometry, ' . $fSearchDiam . ')'; $sSQL .= ' and rank_search != 28 and rank_search >= ' . $iMaxRank; $sSQL .= ' and (name is not null or housenumber is not null)'; $sSQL .= ' and class not in (\'waterway\')'; $sSQL .= ' and (ST_GeometryType(geometry) not in (\'ST_Polygon\',\'ST_MultiPolygon\') '; $sSQL .= ' OR ST_DWithin(' . $sPointSQL . ', ST_Centroid(geometry), ' . $fSearchDiam . '))'; $sSQL .= ' ORDER BY ST_distance(' . $sPointSQL . ', geometry) ASC limit 1'; //var_dump($sSQL); $aPlace = $oDB->getRow($sSQL); $iPlaceID = $aPlace['place_id']; if (PEAR::IsError($iPlaceID)) { var_Dump($sSQL, $iPlaceID); exit; } } // The point we found might be too small - use the address to find what it is a child of if ($iPlaceID) { $sSQL = "select address_place_id from place_addressline where cached_rank_address <= {$iMaxRank} and place_id = {$iPlaceID} order by cached_rank_address desc,isaddress desc,distance desc limit 1"; $iPlaceID = $oDB->getOne($sSQL); if (PEAR::IsError($iPlaceID)) { var_Dump($sSQL, $iPlaceID); exit; } if ($iPlaceID && $aPlace['place_id'] && $iMaxRank < 28) { $sSQL = "select address_place_id from place_addressline where cached_rank_address <= {$iMaxRank} and place_id = " . $aPlace['place_id'] . " order by cached_rank_address desc,isaddress desc,distance desc"; $iPlaceID = $oDB->getOne($sSQL); if (PEAR::IsError($iPlaceID)) { var_Dump($sSQL, $iPlaceID); exit; } } if (!$iPlaceID) { $iPlaceID = $aPlace['place_id']; } } return $iPlaceID; }
function getAddressDetails(&$oDB, $sLanguagePrefArraySQL, $iPlaceID, $sCountryCode = false, $bRaw = false) { $sHouseNumber = $oDB->getOne('select housenumber from placex where place_id = ' . $iPlaceID); // 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})"; // and isaddress"; if ($sCountryCode) { $sSQL .= " and (placex.country_code IS NULL OR placex.country_code = '" . $sCountryCode . "' OR rank_address < 4)"; } $sSQL .= " order by cached_rank_address 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 ($sHouseNumber) { $aAddress['house_number'] = $sHouseNumber; } foreach ($aAddressLines as $aLine) { if (!$sCountryCode) { $sCountryCode = $aLine['country_code']; } if ($aLine['rank_address'] < $iMinRank) { $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']); if (!isset($aAddress[$sTypeLabel]) && $aLine['localname']) { $aAddress[$sTypeLabel] = $aLine['localname'] ? $aLine['localname'] : $aLine['housenumber']; } } $iMinRank = $aLine['rank_address']; } } 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) { $aAddress['country'] = $sCountryName; } } if ($sCountryCode) { $aAddress['country_code'] = $sCountryCode; } return $aAddress; }
function lookup() { if (!$this->sQuery && !$this->aStructuredQuery) { return false; } $sLanguagePrefArraySQL = "ARRAY[" . join(',', array_map("getDBQuoted", $this->aLangPrefOrder)) . "]"; $sCountryCodesSQL = false; if ($this->aCountryCodes && sizeof($this->aCountryCodes)) { $sCountryCodesSQL = join(',', array_map('addQuotes', $this->aCountryCodes)); } $sQuery = $this->sQuery; // Conflicts between US state abreviations and various words for 'the' in different languages if (isset($this->aLangPrefOrder['name:en'])) { $sQuery = preg_replace('/(^|,)\\s*il\\s*(,|$)/', '\\1illinois\\2', $sQuery); $sQuery = preg_replace('/(^|,)\\s*al\\s*(,|$)/', '\\1alabama\\2', $sQuery); $sQuery = preg_replace('/(^|,)\\s*la\\s*(,|$)/', '\\1louisiana\\2', $sQuery); } // View Box SQL $sViewboxCentreSQL = false; $bBoundingBoxSearch = false; if ($this->aViewBox) { $fHeight = $this->aViewBox[0] - $this->aViewBox[2]; $fWidth = $this->aViewBox[1] - $this->aViewBox[3]; $aBigViewBox[0] = $this->aViewBox[0] + $fHeight; $aBigViewBox[2] = $this->aViewBox[2] - $fHeight; $aBigViewBox[1] = $this->aViewBox[1] + $fWidth; $aBigViewBox[3] = $this->aViewBox[3] - $fWidth; $this->sViewboxSmallSQL = "ST_SetSRID(ST_MakeBox2D(ST_Point(" . (double) $this->aViewBox[0] . "," . (double) $this->aViewBox[1] . "),ST_Point(" . (double) $this->aViewBox[2] . "," . (double) $this->aViewBox[3] . ")),4326)"; $this->sViewboxLargeSQL = "ST_SetSRID(ST_MakeBox2D(ST_Point(" . (double) $aBigViewBox[0] . "," . (double) $aBigViewBox[1] . "),ST_Point(" . (double) $aBigViewBox[2] . "," . (double) $aBigViewBox[3] . ")),4326)"; $bBoundingBoxSearch = $this->bBoundedSearch; } // Route SQL if ($this->aRoutePoints) { $sViewboxCentreSQL = "ST_SetSRID('LINESTRING("; $bFirst = true; foreach ($this->aRoutePoints as $aPoint) { if (!$bFirst) { $sViewboxCentreSQL .= ","; } $sViewboxCentreSQL .= $aPoint[0] . ' ' . $aPoint[1]; $bFirst = false; } $sViewboxCentreSQL .= ")'::geometry,4326)"; $sSQL = "select st_buffer(" . $sViewboxCentreSQL . "," . (double) ($_GET['routewidth'] / 69) . ")"; $this->sViewboxSmallSQL = $this->oDB->getOne($sSQL); if (PEAR::isError($this->sViewboxSmallSQL)) { failInternalError("Could not get small viewbox.", $sSQL, $this->sViewboxSmallSQL); } $this->sViewboxSmallSQL = "'" . $this->sViewboxSmallSQL . "'::geometry"; $sSQL = "select st_buffer(" . $sViewboxCentreSQL . "," . (double) ($_GET['routewidth'] / 30) . ")"; $this->sViewboxLargeSQL = $this->oDB->getOne($sSQL); if (PEAR::isError($this->sViewboxLargeSQL)) { failInternalError("Could not get large viewbox.", $sSQL, $this->sViewboxLargeSQL); } $this->sViewboxLargeSQL = "'" . $this->sViewboxLargeSQL . "'::geometry"; $bBoundingBoxSearch = $this->bBoundedSearch; } // Do we have anything that looks like a lat/lon pair? if ($aLooksLike = looksLikeLatLonPair($sQuery)) { $this->setNearPoint(array($aLooksLike['lat'], $aLooksLike['lon'])); $sQuery = $aLooksLike['query']; } $aSearchResults = array(); if ($sQuery || $this->aStructuredQuery) { // Start with a blank search $aSearches = array(array('iSearchRank' => 0, 'iNamePhrase' => -1, 'sCountryCode' => false, 'aName' => array(), 'aAddress' => array(), 'aFullNameAddress' => array(), 'aNameNonSearch' => array(), 'aAddressNonSearch' => array(), 'sOperator' => '', 'aFeatureName' => array(), 'sClass' => '', 'sType' => '', 'sHouseNumber' => '', 'fLat' => '', 'fLon' => '', 'fRadius' => '')); // Do we have a radius search? $sNearPointSQL = false; if ($this->aNearPoint) { $sNearPointSQL = "ST_SetSRID(ST_Point(" . (double) $this->aNearPoint[1] . "," . (double) $this->aNearPoint[0] . "),4326)"; $aSearches[0]['fLat'] = (double) $this->aNearPoint[0]; $aSearches[0]['fLon'] = (double) $this->aNearPoint[1]; $aSearches[0]['fRadius'] = (double) $this->aNearPoint[2]; } // Any 'special' terms in the search? $bSpecialTerms = false; preg_match_all('/\\[(.*)=(.*)\\]/', $sQuery, $aSpecialTermsRaw, PREG_SET_ORDER); $aSpecialTerms = array(); foreach ($aSpecialTermsRaw as $aSpecialTerm) { $sQuery = str_replace($aSpecialTerm[0], ' ', $sQuery); $aSpecialTerms[strtolower($aSpecialTerm[1])] = $aSpecialTerm[2]; } preg_match_all('/\\[([\\w ]*)\\]/u', $sQuery, $aSpecialTermsRaw, PREG_SET_ORDER); $aSpecialTerms = array(); if (isset($this->aStructuredQuery['amenity']) && $this->aStructuredQuery['amenity']) { $aSpecialTermsRaw[] = array('[' . $this->aStructuredQuery['amenity'] . ']', $this->aStructuredQuery['amenity']); unset($this->aStructuredQuery['amenity']); } foreach ($aSpecialTermsRaw as $aSpecialTerm) { $sQuery = str_replace($aSpecialTerm[0], ' ', $sQuery); $sToken = $this->oDB->getOne("select make_standard_name('" . $aSpecialTerm[1] . "') as string"); $sSQL = 'select * from (select word_id,word_token, word, class, type, country_code, operator'; $sSQL .= ' from word where word_token in (\' ' . $sToken . '\')) as x where (class is not null and class not in (\'place\')) or country_code is not null'; if (CONST_Debug) { var_Dump($sSQL); } $aSearchWords = $this->oDB->getAll($sSQL); $aNewSearches = array(); foreach ($aSearches as $aSearch) { foreach ($aSearchWords as $aSearchTerm) { $aNewSearch = $aSearch; if ($aSearchTerm['country_code']) { $aNewSearch['sCountryCode'] = strtolower($aSearchTerm['country_code']); $aNewSearches[] = $aNewSearch; $bSpecialTerms = true; } if ($aSearchTerm['class']) { $aNewSearch['sClass'] = $aSearchTerm['class']; $aNewSearch['sType'] = $aSearchTerm['type']; $aNewSearches[] = $aNewSearch; $bSpecialTerms = true; } } } $aSearches = $aNewSearches; } // Split query into phrases // Commas are used to reduce the search space by indicating where phrases split if ($this->aStructuredQuery) { $aPhrases = $this->aStructuredQuery; $bStructuredPhrases = true; } else { $aPhrases = explode(',', $sQuery); $bStructuredPhrases = false; } // Convert each phrase to standard form // Create a list of standard words // Get all 'sets' of words // Generate a complete list of all $aTokens = array(); foreach ($aPhrases as $iPhrase => $sPhrase) { $aPhrase = $this->oDB->getRow("select make_standard_name('" . pg_escape_string($sPhrase) . "') as string"); if (PEAR::isError($aPhrase)) { userError("Illegal query string (not an UTF-8 string): " . $sPhrase); if (CONST_Debug) { var_dump($aPhrase); } exit; } if (trim($aPhrase['string'])) { $aPhrases[$iPhrase] = $aPhrase; $aPhrases[$iPhrase]['words'] = explode(' ', $aPhrases[$iPhrase]['string']); $aPhrases[$iPhrase]['wordsets'] = getWordSets($aPhrases[$iPhrase]['words'], 0); $aTokens = array_merge($aTokens, getTokensFromSets($aPhrases[$iPhrase]['wordsets'])); } else { unset($aPhrases[$iPhrase]); } } // Reindex phrases - we make assumptions later on that they are numerically keyed in order $aPhraseTypes = array_keys($aPhrases); $aPhrases = array_values($aPhrases); if (sizeof($aTokens)) { // Check which tokens we have, get the ID numbers $sSQL = 'select word_id,word_token, word, class, type, country_code, operator, search_name_count'; $sSQL .= ' from word where word_token in (' . join(',', array_map("getDBQuoted", $aTokens)) . ')'; if (CONST_Debug) { var_Dump($sSQL); } $aValidTokens = array(); if (sizeof($aTokens)) { $aDatabaseWords = $this->oDB->getAll($sSQL); } else { $aDatabaseWords = array(); } if (PEAR::IsError($aDatabaseWords)) { failInternalError("Could not get word tokens.", $sSQL, $aDatabaseWords); } $aPossibleMainWordIDs = array(); $aWordFrequencyScores = array(); foreach ($aDatabaseWords as $aToken) { // Very special case - require 2 letter country param to match the country code found if ($bStructuredPhrases && $aToken['country_code'] && !empty($this->aStructuredQuery['country']) && strlen($this->aStructuredQuery['country']) == 2 && strtolower($this->aStructuredQuery['country']) != $aToken['country_code']) { continue; } if (isset($aValidTokens[$aToken['word_token']])) { $aValidTokens[$aToken['word_token']][] = $aToken; } else { $aValidTokens[$aToken['word_token']] = array($aToken); } if (!$aToken['class'] && !$aToken['country_code']) { $aPossibleMainWordIDs[$aToken['word_id']] = 1; } $aWordFrequencyScores[$aToken['word_id']] = $aToken['search_name_count'] + 1; } if (CONST_Debug) { var_Dump($aPhrases, $aValidTokens); } // Try and calculate GB postcodes we might be missing foreach ($aTokens as $sToken) { // Source of gb postcodes is now definitive - always use if (preg_match('/^([A-Z][A-Z]?[0-9][0-9A-Z]? ?[0-9])([A-Z][A-Z])$/', strtoupper(trim($sToken)), $aData)) { if (substr($aData[1], -2, 1) != ' ') { $aData[0] = substr($aData[0], 0, strlen($aData[1]) - 1) . ' ' . substr($aData[0], strlen($aData[1]) - 1); $aData[1] = substr($aData[1], 0, -1) . ' ' . substr($aData[1], -1, 1); } $aGBPostcodeLocation = gbPostcodeCalculate($aData[0], $aData[1], $aData[2], $this->oDB); if ($aGBPostcodeLocation) { $aValidTokens[$sToken] = $aGBPostcodeLocation; } } else { if (!isset($aValidTokens[$sToken]) && preg_match('/^([0-9]{5}) [0-9]{4}$/', $sToken, $aData)) { if (isset($aValidTokens[$aData[1]])) { foreach ($aValidTokens[$aData[1]] as $aToken) { if (!$aToken['class']) { if (isset($aValidTokens[$sToken])) { $aValidTokens[$sToken][] = $aToken; } else { $aValidTokens[$sToken] = array($aToken); } } } } } } } foreach ($aTokens as $sToken) { // Unknown single word token with a number - assume it is a house number if (!isset($aValidTokens[' ' . $sToken]) && strpos($sToken, ' ') === false && preg_match('/[0-9]/', $sToken)) { $aValidTokens[' ' . $sToken] = array(array('class' => 'place', 'type' => 'house')); } } // Any words that have failed completely? // TODO: suggestions // Start the search process $aResultPlaceIDs = array(); $aGroupedSearches = $this->getGroupedSearches($aSearches, $aPhraseTypes, $aPhrases, $aValidTokens, $aWordFrequencyScores, $bStructuredPhrases); if ($this->bReverseInPlan) { // Reverse phrase array and also reverse the order of the wordsets in // the first and final phrase. Don't bother about phrases in the middle // because order in the address doesn't matter. $aPhrases = array_reverse($aPhrases); $aPhrases[0]['wordsets'] = getInverseWordSets($aPhrases[0]['words'], 0); if (sizeof($aPhrases) > 1) { $aFinalPhrase = end($aPhrases); $aPhrases[sizeof($aPhrases) - 1]['wordsets'] = getInverseWordSets($aFinalPhrase['words'], 0); } $aReverseGroupedSearches = $this->getGroupedSearches($aSearches, null, $aPhrases, $aValidTokens, $aWordFrequencyScores, false); foreach ($aGroupedSearches as $aSearches) { foreach ($aSearches as $aSearch) { if ($aSearch['iSearchRank'] < $this->iMaxRank) { if (!isset($aReverseGroupedSearches[$aSearch['iSearchRank']])) { $aReverseGroupedSearches[$aSearch['iSearchRank']] = array(); } $aReverseGroupedSearches[$aSearch['iSearchRank']][] = $aSearch; } } } $aGroupedSearches = $aReverseGroupedSearches; ksort($aGroupedSearches); } } else { // Re-group the searches by their score, junk anything over 20 as just not worth trying $aGroupedSearches = array(); foreach ($aSearches as $aSearch) { if ($aSearch['iSearchRank'] < $this->iMaxRank) { if (!isset($aGroupedSearches[$aSearch['iSearchRank']])) { $aGroupedSearches[$aSearch['iSearchRank']] = array(); } $aGroupedSearches[$aSearch['iSearchRank']][] = $aSearch; } } ksort($aGroupedSearches); } if (CONST_Debug) { var_Dump($aGroupedSearches); } if (CONST_Search_TryDroppedAddressTerms && sizeof($this->aStructuredQuery) > 0) { $aCopyGroupedSearches = $aGroupedSearches; foreach ($aCopyGroupedSearches as $iGroup => $aSearches) { foreach ($aSearches as $iSearch => $aSearch) { $aReductionsList = array($aSearch['aAddress']); $iSearchRank = $aSearch['iSearchRank']; while (sizeof($aReductionsList) > 0) { $iSearchRank += 5; if ($iSearchRank > iMaxRank) { break 3; } $aNewReductionsList = array(); foreach ($aReductionsList as $aReductionsWordList) { for ($iReductionWord = 0; $iReductionWord < sizeof($aReductionsWordList); $iReductionWord++) { $aReductionsWordListResult = array_merge(array_slice($aReductionsWordList, 0, $iReductionWord), array_slice($aReductionsWordList, $iReductionWord + 1)); $aReverseSearch = $aSearch; $aSearch['aAddress'] = $aReductionsWordListResult; $aSearch['iSearchRank'] = $iSearchRank; $aGroupedSearches[$iSearchRank][] = $aReverseSearch; if (sizeof($aReductionsWordListResult) > 0) { $aNewReductionsList[] = $aReductionsWordListResult; } } } $aReductionsList = $aNewReductionsList; } } } ksort($aGroupedSearches); } // Filter out duplicate searches $aSearchHash = array(); foreach ($aGroupedSearches as $iGroup => $aSearches) { foreach ($aSearches as $iSearch => $aSearch) { $sHash = serialize($aSearch); if (isset($aSearchHash[$sHash])) { unset($aGroupedSearches[$iGroup][$iSearch]); if (sizeof($aGroupedSearches[$iGroup]) == 0) { unset($aGroupedSearches[$iGroup]); } } else { $aSearchHash[$sHash] = 1; } } } if (CONST_Debug) { _debugDumpGroupedSearches($aGroupedSearches, $aValidTokens); } $iGroupLoop = 0; $iQueryLoop = 0; foreach ($aGroupedSearches as $iGroupedRank => $aSearches) { $iGroupLoop++; foreach ($aSearches as $aSearch) { $iQueryLoop++; if (CONST_Debug) { echo "<hr><b>Search Loop, group {$iGroupLoop}, loop {$iQueryLoop}</b>"; } if (CONST_Debug) { _debugDumpGroupedSearches(array($iGroupedRank => array($aSearch)), $aValidTokens); } // No location term? if (!sizeof($aSearch['aName']) && !sizeof($aSearch['aAddress']) && !$aSearch['fLon']) { if ($aSearch['sCountryCode'] && !$aSearch['sClass'] && !$aSearch['sHouseNumber']) { // Just looking for a country by code - look it up if (4 >= $this->iMinAddressRank && 4 <= $this->iMaxAddressRank) { $sSQL = "select place_id from placex where calculated_country_code='" . $aSearch['sCountryCode'] . "' and rank_search = 4"; if ($sCountryCodesSQL) { $sSQL .= " and calculated_country_code in ({$sCountryCodesSQL})"; } if ($bBoundingBoxSearch) { $sSQL .= " and _st_intersects({$this->sViewboxSmallSQL}, geometry)"; } $sSQL .= " order by st_area(geometry) desc limit 1"; if (CONST_Debug) { var_dump($sSQL); } $aPlaceIDs = $this->oDB->getCol($sSQL); } else { $aPlaceIDs = array(); } } else { if (!$bBoundingBoxSearch && !$aSearch['fLon']) { continue; } if (!$aSearch['sClass']) { continue; } $sSQL = "select count(*) from pg_tables where tablename = 'place_classtype_" . $aSearch['sClass'] . "_" . $aSearch['sType'] . "'"; if ($this->oDB->getOne($sSQL)) { $sSQL = "select place_id from place_classtype_" . $aSearch['sClass'] . "_" . $aSearch['sType'] . " ct"; if ($sCountryCodesSQL) { $sSQL .= " join placex using (place_id)"; } $sSQL .= " where st_contains({$this->sViewboxSmallSQL}, ct.centroid)"; if ($sCountryCodesSQL) { $sSQL .= " and calculated_country_code in ({$sCountryCodesSQL})"; } if (sizeof($this->aExcludePlaceIDs)) { $sSQL .= " and place_id not in (" . join(',', $this->aExcludePlaceIDs) . ")"; } if ($sViewboxCentreSQL) { $sSQL .= " order by st_distance({$sViewboxCentreSQL}, ct.centroid) asc"; } $sSQL .= " limit {$this->iLimit}"; if (CONST_Debug) { var_dump($sSQL); } $aPlaceIDs = $this->oDB->getCol($sSQL); // If excluded place IDs are given, it is fair to assume that // there have been results in the small box, so no further // expansion in that case. // Also don't expand if bounded results were requested. if (!sizeof($aPlaceIDs) && !sizeof($this->aExcludePlaceIDs) && !$this->bBoundedSearch) { $sSQL = "select place_id from place_classtype_" . $aSearch['sClass'] . "_" . $aSearch['sType'] . " ct"; if ($sCountryCodesSQL) { $sSQL .= " join placex using (place_id)"; } $sSQL .= " where st_contains({$this->sViewboxLargeSQL}, ct.centroid)"; if ($sCountryCodesSQL) { $sSQL .= " and calculated_country_code in ({$sCountryCodesSQL})"; } if ($sViewboxCentreSQL) { $sSQL .= " order by st_distance({$sViewboxCentreSQL}, ct.centroid) asc"; } $sSQL .= " limit {$this->iLimit}"; if (CONST_Debug) { var_dump($sSQL); } $aPlaceIDs = $this->oDB->getCol($sSQL); } } else { $sSQL = "select place_id from placex where class='" . $aSearch['sClass'] . "' and type='" . $aSearch['sType'] . "'"; $sSQL .= " and st_contains({$this->sViewboxSmallSQL}, geometry) and linked_place_id is null"; if ($sCountryCodesSQL) { $sSQL .= " and calculated_country_code in ({$sCountryCodesSQL})"; } if ($sViewboxCentreSQL) { $sSQL .= " order by st_distance({$sViewboxCentreSQL}, centroid) asc"; } $sSQL .= " limit {$this->iLimit}"; if (CONST_Debug) { var_dump($sSQL); } $aPlaceIDs = $this->oDB->getCol($sSQL); } } } else { $aPlaceIDs = array(); // First we need a position, either aName or fLat or both $aTerms = array(); $aOrder = array(); if ($aSearch['sHouseNumber'] && sizeof($aSearch['aAddress'])) { $sHouseNumberRegex = '\\\\m' . $aSearch['sHouseNumber'] . '\\\\M'; $aOrder[] = "exists(select place_id from placex where parent_place_id = search_name.place_id and transliteration(housenumber) ~* E'" . $sHouseNumberRegex . "' limit 1) desc"; } // TODO: filter out the pointless search terms (2 letter name tokens and less) // they might be right - but they are just too darned expensive to run if (sizeof($aSearch['aName'])) { $aTerms[] = "name_vector @> ARRAY[" . join($aSearch['aName'], ",") . "]"; } if (sizeof($aSearch['aNameNonSearch'])) { $aTerms[] = "array_cat(name_vector,ARRAY[]::integer[]) @> ARRAY[" . join($aSearch['aNameNonSearch'], ",") . "]"; } if (sizeof($aSearch['aAddress']) && $aSearch['aName'] != $aSearch['aAddress']) { // For infrequent name terms disable index usage for address if (CONST_Search_NameOnlySearchFrequencyThreshold && sizeof($aSearch['aName']) == 1 && $aWordFrequencyScores[$aSearch['aName'][reset($aSearch['aName'])]] < CONST_Search_NameOnlySearchFrequencyThreshold) { $aTerms[] = "array_cat(nameaddress_vector,ARRAY[]::integer[]) @> ARRAY[" . join(array_merge($aSearch['aAddress'], $aSearch['aAddressNonSearch']), ",") . "]"; } else { $aTerms[] = "nameaddress_vector @> ARRAY[" . join($aSearch['aAddress'], ",") . "]"; if (sizeof($aSearch['aAddressNonSearch'])) { $aTerms[] = "array_cat(nameaddress_vector,ARRAY[]::integer[]) @> ARRAY[" . join($aSearch['aAddressNonSearch'], ",") . "]"; } } } if ($aSearch['sCountryCode']) { $aTerms[] = "country_code = '" . pg_escape_string($aSearch['sCountryCode']) . "'"; } if ($aSearch['sHouseNumber']) { $aTerms[] = "address_rank between 16 and 27"; } else { if ($this->iMinAddressRank > 0) { $aTerms[] = "address_rank >= " . $this->iMinAddressRank; } if ($this->iMaxAddressRank < 30) { $aTerms[] = "address_rank <= " . $this->iMaxAddressRank; } } if ($aSearch['fLon'] && $aSearch['fLat']) { $aTerms[] = "ST_DWithin(centroid, ST_SetSRID(ST_Point(" . $aSearch['fLon'] . "," . $aSearch['fLat'] . "),4326), " . $aSearch['fRadius'] . ")"; $aOrder[] = "ST_Distance(centroid, ST_SetSRID(ST_Point(" . $aSearch['fLon'] . "," . $aSearch['fLat'] . "),4326)) ASC"; } if (sizeof($this->aExcludePlaceIDs)) { $aTerms[] = "place_id not in (" . join(',', $this->aExcludePlaceIDs) . ")"; } if ($sCountryCodesSQL) { $aTerms[] = "country_code in ({$sCountryCodesSQL})"; } if ($bBoundingBoxSearch) { $aTerms[] = "centroid && {$this->sViewboxSmallSQL}"; } if ($sNearPointSQL) { $aOrder[] = "ST_Distance({$sNearPointSQL}, centroid) asc"; } if ($aSearch['sHouseNumber']) { $sImportanceSQL = '- abs(26 - address_rank) + 3'; } else { $sImportanceSQL = '(case when importance = 0 OR importance IS NULL then 0.75-(search_rank::float/40) else importance end)'; } if ($this->sViewboxSmallSQL) { $sImportanceSQL .= " * case when ST_Contains({$this->sViewboxSmallSQL}, centroid) THEN 1 ELSE 0.5 END"; } if ($this->sViewboxLargeSQL) { $sImportanceSQL .= " * case when ST_Contains({$this->sViewboxLargeSQL}, centroid) THEN 1 ELSE 0.5 END"; } $aOrder[] = "{$sImportanceSQL} DESC"; if (sizeof($aSearch['aFullNameAddress'])) { $sExactMatchSQL = '(select count(*) from (select unnest(ARRAY[' . join($aSearch['aFullNameAddress'], ",") . ']) INTERSECT select unnest(nameaddress_vector))s) as exactmatch'; $aOrder[] = 'exactmatch DESC'; } else { $sExactMatchSQL = '0::int as exactmatch'; } if (sizeof($aTerms)) { $sSQL = "select place_id, "; $sSQL .= $sExactMatchSQL; $sSQL .= " from search_name"; $sSQL .= " where " . join(' and ', $aTerms); $sSQL .= " order by " . join(', ', $aOrder); if ($aSearch['sHouseNumber'] || $aSearch['sClass']) { $sSQL .= " limit 20"; } elseif (!sizeof($aSearch['aName']) && !sizeof($aSearch['aAddress']) && $aSearch['sClass']) { $sSQL .= " limit 1"; } else { $sSQL .= " limit " . $this->iLimit; } if (CONST_Debug) { var_dump($sSQL); } $aViewBoxPlaceIDs = $this->oDB->getAll($sSQL); if (PEAR::IsError($aViewBoxPlaceIDs)) { failInternalError("Could not get places for search terms.", $sSQL, $aViewBoxPlaceIDs); } //var_dump($aViewBoxPlaceIDs); // Did we have an viewbox matches? $aPlaceIDs = array(); $bViewBoxMatch = false; foreach ($aViewBoxPlaceIDs as $aViewBoxRow) { //if ($bViewBoxMatch == 1 && $aViewBoxRow['in_small'] == 'f') break; //if ($bViewBoxMatch == 2 && $aViewBoxRow['in_large'] == 'f') break; //if ($aViewBoxRow['in_small'] == 't') $bViewBoxMatch = 1; //else if ($aViewBoxRow['in_large'] == 't') $bViewBoxMatch = 2; $aPlaceIDs[] = $aViewBoxRow['place_id']; $this->exactMatchCache[$aViewBoxRow['place_id']] = $aViewBoxRow['exactmatch']; } } //var_Dump($aPlaceIDs); //exit; if ($aSearch['sHouseNumber'] && sizeof($aPlaceIDs)) { $aRoadPlaceIDs = $aPlaceIDs; $sPlaceIDs = join(',', $aPlaceIDs); // Now they are indexed look for a house attached to a street we found $sHouseNumberRegex = '\\\\m' . $aSearch['sHouseNumber'] . '\\\\M'; $sSQL = "select place_id from placex where parent_place_id in (" . $sPlaceIDs . ") and transliteration(housenumber) ~* E'" . $sHouseNumberRegex . "'"; if (sizeof($this->aExcludePlaceIDs)) { $sSQL .= " and place_id not in (" . join(',', $this->aExcludePlaceIDs) . ")"; } $sSQL .= " limit {$this->iLimit}"; if (CONST_Debug) { var_dump($sSQL); } $aPlaceIDs = $this->oDB->getCol($sSQL); // If not try the aux fallback table if (!sizeof($aPlaceIDs)) { $sSQL = "select place_id from location_property_aux where parent_place_id in (" . $sPlaceIDs . ") and housenumber = '" . pg_escape_string($aSearch['sHouseNumber']) . "'"; if (sizeof($this->aExcludePlaceIDs)) { $sSQL .= " and place_id not in (" . join(',', $this->aExcludePlaceIDs) . ")"; } //$sSQL .= " limit $this->iLimit"; if (CONST_Debug) { var_dump($sSQL); } $aPlaceIDs = $this->oDB->getCol($sSQL); } if (!sizeof($aPlaceIDs)) { $sSQL = "select place_id from location_property_tiger where parent_place_id in (" . $sPlaceIDs . ") and housenumber = '" . pg_escape_string($aSearch['sHouseNumber']) . "'"; if (sizeof($this->aExcludePlaceIDs)) { $sSQL .= " and place_id not in (" . join(',', $this->aExcludePlaceIDs) . ")"; } //$sSQL .= " limit $this->iLimit"; if (CONST_Debug) { var_dump($sSQL); } $aPlaceIDs = $this->oDB->getCol($sSQL); } // Fallback to the road if (!sizeof($aPlaceIDs) && preg_match('/[0-9]+/', $aSearch['sHouseNumber'])) { $aPlaceIDs = $aRoadPlaceIDs; } } if ($aSearch['sClass'] && sizeof($aPlaceIDs)) { $sPlaceIDs = join(',', $aPlaceIDs); $aClassPlaceIDs = array(); if (!$aSearch['sOperator'] || $aSearch['sOperator'] == 'name') { // If they were searching for a named class (i.e. 'Kings Head pub') then we might have an extra match $sSQL = "select place_id from placex where place_id in ({$sPlaceIDs}) and class='" . $aSearch['sClass'] . "' and type='" . $aSearch['sType'] . "'"; $sSQL .= " and linked_place_id is null"; if ($sCountryCodesSQL) { $sSQL .= " and calculated_country_code in ({$sCountryCodesSQL})"; } $sSQL .= " order by rank_search asc limit {$this->iLimit}"; if (CONST_Debug) { var_dump($sSQL); } $aClassPlaceIDs = $this->oDB->getCol($sSQL); } if (!$aSearch['sOperator'] || $aSearch['sOperator'] == 'near') { $sSQL = "select count(*) from pg_tables where tablename = 'place_classtype_" . $aSearch['sClass'] . "_" . $aSearch['sType'] . "'"; $bCacheTable = $this->oDB->getOne($sSQL); $sSQL = "select min(rank_search) from placex where place_id in ({$sPlaceIDs})"; if (CONST_Debug) { var_dump($sSQL); } $this->iMaxRank = (int) $this->oDB->getOne($sSQL); // For state / country level searches the normal radius search doesn't work very well $sPlaceGeom = false; if ($this->iMaxRank < 9 && $bCacheTable) { // Try and get a polygon to search in instead $sSQL = "select geometry from placex where place_id in ({$sPlaceIDs}) and rank_search < {$this->iMaxRank} + 5 and st_geometrytype(geometry) in ('ST_Polygon','ST_MultiPolygon') order by rank_search asc limit 1"; if (CONST_Debug) { var_dump($sSQL); } $sPlaceGeom = $this->oDB->getOne($sSQL); } if ($sPlaceGeom) { $sPlaceIDs = false; } else { $this->iMaxRank += 5; $sSQL = "select place_id from placex where place_id in ({$sPlaceIDs}) and rank_search < {$this->iMaxRank}"; if (CONST_Debug) { var_dump($sSQL); } $aPlaceIDs = $this->oDB->getCol($sSQL); $sPlaceIDs = join(',', $aPlaceIDs); } if ($sPlaceIDs || $sPlaceGeom) { $fRange = 0.01; if ($bCacheTable) { // More efficient - can make the range bigger $fRange = 0.05; $sOrderBySQL = ''; if ($sNearPointSQL) { $sOrderBySQL = "ST_Distance({$sNearPointSQL}, l.centroid)"; } else { if ($sPlaceIDs) { $sOrderBySQL = "ST_Distance(l.centroid, f.geometry)"; } else { if ($sPlaceGeom) { $sOrderBysSQL = "ST_Distance(st_centroid('" . $sPlaceGeom . "'), l.centroid)"; } } } $sSQL = "select distinct l.place_id" . ($sOrderBySQL ? ',' . $sOrderBySQL : '') . " from place_classtype_" . $aSearch['sClass'] . "_" . $aSearch['sType'] . " as l"; if ($sCountryCodesSQL) { $sSQL .= " join placex as lp using (place_id)"; } if ($sPlaceIDs) { $sSQL .= ",placex as f where "; $sSQL .= "f.place_id in ({$sPlaceIDs}) and ST_DWithin(l.centroid, f.centroid, {$fRange}) "; } if ($sPlaceGeom) { $sSQL .= " where "; $sSQL .= "ST_Contains('" . $sPlaceGeom . "', l.centroid) "; } if (sizeof($this->aExcludePlaceIDs)) { $sSQL .= " and l.place_id not in (" . join(',', $this->aExcludePlaceIDs) . ")"; } if ($sCountryCodesSQL) { $sSQL .= " and lp.calculated_country_code in ({$sCountryCodesSQL})"; } if ($sOrderBySQL) { $sSQL .= "order by " . $sOrderBySQL . " asc"; } if ($this->iOffset) { $sSQL .= " offset {$this->iOffset}"; } $sSQL .= " limit {$this->iLimit}"; if (CONST_Debug) { var_dump($sSQL); } $aClassPlaceIDs = array_merge($aClassPlaceIDs, $this->oDB->getCol($sSQL)); } else { if (isset($aSearch['fRadius']) && $aSearch['fRadius']) { $fRange = $aSearch['fRadius']; } $sOrderBySQL = ''; if ($sNearPointSQL) { $sOrderBySQL = "ST_Distance({$sNearPointSQL}, l.geometry)"; } else { $sOrderBySQL = "ST_Distance(l.geometry, f.geometry)"; } $sSQL = "select distinct l.place_id" . ($sOrderBysSQL ? ',' . $sOrderBysSQL : '') . " from placex as l,placex as f where "; $sSQL .= "f.place_id in ( {$sPlaceIDs}) and ST_DWithin(l.geometry, f.centroid, {$fRange}) "; $sSQL .= "and l.class='" . $aSearch['sClass'] . "' and l.type='" . $aSearch['sType'] . "' "; if (sizeof($this->aExcludePlaceIDs)) { $sSQL .= " and l.place_id not in (" . join(',', $this->aExcludePlaceIDs) . ")"; } if ($sCountryCodesSQL) { $sSQL .= " and l.calculated_country_code in ({$sCountryCodesSQL})"; } if ($sOrderBy) { $sSQL .= "order by " . $OrderBysSQL . " asc"; } if ($this->iOffset) { $sSQL .= " offset {$this->iOffset}"; } $sSQL .= " limit {$this->iLimit}"; if (CONST_Debug) { var_dump($sSQL); } $aClassPlaceIDs = array_merge($aClassPlaceIDs, $this->oDB->getCol($sSQL)); } } } $aPlaceIDs = $aClassPlaceIDs; } } if (PEAR::IsError($aPlaceIDs)) { failInternalError("Could not get place IDs from tokens.", $sSQL, $aPlaceIDs); } if (CONST_Debug) { echo "<br><b>Place IDs:</b> "; var_Dump($aPlaceIDs); } foreach ($aPlaceIDs as $iPlaceID) { $aResultPlaceIDs[$iPlaceID] = $iPlaceID; } if ($iQueryLoop > 20) { break; } } if (isset($aResultPlaceIDs) && sizeof($aResultPlaceIDs) && ($this->iMinAddressRank != 0 || $this->iMaxAddressRank != 30)) { // Need to verify passes rank limits before dropping out of the loop (yuk!) $sSQL = "select place_id from placex where place_id in (" . join(',', $aResultPlaceIDs) . ") "; $sSQL .= "and (placex.rank_address between {$this->iMinAddressRank} and {$this->iMaxAddressRank} "; if (14 >= $this->iMinAddressRank && 14 <= $this->iMaxAddressRank) { $sSQL .= " OR (extratags->'place') = 'city'"; } if ($this->aAddressRankList) { $sSQL .= " OR placex.rank_address in (" . join(',', $this->aAddressRankList) . ")"; } $sSQL .= ") UNION select place_id from location_property_tiger where place_id in (" . join(',', $aResultPlaceIDs) . ") "; $sSQL .= "and (30 between {$this->iMinAddressRank} and {$this->iMaxAddressRank} "; if ($this->aAddressRankList) { $sSQL .= " OR 30 in (" . join(',', $this->aAddressRankList) . ")"; } $sSQL .= ")"; if (CONST_Debug) { var_dump($sSQL); } $aResultPlaceIDs = $this->oDB->getCol($sSQL); } //exit; if (isset($aResultPlaceIDs) && sizeof($aResultPlaceIDs)) { break; } if ($iGroupLoop > 4) { break; } if ($iQueryLoop > 30) { break; } } // Did we find anything? if (isset($aResultPlaceIDs) && sizeof($aResultPlaceIDs)) { $aSearchResults = $this->getDetails($aResultPlaceIDs); } } else { // Just interpret as a reverse geocode $iPlaceID = geocodeReverse((double) $this->aNearPoint[0], (double) $this->aNearPoint[1]); if ($iPlaceID) { $aSearchResults = $this->getDetails(array($iPlaceID)); } else { $aSearchResults = array(); } } // No results? Done if (!sizeof($aSearchResults)) { if ($this->bFallback) { if ($this->fallbackStructuredQuery()) { return $this->lookup(); } } return array(); } $aClassType = getClassTypesWithImportance(); $aRecheckWords = preg_split('/\\b[\\s,\\-]*/u', $sQuery); foreach ($aRecheckWords as $i => $sWord) { if (!preg_match('/\\pL/', $sWord)) { unset($aRecheckWords[$i]); } } if (CONST_Debug) { echo '<i>Recheck words:<\\i>'; var_dump($aRecheckWords); } foreach ($aSearchResults as $iResNum => $aResult) { // Default $fDiameter = 0.0001; if (isset($aClassType[$aResult['class'] . ':' . $aResult['type'] . ':' . $aResult['admin_level']]['defdiameter']) && $aClassType[$aResult['class'] . ':' . $aResult['type'] . ':' . $aResult['admin_level']]['defdiameter']) { $fDiameter = $aClassType[$aResult['class'] . ':' . $aResult['type'] . ':' . $aResult['admin_level']]['defdiameter']; } elseif (isset($aClassType[$aResult['class'] . ':' . $aResult['type']]['defdiameter']) && $aClassType[$aResult['class'] . ':' . $aResult['type']]['defdiameter']) { $fDiameter = $aClassType[$aResult['class'] . ':' . $aResult['type']]['defdiameter']; } $fRadius = $fDiameter / 2; if (CONST_Search_AreaPolygons) { // Get the bounding box and outline polygon $sSQL = "select place_id,0 as numfeatures,st_area(geometry) as area,"; $sSQL .= "ST_Y(centroid) as centrelat,ST_X(centroid) as centrelon,"; $sSQL .= "ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,"; $sSQL .= "ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon"; if ($this->bIncludePolygonAsGeoJSON) { $sSQL .= ",ST_AsGeoJSON(geometry) as asgeojson"; } if ($this->bIncludePolygonAsKML) { $sSQL .= ",ST_AsKML(geometry) as askml"; } if ($this->bIncludePolygonAsSVG) { $sSQL .= ",ST_AsSVG(geometry) as assvg"; } if ($this->bIncludePolygonAsText || $this->bIncludePolygonAsPoints) { $sSQL .= ",ST_AsText(geometry) as astext"; } $sFrom = " from placex where place_id = " . $aResult['place_id']; if ($this->fPolygonSimplificationThreshold > 0) { $sSQL .= " from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry," . $this->fPolygonSimplificationThreshold . ") as geometry" . $sFrom . ") as plx"; } else { $sSQL .= $sFrom; } $aPointPolygon = $this->oDB->getRow($sSQL); if (PEAR::IsError($aPointPolygon)) { failInternalError("Could not get outline.", $sSQL, $aPointPolygon); } if ($aPointPolygon['place_id']) { if ($this->bIncludePolygonAsGeoJSON) { $aResult['asgeojson'] = $aPointPolygon['asgeojson']; } if ($this->bIncludePolygonAsKML) { $aResult['askml'] = $aPointPolygon['askml']; } if ($this->bIncludePolygonAsSVG) { $aResult['assvg'] = $aPointPolygon['assvg']; } if ($this->bIncludePolygonAsText) { $aResult['astext'] = $aPointPolygon['astext']; } if ($aPointPolygon['centrelon'] !== null && $aPointPolygon['centrelat'] !== null) { $aResult['lat'] = $aPointPolygon['centrelat']; $aResult['lon'] = $aPointPolygon['centrelon']; } if ($this->bIncludePolygonAsPoints) { // Translate geometry string to point array if (preg_match('#POLYGON\\(\\(([- 0-9.,]+)#', $aPointPolygon['astext'], $aMatch)) { preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER); } elseif (preg_match('#MULTIPOLYGON\\(\\(\\(([- 0-9.,]+)#', $aPointPolygon['astext'], $aMatch)) { preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER); } elseif (preg_match('#POINT\\((-?[0-9.]+) (-?[0-9.]+)\\)#', $aPointPolygon['astext'], $aMatch)) { $iSteps = max(8, min(100, $fRadius * 40000 ^ 2)); $fStepSize = 2 * pi() / $iSteps; $aPolyPoints = array(); for ($f = 0; $f < 2 * pi(); $f += $fStepSize) { $aPolyPoints[] = array('', $aMatch[1] + $fRadius * sin($f), $aMatch[2] + $fRadius * cos($f)); } } } // Output data suitable for display (points and a bounding box) if ($this->bIncludePolygonAsPoints && isset($aPolyPoints)) { $aResult['aPolyPoints'] = array(); foreach ($aPolyPoints as $aPoint) { $aResult['aPolyPoints'][] = array($aPoint[1], $aPoint[2]); } } if (abs($aPointPolygon['minlat'] - $aPointPolygon['maxlat']) < 1.0E-7) { $aPointPolygon['minlat'] = $aPointPolygon['minlat'] - $fRadius; $aPointPolygon['maxlat'] = $aPointPolygon['maxlat'] + $fRadius; } if (abs($aPointPolygon['minlon'] - $aPointPolygon['maxlon']) < 1.0E-7) { $aPointPolygon['minlon'] = $aPointPolygon['minlon'] - $fRadius; $aPointPolygon['maxlon'] = $aPointPolygon['maxlon'] + $fRadius; } $aResult['aBoundingBox'] = array((string) $aPointPolygon['minlat'], (string) $aPointPolygon['maxlat'], (string) $aPointPolygon['minlon'], (string) $aPointPolygon['maxlon']); } } if ($aResult['extra_place'] == 'city') { $aResult['class'] = 'place'; $aResult['type'] = 'city'; $aResult['rank_search'] = 16; } if (!isset($aResult['aBoundingBox'])) { $iSteps = max(8, min(100, $fRadius * 3.14 * 100000)); $fStepSize = 2 * pi() / $iSteps; $aPointPolygon['minlat'] = $aResult['lat'] - $fRadius; $aPointPolygon['maxlat'] = $aResult['lat'] + $fRadius; $aPointPolygon['minlon'] = $aResult['lon'] - $fRadius; $aPointPolygon['maxlon'] = $aResult['lon'] + $fRadius; // Output data suitable for display (points and a bounding box) if ($this->bIncludePolygonAsPoints) { $aPolyPoints = array(); for ($f = 0; $f < 2 * pi(); $f += $fStepSize) { $aPolyPoints[] = array('', $aResult['lon'] + $fRadius * sin($f), $aResult['lat'] + $fRadius * cos($f)); } $aResult['aPolyPoints'] = array(); foreach ($aPolyPoints as $aPoint) { $aResult['aPolyPoints'][] = array($aPoint[1], $aPoint[2]); } } $aResult['aBoundingBox'] = array((string) $aPointPolygon['minlat'], (string) $aPointPolygon['maxlat'], (string) $aPointPolygon['minlon'], (string) $aPointPolygon['maxlon']); } // Is there an icon set for this type of result? if (isset($aClassType[$aResult['class'] . ':' . $aResult['type']]['icon']) && $aClassType[$aResult['class'] . ':' . $aResult['type']]['icon']) { $aResult['icon'] = CONST_Website_BaseURL . 'images/mapicons/' . $aClassType[$aResult['class'] . ':' . $aResult['type']]['icon'] . '.p.20.png'; } if (isset($aClassType[$aResult['class'] . ':' . $aResult['type'] . ':' . $aResult['admin_level']]['label']) && $aClassType[$aResult['class'] . ':' . $aResult['type'] . ':' . $aResult['admin_level']]['label']) { $aResult['label'] = $aClassType[$aResult['class'] . ':' . $aResult['type'] . ':' . $aResult['admin_level']]['label']; } elseif (isset($aClassType[$aResult['class'] . ':' . $aResult['type']]['label']) && $aClassType[$aResult['class'] . ':' . $aResult['type']]['label']) { $aResult['label'] = $aClassType[$aResult['class'] . ':' . $aResult['type']]['label']; } if ($this->bIncludeAddressDetails) { $aResult['address'] = getAddressDetails($this->oDB, $sLanguagePrefArraySQL, $aResult['place_id'], $aResult['country_code']); if ($aResult['extra_place'] == 'city' && !isset($aResult['address']['city'])) { $aResult['address'] = array_merge(array('city' => array_shift(array_values($aResult['address']))), $aResult['address']); } } if ($this->bIncludeExtraTags) { if ($aResult['extra']) { $aResult['sExtraTags'] = json_decode($aResult['extra']); } else { $aResult['sExtraTags'] = (object) array(); } } if ($this->bIncludeNameDetails) { if ($aResult['names']) { $aResult['sNameDetails'] = json_decode($aResult['names']); } else { $aResult['sNameDetails'] = (object) array(); } } // Adjust importance for the number of exact string matches in the result $aResult['importance'] = max(0.001, $aResult['importance']); $iCountWords = 0; $sAddress = $aResult['langaddress']; foreach ($aRecheckWords as $i => $sWord) { if (stripos($sAddress, $sWord) !== false) { $iCountWords++; if (preg_match("/(^|,)\\s*" . preg_quote($sWord, '/') . "\\s*(,|\$)/", $sAddress)) { $iCountWords += 0.1; } } } $aResult['importance'] = $aResult['importance'] + $iCountWords * 0.1; // 0.1 is a completely arbitrary number but something in the range 0.1 to 0.5 would seem right $aResult['name'] = $aResult['langaddress']; // secondary ordering (for results with same importance (the smaller the better): // - approximate importance of address parts $aResult['foundorder'] = -$aResult['addressimportance'] / 10; // - number of exact matches from the query if (isset($this->exactMatchCache[$aResult['place_id']])) { $aResult['foundorder'] -= $this->exactMatchCache[$aResult['place_id']]; } else { if (isset($this->exactMatchCache[$aResult['parent_place_id']])) { $aResult['foundorder'] -= $this->exactMatchCache[$aResult['parent_place_id']]; } } // - importance of the class/type if (isset($aClassType[$aResult['class'] . ':' . $aResult['type']]['importance']) && $aClassType[$aResult['class'] . ':' . $aResult['type']]['importance']) { $aResult['foundorder'] += 0.0001 * $aClassType[$aResult['class'] . ':' . $aResult['type']]['importance']; } else { $aResult['foundorder'] += 0.01; } if (CONST_Debug) { var_dump($aResult); } $aSearchResults[$iResNum] = $aResult; } uasort($aSearchResults, 'byImportance'); $aOSMIDDone = array(); $aClassTypeNameDone = array(); $aToFilter = $aSearchResults; $aSearchResults = array(); $bFirst = true; foreach ($aToFilter as $iResNum => $aResult) { $this->aExcludePlaceIDs[$aResult['place_id']] = $aResult['place_id']; if ($bFirst) { $fLat = $aResult['lat']; $fLon = $aResult['lon']; if (isset($aResult['zoom'])) { $iZoom = $aResult['zoom']; } $bFirst = false; } if (!$this->bDeDupe || !isset($aOSMIDDone[$aResult['osm_type'] . $aResult['osm_id']]) && !isset($aClassTypeNameDone[$aResult['osm_type'] . $aResult['class'] . $aResult['type'] . $aResult['name'] . $aResult['admin_level']])) { $aOSMIDDone[$aResult['osm_type'] . $aResult['osm_id']] = true; $aClassTypeNameDone[$aResult['osm_type'] . $aResult['class'] . $aResult['type'] . $aResult['name'] . $aResult['admin_level']] = true; $aSearchResults[] = $aResult; } // Absolute limit on number of results if (sizeof($aSearchResults) >= $this->iFinalLimit) { break; } } return $aSearchResults; }
function UltraMail( $to, $subject, $message, $additional_headers = '', $additional_parameters = '') { global $MailBoxs, $UltraMailError; $UM_StFrom = ''; ##--------------------------------------- ## Converte o HEADER de STRING para ARRAY ##--------------------------------------- $Aux_headers = str_replace("\r", '', $additional_headers); $Aux_headers = split("\n", $Aux_headers); $headers = array(); foreach ($Aux_headers as $Aux_header) { if ( ereg( '^([^:]+):([^:]+)$', $Aux_header, $regs ) ) { $headers[ $regs[1] ] = $regs[2]; } } ##--------------------------------------- ##-------------------------------------------------- ## Localiza os dados do MailBox que enviará o e-mail ##-------------------------------------------------- # Caso o usuário não tenha configurado um FROM # utilizar sempre o primeiro if ( empty( $headers['From'] ) ) { if ( !Empty($MailBox['StName']) ) { $headers['From'] = $MailBoxs[0]['StName'] . " <{$MailBoxs[0]['StEMail']}>"; } else { $headers['From'] = $MailBoxs[0]['StEMail']; } $UM_StName = $MailBoxs[0]['StName']; $UM_StFrom = $MailBoxs[0]['StEMail']; $UM_StUser = $MailBoxs[0]['StUser']; $UM_StPassword = $MailBoxs[0]['StPassword']; $UM_StServer = $MailBoxs[0]['StSMTPServer']; } # Caso exista o FROM procurar os # dados do MailBox do mesmo else { if ( eregi( '<?([^<>, ]+\@[^<>, ]+)>?', $headers['From'], $regs ) ) { $EMailDeEnvio = $regs[1]; } else { print "E-mail inválido: $to<BR>\n"; exit; } foreach ($MailBoxs as $MailBox) { if ($MailBox['StEMail'] == $EMailDeEnvio) { $UM_StName = $MailBox['StName']; $UM_StFrom = $MailBox['StEMail']; $UM_StUser = $MailBox['StUser']; $UM_StPassword = $MailBox['StPassword']; $UM_StServer = $MailBox['StSMTPServer']; } } if ( Empty($UM_StFrom) ) { if ( !Empty($MailBox['StName']) ) { $headers['From'] = $MailBoxs[0]['StName'] . " <{$MailBoxs[0]['StEMail']}>"; } else { $headers['From'] = $MailBoxs[0]['StEMail']; } $UM_StName = $MailBoxs[0]['StName']; $UM_StFrom = $MailBoxs[0]['StEMail']; $UM_StUser = $MailBoxs[0]['StUser']; $UM_StPassword = $MailBoxs[0]['StPassword']; $UM_StServer = $MailBoxs[0]['StSMTPServer']; } } ##-------------------------------------------------- ##------------------------------------------------ ## Configura as varíaveis necessárias para o envio ##------------------------------------------------ $headers['To'] = $to; $headers['Subject'] = $subject; $recipients[0] = $to; if ($headers['Cc']) { array_push($recipients, $headers['Cc']); } if ($headers['Bcc']) { array_push($recipients, $headers['Bcc']); } $params = array ( 'auth' => true, # SMTP requer autenticação. 'host' => $UM_StServer, # Servidor SMTP 'username' => $UM_StUser, # Usuário do SMTP 'password' => $UM_StPassword # Senha do seu MailBox. ); ##------------------------------------------------ ##------------------------------------ ## Envio o e-mail de forma autenticada ##------------------------------------ # Define o método de envio. # Queremos 'smtp'. OBRIGATÓRIO. $mail_object =& Mail::factory('smtp', $params); if (PEAR::IsError($mail_object)) { $UltraMailError = $mail_object->getMessage(); return FALSE; } # Envia o email. Se não ocorrer erro retorna TRUE, # caso contrário retorna um objeto PEAR_Error. # Para ler a mensagem de erro use o método getMessage(). $result = $mail_object->send($recipients, $headers, $message); if (PEAR::IsError($result)) { $UltraMailError = $result->getMessage(); return FALSE; } else { return TRUE; } ##------------------------------------ }