QUERY($map); $this->map = $map; $this->qLayer = $qLayer; $this->qLayerName = $this->qLayer->name; $this->qLayerType = $this->qLayer->type; $this->glayer = $glayer; $this->selFields = $glayer->getResFields(); $this->zoomFull = $zoomFull; $this->infoWin = $_SESSION["infoWin"]; $this->limitResult = $_SESSION["limitResult"]; $this->pointBuffer = $_SESSION["pointBuffer"]; $this->layerEncoding = $glayer->getLayerEncoding(); // dump results to resultString $this->dumpQueryResults(); //error_log($this->qStr); } function getResultString() { return $this->qStr; } // Get the number of results for query on the layer function setNumResults() { $this->qLayer->open(); $this->numResults = $this->qLayer->getNumResults(); // Apply limit for query results if ($this->numResults > $this->limitResult) $this->numResults = $this->limitResult; } /** * DUMP QUERY RESULTS INTO QUERY STRING $qStr *******************************************************/ function dumpQueryResults() { if ($this->zoomFull) { // Maximum extents $this->mExtMinx = 999999999; $this->mExtMiny = 999999999; $this->mExtMaxx = -999999999; $this->mExtMaxy = -999999999; } $this->returnTableJoinProperties(); $this->setNumResults(); //error_log($this->numResults); for ($iRes=0; $iRes < $this->numResults; $iRes++) { $qRes = $this->qLayer->getResult($iRes); $qShape = $this->qLayer->getShape($qRes->tileindex,$qRes->shapeindex); $this->qStr .= $this->printResultRow($qShape); $this->qStr .= $iRes < ($this->numResults - 1) ? ", " : ""; $this->resultindexes[] = $qRes->shapeindex; $this->resulttileindexes[$qRes->shapeindex] = $qRes->tileindex; } //error_log($this->qStr); } function printResultRow($qShape) { $this->qStr .= "["; // DO NOT PRINT LINK FOR RASTER LAYERS (TYPE 3), ONLY FOR VECTOR $this->qStr .= ($this->qLayerType != 3 ? $this->printShapeField($qShape) : "\"r\""); $this->printFields($qShape); $this->qStr .= "]"; } /** * Print SHAPEINDEX COLUMN as HTML hyperlink (for zoom-to-feature link) *************************************************************************/ function printShapeField($qShape) { // Add LINK with shape extent and javascript zoom function as new column // $qShpIdx = $qShape->index; $qShpBounds = $qShape->bounds; $changeLayProj = $this->checkProjection(); //$this->resultindexes[] = $qShpIdx; // Change PROJECTION to map projection if necessary if ($changeLayProj) { if ($this->qLayerType == 0) { // Apply buffer in order to have a correct re-projection of POINT layers $pjbuff = 0.0000001; $sMinx = $qShpBounds->minx - $pjbuff; $sMiny = $qShpBounds->miny - $pjbuff; $sMaxx = $qShpBounds->maxx + $pjbuff; $sMaxy = $qShpBounds->maxy + $pjbuff; $qShpBounds = ms_newRectObj(); $qShpBounds->set("minx", $sMinx); $qShpBounds->set("miny", $sMiny); $qShpBounds->set("maxx", $sMaxx); $qShpBounds->set("maxy", $sMaxy); } $qShpBounds->project($this->qLayerProjObj, $this->mapProjObj); } //Get MIN/MAX values for shape extent rectangle $shpMinx = $qShpBounds->minx; $shpMiny = $qShpBounds->miny; $shpMaxx = $qShpBounds->maxx; $shpMaxy = $qShpBounds->maxy; // Buffer for points: ADAPT BUFFER VALUE TO SCALE RANGE [ needs to be improved though ] if ($this->qLayerType == 0) { $buf = $this->pointBuffer; // set buffer depending on dimensions of your coordinate system $shpMinx -= $buf; $shpMiny -= $buf; $shpMaxx += $buf; $shpMaxy += $buf; } // Get maximum extents if zoomAll or autoZoom is enabled if ($this->zoomFull) { $this->mExtMinx = min($this->mExtMinx, $shpMinx); $this->mExtMiny = min($this->mExtMiny, $shpMiny); $this->mExtMaxx = max($this->mExtMaxx, $shpMaxx); $this->mExtMaxy = max($this->mExtMaxy, $shpMaxy); } // Define if for zoom2extent for select and search the single click should change highlight ##$jsLink = "zoom2extent(" . ($this->zoomFull ? "0, 0" : "'" . $this->qLayerName ."',".$qShpIdx) .",'". $shpMinx ."+". $shpMiny ."+". $shpMaxx ."+". $shpMaxy ."')"; ##$qShpLink = "infoWin == "frame" ? "" : "opener.parent.mapFrame.") . $jsLink . "\">"; $qShpLink = "{\"shplink\": [" . ($this->zoomFull ? "\"0\",\"0" : "\"" . $this->qLayerName ."\",\"".$qShpIdx) ."\",\"". $shpMinx ."+". $shpMiny ."+". $shpMaxx ."+". $shpMaxy ."\"]}"; return $qShpLink; } /** * Print results for rest of fields (all but shape) *************************************************/ function printFields($qShape) { // PRINT RESULT ROW $loop = 2; // Used for one-to-many joins to break while loop when all DB data printed $dbloop = 0; // Used for one-to-many joins as index to step through join table while($loop > 0) { ##$this->qStr .= "pippo anzahl felder:" . sizeof($this->selFields); // Add shape index to array, used for highlight //$resultindexes[] = $qShpIdx; // Print all OTHER COLUMNS from SHAPE for ($iField=0; $iField < sizeof($this->selFields); $iField++) { $fldName = $this->selFields[$iField]; $fldValue = $qShape->values[$fldName]; //$this->qStr .= $fldValue; $this->qStr .= $this->printFieldValues($fldName, $fldValue); } ##print_r($this->joinList); // Now add JOIN COLUMNS from DB if defined if ($this->joinList && $this->dbh) { $toValue = $qShape->values[$this->toField]; $joinFieldList = split(',', $this->joinFields); //echo $this->sql; // get data only once from DB if ($dbloop == 0) { $data = $this->returnData($this->dbh, $this->sql, $toValue, $this->fromFieldType, $this->one2many); $dbresCount = count($data); } //print_r($data); //exit; // if ($dbresCount > 0) { $jfldi = 0; foreach($data[$dbloop] as $val) { $fldName = trim($joinFieldList[$jfldi]); $jfldi++; $this->qStr .= $this->printFieldValues($fldName, $val); } $dbloop++; // if NO one2many set $dbloop to end value and stop after first record if (!$this->one2many) { $dbloop = $dbresCount; } // if all recors from one2many retrieved (or only one2one) stop loop if ($dbloop == $dbresCount) $loop = 0; } else { $loop = 0; } // NO JOIN field defined, so break while loop and continue with next record } else { $loop = 0; } } } /** * FUNCTIONS FOR JOINING DB TABLES TO QUERY RESULT ************************************************************/ // Get properties for DB table join function returnTableJoinProperties() { if ($this->glayer->getTableJoin()) { //$dsn, $fromTable, $fromField, $fromFieldType, $joinFields, $toField, $one2many require_once ("DB.php"); $joinList = $this->glayer->getTableJoin(); // Join table properties $fromTable = $joinList["fromTable"]; $fromField = $joinList["fromField"]; $this->fromFieldType = $joinList["fromFieldType"]; $this->joinFields = $joinList["joinFields"]; // Layer field to join TO $this->toField = $joinList["toField"]; // Join type: one-to-one (0) or one-to-many (1) $this->one2many = $joinList["one2many"]; // Connnect to DB $dsn = $joinList["dsn"]; $dbh = $this->dbConnect($dsn); if (!$dbh) error_log ("Could not connect to DB defined for Layer '" . $this->glayer->getLayerName() . "'. Check map file entry for JOIN definition.", 0); } $this->sql = "SELECT " . $this->joinFields . " FROM $fromTable WHERE $fromField="; $this->dbh = $dbh; $this->joinList = $joinList; } // Get data from DB function returnData($dbh, $sql, $toValue, $fromFieldType) { $quote = ($fromFieldType == "1" ? "'" : ""); $sqlRun = $sql.$quote.$toValue.$quote; $data = $dbh->getAll($sqlRun); // For 1:n Joins #$data = $dbh->getRow($sqlRun); if (PEAR::isError($data)) { db_logErrors($data); die(); } return $data; } } // end CLASS DQUERY /********************************************** * QUERY RESULTS FOR WMS LAYER **********************************************/ class WMSQuery extends Query { function WMSQuery($grp, $qLayer, $x_pix, $y_pix ) { //$this->QUERY($qLayer); $this->grp = $grp; $this->qLayer = $qLayer; $this->x_pix = $x_pix; $this->y_pix = $y_pix; // dump results to resultString $this->dumpWMSQueryResults(); } function dumpWMSQueryResults() { $wmsResultURL = $this->qLayer->getWMSFeatureInfoURL($this->x_pix, $this->y_pix, 10, "MIME"); error_log($wmsResultURL); $wmsResult = file($wmsResultURL); $wmsNumRes = count($wmsResult); //print_r($wmsResult); //echo $wmsResultURL; if ($wmsNumRes > 4) { $firstRun = 1; $featureCount = 0; $fldHeaderStr = "["; $resRowStr = "\"values\": [ ["; foreach ($wmsResult as $row) { if (preg_match ("/\sFeature\s/i", $row)) { $featureCount++; if (!$firstRun) { $resRowStr = substr($resRowStr, 0, -1); $resRowStr .= "],["; } $firstRun = 0; } elseif (preg_match ("/\=/", $row)) { $resRowStr .= ""; $resFld = preg_split ("/\=/", $row); if ($featureCount < 2) { $fldHeaderStr .= "\"" . trim($resFld[0]) . "\","; } $resRowStr .= "\"" . utf8_encode(trim(str_replace("'","",$resFld[1]))) . "\","; } } $fldHeaderStr = "\"header\": " . substr($fldHeaderStr, 0, -1) . "], "; $resRowStr = substr($resRowStr, 0, -1) . "]"; $this->numResults = $wmsNumRes - 4; $this->colspan = $colspan; $this->fieldHeaderStr = $fldHeaderStr; $this->qStr = "$fldHeaderStr $resRowStr"; } } } // end CLASS WMSQUERY /********************************************** * QUERY RESULTS FOR XY ('EVENT') LAYER **********************************************/ class XYQuery extends Query { function XYQUERY($qLayer, $glayer, $xyLayQueryList, $search, $zoomFull) { //$this->QUERY($qLayer); $this->glayer = $glayer; $this->qLayer = $qLayer; $this->qLayerName = $qLayer->name; $this->xyLayQueryList = $xyLayQueryList; $this->zoomFull = $zoomFull; $this->search = $search; $this->layerEncoding = $glayer->getLayerEncoding(); $this->limitResult = $_SESSION["limitResult"]; $this->pointBuffer = $_SESSION["pointBuffer"]; // dump results to resultString $this->dumpXYQueryResults(); } function dumpXYQueryResults() { require_once ("DB.php"); $eqr = $_SESSION["equeryRect"]; // XY Layer Properties $XYLayerProperties = $this->glayer->getXYLayerProperties(); $dsn = $XYLayerProperties["dsn"]; $xyTable = $XYLayerProperties["xyTable"]; $x_fld = $XYLayerProperties["x_fld"]; $y_fld = $XYLayerProperties["y_fld"]; $classidx_fld = $XYLayerProperties["classidx_fld"]; $resFieldList = $this->glayer->getResFields(); $resFldStr = join(',', $resFieldList); // Prepare SQL query if (preg_match("/@/", $xyTable)) { // Check for WHERE filter in table definition $xyList = preg_split('/@/', $xyTable); $whereFilter = $xyList[1]; $xyTable = $xyList[0]; } $sql_select = "SELECT $x_fld, $y_fld, $resFldStr FROM $xyTable"; $qr = $this->xyLayQueryList; if ($this->search) { $sql_where = "WHERE " . ($whereFilter ? $whereFilter . " AND " : "") . $qr; } else { $sql_where = "WHERE " . ($whereFilter ? $whereFilter . " AND " : "") . " $x_fld >= " . $qr["xmin"] . " AND $x_fld <= " . $qr["xmax"] . " AND $y_fld >= " . $qr["ymin"] . " AND $y_fld <= " . $qr["ymax"]; } $sql = "$sql_select $sql_where"; //echo $sql; // Connect to DB $dbh = DB::connect($dsn); if (DB::isError($dbh)) { db_logErrors($dbh); die(); } // Execute query $res = $dbh->query($sql); if (DB::isError($res)) { db_logErrors($res); die(); } $this->mExtMinx = 999999999; $this->mExtMiny = 999999999; $this->mExtMaxx = -999999999; $this->mExtMaxy = -999999999; // Now print results as JSON $nres = 0; $numrows = $res->numRows(); while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) { $buf = $this->pointBuffer; //error_log($buf); $shpMinx = $row["$x_fld"] - $buf; $shpMiny = $row["$y_fld"] - $buf; $shpMaxx = $row["$x_fld"] + $buf; $shpMaxy = $row["$y_fld"] + $buf; if ($this->zoomFull) { $this->mExtMinx = min($this->mExtMinx, $shpMinx); $this->mExtMiny = min($this->mExtMiny, $shpMiny); $this->mExtMaxx = max($this->mExtMaxx, $shpMaxx); $this->mExtMaxy = max($this->mExtMaxy, $shpMaxy); } // Link for zoom to feature $qShpIdx = $row["$oid_fld"]; $this->resultindexes[] = $row["$x_fld"] ."@". $row["$y_fld"]; // Output JSON $qShpLink = "{\"shplink\": [\"0\",\"0\",\"" . $shpMinx ."+". $shpMiny ."+". $shpMaxx ."+". $shpMaxy ."\"]}"; if ($nres > 0) $this->qStr .= ", "; // Add shape link $this->qStr .= "[" . $qShpLink; // Add 'normal' field values foreach ($resFieldList as $fn) { $this->qStr .= $this->printFieldValues($fn, $row["$fn"]); } $this->qStr .= "]"; $nres++; // Stop query if result records exceed limit set in config.ini if ($nres > $this->limitResult) break; } $this->numResults = $nres; $res->free(); $dbh->disconnect(); } } // END CLASS XYQUERY /********************************************** * ATTRIBUTE QUERY RESULTS FOR POSTGIS LAYER **********************************************/ class PGQuery extends Query { function PGQuery($map, $qLayer, $glayer, $queryStr, $zoomFull) { $this->map = $map; $this->qLayer = $qLayer; $this->qLayerType = $this->qLayer->type; $this->glayer = $glayer; $this->zoomFull = $zoomFull; $this->layerEncoding = $glayer->getLayerEncoding(); $this->limitResult = $_SESSION["limitResult"]; $this->pointBuffer = $_SESSION["pointBuffer"]; $this->changeLayProj = $this->checkProjection(); //error_log("change proj: " . $this->changeLayProj); // dump results to resultString $this->dumpPGQueryResults($queryStr); } function dumpPGQueryResults($queryStr) { $layerDataList = $this->pgLayerParseData(); $geom = $layerDataList['geocol']; $dbtable = $layerDataList['dbtable']; $unique_field = $layerDataList['unique_field']; // Load PGSQL extension if necessary if (PHP_OS == "WINNT" || PHP_OS == "WIN32") { if (! extension_loaded('pgsql')) { dl('php_pgsql.dll'); } } // CONNECT TO DB $connString = $this->qLayer->connection; if (!($connection = pg_Connect($connString))){ error_log ("P.MAPPER: Could not connect to database"); error_log ("P.MAPPER: PG Connection error: " . pg_last_error($connection)); exit(); } // FIELDS and FIELD HEADERS for result $selFields = $this->glayer->getResFields(); foreach ($selFields as $f) { $s .= "$f,"; } // Select string for DB query $select = substr($s, 0, -1); // Apply already existing filter on layer $pg_filter = trim(str_replace('"', '', $this->qLayer->getFilter())); if (strlen($pg_filter) > 2 && $pg_filter != "(null)") { $queryStr .= " AND $pg_filter "; } // Limit search to limit set in INI file $searchlimit = $this->limitResult + 1; // RUN DB DEFINE QUERY $query = "SELECT $unique_field, xmin(box3d($geom)), ymin(box3d($geom)), xmax(box3d($geom)), ymax(box3d($geom)), $select FROM $dbtable WHERE $queryStr LIMIT $searchlimit"; //error_log($query); //$qresult = pg_Exec ($connection, $query); $qresult = pg_query ($connection, $query); if (!$qresult) { error_log("P.MAPPER: PG Query error for : $query" . pg_result_error($qresult)); } $numrows = pg_numrows ($qresult); $this->numResults = $numrows; // CREATE HTML OUPTPUT if ($numrows > 0){ if ($this->zoomFull) { // Maximum start extents $mExtMinx = 999999999; $mExtMiny = 999999999; $mExtMaxx = -999999999; $mExtMaxy = -999999999; } // Fetch records from db and print them out for ($r=0; $r < $numrows; ++$r){ $a = pg_fetch_row($qresult, $r); $a_rows = count($a); $qShpIdx = $a[0]; $oids[] = $qShpIdx; // If map and layer have different proj, re-project extents if ($this->changeLayProj) { $pb = $this->reprojectExtent($a); $xmin = $pb['shpMinx']; $ymin = $pb['shpMiny']; $xmax = $pb['shpMaxx']; $ymax = $pb['shpMaxy']; } else { $xmin = $a[1]; $ymin = $a[2]; $xmax = $a[3]; $ymax = $a[4]; } // Set buffer for point layers if ($this->qLayerType == 0) { $buf = $this->pointBuffer; // set buffer depending on dimensions of your coordinate system $xmin -= $buf; $ymin -= $buf; $xmax += $buf; $ymax += $buf; } // Look for min/max extents of ALL features if ($this->zoomFull) { $mExtMinx = min($mExtMinx, $xmin); $mExtMiny = min($mExtMiny, $ymin); $mExtMaxx = max($mExtMaxx, $xmax); $mExtMaxy = max($mExtMaxy, $ymax); } // Output JSON $qShpLink = "{\"shplink\": [" . ($this->zoomFull ? "\"0\",\"0" : "\"" . $this->qLayerName ."\",\"".$qShpIdx) ."\",\"". $xmin ."+". $ymin ."+". $xmax ."+". $ymax ."\"]}"; // print SHAPEINDEX link $this->qStr .= "[" . $qShpLink; // Print all OTHER FIELDS for ($i=5; $i < $a_rows; ++$i) { //printFieldValues($glayer, $qlayerName, $fldName, $a[$i]); $this->qStr .= $this->printFieldValues($fldName, $a[$i]); } $this->qStr .= "]"; if ($r < ($numrows - 1)) $this->qStr .= ", "; //$this->qStr .= "\n"; } // Full extent for ALL features if ($this->zoomFull) { $this->maxExtent = array($mExtMinx, $mExtMiny, $mExtMaxx, $mExtMaxy); } else { $this->maxExtent = 0; } $this->resultindexes = $oids; } pg_Close ($connection); } /** * Parse DATA tag from PostGIS layer */ function pgLayerParseData() { $pg_data = $this->qLayer->data; //"the_geom from images"; $dl = preg_split('/ from /i', $pg_data); $data_list['geocol'] = trim($dl[0]); $flds = trim($dl[1]); if (substr($flds, 0, 1) == '(') { // is of type "the_geom from (select the_geom, oid, from mytable) AS foo USING UNIQUE gid USING SRID=4258" $tabl = preg_split('/as ([a-z]|_|[A-Z]|[0-9])+ using unique /i', $dl[2]); $unique_list = preg_split('/[\s,]+/', $tabl[1]); $data_list['dbtable'] = $flds . " from " . trim($tabl[0]) . " as foo "; $data_list['unique_field'] = trim($unique_list[0]); } else { $tabl = preg_split('/using unique/i', $dl[1]); if (count($tabl) > 1) { // is of type "the_geom from mytable USING UNIQUE gid " $data_list['dbtable'] = trim($tabl[0]); //$data_list['unique_field'] = trim($tabl[1]); $unique_list = preg_split('/[\s]+/', trim($tabl[1])); $data_list['unique_field'] = trim($unique_list[0]); } else { // is of type "the_geom from mytable" $dbtable = trim($dl[1]); $data_list['dbtable'] = $dbtable; $data_list['unique_field'] = "oid"; error_log("P.MAPPER Warning: no UNIQUE field specified for PostGIS table '$dbtable'. Trying using OID field..."); } } //print_r($data_list); return $data_list; } function reprojectExtent($inExt) { $qShpBounds = ms_newRectObj(); // Apply buffer in order to have a correct re-projection of POINT layers $pjbuff = ($this->qLayer->type == 0 ? 0.0000001 : 0); $sMinx = $inExt[1] - $pjbuff; $sMiny = $inExt[2] - $pjbuff; $sMaxx = $inExt[3] + $pjbuff; $sMaxy = $inExt[4] + $pjbuff; $qShpBounds->set("minx", $sMinx); $qShpBounds->set("miny", $sMiny); $qShpBounds->set("maxx", $sMaxx); $qShpBounds->set("maxy", $sMaxy); $qShpBounds->project($this->qLayerProjObj, $this->mapProjObj); $pb['shpMinx'] = $qShpBounds->minx; $pb['shpMiny'] = $qShpBounds->miny; $pb['shpMaxx'] = $qShpBounds->maxx; $pb['shpMaxy'] = $qShpBounds->maxy; return $pb; } function returnMaxExtent() { return $this->maxExtent; } } //END CLASS PGQUERY ?>