Location: PHPKode > projects > PhpArcIMS > phpConnector/phparcims_connector.php
<?php
/*
*    Copyright 2001, Christoph Spoerri
*
*    This file is part of the phpArcIMS connector.
*
*    phpArcIMS is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    phpArcIMS is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with Foobar; if not, write to the Free Software
*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*/

/* ***********************************************************************
  			phparcims/aimsconnector.php - Copyright spoerri

Here you can write a license for your code, some comments or any other
information you want to have in your generated code. To to this simply
configure the "headings" directory in uml to point to a directory
where you have your heading files.

or you can just replace the contents of this file with your own.
If you want to do this, this file is located at

/usr/share/apps/umbrello/headings/heading.php

-->Code Generators searches for heading files based on the file extension
   i.e. it will look for a file name ending in ".h" to include in C++ header
   files, and for a file name ending in ".java" to include in all generated
   java code.
   If you name the file "heading.<extension>", Code Generator will always
   choose this file even if there are other files with the same extension in the
   directory. If you name the file something else, it must be the only one with that
   extension in the directory to guarantee that Code Generator will choose it.

you can use variables in your heading files which are replaced at generation
time. possible variables are : author, date, time, filename and filepath.
just write %variable_name%

This file was generated on Wed Oct 15 2003 at 11:08:11
The original location of this file is /home/spoerri/tmp/phparcims/aimsconnector.php
**************************************************************************/

//./phpdocgen.pl -r --defpack phparcims -f --windowtitle 'phpArcIMS Connector API' --doctitle 'phpArcIMS API' ./

require_once 'phparcims0.5/phparcims_map.php';

// not for general consumption
DEFINE(CONNECTOR_VERSION,'0.5.1');

/**
* Defines a request as a feature/query request (currently not used).
* @package phparcims
* @constant string REQUEST_GET_FEATURE
*/
DEFINE(REQUEST_GET_FEATURE,'GET_FEATURE');
/**
* Defines a request as a image/map request (currently not used).
* @package phparcims
* @constant string REQUEST_GET_IMAGE
*/
DEFINE(REQUEST_GET_IMAGE,'GET_IMAGE');
/**
* Defines a request as geocodeing request (currently not used).
* @package phparcims
* @constant string REQUEST_GET_GEOCODE
*/
DEFINE(REQUEST_GET_GEOCODE,'GET_GEOCODE');
/**
* Specifies that the request will retrieve info about a service (currently not used).
* @package phparcims
* @constant string REQUEST_GET_SERVICE_INFO
*/
DEFINE(REQUEST_GET_SERVICE_INFO,'GET_SERVICE_INFO');
/**
* Defines a request as an extraction (currently not used).
* @package phparcims
* @constant string REQUEST_GET_EXTRACT
*/
DEFINE(REQUEST_GET_EXTRACT,'GET_EXTRACT');
/**
* Specifies as reqeust retrieving services info (currently not used).
* @package phparcims
* @constant string REQUEST_GETCLIENTSERVICES
*/
DEFINE(REQUEST_GETCLIENTSERVICES,'GETCLIENTSERVICES');
/**
* Defines a request  that sends a command to the server (currently not used).
* @package phparcims
* @constant string REQUEST_ADMINCMD
*/
DEFINE(REQUEST_ADMINCMD,'ADMINCMD');

/**
* Specifies the image type for the service to be png (16/32 bit).
* @package phparcims
* @constant string AIMS_PNG
*/
DEFINE(AIMS_PNG,'PNG');
/**
* Specifies the image type for the service to be png (8 bit).
* @package phparcims
* @constant string AIMS_PNG8
*/
DEFINE(AIMS_PNG8,'PNG8');
/**
* Specifies the image type for the service to be jpg.
* @package phparcims
* @constant string AIMS_JPG
*/
DEFINE(AIMS_JPG,'JPG');
/**
* Specifies the image type for the service to be gif.
* @package phparcims
* @constant string AIMS_GIF
*/
DEFINE(AIMS_GIF,'GIF');
/**
* The constant is used to specify what level of debug info should be printed to the {@link DEBUG_FILE}.
* The following debug levels are available:
* <ul>
*  <li>0 => debugging off</li>
*  <li>1 => print custom info, use this to show only the things you just 'marked'</li>
*  <li>2 => show the program flow; the names of each function/method called during the
*			request is printed</li>
*  <li>4 => show request and respond XML communication</li>
*  <li>8 => some minor stuff (XML parsing currently)</li>
* </ul>
* Levels can be combined by simply adding the levels up. E.g. providing a 'level' of 9
* would result in printing level 1 and level 8 messages.</p>
* @brief Specified the level of debug info printed.
* @package phparcims
* @constant int DEBUG_LEVEL
*/
DEFINE(DEBUG_LEVEL,4);
/**
* Specifies if the debug file {@link DEBUG_FILE} should over writen be subsequent request (DEBUG_RECYCLE=0), or
* if message from subsequent request should be appended (DEBUG_RECYCLE=1).
* @brief Specified re-use of debug file.
* @package phparcims
* @constant int DEBUG_RECYCLE
*/
DEFINE(DEBUG_RECYCLE,0); // 1 => append to existing log, 0 => overwrite with each request
/**
* The constant LOGFILE contains the location of the log/debug files. Please specify the
* directory and name of the log file (e.g. /tmp/myLogFile). You do not need to include
* an extension, since the session ID of the request and the extension .log will be
* appended to the name. Also, make sure that you have write access to the specified
* directory.
* @brief Location of the debug file.
* @package phparcims
* @constant string DEBUG_FILE
*/
DEFINE(DEBUG_FILE,'/tmp/phparcims');

$GLOBALS['firstLog']=1; // indicates if info was already written to log

/**
* <p>This is the function to call when you want to print debuging info to a log file. The level
* parameter can have one of the following values:
* <ul>
*  <li>0 => debugging off</li>
*  <li>1 => print custom info, use this to show only the things you just 'marked'</li>
*  <li>2 => show the program flow; the names of each function/method called during the
*			request is printed</li>
*  <li>4 => show request and respond XML communication</li>
*  <li>8 => some minor stuff (XML parsing currently)</li>
*  <li>64 => error messages</li>
* </ul></p>
* <p>Depending on the constant {@link DEBUG_RECYCLE}, the logs are recycled with every new request. </p>
* write access to the location specified.
* <p>The output has the following format: <br>
* **** {time of request} *****<br>
* Debug level: <br>
* [message 1]<br>
* [message 2]<br>
* [message ...]</p>
*
* @function printDebug
* @package phparcims
* @use DEBUG_FILE
* @use DEBUG_LEVEL
* @use DEBUG_RECYCLE
* @param string Message The message to print in the log
* @param optional int Level The log level, which is used to check if message should be printed (default=1)
*/
function printDebug($str,$level=1) {
	if ($level & DEBUG_LEVEL) {
		if (DEBUG_RECYCLE || !$GLOBALS['firstLog']) {
			$logFile=fopen(DEBUG_FILE.session_id().'.log','a');
		} else {
			$logFile=fopen(DEBUG_FILE.session_id().'.log','w');
		}
		if ($GLOBALS['firstLog']) {
			$GLOBALS['firstLog']=0;
			$h='***** '.date('H:m:s')." *****\nDebug level: ".DEBUG_LEVEL."\n";
			fwrite($logFile,$h);
		}
		fwrite($logFile,$str);
		fwrite($logFile,"\n");
		fclose($logFile);
	}
}


/**
  * @brief The aimsConnectore class is used to establish a connection to the ArcIMS server.
  * @class aimsConnector
  * @package phparcims
  */
class aimsConnector
{

