Copyright (c) 2003, DM Solutions Group Inc. * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. **/ // set the time limit set_time_limit( 120 ); //set the language resource file $szLanguageResource = str_replace("\\","/",dirname(__FILE__))."/ExtractWFSData.dbf"; // include the layer attribute handling functions include( dirname(__FILE__)."/../LayerAttributes.php" ); // set the flag to setup the mapsession if ( !defined("LOAD_MAPSESSION") ) define("LOAD_MAPSESSION", 1); // include the session handling file (currently only required for MLT) include_once("../session.inc.php"); include_once("../CWC2ButtonCache.php"); // include the ogr handling functions include( COMMON."/ogr/ogr2ogr.php" ); // check if the ogr module is available $szOGRModuleName = ''; $bModuleFound = checkOGRModule( $szOGRModuleName ); // get the form vars $_FORM = array_merge( $_GET, $_POST ); /* ============================================================================ * Determine the layer specific info * ========================================================================= */ // init vars $nCount = 0; $nSelectedLayer = ''; $szSelectedLayerName = ""; $szErrorNotice = ""; $szWFSConnection = ""; $szLayerType = ""; $bSkipGetFeature = false; $bClearFilter = false; $nLayerCount = $oMapSession->oMap->numlayers; $szSpacialFilter = ''; $szExistingWFSFilter = ''; $szROIExists = ''; // loop through layers and determine which ones are selected for ( $i=0; $i<$nLayerCount; $i++ ) { // init var $bSelected = false; // get layer $oLayer = $oMapSession->oMap->getLayer( $i ); // check if overide on selected layer is needed if ( isset( $_FORM["selectedlayers"] ) && strlen( $_FORM["selectedlayers"] ) > 0 ) { // put layers into array $aszLayers = explode( ",", $_FORM["selectedlayers"] ); for( $j=0; $jname || $aszLayers[$j] == $oLayer->getMetadata( "WMS_NAME" ) || $aszLayers[$j] == $oLayer->getMetadata( "WMS_TITLE" )) { $bSelected = true; } } // check if layer is in the array //$bSelected = in_array( trim( $oLayer->name ), $aszLayers ); } else { $bSelected = $oLayer->getmetadata("selected") == 1; } // process layer if selected if ( $bSelected ) { // record the info for first selected layer only if ( strlen( $nSelectedLayer ) <= 0 ) { // determine the layer name to use $szSelectedLayerName = $oLayer->name; // process according to layer type if( $oLayer->connectiontype == MS_WFS ) { // record layer index $nSelectedLayer = $i; // record the connection string $szWFSConnection = $oLayer->connection; // set type $szLayerType = "WFS"; } elseif( $oLayer->connectiontype == MS_WMS ) { // record layer index $nSelectedLayer = $i; // set type $szLayerType = "WMS"; $szSelectedLayerName = $oLayer->getMetadata( "WMS_NAME" ); // resort to layer name for the selected layer name if ( strlen( $szSelectedLayerName ) <= 0 ) { $szSelectedLayerName = $oLayer->name; } // get the connection info only if extracting if ( isset( $_FORM["txtExtract"] ) && $_FORM["txtExtract"] == 1 ) { // get the url to perform a describelayer on $szWMSConnection = trim( $oLayer->connection ); $szUpperCase = strtoupper( $szWMSConnection ); // check last char for ? or & if ( substr( $szWMSConnection, -1 ) != "?" && substr( $szWMSConnection, -1 ) != "&" ) { // check for ? if ( strpos( $szWMSConnection, "?" ) === false ) { $szWMSConnection .= "?"; } else $szWMSConnection .= "&"; } // check for and add VERSION if ( strpos( $szUpperCase, "VERSION=" ) === false ) $szWMSConnection .= "VERSION=1.1.0&"; // check for and add SERVICE if ( strpos( $szUpperCase, "SERVICE=" ) === false ) $szWMSConnection .= "SERVICE=WMS&"; // add LAYERS if ( strpos( $szUpperCase, "LAYERS=" ) === false ) $szWMSConnection .= "LAYERS=".$szSelectedLayerName."&"; // add REQUEST $szWMSConnection .= "REQUEST=DESCRIBELAYER"; // perform a describe layer if ( !$aszWFSConnection = getWFSResource( $szWMSConnection ) ) { $szErrorNotice .= $oMLT->get("12", "WMS `DescribeLayer` request failed. ". "The server returned the following: %1\$s", array() ); } else { // record set the wfs connection $szWFSConnection = $aszWFSConnection['wfs']; } } } // increment the counter $nCount++; } } } /* ============================================================================ * Build spacial filter * ========================================================================= */ if ( strlen( $nSelectedLayer ) > 0 ) { // get layer $oLayer = $oMapSession->oMap->getLayer( $nSelectedLayer ); // build new spacial filter for current ROI or extent $szSpacialFilter = buildSpacialFilterString( $oMapSession->oMap, $oLayer ); // check for existing wfs_filter $szExistingWFSFilter = trim( $oLayer->getmetadata( "wfs_filter" ) ); // check for spatial tags if ( strlen( $szExistingWFSFilter ) > 0 ) { $szTmpFilter = strtolower( $szExistingWFSFilter ); if ( strpos( $szTmpFilter, 'get('19', 'Note:
This layer has a WFS '. 'filter set that contains spatial attributes which may or '. 'may not match the current ROI/extent. These spatial '. 'attributes will be used instead of the current ROI/extent '. 'for this data extraction.' ); } else { $szSpacialFilter = "".$szSpacialFilter. $szExistingWFSFilter.""; } } else { // set flag to clear the metadata item after use $bClearFilter = true; } } /* ============================================================================ * Perform extraction * ========================================================================= */ if ( isset( $_FORM["txtExtract"] ) && $_FORM["txtExtract"] == 1 ) { // be sure there is a connection if ( strlen( trim( $szWFSConnection ) ) > 0 ) { // create the temp download directory $szDownloadPath = cleanPath( $_SESSION["gszTmpImgPath"] ); $szDownloadUrl = cleanPath( $_SESSION["gszTmpWebPath"] ); $szUniqid = md5( uniqid( rand(), true ) ); // check if directory exists if ( !is_dir( $szDownloadPath.$szUniqid."/" ) ) @mkdir( $szDownloadPath.$szUniqid."/", 0777 ); // check for failure if ( !is_dir( $szDownloadPath.$szUniqid."/" ) ) { // set flag $bSkipExtract = true; // set error message $szErrorNotice .= $oMLT->get("17", "Failed to create temp download directory." ); } else { // set flag $bSkipExtract = false; // update paths $szDownloadPath .= $szUniqid."/"; $szDownloadUrl .= $szUniqid."/"; } // define the temp file name if ( isset( $_FORM["txtDLFilename"] ) && strlen( trim( $_FORM["txtDLFilename"] ) ) > 0 ) $szFile = $_FORM["txtDLFilename"]; else $szFile = $szUniqid; // perform an executeWFSGetfeature() call if WFS if ( $szLayerType == "WFS" && !$bSkipExtract ) { // get layer $oLayer = $oMapSession->oMap->getLayer( $nSelectedLayer ); // set the filter metadata $oLayer->setmetadata( "wfs_filter", $szSpacialFilter ); // get features if ( !$bSkipGetFeature ) { // execute $szTmpGML = $oLayer->executeWFSGetfeature(); // clear the filter if necessary if ( $bClearFilter ) { $oLayer->removeMetaData( "wfs_filter" ); } else { // otherwise restore it $oLayer->setmetadata( "wfs_filter", $szExistingWFSFilter ); } // check success if ( strlen( trim( $szTmpGML ) ) > 0 ) { // flag success $szGMLSuccess = "NOERROR"; // set extension $szExt = ".gml"; // copy temp gml to download if ( !copy( $szTmpGML, $szDownloadPath.$szFile.$szExt ) ) $szGMLSuccess .= $oMLT->get("13", "An error occurred ". "copying the temp gml file. Please check permissions ". "on your temp folder." ); // delete temp if ( file_exists( $szTmpGML ) ) unlink( $szTmpGML ); } else { // set error message $szGMLSuccess = $oMLT->get("14", "An error occurred getting ". "WFS features for this layer." ); } } } elseif ( !$bSkipExtract ) // layer is WMS { // check last char for ? or & if ( substr( $szWFSConnection, -1 ) != "?" && substr( $szWFSConnection, -1 ) != "&" ) { // check for ? if ( strpos( $szWFSConnection, "?" ) === false ) { $szWFSConnection .= "?"; } else $szWFSConnection .= "&"; } // copy to uppercase for comparison $szUpperCase = strtoupper( $szWFSConnection ); // check for service if ( strpos( $szUpperCase, "SERVICE=" ) === false ) $szWFSConnection .= "SERVICE=WFS&"; // check for version if ( strpos( $szUpperCase, "VERSION=" ) === false ) $szWFSConnection .= "VERSION=1.0.0&"; // check for type name if ( strpos( $szUpperCase, "TYPENAME=" ) === false ) { // get the type name if ( isset( $aszWFSConnection['typename'] ) ) { $szTypeName = ''; foreach( $aszWFSConnection['typename'] as $szCurrentTypeName ) { $szTypeName .= $szCurrentTypeName.','; } // remove final ',' if ( substr( $szTypeName, -1, 1 ) == ',' ) { $szTypeName = substr( $szTypeName, 0, -1 ); } } else { $szTypeName = $szSelectedLayerName; } $szWFSConnection .= "TYPENAME=".$szTypeName."&"; } // extract gml $szExt = ".gml"; $szTmpFile = getGML( $szWFSConnection. "request=getfeature&filter=". urlencode( $szSpacialFilter ).'' ); // copy the temp file if ( file_exists( $szTmpFile ) ) { copy( $szTmpFile, $szDownloadPath.$szFile.$szExt ); $szGMLSuccess = 'NOERROR'; } else { $szGMLSuccess = 'Errors'; } } /* ============================================================================ * Check result and convert output if necessary * ========================================================================= */ // check result if ( $szGMLSuccess == "NOERROR" && !$bSkipGetFeature ) { // convert to shape if necessary if ( isset( $_FORM["selOutputType"] ) && strtoupper($_FORM["selOutputType"]) == "SHAPE" ) { // convert & check success if ( !ogr2ogr( $szDownloadPath.$szFile.$szExt, $szDownloadPath. $szFile.".shp","ESRI Shapefile" ) ) { // give error $szErrorNotice .= $oMLT->get("11", "Unable to create Shape ". "file. It is most likely that no features were found for ". "this layer in the current region." ); // cancel download $szDownloadUrl = ""; } else { // archive the 3 files $aSzFiles = array($szDownloadPath.$szFile.".shp", $szDownloadPath.$szFile.".shx", $szDownloadPath.$szFile.".dbf" ); if ( isset( $_FORM["selCompressType"] ) && strtoupper($_FORM["selCompressType"]) == "TGZ" ) { if ( !tar( $aSzFiles, $szDownloadPath.$szFile.".tar" ) ) $szErrorNotice .= $oMLT->get("10", "Could not create archive" ); else { // delete files if ( file_exists( $szDownloadPath.$szFile.".shp" ) ) unlink( $szDownloadPath.$szFile.".shp" ); if ( file_exists( $szDownloadPath.$szFile.".shx" ) ) unlink( $szDownloadPath.$szFile.".shx" ); if ( file_exists( $szDownloadPath.$szFile.".dbf" ) ) unlink( $szDownloadPath.$szFile.".dbf" ); } // set the ext name to download $szExt = ".tar.gz"; // compress gZip( $szDownloadPath.$szFile.".tar", $szDownloadPath.$szFile.$szExt ); // delete the original file if ( file_exists( $szDownloadPath.$szFile.".tar" ) ) unlink( $szDownloadPath.$szFile.".tar" ); } else if ( isset( $_FORM["selCompressType"] ) && strtoupper($_FORM["selCompressType"]) == "ZIP" ) { // combine shape files into zip (compressed) $szExt = ".zip"; zip( $aSzFiles, $szDownloadPath.$szFile.$szExt ); } } } else { $aSzFiles = array( $szTmpFile ); if ( isset( $_FORM["selCompressType"] ) && strtoupper($_FORM["selCompressType"]) == "TGZ" ) { if ( !tar( $aSzFiles, $szDownloadPath.$szFile.".tar" ) ) $szErrorNotice .= $oMLT->get("10", "Could not create archive" ); $szExt = ".tar.gz"; // compress gZip( $szDownloadPath.$szFile.".tar", $szDownloadPath.$szFile.$szExt ); // delete the original file (tar file) if ( file_exists( $szDownloadPath.$szFile.".tar" ) ) unlink( $szDownloadPath.$szFile.".tar" ); } else if ( isset( $_FORM["selCompressType"] ) && strtoupper($_FORM["selCompressType"]) == "ZIP" ) { $szExt = ".zip"; zip( $aSzFiles, $szDownloadPath.$szFile.$szExt ); } } } else { // output error $szGMLError = $szGMLSuccess; // clear url $szDownloadUrl = ""; } } else { // give error message $szErrorNotice .= $oMLT->get("4", "Invalid layer or none selected. ". "Please ensure that the selected layer is a WFS or WMS layer." ); } } /* ============================================================================ * Determine the output filename to display * ========================================================================= */ if ( isset( $_FORM["txtDLFilename"] ) && strlen( trim( $_FORM["txtDLFilename"] ) ) > 0 ) { $szDLFilename = $_FORM["txtDLFilename"]; } else { $szDLFilename = $szSelectedLayerName; } /* ============================================================================ * Make close button * ========================================================================= */ $szCloseButton = makeButton( 'CloseWindow', '', 'ExtractWFSData', "icons/icon_cancel.png", $oCommonMLT->get("Close", "Close"), $oCommonMLT->get("CloseTip", "Close Dialog"), array( 'width' => 75) ); /** * getGML() * * Postscript: This function writes the given URL to the given file. * * @param $szURL string - URL to the GML source. * @param $szTmpFile string - Path and filename of the file to write to. * @param $oMLT object - Translation object * @return string - "NOERROR" if successful, error message if failed. * @desc Write url results to given file. */ /* function getGML( $szURL, $szTmpFile, $oMLT ) { // read the xml datasource $aszFile = file( $szURL ); // check to see if an error was generated if ( !is_array( $aszFile ) || strpos( strtoupper( $aszFile[0] ), 'get("5", "WFS `GetFeature` request failed. ". "The server returned the following: %1\$s", array( $szServerDump ) ); } // open the tmp file for writing if ( !( $fp = fopen( $szTmpFile, "w" ) ) ) { // open failed so give error return $oMLT->get("6", "File IO. Unable to open file(%1\$s)", array( $szTmpFile ) ); } // process url foreach( $aszFile as $line ) { // write entry to file fputs($fp, $line."\n"); } // close the file fclose($fp); // return true return "NOERROR"; } */ /** * parseDesc() * * Postcondition: This function parses the given array and returns the wfs param. * * @param axValues Array - Mixed array of XML tags to process. * @return string - WFS onlineresource. * @desc Parses array and returns wfs online resource. */ function parseDesc( $axValues ) { // loop through each item of the array $nCount = count( $axValues ); for ( $i=0; $i < $nCount; $i++ ) { // only process "LayerDescription" tag if ( strtoupper( $axValues[$i]["tag"] ) == "LAYERDESCRIPTION" ) return $axValues[$i]["attributes"]["wfs"]; } // if here then errors return null; // end parseDesc() function } /** * getBboxIntersect() * * Postcondition: This function determines the intersecting bbox between the * two given ones. The input and output format is: * "minx,miny max,maxy" * * @param $szBbox1 string - Delimited string of bbox extent. * @param $szBbox2 string - Delimited string of bbox extent. * @return mixed - Intersecting Bbox if found otherwise false. * @desc Returns intersecting Bbox or false if does not exist. */ function getBboxIntersect( $szBbox1, $szBbox2 ) { // split apart bboxes $aszTmpBboxMinMax = explode( " ", $szBbox1 ); $aszTmpBobx = explode( ",", $aszTmpBboxMinMax[0] ); $nMinx1 = $aszTmpBobx[0]; $nMiny1 = $aszTmpBobx[1]; $aszTmpBobx = explode( ",", $aszTmpBboxMinMax[1] ); $nMaxx1 = $aszTmpBobx[0]; $nMaxy1 = $aszTmpBobx[1]; $aszTmpBboxMinMax = explode( " ", $szBbox2 ); $aszTmpBobx = explode( ",", $aszTmpBboxMinMax[0] ); $nMinx2 = $aszTmpBobx[0]; $nMiny2 = $aszTmpBobx[1]; $aszTmpBobx = explode( ",", $aszTmpBboxMinMax[1] ); $nMaxx2 = $aszTmpBobx[0]; $nMaxy2 = $aszTmpBobx[1]; // compare minx if ( $nMinx1 >= $nMinx2 && $nMinx1 <= $nMaxx2 ) $nReturnMinx = $nMinx1; elseif( $nMinx2 >= $nMinx1 && $nMinx2 <= $nMaxx1 ) $nReturnMinx = $nMinx2; else return false; // compare maxx if ( $nMaxx1 >= $nMinx2 && $nMaxx1 <= $nMaxx2 ) $nReturnMaxx = $nMaxx1; elseif( $nMaxx2 >= $nMinx1 && $nMaxx2 <= $nMaxx1 ) $nReturnMaxx = $nMaxx2; else return false; // compare miny if ( $nMiny1 >= $nMiny2 && $nMiny1 <= $nMaxy2 ) $nReturnMiny = $nMiny1; elseif( $nMiny2 >= $nMiny1 && $nMiny2 <= $nMaxy1 ) $nReturnMiny = $nMiny2; else return false; // compare maxy if ( $nMaxy1 >= $nMiny2 && $nMaxy1 <= $nMaxy2 ) $nReturnMaxy = $nMaxy1; elseif( $nMaxy2 >= $nMiny1 && $nMaxy2 <= $nMaxy1 ) $nReturnMaxy = $nMaxy2; else return false; // return results return $nReturnMinx.",".$nReturnMiny." ".$nReturnMaxx.",".$nReturnMaxy; // end getBboxIntersect function } function tar( $aszSource, $szDestination ) { // include file include( COMMON."/tar/tar.php" ); // specify filename for output file $tar = new Archive_Tar( $szDestination ); // build archive if ( !$tar->create( $aszSource ) ) return false; else return true; } function gZip( $szSource, $szDestination ) { $fp = fopen( $szSource, "r" ); $data = fread ( $fp, filesize( $szSource ) ); fclose( $fp ); $zp = gzopen( $szDestination, "w9" ); gzwrite( $zp, $data ); gzclose( $zp ); } function zip( $aszSource, $szDestination ) { // include file include_once( COMMON."/zip/zip.php" ); // build archive $szDirName = dirname( $szDestination ); // specify filename for output file $aParams = array(); $aParams[ARCHIVE_ZIP_PARAM_REMOVE_ALL_PATH] = true; $zip = new Archive_Zip( $szDestination ); if( ! $zip->create( $aszSource, $aParams ) ) return false; else return true; } /** * cleanPath() * * Postcondition: This function takes a path and converts all "\" to "/" and * guarantees that the path will end with "/" with no whitespaces. * * @param szPath string - path to clean. * @return string - clean path. * @desc Cleans path and guarantees closing "/". */ function cleanPath( $szPath ) { // replace "\" and trim whitespace $szReturn = trim( str_replace( "\\", "/", $szPath ) ); // check for closing "/" if ( substr( $szReturn, -1 ) != "/" ) $szReturn .= "/"; // return return $szReturn; } /** * buildSpacialFilterString() * * Postcondition: This function returns the spacial filter string based on current * ROI and extents. * * @param $oMap object - The Map to apply the expression to. * @param $oLayer object - The layer to apply the expression to. * @return String - Filter string. * @desc Builds and returns a properly formatted wfs filter string. **/ function buildSpacialFilterString( $oMap, $oLayer ) { // get projection $szProjection = trim( $oLayer->getprojection() ); if ( strlen( $szProjection ) <= 0 ) $szProjection = trim( $oMap->getprojection() ); if ( strlen( $szProjection ) > 0 ) { $szProjection = substr( $szProjection, 5 ); $szProjection = str_replace( 'epsg', 'EPSG', $szProjection ); } if ( substr( $szProjection, 0, 4 ) != 'EPSG' ) { $szProjection = ''; } // check for AOI if ( isset( $_SESSION['ROIRENDERER'] ) && is_array( $_SESSION['ROIRENDERER'] ) && count( $_SESSION['ROIRENDERER'] ) > 0 ) { // loop and build the filter string based on the ROI $bNotFirstExpression = false; $szBbox = ''; foreach( $_SESSION['ROIRENDERER'] as $szTmpROI ) { // process based on type $szThisBbox = ''; switch ( strtoupper($szTmpROI['type'] ) ) { case 'RECTANGLE': $szThisBbox = buildRectFilter( $szTmpROI['aGeoCoords'], $szProjection ); break; case 'CIRCLE': $szThisBbox = buildCircleFilter( $szTmpROI['aGeoCoords'], $szTmpROI['aGeoCoords'][2]-$szTmpROI['aGeoCoords'][0] ); break; case 'POLYGON': $szThisBbox = buildPolygonFilter( $szTmpROI['aGeoCoords'] ); break; default: $szBbox .= ''; } // decide how to add to ROI if ( $bNotFirstExpression ) { switch( $szTmpROI['mode'] ) { // additive case 2: $szBbox = ''.$szBbox.$szThisBbox.''; break; // subtractive case 3: $szBbox = ''.$szBbox.''.$szThisBbox.''; break; } } else $szBbox .= $szThisBbox; // set flag $bNotFirstExpression = true; } } else { // use current extents as bbox $szBbox = buildRectFilter( array( $oMap->extent->minx, $oMap->extent->miny, $oMap->extent->maxx, $oMap->extent->maxy ), $szProjection ); } // return the filter string return $szBbox; // end of buildFilterString function } function buildRectFilter( $adCoords, $szProjection ) { return 'Name'. "". $adCoords[0].','. $adCoords[1].' '. $adCoords[2].','. $adCoords[3]. ''; } function buildCircleFilter( $adCoords, $dDistance ) { return 'Name'. ''.$adCoords[0].','.$adCoords[1]. '". $dDistance.''; } function buildPolygonFilter( $adCoords ) { $szReturn = 'Name'. ''; // loop and build list of coordinates $nCount = count( $adCoords ); $szCoords = ''; for( $i=0; $i<$nCount; $i=$i+2 ) { $szCoords .= $adCoords[$i].','.$adCoords[$i+1].' '; } $szReturn .= trim( $szCoords ); $szReturn .= ''. ''; return $szReturn; } ?>