class.nusoap_base.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. <?php
  2. /*
  3. $Id: class.nusoap_base.php,v 1.56 2010/04/26 20:15:08 snichol Exp $
  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. The NuSOAP project home is:
  18. http://sourceforge.net/projects/nusoap/
  19. The primary support for NuSOAP is the Help forum on the project home page.
  20. If you have any questions or comments, please email:
  21. Dietrich Ayala
  22. dietrich@ganx4.com
  23. http://dietrich.ganx4.com/nusoap
  24. NuSphere Corporation
  25. http://www.nusphere.com
  26. */
  27. /*
  28. * Some of the standards implmented in whole or part by NuSOAP:
  29. *
  30. * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
  31. * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
  32. * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
  33. * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
  34. * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
  35. * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
  36. * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
  37. * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
  38. * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
  39. */
  40. /* load classes
  41. // necessary classes
  42. require_once('class.soapclient.php');
  43. require_once('class.soap_val.php');
  44. require_once('class.soap_parser.php');
  45. require_once('class.soap_fault.php');
  46. // transport classes
  47. require_once('class.soap_transport_http.php');
  48. // optional add-on classes
  49. require_once('class.xmlschema.php');
  50. require_once('class.wsdl.php');
  51. // server class
  52. require_once('class.soap_server.php');*/
  53. // class variable emulation
  54. // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
  55. $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9;
  56. /**
  57. *
  58. * nusoap_base
  59. *
  60. * @author Dietrich Ayala <dietrich@ganx4.com>
  61. * @author Scott Nichol <snichol@users.sourceforge.net>
  62. * @version $Id: class.nusoap_base.php,v 1.56 2010/04/26 20:15:08 snichol Exp $
  63. * @access public
  64. */
  65. class nusoap_base {
  66. /**
  67. * Identification for HTTP headers.
  68. *
  69. * @var string
  70. * @access private
  71. */
  72. var $title = 'NuSOAP';
  73. /**
  74. * Version for HTTP headers.
  75. *
  76. * @var string
  77. * @access private
  78. */
  79. var $version = '0.9.5';
  80. /**
  81. * CVS revision for HTTP headers.
  82. *
  83. * @var string
  84. * @access private
  85. */
  86. var $revision = '$Revision: 1.56 $';
  87. /**
  88. * Current error string (manipulated by getError/setError)
  89. *
  90. * @var string
  91. * @access private
  92. */
  93. var $error_str = '';
  94. /**
  95. * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
  96. *
  97. * @var string
  98. * @access private
  99. */
  100. var $debug_str = '';
  101. /**
  102. * toggles automatic encoding of special characters as entities
  103. * (should always be true, I think)
  104. *
  105. * @var boolean
  106. * @access private
  107. */
  108. var $charencoding = true;
  109. /**
  110. * the debug level for this instance
  111. *
  112. * @var integer
  113. * @access private
  114. */
  115. var $debugLevel;
  116. /**
  117. * set schema version
  118. *
  119. * @var string
  120. * @access public
  121. */
  122. var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
  123. /**
  124. * charset encoding for outgoing messages
  125. *
  126. * @var string
  127. * @access public
  128. */
  129. var $soap_defencoding = 'ISO-8859-1';
  130. //var $soap_defencoding = 'UTF-8';
  131. /**
  132. * namespaces in an array of prefix => uri
  133. *
  134. * this is "seeded" by a set of constants, but it may be altered by code
  135. *
  136. * @var array
  137. * @access public
  138. */
  139. var $namespaces = array(
  140. 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
  141. 'xsd' => 'http://www.w3.org/2001/XMLSchema',
  142. 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  143. 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
  144. );
  145. /**
  146. * namespaces used in the current context, e.g. during serialization
  147. *
  148. * @var array
  149. * @access private
  150. */
  151. var $usedNamespaces = array();
  152. /**
  153. * XML Schema types in an array of uri => (array of xml type => php type)
  154. * is this legacy yet?
  155. * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
  156. * @var array
  157. * @access public
  158. */
  159. var $typemap = array(
  160. 'http://www.w3.org/2001/XMLSchema' => array(
  161. 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
  162. 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
  163. 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
  164. // abstract "any" types
  165. 'anyType'=>'string','anySimpleType'=>'string',
  166. // derived datatypes
  167. 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
  168. 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
  169. 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
  170. 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
  171. 'http://www.w3.org/2000/10/XMLSchema' => array(
  172. 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
  173. 'float'=>'double','dateTime'=>'string',
  174. 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
  175. 'http://www.w3.org/1999/XMLSchema' => array(
  176. 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
  177. 'float'=>'double','dateTime'=>'string',
  178. 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
  179. 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
  180. 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
  181. 'http://xml.apache.org/xml-soap' => array('Map')
  182. );
  183. /**
  184. * XML entities to convert
  185. *
  186. * @var array
  187. * @access public
  188. * @deprecated
  189. * @see expandEntities
  190. */
  191. var $xmlEntities = array('quot' => '"','amp' => '&',
  192. 'lt' => '<','gt' => '>','apos' => "'");
  193. /**
  194. * constructor
  195. *
  196. * @access public
  197. */
  198. function nusoap_base() {
  199. $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
  200. }
  201. /**
  202. * gets the global debug level, which applies to future instances
  203. *
  204. * @return integer Debug level 0-9, where 0 turns off
  205. * @access public
  206. */
  207. function getGlobalDebugLevel() {
  208. return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
  209. }
  210. /**
  211. * sets the global debug level, which applies to future instances
  212. *
  213. * @param int $level Debug level 0-9, where 0 turns off
  214. * @access public
  215. */
  216. function setGlobalDebugLevel($level) {
  217. $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
  218. }
  219. /**
  220. * gets the debug level for this instance
  221. *
  222. * @return int Debug level 0-9, where 0 turns off
  223. * @access public
  224. */
  225. function getDebugLevel() {
  226. return $this->debugLevel;
  227. }
  228. /**
  229. * sets the debug level for this instance
  230. *
  231. * @param int $level Debug level 0-9, where 0 turns off
  232. * @access public
  233. */
  234. function setDebugLevel($level) {
  235. $this->debugLevel = $level;
  236. }
  237. /**
  238. * adds debug data to the instance debug string with formatting
  239. *
  240. * @param string $string debug data
  241. * @access private
  242. */
  243. function debug($string){
  244. if ($this->debugLevel > 0) {
  245. $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
  246. }
  247. }
  248. /**
  249. * adds debug data to the instance debug string without formatting
  250. *
  251. * @param string $string debug data
  252. * @access public
  253. */
  254. function appendDebug($string){
  255. if ($this->debugLevel > 0) {
  256. // it would be nice to use a memory stream here to use
  257. // memory more efficiently
  258. $this->debug_str .= $string;
  259. }
  260. }
  261. /**
  262. * clears the current debug data for this instance
  263. *
  264. * @access public
  265. */
  266. function clearDebug() {
  267. // it would be nice to use a memory stream here to use
  268. // memory more efficiently
  269. $this->debug_str = '';
  270. }
  271. /**
  272. * gets the current debug data for this instance
  273. *
  274. * @return debug data
  275. * @access public
  276. */
  277. function &getDebug() {
  278. // it would be nice to use a memory stream here to use
  279. // memory more efficiently
  280. return $this->debug_str;
  281. }
  282. /**
  283. * gets the current debug data for this instance as an XML comment
  284. * this may change the contents of the debug data
  285. *
  286. * @return debug data as an XML comment
  287. * @access public
  288. */
  289. function &getDebugAsXMLComment() {
  290. // it would be nice to use a memory stream here to use
  291. // memory more efficiently
  292. while (strpos($this->debug_str, '--')) {
  293. $this->debug_str = str_replace('--', '- -', $this->debug_str);
  294. }
  295. $ret = "<!--\n" . $this->debug_str . "\n-->";
  296. return $ret;
  297. }
  298. /**
  299. * expands entities, e.g. changes '<' to '&lt;'.
  300. *
  301. * @param string $val The string in which to expand entities.
  302. * @access private
  303. */
  304. function expandEntities($val) {
  305. if ($this->charencoding) {
  306. $val = str_replace('&', '&amp;', $val);
  307. $val = str_replace("'", '&apos;', $val);
  308. $val = str_replace('"', '&quot;', $val);
  309. $val = str_replace('<', '&lt;', $val);
  310. $val = str_replace('>', '&gt;', $val);
  311. }
  312. return $val;
  313. }
  314. /**
  315. * returns error string if present
  316. *
  317. * @return mixed error string or false
  318. * @access public
  319. */
  320. function getError(){
  321. if($this->error_str != ''){
  322. return $this->error_str;
  323. }
  324. return false;
  325. }
  326. /**
  327. * sets error string
  328. *
  329. * @return boolean $string error string
  330. * @access private
  331. */
  332. function setError($str){
  333. $this->error_str = $str;
  334. }
  335. /**
  336. * detect if array is a simple array or a struct (associative array)
  337. *
  338. * @param mixed $val The PHP array
  339. * @return string (arraySimple|arrayStruct)
  340. * @access private
  341. */
  342. function isArraySimpleOrStruct($val) {
  343. $keyList = array_keys($val);
  344. foreach ($keyList as $keyListValue) {
  345. if (!is_int($keyListValue)) {
  346. return 'arrayStruct';
  347. }
  348. }
  349. return 'arraySimple';
  350. }
  351. /**
  352. * serializes PHP values in accordance w/ section 5. Type information is
  353. * not serialized if $use == 'literal'.
  354. *
  355. * @param mixed $val The value to serialize
  356. * @param string $name The name (local part) of the XML element
  357. * @param string $type The XML schema type (local part) for the element
  358. * @param string $name_ns The namespace for the name of the XML element
  359. * @param string $type_ns The namespace for the type of the element
  360. * @param array $attributes The attributes to serialize as name=>value pairs
  361. * @param string $use The WSDL "use" (encoded|literal)
  362. * @param boolean $soapval Whether this is called from soapval.
  363. * @return string The serialized element, possibly with child elements
  364. * @access public
  365. */
  366. function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {
  367. $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
  368. $this->appendDebug('value=' . $this->varDump($val));
  369. $this->appendDebug('attributes=' . $this->varDump($attributes));
  370. if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {
  371. $this->debug("serialize_val: serialize soapval");
  372. $xml = $val->serialize($use);
  373. $this->appendDebug($val->getDebug());
  374. $val->clearDebug();
  375. $this->debug("serialize_val of soapval returning $xml");
  376. return $xml;
  377. }
  378. // force valid name if necessary
  379. if (is_numeric($name)) {
  380. $name = '__numeric_' . $name;
  381. } elseif (! $name) {
  382. $name = 'noname';
  383. }
  384. // if name has ns, add ns prefix to name
  385. $xmlns = '';
  386. if($name_ns){
  387. $prefix = 'nu'.rand(1000,9999);
  388. $name = $prefix.':'.$name;
  389. $xmlns .= " xmlns:$prefix=\"$name_ns\"";
  390. }
  391. // if type is prefixed, create type prefix
  392. if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
  393. // need to fix this. shouldn't default to xsd if no ns specified
  394. // w/o checking against typemap
  395. $type_prefix = 'xsd';
  396. } elseif($type_ns){
  397. $type_prefix = 'ns'.rand(1000,9999);
  398. $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
  399. }
  400. // serialize attributes if present
  401. $atts = '';
  402. if($attributes){
  403. foreach($attributes as $k => $v){
  404. $atts .= " $k=\"".$this->expandEntities($v).'"';
  405. }
  406. }
  407. // serialize null value
  408. if (is_null($val)) {
  409. $this->debug("serialize_val: serialize null");
  410. if ($use == 'literal') {
  411. // TODO: depends on minOccurs
  412. $xml = "<$name$xmlns$atts/>";
  413. $this->debug("serialize_val returning $xml");
  414. return $xml;
  415. } else {
  416. if (isset($type) && isset($type_prefix)) {
  417. $type_str = " xsi:type=\"$type_prefix:$type\"";
  418. } else {
  419. $type_str = '';
  420. }
  421. $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
  422. $this->debug("serialize_val returning $xml");
  423. return $xml;
  424. }
  425. }
  426. // serialize if an xsd built-in primitive type
  427. if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
  428. $this->debug("serialize_val: serialize xsd built-in primitive type");
  429. if (is_bool($val)) {
  430. if ($type == 'boolean') {
  431. $val = $val ? 'true' : 'false';
  432. } elseif (! $val) {
  433. $val = 0;
  434. }
  435. } else if (is_string($val)) {
  436. $val = $this->expandEntities($val);
  437. }
  438. if ($use == 'literal') {
  439. $xml = "<$name$xmlns$atts>$val</$name>";
  440. $this->debug("serialize_val returning $xml");
  441. return $xml;
  442. } else {
  443. $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
  444. $this->debug("serialize_val returning $xml");
  445. return $xml;
  446. }
  447. }
  448. // detect type and serialize
  449. $xml = '';
  450. switch(true) {
  451. case (is_bool($val) || $type == 'boolean'):
  452. $this->debug("serialize_val: serialize boolean");
  453. if ($type == 'boolean') {
  454. $val = $val ? 'true' : 'false';
  455. } elseif (! $val) {
  456. $val = 0;
  457. }
  458. if ($use == 'literal') {
  459. $xml .= "<$name$xmlns$atts>$val</$name>";
  460. } else {
  461. $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
  462. }
  463. break;
  464. case (is_int($val) || is_long($val) || $type == 'int'):
  465. $this->debug("serialize_val: serialize int");
  466. if ($use == 'literal') {
  467. $xml .= "<$name$xmlns$atts>$val</$name>";
  468. } else {
  469. $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
  470. }
  471. break;
  472. case (is_float($val)|| is_double($val) || $type == 'float'):
  473. $this->debug("serialize_val: serialize float");
  474. if ($use == 'literal') {
  475. $xml .= "<$name$xmlns$atts>$val</$name>";
  476. } else {
  477. $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
  478. }
  479. break;
  480. case (is_string($val) || $type == 'string'):
  481. $this->debug("serialize_val: serialize string");
  482. $val = $this->expandEntities($val);
  483. if ($use == 'literal') {
  484. $xml .= "<$name$xmlns$atts>$val</$name>";
  485. } else {
  486. $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
  487. }
  488. break;
  489. case is_object($val):
  490. $this->debug("serialize_val: serialize object");
  491. if (get_class($val) == 'soapval') {
  492. $this->debug("serialize_val: serialize soapval object");
  493. $pXml = $val->serialize($use);
  494. $this->appendDebug($val->getDebug());
  495. $val->clearDebug();
  496. } else {
  497. if (! $name) {
  498. $name = get_class($val);
  499. $this->debug("In serialize_val, used class name $name as element name");
  500. } else {
  501. $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
  502. }
  503. foreach(get_object_vars($val) as $k => $v){
  504. $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
  505. }
  506. }
  507. if(isset($type) && isset($type_prefix)){
  508. $type_str = " xsi:type=\"$type_prefix:$type\"";
  509. } else {
  510. $type_str = '';
  511. }
  512. if ($use == 'literal') {
  513. $xml .= "<$name$xmlns$atts>$pXml</$name>";
  514. } else {
  515. $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
  516. }
  517. break;
  518. break;
  519. case (is_array($val) || $type):
  520. // detect if struct or array
  521. $valueType = $this->isArraySimpleOrStruct($val);
  522. if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){
  523. $this->debug("serialize_val: serialize array");
  524. $i = 0;
  525. if(is_array($val) && count($val)> 0){
  526. foreach($val as $v){
  527. if(is_object($v) && get_class($v) == 'soapval'){
  528. $tt_ns = $v->type_ns;
  529. $tt = $v->type;
  530. } elseif (is_array($v)) {
  531. $tt = $this->isArraySimpleOrStruct($v);
  532. } else {
  533. $tt = gettype($v);
  534. }
  535. $array_types[$tt] = 1;
  536. // TODO: for literal, the name should be $name
  537. $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
  538. ++$i;
  539. }
  540. if(count($array_types) > 1){
  541. $array_typename = 'xsd:anyType';
  542. } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
  543. if ($tt == 'integer') {
  544. $tt = 'int';
  545. }
  546. $array_typename = 'xsd:'.$tt;
  547. } elseif(isset($tt) && $tt == 'arraySimple'){
  548. $array_typename = 'SOAP-ENC:Array';
  549. } elseif(isset($tt) && $tt == 'arrayStruct'){
  550. $array_typename = 'unnamed_struct_use_soapval';
  551. } else {
  552. // if type is prefixed, create type prefix
  553. if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
  554. $array_typename = 'xsd:' . $tt;
  555. } elseif ($tt_ns) {
  556. $tt_prefix = 'ns' . rand(1000, 9999);
  557. $array_typename = "$tt_prefix:$tt";
  558. $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
  559. } else {
  560. $array_typename = $tt;
  561. }
  562. }
  563. $array_type = $i;
  564. if ($use == 'literal') {
  565. $type_str = '';
  566. } else if (isset($type) && isset($type_prefix)) {
  567. $type_str = " xsi:type=\"$type_prefix:$type\"";
  568. } else {
  569. $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
  570. }
  571. // empty array
  572. } else {
  573. if ($use == 'literal') {
  574. $type_str = '';
  575. } else if (isset($type) && isset($type_prefix)) {
  576. $type_str = " xsi:type=\"$type_prefix:$type\"";
  577. } else {
  578. $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
  579. }
  580. }
  581. // TODO: for array in literal, there is no wrapper here
  582. $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
  583. } else {
  584. // got a struct
  585. $this->debug("serialize_val: serialize struct");
  586. if(isset($type) && isset($type_prefix)){
  587. $type_str = " xsi:type=\"$type_prefix:$type\"";
  588. } else {
  589. $type_str = '';
  590. }
  591. if ($use == 'literal') {
  592. $xml .= "<$name$xmlns$atts>";
  593. } else {
  594. $xml .= "<$name$xmlns$type_str$atts>";
  595. }
  596. foreach($val as $k => $v){
  597. // Apache Map
  598. if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
  599. $xml .= '<item>';
  600. $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
  601. $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
  602. $xml .= '</item>';
  603. } else {
  604. $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
  605. }
  606. }
  607. $xml .= "</$name>";
  608. }
  609. break;
  610. default:
  611. $this->debug("serialize_val: serialize unknown");
  612. $xml .= 'not detected, got '.gettype($val).' for '.$val;
  613. break;
  614. }
  615. $this->debug("serialize_val returning $xml");
  616. return $xml;
  617. }
  618. /**
  619. * serializes a message
  620. *
  621. * @param string $body the XML of the SOAP body
  622. * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
  623. * @param array $namespaces optional the namespaces used in generating the body and headers
  624. * @param string $style optional (rpc|document)
  625. * @param string $use optional (encoded|literal)
  626. * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
  627. * @return string the message
  628. * @access public
  629. */
  630. function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
  631. // TODO: add an option to automatically run utf8_encode on $body and $headers
  632. // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
  633. // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
  634. $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
  635. $this->debug("headers:");
  636. $this->appendDebug($this->varDump($headers));
  637. $this->debug("namespaces:");
  638. $this->appendDebug($this->varDump($namespaces));
  639. // serialize namespaces
  640. $ns_string = '';
  641. foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
  642. $ns_string .= " xmlns:$k=\"$v\"";
  643. }
  644. if($encodingStyle) {
  645. $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
  646. }
  647. // serialize headers
  648. if($headers){
  649. if (is_array($headers)) {
  650. $xml = '';
  651. foreach ($headers as $k => $v) {
  652. if (is_object($v) && get_class($v) == 'soapval') {
  653. $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
  654. } else {
  655. $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
  656. }
  657. }
  658. $headers = $xml;
  659. $this->debug("In serializeEnvelope, serialized array of headers to $headers");
  660. }
  661. $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
  662. }
  663. // serialize envelope
  664. return
  665. '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
  666. '<SOAP-ENV:Envelope'.$ns_string.">".
  667. $headers.
  668. "<SOAP-ENV:Body>".
  669. $body.
  670. "</SOAP-ENV:Body>".
  671. "</SOAP-ENV:Envelope>";
  672. }
  673. /**
  674. * formats a string to be inserted into an HTML stream
  675. *
  676. * @param string $str The string to format
  677. * @return string The formatted string
  678. * @access public
  679. * @deprecated
  680. */
  681. function formatDump($str){
  682. $str = htmlspecialchars($str);
  683. return nl2br($str);
  684. }
  685. /**
  686. * contracts (changes namespace to prefix) a qualified name
  687. *
  688. * @param string $qname qname
  689. * @return string contracted qname
  690. * @access private
  691. */
  692. function contractQname($qname){
  693. // get element namespace
  694. //$this->xdebug("Contract $qname");
  695. if (strrpos($qname, ':')) {
  696. // get unqualified name
  697. $name = substr($qname, strrpos($qname, ':') + 1);
  698. // get ns
  699. $ns = substr($qname, 0, strrpos($qname, ':'));
  700. $p = $this->getPrefixFromNamespace($ns);
  701. if ($p) {
  702. return $p . ':' . $name;
  703. }
  704. return $qname;
  705. } else {
  706. return $qname;
  707. }
  708. }
  709. /**
  710. * expands (changes prefix to namespace) a qualified name
  711. *
  712. * @param string $qname qname
  713. * @return string expanded qname
  714. * @access private
  715. */
  716. function expandQname($qname){
  717. // get element prefix
  718. if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){
  719. // get unqualified name
  720. $name = substr(strstr($qname,':'),1);
  721. // get ns prefix
  722. $prefix = substr($qname,0,strpos($qname,':'));
  723. if(isset($this->namespaces[$prefix])){
  724. return $this->namespaces[$prefix].':'.$name;
  725. } else {
  726. return $qname;
  727. }
  728. } else {
  729. return $qname;
  730. }
  731. }
  732. /**
  733. * returns the local part of a prefixed string
  734. * returns the original string, if not prefixed
  735. *
  736. * @param string $str The prefixed string
  737. * @return string The local part
  738. * @access public
  739. */
  740. function getLocalPart($str){
  741. if($sstr = strrchr($str,':')){
  742. // get unqualified name
  743. return substr( $sstr, 1 );
  744. } else {
  745. return $str;
  746. }
  747. }
  748. /**
  749. * returns the prefix part of a prefixed string
  750. * returns false, if not prefixed
  751. *
  752. * @param string $str The prefixed string
  753. * @return mixed The prefix or false if there is no prefix
  754. * @access public
  755. */
  756. function getPrefix($str){
  757. if($pos = strrpos($str,':')){
  758. // get prefix
  759. return substr($str,0,$pos);
  760. }
  761. return false;
  762. }
  763. /**
  764. * pass it a prefix, it returns a namespace
  765. *
  766. * @param string $prefix The prefix
  767. * @return mixed The namespace, false if no namespace has the specified prefix
  768. * @access public
  769. */
  770. function getNamespaceFromPrefix($prefix){
  771. if (isset($this->namespaces[$prefix])) {
  772. return $this->namespaces[$prefix];
  773. }
  774. //$this->setError("No namespace registered for prefix '$prefix'");
  775. return false;
  776. }
  777. /**
  778. * returns the prefix for a given namespace (or prefix)
  779. * or false if no prefixes registered for the given namespace
  780. *
  781. * @param string $ns The namespace
  782. * @return mixed The prefix, false if the namespace has no prefixes
  783. * @access public
  784. */
  785. function getPrefixFromNamespace($ns) {
  786. foreach ($this->namespaces as $p => $n) {
  787. if ($ns == $n || $ns == $p) {
  788. $this->usedNamespaces[$p] = $n;
  789. return $p;
  790. }
  791. }
  792. return false;
  793. }
  794. /**
  795. * returns the time in ODBC canonical form with microseconds
  796. *
  797. * @return string The time in ODBC canonical form with microseconds
  798. * @access public
  799. */
  800. function getmicrotime() {
  801. if (function_exists('gettimeofday')) {
  802. $tod = gettimeofday();
  803. $sec = $tod['sec'];
  804. $usec = $tod['usec'];
  805. } else {
  806. $sec = time();
  807. $usec = 0;
  808. }
  809. return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
  810. }
  811. /**
  812. * Returns a string with the output of var_dump
  813. *
  814. * @param mixed $data The variable to var_dump
  815. * @return string The output of var_dump
  816. * @access public
  817. */
  818. function varDump($data) {
  819. ob_start();
  820. var_dump($data);
  821. $ret_val = ob_get_contents();
  822. ob_end_clean();
  823. return $ret_val;
  824. }
  825. /**
  826. * represents the object as a string
  827. *
  828. * @return string
  829. * @access public
  830. */
  831. function __toString() {
  832. return $this->varDump($this);
  833. }
  834. }
  835. // XML Schema Datatype Helper Functions
  836. //xsd:dateTime helpers
  837. /**
  838. * convert unix timestamp to ISO 8601 compliant date string
  839. *
  840. * @param int $timestamp Unix time stamp
  841. * @param boolean $utc Whether the time stamp is UTC or local
  842. * @return mixed ISO 8601 date string or false
  843. * @access public
  844. */
  845. function timestamp_to_iso8601($timestamp,$utc=true){
  846. $datestr = date('Y-m-d\TH:i:sO',$timestamp);
  847. $pos = strrpos($datestr, "+");
  848. if ($pos === FALSE) {
  849. $pos = strrpos($datestr, "-");
  850. }
  851. if ($pos !== FALSE) {
  852. if (strlen($datestr) == $pos + 5) {
  853. $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2);
  854. }
  855. }
  856. if($utc){
  857. $pattern = '/'.
  858. '([0-9]{4})-'. // centuries & years CCYY-
  859. '([0-9]{2})-'. // months MM-
  860. '([0-9]{2})'. // days DD
  861. 'T'. // separator T
  862. '([0-9]{2}):'. // hours hh:
  863. '([0-9]{2}):'. // minutes mm:
  864. '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
  865. '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
  866. '/';
  867. if(preg_match($pattern,$datestr,$regs)){
  868. return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
  869. }
  870. return false;
  871. } else {
  872. return $datestr;
  873. }
  874. }
  875. /**
  876. * convert ISO 8601 compliant date string to unix timestamp
  877. *
  878. * @param string $datestr ISO 8601 compliant date string
  879. * @return mixed Unix timestamp (int) or false
  880. * @access public
  881. */
  882. function iso8601_to_timestamp($datestr){
  883. $pattern = '/'.
  884. '([0-9]{4})-'. // centuries & years CCYY-
  885. '([0-9]{2})-'. // months MM-
  886. '([0-9]{2})'. // days DD
  887. 'T'. // separator T
  888. '([0-9]{2}):'. // hours hh:
  889. '([0-9]{2}):'. // minutes mm:
  890. '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
  891. '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
  892. '/';
  893. if(preg_match($pattern,$datestr,$regs)){
  894. // not utc
  895. if($regs[8] != 'Z'){
  896. $op = substr($regs[8],0,1);
  897. $h = substr($regs[8],1,2);
  898. $m = substr($regs[8],strlen($regs[8])-2,2);
  899. if($op == '-'){
  900. $regs[4] = $regs[4] + $h;
  901. $regs[5] = $regs[5] + $m;
  902. } elseif($op == '+'){
  903. $regs[4] = $regs[4] - $h;
  904. $regs[5] = $regs[5] - $m;
  905. }
  906. }
  907. return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
  908. // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
  909. } else {
  910. return false;
  911. }
  912. }
  913. /**
  914. * sleeps some number of microseconds
  915. *
  916. * @param string $usec the number of microseconds to sleep
  917. * @access public
  918. * @deprecated
  919. */
  920. function usleepWindows($usec)
  921. {
  922. $start = gettimeofday();
  923. do
  924. {
  925. $stop = gettimeofday();
  926. $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
  927. + $stop['usec'] - $start['usec'];
  928. }
  929. while ($timePassed < $usec);
  930. }
  931. ?>