	/**
	* Contains the last AXL response that was received from the server. In the case you use the same aimsConnector
	* object to connect to different services, the string contains the last AXL reseived from any of the services. So
	* keep this in mind, when working directly with the AxlResponse string.
	* @brief Contains the last AXL response from the server.
	* @class aimsConnector
	* @attribute public string AxlResponse
	*/
	var $AxlResponse;
	/**
	* Contains the last AXL request that was sent to the server. In the case you use the same aimsConnector
	* object to connect to different services, the string contains the last AXL sent to any of the services. So
	* keep this in mind, when working directly with the AxlRequst string.
	* @brief Contains the last AXL reqeust sent to the server.
	* @class aimsConnector
	* @attribute public string AxlRequest
	*/
	var $AxlRequest;
	/**
	* The string represent the type of character encoding used for the AXL/XML communication. In most
	* cases this does not need to be changed.
	* @brief Specifies the character encoding used in the AXL, by default UTF-8
	* @class aimsConnector
	* @attribute public string EncodeType
	*/
	var $EncodeType='UTF-8';
	/**
	* This is a 'read-only' variable. When ever {@link aimsConnector::HasError} is TRUE, you can check this
	* attribute for the error code.
	* <ul>
	* <li> error codes 1-1000 are system errors (network problems, etc.)</li>
	* <li> error codes 4000-4999 are general connector errors (check ErrorMsg for more info on error).</li>
	* <li> error code 5xxx indicates that there was an ArcIMS error; check {@link aimsMap::ErrorCode} and {@link aimsMap::ErrorMsg} for more details.</li>
	* </ul>
	* @brief Contains the last error code thrown during communication with server or while parsing the AXL.
	* @class aimsConnector
	* @attribute public int ErrorCode
	*/
	var $ErrorCode=0;
	/**
	* Contains the error message that occured (see {@link aimsConnector::ErrorCode} for more details).
	* @brief Contains the last error message thrown during communication with server or while parsing the AXL.
	* @class aimsConnector
	* @attribute public string ErrorMsg
	*/
	var $ErrorMsg='';
	/**
	* Indicates if an error occured during the last call to the aimsConnector object. It's TRUE if there was another, otherwise
	* it's FALSE.
	* @brief Indicates if an error occured during the last call to the aimsConnector object.
	* @class aimsConnector
	* @attribute public boolean HasError
	*/
	var $HasError=FALSE;
	/**
	* The connector give the user the possiblity to connect directly to the ArcIMS
	* server, avoiding the web server as middle-man. Set this to TRUE for such a connection. If you want to
	* connect through a webserver to the ArcIMS server (e.g. webserver is behind a firewall where only port 80 is open) use
	* IsDirect=FALSE.
	* The benefit of using a direct connection is that you can avoid the access restriction to the different servers.
	* @brief Specifies if connector should communicat directly with the server.
	* @class aimsConnector
	* @attribute public boolean IsDirect
	*/
	var $IsDirect;
	/**
	* The build of the ArcIMS server with which the connector communicats.
	* @brief The build of the ArcIMS server with which the connector communicats.
	* @class aimsConnector
	* @attribute public string ServerBuild
	*/
	var $ServerBuild;
	/**
	* The name of the ArcIMS server/host.
	* @brief The name of the ArcIMS server/host.
	* @class aimsConnector
	* @attribute public string ServerName
	*/
	var $ServerName;
	/**
	* The port where the webserver is listing. Used only when {@link aimsConnector::IsDirect} = TRUE.
	* @brief The port where the webserver is listing. Used only when {@link aimsConnector::IsDirect} = TRUE.
	* @class aimsConnector
	* @attribute public int ServerPortHttp
	*/
	var $ServerPortHttp=80;
	/**
	* The port where the webserver is listing. Used only when {@link aimsConnector::IsDirect} = TRUE.
	* @brief The port where the webserver is listing. Used only when {@link aimsConnector::IsDirect} = TRUE.
	* @class aimsConnector
	* @attribute public int ServerPortArcIMS
	*/
	var $ServerPortArcIMS=5300;
	/**
	* The URL of the java servlet of the server. By default it's '/servlet/com.esri.esrimap.Esrimap' and probably
	* does not need to be changed.
	* @brief The URL of the java servlet of the server.
	* @class aimsConnector
	* @attribute public string ServerURL
	*/
	var $ServerURL='/servlet/com.esri.esrimap.Esrimap';
	/**
	* @brief The version of the ArcIMS server.
	* @class aimsConnector
	* @attribute public string ServerVersion
	*/
	var $ServerVersion;
	/**
	* After a {@link aimsConnector::getServices} request, contains a list of {@link aimsService} object available on the server. The
	* attribute is a regular array (has a numeric index) containing {@link aimsService} objects.
	* @brief After a {@link aimsConnector::getServices} request, contains a list of {@link aimsService} object available on the server.
	* @class aimsConnector
	* @attribute public array Services
	*/
	var $Services;

// ******************************* private variables ********************************
	/**
	* The ArcXML version used for communication. Default = 1.1. This should be changed, it may result in
	* malfunctioning of the connector.
	* @brief The ArcXML version used for communication. Default = 1.1.
	* @public
	* @class aimsConnector
	* @attribute string _ArcXMLVersion
	*/
	var $_ArcXMLVersion='1.1';
	/**
	* Indicates the depth (in regard of levels) of the currently processed tag.
	* @brief Indicates the depth (in regard of levels) of the currently processed tag.
	* @private
	* @attribute int _Depth
	*/
	var $_Depth;

	/**
	* An array that is indexed by the {@link aimsConnector::_Depth} variable and contains the tag name of the
	* parents. This way, it's easy to lookup what any of the previous (higher level) tags were.
	* @brief An array containing the parent tags
	* @private
	* @attribute array _Parent
	*/
	var $_Parent;

	/**
	* Contains the objects for the current and previous tags. (Currently not used)
	* @brief Contains the objects for the current and previous tags. (Currently not used)
	* @private
	* @attribute array _PObject
	*/
	var $_PObject;

	/**
	* Contains the aimsMap or other object that provided the request.
	* @brief Contains the aimsMap or other object that provided the request.
	* @private
	* @attribute array _RequestFrom
	*/
	var $_RequestFrom;
	/**
	* The parser object, used during the parsing of the XML response.
	* @brief The parser object, used during the parsing of the XML response.
	* @private
	* @attribute object _xmlParser
	*/
	var $_xmlParser;

	/*
	* @brief The following are variables that are used during Axl parsing and contains the object that is currently populated/created.
	* @private
	*/
	var $_currentService;
	var $_currentEnvironment;
	var $_currentEnvelope;
	var $_currentFeature;
	var $_currentRecord;
	var $_currentLayer;
	var $_currentShape;
	var $_currentGroupRenderer;
	var $_currentRenderer;
	var $_currentExact;
	var $_currentRange;
	var $_currentOther;
	var $_currentSymbol;

	/**
	 * {@example frame ex_aimsConnector.txt}
	 * @brief Constructor for aimsConnector object.
	 * @constructor aimsConnector
	 * @param string $host The full name of the arcims server (direct mode) or webserver (indirect mode)
	 * @param optional int $direct The connection mode: 1=direct / 0=indirect  (optional); default is 1
	 */
	function aimsConnector($name,$direct=TRUE) {
		$this->ServerName=$name;
		$this->IsDirect=$direct;
	}

