p['ms'] = $msFormat; $this->p['sql'] = $sqlFormat; } public function toMapServer($field_name, $value) { return sprintf($this->p['ms'], strtoupper($field_name), $value); } public function toSQL($field_name, $value) { return sprintf($this->p['sql'], $field_name, $value); } } class Operator { protected $ms_format = ""; protected $sql_format = ""; public function __construct($msFormat, $sqlFormat) { $this->ms_format = $msFormat; $this->sql_format = $sqlFormat; } public function toMapServer($v) { return sprintf($this->ms_format, $v); } public function toSQL($v) { return sprintf($this->sql_format, $v); } } $comparitors = array(); # string specific operations # mapserver doesn't quite honor this the way I'd like it to but at the very least, # the SQL databases will support it. $comparitors['eq-str'] = new Comparitor('"[%s]" == "%s"', "%s = '%s'"); $comparitors['like'] = new Comparitor('"[%s]" =~ /.*%s.*/', "%s like '%%%s%%'"); $comparitors['left-like'] = new Comparitor('"[%s]" =~ /.*%s/', "%s like '%%%s'"); $comparitors['right-like'] = new Comparitor('"[%s]" =~ /%s.*/', "%s like '%s%%'"); # # This will probably look terribly goofy to anyone who didn't write this code. # Here's why it's neccessary: # - The "/regex/i" is not accepted by MapServer's EXPRESSION clause. It's not recognized as a regex. # - /[Aa][Zz]/ will try to be parsed as a column name. # Therefore, we need a regex trick, which is to use the or operator (a|A)(z|Z) # class IgnoreCaseLike extends Comparitor { public function toMapServer($field_name, $value) { $lcase_value = strtolower($value); $ucase_value = strtoupper($value); $result = ''; for($i = 0; $i < strlen($lcase_value); $i++) { $result = $result . '('.$lcase_value[$i].'|'.$ucase_value[$i].')'; } return sprintf($this->p['ms'], strtoupper($field_name), $result); } } $comparitors['like-icase'] = new IgnoreCaseLike('"[%s]" =~ /.*%s.*/', "upper(%s) like '%%'||upper('%s')||'%%'"); $comparitors['left-like-icase'] = new IgnoreCaseLike('"[%s]" =~ /.*%s/', "%s like '%%'||upper('%s')"); $comparitors['right-like-icase'] = new IgnoreCaseLike('"[%s]" =~ /%s.*/', "%s like upper('%s')||'%%'"); # all other types $comparitors['eq'] = new Comparitor('[%s] == %s', "%s = %s"); $comparitors['ge'] = new Comparitor('[%s] >= %s', '%s >= %s'); $comparitors['gt'] = new Comparitor('[%s] > %s', '%s > %s'); $comparitors['le'] = new Comparitor('[%s] <= %s', '%s <= %s'); $comparitors['lt'] = new Comparitor('[%s] < %s', '%s < %s'); $operators = array(); # MS, SQL formats # this is probably a little redundant but C'est la Vie. $operators['init'] = new Operator('(%s)', '%s'); $operators['and'] = new Operator('AND (%s)', 'and %s'); $operators['or'] = new Operator('OR (%s)', 'or %s'); $operators['nand'] = new Operator('AND (NOT (%s))', 'and not (%s)'); $operators['nor'] = new Operator('OR (NOT (%s))', 'or not (%s)'); class Predicate { protected $self = array(); /* * field_name = Field Name to search * value = value to test against * operator = operator class * comparitor = comparitor class * blank_okay (boolean) = set whether or not a blank value should be evaluated */ public function __construct($layer, $field_name, $value, $operator, $comparitor, $blank_okay = true) { $this->self['layer'] = $layer; $this->self['fname'] = $field_name; $this->self['val'] = $value; $this->self['op'] = $operator; $this->self['comp'] = $comparitor; $this->self['blank'] = $blank_okay; } public function getLayer() { return $this->self['layer']; } public function toMapServer() { if(((string)$this->self['val'] == '') and $this->self['blank']) { return ''; } return $this->self['op']->toMapServer($this->self['comp']->toMapServer($this->self['fname'], $this->self['val'])); } public function toSQL() { return $this->self['op']->toSQL($this->self['comp']->toSQL($this->self['fname'], $this->self['val'])); } } $predicates = array(); # the mode! $mode = $_REQUEST['mode']; $highlightResults = parseBoolean($_REQUEST['highlight']); $zoomToFirst = parseBoolean($_REQUEST['zoom_to_first']); # layers to search $query_layers = array(); $query_layers[0] = $_REQUEST['layer0']; # this will check to see which template format should be used # query/itemquery/select/popup/etc. $query_templates = array(); $query_templates[0] = $_REQUEST['template0']; $usejQuery = $_REQUEST['usejQuery']; $template5 = $_REQUEST['template']; $template_header = $_REQUEST['template_header']; $template_footer = $_REQUEST['template_footer']; $template_header_tools = $_REQUEST['template_header_tools']; //Lets do some error checking to make sure the template files are right if($usejQuery && file_exists($CONFIGURATION['root'].$usejQuery) == false) { echo "jQuery template not valid"; exit(); } if(!$template5 || file_exists($CONFIGURATION['root'].$template5) == false) { echo "Template not valid"; exit(); } if(!$template_header || file_exists($CONFIGURATION['root'].$template_header) == false) { echo "Template header not valid"; exit(); } if(!$template_footer || file_exists($CONFIGURATION['root'].$template_footer) == false) { echo "Template footer not valid"; exit(); } $vector_js = "removeFeature();"; # get set of predicates # I've only allowed for 255 right now... people will have to deal with this for($i = 0; $i < 255; $i++) { if($_REQUEST['operator'.$i] != NULL or $i == 0) { # see if the layer is different $layer = $query_layers[0]; if(isset($_REQUEST['layer'.$i])) { $layer = $_REQUEST['layer'.$i]; } // $template = $query_templates[0]; if(isset($_REQUEST['template'.$i])) { $template = $_REQUEST['template'.$i]; } if(!in_array($layer, $query_layers)) { $query_layers[] = $layer; $query_templates[] = $template; } # check the opeartor $operator = false; $comparitor = false; if($i == 0) { $operator = $operators['init']; } else if(isset($_REQUEST['operator'.$i]) and $operators[$_REQUEST['operator'.$i]]) { $operator = $operators[$_REQUEST['operator'.$i]]; } else { # return error saying no valid operator found } if(isset($_REQUEST['comparitor'.$i]) and $comparitors[$_REQUEST['comparitor'.$i]]) { $comparitor = $comparitors[$_REQUEST['comparitor'.$i]]; } else { # return error saying there is no valid comparitor } $blank_okay = true; if(isset($_REQUEST['blanks'.$i]) and strtolower($_REQUEST['blanks'.$i]) == 'false') { $blank_okay = false; } # if a value is not set for subsequent inputs, use the first input # this allows queries to permeate across multiple layers $value = $_REQUEST['value0']; if(isset($_REQUEST['value'.$i])) { $value = $_REQUEST['value'.$i]; } //LK Stupid IE $value = str_replace('__',' ',$value); $p = new Predicate($layer, $_REQUEST['fieldname'.$i], $value, $operator, $comparitor, $blank_okay); $predicates[] = $p; } } # # Iterate through the layers and build the results set. # # Load the mapbook $mapbook = getMapbook(); $msXML = $mapbook->getElementsByTagName('map-source'); # content stores the HTML results $content = ''; $totalResults = 0; $firstResult = false; # store the features so we can render a map later $resultFeatures = array(); # These are all the connection types, we ID the ones to be used as SQL versus MS regular expressions # MS_INLINE, MS_SHAPEFILE, MS_TILED_SHAPEFILE, MS_SDE, MS_OGR, MS_TILED_OGR, MS_POSTGIS, MS_WMS, MS_ORACLESPATIAL, MS_WFS, MS_GRATICULE, MS_MYGIS, MS_RASTER, MS_PLUGIN $SQL_LAYER_TYPES = array(MS_POSTGIS, MS_ORACLESPATIAL, MS_MYGIS); $NOT_SUPPORTED = array(MS_INLINE, MS_SDE, MS_WMS, WMS_WFS, MS_GRATICULE, MS_RASTER, MS_PLUGIN); for($la = 0; $la < sizeof($query_layers); $la++) { # get the layer. for($map_source_i = 0; $map_source_i < $msXML->length; $map_source_i++) { $node = $msXML->item($map_source_i); $layers = $node->getElementsByTagName('layer'); for($l = 0; $l < $layers->length; $l++) { $layer = $layers->item($l); $layerName = $layer->getAttribute('name'); $path = $node->getAttribute('name').'/'.$layerName; if($path == $query_layers[$la]) { $file = $node->getElementsByTagName('file')->item(0)->firstChild->nodeValue; # Okay, now it's time to cook if(substr($file,0,1) == '.') { $file = $CONFIGURATION['root'].$file; } $map = ms_newMapObj($file); # Create an array of query layers $queryLayers = array(); if($layerName == 'all') { for($ml = 0; $ml < $map->numlayers; $ml++) { array_push($queryLayers, $map->getLayer($ml)); } } else { # Turn on the specific layer array_push($queryLayers, $map->getLayerByName($layerName)); } # Iterate through the queryLayers... foreach($queryLayers as $queryLayer) { $predicate_strings = array(); $is_sql = in_array($queryLayer->connectiontype, $SQL_LAYER_TYPES); for($i = 0; $i < sizeof($predicates); $i++) { if($predicates[$i]->getLayer() == $query_layers[$la]) { if($is_sql) { $predicate_strings[] = $predicates[$i]->toSQL(); } else { $predicate_strings[] = $predicates[$i]->toMapServer(); } } } # the filter string. $filter_string = implode(' ', $predicate_strings); # diag message # print 'Search Layer: '.$query_layers[$la].' Template: '.$query_templates[$la].' FILTER: '.$filter_string; # print '
'; $queryLayer->set('status', MS_DEFAULT); if($is_sql) { if($filter_string) { $queryLayer->setFilter($filter_string); } $queryLayer->set('template', $queryLayer->getMetaData($query_templates[$la])); } else { # we need to create a query class # in order to configure complex expressions with shapefiles + OGR $tmp_layer = ms_newLayerObj($map); $tmp_layer->set('data', $queryLayer->data); $tmp_layer->set('connection', $queryLayer->connection); #$tmp_layer->setConnectionType($queryLayer->connectiontype); $tmp_class = ms_newClassObj($tmp_layer); if(!$usejQuery) { $tmp_layer->set('header', $CONFIGURATION['root'].$template_header); $tmp_layer->set('footer', $CONFIGURATION['root'].$template_footer); } $tmp_class->set('template', $CONFIGURATION['root'].$template5); if($filter_string) { $tmp_class->setExpression('('.$filter_string.')'); } $queryLayer = $tmp_layer; } #$queryLayer->setFilter($filter_string); #$queryLayer->set('filteritem', 'PARC_CODE'); #$queryLayer->setFilter('1'); #$queryLayer->setFilter('[PARC_CODE] == 1'); $queryLayer->queryByRect($queryLayer->getExtent()); $queryLayer->open(); $numResults = $queryLayer->getNumResults(); if($numResults > 0 and $totalResults == 0) { $res = $queryLayer->getResult(0); $firstResult = $queryLayer->getFeature($res->shapeindex); } for($rx = 0; $rx < $numResults; $rx++) { $res = $queryLayer->getResult($rx); array_push($resultFeatures, $queryLayer->getFeature($res->shapeindex)); } $totalResults += $numResults; $queryLayer->close(); #print 'Total Results: '.$numResults; } $results = $map->processquerytemplate(array(), false); $content = $content . $results; } } } $vector_js = ""; foreach($resultFeatures as $shape) { //LK Add found shapes to vector layer $wkt = $shape->toWkt(); $id = $shape->values[$_REQUEST['id']]; $values = json_encode($shape->values); $vector_js .= "highlight.draw(\"" . $wkt . "\",\"" . $id . "\",\"\",\"highlight\",$values);"; } } # # Didn't find any results # so we're going to just say, "I found nothing" to the user and quit. # if($totalResults == 0) { if($CONFIGURATION['query_miss'] == NULL) { $CONFIGURATION['query_miss'] = $CONFIGURATION['itemquery_miss']; } print implode('', file($CONFIGURATION['query_miss'])); exit(0); } if($mode == 'search') { header('Content-type: text/xml'); print ""; print ""; print "Results"; } else { // if($CONFIGURATION['query_header'] == NULL) { // $CONFIGURATION['query_header'] = $CONFIGURATION['itemquery_header']; // } // if($CONFIGURATION['query_footer'] == NULL) { // $CONFIGURATION['query_footer'] = $CONFIGURATION['itemquery_footer']; // } // $headerArray = file($header_template); // $footerArray = file($footer_template); // $contents = implode('', array_merge($headerArray, array($content), $footerArray)); $contents = str_replace("[nlr]",$totalResults,$content); print $contents; } print "]]>"; print ""; } elseif($mode == 'details') { print_r($results); } elseif($mode == 'map') { $mapext = $_REQUEST['mapext']; $mapsize = $_REQUEST['map_size']; if(!isset($mapsize)) { $mapsize = $_REQUEST['mapsize']; } $path = ''; $highlight_map = ms_newMapObj($path.'itemquery/highlight.map'); $pointsLayer = $highlight_map->getLayerByName('points'); $polygonsLayer = $highlight_map->getLayerByName('polygons'); $linesLayer = $highlight_map->getLayerByName('lines'); for($i = 0; $i < sizeof($resultFeatures); $i++) { if($resultFeatures[$i]->type == MS_SHAPE_POINT) { $pointsLayer->addFeature($resultFeatures[$i]); } elseif($resultFeatures[$i]->type == MS_SHAPE_POLYGON) { $polygonsLayer->addFeature($resultFeatures[$i]); } elseif($resultFeatures[$i]->type == MS_SHAPE_LINE) { $linesLayer->addFeature($resultFeatures[$i]); } } header('Content-type: image/gif'); $ext = explode(' ', $mapext); $size = explode(' ', $mapsize); $highlight_map->setExtent($ext[0],$ext[1],$ext[2],$ext[3]); $highlight_map->setSize($size[0], $size[1]); $image = $highlight_map->prepareImage(); $image = $highlight_map->draw(); $image->saveImage(''); } else if($mode == 'results') { header("Content-type: text/plain"); print $content; } else { header('Content-type: text/html'); print 'Error! Unknown mode!'; } function parseBoolean($p) { return($p == 1 || $p == '1' || strtolower($p) == 'true' || strtolower($p) == 'on'); } ?>