PageRenderTime 55ms CodeModel.GetById 17ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

/halogy/libraries/Xmlrpc.php

https://bitbucket.org/haloweb/halogy-1.0/
PHP | 1421 lines | 1020 code | 202 blank | 199 comment | 124 complexity | 79927efd3d180191c616234f8644885e MD5 | raw file
   1<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
   2/**
   3 * CodeIgniter
   4 *
   5 * An open source application development framework for PHP 4.3.2 or newer
   6 *
   7 * @package		CodeIgniter
   8 * @author		ExpressionEngine Dev Team
   9 * @copyright	Copyright (c) 2008 - 2009, EllisLab, Inc.
  10 * @license		http://codeigniter.com/user_guide/license.html
  11 * @link		http://codeigniter.com
  12 * @since		Version 1.0
  13 * @filesource
  14 */
  15
  16if ( ! function_exists('xml_parser_create'))
  17{	
  18	show_error('Your PHP installation does not support XML');
  19}
  20
  21
  22// ------------------------------------------------------------------------
  23
  24/**
  25 * XML-RPC request handler class
  26 *
  27 * @package		CodeIgniter
  28 * @subpackage	Libraries
  29 * @category	XML-RPC
  30 * @author		ExpressionEngine Dev Team
  31 * @link		http://codeigniter.com/user_guide/libraries/xmlrpc.html
  32 */
  33class CI_Xmlrpc {
  34
  35	var $debug			= FALSE; 	// Debugging on or off	
  36	var $xmlrpcI4		= 'i4';
  37	var $xmlrpcInt		= 'int';
  38	var $xmlrpcBoolean	= 'boolean';
  39	var $xmlrpcDouble	= 'double';	
  40	var $xmlrpcString	= 'string';
  41	var $xmlrpcDateTime	= 'dateTime.iso8601';
  42	var $xmlrpcBase64	= 'base64';
  43	var $xmlrpcArray	= 'array';
  44	var $xmlrpcStruct	= 'struct';
  45	
  46	var $xmlrpcTypes	= array();
  47	var $valid_parents	= array();
  48	var $xmlrpcerr		= array();	// Response numbers
  49	var $xmlrpcstr		= array();  // Response strings
  50	
  51	var $xmlrpc_defencoding = 'UTF-8';
  52	var $xmlrpcName			= 'XML-RPC for CodeIgniter';
  53	var $xmlrpcVersion		= '1.1';
  54	var $xmlrpcerruser		= 800; // Start of user errors
  55	var $xmlrpcerrxml		= 100; // Start of XML Parse errors
  56	var $xmlrpc_backslash	= ''; // formulate backslashes for escaping regexp
  57	
  58	var $client;
  59	var $method;
  60	var $data;
  61	var $message			= '';
  62	var $error				= '';  		// Error string for request
  63	var $result;
  64	var $response			= array();  // Response from remote server
  65
  66
  67	//-------------------------------------
  68	//  VALUES THAT MULTIPLE CLASSES NEED
  69	//-------------------------------------
  70
  71	function CI_Xmlrpc ($config = array())
  72	{
  73		$this->xmlrpcName 		= $this->xmlrpcName;
  74		$this->xmlrpc_backslash = chr(92).chr(92);
  75		
  76		// Types for info sent back and forth
  77		$this->xmlrpcTypes = array(
  78			$this->xmlrpcI4	   => '1',
  79			$this->xmlrpcInt	  => '1',
  80			$this->xmlrpcBoolean  => '1',
  81			$this->xmlrpcString   => '1',
  82			$this->xmlrpcDouble   => '1',
  83			$this->xmlrpcDateTime => '1',
  84			$this->xmlrpcBase64   => '1',
  85			$this->xmlrpcArray	=> '2',
  86			$this->xmlrpcStruct   => '3'
  87			);
  88			
  89		// Array of Valid Parents for Various XML-RPC elements
  90		$this->valid_parents = array('BOOLEAN'			=> array('VALUE'),
  91									 'I4'				=> array('VALUE'),
  92									 'INT'				=> array('VALUE'),
  93									 'STRING'			=> array('VALUE'),
  94									 'DOUBLE'			=> array('VALUE'),
  95									 'DATETIME.ISO8601'	=> array('VALUE'),
  96									 'BASE64'			=> array('VALUE'),
  97									 'ARRAY'			=> array('VALUE'),
  98									 'STRUCT'			=> array('VALUE'),
  99									 'PARAM'			=> array('PARAMS'),
 100									 'METHODNAME'		=> array('METHODCALL'),
 101									 'PARAMS'			=> array('METHODCALL', 'METHODRESPONSE'),
 102									 'MEMBER'			=> array('STRUCT'),
 103									 'NAME'				=> array('MEMBER'),
 104									 'DATA'				=> array('ARRAY'),
 105									 'FAULT'			=> array('METHODRESPONSE'),
 106									 'VALUE'			=> array('MEMBER', 'DATA', 'PARAM', 'FAULT')
 107									 );
 108			
 109			
 110		// XML-RPC Responses
 111		$this->xmlrpcerr['unknown_method'] = '1';
 112		$this->xmlrpcstr['unknown_method'] = 'This is not a known method for this XML-RPC Server';
 113		$this->xmlrpcerr['invalid_return'] = '2';
 114		$this->xmlrpcstr['invalid_return'] = 'The XML data receieved was either invalid or not in the correct form for XML-RPC.  Turn on debugging to examine the XML data further.';
 115		$this->xmlrpcerr['incorrect_params'] = '3';
 116		$this->xmlrpcstr['incorrect_params'] = 'Incorrect parameters were passed to method';
 117		$this->xmlrpcerr['introspect_unknown'] = '4';
 118		$this->xmlrpcstr['introspect_unknown'] = "Cannot inspect signature for request: method unknown";
 119		$this->xmlrpcerr['http_error'] = '5';
 120		$this->xmlrpcstr['http_error'] = "Did not receive a '200 OK' response from remote server.";
 121		$this->xmlrpcerr['no_data'] = '6';
 122		$this->xmlrpcstr['no_data'] ='No data received from server.';
 123		
 124		$this->initialize($config);
 125		
 126		log_message('debug', "XML-RPC Class Initialized");
 127	}
 128	
 129	
 130	//-------------------------------------
 131	//  Initialize Prefs
 132	//-------------------------------------
 133
 134	function initialize($config = array())
 135	{
 136		if (count($config) > 0)
 137		{
 138			foreach ($config as $key => $val)
 139			{
 140				if (isset($this->$key))
 141				{
 142					$this->$key = $val;			
 143				}
 144			}
 145		}
 146	}
 147	// END
 148	
 149	//-------------------------------------
 150	//  Take URL and parse it
 151	//-------------------------------------
 152
 153	function server($url, $port=80)
 154	{
 155		if (substr($url, 0, 4) != "http")
 156		{
 157			$url = "http://".$url;
 158		}
 159		
 160		$parts = parse_url($url);
 161		
 162		$path = ( ! isset($parts['path'])) ? '/' : $parts['path'];
 163		
 164		if (isset($parts['query']) && $parts['query'] != '')
 165		{
 166			$path .= '?'.$parts['query'];
 167		}	
 168		
 169		$this->client = new XML_RPC_Client($path, $parts['host'], $port);
 170	}
 171	// END
 172	
 173	//-------------------------------------
 174	//  Set Timeout
 175	//-------------------------------------
 176
 177	function timeout($seconds=5)
 178	{
 179		if ( ! is_null($this->client) && is_int($seconds))
 180		{
 181			$this->client->timeout = $seconds;
 182		}
 183	}
 184	// END
 185	
 186	//-------------------------------------
 187	//  Set Methods
 188	//-------------------------------------
 189
 190	function method($function)
 191	{
 192		$this->method = $function;
 193	}
 194	// END
 195	
 196	//-------------------------------------
 197	//  Take Array of Data and Create Objects
 198	//-------------------------------------
 199
 200	function request($incoming)
 201	{
 202		if ( ! is_array($incoming))
 203		{
 204			// Send Error
 205		}
 206		
 207		$this->data = array();
 208		
 209		foreach($incoming as $key => $value)
 210		{
 211			$this->data[$key] = $this->values_parsing($value);
 212		}
 213	}
 214	// END
 215	
 216	
 217	//-------------------------------------
 218	//  Set Debug
 219	//-------------------------------------
 220
 221	function set_debug($flag = TRUE)
 222	{
 223		$this->debug = ($flag == TRUE) ? TRUE : FALSE;
 224	}
 225	
 226	//-------------------------------------
 227	//  Values Parsing
 228	//-------------------------------------
 229
 230	function values_parsing($value, $return = FALSE)
 231	{
 232		if (is_array($value) && isset($value['0']))
 233		{
 234			if ( ! isset($value['1']) OR (! isset($this->xmlrpcTypes[$value['1']])))
 235			{
 236				if (is_array($value[0]))
 237				{
 238					$temp = new XML_RPC_Values($value['0'], 'array');
 239				}
 240				else
 241				{
 242					$temp = new XML_RPC_Values($value['0'], 'string');
 243				}
 244			}
 245			elseif(is_array($value['0']) && ($value['1'] == 'struct' OR $value['1'] == 'array'))
 246			{
 247				while (list($k) = each($value['0']))
 248				{
 249					$value['0'][$k] = $this->values_parsing($value['0'][$k], TRUE);
 250				}
 251				
 252				$temp = new XML_RPC_Values($value['0'], $value['1']);
 253			}
 254			else
 255			{
 256				$temp = new XML_RPC_Values($value['0'], $value['1']);
 257			}
 258		}
 259		else
 260		{
 261			$temp = new XML_RPC_Values($value, 'string');
 262		}
 263
 264		return $temp;
 265	}
 266	// END
 267
 268
 269	//-------------------------------------
 270	//  Sends XML-RPC Request
 271	//-------------------------------------
 272
 273	function send_request()
 274	{
 275		$this->message = new XML_RPC_Message($this->method,$this->data);
 276		$this->message->debug = $this->debug;
 277	
 278		if ( ! $this->result = $this->client->send($this->message))
 279		{
 280			$this->error = $this->result->errstr;
 281			return FALSE;
 282		}
 283		elseif( ! is_object($this->result->val))
 284		{
 285			$this->error = $this->result->errstr;
 286			return FALSE;
 287		}
 288		
 289		$this->response = $this->result->decode();
 290		
 291		return TRUE;
 292	}
 293	// END
 294	
 295	//-------------------------------------
 296	//  Returns Error
 297	//-------------------------------------
 298
 299	function display_error()
 300	{
 301		return $this->error;
 302	}
 303	// END
 304	
 305	//-------------------------------------
 306	//  Returns Remote Server Response
 307	//-------------------------------------
 308
 309	function display_response()
 310	{
 311		return $this->response;
 312	}
 313	// END
 314	
 315	//-------------------------------------
 316	//  Sends an Error Message for Server Request
 317	//-------------------------------------
 318	
 319	function send_error_message($number, $message)
 320	{
 321		return new XML_RPC_Response('0',$number, $message);
 322	}
 323	// END
 324	
 325	
 326	//-------------------------------------
 327	//  Send Response for Server Request
 328	//-------------------------------------
 329	
 330	function send_response($response)
 331	{
 332		// $response should be array of values, which will be parsed
 333		// based on their data and type into a valid group of XML-RPC values
 334		
 335		$response = $this->values_parsing($response);
 336	
 337		return new XML_RPC_Response($response);
 338	}
 339	// END
 340	
 341} // END XML_RPC Class
 342
 343	
 344	
 345/**
 346 * XML-RPC Client class
 347 *
 348 * @category	XML-RPC
 349 * @author		ExpressionEngine Dev Team
 350 * @link		http://codeigniter.com/user_guide/libraries/xmlrpc.html
 351 */
 352class XML_RPC_Client extends CI_Xmlrpc
 353{
 354	var $path			= '';
 355	var $server			= '';
 356	var $port			= 80;
 357	var $errno			= '';
 358	var $errstring		= '';
 359	var $timeout		= 5;
 360	var $no_multicall	= false;
 361
 362	function XML_RPC_Client($path, $server, $port=80)
 363	{
 364		parent::CI_Xmlrpc();
 365		
 366		$this->port = $port;
 367		$this->server = $server;
 368		$this->path = $path;
 369	}
 370	
 371	function send($msg)
 372	{
 373		if (is_array($msg))
 374		{
 375			// Multi-call disabled
 376			$r = new XML_RPC_Response(0, $this->xmlrpcerr['multicall_recursion'],$this->xmlrpcstr['multicall_recursion']);
 377			return $r;
 378		}
 379
 380		return $this->sendPayload($msg);
 381	}
 382
 383	function sendPayload($msg)
 384	{	
 385		$fp = @fsockopen($this->server, $this->port,$this->errno, $this->errstr, $this->timeout);
 386		
 387		if ( ! is_resource($fp))
 388		{
 389			error_log($this->xmlrpcstr['http_error']);
 390			$r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'],$this->xmlrpcstr['http_error']);
 391			return $r;
 392		}
 393		
 394		if(empty($msg->payload))
 395		{
 396			// $msg = XML_RPC_Messages
 397			$msg->createPayload();
 398		}
 399		
 400		$r = "\r\n";
 401		$op  = "POST {$this->path} HTTP/1.0$r";
 402		$op .= "Host: {$this->server}$r";
 403		$op .= "Content-Type: text/xml$r";
 404		$op .= "User-Agent: {$this->xmlrpcName}$r";
 405		$op .= "Content-Length: ".strlen($msg->payload). "$r$r";
 406		$op .= $msg->payload;
 407		
 408
 409		if ( ! fputs($fp, $op, strlen($op)))
 410		{
 411			error_log($this->xmlrpcstr['http_error']);
 412			$r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']);
 413			return $r;
 414		}
 415		$resp = $msg->parseResponse($fp);
 416		fclose($fp);
 417		return $resp;
 418	}
 419
 420} // end class XML_RPC_Client
 421
 422
 423/**
 424 * XML-RPC Response class
 425 *
 426 * @category	XML-RPC
 427 * @author		ExpressionEngine Dev Team
 428 * @link		http://codeigniter.com/user_guide/libraries/xmlrpc.html
 429 */
 430class XML_RPC_Response
 431{
 432	var $val = 0;
 433	var $errno = 0;
 434	var $errstr = '';
 435	var $headers = array();
 436
 437	function XML_RPC_Response($val, $code = 0, $fstr = '')
 438	{	
 439		if ($code != 0)
 440		{
 441			// error
 442			$this->errno = $code;
 443			$this->errstr = htmlentities($fstr);
 444		}
 445		else if ( ! is_object($val))
 446		{
 447			// programmer error, not an object
 448			error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to XML_RPC_Response.  Defaulting to empty value.");
 449			$this->val = new XML_RPC_Values();
 450		}
 451		else
 452		{
 453			$this->val = $val;
 454		}
 455	}
 456
 457	function faultCode()
 458	{
 459		return $this->errno;
 460	}
 461
 462	function faultString()
 463	{
 464		return $this->errstr;
 465	}
 466
 467	function value()
 468	{
 469		return $this->val;
 470	}
 471	
 472	function prepare_response()
 473	{
 474		$result = "<methodResponse>\n";
 475		if ($this->errno)
 476		{
 477			$result .= '<fault>
 478	<value>
 479		<struct>
 480			<member>
 481				<name>faultCode</name>
 482				<value><int>' . $this->errno . '</int></value>
 483			</member>
 484			<member>
 485				<name>faultString</name>
 486				<value><string>' . $this->errstr . '</string></value>
 487			</member>
 488		</struct>
 489	</value>
 490</fault>';
 491		}
 492		else
 493		{
 494			$result .= "<params>\n<param>\n" .
 495					$this->val->serialize_class() .
 496					"</param>\n</params>";
 497		}
 498		$result .= "\n</methodResponse>";
 499		return $result;
 500	}
 501	
 502	function decode($array=FALSE)
 503	{
 504		$CI =& get_instance();
 505
 506		if ($array !== FALSE && is_array($array))
 507		{
 508			while (list($key) = each($array))
 509			{
 510				if (is_array($array[$key]))
 511				{
 512					$array[$key] = $this->decode($array[$key]);
 513				}
 514				else
 515				{
 516					$array[$key] = $CI->input->xss_clean($array[$key]);
 517				}
 518			}
 519			
 520			$result = $array;
 521		}
 522		else
 523		{
 524			$result = $this->xmlrpc_decoder($this->val);
 525			
 526			if (is_array($result))
 527			{
 528				$result = $this->decode($result);
 529			}
 530			else
 531			{
 532				$result = $CI->input->xss_clean($result);
 533			}
 534		}
 535		
 536		return $result;
 537	}
 538
 539	
 540	
 541	//-------------------------------------
 542	//  XML-RPC Object to PHP Types
 543	//-------------------------------------
 544
 545	function xmlrpc_decoder($xmlrpc_val)
 546	{
 547		$kind = $xmlrpc_val->kindOf();
 548
 549		if($kind == 'scalar')
 550		{
 551			return $xmlrpc_val->scalarval();
 552		}
 553		elseif($kind == 'array')
 554		{
 555			reset($xmlrpc_val->me);
 556			list($a,$b) = each($xmlrpc_val->me);
 557			$size = count($b);
 558			
 559			$arr = array();
 560
 561			for($i = 0; $i < $size; $i++)
 562			{
 563				$arr[] = $this->xmlrpc_decoder($xmlrpc_val->me['array'][$i]);
 564			}
 565			return $arr;
 566		}
 567		elseif($kind == 'struct')
 568		{
 569			reset($xmlrpc_val->me['struct']);
 570			$arr = array();
 571
 572			while(list($key,$value) = each($xmlrpc_val->me['struct']))
 573			{
 574				$arr[$key] = $this->xmlrpc_decoder($value);
 575			}
 576			return $arr;
 577		}
 578	}
 579	
 580	
 581	//-------------------------------------
 582	//  ISO-8601 time to server or UTC time
 583	//-------------------------------------
 584
 585	function iso8601_decode($time, $utc=0)
 586	{
 587		// return a timet in the localtime, or UTC
 588		$t = 0;
 589		if (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $time, $regs))
 590		{
 591			if ($utc == 1)
 592				$t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
 593			else
 594				$t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
 595		}
 596		return $t;
 597	}
 598	
 599} // End Response Class
 600
 601
 602
 603/**
 604 * XML-RPC Message class
 605 *
 606 * @category	XML-RPC
 607 * @author		ExpressionEngine Dev Team
 608 * @link		http://codeigniter.com/user_guide/libraries/xmlrpc.html
 609 */
 610class XML_RPC_Message extends CI_Xmlrpc
 611{
 612	var $payload;
 613	var $method_name;
 614	var $params			= array();
 615	var $xh 			= array();
 616
 617	function XML_RPC_Message($method, $pars=0)
 618	{
 619		parent::CI_Xmlrpc();
 620		
 621		$this->method_name = $method;
 622		if (is_array($pars) && count($pars) > 0)
 623		{
 624			for($i=0; $i<count($pars); $i++)
 625			{
 626				// $pars[$i] = XML_RPC_Values
 627				$this->params[] = $pars[$i];
 628			}
 629		}
 630	}
 631	
 632	//-------------------------------------
 633	//  Create Payload to Send
 634	//-------------------------------------
 635	
 636	function createPayload()
 637	{
 638		$this->payload = "<?xml version=\"1.0\"?".">\r\n<methodCall>\r\n";
 639		$this->payload .= '<methodName>' . $this->method_name . "</methodName>\r\n";
 640		$this->payload .= "<params>\r\n";
 641		
 642		for($i=0; $i<count($this->params); $i++)
 643		{
 644			// $p = XML_RPC_Values
 645			$p = $this->params[$i];
 646			$this->payload .= "<param>\r\n".$p->serialize_class()."</param>\r\n";
 647		}
 648		
 649		$this->payload .= "</params>\r\n</methodCall>\r\n";
 650	}
 651	
 652	//-------------------------------------
 653	//  Parse External XML-RPC Server's Response
 654	//-------------------------------------
 655	
 656	function parseResponse($fp)
 657	{
 658		$data = '';
 659		
 660		while($datum = fread($fp, 4096))
 661		{
 662			$data .= $datum;
 663		}
 664		
 665		//-------------------------------------
 666		//  DISPLAY HTTP CONTENT for DEBUGGING
 667		//-------------------------------------
 668		
 669		if ($this->debug === TRUE)
 670		{
 671			echo "<pre>";
 672			echo "---DATA---\n" . htmlspecialchars($data) . "\n---END DATA---\n\n";
 673			echo "</pre>";
 674		}
 675		
 676		//-------------------------------------
 677		//  Check for data
 678		//-------------------------------------
 679
 680		if($data == "")
 681		{
 682			error_log($this->xmlrpcstr['no_data']);
 683			$r = new XML_RPC_Response(0, $this->xmlrpcerr['no_data'], $this->xmlrpcstr['no_data']);
 684			return $r;
 685		}
 686		
 687		
 688		//-------------------------------------
 689		//  Check for HTTP 200 Response
 690		//-------------------------------------
 691		
 692		if (strncmp($data, 'HTTP', 4) == 0 && ! preg_match('/^HTTP\/[0-9\.]+ 200 /', $data))
 693		{
 694			$errstr= substr($data, 0, strpos($data, "\n")-1);
 695			$r = new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']. ' (' . $errstr . ')');
 696			return $r;
 697		}
 698		
 699		//-------------------------------------
 700		//  Create and Set Up XML Parser
 701		//-------------------------------------
 702	
 703		$parser = xml_parser_create($this->xmlrpc_defencoding);
 704
 705		$this->xh[$parser]				 = array();
 706		$this->xh[$parser]['isf']		 = 0;
 707		$this->xh[$parser]['ac']		 = '';
 708		$this->xh[$parser]['headers'] 	 = array();
 709		$this->xh[$parser]['stack']		 = array();
 710		$this->xh[$parser]['valuestack'] = array();
 711		$this->xh[$parser]['isf_reason'] = 0;
 712
 713		xml_set_object($parser, $this);
 714		xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
 715		xml_set_element_handler($parser, 'open_tag', 'closing_tag');
 716		xml_set_character_data_handler($parser, 'character_data');
 717		//xml_set_default_handler($parser, 'default_handler');
 718
 719
 720		//-------------------------------------
 721		//  GET HEADERS
 722		//-------------------------------------
 723		
 724		$lines = explode("\r\n", $data);
 725		while (($line = array_shift($lines)))
 726		{
 727			if (strlen($line) < 1)
 728			{
 729				break;
 730			}
 731			$this->xh[$parser]['headers'][] = $line;
 732		}
 733		$data = implode("\r\n", $lines);
 734		
 735		
 736		//-------------------------------------
 737		//  PARSE XML DATA
 738		//-------------------------------------  	
 739
 740		if ( ! xml_parse($parser, $data, count($data)))
 741		{
 742			$errstr = sprintf('XML error: %s at line %d',
 743					xml_error_string(xml_get_error_code($parser)),
 744					xml_get_current_line_number($parser));
 745			//error_log($errstr);
 746			$r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']);
 747			xml_parser_free($parser);
 748			return $r;
 749		}
 750		xml_parser_free($parser);
 751		
 752		// ---------------------------------------
 753		//  Got Ourselves Some Badness, It Seems
 754		// ---------------------------------------
 755		
 756		if ($this->xh[$parser]['isf'] > 1)
 757		{
 758			if ($this->debug === TRUE)
 759			{
 760				echo "---Invalid Return---\n";
 761				echo $this->xh[$parser]['isf_reason'];
 762				echo "---Invalid Return---\n\n";
 763			}
 764				
 765			$r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'],$this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']);
 766			return $r;
 767		}
 768		elseif ( ! is_object($this->xh[$parser]['value']))
 769		{
 770			$r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'],$this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']);
 771			return $r;
 772		}
 773		
 774		//-------------------------------------
 775		//  DISPLAY XML CONTENT for DEBUGGING
 776		//-------------------------------------  	
 777		
 778		if ($this->debug === TRUE)
 779		{
 780			echo "<pre>";
 781			
 782			if (count($this->xh[$parser]['headers'] > 0))
 783			{
 784				echo "---HEADERS---\n";
 785				foreach ($this->xh[$parser]['headers'] as $header)
 786				{
 787					echo "$header\n";
 788				}
 789				echo "---END HEADERS---\n\n";
 790			}
 791			
 792			echo "---DATA---\n" . htmlspecialchars($data) . "\n---END DATA---\n\n";
 793			
 794			echo "---PARSED---\n" ;
 795			var_dump($this->xh[$parser]['value']);
 796			echo "\n---END PARSED---</pre>";
 797		}
 798		
 799		//-------------------------------------
 800		//  SEND RESPONSE
 801		//-------------------------------------
 802		
 803		$v = $this->xh[$parser]['value'];
 804			
 805		if ($this->xh[$parser]['isf'])
 806		{
 807			$errno_v = $v->me['struct']['faultCode'];
 808			$errstr_v = $v->me['struct']['faultString'];
 809			$errno = $errno_v->scalarval();
 810
 811			if ($errno == 0)
 812			{
 813				// FAULT returned, errno needs to reflect that
 814				$errno = -1;
 815			}
 816
 817			$r = new XML_RPC_Response($v, $errno, $errstr_v->scalarval());
 818		}
 819		else
 820		{
 821			$r = new XML_RPC_Response($v);
 822		}
 823
 824		$r->headers = $this->xh[$parser]['headers'];
 825		return $r;
 826	}
 827	
 828	// ------------------------------------
 829	//  Begin Return Message Parsing section
 830	// ------------------------------------
 831	
 832	// quick explanation of components:
 833	//   ac - used to accumulate values
 834	//   isf - used to indicate a fault
 835	//   lv - used to indicate "looking for a value": implements
 836	//		the logic to allow values with no types to be strings
 837	//   params - used to store parameters in method calls
 838	//   method - used to store method name
 839	//	 stack - array with parent tree of the xml element,
 840	//			 used to validate the nesting of elements
 841
 842	//-------------------------------------
 843	//  Start Element Handler
 844	//-------------------------------------
 845
 846	function open_tag($the_parser, $name, $attrs)
 847	{
 848		// If invalid nesting, then return
 849		if ($this->xh[$the_parser]['isf'] > 1) return;
 850		
 851		// Evaluate and check for correct nesting of XML elements
 852		
 853		if (count($this->xh[$the_parser]['stack']) == 0)
 854		{
 855			if ($name != 'METHODRESPONSE' && $name != 'METHODCALL')
 856			{
 857				$this->xh[$the_parser]['isf'] = 2;
 858				$this->xh[$the_parser]['isf_reason'] = 'Top level XML-RPC element is missing';
 859				return;
 860			}
 861		}
 862		else
 863		{
 864			// not top level element: see if parent is OK
 865			if ( ! in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name], TRUE))
 866			{
 867				$this->xh[$the_parser]['isf'] = 2;
 868				$this->xh[$the_parser]['isf_reason'] = "XML-RPC element $name cannot be child of ".$this->xh[$the_parser]['stack'][0];
 869				return;
 870			}
 871		}
 872		
 873		switch($name)
 874		{
 875			case 'STRUCT':
 876			case 'ARRAY':
 877				// Creates array for child elements
 878				
 879				$cur_val = array('value' => array(),
 880								 'type'	 => $name);
 881								
 882				array_unshift($this->xh[$the_parser]['valuestack'], $cur_val);
 883			break;
 884			case 'METHODNAME':
 885			case 'NAME':
 886				$this->xh[$the_parser]['ac'] = '';
 887			break;
 888			case 'FAULT':
 889				$this->xh[$the_parser]['isf'] = 1;
 890			break;
 891			case 'PARAM':
 892				$this->xh[$the_parser]['value'] = null;
 893			break;
 894			case 'VALUE':
 895				$this->xh[$the_parser]['vt'] = 'value';
 896				$this->xh[$the_parser]['ac'] = '';
 897				$this->xh[$the_parser]['lv'] = 1;
 898			break;
 899			case 'I4':
 900			case 'INT':
 901			case 'STRING':
 902			case 'BOOLEAN':
 903			case 'DOUBLE':
 904			case 'DATETIME.ISO8601':
 905			case 'BASE64':
 906				if ($this->xh[$the_parser]['vt'] != 'value')
 907				{
 908					//two data elements inside a value: an error occurred!
 909					$this->xh[$the_parser]['isf'] = 2;
 910					$this->xh[$the_parser]['isf_reason'] = "'Twas a $name element following a ".$this->xh[$the_parser]['vt']." element inside a single value";
 911					return;
 912				}
 913				
 914				$this->xh[$the_parser]['ac'] = '';
 915			break;
 916			case 'MEMBER':
 917				// Set name of <member> to nothing to prevent errors later if no <name> is found
 918				$this->xh[$the_parser]['valuestack'][0]['name'] = '';
 919				
 920				// Set NULL value to check to see if value passed for this param/member
 921				$this->xh[$the_parser]['value'] = null;
 922			break;
 923			case 'DATA':
 924			case 'METHODCALL':
 925			case 'METHODRESPONSE':
 926			case 'PARAMS':
 927				// valid elements that add little to processing
 928			break;
 929			default:
 930				/// An Invalid Element is Found, so we have trouble
 931				$this->xh[$the_parser]['isf'] = 2;
 932				$this->xh[$the_parser]['isf_reason'] = "Invalid XML-RPC element found: $name";
 933			break;
 934		}
 935		
 936		// Add current element name to stack, to allow validation of nesting
 937		array_unshift($this->xh[$the_parser]['stack'], $name);
 938
 939		if ($name != 'VALUE') $this->xh[$the_parser]['lv'] = 0;
 940	}
 941	// END
 942
 943
 944	//-------------------------------------
 945	//  End Element Handler
 946	//-------------------------------------
 947
 948	function closing_tag($the_parser, $name)
 949	{
 950		if ($this->xh[$the_parser]['isf'] > 1) return;
 951		
 952		// Remove current element from stack and set variable
 953		// NOTE: If the XML validates, then we do not have to worry about
 954		// the opening and closing of elements.  Nesting is checked on the opening
 955		// tag so we be safe there as well.
 956		
 957		$curr_elem = array_shift($this->xh[$the_parser]['stack']);
 958	
 959		switch($name)
 960		{
 961			case 'STRUCT':
 962			case 'ARRAY':
 963				$cur_val = array_shift($this->xh[$the_parser]['valuestack']);
 964				$this->xh[$the_parser]['value'] = ( ! isset($cur_val['values'])) ? array() : $cur_val['values'];
 965				$this->xh[$the_parser]['vt']	= strtolower($name);
 966			break;
 967			case 'NAME':
 968				$this->xh[$the_parser]['valuestack'][0]['name'] = $this->xh[$the_parser]['ac'];
 969			break;
 970			case 'BOOLEAN':
 971			case 'I4':
 972			case 'INT':
 973			case 'STRING':
 974			case 'DOUBLE':
 975			case 'DATETIME.ISO8601':
 976			case 'BASE64':
 977				$this->xh[$the_parser]['vt'] = strtolower($name);
 978				
 979				if ($name == 'STRING')
 980				{
 981					$this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
 982				}
 983				elseif ($name=='DATETIME.ISO8601')
 984				{
 985					$this->xh[$the_parser]['vt']	= $this->xmlrpcDateTime;
 986					$this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac'];
 987				}
 988				elseif ($name=='BASE64')
 989				{
 990					$this->xh[$the_parser]['value'] = base64_decode($this->xh[$the_parser]['ac']);
 991				}
 992				elseif ($name=='BOOLEAN')
 993				{
 994					// Translated BOOLEAN values to TRUE AND FALSE
 995					if ($this->xh[$the_parser]['ac'] == '1')
 996					{
 997						$this->xh[$the_parser]['value'] = TRUE;
 998					}
 999					else
1000					{
1001						$this->xh[$the_parser]['value'] = FALSE;
1002					}
1003				}
1004				elseif ($name=='DOUBLE')
1005				{
1006					// we have a DOUBLE
1007					// we must check that only 0123456789-.<space> are characters here
1008					if ( ! preg_match('/^[+-]?[eE0-9\t \.]+$/', $this->xh[$the_parser]['ac']))
1009					{
1010						$this->xh[$the_parser]['value'] = 'ERROR_NON_NUMERIC_FOUND';
1011					}
1012					else
1013					{
1014						$this->xh[$the_parser]['value'] = (double)$this->xh[$the_parser]['ac'];
1015					}
1016				}
1017				else
1018				{
1019					// we have an I4/INT
1020					// we must check that only 0123456789-<space> are characters here
1021					if ( ! preg_match('/^[+-]?[0-9\t ]+$/', $this->xh[$the_parser]['ac']))
1022					{
1023						$this->xh[$the_parser]['value'] = 'ERROR_NON_NUMERIC_FOUND';
1024					}
1025					else
1026					{
1027						$this->xh[$the_parser]['value'] = (int)$this->xh[$the_parser]['ac'];
1028					}
1029				}
1030				$this->xh[$the_parser]['ac'] = '';
1031				$this->xh[$the_parser]['lv'] = 3; // indicate we've found a value
1032			break;
1033			case 'VALUE':
1034				// This if() detects if no scalar was inside <VALUE></VALUE>
1035				if ($this->xh[$the_parser]['vt']=='value')
1036				{
1037					$this->xh[$the_parser]['value']	= $this->xh[$the_parser]['ac'];
1038					$this->xh[$the_parser]['vt']	= $this->xmlrpcString;
1039				}
1040				
1041				// build the XML-RPC value out of the data received, and substitute it
1042				$temp = new XML_RPC_Values($this->xh[$the_parser]['value'], $this->xh[$the_parser]['vt']);
1043				
1044				if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] == 'ARRAY')
1045				{
1046					// Array
1047					$this->xh[$the_parser]['valuestack'][0]['values'][] = $temp;
1048				}
1049				else
1050				{
1051					// Struct
1052					$this->xh[$the_parser]['value'] = $temp;
1053				}
1054			break;
1055			case 'MEMBER':
1056				$this->xh[$the_parser]['ac']='';
1057				
1058				// If value add to array in the stack for the last element built
1059				if ($this->xh[$the_parser]['value'])
1060				{
1061					$this->xh[$the_parser]['valuestack'][0]['values'][$this->xh[$the_parser]['valuestack'][0]['name']] = $this->xh[$the_parser]['value'];
1062				}
1063			break;
1064			case 'DATA':
1065				$this->xh[$the_parser]['ac']='';
1066			break;
1067			case 'PARAM':
1068				if ($this->xh[$the_parser]['value'])
1069				{
1070					$this->xh[$the_parser]['params'][] = $this->xh[$the_parser]['value'];
1071				}
1072			break;
1073			case 'METHODNAME':
1074				$this->xh[$the_parser]['method'] = ltrim($this->xh[$the_parser]['ac']);
1075			break;
1076			case 'PARAMS':
1077			case 'FAULT':
1078			case 'METHODCALL':
1079			case 'METHORESPONSE':
1080				// We're all good kids with nuthin' to do
1081			break;
1082			default:
1083				// End of an Invalid Element.  Taken care of during the opening tag though
1084			break;
1085		}
1086	}
1087
1088	//-------------------------------------
1089	//  Parses Character Data
1090	//-------------------------------------
1091
1092	function character_data($the_parser, $data)
1093	{
1094		if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already
1095		
1096		// If a value has not been found
1097		if ($this->xh[$the_parser]['lv'] != 3)
1098		{
1099			if ($this->xh[$the_parser]['lv'] == 1)
1100			{
1101				$this->xh[$the_parser]['lv'] = 2; // Found a value
1102			}
1103				
1104			if( ! @isset($this->xh[$the_parser]['ac']))
1105			{
1106				$this->xh[$the_parser]['ac'] = '';
1107			}
1108				
1109			$this->xh[$the_parser]['ac'] .= $data;
1110		}
1111	}
1112	
1113	
1114	function addParam($par) { $this->params[]=$par; }
1115	
1116	function output_parameters($array=FALSE)
1117	{
1118		$CI =& get_instance();	
1119
1120		if ($array !== FALSE && is_array($array))
1121		{
1122			while (list($key) = each($array))
1123			{
1124				if (is_array($array[$key]))
1125				{
1126					$array[$key] = $this->output_parameters($array[$key]);
1127				}
1128				else
1129				{
1130					$array[$key] = $CI->input->xss_clean($array[$key]);
1131				}
1132			}
1133			
1134			$parameters = $array;
1135		}
1136		else
1137		{
1138			$parameters = array();
1139		
1140			for ($i = 0; $i < count($this->params); $i++)
1141			{
1142				$a_param = $this->decode_message($this->params[$i]);
1143				
1144				if (is_array($a_param))
1145				{
1146					$parameters[] = $this->output_parameters($a_param);
1147				}
1148				else
1149				{
1150					$parameters[] = $CI->input->xss_clean($a_param);
1151				}
1152			}	
1153		}
1154		
1155		return $parameters;
1156	}
1157	
1158	
1159	function decode_message($param)
1160	{
1161		$kind = $param->kindOf();
1162
1163		if($kind == 'scalar')
1164		{
1165			return $param->scalarval();
1166		}
1167		elseif($kind == 'array')
1168		{
1169			reset($param->me);
1170			list($a,$b) = each($param->me);
1171			
1172			$arr = array();
1173
1174			for($i = 0; $i < count($b); $i++)
1175			{
1176				$arr[] = $this->decode_message($param->me['array'][$i]);
1177			}
1178			
1179			return $arr;
1180		}
1181		elseif($kind == 'struct')
1182		{
1183			reset($param->me['struct']);
1184			
1185			$arr = array();
1186
1187			while(list($key,$value) = each($param->me['struct']))
1188			{
1189				$arr[$key] = $this->decode_message($value);
1190			}
1191			
1192			return $arr;
1193		}
1194	}
1195	
1196} // End XML_RPC_Messages class
1197
1198
1199
1200/**
1201 * XML-RPC Values class
1202 *
1203 * @category	XML-RPC
1204 * @author		ExpressionEngine Dev Team
1205 * @link		http://codeigniter.com/user_guide/libraries/xmlrpc.html
1206 */
1207class XML_RPC_Values extends CI_Xmlrpc
1208{
1209	var $me 	= array();
1210	var $mytype	= 0;
1211
1212	function XML_RPC_Values($val=-1, $type='')
1213	{	
1214		parent::CI_Xmlrpc();
1215		
1216		if ($val != -1 OR $type != '')
1217		{
1218			$type = $type == '' ? 'string' : $type;
1219			
1220			if ($this->xmlrpcTypes[$type] == 1)
1221			{
1222				$this->addScalar($val,$type);
1223			}
1224			elseif ($this->xmlrpcTypes[$type] == 2)
1225			{
1226				$this->addArray($val);
1227			}
1228			elseif ($this->xmlrpcTypes[$type] == 3)
1229			{
1230				$this->addStruct($val);
1231			}
1232		}
1233	}
1234
1235	function addScalar($val, $type='string')
1236	{
1237		$typeof = $this->xmlrpcTypes[$type];
1238		
1239		if ($this->mytype==1)
1240		{
1241			echo '<strong>XML_RPC_Values</strong>: scalar can have only one value<br />';
1242			return 0;
1243		}
1244		
1245		if ($typeof != 1)
1246		{
1247			echo '<strong>XML_RPC_Values</strong>: not a scalar type (${typeof})<br />';
1248			return 0;
1249		}
1250
1251		if ($type == $this->xmlrpcBoolean)
1252		{
1253			if (strcasecmp($val,'true')==0 OR $val==1 OR ($val==true && strcasecmp($val,'false')))
1254			{
1255				$val = 1;
1256			}
1257			else
1258			{
1259				$val=0;
1260			}
1261		}
1262
1263		if ($this->mytype == 2)
1264		{
1265			// adding to an array here
1266			$ar = $this->me['array'];
1267			$ar[] = new XML_RPC_Values($val, $type);
1268			$this->me['array'] = $ar;
1269		}
1270		else
1271		{
1272			// a scalar, so set the value and remember we're scalar
1273			$this->me[$type] = $val;
1274			$this->mytype = $typeof;
1275		}
1276		return 1;
1277	}
1278
1279	function addArray($vals)
1280	{
1281		if ($this->mytype != 0)
1282		{
1283			echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
1284			return 0;
1285		}
1286
1287		$this->mytype = $this->xmlrpcTypes['array'];
1288		$this->me['array'] = $vals;
1289		return 1;
1290	}
1291
1292	function addStruct($vals)
1293	{
1294		if ($this->mytype != 0)
1295		{
1296			echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />';
1297			return 0;
1298		}
1299		$this->mytype = $this->xmlrpcTypes['struct'];
1300		$this->me['struct'] = $vals;
1301		return 1;
1302	}
1303
1304	function kindOf()
1305	{
1306		switch($this->mytype)
1307		{
1308			case 3:
1309				return 'struct';
1310				break;
1311			case 2:
1312				return 'array';
1313				break;
1314			case 1:
1315				return 'scalar';
1316				break;
1317			default:
1318				return 'undef';
1319		}
1320	}
1321
1322	function serializedata($typ, $val)
1323	{
1324		$rs = '';
1325		
1326		switch($this->xmlrpcTypes[$typ])
1327		{
1328			case 3:
1329				// struct
1330				$rs .= "<struct>\n";
1331				reset($val);
1332				while(list($key2, $val2) = each($val))
1333				{
1334					$rs .= "<member>\n<name>{$key2}</name>\n";
1335					$rs .= $this->serializeval($val2);
1336					$rs .= "</member>\n";
1337				}
1338				$rs .= '</struct>';
1339			break;
1340			case 2:
1341				// array
1342				$rs .= "<array>\n<data>\n";
1343				for($i=0; $i < count($val); $i++)
1344				{
1345					$rs .= $this->serializeval($val[$i]);
1346				}
1347				$rs.="</data>\n</array>\n";
1348				break;
1349			case 1:
1350				// others
1351				switch ($typ)
1352				{
1353					case $this->xmlrpcBase64:
1354						$rs .= "<{$typ}>" . base64_encode((string)$val) . "</{$typ}>\n";
1355					break;
1356					case $this->xmlrpcBoolean:
1357						$rs .= "<{$typ}>" . ((bool)$val ? '1' : '0') . "</{$typ}>\n";
1358					break;
1359					case $this->xmlrpcString:
1360						$rs .= "<{$typ}>" . htmlspecialchars((string)$val). "</{$typ}>\n";
1361					break;
1362					default:
1363						$rs .= "<{$typ}>{$val}</{$typ}>\n";
1364					break;
1365				}
1366			default:
1367			break;
1368		}
1369		return $rs;
1370	}
1371
1372	function serialize_class()
1373	{
1374		return $this->serializeval($this);
1375	}
1376
1377	function serializeval($o)
1378	{
1379		$ar = $o->me;
1380		reset($ar);
1381		
1382		list($typ, $val) = each($ar);
1383		$rs = "<value>\n".$this->serializedata($typ, $val)."</value>\n";
1384		return $rs;
1385	}
1386	
1387	function scalarval()
1388	{
1389		reset($this->me);
1390		list($a,$b) = each($this->me);
1391		return $b;
1392	}
1393
1394
1395	//-------------------------------------
1396	// Encode time in ISO-8601 form.
1397	//-------------------------------------
1398	
1399	// Useful for sending time in XML-RPC
1400
1401	function iso8601_encode($time, $utc=0)
1402	{	
1403		if ($utc == 1)
1404		{
1405			$t = strftime("%Y%m%dT%H:%M:%S", $time);
1406		}
1407		else
1408		{
1409			if (function_exists('gmstrftime'))
1410				$t = gmstrftime("%Y%m%dT%H:%M:%S", $time);
1411			else
1412				$t = strftime("%Y%m%dT%H:%M:%S", $time - date('Z'));
1413		}
1414		return $t;
1415	}
1416	
1417}
1418// END XML_RPC_Values Class
1419
1420/* End of file Xmlrpc.php */
1421/* Location: ./system/libraries/Xmlrpc.php */