PageRenderTime 97ms CodeModel.GetById 55ms RepoModel.GetById 0ms app.codeStats 1ms

/include/nusoap/nusoap.php

https://bitbucket.org/yousef_fadila/vtiger
PHP | 7260 lines | 5916 code | 184 blank | 1160 comment | 658 complexity | 7d6ffe3c200702fafc0c78a69d9ffe3a MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. require_once('include/logging.php');
  3. /*
  4. $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
  5. NuSOAP - Web Services Toolkit for PHP
  6. Copyright (c) 2002 NuSphere Corporation
  7. This library is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Lesser General Public
  9. License as published by the Free Software Foundation; either
  10. version 2.1 of the License, or (at your option) any later version.
  11. This library is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. Lesser General Public License for more details.
  15. You should have received a copy of the GNU Lesser General Public
  16. License along with this library; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. If you have any questions or comments, please email:
  19. Dietrich Ayala
  20. dietrich@ganx4.com
  21. http://dietrich.ganx4.com/nusoap
  22. NuSphere Corporation
  23. http://www.nusphere.com
  24. */
  25. /* load classes
  26. // necessary classes
  27. require_once('class.soapclient.php');
  28. require_once('class.soap_val.php');
  29. require_once('class.soap_parser.php');
  30. require_once('class.soap_fault.php');
  31. // transport classes
  32. require_once('class.soap_transport_http.php');
  33. // optional add-on classes
  34. require_once('class.xmlschema.php');
  35. require_once('class.wsdl.php');
  36. // server class
  37. require_once('class.soap_server.php');*/
  38. // class variable emulation
  39. // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
  40. $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
  41. global $soap_log;
  42. $soap_log =& LoggerManager::getLogger('SOAP');
  43. /**
  44. *
  45. * nusoap_base
  46. *
  47. * @author Dietrich Ayala <dietrich@ganx4.com>
  48. * @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
  49. * @access public
  50. */
  51. class nusoap_base {
  52. /**
  53. * Identification for HTTP headers.
  54. *
  55. * @var string
  56. * @access private
  57. */
  58. var $title = 'NuSOAP';
  59. /**
  60. * Version for HTTP headers.
  61. *
  62. * @var string
  63. * @access private
  64. */
  65. var $version = '0.7.2';
  66. /**
  67. * CVS revision for HTTP headers.
  68. *
  69. * @var string
  70. * @access private
  71. */
  72. var $revision = '$Revision: 1.94 $';
  73. /**
  74. * Current error string (manipulated by getError/setError)
  75. *
  76. * @var string
  77. * @access private
  78. */
  79. var $error_str = '';
  80. /**
  81. * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
  82. *
  83. * @var string
  84. * @access private
  85. */
  86. var $debug_str = '';
  87. /**
  88. * toggles automatic encoding of special characters as entities
  89. * (should always be true, I think)
  90. *
  91. * @var boolean
  92. * @access private
  93. */
  94. var $charencoding = true;
  95. /**
  96. * the debug level for this instance
  97. *
  98. * @var integer
  99. * @access private
  100. */
  101. var $debugLevel = 9;
  102. /**
  103. * set schema version
  104. *
  105. * @var string
  106. * @access public
  107. */
  108. var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
  109. /**
  110. * charset encoding for outgoing messages
  111. *
  112. * @var string
  113. * @access public
  114. */
  115. //var $soap_defencoding = 'ISO-8859-1';
  116. var $soap_defencoding = 'UTF-8';
  117. /**
  118. * namespaces in an array of prefix => uri
  119. *
  120. * this is "seeded" by a set of constants, but it may be altered by code
  121. *
  122. * @var array
  123. * @access public
  124. */
  125. var $namespaces = array(
  126. 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
  127. 'xsd' => 'http://www.w3.org/2001/XMLSchema',
  128. 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  129. 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
  130. );
  131. /**
  132. * namespaces used in the current context, e.g. during serialization
  133. *
  134. * @var array
  135. * @access private
  136. */
  137. var $usedNamespaces = array();
  138. /**
  139. * XML Schema types in an array of uri => (array of xml type => php type)
  140. * is this legacy yet?
  141. * no, this is used by the xmlschema class to verify type => namespace mappings.
  142. * @var array
  143. * @access public
  144. */
  145. var $typemap = array(
  146. 'http://www.w3.org/2001/XMLSchema' => array(
  147. 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
  148. 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
  149. 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
  150. // abstract "any" types
  151. 'anyType'=>'string','anySimpleType'=>'string',
  152. // derived datatypes
  153. 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
  154. 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
  155. 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
  156. 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
  157. 'http://www.w3.org/2000/10/XMLSchema' => array(
  158. 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
  159. 'float'=>'double','dateTime'=>'string',
  160. 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
  161. 'http://www.w3.org/1999/XMLSchema' => array(
  162. 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
  163. 'float'=>'double','dateTime'=>'string',
  164. 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
  165. 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
  166. 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
  167. 'http://xml.apache.org/xml-soap' => array('Map')
  168. );
  169. /**
  170. * XML entities to convert
  171. *
  172. * @var array
  173. * @access public
  174. * @deprecated
  175. * @see expandEntities
  176. */
  177. var $xmlEntities = array('quot' => '"','amp' => '&',
  178. 'lt' => '<','gt' => '>','apos' => "'");
  179. /**
  180. * constructor
  181. *
  182. * @access public
  183. */
  184. function nusoap_base() {
  185. $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
  186. }
  187. /**
  188. * gets the global debug level, which applies to future instances
  189. *
  190. * @return integer Debug level 0-9, where 0 turns off
  191. * @access public
  192. */
  193. function getGlobalDebugLevel() {
  194. return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
  195. }
  196. /**
  197. * sets the global debug level, which applies to future instances
  198. *
  199. * @param int $level Debug level 0-9, where 0 turns off
  200. * @access public
  201. */
  202. function setGlobalDebugLevel($level) {
  203. $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;
  204. }
  205. /**
  206. * gets the debug level for this instance
  207. *
  208. * @return int Debug level 0-9, where 0 turns off
  209. * @access public
  210. */
  211. function getDebugLevel() {
  212. return $this->debugLevel;
  213. }
  214. /**
  215. * sets the debug level for this instance
  216. *
  217. * @param int $level Debug level 0-9, where 0 turns off
  218. * @access public
  219. */
  220. function setDebugLevel($level) {
  221. $this->debugLevel = $level;
  222. }
  223. /**
  224. * adds debug data to the instance debug string with formatting
  225. *
  226. * @param string $string debug data
  227. * @access private
  228. */
  229. function debug($string){
  230. if ($this->debugLevel > 0) {
  231. $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
  232. }
  233. }
  234. /**
  235. * adds debug data to the instance debug string without formatting
  236. *
  237. * @param string $string debug data
  238. * @access public
  239. */
  240. function appendDebug($string){
  241. if ($this->debugLevel > 0) {
  242. // it would be nice to use a memory stream here to use
  243. // memory more efficiently
  244. global $soap_log;
  245. $soap_log->debug($string);
  246. $this->debug_str .= $string;
  247. }
  248. }
  249. /**
  250. * clears the current debug data for this instance
  251. *
  252. * @access public
  253. */
  254. function clearDebug() {
  255. // it would be nice to use a memory stream here to use
  256. // memory more efficiently
  257. $this->debug_str = '';
  258. }
  259. /**
  260. * gets the current debug data for this instance
  261. *
  262. * @return debug data
  263. * @access public
  264. */
  265. function &getDebug() {
  266. // it would be nice to use a memory stream here to use
  267. // memory more efficiently
  268. return $this->debug_str;
  269. }
  270. /**
  271. * gets the current debug data for this instance as an XML comment
  272. * this may change the contents of the debug data
  273. *
  274. * @return debug data as an XML comment
  275. * @access public
  276. */
  277. function &getDebugAsXMLComment() {
  278. // it would be nice to use a memory stream here to use
  279. // memory more efficiently
  280. while (strpos($this->debug_str, '--')) {
  281. $this->debug_str = str_replace('--', '- -', $this->debug_str);
  282. }
  283. return "<!--\n" . $this->debug_str . "\n-->";
  284. }
  285. /**
  286. * expands entities, e.g. changes '<' to '&lt;'.
  287. *
  288. * @param string $val The string in which to expand entities.
  289. * @access private
  290. */
  291. function expandEntities($val) {
  292. if ($this->charencoding) {
  293. $val = str_replace('&', '&amp;', $val);
  294. $val = str_replace("'", '&apos;', $val);
  295. $val = str_replace('"', '&quot;', $val);
  296. $val = str_replace('<', '&lt;', $val);
  297. $val = str_replace('>', '&gt;', $val);
  298. }
  299. return $val;
  300. }
  301. /**
  302. * returns error string if present
  303. *
  304. * @return mixed error string or false
  305. * @access public
  306. */
  307. function getError(){
  308. if($this->error_str != ''){
  309. return $this->error_str;
  310. }
  311. return false;
  312. }
  313. /**
  314. * sets error string
  315. *
  316. * @return boolean $string error string
  317. * @access private
  318. */
  319. function setError($str){
  320. $this->error_str = $str;
  321. }
  322. /**
  323. * detect if array is a simple array or a struct (associative array)
  324. *
  325. * @param mixed $val The PHP array
  326. * @return string (arraySimple|arrayStruct)
  327. * @access private
  328. */
  329. function isArraySimpleOrStruct($val) {
  330. $keyList = array_keys($val);
  331. foreach ($keyList as $keyListValue) {
  332. if (!is_int($keyListValue)) {
  333. return 'arrayStruct';
  334. }
  335. }
  336. return 'arraySimple';
  337. }
  338. /**
  339. * serializes PHP values in accordance w/ section 5. Type information is
  340. * not serialized if $use == 'literal'.
  341. *
  342. * @param mixed $val The value to serialize
  343. * @param string $name The name (local part) of the XML element
  344. * @param string $type The XML schema type (local part) for the element
  345. * @param string $name_ns The namespace for the name of the XML element
  346. * @param string $type_ns The namespace for the type of the element
  347. * @param array $attributes The attributes to serialize as name=>value pairs
  348. * @param string $use The WSDL "use" (encoded|literal)
  349. * @return string The serialized element, possibly with child elements
  350. * @access public
  351. */
  352. function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
  353. $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use");
  354. $this->appendDebug('value=' . $this->varDump($val));
  355. $this->appendDebug('attributes=' . $this->varDump($attributes));
  356. if(is_object($val) && get_class($val) == 'soapval'){
  357. return $val->serialize($use);
  358. }
  359. // force valid name if necessary
  360. if (is_numeric($name)) {
  361. $name = '__numeric_' . $name;
  362. } elseif (! $name) {
  363. $name = 'noname';
  364. }
  365. // if name has ns, add ns prefix to name
  366. $xmlns = '';
  367. if($name_ns){
  368. $prefix = 'nu'.rand(1000,9999);
  369. $name = $prefix.':'.$name;
  370. $xmlns .= " xmlns:$prefix=\"$name_ns\"";
  371. }
  372. // if type is prefixed, create type prefix
  373. if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
  374. // need to fix this. shouldn't default to xsd if no ns specified
  375. // w/o checking against typemap
  376. $type_prefix = 'xsd';
  377. } elseif($type_ns){
  378. $type_prefix = 'ns'.rand(1000,9999);
  379. $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
  380. }
  381. // serialize attributes if present
  382. $atts = '';
  383. if($attributes){
  384. foreach($attributes as $k => $v){
  385. $atts .= " $k=\"".$this->expandEntities($v).'"';
  386. }
  387. }
  388. // serialize null value
  389. if (is_null($val)) {
  390. if ($use == 'literal') {
  391. // TODO: depends on minOccurs
  392. return "<$name$xmlns $atts/>";
  393. } else {
  394. if (isset($type) && isset($type_prefix)) {
  395. $type_str = " xsi:type=\"$type_prefix:$type\"";
  396. } else {
  397. $type_str = '';
  398. }
  399. return "<$name$xmlns$type_str $atts xsi:nil=\"true\"/>";
  400. }
  401. }
  402. // serialize if an xsd built-in primitive type
  403. if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
  404. if (is_bool($val)) {
  405. if ($type == 'boolean') {
  406. $val = $val ? 'true' : 'false';
  407. } elseif (! $val) {
  408. $val = 0;
  409. }
  410. } else if (is_string($val)) {
  411. $val = $this->expandEntities($val);
  412. }
  413. if ($use == 'literal') {
  414. return "<$name$xmlns $atts>$val</$name>";
  415. } else {
  416. return "<$name$xmlns $atts xsi:type=\"xsd:$type\">$val</$name>";
  417. }
  418. }
  419. // detect type and serialize
  420. $xml = '';
  421. switch(true) {
  422. case (is_bool($val) || $type == 'boolean'):
  423. if ($type == 'boolean') {
  424. $val = $val ? 'true' : 'false';
  425. } elseif (! $val) {
  426. $val = 0;
  427. }
  428. if ($use == 'literal') {
  429. $xml .= "<$name$xmlns $atts>$val</$name>";
  430. } else {
  431. $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
  432. }
  433. break;
  434. case (is_int($val) || is_long($val) || $type == 'int'):
  435. if ($use == 'literal') {
  436. $xml .= "<$name$xmlns $atts>$val</$name>";
  437. } else {
  438. $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
  439. }
  440. break;
  441. case (is_float($val)|| is_double($val) || $type == 'float'):
  442. if ($use == 'literal') {
  443. $xml .= "<$name$xmlns $atts>$val</$name>";
  444. } else {
  445. $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
  446. }
  447. break;
  448. case (is_string($val) || $type == 'string'):
  449. $val = $this->expandEntities($val);
  450. if ($use == 'literal') {
  451. $xml .= "<$name$xmlns $atts>$val</$name>";
  452. } else {
  453. $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
  454. }
  455. break;
  456. case is_object($val):
  457. if (! $name) {
  458. $name = get_class($val);
  459. $this->debug("In serialize_val, used class name $name as element name");
  460. } else {
  461. $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
  462. }
  463. foreach(get_object_vars($val) as $k => $v){
  464. $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
  465. }
  466. $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>';
  467. break;
  468. break;
  469. case (is_array($val) || $type):
  470. // detect if struct or array
  471. $valueType = $this->isArraySimpleOrStruct($val);
  472. if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
  473. $i = 0;
  474. if(is_array($val) && count($val)> 0){
  475. foreach($val as $v){
  476. if(is_object($v) && get_class($v) == 'soapval'){
  477. $tt_ns = $v->type_ns;
  478. $tt = $v->type;
  479. } elseif (is_array($v)) {
  480. $tt = $this->isArraySimpleOrStruct($v);
  481. } else {
  482. $tt = gettype($v);
  483. }
  484. $array_types[$tt] = 1;
  485. // TODO: for literal, the name should be $name
  486. $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
  487. ++$i;
  488. }
  489. if(count($array_types) > 1){
  490. $array_typename = 'xsd:anyType';
  491. } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
  492. if ($tt == 'integer') {
  493. $tt = 'int';
  494. }
  495. $array_typename = 'xsd:'.$tt;
  496. } elseif(isset($tt) && $tt == 'arraySimple'){
  497. $array_typename = 'SOAP-ENC:Array';
  498. } elseif(isset($tt) && $tt == 'arrayStruct'){
  499. $array_typename = 'unnamed_struct_use_soapval';
  500. } else {
  501. // if type is prefixed, create type prefix
  502. if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
  503. $array_typename = 'xsd:' . $tt;
  504. } elseif ($tt_ns) {
  505. $tt_prefix = 'ns' . rand(1000, 9999);
  506. $array_typename = "$tt_prefix:$tt";
  507. $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
  508. } else {
  509. $array_typename = $tt;
  510. }
  511. }
  512. $array_type = $i;
  513. if ($use == 'literal') {
  514. $type_str = '';
  515. } else if (isset($type) && isset($type_prefix)) {
  516. $type_str = " xsi:type=\"$type_prefix:$type\"";
  517. } else {
  518. $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
  519. }
  520. // empty array
  521. } else {
  522. if ($use == 'literal') {
  523. $type_str = '';
  524. } else if (isset($type) && isset($type_prefix)) {
  525. $type_str = " xsi:type=\"$type_prefix:$type\"";
  526. } else {
  527. $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
  528. }
  529. }
  530. // TODO: for array in literal, there is no wrapper here
  531. $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
  532. } else {
  533. // got a struct
  534. if(isset($type) && isset($type_prefix)){
  535. $type_str = " xsi:type=\"$type_prefix:$type\"";
  536. } else {
  537. $type_str = '';
  538. }
  539. if ($use == 'literal') {
  540. $xml .= "<$name$xmlns $atts>";
  541. } else {
  542. $xml .= "<$name$xmlns$type_str$atts>";
  543. }
  544. foreach($val as $k => $v){
  545. // Apache Map
  546. if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
  547. $xml .= '<item>';
  548. $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
  549. $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
  550. $xml .= '</item>';
  551. } else {
  552. $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
  553. }
  554. }
  555. $xml .= "</$name>";
  556. }
  557. break;
  558. default:
  559. $xml .= 'not detected, got '.gettype($val).' for '.$val;
  560. break;
  561. }
  562. return $xml;
  563. }
  564. /**
  565. * serializes a message
  566. *
  567. * @param string $body the XML of the SOAP body
  568. * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers
  569. * @param array $namespaces optional the namespaces used in generating the body and headers
  570. * @param string $style optional (rpc|document)
  571. * @param string $use optional (encoded|literal)
  572. * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
  573. * @return string the message
  574. * @access public
  575. */
  576. function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
  577. // TODO: add an option to automatically run utf8_encode on $body and $headers
  578. // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
  579. // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
  580. $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
  581. $this->debug("headers:");
  582. $this->appendDebug($this->varDump($headers));
  583. $this->debug("namespaces:");
  584. $this->appendDebug($this->varDump($namespaces));
  585. // serialize namespaces
  586. $ns_string = '';
  587. foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
  588. $ns_string .= " xmlns:$k=\"$v\"";
  589. }
  590. if($encodingStyle) {
  591. $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
  592. }
  593. // serialize headers
  594. if($headers){
  595. if (is_array($headers)) {
  596. $xml = '';
  597. foreach ($headers as $header) {
  598. $xml .= $this->serialize_val($header, false, false, false, false, false, $use);
  599. }
  600. $headers = $xml;
  601. $this->debug("In serializeEnvelope, serialzied array of headers to $headers");
  602. }
  603. $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
  604. }
  605. // serialize envelope
  606. return
  607. '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
  608. '<SOAP-ENV:Envelope'.$ns_string.">".
  609. $headers.
  610. "<SOAP-ENV:Body>".
  611. $body.
  612. "</SOAP-ENV:Body>".
  613. "</SOAP-ENV:Envelope>";
  614. }
  615. /**
  616. * formats a string to be inserted into an HTML stream
  617. *
  618. * @param string $str The string to format
  619. * @return string The formatted string
  620. * @access public
  621. * @deprecated
  622. */
  623. function formatDump($str){
  624. $str = htmlspecialchars($str);
  625. return nl2br($str);
  626. }
  627. /**
  628. * contracts (changes namespace to prefix) a qualified name
  629. *
  630. * @param string $qname qname
  631. * @return string contracted qname
  632. * @access private
  633. */
  634. function contractQname($qname){
  635. // get element namespace
  636. //$this->xdebug("Contract $qname");
  637. if (strrpos($qname, ':')) {
  638. // get unqualified name
  639. $name = substr($qname, strrpos($qname, ':') + 1);
  640. // get ns
  641. $ns = substr($qname, 0, strrpos($qname, ':'));
  642. $p = $this->getPrefixFromNamespace($ns);
  643. if ($p) {
  644. return $p . ':' . $name;
  645. }
  646. return $qname;
  647. } else {
  648. return $qname;
  649. }
  650. }
  651. /**
  652. * expands (changes prefix to namespace) a qualified name
  653. *
  654. * @param string $string qname
  655. * @return string expanded qname
  656. * @access private
  657. */
  658. function expandQname($qname){
  659. // get element prefix
  660. if(strpos($qname,':') && !ereg('^http://',$qname)){
  661. // get unqualified name
  662. $name = substr(strstr($qname,':'),1);
  663. // get ns prefix
  664. $prefix = substr($qname,0,strpos($qname,':'));
  665. if(isset($this->namespaces[$prefix])){
  666. return $this->namespaces[$prefix].':'.$name;
  667. } else {
  668. return $qname;
  669. }
  670. } else {
  671. return $qname;
  672. }
  673. }
  674. /**
  675. * returns the local part of a prefixed string
  676. * returns the original string, if not prefixed
  677. *
  678. * @param string $str The prefixed string
  679. * @return string The local part
  680. * @access public
  681. */
  682. function getLocalPart($str){
  683. if($sstr = strrchr($str,':')){
  684. // get unqualified name
  685. return substr( $sstr, 1 );
  686. } else {
  687. return $str;
  688. }
  689. }
  690. /**
  691. * returns the prefix part of a prefixed string
  692. * returns false, if not prefixed
  693. *
  694. * @param string $str The prefixed string
  695. * @return mixed The prefix or false if there is no prefix
  696. * @access public
  697. */
  698. function getPrefix($str){
  699. if($pos = strrpos($str,':')){
  700. // get prefix
  701. return substr($str,0,$pos);
  702. }
  703. return false;
  704. }
  705. /**
  706. * pass it a prefix, it returns a namespace
  707. *
  708. * @param string $prefix The prefix
  709. * @return mixed The namespace, false if no namespace has the specified prefix
  710. * @access public
  711. */
  712. function getNamespaceFromPrefix($prefix){
  713. if (isset($this->namespaces[$prefix])) {
  714. return $this->namespaces[$prefix];
  715. }
  716. //$this->setError("No namespace registered for prefix '$prefix'");
  717. return false;
  718. }
  719. /**
  720. * returns the prefix for a given namespace (or prefix)
  721. * or false if no prefixes registered for the given namespace
  722. *
  723. * @param string $ns The namespace
  724. * @return mixed The prefix, false if the namespace has no prefixes
  725. * @access public
  726. */
  727. function getPrefixFromNamespace($ns) {
  728. foreach ($this->namespaces as $p => $n) {
  729. if ($ns == $n || $ns == $p) {
  730. $this->usedNamespaces[$p] = $n;
  731. return $p;
  732. }
  733. }
  734. return false;
  735. }
  736. /**
  737. * returns the time in ODBC canonical form with microseconds
  738. *
  739. * @return string The time in ODBC canonical form with microseconds
  740. * @access public
  741. */
  742. function getmicrotime() {
  743. if (function_exists('gettimeofday')) {
  744. $tod = gettimeofday();
  745. $sec = $tod['sec'];
  746. $usec = $tod['usec'];
  747. } else {
  748. $sec = time();
  749. $usec = 0;
  750. }
  751. return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
  752. }
  753. /**
  754. * Returns a string with the output of var_dump
  755. *
  756. * @param mixed $data The variable to var_dump
  757. * @return string The output of var_dump
  758. * @access public
  759. */
  760. function varDump($data) {
  761. /** To increase performance we have commented this. */
  762. return 'varDump';
  763. }
  764. }
  765. // XML Schema Datatype Helper Functions
  766. //xsd:dateTime helpers
  767. /**
  768. * convert unix timestamp to ISO 8601 compliant date string
  769. *
  770. * @param string $timestamp Unix time stamp
  771. * @access public
  772. */
  773. function timestamp_to_iso8601($timestamp,$utc=true){
  774. $datestr = date('Y-m-d\TH:i:sO',$timestamp);
  775. if($utc){
  776. $eregStr =
  777. '([0-9]{4})-'. // centuries & years CCYY-
  778. '([0-9]{2})-'. // months MM-
  779. '([0-9]{2})'. // days DD
  780. 'T'. // separator T
  781. '([0-9]{2}):'. // hours hh:
  782. '([0-9]{2}):'. // minutes mm:
  783. '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
  784. '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
  785. if(ereg($eregStr,$datestr,$regs)){
  786. return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
  787. }
  788. return false;
  789. } else {
  790. return $datestr;
  791. }
  792. }
  793. /**
  794. * convert ISO 8601 compliant date string to unix timestamp
  795. *
  796. * @param string $datestr ISO 8601 compliant date string
  797. * @access public
  798. */
  799. function iso8601_to_timestamp($datestr){
  800. $eregStr =
  801. '([0-9]{4})-'. // centuries & years CCYY-
  802. '([0-9]{2})-'. // months MM-
  803. '([0-9]{2})'. // days DD
  804. 'T'. // separator T
  805. '([0-9]{2}):'. // hours hh:
  806. '([0-9]{2}):'. // minutes mm:
  807. '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
  808. '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
  809. if(ereg($eregStr,$datestr,$regs)){
  810. // not utc
  811. if($regs[8] != 'Z'){
  812. $op = substr($regs[8],0,1);
  813. $h = substr($regs[8],1,2);
  814. $m = substr($regs[8],strlen($regs[8])-2,2);
  815. if($op == '-'){
  816. $regs[4] = $regs[4] + $h;
  817. $regs[5] = $regs[5] + $m;
  818. } elseif($op == '+'){
  819. $regs[4] = $regs[4] - $h;
  820. $regs[5] = $regs[5] - $m;
  821. }
  822. }
  823. return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
  824. } else {
  825. return false;
  826. }
  827. }
  828. /**
  829. * sleeps some number of microseconds
  830. *
  831. * @param string $usec the number of microseconds to sleep
  832. * @access public
  833. * @deprecated
  834. */
  835. function usleepWindows($usec)
  836. {
  837. $start = gettimeofday();
  838. do
  839. {
  840. $stop = gettimeofday();
  841. $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
  842. + $stop['usec'] - $start['usec'];
  843. }
  844. while ($timePassed < $usec);
  845. }
  846. ?><?php
  847. /**
  848. * Contains information for a SOAP fault.
  849. * Mainly used for returning faults from deployed functions
  850. * in a server instance.
  851. * @author Dietrich Ayala <dietrich@ganx4.com>
  852. * @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
  853. * @access public
  854. */
  855. class soap_fault extends nusoap_base {
  856. /**
  857. * The fault code (client|server)
  858. * @var string
  859. * @access private
  860. */
  861. var $faultcode;
  862. /**
  863. * The fault actor
  864. * @var string
  865. * @access private
  866. */
  867. var $faultactor;
  868. /**
  869. * The fault string, a description of the fault
  870. * @var string
  871. * @access private
  872. */
  873. var $faultstring;
  874. /**
  875. * The fault detail, typically a string or array of string
  876. * @var mixed
  877. * @access private
  878. */
  879. var $faultdetail;
  880. /**
  881. * constructor
  882. *
  883. * @param string $faultcode (client | server)
  884. * @param string $faultactor only used when msg routed between multiple actors
  885. * @param string $faultstring human readable error message
  886. * @param mixed $faultdetail detail, typically a string or array of string
  887. */
  888. function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
  889. parent::nusoap_base();
  890. $this->faultcode = $faultcode;
  891. $this->faultactor = $faultactor;
  892. $this->faultstring = $faultstring;
  893. $this->faultdetail = $faultdetail;
  894. }
  895. /**
  896. * serialize a fault
  897. *
  898. * @return string The serialization of the fault instance.
  899. * @access public
  900. */
  901. function serialize(){
  902. $ns_string = '';
  903. foreach($this->namespaces as $k => $v){
  904. $ns_string .= "\n xmlns:$k=\"$v\"";
  905. }
  906. $return_msg =
  907. '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
  908. '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
  909. '<SOAP-ENV:Body>'.
  910. '<SOAP-ENV:Fault>'.
  911. $this->serialize_val($this->faultcode, 'faultcode').
  912. $this->serialize_val($this->faultactor, 'faultactor').
  913. $this->serialize_val($this->faultstring, 'faultstring').
  914. $this->serialize_val($this->faultdetail, 'detail').
  915. '</SOAP-ENV:Fault>'.
  916. '</SOAP-ENV:Body>'.
  917. '</SOAP-ENV:Envelope>';
  918. return $return_msg;
  919. }
  920. }
  921. ?><?php
  922. /**
  923. * parses an XML Schema, allows access to it's data, other utility methods
  924. * no validation... yet.
  925. * very experimental and limited. As is discussed on XML-DEV, I'm one of the people
  926. * that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty
  927. * tutorials I refer to :)
  928. *
  929. * @author Dietrich Ayala <dietrich@ganx4.com>
  930. * @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
  931. * @access public
  932. */
  933. class XMLSchema extends nusoap_base {
  934. // files
  935. var $schema = '';
  936. var $xml = '';
  937. // namespaces
  938. var $enclosingNamespaces;
  939. // schema info
  940. var $schemaInfo = array();
  941. var $schemaTargetNamespace = '';
  942. // types, elements, attributes defined by the schema
  943. var $attributes = array();
  944. var $complexTypes = array();
  945. var $complexTypeStack = array();
  946. var $currentComplexType = null;
  947. var $elements = array();
  948. var $elementStack = array();
  949. var $currentElement = null;
  950. var $simpleTypes = array();
  951. var $simpleTypeStack = array();
  952. var $currentSimpleType = null;
  953. // imports
  954. var $imports = array();
  955. // parser vars
  956. var $parser;
  957. var $position = 0;
  958. var $depth = 0;
  959. var $depth_array = array();
  960. var $message = array();
  961. var $defaultNamespace = array();
  962. /**
  963. * constructor
  964. *
  965. * @param string $schema schema document URI
  966. * @param string $xml xml document URI
  967. * @param string $namespaces namespaces defined in enclosing XML
  968. * @access public
  969. */
  970. function XMLSchema($schema='',$xml='',$namespaces=array()){
  971. parent::nusoap_base();
  972. $this->debug('xmlschema class instantiated, inside constructor');
  973. // files
  974. $this->schema = $schema;
  975. $this->xml = $xml;
  976. // namespaces
  977. $this->enclosingNamespaces = $namespaces;
  978. $this->namespaces = array_merge($this->namespaces, $namespaces);
  979. // parse schema file
  980. if($schema != ''){
  981. $this->debug('initial schema file: '.$schema);
  982. $this->parseFile($schema, 'schema');
  983. }
  984. // parse xml file
  985. if($xml != ''){
  986. $this->debug('initial xml file: '.$xml);
  987. $this->parseFile($xml, 'xml');
  988. }
  989. }
  990. /**
  991. * parse an XML file
  992. *
  993. * @param string $xml, path/URL to XML file
  994. * @param string $type, (schema | xml)
  995. * @return boolean
  996. * @access public
  997. */
  998. function parseFile($xml,$type){
  999. // parse xml file
  1000. if($xml != ""){
  1001. $xmlStr = @join("",@file($xml));
  1002. if($xmlStr == ""){
  1003. $msg = 'Error reading XML from '.$xml;
  1004. $this->setError($msg);
  1005. $this->debug($msg);
  1006. return false;
  1007. } else {
  1008. $this->debug("parsing $xml");
  1009. $this->parseString($xmlStr,$type);
  1010. $this->debug("done parsing $xml");
  1011. return true;
  1012. }
  1013. }
  1014. return false;
  1015. }
  1016. /**
  1017. * parse an XML string
  1018. *
  1019. * @param string $xml path or URL
  1020. * @param string $type, (schema|xml)
  1021. * @access private
  1022. */
  1023. function parseString($xml,$type){
  1024. // parse xml string
  1025. if($xml != ""){
  1026. // Create an XML parser.
  1027. $this->parser = xml_parser_create();
  1028. // Set the options for parsing the XML data.
  1029. xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
  1030. // Set the object for the parser.
  1031. xml_set_object($this->parser, $this);
  1032. // Set the element handlers for the parser.
  1033. if($type == "schema"){
  1034. xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
  1035. xml_set_character_data_handler($this->parser,'schemaCharacterData');
  1036. } elseif($type == "xml"){
  1037. xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
  1038. xml_set_character_data_handler($this->parser,'xmlCharacterData');
  1039. }
  1040. // Parse the XML file.
  1041. if(!xml_parse($this->parser,$xml,true)){
  1042. // Display an error message.
  1043. $errstr = sprintf('XML error parsing XML schema on line %d: %s',
  1044. xml_get_current_line_number($this->parser),
  1045. xml_error_string(xml_get_error_code($this->parser))
  1046. );
  1047. $this->debug($errstr);
  1048. $this->debug("XML payload:\n" . $xml);
  1049. $this->setError($errstr);
  1050. }
  1051. xml_parser_free($this->parser);
  1052. } else{
  1053. $this->debug('no xml passed to parseString()!!');
  1054. $this->setError('no xml passed to parseString()!!');
  1055. }
  1056. }
  1057. /**
  1058. * start-element handler
  1059. *
  1060. * @param string $parser XML parser object
  1061. * @param string $name element name
  1062. * @param string $attrs associative array of attributes
  1063. * @access private
  1064. */
  1065. function schemaStartElement($parser, $name, $attrs) {
  1066. // position in the total number of elements, starting from 0
  1067. $pos = $this->position++;
  1068. $depth = $this->depth++;
  1069. // set self as current value for this depth
  1070. $this->depth_array[$depth] = $pos;
  1071. $this->message[$pos] = array('cdata' => '');
  1072. if ($depth > 0) {
  1073. $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
  1074. } else {
  1075. $this->defaultNamespace[$pos] = false;
  1076. }
  1077. // get element prefix
  1078. if($prefix = $this->getPrefix($name)){
  1079. // get unqualified name
  1080. $name = $this->getLocalPart($name);
  1081. } else {
  1082. $prefix = '';
  1083. }
  1084. // loop thru attributes, expanding, and registering namespace declarations
  1085. if(count($attrs) > 0){
  1086. foreach($attrs as $k => $v){
  1087. // if ns declarations, add to class level array of valid namespaces
  1088. if(ereg("^xmlns",$k)){
  1089. //$this->xdebug("$k: $v");
  1090. //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
  1091. if($ns_prefix = substr(strrchr($k,':'),1)){
  1092. //$this->xdebug("Add namespace[$ns_prefix] = $v");
  1093. $this->namespaces[$ns_prefix] = $v;
  1094. } else {
  1095. $this->defaultNamespace[$pos] = $v;
  1096. if (! $this->getPrefixFromNamespace($v)) {
  1097. $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
  1098. }
  1099. }
  1100. if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
  1101. $this->XMLSchemaVersion = $v;
  1102. $this->namespaces['xsi'] = $v.'-instance';
  1103. }
  1104. }
  1105. }
  1106. foreach($attrs as $k => $v){
  1107. // expand each attribute
  1108. $k = strpos($k,':') ? $this->expandQname($k) : $k;
  1109. $v = strpos($v,':') ? $this->expandQname($v) : $v;
  1110. $eAttrs[$k] = $v;
  1111. }
  1112. $attrs = $eAttrs;
  1113. } else {
  1114. $attrs = array();
  1115. }
  1116. // find status, register data
  1117. switch($name){
  1118. case 'all': // (optional) compositor content for a complexType
  1119. case 'choice':
  1120. case 'group':
  1121. case 'sequence':
  1122. //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
  1123. $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
  1124. //if($name == 'all' || $name == 'sequence'){
  1125. // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
  1126. //}
  1127. break;
  1128. case 'attribute': // complexType attribute
  1129. //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
  1130. $this->xdebug("parsing attribute:");
  1131. $this->appendDebug($this->varDump($attrs));
  1132. if (!isset($attrs['form'])) {
  1133. $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
  1134. }
  1135. if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
  1136. $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
  1137. if (!strpos($v, ':')) {
  1138. // no namespace in arrayType attribute value...
  1139. if ($this->defaultNamespace[$pos]) {
  1140. // ...so use the default
  1141. $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
  1142. }
  1143. }
  1144. }
  1145. if(isset($attrs['name'])){
  1146. $this->attributes[$attrs['name']] = $attrs;
  1147. $aname = $attrs['name'];
  1148. } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
  1149. if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
  1150. $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
  1151. } else {
  1152. $aname = '';
  1153. }
  1154. } elseif(isset($attrs['ref'])){
  1155. $aname = $attrs['ref'];
  1156. $this->attributes[$attrs['ref']] = $attrs;
  1157. }
  1158. if($this->currentComplexType){ // This should *always* be
  1159. $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
  1160. }
  1161. // arrayType attribute
  1162. if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
  1163. $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
  1164. $prefix = $this->getPrefix($aname);
  1165. if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
  1166. $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
  1167. } else {
  1168. $v = '';
  1169. }
  1170. if(strpos($v,'[,]')){
  1171. $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
  1172. }
  1173. $v = substr($v,0,strpos($v,'[')); // clip the []
  1174. if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
  1175. $v = $this->XMLSchemaVersion.':'.$v;
  1176. }
  1177. $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
  1178. }
  1179. break;
  1180. case 'complexContent': // (optional) content for a complexType
  1181. break;
  1182. case 'complexType':
  1183. array_push($this->complexTypeStack, $this->currentComplexType);
  1184. if(isset($attrs['name'])){
  1185. $this->xdebug('processing named complexType '.$attrs['name']);
  1186. //$this->currentElement = false;
  1187. $this->currentComplexType = $attrs['name'];
  1188. $this->complexTypes[$this->currentComplexType] = $attrs;
  1189. $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
  1190. // This is for constructs like
  1191. // <complexType name="ListOfString" base="soap:Array">
  1192. // <sequence>
  1193. // <element name="string" type="xsd:string"
  1194. // minOccurs="0" maxOccurs="unbounded" />
  1195. // </sequence>
  1196. // </complexType>
  1197. if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
  1198. $this->xdebug('complexType is unusual array');
  1199. $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
  1200. } else {
  1201. $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
  1202. }
  1203. }else{
  1204. $this->xdebug('processing unnamed complexType for element '.$this->currentElement);
  1205. $this->currentComplexType = $this->currentElement . '_ContainedType';
  1206. //$this->currentElement = false;
  1207. $this->complexTypes[$this->currentComplexType] = $attrs;
  1208. $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
  1209. // This is for constructs like
  1210. // <complexType name="ListOfString" base="soap:Array">
  1211. // <sequence>
  1212. // <element name="string" type="xsd:string"
  1213. // minOccurs="0" maxOccurs="unbounded" />
  1214. // </sequence>
  1215. // </complexType>
  1216. if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
  1217. $this->xdebug('complexType is unusual array');
  1218. $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
  1219. } else {
  1220. $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
  1221. }
  1222. }
  1223. break;
  1224. case 'element':
  1225. array_push($this->elementStack, $this->currentElement);
  1226. // elements defined as part of a complex type should
  1227. // not really be added to $this->elements, but for some
  1228. // reason, they are
  1229. if (!isset($attrs['form'])) {
  1230. $attrs['form'] = $this->schemaInfo['elementFormDefault'];
  1231. }
  1232. if(isset($attrs['type'])){
  1233. $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
  1234. if (! $this->getPrefix($attrs['type'])) {
  1235. if ($this->defaultNamespace[$pos]) {
  1236. $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
  1237. $this->xdebug('used default namespace to make type ' . $attrs['type']);
  1238. }
  1239. }
  1240. // This is for constructs like
  1241. // <complexType name="ListOfString" base="soap:Array">
  1242. // <sequence>
  1243. // <element name="string" type="xsd:string"
  1244. // minOccurs="0" maxOccurs="unbounded" />
  1245. // </sequence>
  1246. // </complexType>
  1247. if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
  1248. $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
  1249. $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
  1250. }
  1251. $this->currentElement = $attrs['name'];
  1252. $this->elements[ $attrs['name'] ] = $attrs;
  1253. $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
  1254. $ename = $attrs['name'];
  1255. } elseif(isset($attrs['ref'])){
  1256. $this->xdebug("processing element as ref to ".$attrs['ref']);
  1257. $this->currentElement = "ref to ".$attrs['ref'];
  1258. $ename = $this->getLocalPart($attrs['ref']);
  1259. } else {
  1260. $this->xdebug("processing untyped element ".$attrs['name']);
  1261. $this->currentElement = $attrs['name'];
  1262. $this->elements[ $attrs['name'] ] = $attrs;
  1263. $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
  1264. $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType';
  1265. $this->elements[ $attrs['name'] ]['type'] = $attrs['type'];
  1266. $ename = $attrs['name'];
  1267. }
  1268. if(isset($ename) && $this->currentComplexType){
  1269. $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
  1270. }
  1271. break;
  1272. case 'enumeration': // restriction value list member
  1273. $this->xdebug('enumeration ' . $attrs['value']);
  1274. if ($this->currentSimpleType) {
  1275. $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
  1276. } elseif ($this->currentComplexType) {
  1277. $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
  1278. }
  1279. break;
  1280. case 'extension': // simpleContent or complexContent type extension
  1281. $this->xdebug('extension ' . $attrs['base']);
  1282. if ($this->currentComplexType) {
  1283. $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
  1284. }
  1285. break;
  1286. case 'import':
  1287. if (isset($attrs['schemaLocation'])) {
  1288. //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
  1289. $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
  1290. } else {
  1291. //$this->xdebug('import namespace ' . $attrs['namespace']);
  1292. $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
  1293. if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
  1294. $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
  1295. }
  1296. }
  1297. break;
  1298. case 'list': // simpleType value list
  1299. break;
  1300. case 'restriction': // simpleType, simpleContent or complexContent value restriction
  1301. $this->xdebug('restriction ' . $attrs['base']);
  1302. if($this->currentSimpleType){
  1303. $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
  1304. } elseif($this->currentComplexType){
  1305. $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
  1306. if(strstr($attrs['base'],':') == ':Array'){
  1307. $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
  1308. }
  1309. }
  1310. break;
  1311. case 'schema':
  1312. $this->schemaInfo = $attrs;
  1313. $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
  1314. if (isset($attrs['targetNamespace'])) {
  1315. $this->schemaTargetNamespace = $attrs['targetNamespace'];
  1316. }
  1317. if (!isset($attrs['elementFormDefault'])) {
  1318. $this->schemaInfo['elementFormDefault'] = 'unqualified';
  1319. }
  1320. if (!isset($attrs['attributeFormDefault'])) {
  1321. $this->schemaInfo['attributeFormDefault'] = 'unqualified';
  1322. }
  1323. break;
  1324. case 'simpleContent': // (optional) content for a complexType
  1325. break;
  1326. case 'simpleType':
  1327. array_push($this->simpleTypeStack, $this->currentSimpleType);
  1328. if(isset($attrs['name'])){
  1329. $this->xdebug("processing simpleType for name " . $attrs['name']);
  1330. $this->currentSimpleType = $attrs['name'];
  1331. $this->simpleTypes[ $attrs['name'] ] = $attrs;
  1332. $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
  1333. $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
  1334. } else {
  1335. $this->xdebug('processing unnamed simpleType for element '.$this->currentElement);
  1336. $this->currentSimpleType = $this->currentElement . '_ContainedType';
  1337. //$this->currentElement = false;
  1338. $this->simpleTypes[$this->currentSimpleType] = $attrs;
  1339. $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
  1340. }
  1341. break;
  1342. case 'union': // simpleType type list
  1343. break;
  1344. default:
  1345. //$this->xdebug("do not have anything to do for element $name");
  1346. }
  1347. }
  1348. /**
  1349. * end-element handler
  1350. *
  1351. * @param string $parser XML parser object
  1352. * @param string $name element name
  1353. * @access private
  1354. */
  1355. function schemaEndElement($parser, $name) {
  1356. // bring depth down a notch
  1357. $this->depth--;
  1358. // position of current element is equal to the last value left in depth_array for my depth
  1359. if(isset($this->depth_array[$this->depth])){
  1360. $pos = $this->depth_array[$this->depth];
  1361. }
  1362. // get element prefix
  1363. if ($prefix = $this->getPrefix($name)){
  1364. // get unqualified name
  1365. $name = $this->getLocalPart($name);
  1366. } else {
  1367. $prefix = '';
  1368. }
  1369. // move on...
  1370. if($name == 'complexType'){
  1371. $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
  1372. $this->currentComplexType = array_pop($this->complexTypeStack);
  1373. //$this->currentElement = false;
  1374. }
  1375. if($name == 'element'){
  1376. $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
  1377. $this->currentElement = array_pop($this->elementStack);
  1378. }
  1379. if($name == 'simpleType'){
  1380. $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
  1381. $this->currentSimpleType = array_pop($this->simpleTypeStack);
  1382. }
  1383. }
  1384. /**
  1385. * element content handler
  1386. *
  1387. * @param string $parser XML parser object
  1388. * @param string $data element content
  1389. * @access private
  1390. */
  1391. function schemaCharacterData($parser, $data){
  1392. $pos = $this->depth_array[$this->depth - 1];
  1393. $this->message[$pos]['cdata'] .= $data;
  1394. }
  1395. /**
  1396. * serialize the schema
  1397. *
  1398. * @access public
  1399. */
  1400. function serializeSchema(){
  1401. $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
  1402. $xml = '';
  1403. // imports
  1404. if (sizeof($this->imports) > 0) {
  1405. foreach($this->imports as $ns => $list) {
  1406. foreach ($list as $ii) {
  1407. if ($ii['location'] != '') {
  1408. $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
  1409. } else {
  1410. $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
  1411. }
  1412. }
  1413. }
  1414. }
  1415. // complex types
  1416. foreach($this->complexTypes as $typeName => $attrs){
  1417. $contentStr = '';
  1418. // serialize child elements
  1419. if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
  1420. foreach($attrs['elements'] as $element => $eParts){
  1421. if(isset($eParts['ref'])){
  1422. $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
  1423. } else {
  1424. $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
  1425. foreach ($eParts as $aName => $aValue) {
  1426. // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
  1427. if ($aName != 'name' && $aName != 'type') {
  1428. $contentStr .= " $aName=\"$aValue\"";
  1429. }
  1430. }
  1431. $contentStr .= "/>\n";
  1432. }
  1433. }
  1434. // compositor wraps elements
  1435. if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
  1436. $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n";
  1437. }
  1438. }
  1439. // attributes
  1440. if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
  1441. foreach($attrs['attrs'] as $attr => $aParts){
  1442. $contentStr .= " <$schemaPrefix:attribute";
  1443. foreach ($aParts as $a => $v) {
  1444. if ($a == 'ref' || $a == 'type') {
  1445. $contentStr .= " $a=\"".$this->contractQName($v).'"';
  1446. } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
  1447. $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
  1448. $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
  1449. } else {
  1450. $contentStr .= " $a=\"$v\"";
  1451. }
  1452. }
  1453. $contentStr .= "/>\n";
  1454. }
  1455. }
  1456. // if restriction
  1457. if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
  1458. $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n";
  1459. // complex or simple content
  1460. if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
  1461. $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n";
  1462. }
  1463. }
  1464. // finalize complex type
  1465. if($contentStr != ''){
  1466. $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
  1467. } else {
  1468. $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
  1469. }
  1470. $xml .= $contentStr;
  1471. }
  1472. // simple types
  1473. if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
  1474. foreach($this->simpleTypes as $typeName => $eParts){
  1475. $xml .= " <$schemaPrefix:simpleTyp…

Large files files are truncated, but you can click here to view the full file