	/**
	* Return the version of the phparcims connector and associated classes.
	* @class aimsConnector
	* @method public getConnectorVersion
	* @return string Version The version of the connector.
	*/
	function getConnectorVersion () {
		return CONNECTOR_VERSION;
	}
	/**
	* The function retrieves version and build number from server. It is not only usefull for
	* checking server version, but also for checking if a server is actually available or if
	* the network connection is working properly.
	* <p>{@example frame ex_aimsConnector.txt}
	* </p><br>
	* @brief Request for server version and build number.
	* @class aimsConnector
	* @method public getArcIMSVersion
	* @return int TRUE on success, FALSE if connection could not be made.
	*/
	function getArcIMSVersion( )
	{
		if ($this->IsDirect) {
			$fp = @fsockopen($this->ServerName,$this->ServerPortArcIMS,$this->ErrorCode,$this->ErrorMsg,1);
			if (!$fp) {
				$this->HasError=TRUE;
				return FALSE;
			}else{
				fputs($fp,'',0);
				$str=chr(0).chr(0).chr(0).chr(14).'Cmd=getVersion'.chr(0).chr(0).chr(0).chr(2).chr(0).chr(0).chr(0).chr(1);
				$len=strlen($str);
				fputs($fp,$str,$len);
				$null=fgets($fp,0);
				fputs($fp,chr(1),1);
			}
			while (!feof($fp)) {
				$response.=fgets($fp,1024);
			}
		} else {
			$fp = @fsockopen($this->ServerName,$this->ServerPortHttp,$this->ErrorCode,$this->ErrorMsg,1);
			if (!$fp) {
				$this->HasError=TRUE;
				return FALSE;
			} else {
				fputs($fp,"GET ".$this->ServerURL."?Cmd=getVersion HTTP/1.1\r\n");
				fputs($fp,"User-Agent: phpArcIMS connector [en]\r\n");
				fputs($fp,"Host: ".$this->ServerName."\r\n");
				fputs($fp,"Accept: text/html, image/gif, image/jpeg\r\n\r\n");
			}
			$this->_readHttpHeader($fp,$returncode,$headers);
			$responselength=$headers['Content-Length'].'<br>';
			$response='';
			do {
				$response.=fread($fp,$responselength);
				$responselength=$responselength-strlen($response);
				if ($responselength<=0) break;
//			} while (strlen($response)<$responselength);
			} while (TRUE);
		}
		fclose($fp);
		// the response is of the form:
		//    Version=xxxxx
		//    Build=xxxx
		preg_match('/=(.+)\s.+=(.+)/',$response,$result);
		$this->ServerVersion=$result[1];
		$this->ServerBuild=$result[2];
		$this->HasError=FALSE;
		$this->ErrorCode=0;
		$this->ErrorMsg='';
		return TRUE;
	}

	/**
	* It returns the avialable/accessible services on the server. In case of a direct connection ({@link aimsConnector::IsDirect}=TRUE) you
	* will receive a list of all the services on the server. In contrast, an indirect connection will return only the services for which
	* you have the correct access rights. Currently, all indirect connection are made as anonymous (meaning: no specific user).
	* <p>Once the call returns, use the {@aimsMap::Services} attribute to loop throught the available services and retrieve info
	* about them.
	* @brief Returns the available services on the server.
	* @class aimsConnector
	* @method public getServices
	* @return array List of {@link aimsService} objects.
	*/
	function getServices( )
	{
		$this->sendRequest('<GETCLIENTSERVICES/>', $t='internal');
		return $this->Services;
	}


	/**
	* Initializes a ArcIMS map. A map is based on a service to which the user has access.
	* Before the user can display, modify, etc. a service the map needs to be initialized. Once
	* the map is initialized the user can use the aimsMap object (returned by the method) to
	* manipulate the map/service.
	* @class aimsConnector
	* @method public initMap
	* @param string ServiceName The name of the service for which to create the map.
	* @return object A reference to the {@link aimsMap} object.
	*/
	function &initMap($servicename)
	{
		$m=new aimsMap($this, $servicename);
		printDebug("[aimsConnector.initMap]",2);
		$request.='<ARCXML version="1.1"><REQUEST>';
		$request.='<GET_SERVICE_INFO extensions="false" fields="true" envelope="true" renderer="false"/>';
		$request.='</REQUEST></ARCXML>';
		$this->sendRequest($request, $m);
		return $m;
	}


