File indexing completed on 2024-12-22 05:37:15
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_XmlRpc 0017 * @subpackage Value 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * Represent a native XML-RPC value entity, used as parameters for the methods 0025 * called by the Zend_XmlRpc_Client object and as the return value for those calls. 0026 * 0027 * This object as a very important static function Zend_XmlRpc_Value::getXmlRpcValue, this 0028 * function acts likes a factory for the Zend_XmlRpc_Value objects 0029 * 0030 * Using this function, users/Zend_XmlRpc_Client object can create the Zend_XmlRpc_Value objects 0031 * from PHP variables, XML string or by specifing the exact XML-RPC natvie type 0032 * 0033 * @package Zend_XmlRpc 0034 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0035 * @license http://framework.zend.com/license/new-bsd New BSD License 0036 */ 0037 abstract class Zend_XmlRpc_Value 0038 { 0039 /** 0040 * The native XML-RPC representation of this object's value 0041 * 0042 * If the native type of this object is array or struct, this will be an array 0043 * of Zend_XmlRpc_Value objects 0044 */ 0045 protected $_value; 0046 0047 /** 0048 * The native XML-RPC type of this object 0049 * One of the XMLRPC_TYPE_* constants 0050 */ 0051 protected $_type; 0052 0053 /** 0054 * XML code representation of this object (will be calculated only once) 0055 */ 0056 protected $_xml; 0057 0058 /** 0059 * @var Zend_XmlRpc_Generator_GeneratorAbstract 0060 */ 0061 protected static $_generator; 0062 0063 /** 0064 * Specify that the XML-RPC native type will be auto detected from a PHP variable type 0065 */ 0066 const AUTO_DETECT_TYPE = 'auto_detect'; 0067 0068 /** 0069 * Specify that the XML-RPC value will be parsed out from a given XML code 0070 */ 0071 const XML_STRING = 'xml'; 0072 0073 /** 0074 * All the XML-RPC native types 0075 */ 0076 const XMLRPC_TYPE_I4 = 'i4'; 0077 const XMLRPC_TYPE_INTEGER = 'int'; 0078 const XMLRPC_TYPE_I8 = 'i8'; 0079 const XMLRPC_TYPE_APACHEI8 = 'ex:i8'; 0080 const XMLRPC_TYPE_DOUBLE = 'double'; 0081 const XMLRPC_TYPE_BOOLEAN = 'boolean'; 0082 const XMLRPC_TYPE_STRING = 'string'; 0083 const XMLRPC_TYPE_DATETIME = 'dateTime.iso8601'; 0084 const XMLRPC_TYPE_BASE64 = 'base64'; 0085 const XMLRPC_TYPE_ARRAY = 'array'; 0086 const XMLRPC_TYPE_STRUCT = 'struct'; 0087 const XMLRPC_TYPE_NIL = 'nil'; 0088 const XMLRPC_TYPE_APACHENIL = 'ex:nil'; 0089 0090 /** 0091 * Get the native XML-RPC type (the type is one of the Zend_XmlRpc_Value::XMLRPC_TYPE_* constants) 0092 * 0093 * @return string 0094 */ 0095 public function getType() 0096 { 0097 return $this->_type; 0098 } 0099 0100 /** 0101 * Get XML generator instance 0102 * 0103 * @return Zend_XmlRpc_Generator_GeneratorAbstract 0104 */ 0105 public static function getGenerator() 0106 { 0107 if (!self::$_generator) { 0108 if (extension_loaded('xmlwriter')) { 0109 // require_once 'Zend/XmlRpc/Generator/XmlWriter.php'; 0110 self::$_generator = new Zend_XmlRpc_Generator_XmlWriter(); 0111 } else { 0112 // require_once 'Zend/XmlRpc/Generator/DomDocument.php'; 0113 self::$_generator = new Zend_XmlRpc_Generator_DomDocument(); 0114 } 0115 } 0116 0117 return self::$_generator; 0118 } 0119 0120 /** 0121 * Sets XML generator instance 0122 * 0123 * @param Zend_XmlRpc_Generator_GeneratorAbstract $generator 0124 * @return void 0125 */ 0126 public static function setGenerator(Zend_XmlRpc_Generator_GeneratorAbstract $generator) 0127 { 0128 self::$_generator = $generator; 0129 } 0130 0131 /** 0132 * Changes the encoding of the generator 0133 * 0134 * @param string $encoding 0135 * @return void 0136 */ 0137 public static function setEncoding($encoding) 0138 { 0139 $generator = self::getGenerator(); 0140 $newGenerator = new $generator($encoding); 0141 self::setGenerator($newGenerator); 0142 } 0143 0144 /** 0145 * Return the value of this object, convert the XML-RPC native value into a PHP variable 0146 * 0147 * @return mixed 0148 */ 0149 abstract public function getValue(); 0150 0151 0152 /** 0153 * Return the XML code that represent a native MXL-RPC value 0154 * 0155 * @return string 0156 */ 0157 public function saveXml() 0158 { 0159 if (!$this->_xml) { 0160 $this->generateXml(); 0161 $this->_xml = (string) $this->getGenerator(); 0162 } 0163 return $this->_xml; 0164 } 0165 0166 /** 0167 * Generate XML code that represent a native XML/RPC value 0168 * 0169 * @return void 0170 */ 0171 public function generateXml() 0172 { 0173 $this->_generateXml(); 0174 } 0175 0176 /** 0177 * Creates a Zend_XmlRpc_Value* object, representing a native XML-RPC value 0178 * A XmlRpcValue object can be created in 3 ways: 0179 * 1. Autodetecting the native type out of a PHP variable 0180 * (if $type is not set or equal to Zend_XmlRpc_Value::AUTO_DETECT_TYPE) 0181 * 2. By specifing the native type ($type is one of the Zend_XmlRpc_Value::XMLRPC_TYPE_* constants) 0182 * 3. From a XML string ($type is set to Zend_XmlRpc_Value::XML_STRING) 0183 * 0184 * By default the value type is autodetected according to it's PHP type 0185 * 0186 * @param mixed $value 0187 * @param Zend_XmlRpc_Value::constant $type 0188 * 0189 * @return Zend_XmlRpc_Value 0190 * @static 0191 */ 0192 public static function getXmlRpcValue($value, $type = self::AUTO_DETECT_TYPE) 0193 { 0194 switch ($type) { 0195 case self::AUTO_DETECT_TYPE: 0196 // Auto detect the XML-RPC native type from the PHP type of $value 0197 return self::_phpVarToNativeXmlRpc($value); 0198 0199 case self::XML_STRING: 0200 // Parse the XML string given in $value and get the XML-RPC value in it 0201 return self::_xmlStringToNativeXmlRpc($value); 0202 0203 case self::XMLRPC_TYPE_I4: 0204 // fall through to the next case 0205 case self::XMLRPC_TYPE_INTEGER: 0206 // require_once 'Zend/XmlRpc/Value/Integer.php'; 0207 return new Zend_XmlRpc_Value_Integer($value); 0208 0209 case self::XMLRPC_TYPE_I8: 0210 // fall through to the next case 0211 case self::XMLRPC_TYPE_APACHEI8: 0212 // require_once 'Zend/XmlRpc/Value/BigInteger.php'; 0213 return new Zend_XmlRpc_Value_BigInteger($value); 0214 0215 case self::XMLRPC_TYPE_DOUBLE: 0216 // require_once 'Zend/XmlRpc/Value/Double.php'; 0217 return new Zend_XmlRpc_Value_Double($value); 0218 0219 case self::XMLRPC_TYPE_BOOLEAN: 0220 // require_once 'Zend/XmlRpc/Value/Boolean.php'; 0221 return new Zend_XmlRpc_Value_Boolean($value); 0222 0223 case self::XMLRPC_TYPE_STRING: 0224 // require_once 'Zend/XmlRpc/Value/String.php'; 0225 return new Zend_XmlRpc_Value_String($value); 0226 0227 case self::XMLRPC_TYPE_BASE64: 0228 // require_once 'Zend/XmlRpc/Value/Base64.php'; 0229 return new Zend_XmlRpc_Value_Base64($value); 0230 0231 case self::XMLRPC_TYPE_NIL: 0232 // fall through to the next case 0233 case self::XMLRPC_TYPE_APACHENIL: 0234 // require_once 'Zend/XmlRpc/Value/Nil.php'; 0235 return new Zend_XmlRpc_Value_Nil(); 0236 0237 case self::XMLRPC_TYPE_DATETIME: 0238 // require_once 'Zend/XmlRpc/Value/DateTime.php'; 0239 return new Zend_XmlRpc_Value_DateTime($value); 0240 0241 case self::XMLRPC_TYPE_ARRAY: 0242 // require_once 'Zend/XmlRpc/Value/Array.php'; 0243 return new Zend_XmlRpc_Value_Array($value); 0244 0245 case self::XMLRPC_TYPE_STRUCT: 0246 // require_once 'Zend/XmlRpc/Value/Struct.php'; 0247 return new Zend_XmlRpc_Value_Struct($value); 0248 0249 default: 0250 // require_once 'Zend/XmlRpc/Value/Exception.php'; 0251 throw new Zend_XmlRpc_Value_Exception('Given type is not a '. __CLASS__ .' constant'); 0252 } 0253 } 0254 0255 /** 0256 * Get XML-RPC type for a PHP native variable 0257 * 0258 * @static 0259 * @param mixed $value 0260 * @return string 0261 */ 0262 public static function getXmlRpcTypeByValue($value) 0263 { 0264 if (is_object($value)) { 0265 if ($value instanceof Zend_XmlRpc_Value) { 0266 return $value->getType(); 0267 } elseif (($value instanceof Zend_Date) || ($value instanceof DateTime)) { 0268 return self::XMLRPC_TYPE_DATETIME; 0269 } 0270 return self::getXmlRpcTypeByValue(get_object_vars($value)); 0271 } elseif (is_array($value)) { 0272 if (!empty($value) && is_array($value) && (array_keys($value) !== range(0, count($value) - 1))) { 0273 return self::XMLRPC_TYPE_STRUCT; 0274 } 0275 return self::XMLRPC_TYPE_ARRAY; 0276 } elseif (is_int($value)) { 0277 return ($value > PHP_INT_MAX) ? self::XMLRPC_TYPE_I8 : self::XMLRPC_TYPE_INTEGER; 0278 } elseif (is_double($value)) { 0279 return self::XMLRPC_TYPE_DOUBLE; 0280 } elseif (is_bool($value)) { 0281 return self::XMLRPC_TYPE_BOOLEAN; 0282 } elseif (is_null($value)) { 0283 return self::XMLRPC_TYPE_NIL; 0284 } elseif (is_string($value)) { 0285 return self::XMLRPC_TYPE_STRING; 0286 } 0287 throw new Zend_XmlRpc_Value_Exception(sprintf( 0288 'No matching XMLRPC type found for php type %s.', 0289 gettype($value) 0290 )); 0291 } 0292 0293 /** 0294 * Transform a PHP native variable into a XML-RPC native value 0295 * 0296 * @param mixed $value The PHP variable for convertion 0297 * 0298 * @return Zend_XmlRpc_Value 0299 * @static 0300 */ 0301 protected static function _phpVarToNativeXmlRpc($value) 0302 { 0303 // @see http://framework.zend.com/issues/browse/ZF-8623 0304 if (is_object($value)) { 0305 if ($value instanceof Zend_XmlRpc_Value) { 0306 return $value; 0307 } 0308 if ($value instanceof Zend_Crypt_Math_BigInteger) { 0309 // require_once 'Zend/XmlRpc/Value/Exception.php'; 0310 throw new Zend_XmlRpc_Value_Exception( 0311 'Using Zend_Crypt_Math_BigInteger to get an ' . 0312 'instance of Zend_XmlRpc_Value_BigInteger is not ' . 0313 'available anymore.' 0314 ); 0315 } 0316 } 0317 0318 switch (self::getXmlRpcTypeByValue($value)) 0319 { 0320 case self::XMLRPC_TYPE_DATETIME: 0321 // require_once 'Zend/XmlRpc/Value/DateTime.php'; 0322 return new Zend_XmlRpc_Value_DateTime($value); 0323 0324 case self::XMLRPC_TYPE_ARRAY: 0325 // require_once 'Zend/XmlRpc/Value/Array.php'; 0326 return new Zend_XmlRpc_Value_Array($value); 0327 0328 case self::XMLRPC_TYPE_STRUCT: 0329 // require_once 'Zend/XmlRpc/Value/Struct.php'; 0330 return new Zend_XmlRpc_Value_Struct($value); 0331 0332 case self::XMLRPC_TYPE_INTEGER: 0333 // require_once 'Zend/XmlRpc/Value/Integer.php'; 0334 return new Zend_XmlRpc_Value_Integer($value); 0335 0336 case self::XMLRPC_TYPE_DOUBLE: 0337 // require_once 'Zend/XmlRpc/Value/Double.php'; 0338 return new Zend_XmlRpc_Value_Double($value); 0339 0340 case self::XMLRPC_TYPE_BOOLEAN: 0341 // require_once 'Zend/XmlRpc/Value/Boolean.php'; 0342 return new Zend_XmlRpc_Value_Boolean($value); 0343 0344 case self::XMLRPC_TYPE_NIL: 0345 // require_once 'Zend/XmlRpc/Value/Nil.php'; 0346 return new Zend_XmlRpc_Value_Nil; 0347 0348 case self::XMLRPC_TYPE_STRING: 0349 // Fall through to the next case 0350 default: 0351 // If type isn't identified (or identified as string), it treated as string 0352 // require_once 'Zend/XmlRpc/Value/String.php'; 0353 return new Zend_XmlRpc_Value_String($value); 0354 } 0355 } 0356 0357 0358 /** 0359 * Transform an XML string into a XML-RPC native value 0360 * 0361 * @param string|SimpleXMLElement $xml A SimpleXMLElement object represent the XML string 0362 * It can be also a valid XML string for convertion 0363 * 0364 * @return Zend_XmlRpc_Value 0365 * @static 0366 */ 0367 protected static function _xmlStringToNativeXmlRpc($xml) 0368 { 0369 self::_createSimpleXMLElement($xml); 0370 0371 self::_extractTypeAndValue($xml, $type, $value); 0372 0373 switch ($type) { 0374 // All valid and known XML-RPC native values 0375 case self::XMLRPC_TYPE_I4: 0376 // Fall through to the next case 0377 case self::XMLRPC_TYPE_INTEGER: 0378 // require_once 'Zend/XmlRpc/Value/Integer.php'; 0379 $xmlrpcValue = new Zend_XmlRpc_Value_Integer($value); 0380 break; 0381 case self::XMLRPC_TYPE_APACHEI8: 0382 // Fall through to the next case 0383 case self::XMLRPC_TYPE_I8: 0384 // require_once 'Zend/XmlRpc/Value/BigInteger.php'; 0385 $xmlrpcValue = new Zend_XmlRpc_Value_BigInteger($value); 0386 break; 0387 case self::XMLRPC_TYPE_DOUBLE: 0388 // require_once 'Zend/XmlRpc/Value/Double.php'; 0389 $xmlrpcValue = new Zend_XmlRpc_Value_Double($value); 0390 break; 0391 case self::XMLRPC_TYPE_BOOLEAN: 0392 // require_once 'Zend/XmlRpc/Value/Boolean.php'; 0393 $xmlrpcValue = new Zend_XmlRpc_Value_Boolean($value); 0394 break; 0395 case self::XMLRPC_TYPE_STRING: 0396 // require_once 'Zend/XmlRpc/Value/String.php'; 0397 $xmlrpcValue = new Zend_XmlRpc_Value_String($value); 0398 break; 0399 case self::XMLRPC_TYPE_DATETIME: // The value should already be in a iso8601 format 0400 // require_once 'Zend/XmlRpc/Value/DateTime.php'; 0401 $xmlrpcValue = new Zend_XmlRpc_Value_DateTime($value); 0402 break; 0403 case self::XMLRPC_TYPE_BASE64: // The value should already be base64 encoded 0404 // require_once 'Zend/XmlRpc/Value/Base64.php'; 0405 $xmlrpcValue = new Zend_XmlRpc_Value_Base64($value, true); 0406 break; 0407 case self::XMLRPC_TYPE_NIL: 0408 // Fall through to the next case 0409 case self::XMLRPC_TYPE_APACHENIL: 0410 // The value should always be NULL 0411 // require_once 'Zend/XmlRpc/Value/Nil.php'; 0412 $xmlrpcValue = new Zend_XmlRpc_Value_Nil(); 0413 break; 0414 case self::XMLRPC_TYPE_ARRAY: 0415 // PHP 5.2.4 introduced a regression in how empty($xml->value) 0416 // returns; need to look for the item specifically 0417 $data = null; 0418 foreach ($value->children() as $key => $value) { 0419 if ('data' == $key) { 0420 $data = $value; 0421 break; 0422 } 0423 } 0424 0425 if (null === $data) { 0426 // require_once 'Zend/XmlRpc/Value/Exception.php'; 0427 throw new Zend_XmlRpc_Value_Exception('Invalid XML for XML-RPC native '. self::XMLRPC_TYPE_ARRAY .' type: ARRAY tag must contain DATA tag'); 0428 } 0429 $values = array(); 0430 // Parse all the elements of the array from the XML string 0431 // (simple xml element) to Zend_XmlRpc_Value objects 0432 foreach ($data->value as $element) { 0433 $values[] = self::_xmlStringToNativeXmlRpc($element); 0434 } 0435 // require_once 'Zend/XmlRpc/Value/Array.php'; 0436 $xmlrpcValue = new Zend_XmlRpc_Value_Array($values); 0437 break; 0438 case self::XMLRPC_TYPE_STRUCT: 0439 $values = array(); 0440 // Parse all the memebers of the struct from the XML string 0441 // (simple xml element) to Zend_XmlRpc_Value objects 0442 foreach ($value->member as $member) { 0443 // @todo? If a member doesn't have a <value> tag, we don't add it to the struct 0444 // Maybe we want to throw an exception here ? 0445 if (!isset($member->value) or !isset($member->name)) { 0446 continue; 0447 //throw new Zend_XmlRpc_Value_Exception('Member of the '. self::XMLRPC_TYPE_STRUCT .' XML-RPC native type must contain a VALUE tag'); 0448 } 0449 $values[(string)$member->name] = self::_xmlStringToNativeXmlRpc($member->value); 0450 } 0451 // require_once 'Zend/XmlRpc/Value/Struct.php'; 0452 $xmlrpcValue = new Zend_XmlRpc_Value_Struct($values); 0453 break; 0454 default: 0455 // require_once 'Zend/XmlRpc/Value/Exception.php'; 0456 throw new Zend_XmlRpc_Value_Exception('Value type \''. $type .'\' parsed from the XML string is not a known XML-RPC native type'); 0457 break; 0458 } 0459 $xmlrpcValue->_setXML($xml->asXML()); 0460 0461 return $xmlrpcValue; 0462 } 0463 0464 protected static function _createSimpleXMLElement(&$xml) 0465 { 0466 if ($xml instanceof SimpleXMLElement) { 0467 return; 0468 } 0469 0470 try { 0471 $xml = new SimpleXMLElement($xml); 0472 } catch (Exception $e) { 0473 // The given string is not a valid XML 0474 // require_once 'Zend/XmlRpc/Value/Exception.php'; 0475 throw new Zend_XmlRpc_Value_Exception('Failed to create XML-RPC value from XML string: ' . $e->getMessage(), $e->getCode(), $e); 0476 } 0477 } 0478 0479 /** 0480 * Extract XML/RPC type and value from SimpleXMLElement object 0481 * 0482 * @param SimpleXMLElement $xml 0483 * @param string &$type Type bind variable 0484 * @param string &$value Value bind variable 0485 * @return void 0486 */ 0487 protected static function _extractTypeAndValue(SimpleXMLElement $xml, &$type, &$value) 0488 { 0489 list($type, $value) = each($xml); 0490 0491 if (!$type and $value === null) { 0492 $namespaces = array('ex' => 'http://ws.apache.org/xmlrpc/namespaces/extensions'); 0493 foreach ($namespaces as $namespaceName => $namespaceUri) { 0494 $namespaceXml = $xml->children($namespaceUri); 0495 list($type, $value) = each($namespaceXml); 0496 if ($type !== null) { 0497 $type = $namespaceName . ':' . $type; 0498 break; 0499 } 0500 } 0501 } 0502 0503 //if there is a child element, try to parse type for it 0504 if (!$type && $value instanceof SimpleXMLElement) { 0505 self::_extractTypeAndValue($value->children(), $type, $value); 0506 } 0507 0508 // If no type was specified, the default is string 0509 if (!$type) { 0510 $type = self::XMLRPC_TYPE_STRING; 0511 if (preg_match('#^<value>.*</value>$#', $xml->asXML())) { 0512 $value = str_replace(array('<value>', '</value>'), '', $xml->asXML()); 0513 } 0514 } 0515 } 0516 0517 /** 0518 * @param string $xml 0519 * @return void 0520 */ 0521 protected function _setXML($xml) 0522 { 0523 $this->_xml = $this->getGenerator()->stripDeclaration($xml); 0524 } 0525 }