PageRenderTime 58ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/gforge/www/soap/nusoap.php

https://github.com/mathieu/fusionforge
PHP | 6413 lines | 4850 code | 226 blank | 1337 comment | 1117 complexity | f82483845de3de70dead88d8d5d0bf05 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, GPL-2.0

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

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

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