	/**
	* The method is used to send an AXL request to the server. In mose cases you must also
	* supply a {@link aimsMap} object for which the request applies. If no map object
	* is supplied, the method expects the keyword 'internal' instead of the map. In this case
	* the server catalog is queries for information.
	* only be done when requesting information about the services served by ArcIMS.
	* @brief Send a request to the server and parses the response.
	* @class aimsConnector
	* @method sendRequest
	* @param string Request A string containing the AXL request.
	* @param mixed Map The map object which should hold the request or 'internal' for server specific requests.
	* @return boolean Return TRUE if the request was sent and prased successfully. False otherwise.
	*/
	function sendRequest($request, &$m)
	{
		$this->_RequestFrom=&$m;
		if (!is_a($m,'aimsMap')) {
			if ($m!='internal') {
				$this->ErrorCode=5205;
				$this->Msg=' Incorrect Map object or keyword supplied to sendRequest()';
				$this->HasError=TRUE;
				return FALSE;
			}
			$name = 'catalog';
		} else {
			$name = $m->ServiceName;
		}
		// set error stuff to OK. It will set in case an error occurs
		$this->ErrorCode='';
		$this->ErrorMsg='';
		$this->HasError=FALSE;

		$this->AxlRequest='<?xml version="1.0" encoding="'.$this->EncodeType.'" ?>'.str_replace("><",">\r\n<",$request);
		if (stristr($this->AxlRequest,'GET_FEATURES')) $customService='&CustomService=Query';
		else if (stristr($this->AxlRequest,'GET_IMAGE')) $customService='';
		else if (stristr($this->AxlRequest,'GET_GEOCODE')) $customService='&CustomService=Geocode';
		else if (stristr($this->AxlRequest,'GET_SERVICE_INFO'))  $customService='';
		else if (stristr($this->AxlRequest,'GET_EXTRACT')) $customService='&CustomService=Extract';
		else if (stristr($this->AxlRequest,'GETCLIENTSERVICES')) $customService='';
		else if (stristr($this->AxlRequest,'ADMINCMD')) $customService='';
		else {
			$this->HasError=TRUE;
			$this->ErrorCode=4000;
			$this->ErrorMsg='Request AXL does not contain a valid request type.';
			return FALSE;
		}

		//basic request header, applies to all requests
		$requestheader="ServiceName=$name$customService&CustomStream=True&ClientLocale=en_US&ClientVersion=3.1";
		//basic request footer is appended to request
		$requestfooter='AllowRequestOutput=False&AllowResponsePath=False&AllowOutputTypeChange=True&ForbiddenLayoutTypes=&';
		if ($this->IsDirect) {
			$fp = @fsockopen($this->ServerName,$this->ServerPortArcIMS,$this->ErrorCode,$this->ErrorMsg,1);
			stream_set_blocking($fp,TRUE);
			if (!$fp) {
				$this->HasError=TRUE;
				return FALSE;
			}else{
				$headerlength=$this->_convertLengthToHex(strlen($requestheader));
				$package1_length=$this->_convertLengthToHex(strlen($this->AxlRequest));
				$package2_length=$this->_convertLengthToHex(strlen($requestfooter));

				$packageheader=$requestheader.chr(0).chr(0).chr(0).chr(3).$package1_length;
				fwrite($fp,$headerlength.$packageheader,strlen($headerlength.$packageheader));
				fwrite($fp,$this->AxlRequest,strlen($this->AxlRequest));
				fwrite($fp,$package2_length,strlen($package2_length));
				fwrite($fp,$requestfooter,strlen($requestfooter));

				$responselength = fread($fp,8);
				$responselength=substr($responselength,4);
				$t=unpack('C4',$responselength);
				$length = hexdec(dechex($t[1]).dechex($t[2]).dechex($t[3]).dechex($t[4]))."<br>";

				$this->AxlResponse='';
				do {
					$buf=fgets($fp,$length);
					if (strlen($buf)==0) {
						break;
					}
					if (substr($buf,3,1)=='d') {
						// incase a package has a 'd' at the 4th position, the first 8 bits are not relevant to the AXL.
						// They rather specify the size of the following Axl string (hex: 00 00 00 64 xx xx xx xx, where
						// the last four specify the size of the Axl package in hex)
						$this->AxlResponse.=substr($buf,8);
					} else {
						$this->AxlResponse.=$buf;
					}
				} while(TRUE);
				fclose($fp);
			}
		} else {
			$fp = @fsockopen($this->ServerName,$this->ServerPortHttp,$this->ErrorCode,$this->ErrorMsg,1);
			if (!$fp) {
				$this->HasError=TRUE;
				return FALSE;
			}else{
				$header='POST '.$this->ServerURL."?$requestheader HTTP/1.1\r\n";
				$header.="Connection: Keep-Alive\r\n";
				$header.="User-Agent: phpArcIMS connector [en]\r\n";
				$header.="Host: ".$this->ServerName."\r\n";
				$header.="Accept: image/gif, image/jpeg, image/png, */*\r\n";
				$header.="Accept-Language: en\r\n";
				$header.="Accept-Charset: iso-8859-1,*,utf-8\r\n";
				$header.="Content-type: text/axl\r\n";
				$header.="Content-length: ".strlen($this->AxlRequest)."\r\n\r\n";
				fputs($fp,$header.$this->AxlRequest);

				$this->_readHttpHeader($fp,$returncode,$headers);
				if ($returncode==100) {
					// with IIS/5.0 and maybe others, the first returned packed doesn't contain any data, but '
					// referes' to the next data package
					$this->_readHttpHeader($fp,$returncode,$headers);
				}
				$responselength=$headers['Content-Length'];
				$response='';
				if (!$responselength) {
					if ($headers['Transfer-Encoding']!='chunked') {
						// okay, it's look like we deal with IIS, where the 'Content-length' and 'Transfer-Encoding'
						// headers are missing, so let's just read all the info/data
						stream_set_blocking($fp,FALSE);
						do {
							$buf=fread($fp,1024);
							$response.=$buf;
							if (($pos=strpos($buf,'</ARCXML'))) break;
						} while (TRUE);
					} else {
						// the HTTP response is chunked => read the length in the data section and
						// repeat for each chunk
						stream_set_blocking($fp,FALSE);  //this does reduce waiting time on certain browsers during a GETSERVICES request
						$readLength=1024;
						$buf=fread($fp,$readLength);
						$pos=strpos($buf,"\r\n");
						$chunklength=hexdec(substr($buf,0,$pos))+$pos+2;  // need to add \r\n as well as the bytes specifying the chunk length
						$response=substr($buf,$pos+2);
						$readLength=$chunklength-$readLength;
						while ($readLength>0) {
							$buf=fread($fp,$readLength);
							$response.=$buf;
							$readLength=$readLength-strlen($buf);
							if ($readLength<=0) {
								// check if we got the end of the ArcXML, otherwise read the next chunk
								if (($pos=strpos($buf,'</ARCXML'))) break;
								$readLength=100;
								$buf=fread($fp,$readLength);
								$pos=strpos($buf,"\r\n",2);
								$chunklength=hexdec(substr($buf,2,$pos))+$pos+2;  // need to add \r\n as well as the bytes specifying the chunk length
								$response.=substr($buf,$pos+2);
								$readLength=$chunklength-$readLength;
							}
						}
					}
					$response=preg_replace('/(\x00\x00\x00d.{4})/s','',$response);  //remove any '000dxxxx' we may have missed
				} else {
					do {
						$response.=fread($fp,$responselength);
						$responselength=$responselength-strlen($response);
						if ($responselength<=0) break;
					} while (TRUE);
				}
			}
			fclose($fp);
			$this->AxlResponse=$response;
		}

		$this->_Depth=0;
		$this->_Parent=array();
		$this->_PObject=array();
		$startpos=strpos($this->AxlResponse,'<ARCXML');
		$endpos=strpos($this->AxlResponse,'</ARCXML>');
		$this->AxlResponse=substr($this->AxlResponse,$startpos,$endpos+9-$startpos);

		$this->_xmlParser=xml_parser_create($this->EncodeType);
		xml_set_object($this->_xmlParser,&$this);
		xml_set_element_handler($this->_xmlParser,"_startElement","_endElement");
		xml_set_character_data_handler($this->_xmlParser,"_cdata");
		if (!xml_parse($this->_xmlParser,$this->AxlResponse)) {
			$this->ErrorCode=xml_get_error_code($this->_xmlParser);
			$this->ErrorMsg=xml_error_string(xml_get_error_code($this->_xmlParser)).' at line '.xml_get_current_line_number($this->_xmlParser);
			$this->HasError=TRUE;
		}
		xml_parser_free($this->_xmlParser);
		return TRUE;
	}

	function _convertLengthToHex($len) {
			$n=base_convert($len,10,16);
			$s='';
			for ($i=strlen($n)-2;$i>=0;$i-=2) $s=chr(base_convert(substr($n,$i,2),16,10)).$s;
			if (!is_long((strlen($n)/2))) $s=chr(base_convert(substr($n,0,1),16,10)).$s;
			return str_pad($s,4,chr(0),STR_PAD_LEFT);
	}

