PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/include/PayPal/SOAP/Base.php

https://github.com/radicaldesigns/amp
PHP | 1182 lines | 859 code | 98 blank | 225 comment | 201 complexity | edcf589414ca280da65d81c3e2250f66 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, BSD-3-Clause, LGPL-2.0, CC-BY-SA-3.0, AGPL-1.0
  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available at through the world-wide-web at |
  11. // | http://www.php.net/license/2_02.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Shane Caraveo <Shane@Caraveo.com> Port to PEAR and more |
  17. // | Authors: Dietrich Ayala <dietrich@ganx4.com> Original Author |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: Base.php,v 1.1.1.1 2006/02/19 08:15:20 dennis Exp $
  21. //
  22. /*
  23. SOAP_OBJECT_STRUCT makes pear::soap use objects for soap structures
  24. rather than arrays. This has been done to provide a closer match to php-soap.
  25. If the old behaviour is needed, set to false. The old behaviour is deprecated.
  26. */
  27. $GLOBALS['SOAP_OBJECT_STRUCT'] = true;
  28. /*
  29. SOAP_RAW_CONVERT makes pear::soap attempt to determine what SOAP type
  30. a php string COULD be. This may result in slightly better interoperability when
  31. you are not using WSDL, and are being lazy and not using SOAP_Value to define
  32. types for your values.
  33. */
  34. $GLOBALS['SOAP_RAW_CONVERT'] = false;
  35. require_once 'PEAR.php';
  36. require_once 'PayPal/SOAP/Type/dateTime.php';
  37. require_once 'PayPal/SOAP/Type/hexBinary.php';
  38. // optional features
  39. $GLOBALS['SOAP_options'] = array();
  40. @include_once 'Mail/mimePart.php';
  41. @include_once 'Mail/mimeDecode.php';
  42. if (class_exists('Mail_mimePart')) {
  43. $GLOBALS['SOAP_options']['Mime'] = 1;
  44. define('MAIL_MIMEPART_CRLF', "\r\n");
  45. }
  46. @include_once 'Net/DIME.php';
  47. if (class_exists('Net_DIME_Message')) {
  48. $GLOBALS['SOAP_options']['DIME'] = 1;
  49. }
  50. /**
  51. * Enable debugging informations?
  52. *
  53. * @name $SOAP_DEBUG
  54. * @global $GLOBALS['SOAP_DEBUG']
  55. */
  56. $GLOBALS['SOAP_DEBUG'] = false;
  57. if (!function_exists('version_compare') ||
  58. version_compare(phpversion(), '4.1', '<')) {
  59. die("requires PHP 4.1 or higher\n");
  60. }
  61. if (version_compare(phpversion(), '4.1', '>=') &&
  62. version_compare(phpversion(), '4.2', '<')) {
  63. define('FLOAT', 'double');
  64. } else {
  65. define('FLOAT', 'float');
  66. }
  67. if (!defined('INF')) {
  68. define('INF', 1.8e307);
  69. }
  70. if (!defined('NAN')) {
  71. define('NAN', 0.0);
  72. }
  73. define('SOAP_LIBRARY_VERSION', '0.8.0RC4');
  74. define('SOAP_LIBRARY_NAME', 'PEAR-SOAP 0.8.0RC4-devel');
  75. // set schema version
  76. define('SOAP_XML_SCHEMA_VERSION', 'http://www.w3.org/2001/XMLSchema');
  77. define('SOAP_XML_SCHEMA_INSTANCE', 'http://www.w3.org/2001/XMLSchema-instance');
  78. define('SOAP_XML_SCHEMA_1999', 'http://www.w3.org/1999/XMLSchema');
  79. define('SOAP_SCHEMA', 'http://schemas.xmlsoap.org/wsdl/soap/');
  80. define('SOAP_SCHEMA_ENCODING', 'http://schemas.xmlsoap.org/soap/encoding/');
  81. define('SOAP_ENVELOP', 'http://schemas.xmlsoap.org/soap/envelope/');
  82. define('SCHEMA_DISCO', 'http://schemas.xmlsoap.org/disco/');
  83. define('SCHEMA_DISCO_SCL', 'http://schemas.xmlsoap.org/disco/scl/');
  84. define('SCHEMA_SOAP', 'http://schemas.xmlsoap.org/wsdl/soap/');
  85. define('SCHEMA_SOAP_HTTP', 'http://schemas.xmlsoap.org/soap/http');
  86. define('SCHEMA_WSDL_HTTP', 'http://schemas.xmlsoap.org/wsdl/http/');
  87. define('SCHEMA_MIME', 'http://schemas.xmlsoap.org/wsdl/mime/');
  88. define('SCHEMA_WSDL', 'http://schemas.xmlsoap.org/wsdl/');
  89. define('SCHEMA_DIME', 'http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/');
  90. define('SCHEMA_CONTENT', 'http://schemas.xmlsoap.org/ws/2002/04/content-type/');
  91. define('SCHEMA_REF', 'http://schemas.xmlsoap.org/ws/2002/04/reference/');
  92. define('SOAP_DEFAULT_ENCODING', 'UTF-8');
  93. if (!function_exists('is_a'))
  94. {
  95. function is_a(&$object, $class_name)
  96. {
  97. if (strtolower(get_class($object)) == $class_name) {
  98. return true;
  99. }
  100. return is_subclass_of($object, $class_name);
  101. }
  102. }
  103. if (!class_exists('stdClass')) {
  104. /* PHP5 doesn't define this? */
  105. class stdClass {
  106. function __constructor() {}
  107. };
  108. }
  109. class SOAP_Base_Object extends PEAR
  110. {
  111. /**
  112. * Store debugging information in $debug_data?
  113. *
  114. * @var boolean if true debugging informations will be store in $debug_data
  115. * @see $debug_data, SOAP_Base
  116. */
  117. var $_debug_flag = false;
  118. /**
  119. * String containing debugging informations if $debug_flag is set to true
  120. *
  121. * @var string debugging informations - mostyl error messages
  122. * @see $debug_flag, SOAP_Base
  123. * @access public
  124. */
  125. var $_debug_data = '';
  126. /**
  127. * supported encodings, limited by XML extension
  128. */
  129. var $_encodings = array('ISO-8859-1', 'US-ASCII', 'UTF-8');
  130. /**
  131. * Fault code
  132. *
  133. * @var string
  134. */
  135. var $_myfaultcode = '';
  136. /**
  137. * Recent PEAR error object
  138. *
  139. * @var object PEAR Error
  140. */
  141. var $fault = null;
  142. /**
  143. * Constructor
  144. *
  145. * @param string error code
  146. * @see $debug_data, _debug()
  147. */
  148. function SOAP_Base_Object($faultcode = 'Client')
  149. {
  150. $this->_myfaultcode = $faultcode;
  151. $this->_debug_flag = $GLOBALS['SOAP_DEBUG'];
  152. parent::PEAR('SOAP_Fault');
  153. }
  154. /**
  155. * Raise a soap error
  156. *
  157. * Please referr to the SOAP definition for an impression of what a certain parameter
  158. * stands for.
  159. *
  160. * Use $debug_flag to store errors to the member variable $debug_data
  161. *
  162. * @param string error message
  163. * @param string detailed error message.
  164. * @param string actor
  165. * @param mixed
  166. * @param mixed
  167. * @param mixed
  168. * @param boolean
  169. * @see $debug_flag, $debug_data
  170. */
  171. function &_raiseSoapFault($str, $detail = '', $actorURI = '', $code = null, $mode = null, $options = null, $skipmsg = false)
  172. {
  173. // Pass through previous faults.
  174. $is_instance = isset($this);
  175. if (is_object($str)) {
  176. $fault = $str;
  177. } else {
  178. if (!$code) {
  179. $code = $is_instance?$this->_myfaultcode:'Client';
  180. }
  181. $fault = new SOAP_Fault($str,
  182. $code,
  183. $actorURI,
  184. $detail,
  185. $mode,
  186. $options);
  187. }
  188. if ($is_instance) {
  189. $this->fault = $fault;
  190. }
  191. return $fault;
  192. }
  193. function __isfault()
  194. {
  195. return $this->fault != null;
  196. }
  197. function &__getfault()
  198. {
  199. return $this->fault;
  200. }
  201. /**
  202. * maintains a string of debug data.
  203. *
  204. * @param debugging message - sometimes an error message
  205. */
  206. function _debug($string)
  207. {
  208. if ($this->_debug_flag) {
  209. $this->_debug_data .= get_class($this) . ': ' . preg_replace("/>/", ">\r\n", $string) . "\n";
  210. }
  211. }
  212. }
  213. /**
  214. * SOAP_Base
  215. * Common base class of all Soap lclasses
  216. *
  217. * @access public
  218. * @package SOAP::Client
  219. * @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
  220. */
  221. class SOAP_Base extends SOAP_Base_Object
  222. {
  223. var $_XMLSchema = array('http://www.w3.org/2001/XMLSchema', 'http://www.w3.org/1999/XMLSchema');
  224. var $_XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
  225. // load types into typemap array
  226. var $_typemap = array(
  227. 'http://www.w3.org/2001/XMLSchema' => array(
  228. 'string' => 'string',
  229. 'boolean' => 'boolean',
  230. 'float' => FLOAT,
  231. 'double' => FLOAT,
  232. 'decimal' => FLOAT,
  233. 'duration' => 'integer',
  234. 'dateTime' => 'string',
  235. 'time' => 'string',
  236. 'date' => 'string',
  237. 'gYearMonth' => 'integer',
  238. 'gYear' => 'integer',
  239. 'gMonthDay' => 'integer',
  240. 'gDay' => 'integer',
  241. 'gMonth' => 'integer',
  242. 'hexBinary' => 'string',
  243. 'base64Binary' => 'string',
  244. // derived datatypes
  245. 'normalizedString' => 'string',
  246. 'token' => 'string',
  247. 'language' => 'string',
  248. 'NMTOKEN' => 'string',
  249. 'NMTOKENS' => 'string',
  250. 'Name' => 'string',
  251. 'NCName' => 'string',
  252. 'ID' => 'string',
  253. 'IDREF' => 'string',
  254. 'IDREFS' => 'string',
  255. 'ENTITY' => 'string',
  256. 'ENTITIES' => 'string',
  257. 'integer' => 'integer',
  258. 'nonPositiveInteger' => 'integer',
  259. 'negativeInteger' => 'integer',
  260. 'long' => 'integer',
  261. 'int' => 'integer',
  262. 'short' => 'integer',
  263. 'byte' => 'string',
  264. 'nonNegativeInteger' => 'integer',
  265. 'unsignedLong' => 'integer',
  266. 'unsignedInt' => 'integer',
  267. 'unsignedShort' => 'integer',
  268. 'unsignedByte' => 'integer',
  269. 'positiveInteger' => 'integer',
  270. 'anyType' => 'string',
  271. 'anyURI' => 'string',
  272. 'QName' => 'string'
  273. ),
  274. 'http://www.w3.org/1999/XMLSchema' => array(
  275. 'i4' => 'integer',
  276. 'int' => 'integer',
  277. 'boolean' => 'boolean',
  278. 'string' => 'string',
  279. 'double' => FLOAT,
  280. 'float' => FLOAT,
  281. 'dateTime' => 'string',
  282. 'timeInstant' => 'string',
  283. 'base64Binary' => 'string',
  284. 'base64' => 'string',
  285. 'ur-type' => 'string'
  286. ),
  287. 'http://schemas.xmlsoap.org/soap/encoding/' => array(
  288. 'base64' => 'string',
  289. 'array' => 'array',
  290. 'Array' => 'array',
  291. 'Struct' => 'array')
  292. );
  293. /**
  294. * Default class name to use for decoded response objects.
  295. */
  296. var $_defaultObjectClassname = 'stdClass';
  297. // Load namespace uris into an array of uri => prefix
  298. var $_namespaces;
  299. var $_namespace;
  300. var $_xmlEntities = array('&' => '&amp;', '<' => '&lt;', '>' => '&gt;', "'" => '&apos;', '"' => '&quot;');
  301. var $_doconversion = false;
  302. var $__attachments = array();
  303. var $_wsdl = null;
  304. /**
  305. * section5
  306. *
  307. * @var boolean defines if we use section 5 encoding, or false if this is literal
  308. */
  309. var $_section5 = true;
  310. // handle type to class mapping
  311. var $_auto_translation = false;
  312. var $_type_translation = array();
  313. /**
  314. * Constructor
  315. *
  316. * @param string error code
  317. * @see $debug_data, _debug()
  318. */
  319. function SOAP_Base($faultcode = 'Client')
  320. {
  321. parent::SOAP_Base_Object($faultcode);
  322. $this->_resetNamespaces();
  323. }
  324. function _resetNamespaces()
  325. {
  326. $this->_namespaces = array(
  327. 'http://schemas.xmlsoap.org/soap/envelope/' => 'SOAP-ENV',
  328. 'http://www.w3.org/2001/XMLSchema' => 'xsd',
  329. 'http://www.w3.org/2001/XMLSchema-instance' => 'xsi',
  330. 'http://schemas.xmlsoap.org/soap/encoding/' => 'SOAP-ENC');
  331. }
  332. /**
  333. * _setSchemaVersion
  334. *
  335. * sets the schema version used in the soap message
  336. *
  337. * @param string (see globals.php)
  338. *
  339. * @access private
  340. */
  341. function _setSchemaVersion($schemaVersion)
  342. {
  343. if (!in_array($schemaVersion, $this->_XMLSchema)) {
  344. return $this->_raiseSoapFault("unsuported XMLSchema $schemaVersion");
  345. }
  346. $this->_XMLSchemaVersion = $schemaVersion;
  347. $tmpNS = array_flip($this->_namespaces);
  348. $tmpNS['xsd'] = $this->_XMLSchemaVersion;
  349. $tmpNS['xsi'] = $this->_XMLSchemaVersion. '-instance';
  350. $this->_namespaces = array_flip($tmpNS);
  351. }
  352. function _getNamespacePrefix($ns)
  353. {
  354. if ($this->_namespace && $ns == $this->_namespace) {
  355. return '';
  356. }
  357. if (isset($this->_namespaces[$ns])) {
  358. return $this->_namespaces[$ns];
  359. }
  360. $prefix = 'ns' . count($this->_namespaces);
  361. $this->_namespaces[$ns] = $prefix;
  362. return $prefix;
  363. }
  364. function _getNamespaceForPrefix($prefix)
  365. {
  366. $flipped = array_flip($this->_namespaces);
  367. if (isset($flipped[$prefix])) {
  368. return $flipped[$prefix];
  369. }
  370. return null;
  371. }
  372. function _isSoapValue(&$value)
  373. {
  374. return is_object($value) && is_a($value, 'soap_value');
  375. }
  376. function _serializeValue(&$value, $name = '', $type = false, $elNamespace = null,
  377. $typeNamespace = null, $options = array(), $attributes = array(), $artype = '')
  378. {
  379. $namespaces = array();
  380. $arrayType = $array_depth = $xmlout_value = null;
  381. $typePrefix = $elPrefix = $xmlout_offset = $xmlout_arrayType = $xmlout_type = $xmlns = '';
  382. $ptype = $array_type_ns = '';
  383. if (!$name || is_numeric($name)) {
  384. $name = 'item';
  385. }
  386. if ($this->_wsdl) {
  387. list($ptype, $arrayType, $array_type_ns, $array_depth)
  388. = $this->_wsdl->getSchemaType($type, $name, $typeNamespace);
  389. }
  390. if (!$arrayType) {
  391. $arrayType = $artype;
  392. }
  393. if (!$ptype) {
  394. $ptype = $this->_getType($value);
  395. }
  396. if (!$type) {
  397. $type = $ptype;
  398. }
  399. if (strcasecmp($ptype, 'Struct') == 0 || strcasecmp($type, 'Struct') == 0) {
  400. // struct
  401. $vars = null;
  402. if (is_object($value)) {
  403. $vars = get_object_vars($value);
  404. } else {
  405. $vars = &$value;
  406. }
  407. if (is_array($vars)) {
  408. foreach (array_keys($vars) as $k) {
  409. // Hide private vars.
  410. if ($k[0] == '_') continue;
  411. if (is_object($vars[$k])) {
  412. if (is_a($vars[$k], 'soap_value')) {
  413. $xmlout_value .= $vars[$k]->serialize($this);
  414. } else {
  415. // XXX get the members and serialize them instead
  416. // converting to an array is more overhead than we
  417. // should really do.
  418. $dvar = get_object_vars($vars[$k]);
  419. $xmlout_value .= $this->_serializeValue( $dvar, $k, false, $this->_section5 ? null : $elNamespace);
  420. }
  421. } else {
  422. $xmlout_value .= $this->_serializeValue($vars[$k], $k, false, $this->_section5 ? null : $elNamespace);
  423. }
  424. }
  425. }
  426. } elseif (strcasecmp($ptype, 'Array') == 0 || strcasecmp($type, 'Array') == 0) {
  427. // Array.
  428. $typeNamespace = SOAP_SCHEMA_ENCODING;
  429. $orig_type = $type;
  430. $type = 'Array';
  431. $numtypes = 0;
  432. // XXX this will be slow on larger arrays. Basically, it
  433. // flattens arrays to allow us to serialize
  434. // multi-dimensional arrays. We only do this if arrayType
  435. // is set, which will typically only happen if we are
  436. // using WSDL
  437. if (isset($options['flatten']) || ($arrayType && (strchr($arrayType, ',') || strstr($arrayType, '][')))) {
  438. $numtypes = $this->_multiArrayType($value, $arrayType, $ar_size, $xmlout_value);
  439. }
  440. $array_type = $array_type_prefix = '';
  441. if ($numtypes != 1) {
  442. $arrayTypeQName = new QName($arrayType);
  443. $arrayType = $arrayTypeQName->name;
  444. $array_types = array();
  445. $array_val = null;
  446. // Serialize each array element.
  447. $ar_size = count($value);
  448. foreach ($value as $array_val) {
  449. if ($this->_isSoapValue($array_val)) {
  450. $array_type = $array_val->type;
  451. $array_types[$array_type] = 1;
  452. $array_type_ns = $array_val->type_namespace;
  453. $xmlout_value .= $this->_serializeValue($array_val, $array_val->name, $array_type, $array_type_ns);
  454. } else {
  455. $array_type = $this->_getType($array_val);
  456. $array_types[$array_type] = 1;
  457. $xmlout_value .= $this->_serializeValue($array_val, 'item', $array_type, $this->_section5 ? null : $elNamespace);
  458. }
  459. }
  460. $xmlout_offset = " SOAP-ENC:offset=\"[0]\"";
  461. if (!$arrayType) {
  462. $numtypes = count($array_types);
  463. if ($numtypes == 1) {
  464. $arrayType = $array_type;
  465. }
  466. // Using anyType is more interoperable.
  467. if ($array_type == 'Struct') {
  468. $array_type = '';
  469. } elseif ($array_type == 'Array') {
  470. $arrayType = 'anyType';
  471. $array_type_prefix = 'xsd';
  472. } else {
  473. if (!$arrayType) {
  474. $arrayType = $array_type;
  475. }
  476. }
  477. }
  478. }
  479. if (!$arrayType || $numtypes > 1) {
  480. $arrayType = 'xsd:anyType'; // should reference what schema we're using
  481. } else {
  482. if ($array_type_ns) {
  483. $array_type_prefix = $this->_getNamespacePrefix($array_type_ns);
  484. } elseif (isset($this->_typemap[$this->_XMLSchemaVersion][$arrayType])) {
  485. $array_type_prefix = $this->_namespaces[$this->_XMLSchemaVersion];
  486. }
  487. if ($array_type_prefix)
  488. $arrayType = $array_type_prefix. ':' .$arrayType;
  489. }
  490. $xmlout_arrayType = " SOAP-ENC:arrayType=\"" . $arrayType;
  491. if ($array_depth != null) {
  492. for ($i = 0; $i < $array_depth; $i++) {
  493. $xmlout_arrayType .= '[]';
  494. }
  495. }
  496. $xmlout_arrayType .= "[$ar_size]\"";
  497. } elseif ($this->_isSoapValue($value)) {
  498. $xmlout_value = $value->serialize($this);
  499. } elseif ($type == 'string') {
  500. $xmlout_value = htmlspecialchars($value);
  501. } elseif ($type == 'rawstring') {
  502. $xmlout_value = $value;
  503. } elseif ($type == 'boolean') {
  504. $xmlout_value = $value?'true':'false';
  505. } else {
  506. $xmlout_value = $value;
  507. }
  508. // Add namespaces.
  509. if ($elNamespace) {
  510. $elPrefix = $this->_getNamespacePrefix($elNamespace);
  511. if ($elPrefix) {
  512. $xmlout_name = "$elPrefix:$name";
  513. } else {
  514. $xmlout_name = $name;
  515. }
  516. } else {
  517. $xmlout_name = $name;
  518. }
  519. if ($typeNamespace) {
  520. $typePrefix = $this->_getNamespacePrefix($typeNamespace);
  521. if ($typePrefix) {
  522. $xmlout_type = "$typePrefix:$type";
  523. } else {
  524. $xmlout_type = $type;
  525. }
  526. } elseif ($type && isset($this->_typemap[$this->_XMLSchemaVersion][$type])) {
  527. $typePrefix = $this->_namespaces[$this->_XMLSchemaVersion];
  528. if ($typePrefix) {
  529. $xmlout_type = "$typePrefix:$type";
  530. } else {
  531. $xmlout_type = $type;
  532. }
  533. }
  534. // Handle additional attributes.
  535. $xml_attr = '';
  536. if (count($attributes)) {
  537. foreach ($attributes as $k => $v) {
  538. $kqn = new QName($k);
  539. $vqn = new QName($v);
  540. $xml_attr .= ' ' . $kqn->fqn() . '="' . $vqn->fqn() . '"';
  541. }
  542. }
  543. // Store the attachement for mime encoding.
  544. if (isset($options['attachment'])) {
  545. $this->__attachments[] = $options['attachment'];
  546. }
  547. if ($this->_section5) {
  548. if ($xmlout_type) {
  549. $xmlout_type = " xsi:type=\"$xmlout_type\"";
  550. }
  551. if (is_null($xmlout_value)) {
  552. $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType$xml_attr xsi:nil=\"true\"/>";
  553. } else {
  554. $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType$xmlout_offset$xml_attr>" .
  555. $xmlout_value . "</$xmlout_name>";
  556. }
  557. } else {
  558. if (is_null($xmlout_value)) {
  559. $xml = "\r\n<$xmlout_name$xmlns$xml_attr/>";
  560. } else {
  561. $xml = "\r\n<$xmlout_name$xmlns$xml_attr>" .
  562. $xmlout_value . "</$xmlout_name>";
  563. }
  564. }
  565. return $xml;
  566. }
  567. /**
  568. * SOAP::Value::_getType
  569. *
  570. * Convert a php type to a soap type.
  571. *
  572. * @param string &$value The value to inspect.
  573. *
  574. * @return string Soap type.
  575. *
  576. * @access private
  577. */
  578. function _getType(&$value)
  579. {
  580. global $SOAP_OBJECT_STRUCT, $SOAP_RAW_CONVERT;
  581. $type = gettype($value);
  582. switch ($type) {
  583. case 'object':
  584. if (is_a($value, 'soap_value')) {
  585. $type = $value->type;
  586. } else {
  587. $type = 'Struct';
  588. }
  589. break;
  590. case 'array':
  591. // XXX hashes always get done as structs by pear::soap
  592. if ($this->_isHash($value)) {
  593. $type = 'Struct';
  594. } else {
  595. $ar_size = count($value);
  596. reset($value);
  597. $key1 = key($value);
  598. if ($ar_size > 0 && is_a($key1, 'soap_value')) {
  599. // fixme for non-wsdl structs that are all the same type
  600. $key2 = key($value);
  601. if ($ar_size > 1 &&
  602. $this->_isSoapValue($key1) &&
  603. $this->_isSoapValue($key2) &&
  604. $key1->name != $key2->name) {
  605. // this is a struct, not an array
  606. $type = 'Struct';
  607. } else {
  608. $type = 'Array';
  609. }
  610. } else {
  611. $type = 'Array';
  612. }
  613. }
  614. break;
  615. case 'integer':
  616. case 'long':
  617. $type = 'int';
  618. break;
  619. case 'boolean':
  620. break;
  621. case 'double':
  622. $type = 'float'; // double is deprecated in 4.2 and later
  623. break;
  624. case 'null':
  625. $type = '';
  626. break;
  627. case 'string':
  628. if ($SOAP_RAW_CONVERT) {
  629. if (is_numeric($value)) {
  630. if (strstr($value, '.')) {
  631. $type = 'float';
  632. } else {
  633. $type = 'int';
  634. }
  635. } else {
  636. if (SOAP_Type_hexBinary::is_hexbin($value)) {
  637. $type = 'hexBinary';
  638. } else {
  639. if ($this->_isBase64($value)) {
  640. $type = 'base64Binary';
  641. } else {
  642. $dt = new SOAP_Type_dateTime($value);
  643. if ($dt->toUnixtime() != -1) {
  644. $type = 'dateTime';
  645. }
  646. }
  647. }
  648. }
  649. }
  650. break;
  651. default:
  652. break;
  653. }
  654. return $type;
  655. }
  656. function _multiArrayType(&$value, &$type, &$size, &$xml)
  657. {
  658. $sz = count($value);
  659. if (is_array($value)) {
  660. // Seems we have a multi dimensional array, figure it out
  661. // if we do.
  662. $c = count($value);
  663. for ($i = 0; $i < $c; $i++) {
  664. $this->_multiArrayType($value[$i], $type, $size, $xml);
  665. }
  666. if ($size) {
  667. $size = $sz. ',' . $size;
  668. } else {
  669. $size = $sz;
  670. }
  671. return 1;
  672. } else {
  673. if (is_object($value)) {
  674. $type = $value->type;
  675. $xml .= $value->serialize($this);
  676. } else {
  677. $type = $this->_getType($value);
  678. $xml .= $this->_serializeValue($value, 'item', $type);
  679. }
  680. }
  681. $size = null;
  682. return 1;
  683. }
  684. /**
  685. *
  686. * @param string
  687. * @return boolean
  688. */
  689. function _isBase64(&$value)
  690. {
  691. $l = strlen($value);
  692. if ($l) {
  693. return $value[$l - 1] == '=' && preg_match("/[A-Za-z=\/\+]+/", $value);
  694. }
  695. return false;
  696. }
  697. /**
  698. *
  699. * @param string
  700. * @return boolean
  701. */
  702. function _isBase64Type($type)
  703. {
  704. return $type == 'base64' || $type == 'base64Binary';
  705. }
  706. /**
  707. *
  708. * @param mixed
  709. * @return boolean
  710. */
  711. function _isHash(&$a)
  712. {
  713. // XXX I really dislike having to loop through this in PHP
  714. // code, really large arrays will be slow. We need a C
  715. // function to do this.
  716. $names = array();
  717. $it = 0;
  718. foreach ($a as $k => $v) {
  719. // Checking the type is faster than regexp.
  720. $t = gettype($k);
  721. if ($t != 'integer') {
  722. return true;
  723. } elseif ($this->_isSoapValue($v)) {
  724. $names[$v->name] = 1;
  725. }
  726. // If someone has a large hash they should realy be
  727. // defining the type.
  728. if ($it++ > 10) {
  729. return false;
  730. }
  731. }
  732. return count($names)>1;
  733. }
  734. function &_un_htmlentities($string)
  735. {
  736. $trans_tbl = get_html_translation_table(HTML_ENTITIES);
  737. $trans_tbl = array_flip($trans_tbl);
  738. return strtr($string, $trans_tbl);
  739. }
  740. /**
  741. *
  742. * @param mixed
  743. */
  744. function &_decode(&$soapval)
  745. {
  746. global $SOAP_OBJECT_STRUCT;
  747. if (!$this->_isSoapValue($soapval)) {
  748. return $soapval;
  749. } elseif (is_array($soapval->value)) {
  750. if ($SOAP_OBJECT_STRUCT && $soapval->type != 'Array') {
  751. $classname = $this->_defaultObjectClassname;
  752. if (isset($this->_type_translation[$soapval->tqn->fqn()])) {
  753. // This will force an error in php if the class
  754. // does not exist.
  755. $classname = $this->_type_translation[$soapval->tqn->fqn()];
  756. } elseif (isset($this->_type_translation[$soapval->type])) {
  757. // This will force an error in php if the class
  758. // does not exist.
  759. $classname = $this->_type_translation[$soapval->type];
  760. } elseif ($this->_auto_translation) {
  761. if (class_exists($soapval->type)) {
  762. $classname = $soapval->type;
  763. } elseif ($this->_wsdl) {
  764. $t = $this->_wsdl->getComplexTypeNameForElement($soapval->name, $soapval->namespace);
  765. if ($t && class_exists($t)) {
  766. $classname = $t;
  767. }
  768. }
  769. }
  770. $return = new $classname;
  771. } else {
  772. $return = array();
  773. }
  774. $counter = 1;
  775. $isstruct = !$SOAP_OBJECT_STRUCT || !is_array($return);
  776. foreach ($soapval->value as $item) {
  777. if (is_object($return)) {
  778. if ($this->_wsdl) {
  779. // Get this child's WSDL information.
  780. // /$soapval->ns/$soapval->type/$item->ns/$item->name
  781. $child_type = $this->_wsdl->getComplexTypeChildType(
  782. $soapval->namespace,
  783. $soapval->name,
  784. $item->namespace,
  785. $item->name);
  786. if ($child_type) {
  787. $item->type = $child_type;
  788. }
  789. }
  790. if (!$isstruct || $item->type == 'Array') {
  791. if (isset($return->{$item->name}) &&
  792. is_object($return->{$item->name})) {
  793. $return->{$item->name} = $this->_decode($item);
  794. } elseif (isset($return->{$item->name}) &&
  795. is_array($return->{$item->name})) {
  796. $return->{$item->name}[] = $this->_decode($item);
  797. } elseif (is_array($return)) {
  798. $return[] = $this->_decode($item);
  799. } else {
  800. $return->{$item->name} = $this->_decode($item);
  801. }
  802. } elseif (isset($return->{$item->name})) {
  803. $isstruct = false;
  804. if (count(get_object_vars($return)) == 1) {
  805. $d = $this->_decode($item);
  806. $return = array($return->{$item->name}, $d);
  807. } else {
  808. $d = $this->_decode($item);
  809. $return->{$item->name} = array($return->{$item->name}, $d);
  810. }
  811. } else {
  812. $return->{$item->name} = $this->_decode($item);
  813. }
  814. // Set the attributes as members in the class.
  815. if (method_exists($return, '__set_attribute')) {
  816. foreach ($soapval->attributes as $key => $value) {
  817. call_user_func_array(array(&$return, '__set_attribute'), array($key, $value));
  818. }
  819. }
  820. } else {
  821. if ($soapval->arrayType && $this->_isSoapValue($item)) {
  822. if ($this->_isBase64Type($item->type) && !$this->_isBase64Type($soapval->arrayType)) {
  823. // Decode the value if we're losing the
  824. // base64 type information.
  825. $item->value = base64_decode($item->value);
  826. }
  827. $item->type = $soapval->arrayType;
  828. }
  829. if (!$isstruct) {
  830. $return[] = $this->_decode($item);
  831. } elseif (isset($return[$item->name])) {
  832. $isstruct = false;
  833. $d = $this->_decode($item);
  834. $return = array($return[$item->name], $d);
  835. } else {
  836. $return[$item->name] = $this->_decode($item);
  837. }
  838. }
  839. }
  840. return $return;
  841. }
  842. if ($soapval->type == 'boolean') {
  843. if ($soapval->value != '0' && strcasecmp($soapval->value, 'false') != 0) {
  844. $soapval->value = true;
  845. } else {
  846. $soapval->value = false;
  847. }
  848. } elseif ($soapval->type && isset($this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type])) {
  849. // If we can, set variable type.
  850. settype($soapval->value, $this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type]);
  851. }
  852. if ($this->_isBase64Type($soapval->type)) {
  853. return base64_decode($soapval->value);
  854. } else {
  855. return $soapval->value;
  856. }
  857. }
  858. /**
  859. * Creates the soap envelope with the soap envelop data.
  860. *
  861. * @param string $payload soap data (in xml)
  862. * @return associative array (headers,body)
  863. * @access private
  864. */
  865. function &_makeEnvelope(&$method, &$headers, $encoding = SOAP_DEFAULT_ENCODING, $options = array())
  866. {
  867. $smsg = $header_xml = $ns_string = '';
  868. if ($headers) {
  869. $c = count($headers);
  870. for ($i = 0; $i < $c; $i++) {
  871. $header_xml .= $headers[$i]->serialize($this);
  872. }
  873. $header_xml = "<SOAP-ENV:Header>\r\n$header_xml\r\n</SOAP-ENV:Header>\r\n";
  874. }
  875. if (!isset($options['input']) || $options['input'] == 'parse') {
  876. if (is_array($method)) {
  877. $c = count($method);
  878. for ($i = 0; $i < $c; $i++) {
  879. $smsg .= $method[$i]->serialize($this);
  880. }
  881. } else {
  882. $smsg = $method->serialize($this);
  883. }
  884. } else {
  885. $smsg = $method;
  886. }
  887. $body = "<SOAP-ENV:Body>\r\n" . $smsg . "\r\n</SOAP-ENV:Body>\r\n";
  888. foreach ($this->_namespaces as $k => $v) {
  889. $ns_string .= " xmlns:$v=\"$k\"\r\n";
  890. }
  891. if ($this->_namespace) {
  892. $ns_string .= " xmlns=\"{$this->_namespace}\"\r\n";
  893. }
  894. /* if use='literal', we do not put in the encodingStyle. This is denoted by
  895. $this->_section5 being false.
  896. XXX use can be defined at a more granular level than we are dealing with
  897. here, so this does not work for all services.
  898. */
  899. $xml = "<?xml version=\"1.0\" encoding=\"$encoding\"?>\r\n\r\n".
  900. "<SOAP-ENV:Envelope $ns_string".
  901. ($this->_section5 ? ' SOAP-ENV:encodingStyle="' . SOAP_SCHEMA_ENCODING . '"' : '').
  902. ">\r\n".
  903. "$header_xml$body</SOAP-ENV:Envelope>\r\n";
  904. return $xml;
  905. }
  906. function &_makeMimeMessage(&$xml, $encoding = SOAP_DEFAULT_ENCODING)
  907. {
  908. global $SOAP_options;
  909. if (!isset($SOAP_options['Mime'])) {
  910. return $this->_raiseSoapFault('Mime is not installed');
  911. }
  912. // encode any attachments
  913. // see http://www.w3.org/TR/SOAP-attachments
  914. // now we have to mime encode the message
  915. $params = array('content_type' => 'multipart/related; type=text/xml');
  916. $msg = new Mail_mimePart('', $params);
  917. // add the xml part
  918. $params['content_type'] = 'text/xml';
  919. $params['charset'] = $encoding;
  920. $params['encoding'] = 'base64';
  921. $msg->addSubPart($xml, $params);
  922. // add the attachements
  923. $c = count($this->__attachments);
  924. for ($i = 0; $i < $c; $i++) {
  925. $attachment = $this->__attachments[$i];
  926. $msg->addSubPart($attachment['body'], $attachment);
  927. }
  928. return $msg->encode();
  929. }
  930. // XXX this needs to be used from the Transport system
  931. function &_makeDIMEMessage(&$xml)
  932. {
  933. global $SOAP_options;
  934. if (!isset($SOAP_options['DIME'])) {
  935. return $this->_raiseSoapFault('DIME is not installed');
  936. }
  937. // encode any attachments
  938. // see http://search.ietf.org/internet-drafts/draft-nielsen-dime-soap-00.txt
  939. // now we have to DIME encode the message
  940. $dime = new Net_DIME_Message();
  941. $msg = $dime->encodeData($xml,SOAP_ENVELOP,null,NET_DIME_TYPE_URI);
  942. // add the attachements
  943. $c = count($this->__attachments);
  944. for ($i = 0; $i < $c; $i++) {
  945. $attachment = $this->__attachments[$i];
  946. $msg .= $dime->encodeData($attachment['body'], $attachment['content_type'], $attachment['cid'],NET_DIME_TYPE_MEDIA);
  947. }
  948. $msg .= $dime->endMessage();
  949. return $msg;
  950. }
  951. function _decodeMimeMessage(&$data, &$headers, &$attachments)
  952. {
  953. global $SOAP_options;
  954. if (!isset($SOAP_options['Mime'])) {
  955. $this->_raiseSoapFault('Mime Unsupported, install PEAR::Mail::Mime', '', '', 'Server');
  956. return;
  957. }
  958. $params['include_bodies'] = true;
  959. $params['decode_bodies'] = true;
  960. $params['decode_headers'] = true;
  961. // XXX lame thing to have to do for decoding
  962. $decoder = new Mail_mimeDecode($data);
  963. $structure = $decoder->decode($params);
  964. if (isset($structure->body)) {
  965. $data = $structure->body;
  966. $headers = $structure->headers;
  967. return;
  968. } elseif (isset($structure->parts)) {
  969. $data = $structure->parts[0]->body;
  970. $headers = array_merge($structure->headers, $structure->parts[0]->headers);
  971. if (count($structure->parts) > 1) {
  972. $mime_parts = array_splice($structure->parts,1);
  973. // prepare the parts for the soap parser
  974. $c = count($mime_parts);
  975. for ($i = 0; $i < $c; $i++) {
  976. $p = $mime_parts[$i];
  977. if (isset($p->headers['content-location'])) {
  978. // XXX TODO: modify location per SwA note section 3
  979. // http://www.w3.org/TR/SOAP-attachments
  980. $attachments[$p->headers['content-location']] = $p->body;
  981. } else {
  982. $cid = 'cid:' . substr($p->headers['content-id'], 1, strlen($p->headers['content-id']) - 2);
  983. $attachments[$cid] = $p->body;
  984. }
  985. }
  986. }
  987. return;
  988. }
  989. $this->_raiseSoapFault('Mime parsing error', '', '', 'Server');
  990. }
  991. function _decodeDIMEMessage(&$data, &$headers, &$attachments)
  992. {
  993. global $SOAP_options;
  994. if (!isset($SOAP_options['DIME'])) {
  995. $this->_raiseSoapFault('DIME Unsupported, install PEAR::Net::DIME', '', '', 'Server');
  996. return;
  997. }
  998. // XXX this SHOULD be moved to the transport layer, e.g. PHP itself
  999. // should handle parsing DIME ;)
  1000. $dime = new Net_DIME_Message();
  1001. $err = $dime->decodeData($data);
  1002. if (PEAR::isError($err)) {
  1003. $this->_raiseSoapFault('Failed to decode the DIME message!', '', '', 'Server');
  1004. return;
  1005. }
  1006. if (strcasecmp($dime->parts[0]['type'], SOAP_ENVELOP) != 0) {
  1007. $this->_raiseSoapFault('DIME record 1 is not a SOAP envelop!', '', '', 'Server');
  1008. return;
  1009. }
  1010. $data = $dime->parts[0]['data'];
  1011. // fake it for now
  1012. $headers['content-type'] = 'text/xml';
  1013. $c = count($dime->parts);
  1014. for ($i = 0; $i < $c; $i++) {
  1015. $part = $dime->parts[$i];
  1016. // XXX we need to handle URI's better.
  1017. $id = strncmp($part['id'], 'cid:', 4) ? 'cid:' . $part['id'] : $part['id'];
  1018. $attachments[$id] = $part['data'];
  1019. }
  1020. }
  1021. function __set_type_translation($type, $class = null)
  1022. {
  1023. $tq = new QName($type);
  1024. if (!$class) {
  1025. $class = $tq->name;
  1026. }
  1027. $this->_type_translation[$type]=$class;
  1028. }
  1029. }
  1030. /**
  1031. * Class used to handle QNAME values in XML.
  1032. *
  1033. * @access public
  1034. * @package SOAP::Client
  1035. * @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
  1036. */
  1037. class QName
  1038. {
  1039. var $name = '';
  1040. var $ns = '';
  1041. var $namespace='';
  1042. function QName($name, $namespace = '')
  1043. {
  1044. if ($name && $name[0] == '{') {
  1045. preg_match('/\{(.*?)\}(.*)/', $name, $m);
  1046. $this->name = $m[2];
  1047. $this->namespace = $m[1];
  1048. } elseif (substr_count($name, ':') == 1) {
  1049. $s = explode(':', $name);
  1050. $s = array_reverse($s);
  1051. $this->name = $s[0];
  1052. $this->ns = $s[1];
  1053. $this->namespace = $namespace;
  1054. } else {
  1055. $this->name = $name;
  1056. $this->namespace = $namespace;
  1057. }
  1058. // a little more magic than should be in a qname.
  1059. $p = strpos($this->name, '[');
  1060. if ($p) {
  1061. // XXX need to re-examine this logic later
  1062. // chop off []
  1063. $this->arraySize = explode(',', substr($this->name, $p + 1, strlen($this->name) - $p - 2));
  1064. $this->arrayInfo = substr($this->name, $p);
  1065. $this->name = substr($this->name, 0, $p);
  1066. }
  1067. }
  1068. function fqn()
  1069. {
  1070. if ($this->namespace) {
  1071. return '{' . $this->namespace . '}' . $this->name;
  1072. } elseif ($this->ns) {
  1073. return $this->ns . ':' . $this->name;
  1074. }
  1075. return $this->name;
  1076. }
  1077. }