	/**
	* Usefull only to connector developers.
	* @brief part of the php XML parses, the function is used to parse the starting XML elements
	* @class aimsConnector
	* @method private _startElement
	* @author Christoph Spoerri
	*/
	function _startElement($parser, $name, $attrs=''){
		printDebug('[aimsConnector.startElement] '.$this->_Depth.": $name$i",8);
		$map=&$this->_RequestFrom;
		switch ($name) {
		case 'ARCXML':
			$this->ArcXMLVersion=$attrs['VERSION'];
			break;
		case 'RESPONSE':

		case 'CONFIG':
		case 'MARKUP':
		case 'REQUEST':
			$this->RootType=$name;
			break;

		// aje 7/06/2002 error handling
		case 'ERROR':
			$this->ErrorCode = 5000;
			$this->HasError=TRUE;
			$this->ErrorMsg = 'ArcIMS server error occured during the processing of the AXL request. Check aimsConnector::Error for server message.';
			$map->ErrorCode = 5100;
			$Map->ErrorMsg = $attrs['MACHINE'].' (processid = '.$attrs['PROCESSID'].'; threadid = '.$attrs['THREADID'].'): ';
			break;

		case 'IMAGE':
		case 'SERVICEINFO':
		case 'ENVIRONMENT':
			$this->_currentEnvironment = new aimsEnvironment;
			break;
		case 'LOCALE':
			$this->_currentEnvironment->LocalLanguage=$attrs['LANGUAGE'];
			if ($attrs['COUNTRY']) $this->_currentEnvironment->LocalCountry=$attrs['COUNTRY'];
			if ($attrs['VARIANT']) $this->_currentEnvironment->LocalVariant=$attrs['VARIANT'];
			break;

		case 'UIFONT':
			$this->_currentEnvironment->UIFontName=$attrs['NAME'];
			if ($attrs['COLOR']) $this->_currentEnvironment->UIFontColor=$attrs['COLOR'];
			if ($attrs['SIZE']) $this->_currentEnvironment->UIFontSize=$attrs['SIZE'];
			if ($attrs['STYLE']) $this->_currentEnvironment->UIFontStyle=$attrs['STYLE'];
			break;

		case 'SCREEN':
			$this->_currentEnvironment->ScreenDPI=$attrs['DPI'];
			break;

		case 'SEPARATORS':
			if ($attrs['CS']) $this->_currentEnvironment->SeparatorCS=$attrs['CS'];
			if ($attrs['TS']) $this->_currentEnvironment->SeparatorTS=$attrs['TS'];
			break;

		case 'SERVICE':
			$this->_currentService = new aimsService(&$this);
			$this->_currentService->Name=$attrs['NAME'];
			$this->_currentService->ServiceGroup=$attrs['SERVICEGROUP'];
			$this->_currentService->Access=$attrs['ACCESS'];
			$this->_currentService->Type=$attrs['TYPE'];
			$this->_currentService->Status=$attrs['STATUS'];
			$this->_currentService->Version=$attrs['VERSION'];
			$this->_currentService->ImageType=$attrs['IMAGETYPE'];
			break;

		case 'SERVICES':
			$this->Services=array();
			break;

		case 'ENVELOPE':
			$l = new aimsEnvelope($attrs['MAXX'],$attrs['MAXY'],$attrs['MINX'],$attrs['MINY']);
			switch ($this->_Parent[$this->_Depth-1]) {
			case 'FCLASS':
				//$map->Layers[count($this->Layers)-1]->setEnvelope($l);
				$this->_currentLayer->setExtent($l);
				break;
			case 'PROPERTIES':
				$map->InitialExtent=$l;
				$map->Extent=$l;
				break;
			case 'PARTITION':
				$this->_currentEnvelope=&$l;
				break;
			case 'EXTRACT':
				break;
			case 'SPATIALFILTER':
				break;
			case 'FEATURE':
				$this->Features['DATASET'][$this->_currentFeature]['ENVELOPE']=&$l;
				$this->_currentEnvelope=$l;
				$this->_currentRecord->Envelope=$l;
				break;
			case 'FEATURES':
				//$map->Features['ENVELOPE']=$l;
				//$map->Recordset->Envelope=$l;
				$this->_currentRecordset->Extent=$l;
				break;
			case 'LAYERINFO':
				break;
			case 'IMAGE':
				unset($map->ImageEnvelope);
				$map->ImageEnvelope=&$l;
				break;
			default:
				return 0;
			}
			break;

		case 'FEATURECOORDSYS':
			$l = new aimsFeatureCoordsys($p1);
			if ($attrs['ID']) {
				$l->setByID($attrs['ID']);
			} else {
				$l->setByString($attrs['STRING']);
			}
			if (count($attrs)>1) {
				if ($attrs['DATUMTRANSFORMID']) $l = new aimsFeatureCoordsys($p1,$attrs['DATUMTRANSFORMID']);
				else $l = new aimsFeatureCoordsys($p1,$attrs['DATUMTRANSFORMSTRING']);
			}
			$map->FeatureCoordsys=&$l;
			break;

		case 'FILTERCOORDSYS':
			$l = new aimsFilterCoordsys();
			if ($attrs['ID']) {
				$l->setByID($attrs['ID']);
			} else {
				$l->setByString($attrs['STRING']);
			}
			if (count($attrs)>1) {
				if ($attrs['DATUMTRANSFORMID']) $l = new aimsFilterCoordsys($p1,$attrs['DATUMTRANSFORMID']);
				else $l = new aimsFilterCoordsys($p1,$attrs['DATUMTRANSFORMSTRING']);
			}
			$map->FilterCoordsys=&$l;
			break;

		case 'FEATURECOUNT':
			$map->FeatureCount=$attrs['COUNT'];
			$map->HasMoreFeatures=(strtolower($attrs['HASMORE'])=='true'?TRUE:FALSE);
			break;

		case 'FEATURES':
			$this->_currentRecordset=&$map->Layers[$map->_queringLayer]->Recordset;
			break;

		case 'FEATURE':
			switch ($this->_Parent[$this->_Depth-1]) {
			case 'FEATURES':
				$this->_currentRecord=&$this->_currentRecordset->newRecord();
				break;
			case 'GEOCODE':
				break;
			case 'DELETEDFEATURES':
			case 'ADDEDFEATURES':
			case 'MODIFIEDFEATURES':

			}
			break;

		case 'FCLASS':
			//parent tag is always LAYERINFO
			//$d = new aimsDataset('unkown','unkown',$attrs['TYPE']);
			//$d = new aimsDataset($attrs['TYPE'],
			$map->Layers[count($map->Layers)-1]->FeatureType=$attrs['TYPE'];
			break;

		case 'FIELD':
			switch ($this->_Parent[$this->_Depth-1]) {
			case 'FIELDS':
				$this->_currentRecord->addValue(strtoupper($attrs['NAME']),$attrs['VALUE']);
				break;
			default:
				// FEATURE, FCLASS, SQVAR
				$l = new aimsField($attrs['NAME'],$attrs['TYPE']);
				if (isset($attrs['PRECISION'])) $l->Precision=$attrs['PRECISION'];
				if (isset($attrs['SIZE'])) $l->Size=$attrs['SIZE'];
				$this->_currentLayer->Recordset->addField($l);
			}
			break;

		case 'FIELDS':
			break;

		case 'LAYERINFO':
			//parent tag is always RESPONSE/SERVICEINFO, returned after a GET_SERVICE_INFO request
			switch ($attrs['TYPE']) {
			case FEATURE_LAYER:
				$this->_currentLayer=&new aimsFeatureLayer(($attrs['NAME']?$attrs['NAME']:'Layer'.$attrs['ID']),&$map,$attrs['ID'],($attrs['MINSCALE']?$attrs['MINSCALE']:0),($attrs['MAXSCALE']?$attrs['MAXSCALE']:0));
				break;
			case IMAGE_LAYER:
				$this->_currentLayer=&new aimsImageLayer(($attrs['NAME']?$attrs['NAME']:'Layer'.$attrs['ID']),&$map,$attrs['ID'],($attrs['MINSCALE']?$attrs['MINSCALE']:0),($attrs['MAXSCALE']?$attrs['MAXSCALE']:0));
				break;
			case ACETATE_LAYER:
			}
			$this->_currentLayer->IsVisible = (strtolower($attrs['VISIBLE'])=='true'?TRUE:FALSE);
			break;

		case 'LEGEND':
			switch ($this->_Parent[$this->_Depth-1]) {
			case 'IMAGE':
				$map->_legend->URL=$attrs['URL'];
				$map->_legend->File=$attrs['FILE'];
				break;
			case 'PROPERTIES':
				$map->LegendInfo=$attrs;
				break;
			default:
				return 0;
			}
			break;

		case 'LAYER':
			$l = new aimsLayer($attrs['ID'], $attrs['TYPE'], ($attrs['NAME']?$attrs['NAME']:''),($attrs['MAXSCALE']?$attrs['MAXSCALE']:0),($attrs['MINSCALE']?$attrs['MINSCALE']:0), ($attrs['VISIBLE']?$attrs['VISIBLE']:1), 1);
			if ($map->returnLayer($l->Name,$index)) {
				if ($map->Layers[$index]->Service) {
					$map->Layers[$index]=$l;
					$this->_currentLayer=&$map->Layers[$index];
				}
			}else{
				$map->Layers[]=$l;
				$this->_currentLayer=&$map->Layers[count($map->Layers)-1];
			}
			break;

		case 'DATASET':
			$map->returnWorkspace($attrs['WORKSPACE'],$wIndex);
			$d = new aimsDataset($attrs['NAME'],$map->Workspaces[$wIndex],$attrs['TYPE']);
			$map->Layers[(count($map->Layers)-1)]->setDataset($d);
			break;

		case 'SHAPEWORKSPACE':
			$w = new aimsShapeWorkspace($attrs['NAME'],$attrs['DIRECTORY'],
											($attrs['CODEPAGE']?$attrs['CODEPAGE']:''),
											($attrs['GEOINDEXDIR']?$attrs['GEOINDEXDIR']:''),
											($attrs['SHARED']?$attrs['SHARED']:''));
			$map->Workspaces[]=$w;
			break;

		case 'IMAGEWORKSPACE':
			$w = new aimsShapeWorkspace($attrs['NAME'],$attrs['DIRECTORY']);
			$map->Workspaces[]=$w;
			break;

		case 'SDEWORKSPACE':
			$w = new aimsSDEWorkspace($attrs['NAME'],$attrs['INSTANCE'],$attrs['SERVER'],$attrs['USER'],$attrs['PASSWORD'],
									($attrs['DATABASE']?$attrs['DATABASE']:''),
									($attrs['ENCRYPTED']?$attrs['ENCRYPTED']:''),
									($attrs['GEOINDEXDIR']?$attrs['GEOINDEXDIR']:''));
			$map->Workspaces[]=$w;
			break;


/*      case 'FIELD':
         $l['TYPE']=$attrs['TYPE'];
         $l['NAME']=$attrs['NAME'];
         if (isset($attrs['PRECISION'])) $l['PRECISION']=$attrs['PRECISION'];
         if (isset($attrs['SIZE'])) $l['SIZE']=$attrs['SIZE'];
         switch ($this->_Parent[$this->_Depth-1]) {
         case 'FCLASS':
            if (!isset($this->Layers[$this->NumLayers-1]['FIELDS'])) {
               $p[0]=$l;
            } else {
               $p=$this->Layers[$this->NumLayers-1]['FIELDS'];
               $p[count($p)]=$l;
            }
            $this->Layers[$this->NumLayers-1]['FIELDS']=$p;
            break;
         case 'SQVAR':
            break;
         case 'FIELDS':
            break;
         case 'FEATURE':
            break;
         default:
            return 0;
         }
         break;
      case 'IMAGE':
         $this->Image[0]=array();
         break;
      case 'LAYER':
         if ($attrs) {
            echo 'Attributes:<table border="1">';
            while (list($k,$v)=each($attrs)) echo "<tr><td>$k:</td><td>$v</td></tr>";
            echo "</table>";
         }
         break;

      case 'SIMPLEMARKERSYMBOL':
         if (isset($attrs['ANTIALIASING'])) $l['ANTIALIASING']=$attrs['ANTIALIASING'];
         if (isset($attrs['COLOR'])) $l['COLOR']=$attrs['COLOR'];
         if (isset($attrs['OUTLINE'])) $l['OUTLINE']=$attrs['OUTLINE'];
         if (isset($attrs['SHADOW'])) $l['SHADOW']=$attrs['SHADOW'];
         if (isset($attrs['TYPE'])) $l['TYPE']=$attrs['TYPE'];
         if (isset($attrs['OVERLAP'])) $l['OVERLAP']=$attrs['OVERLAP'];
         if (isset($attrs['TRANSPARENCY'])) $l['TRANSPARENCY']=$attrs['TRANSPARENCY'];
         if (isset($attrs['WIDTH'])) $l['WIDTH']=$attrs['WIDTH'];
         if (isset($attrs['USECENTROID'])) $l['USECENTROID']=$attrs['USECENTROID'];

         switch ($this->_Parent[$this->_Depth-1]) {
         case 'SIMPLERENDERER':
            break;
         case 'EXACT':
            break;
         case 'RANGE':
            break;
         case 'OTHER':
            break;
         case 'POINT':
            break;
         default:
            return 0;
         }

      case 'SIMPLERENDERER':
         switch ($this->_Parent[$this->_Depth-1]) {
         case 'LAYER':
            break;
         case 'LAYERDEF':
            break;
         case 'GROUPRENDERER':
            break;
         case 'SCALEDEPENDENTRENDERER':
            break;
         default:
            return 0;
         }
         break;

      case 'SIMPLEPOLYGONSYMBOL':
         if (isset($attrs['ANTIALIASING'])) $l['ANTIALIASING']=$attrs['ANTIALIASING'];
         if (isset($attrs['BOUNDARY'])) $l['BOUNDARY']=$attrs['BOUNDARY'];
         if (isset($attrs['BOUNDARYCAPTYPE'])) $l['BOUNDARYCAPTYPE']=$attrs['BOUNDARYCAPTYPE'];
         if (isset($attrs['BOUNDARYCOLOR'])) $l['BOUNDARYCOLOR']=$attrs['BOUNDARYCOLOR'];
         if (isset($attrs['BOUNDARYJOINTYPE'])) $l['BOUNDARYJOINTYPE']=$attrs['BOUNDARYJOINTYPE'];
         if (isset($attrs['BOUNDARYTRANSPARENCY'])) $l['BOUNDARYTRANSPARENCY']=$attrs['BOUNDARYTRANSPARENCY'];
         if (isset($attrs['BOUNDARYTYPE'])) $l['NDARYTYPE']=$attrs['NDARYTYPE'];
         if (isset($attrs['BOUNDARYWIDTH'])) $l['BOUNDARYWIDTH']=$attrs['BOUNDARYWIDTH'];
         if (isset($attrs['FILLCOLOR'])) $l['FILLCOLOR']=$attrs['FILLCOLOR'];
         if (isset($attrs['FILLINTERVAL'])) $l['ANTIALIASING']=$attrs['ANTIALIASING'];
         if (isset($attrs['FILLTRANSPARENCY'])) $l['FILLTRANSPARENCY']=$attrs['FILLTRANSPARENCY'];
         if (isset($attrs['FILLTYPE'])) $l['FILLTYPE']=$attrs['FILLTYPE'];
         if (isset($attrs['OVERLAP'])) $l['OVERLAP']=$attrs['OVERLAP'];
         if (isset($attrs['TRANSPARENCY'])) $l['TRANSPARENCY']=$attrs['TRANSPARENCY'];
         switch($this->_Parent[$this->_Depth-1]) {
         case 'SIMPLERENDERER':
            break;
         case 'EXACT':
            break;
         case 'RANGE':
            break;
         case 'OTHER':
            break;
         default:
            return 0;
         }
*/

		case 'PARTITION':
			break;
		case 'POINT':
			switch ($this->_Parent[$this->_Depth-1]){
			case 'OBJECT':
				/* not sure right now what this is for */
				break;
			default:
				$this->_currentShape=new aimsPoint($attrs['X'],$attrs['Y']);
			}
			break;
		case 'MULTIPOINT':
			break;
		case 'POLYGON':
			break;
		case 'LINE':
			break;
		case 'POLYLINE':
			break;

		case 'GROUPRENDERER':
			$this->_currentGroupRenderer[]=new aimsGroupRenderer();
			break;
		 case 'SIMPLERENDERER':
			// has not attributes; processed under endElement function
		 	break;
		case 'SIMPLELABELRENDERER':
			// has attributes, but there are added after processing the subtags (the symbols, which is
			// supplied when creating the renderer
			$t=new aimsTextSymbol();
			$this->_currentRenderer=new aimsSimpleLabelRenderer($attrs['FIELD'],$t,$attrs);
			break;
		case 'VALUEMAPRENDERER':
			//$vmr=new aimsValueMapRenderer($attrs['LOOKUPFIELD']);
			//$this->CurrentLayer->setRenderer($vmr,'Default');
			$this->_currentRenderer=new aimsValueMapRenderer($attrs['LOOKUPFIELD']);
			break;

		case 'EXACT':
			$this->_currentExact=$attrs;
			break;

		case 'RANGE':
			$this->_currentRange=$attrs;
			break;

		case 'OTHER':
			$this->_currentOther=$attrs;
			break;

		case 'SIMPLEPOLYGONSYMBOL':
			$this->_currentSymbol=new aimsSimplePolygonSymbol($attrs);
			break;
		case 'SIMPLELINESYMBOL':
			$this->_currentSymbol=new aimsSimpleLineSymbol($attrs);
			break;
		case 'SIMPLEMARKERSYMBOL':
			$this->_currentSymbol=new aimsSimpleMarkerSymbol($attrs);
			break;
		case 'TEXTSYMBOL':
			$this->_currentSymbol=new aimsTextSymbol($attrs);
			break;

		case 'MAPUNITS':
			$map->Mapunits = $attrs['UNITS'];
			break;

		case 'OUTPUT':
			switch ($this->_Parent[$this->_Depth-1]){
			case 'PROPERTIES':
				break;
			case 'IMAGE':
				$map->ImageURL = $attrs['URL'];
				$map->ImageFile= $attrs['FILE'];
				if ($attrs['WIDTH']) $map->ImageWidth=$attrs['WIDTH'];
				if ($attrs['HEIGHT']) $map->ImageHeight=$attrs['HEIGHT'];
				break;
			case 'EXTRACT':
				break;
			}
			break;

		default:
		}
		$cp = $attrs;
		$i=0;
		$this->_Parent[$this->_Depth]=$name;
		$this->_PObject[$this->_Depth]=$cp;
		$this->_Depth++;
		if ($this->_Depth>$this->maxDepth) $this->maxDepth=$this->_Depth;

	}

	/**
	* Usefull only to connector developers.
	* @brief part of the php XML parses, the function is used to parse the ending XML elements
	* @class aimsConnector
	* @method private _endElement
	* @author Christoph Spoerri
	*/
	function _endElement($parser, $name){
		$this->_Depth--;
		printDebug('[aimsConnector.endElement]',8);
		$map=&$this->_RequestFrom;

		$cp=$this->_PObject[$this->_Depth];  //get object of current tag
		$l=$this->_PObject[$this->_Depth-1]; //get parent object of current tag
		//check to make sure that other child tag which same name does not exist
		$this->_PObject[$this->_Depth-1]=$l;

		switch ($name) {
		case 'SERVICE':
			$this->Services[]=&$this->_currentService;
			unset($this->_currentService);
			break;

		case 'ENVIRONMENT':
			switch ($this->_Parent[$this->_Depth-2]) {
			case 'SERVICE':
				$this->_currentService->Environment=&$this->_currentEnvironment;
				break;
			default:
				$map->Environment=&$this->_currentEnvironment;
			}
			unset($this->_currentEnvironment);
			break;

		case 'LAYERINFO':
			unset ($this->_currentLayer);
			break;

		case 'FEATURE':
			printDebug("\tFEATURE",8);
			switch ($this->_Parent[$this->_Depth-1]) {
			case 'GEOCODE':
				break;
			case 'FEATURES':
				// aje 21/05/2002 uncomment and fix =+ to +=
				$this->_currentFeature+=1;
				if ($this->_currentShape) $this->_currentRecord->Shape=$this->_currentShape;
				unset($this->_currentShape);
				//unset($this->_currentRecord);
				break;
			case 'DELETEDFEATURES':
				break;
			case 'ADDEDFEATURES':
				break;
			case 'MODIFIEDFEATURES':
			}
			break;

		case 'EXACT':
			printDebug("\tEXACT",8);
			//$r=&$this->CurrentLayer->getRenderer('Default');
			//$r->addExact($this->CurrentSymbol,$this->CurrentExact);
			$this->_currentRenderer->addExact($this->_currentSymbol,$this->_currentExact);
			break;

		case 'RANGE':
			printDebug("\tRANGE",8);
			//$r=&$this->CurrentLayer->getRenderer();
			//$r->addRange($this->CurrentSymbol,$this->CurrentRange);
			$this->_currentRenderer->addRange($this->_currentSymbol,$this->_currentRange);
			break;

		case 'OTHER':
			printDebug("\tOTHER",8);
			//$r=&$this->CurrentLayer->getRenderer();
			//$r->addOther($this->CurrentSymbol,$this->CurrentOther['LABEL']);
			$this->_currentRenderer->addOther($this->_currentSymbol,$this->_currentOther['LABEL']);
			break;

		case 'FCLASS':
			unset($this->_currentRecordset);
			break;

		case 'FIELDS':
			printDebug("\tFIELDS",8);
			break;

		case 'ENVELOPE':
			printDebug("\tENVELOPE",8);
			switch ($this->_Parent[$this->_Depth-1]) {
			case 'FCLASS':
				break;
			case 'PROPERTIES':
				break;
			case 'PARTITION':
				break;
			case 'EXTRACT':
				break;
			case 'SPATIALFILTER':
				break;
			case 'FEATURE':
				break;
			case 'IMAGE':
				break;
			default:
				return 0;
			}
			break;
		case 'PARTITION':
			printDebug("\tPARTITION",8);
			$d=&$map->Layers[(count($map->Layers)-1)]->Dataset;
			$d->AddPartition($attrs['NAME'],$this->_currentEnvelope);
			break;

		case 'GROUPRENDERER':
			printDebug("\tGROUPRENDERER",8);
			$cg=count($this->_currentGroupRenderer)-1;
			if ($cg==0) {
				$this->_currentLayer->addRenderer($this->_currentGroupRenderer[$cg],'Default');
				$this->_currentGroupRenderer=FALSE;
			} else {
				$this->_currentGroupRenderer[$cg-1]->addRenderer($this->_currentGroupRenderer[$cg]);
				unset($this->_currentGroupRenderer[$cg]);
			}
			break;
		case 'SIMPLERENDERER':
			printDebug("\tSIMPLERENDERER",8);
			$r=new aimsRenderer($this->_currentSymbol);
			if ($this->_currentGroupRenderer) {
				$cg=count($this->_currentGroupRenderer)-1;
				$this->_currentGroupRenderer[$cg]->addRenderer($r);
			} else {
				$this->_currentLayer->setRenderer($r,'Default');
			}
			break;
		case 'SIMPLELABELRENDERER':
			printDebug("\tSIMPLELABELRENDERER",8);
			$this->_currentRenderer->Symbol=$this->_currentSymbol;
			if ($this->_currentGroupRenderer) {
				$cg=count($this->_currentGroupRenderer)-1;
				$this->_currentGroupRenderer[$cg]->addRenderer($this->_currentRenderer);
			} else {
				$this->_currentLayer->setRenderer($r,'Default');
			}
			break;
		case 'VALUEMAPRENDERER':
			printDebug("\tVALUEMAPRENDERER",8);
			if ($this->_currentGroupRenderer) {
				$cg=count($this->_currentGroupRenderer)-1;
				$this->_currentGroupRenderer[$cg]->addRenderer($this->_currentRenderer);
			} else {
				$this->_currentLayer->setRenderer($this->_currentRenderer,'Default');
			}
			break;

		}
	}

	/**
	* Usefull only to connector developers.
	* @brief part of the php XML parses, the function is used to parse the data elements
	* @class aimsConnector
	* @method private _cdata
	* @author Christoph Spoerri
	*/
   function _cdata($parser,$cdata='') {
		$map=&$this->_RequestFrom;

		if ($cdata) printDebug("data: $cdata",8);
		switch ($this->_Parent[$this->_Depth-1]) {
		case 'ERROR':
			printDebug("[aimsConnector.cdata] IMS error: $cdata",8);
			$map->ErrorMsg.=$cdata;
			break;
		}
   }

	/**
	* Usefull only to connector developers.
	* @brief Reads and returns the headers from the HTTP response
	* @class aimsConnector
	* @method _readHttpHeader
	* @private
	* @param object FilePointer Pointer to the connection stream
	* @param int ReturnCode Variable will be used to store the HTTP return code
	* @param array Associative array with key=Header keyword, value = header value
	*/
	function _readHttpHeader(&$fp,&$returncode,&$headers) {
		$result='';
		while(!feof($fp)) {
			$headerline = fgets($fp,1024);  // read input line-by-line aka header keyword-value pair at a time
			if (substr($headerline,0,4)=='HTTP') {
				preg_match('/(.+)\s(.+)\s(.+)\s\s/',$headerline,$result);
				$returncode=intval($result[2]);
			} else {
				if ($headerline=="\r\n") break;
				preg_match('/(.+):\s(.+)\s\s/',$headerline,$result);
				$headers[$result[1]]=$result[2];
			}
		}
		return $headers;
	}

}

/**
* An aimsService object contains information about a given service available from the ArcIMS server. The
* object can not be changed (or it does you no good). The object is created by calling
* {@link aimsConnector::getServices} which returns a list of aimsService objects.
* @brief Object for available service.
* @package phparcims
* @class aimsService
*/
class aimsService {
	/**
	* @brief The reference to the connector which is used to connect to the service.
	* @class aimsService
	* @attribute public object Connector
	*/
	var $Connector;
	/**
	* Name of the service.
	* @class aimsService
	* @attribute string Name
	*/
	var $Name;
	/**
	* The name of the service group of which the service is part of.
	* @class aimsService
	* @attribute public string ServiceGroup
	*/
	var $ServiceGroup;
	/**
	* Specifies if the service can be access by the user. This is only PRIVATE or
	* PUBLIC. The connector does currenly only show PUBLIC services.
	* @brief Access privilages by the user to the service.
	* @class aimsService
	* @attribute public string Access
	*/
	var $Access;
	/**
	* The type of action to perform on the server. (Currently not used)
	* @class aimsService
	* @attribute public string Type
	*/
	var $Type;
	/**
	* Specifies if the service is currently running or not. The two
	* possibilities are DISABLED or ENABLED. Currently does not have
	* any effect on connector.
	* @brief Status of service.
	* @class aimsService
	* @attribute public string Status
	*/
	var $Status;
	/**
	* Possible image types are png, jpg and gif. Note: in order to create gis
	* images the server needs to have an appropriate license. To assigne a value
	* use the constants {@link AIMS_PNG}, {@link AIMS_PNG8}, {@link AIMS_JPG} and {@link AIMS_GIF}.
	* @brief The image format returned by the service.
	* @attribute public string ImageType
	*/
	var $ImageType;
	/**
	* @brief The {@link aimsEnvironment} object defining the environment of the service.
	* @public
	* @attribute public object Environment
	*/
	var $Environment;

	/**
	* Is not called by the user.
	* @constructor aimsService
	* @public
	* @param object Connector The connector which is used to communicate with the service.
	* @return void
	*/
	function aimsService($c) {
		$this->Connector = &$c;
	}

	/**
	* The method is used to create and initializes an {@link aimsMap} object. The
	* object can then be used to draw an image of the map, zoom in/out, query layers,
	* etc. The method is similar to the {@link aimsConnector::initMap} method, yet does
	* not require a service name, since the map is create for the service defined
	* by this object.
	* <p><b>Note</b>: the method returns an reference to an object => use &aimsService::initMap()
	* to assign the return value to a variable.</P>
	* @brief Initializes the map.
	* @return object The map.
	*/
	function &initMap() {
		return $this->Connector->initMap($this->Name);
	}

}

/**
* The object is used to get (and sometimes set) certain environmental variables
* of the ArcIMS server and/or its services. In most cases it's not necessary
* to change any of its attributes.
* <p>The {@link aimsEnvironment::UIFontColor},{@link aimsEnvironment::UIFontName},
* {@link aimsEnvironment::UIFontSize} and {@link aimsEnvironment::UIFontStyle} do
* not have an effect on the phpArcIMS connector. They effect only the dialogs
* of the ArcIMS java viewer and Java ArcExplorer (ver. 4.x). They are listed
* here just for completness and possible future use.</p>
* @brief The aimsEnvironment object holds various configuration parameters for the ArcIMS server.
* @class aimsEnvironment
* @package phparcims
*/
class aimsEnvironment {
	/**
	* <blockquote style="font-family: arial; background-color:#EEEEEE">
	* Font color using RGB values.
	* <p><sup>(ESRI)</sup></p></blockquote>
	* @class aimsEnvironment
	* @attribute public string UIFontColor
	*/
	var $UIFontColor;
	/**
	* <blockquote style="font-family: arial; background-color:#EEEEEE">
	* Font name. The name is case sensitive. If font
	* name uses "&", use "&amp;" instead. For example, ESRI Transportation
	* & Civic should be written as ESRI Transportation &amp; Civic. For Feature
	* Services, the font must reside on the client machine, or else the system
	* default font is used.
	* <p><sup>(ESRI)</sup></p></blockquote>
	* @class aimsEnvironment
	* @attribute public string UIFontName
	*/
	var $UIFontName;
	/**
	* Font size.
	* @class aimsEnvironment
	* @attribute public int UIFontSize
	*/
	var $UIFontSize;
	/**
	* Font style.
	* @class aimsEnvironment
	* @attribute public string UIFontStyle
	*/
	var $UIFontStyle;
	/**
	* <blockquote style="font-family: arial; background-color:#EEEEEE">
	* Indicates the dots per inch (dpi) used when calculating scales for scale-dependent
	* elements such as SCALEDEPENDENTRENDERER, LAYER, and OBJECT.
	* <p><sup>(ESRI)</sup></p></blockquote>
	* @brief The dpi used when calculating scale.
	* @class aimsEnvironment
	* @attribute public int ScreenDPI
	*/
	var $ScreenDPI;
	/**
	* <blockquote style="font-family: arial; background-color:#EEEEEE">
	* The country code identifies differences in conventions, such as currency
	* symbols, between countries that use the same language. Locales for a country
	* are specified by two-letter, uppercase codes based on the ISO-3166 standard.
	* For example, "DE" represents Germany, and "US" represents the United States.
	* <p><sup>(ESRI)</sup></p></blockquote>
	* @brief The language used in the service/server.
	* @class aimsEnvironment
	* @attribute public string LocalLanguage
	*/
	var $LocalLanguage;
	/**
	* <blockquote style="font-family: arial; background-color:#EEEEEE">
	* The country code identifies differences in conventions, such as currency
	* symbols, between countries that use the same language. Locales for a
	* country are specified by two-letter, uppercase codes based on the ISO-3166
	* standard. For example, "DE" represents Germany, and "US" represents the
	* United States.
	* <p><sup>(ESRI)</sup></p></blockquote>
	* @brief The country code used in the service/server.
	* @class aimsEnvironment
	* @attribute public string LocalCountry
	*/
	var $LocalCountry;
	/**
	* <blockquote style="font-family: arial; background-color:#EEEEEE">
	* The variant handles variations in conventions within a language used
	* in one country and consists of one or more underscored keywords. For example,
	* a European country that wants to use the Euro currency symbol along with its
	* country currency can use the variant "_EURO". If a hardware platform needs to
	* be specified such as for Windows, the variant might be "_EURO_WIN".
	* <p><sup>(ESRI)</sup></p></blockquote>
	* @brief Handles variations in keywrods within languages.
	* @class aimsEnvironment
	* @attribute public string LocalVariant
	*/
	var $LocalVariant;
	/**
	* The coordinate separate is only used in case you want to override the default
	* seperaters. Any new value can only be one Unicode character wide.
	* @brief Coordinate separator is used to separate an x-coordinate from a y-coordinate.
	* @class aimsEnvironment
	* @attribute public string SeparatorCS
	*/
	var $SeparatorCS;
	/**
	* The tuple seperator is used with strings in {@link aimsValueMapRenderer::addExact}. Any
	* new value can only be one Unicode character wide.
	* @brief Tuple separator is used to separate coordinate pairs and string lists.
	* @class aimsEnvironment
	* @attribute public string SeparatorTS
	*/
	var $SeparatorTS;

	function aimsEnvironment () {
	}
}

?>
Return current item: PhpArcIMS