ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilBMFBase.php
Go to the documentation of this file.
1 <?php
35 $GLOBALS['SOAP_OBJECT_STRUCT'] = true;
36 
45 $GLOBALS['SOAP_RAW_CONVERT'] = false;
46 
47 require_once 'PEAR.php';
48 require_once dirname(__FILE__).'/Type/class.ilBMFType_dateTime.php';
49 require_once dirname(__FILE__).'/Type/class.ilBMFType_hexBinary.php';
50 
51 // optional features
52 $GLOBALS['SOAP_options'] = array();
53 
54 @include_once 'Mail/mimePart.php';
55 @include_once 'Mail/mimeDecode.php';
56 if (class_exists('Mail_mimePart')) {
57  $GLOBALS['SOAP_options']['Mime'] = 1;
58  define('MAIL_MIMEPART_CRLF', "\r\n");
59 }
60 
61 @include_once 'Net/DIME.php';
62 if (class_exists('Net_DIME_Message')) {
63  $GLOBALS['SOAP_options']['DIME'] = 1;
64 }
65 
72 $GLOBALS['SOAP_DEBUG'] = false;
73 
74 if (!function_exists('version_compare') ||
75  version_compare(phpversion(), '4.1', '<')) {
76  die("requires PHP 4.1 or higher\n");
77 }
78 if (version_compare(phpversion(), '4.1', '>=') &&
79  version_compare(phpversion(), '4.2', '<')) {
80  define('FLOAT', 'double');
81 } else {
82  define('FLOAT', 'float');
83 }
84 
85 if (!defined('INF')) {
86  define('INF', 1.8e307);
87 }
88 if (!defined('NAN')) {
89  define('NAN', 0.0);
90 }
91 
92 define('SOAP_LIBRARY_VERSION', '0.8.0RC4');
93 define('SOAP_LIBRARY_NAME', 'PEAR-SOAP 0.8.0RC4-devel');
94 
95 // Set schema version.
96 define('SOAP_XML_SCHEMA_VERSION', 'http://www.w3.org/2001/XMLSchema');
97 define('SOAP_XML_SCHEMA_INSTANCE', 'http://www.w3.org/2001/XMLSchema-instance');
98 define('SOAP_XML_SCHEMA_1999', 'http://www.w3.org/1999/XMLSchema');
99 define('SOAP_SCHEMA', 'http://schemas.xmlsoap.org/wsdl/soap/');
100 define('SOAP_SCHEMA_ENCODING', 'http://schemas.xmlsoap.org/soap/encoding/');
101 define('SOAP_ENVELOP', 'http://schemas.xmlsoap.org/soap/envelope/');
102 
103 define('SCHEMA_DISCO', 'http://schemas.xmlsoap.org/disco/');
104 define('SCHEMA_DISCO_SCL', 'http://schemas.xmlsoap.org/disco/scl/');
105 
106 define('SCHEMA_SOAP', 'http://schemas.xmlsoap.org/wsdl/soap/');
107 define('SCHEMA_SOAP_HTTP', 'http://schemas.xmlsoap.org/soap/http');
108 define('SCHEMA_WSDL_HTTP', 'http://schemas.xmlsoap.org/wsdl/http/');
109 define('SCHEMA_MIME', 'http://schemas.xmlsoap.org/wsdl/mime/');
110 define('SCHEMA_WSDL', 'http://schemas.xmlsoap.org/wsdl/');
111 define('SCHEMA_DIME', 'http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/');
112 define('SCHEMA_CONTENT', 'http://schemas.xmlsoap.org/ws/2002/04/content-type/');
113 define('SCHEMA_REF', 'http://schemas.xmlsoap.org/ws/2002/04/reference/');
114 
115 /* Databay: Changes for BMF */
116 #define('SOAP_DEFAULT_ENCODING', 'UTF-8');
117 define('SOAP_DEFAULT_ENCODING', 'ISO-8859-1');
118 
119 class ilBMFBase_Object extends PEAR
120 {
127  var $_debug_flag = false;
128 
136  var $_debug_data = '';
137 
143  var $_encodings = array('ISO-8859-1', 'US-ASCII', 'UTF-8');
144 
150  var $_myfaultcode = '';
151 
157  var $fault = null;
158 
166  function ilBMFBase_Object($faultcode = 'Client')
167  {
168  $this->_myfaultcode = $faultcode;
169  $this->_debug_flag = $GLOBALS['SOAP_DEBUG'];
170  parent::PEAR('ilBMFFault');
171  }
172 
191  function &_raiseSoapFault($str, $detail = '', $actorURI = '', $code = null,
192  $mode = null, $options = null, $skipmsg = false)
193  {
194  // Pass through previous faults.
195  $is_instance = isset($this);
196  if (is_object($str)) {
197  $fault =& $str;
198  } else {
199  if (!$code) {
200  $code = $is_instance ? $this->_myfaultcode : 'Client';
201  }
202  $fault =& new ilBMFFault($str,
203  $code,
204  $actorURI,
205  $detail,
206  $mode,
207  $options);
208  }
209  if ($is_instance) {
210  $this->fault =& $fault;
211  }
212 
213  return $fault;
214  }
215 
216  function __isfault()
217  {
218  return $this->fault != null;
219  }
220 
221  function &__getfault()
222  {
223  return $this->fault;
224  }
225 
231  function _debug($string)
232  {
233  if ($this->_debug_flag) {
234  $this->_debug_data .= get_class($this) . ': ' .
235  str_replace('>', ">\r\n", $string) . "\n";
236  }
237  }
238 
239 }
240 
249 {
250  var $_XMLSchema = array('http://www.w3.org/2001/XMLSchema',
251  'http://www.w3.org/1999/XMLSchema');
252  var $_XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
253 
254  // load types into typemap array
255  var $_typemap = array(
256  'http://www.w3.org/2001/XMLSchema' => array(
257  'string' => 'string',
258  'boolean' => 'boolean',
259  'float' => FLOAT,
260  'double' => FLOAT,
261  'decimal' => FLOAT,
262  'duration' => 'integer',
263  'dateTime' => 'string',
264  'time' => 'string',
265  'date' => 'string',
266  'gYearMonth' => 'integer',
267  'gYear' => 'integer',
268  'gMonthDay' => 'integer',
269  'gDay' => 'integer',
270  'gMonth' => 'integer',
271  'hexBinary' => 'string',
272  'base64Binary' => 'string',
273  // derived datatypes
274  'normalizedString' => 'string',
275  'token' => 'string',
276  'language' => 'string',
277  'NMTOKEN' => 'string',
278  'NMTOKENS' => 'string',
279  'Name' => 'string',
280  'NCName' => 'string',
281  'ID' => 'string',
282  'IDREF' => 'string',
283  'IDREFS' => 'string',
284  'ENTITY' => 'string',
285  'ENTITIES' => 'string',
286  'integer' => 'integer',
287  'nonPositiveInteger' => 'integer',
288  'negativeInteger' => 'integer',
289  'long' => 'integer',
290  'int' => 'integer',
291  'short' => 'integer',
292  'byte' => 'string',
293  'nonNegativeInteger' => 'integer',
294  'unsignedLong' => 'integer',
295  'unsignedInt' => 'integer',
296  'unsignedShort' => 'integer',
297  'unsignedByte' => 'integer',
298  'positiveInteger' => 'integer',
299  'anyType' => 'string',
300  'anyURI' => 'string',
301  'QName' => 'string'
302  ),
303  'http://www.w3.org/1999/XMLSchema' => array(
304  'i4' => 'integer',
305  'int' => 'integer',
306  'boolean' => 'boolean',
307  'string' => 'string',
308  'double' => FLOAT,
309  'float' => FLOAT,
310  'dateTime' => 'string',
311  'timeInstant' => 'string',
312  'base64Binary' => 'string',
313  'base64' => 'string',
314  'ur-type' => 'string'
315  ),
316  'http://schemas.xmlsoap.org/soap/encoding/' => array(
317  'base64' => 'string',
318  'array' => 'array',
319  'Array' => 'array',
320  'Struct' => 'array')
321  );
322 
328  var $_defaultObjectClassname = 'stdClass';
329 
330  // Load namespace URIs into an array of URI => prefix.
333 
334  var $_xmlEntities = array('&' => '&amp;',
335  '<' => '&lt;',
336  '>' => '&gt;',
337  "'" => '&apos;',
338  '"' => '&quot;');
339 
340  var $_doconversion = false;
341 
342  var $__attachments = array();
343 
344  var $_wsdl = null;
345 
351  var $_section5 = true;
352 
353  // Handle type to class mapping.
354  var $_auto_translation = false;
355  var $_type_translation = array();
356 
364  function ilBMFBase($faultcode = 'Client')
365  {
366  parent::ilBMFBase_Object($faultcode);
367  $this->_resetNamespaces();
368  }
369 
370  function _resetNamespaces()
371  {
372  $this->_namespaces = array(
373  'http://schemas.xmlsoap.org/soap/envelope/' => 'SOAP-ENV',
374  'http://www.w3.org/2001/XMLSchema' => 'xsd',
375  'http://www.w3.org/2001/XMLSchema-instance' => 'xsi',
376  'http://schemas.xmlsoap.org/soap/encoding/' => 'SOAP-ENC');
377  }
378 
387  function _setSchemaVersion($schemaVersion)
388  {
389  if (!in_array($schemaVersion, $this->_XMLSchema)) {
390  return $this->_raiseSoapFault("unsuported XMLSchema $schemaVersion");
391  }
392  $this->_XMLSchemaVersion = $schemaVersion;
393  $tmpNS = array_flip($this->_namespaces);
394  $tmpNS['xsd'] = $this->_XMLSchemaVersion;
395  $tmpNS['xsi'] = $this->_XMLSchemaVersion . '-instance';
396  $this->_namespaces = array_flip($tmpNS);
397  }
398 
399  function _getNamespacePrefix($ns)
400  {
401  if ($this->_namespace && $ns == $this->_namespace) {
402  return '';
403  }
404  if (isset($this->_namespaces[$ns])) {
405  return $this->_namespaces[$ns];
406  }
407  $prefix = 'ns' . count($this->_namespaces);
408  $this->_namespaces[$ns] = $prefix;
409  return $prefix;
410  }
411 
412  function _getNamespaceForPrefix($prefix)
413  {
414  $flipped = array_flip($this->_namespaces);
415  if (isset($flipped[$prefix])) {
416  return $flipped[$prefix];
417  }
418  return null;
419  }
420 
421  function _isSoapValue(&$value)
422  {
423  return is_a($value, 'ilBMFValue');
424  }
425 
426  function _serializeValue(&$value, $name = '', $type = false, $elNamespace = NULL, $typeNamespace=NULL, $options=array(), $attributes = array(), $artype='', $OBJTypeNS = array())
427  {
428  $namespaces = array();
429  $arrayType = $array_depth = $xmlout_value = null;
430  $typePrefix = $elPrefix = $xmlout_offset = $xmlout_arrayType = $xmlout_type = $xmlns = '';
431  $ptype = $array_type_ns = '';
432 
433  if (!$name || is_numeric($name)) {
434  $name = 'item';
435  }
436 
437  if ($this->_wsdl)
438  list($ptype, $arrayType, $array_type_ns, $array_depth)
439  = $this->_wsdl->getSchemaType($type, $name, $typeNamespace);
440 
441  if (!$arrayType) $arrayType = $artype;
442  if (!$ptype) $ptype = $this->_getType($value);
443  if (!$type) $type = $ptype;
444 
445  if (strcasecmp($ptype,'Struct') == 0 || strcasecmp($type,'Struct') == 0) {
446  // struct
447  $vars = NULL;
448  if (is_object($value)) {
449  $vars = get_object_vars($value);
450  } else {
451  $vars = &$value;
452  }
453  if (is_array($vars)) {
454  foreach (array_keys($vars) as $k) {
455  if ($k[0]=='_') continue; // hide private vars
456  if (is_object($vars[$k])) {
457  if (is_a($vars[$k],'ilbmfvalue')) {
458  $xmlout_value .= $vars[$k]->serialize($this);
459  } else {
460  // XXX get the members and serialize them instead
461  // converting to an array is more overhead than we
462  // should realy do, but php-soap is on it's way.
463  $objarr = get_object_vars ( $vars[$k] );
464  if (!isset ($objarr['OBJTypeNS'])) {
465  $xmlout_value .= $this->_serializeValue(get_object_vars($vars[$k]), $k, false, $this->_section5?NULL:$elNamespace, NULL, NULL, NULL, NULL);
466  } else {
467  $xmlout_value .= $this->_serializeValue(get_object_vars($vars[$k]), $k, false, $this->_section5?NULL:$elNamespace, NULL, NULL, NULL, NULL, $objarr['OBJTypeNS']);
468  }
469  }
470  } else {
471  if ($k != 'OBJTypeNS') {
472  $xmlout_value .= $this->_serializeValue($vars[$k],$k, false, $this->_section5?NULL:$elNamespace);
473  }
474  }
475  }
476  }
477  } else if (strcasecmp($ptype,'Array')==0 || strcasecmp($type,'Array')==0) {
478  // array
479  $typeNamespace = SOAP_SCHEMA_ENCODING;
480  $orig_type = $type;
481  $type = 'Array';
482  $numtypes = 0;
483  // XXX this will be slow on larger array's. Basicly, it flattens array's to allow us
484  // to serialize multi-dimensional array's. We only do this if arrayType is set,
485  // which will typicaly only happen if we are using WSDL
486  if (isset($options['flatten']) || ($arrayType && (strchr($arrayType,',') || strstr($arrayType,'][')))) {
487  $numtypes = $this->_multiArrayType($value, $arrayType, $ar_size, $xmlout_value);
488  }
489 
490  $array_type = $array_type_prefix = '';
491  if ($numtypes != 1) {
492  $arrayTypeQName =& new QName($arrayType);
493  $arrayType = $arrayTypeQName->name;
494  $array_types = array();
495  $array_val = NULL;
496 
497  // serialize each array element
498  $ar_size = count($value);
499  foreach ($value as $array_val) {
500  if ($this->_isSoapValue($array_val)) {
501  $array_type = $array_val->type;
502  $array_types[$array_type] = 1;
503  $array_type_ns = $array_val->type_namespace;
504  $xmlout_value .= $array_val->serialize($this);
505  } else {
506  $array_type = $this->_getType($array_val);
507  $array_types[$array_type] = 1;
508  $objarr = get_object_vars ( $array_val );
509  if (isset($objarr['OBJTypeNS'])) {
510  $tmp_arr['item'] = $objarr['OBJTypeNS']['item'];
511  $xmlout_value .= $this->_serializeValue($array_val,'item', $array_type, $elNamespace, NULL, NULL, NULL, NULL, $tmp_arr);
512  } else {
513  $xmlout_value .= $this->_serializeValue($array_val,'item', $array_type, $elNamespace);
514  }
515  }
516  }
517 
518  $xmlout_offset = " SOAP-ENC:offset=\"[0]\"";
519  if (!$arrayType) {
520  $numtypes = count($array_types);
521  if ($numtypes == 1) $arrayType = $array_type;
522  // using anyType is more interoperable
523  if ($array_type == 'Struct') {
524  $array_type = '';
525  } else if ($array_type == 'Array') {
526  $arrayType = 'anyType';
527  $array_type_prefix = 'xsd';
528  } else
529  if (!$arrayType) $arrayType = $array_type;
530  }
531  }
532  if (!$arrayType || $numtypes > 1) {
533  $arrayType = 'xsd:anyType'; // should reference what schema we're using
534  } else {
535  if ($array_type_ns) {
536  $array_type_prefix = $this->_getNamespacePrefix($array_type_ns);
537  } else if (array_key_exists($arrayType, $this->_typemap[$this->_XMLSchemaVersion])) {
538  $array_type_prefix = $this->_namespaces[$this->_XMLSchemaVersion];
539  }
540  if ($array_type_prefix)
541  $arrayType = $array_type_prefix.':'.$arrayType;
542  }
543 
544  if (isset($value[0]->OBJTypeNS)) {
545  $xmlout_arrayType = ' xmlns:' . $value[0]->OBJTypeNS['nsPrefix'] . '="' . $value[0]->OBJTypeNS['namespace'] . '" xsi:type="' . $value[0]->OBJTypeNS['nsPrefix'] . ':Array" ' . $value[0]->OBJTypeNS['nsPrefix'] . ':arrayType="' . $value[0]->OBJTypeNS['pnsPrefix'] . ':' . get_class($value[0]);
546  $xmlout_type = $xmlns = $xmlout_offset = $xml_attr = $arrayType = '';
547  } else {
548  $xmlout_arrayType = " SOAP-ENC:arrayType=\"" . $arrayType;
549  }
550  if ($array_depth != null) {
551  for ($i = 0; $i < $array_depth; $i++) {
552  $xmlout_arrayType .= '[]';
553  }
554  }
555  $xmlout_arrayType .= "[$ar_size]\"";
556  } else if ($this->_isSoapValue($value)) {
557  $xmlout_value =& $value->serialize($this);
558  } else if ($type == 'string') {
559  $xmlout_value = htmlspecialchars($value);
560  } else if ($type == 'rawstring') {
561  $xmlout_value =& $value;
562  } else if ($type == 'boolean') {
563  $xmlout_value = $value?'true':'false';
564  } else {
565  $xmlout_value =& $value;
566  }
567 
568  // add namespaces
569  if ($elNamespace) {
570  $elPrefix = $this->_getNamespacePrefix($elNamespace);
571  $xmlout_name = "$elPrefix:$name";
572  } else {
573  $xmlout_name = $name;
574  }
575 
576  if ($typeNamespace) {
577  $typePrefix = $this->_getNamespacePrefix($typeNamespace);
578  $xmlout_type = "$typePrefix:$type";
579  } else if ($type && array_key_exists($type, $this->_typemap[$this->_XMLSchemaVersion])) {
580  $typePrefix = $this->_namespaces[$this->_XMLSchemaVersion];
581  $xmlout_type = "$typePrefix:$type";
582  }
583 
584  // handle additional attributes
585  $xml_attr = '';
586  if (count($attributes) > 0) {
587  foreach ($attributes as $k => $v) {
588  $kqn =& new QName($k);
589  $vqn =& new QName($v);
590  $xml_attr .= ' '.$kqn->fqn().'="'.$vqn->fqn().'"';
591  }
592  }
593 
594  // store the attachement for mime encoding
595  if (isset($options['attachment']))
596  $this->__attachments[] = $options['attachment'];
597 
598  if ($this->_section5) {
599  if ($name == 'item' && isset($OBJTypeNS['item'])) {
600  $xmlout_type = $OBJTypeNS['item'];
601  }
602 
603  if ($xmlout_type) $xmlout_type = " xsi:type=\"$xmlout_type\"";
604  if (is_null($xmlout_value)) {
605  $xml = "";
606  } else {
607  if (is_array($value) && isset ($value[0]->OBJTypeNS)) {
608  $xmlout_type = '';
609  }
610  $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType$xmlout_offset$xml_attr ";
611  if (isset($OBJTypeNS['namespace']) && isset($OBJTypeNS['type'])) {
612  if (trim($OBJTypeNS['namespace']) != '' || trim($OBJTypeNS['type']) != '') {
613  if (isset($OBJTypeNS['namespace']) && $OBJTypeNS['namespace'] != '') {
614  $xml .= ' xmlns:';
615  if ( isset($OBJTypeNS['nsPrefix']))
616  $xml .= $OBJTypeNS['nsPrefix'];
617  else
618  $xml .= 'intf';
619  $xml .= '="' . $OBJTypeNS['namespace'] . '"';
620  }
621  if (isset($OBJTypeNS['type']) && $OBJTypeNS['type'] != '') {
622  $xml .= ' xsi:type="';
623  if (strpos($OBJTypeNS['type'], "xsd:") === false){
624  if (isset($OBJTypeNS['nsPrefix']))
625  $xml .= $OBJTypeNS['nsPrefix'] . ':';
626  else
627  $xml .= 'intf:';
628  }
629  $xml .= $OBJTypeNS['type'] . '"';
630  }
631  }
632  }
633  $xml .= ">" . $xmlout_value . "</$xmlout_name>";
634  }
635  } else {
636  if (is_null($xmlout_value)) {
637  $xml = "";
638  } else {
639  $xml = "\r\n<$xmlout_name$xmlns$xml_attr>".
640  $xmlout_value."</$xmlout_name>";
641  }
642  }
643  return $xml;
644  }
645 
646 
647 /* Databay: Changes for BMF */
648 /* function _serializeValue(&$value, $name = '', $type = false,
649  $elNamespace = null, $typeNamespace = null,
650  $options = array(), $attributes = array(),
651  $artype = '')
652  {
653  $namespaces = array();
654  $arrayType = $array_depth = $xmlout_value = null;
655  $typePrefix = $elPrefix = $xmlout_offset = $xmlout_arrayType = '';
656  $xmlout_type = $xmlns = $ptype = $array_type_ns = '';
657 
658  if (!$name || is_numeric($name)) {
659  $name = 'item';
660  }
661 
662  if ($this->_wsdl) {
663  list($ptype, $arrayType, $array_type_ns, $array_depth)
664  = $this->_wsdl->getSchemaType($type, $name, $typeNamespace);
665  }
666 
667  if (!$arrayType) {
668  $arrayType = $artype;
669  }
670  if (!$ptype) {
671  $ptype = $this->_getType($value);
672  }
673  if (!$type) {
674  $type = $ptype;
675  }
676 
677  if (strcasecmp($ptype, 'Struct') == 0 ||
678  strcasecmp($type, 'Struct') == 0) {
679  // Struct
680  $vars = null;
681  if (is_object($value)) {
682  $vars = get_object_vars($value);
683  } else {
684  $vars = &$value;
685  }
686  if (is_array($vars)) {
687  foreach (array_keys($vars) as $k) {
688  // Hide private vars.
689  if ($k[0] == '_') continue;
690  if (is_object($vars[$k])) {
691  if (is_a($vars[$k], 'ilBMFValue')) {
692  $xmlout_value .= $vars[$k]->serialize($this);
693  } else {
694  // XXX get the members and serialize them instead
695  // converting to an array is more overhead than we
696  // should really do.
697  $xmlout_value .= $this->_serializeValue(get_object_vars($vars[$k]), $k, false, $this->_section5 ? null : $elNamespace);
698  }
699  } else {
700  $xmlout_value .= $this->_serializeValue($vars[$k], $k, false, $this->_section5 ? null : $elNamespace);
701  }
702  }
703  }
704  } elseif (strcasecmp($ptype, 'Array') == 0 ||
705  strcasecmp($type, 'Array') == 0) {
706  // Array.
707  $typeNamespace = SOAP_SCHEMA_ENCODING;
708  $orig_type = $type;
709  $type = 'Array';
710  $numtypes = 0;
711  // XXX this will be slow on larger arrays. Basically, it flattens
712  // arrays to allow us to serialize multi-dimensional arrays. We
713  // only do this if arrayType is set, which will typically only
714  // happen if we are using WSDL
715  if (isset($options['flatten']) ||
716  ($arrayType &&
717  (strchr($arrayType, ',') || strstr($arrayType, '][')))) {
718  $numtypes = $this->_multiArrayType($value, $arrayType,
719  $ar_size, $xmlout_value);
720  }
721 
722  $array_type = $array_type_prefix = '';
723  if ($numtypes != 1) {
724  $arrayTypeQName =& new QName($arrayType);
725  $arrayType = $arrayTypeQName->name;
726  $array_types = array();
727  $array_val = null;
728 
729  // Serialize each array element.
730  $ar_size = count($value);
731  foreach ($value as $array_val) {
732  if ($this->_isSoapValue($array_val)) {
733  $array_type = $array_val->type;
734  $array_types[$array_type] = 1;
735  $array_type_ns = $array_val->type_namespace;
736  $xmlout_value .= $array_val->serialize($this);
737  } else {
738  $array_type = $this->_getType($array_val);
739  $array_types[$array_type] = 1;
740  $xmlout_value .= $this->_serializeValue($array_val, 'item', $array_type, $this->_section5 ? null : $elNamespace);
741  }
742  }
743 
744  $xmlout_offset = ' SOAP-ENC:offset="[0]"';
745  if (!$arrayType) {
746  $numtypes = count($array_types);
747  if ($numtypes == 1) {
748  $arrayType = $array_type;
749  }
750  // Using anyType is more interoperable.
751  if ($array_type == 'Struct') {
752  $array_type = '';
753  } elseif ($array_type == 'Array') {
754  $arrayType = 'anyType';
755  $array_type_prefix = 'xsd';
756  } else {
757  if (!$arrayType) {
758  $arrayType = $array_type;
759  }
760  }
761  }
762  }
763  if (!$arrayType || $numtypes > 1) {
764  // Should reference what schema we're using.
765  $arrayType = 'xsd:anyType';
766  } else {
767  if ($array_type_ns) {
768  $array_type_prefix = $this->_getNamespacePrefix($array_type_ns);
769  } elseif (isset($this->_typemap[$this->_XMLSchemaVersion][$arrayType])) {
770  $array_type_prefix = $this->_namespaces[$this->_XMLSchemaVersion];
771  }
772  if ($array_type_prefix) {
773  $arrayType = $array_type_prefix . ':' . $arrayType;
774  }
775  }
776 
777  $xmlout_arrayType = ' SOAP-ENC:arrayType="' . $arrayType;
778  if ($array_depth != null) {
779  for ($i = 0; $i < $array_depth; $i++) {
780  $xmlout_arrayType .= '[]';
781  }
782  }
783  $xmlout_arrayType .= "[$ar_size]\"";
784  } elseif ($this->_isSoapValue($value)) {
785  $xmlout_value = $value->serialize($this);
786  } elseif ($type == 'string') {
787  $xmlout_value = htmlspecialchars($value);
788  } elseif ($type == 'rawstring') {
789  $xmlout_value =& $value;
790  } elseif ($type == 'boolean') {
791  $xmlout_value = $value ? 'true' : 'false';
792  } else {
793  $xmlout_value =& $value;
794  }
795 
796  // Add namespaces.
797  if ($elNamespace) {
798  $elPrefix = $this->_getNamespacePrefix($elNamespace);
799  if ($elPrefix) {
800  $xmlout_name = "$elPrefix:$name";
801  } else {
802  $xmlout_name = $name;
803  }
804  } else {
805  $xmlout_name = $name;
806  }
807 
808  if ($typeNamespace) {
809  $typePrefix = $this->_getNamespacePrefix($typeNamespace);
810  if ($typePrefix) {
811  $xmlout_type = "$typePrefix:$type";
812  } else {
813  $xmlout_type = $type;
814  }
815  } elseif ($type &&
816  isset($this->_typemap[$this->_XMLSchemaVersion][$type])) {
817  $typePrefix = $this->_namespaces[$this->_XMLSchemaVersion];
818  if ($typePrefix) {
819  $xmlout_type = "$typePrefix:$type";
820  } else {
821  $xmlout_type = $type;
822  }
823  }
824 
825  // Handle additional attributes.
826  $xml_attr = '';
827  if (count($attributes)) {
828  foreach ($attributes as $k => $v) {
829  $kqn =& new QName($k);
830  $vqn =& new QName($v);
831  $xml_attr .= ' ' . $kqn->fqn() . '="' . $vqn->fqn() . '"';
832  }
833  }
834 
835  // Store the attachment for mime encoding.
836  if (isset($options['attachment']) &&
837  !PEAR::isError($options['attachment'])) {
838  $this->__attachments[] = $options['attachment'];
839  }
840 
841  if ($this->_section5) {
842  if ($xmlout_type) {
843  $xmlout_type = " xsi:type=\"$xmlout_type\"";
844  }
845  if (is_null($xmlout_value)) {
846  $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" .
847  "$xml_attr xsi:nil=\"true\"/>";
848  } else {
849  $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" .
850  "$xmlout_offset$xml_attr>$xmlout_value</$xmlout_name>";
851  }
852  } else {
853  if (is_null($xmlout_value)) {
854  $xml = "\r\n<$xmlout_name$xmlns$xml_attr/>";
855  } else {
856  $xml = "\r\n<$xmlout_name$xmlns$xml_attr>" .
857  $xmlout_value . "</$xmlout_name>";
858  }
859  }
860 
861  return $xml;
862  }
863 */
873  function _getType(&$value)
874  {
875  global $SOAP_OBJECT_STRUCT, $SOAP_RAW_CONVERT;
876 
877  $type = gettype($value);
878  switch ($type) {
879  case 'object':
880  if (is_a($value, 'ilbmfvalue')) {
881  $type = $value->type;
882  } else {
883  $type = 'Struct';
884  }
885  break;
886 
887  case 'array':
888  // Hashes are always handled as structs.
889  if ($this->_isHash($value)) {
890  $type = 'Struct';
891  } else {
892  $ar_size = count($value);
893  reset($value);
894  $key1 = key($value);
895  if ($ar_size > 0 && is_a($key1, 'ilBMFValue')) {
896  // FIXME: for non-wsdl structs that are all the same type
897  $key2 = key($value);
898  if ($ar_size > 1 &&
899  $this->_isSoapValue($key1) &&
900  $this->_isSoapValue($key2) &&
901  $key1->name != $key2->name) {
902  // This is a struct, not an array.
903  $type = 'Struct';
904  } else {
905  $type = 'Array';
906  }
907  } else {
908  $type = 'Array';
909  }
910  }
911  break;
912 
913  case 'integer':
914  case 'long':
915  $type = 'int';
916  break;
917 
918  case 'boolean':
919  break;
920 
921  case 'double':
922  // double is deprecated in PHP 4.2 and later.
923  $type = 'decimal';
924  break;
925 
926  case 'null':
927  $type = '';
928  break;
929 
930  case 'string':
931 /* Databay: Changes for BMF */
932 /* if ($SOAP_RAW_CONVERT) {
933  if (is_numeric($value)) {
934  if (strstr($value, '.')) {
935  $type = 'float';
936  } else {
937  $type = 'int';
938  }
939  } else {
940  if (ilBMFType_hexBinary::is_hexbin($value)) {
941  $type = 'hexBinary';
942  } else {
943  if ($this->_isBase64($value)) {
944  $type = 'base64Binary';
945  } else {
946  $dt =& new ilBMFType_dateTime($value);
947  if ($dt->toUnixtime() != -1) {
948  $type = 'dateTime';
949  }
950  }
951  }
952  }
953  }
954  break;*/
955  if ($SOAP_RAW_CONVERT) {
956  if (is_numeric($value)) {
957  if (strstr($value,'.')) $type = 'float';
958  else $type = 'int';
959  } else
960  if (ilBMFType_hexBinary::is_hexbin($value)) {
961  $type = 'hexBinary';
962  } else
963  if ($this->_isBase64($value)) {
964  $type = 'base64Binary';
965  } else {
966  $dt =& new ilBMFType_dateTime($value);
967  if ($dt->toUnixtime() != -1) {
968  $type = 'dateTime';
969  #$value = $dt->toSOAP();
970  }
971  }
972  } else {
973  $dt =& new ilBMFType_dateTime($value);
974  if ($dt->toUnixtime() != -1) {
975  $type = 'dateTime';
976  #$value = $dt->toSOAP();
977  }
978  }
979 
980  default:
981  break;
982  }
983 
984  return $type;
985  }
986 
987  function _multiArrayType(&$value, &$type, &$size, &$xml)
988  {
989  $sz = count($value);
990  if (is_array($value)) {
991  // Seems we have a multi dimensional array, figure it out if we
992  // do.
993  $c = count($value);
994  for ($i = 0; $i < $c; $i++) {
995  $this->_multiArrayType($value[$i], $type, $size, $xml);
996  }
997 
998  if ($size) {
999  $size = $sz. ',' . $size;
1000  } else {
1001  $size = $sz;
1002  }
1003 
1004  return 1;
1005  } else {
1006  if (is_object($value)) {
1007  $type = $value->type;
1008  $xml .= $value->serialize($this);
1009  } else {
1010  $type = $this->_getType($value);
1011  $xml .= $this->_serializeValue($value, 'item', $type);
1012  }
1013  }
1014  $size = null;
1015 
1016  return 1;
1017  }
1018 
1026  function _isBase64(&$value)
1027  {
1028  $l = strlen($value);
1029  if ($l) {
1030  return $value[$l - 1] == '=' &&
1031  preg_match('/[A-Za-z=\/\+]+/', $value);
1032  }
1033  return false;
1034  }
1035 
1043  function _isBase64Type($type)
1044  {
1045  return $type == 'base64' || $type == 'base64Binary';
1046  }
1047 
1055  function _isHash(&$a)
1056  {
1057  // I really dislike having to loop through this in PHP code, really
1058  // large arrays will be slow. We need a C function to do this.
1059  $names = array();
1060  $it = 0;
1061  foreach ($a as $k => $v) {
1062  // Checking the type is faster than regexp.
1063  $t = gettype($k);
1064  if ($t != 'integer') {
1065  return true;
1066  } elseif ($this->_isSoapValue($v)) {
1067  $names[$v->name] = 1;
1068  }
1069  // If someone has a large hash they should really be defining the
1070  // type.
1071  if ($it++ > 10) {
1072  return false;
1073  }
1074  }
1075  return count($names)>1;
1076  }
1077 
1078  function _un_htmlentities($string)
1079  {
1080  $trans_tbl = get_html_translation_table(HTML_ENTITIES);
1081  $trans_tbl = array_flip($trans_tbl);
1082  return strtr($string, $trans_tbl);
1083  }
1084 
1085  function &_decode(&$soapval)
1086  {
1087  global $SOAP_OBJECT_STRUCT;
1088 
1089  if (!$this->_isSoapValue($soapval)) {
1090  return $soapval;
1091  } elseif (is_array($soapval->value)) {
1092  if ($SOAP_OBJECT_STRUCT && $soapval->type != 'Array') {
1093  $classname = $this->_defaultObjectClassname;
1094  if (isset($this->_type_translation[$soapval->tqn->fqn()])) {
1095  // This will force an error in PHP if the class does not
1096  // exist.
1097  $classname = $this->_type_translation[$soapval->tqn->fqn()];
1098  } elseif (isset($this->_type_translation[$soapval->type])) {
1099  // This will force an error in PHP if the class does not
1100  // exist.
1101  $classname = $this->_type_translation[$soapval->type];
1102  } elseif ($this->_auto_translation) {
1103  if (class_exists($soapval->type)) {
1104  $classname = $soapval->type;
1105  } elseif ($this->_wsdl) {
1106  $t = $this->_wsdl->getComplexTypeNameForElement($soapval->name, $soapval->namespace);
1107  if ($t && class_exists($t)) {
1108  $classname = $t;
1109  }
1110  }
1111  }
1112  $return =& new $classname;
1113  } else {
1114  $return = array();
1115  }
1116 
1117  $counter = 1;
1118  $isstruct = !$SOAP_OBJECT_STRUCT || !is_array($return);
1119  foreach ($soapval->value as $item) {
1120  if (is_object($return)) {
1121  if ($this->_wsdl) {
1122  // Get this child's WSDL information.
1123  // /$soapval->ns/$soapval->type/$item->ns/$item->name
1124  $child_type = $this->_wsdl->getComplexTypeChildType(
1125  $soapval->namespace,
1126  $soapval->name,
1127  $item->namespace,
1128  $item->name);
1129  if ($child_type) {
1130  $item->type = $child_type;
1131  }
1132  }
1133  if (!$isstruct || $item->type == 'Array') {
1134  if (isset($return->{$item->name}) &&
1135  is_object($return->{$item->name})) {
1136  $return->{$item->name} =& $this->_decode($item);
1137  } elseif (isset($return->{$item->name}) &&
1138  is_array($return->{$item->name})) {
1139  $return->{$item->name}[] = $this->_decode($item);
1140  } elseif (is_array($return)) {
1141  $return[] =& $this->_decode($item);
1142  } else {
1143  $return->{$item->name} =& $this->_decode($item);
1144  }
1145  } elseif (isset($return->{$item->name})) {
1146  $isstruct = false;
1147  if (count(get_object_vars($return)) == 1) {
1148  $d =& $this->_decode($item);
1149  $return = array($return->{$item->name}, $d);
1150  } else {
1151  $d =& $this->_decode($item);
1152  $return->{$item->name} = array($return->{$item->name}, $d);
1153  }
1154  } else {
1155  $return->{$item->name} =& $this->_decode($item);
1156  }
1157  // Set the attributes as members in the class.
1158  if (method_exists($return, '__set_attribute')) {
1159  foreach ($soapval->attributes as $key => $value) {
1160  call_user_func_array(array(&$return,
1161  '__set_attribute'),
1162  array($key, $value));
1163  }
1164  }
1165  } else {
1166  if ($soapval->arrayType && $this->_isSoapValue($item)) {
1167  if ($this->_isBase64Type($item->type) &&
1168  !$this->_isBase64Type($soapval->arrayType)) {
1169  // Decode the value if we're losing the base64
1170  // type information.
1171  $item->value = base64_decode($item->value);
1172  }
1173  $item->type = $soapval->arrayType;
1174  }
1175  if (!$isstruct) {
1176  $return[] = $this->_decode($item);
1177  } elseif (isset($return[$item->name])) {
1178  $isstruct = false;
1179  $d =& $this->_decode($item);
1180  $return = array($return[$item->name], $d);
1181  } else {
1182  $return[$item->name] = $this->_decode($item);
1183  }
1184  }
1185  }
1186 
1187  return $return;
1188  }
1189 
1190  if ($soapval->type == 'boolean') {
1191  if ($soapval->value != '0' &&
1192  strcasecmp($soapval->value, 'false') != 0) {
1193  $soapval->value = true;
1194  } else {
1195  $soapval->value = false;
1196  }
1197  } elseif ($soapval->type &&
1198  isset($this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type])) {
1199  // If we can, set variable type.
1200  settype($soapval->value,
1201  $this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type]);
1202  }
1203 
1204  if ($this->_isBase64Type($soapval->type)) {
1205  return base64_decode($soapval->value);
1206  } else {
1207  return $soapval->value;
1208  }
1209  }
1210 
1223  function _makeEnvelope(&$method, &$headers,
1224  $encoding = SOAP_DEFAULT_ENCODING,
1225  $options = array())
1226  {
1227  $smsg = $header_xml = $ns_string = '';
1228 
1229  if ($headers) {
1230  $c = count($headers);
1231  for ($i = 0; $i < $c; $i++) {
1232  $header_xml .= $headers[$i]->serialize($this);
1233  }
1234  $header_xml = "<SOAP-ENV:Header>\r\n$header_xml\r\n</SOAP-ENV:Header>\r\n";
1235  }
1236 
1237  if (!isset($options['input']) || $options['input'] == 'parse') {
1238  if (is_array($method)) {
1239  $c = count($method);
1240  for ($i = 0; $i < $c; $i++) {
1241  $smsg .= $method[$i]->serialize($this);
1242  }
1243  } else {
1244  $smsg = $method->serialize($this);
1245  }
1246  } else {
1247  $smsg = $method;
1248  }
1249  $body = "<SOAP-ENV:Body>\r\n" . $smsg . "\r\n</SOAP-ENV:Body>\r\n";
1250 
1251  foreach ($this->_namespaces as $k => $v) {
1252  $ns_string .= " xmlns:$v=\"$k\"\r\n";
1253  }
1254  if ($this->_namespace) {
1255  $ns_string .= " xmlns=\"{$this->_namespace}\"\r\n";
1256  }
1257 
1258  /* If 'use' == 'literal', we do not put in the encodingStyle. This is
1259  * denoted by $this->_section5 being false. 'use' can be defined at a
1260  * more granular level than we are dealing with here, so this does not
1261  * work for all services. */
1262  $xml = "<?xml version=\"1.0\" encoding=\"$encoding\"?>\r\n\r\n".
1263  "<SOAP-ENV:Envelope $ns_string".
1264  ($this->_section5 ? ' SOAP-ENV:encodingStyle="' . SOAP_SCHEMA_ENCODING . '"' : '').
1265  ">\r\n".
1266  "$header_xml$body</SOAP-ENV:Envelope>\r\n";
1267 
1268  return $xml;
1269  }
1270 
1271  function _makeMimeMessage(&$xml, $encoding = SOAP_DEFAULT_ENCODING)
1272  {
1273  global $SOAP_options;
1274 
1275  if (!isset($SOAP_options['Mime'])) {
1276  return $this->_raiseSoapFault('Mime is not installed');
1277  }
1278 
1279  // Encode any attachments.
1280  // See http://www.w3.org/TR/SOAP-attachments
1281  // Now we have to mime encode the message.
1282  $params = array('content_type' => 'multipart/related; type=text/xml');
1283  $msg =& new Mail_mimePart('', $params);
1284 
1285  // Add the xml part.
1286  $params['content_type'] = 'text/xml';
1287  $params['charset'] = $encoding;
1288  $params['encoding'] = 'base64';
1289  $msg->addSubPart($xml, $params);
1290 
1291  // Add the attachements
1292  $c = count($this->__attachments);
1293  for ($i = 0; $i < $c; $i++) {
1294  $attachment =& $this->__attachments[$i];
1295  $msg->addSubPart($attachment['body'], $attachment);
1296  }
1297 
1298  return $msg->encode();
1299  }
1300 
1301  // TODO: this needs to be used from the Transport system.
1302  function _makeDIMEMessage($xml)
1303  {
1304  global $SOAP_options;
1305 
1306  if (!isset($SOAP_options['DIME'])) {
1307  return $this->_raiseSoapFault('DIME is not installed');
1308  }
1309 
1310  // Encode any attachments.
1311  // See http://search.ietf.org/internet-drafts/draft-nielsen-dime-soap-00.txt
1312  // Now we have to DIME encode the message
1313  $dime =& new Net_DIME_Message();
1314  $msg = $dime->encodeData($xml, SOAP_ENVELOP, null, NET_DIME_TYPE_URI);
1315 
1316  // Add the attachments.
1317  $c = count($this->__attachments);
1318  for ($i = 0; $i < $c; $i++) {
1319  $attachment =& $this->__attachments[$i];
1320  $msg .= $dime->encodeData($attachment['body'],
1321  $attachment['content_type'],
1322  $attachment['cid'],
1323  NET_DIME_TYPE_MEDIA);
1324  }
1325  $msg .= $dime->endMessage();
1326 
1327  return $msg;
1328  }
1329 
1330  function _decodeMimeMessage(&$data, &$headers, &$attachments)
1331  {
1332  global $SOAP_options;
1333 
1334  if (!isset($SOAP_options['Mime'])) {
1335  $this->_raiseSoapFault('Mime Unsupported, install PEAR::Mail::Mime', '', '', 'Server');
1336  return;
1337  }
1338 
1339  $params['include_bodies'] = true;
1340  $params['decode_bodies'] = true;
1341  $params['decode_headers'] = true;
1342 
1343  // Lame thing to have to do for decoding.
1344  $decoder =& new Mail_mimeDecode($data);
1345  $structure = $decoder->decode($params);
1346 
1347  if (isset($structure->body)) {
1348  $data = $structure->body;
1349  $headers = $structure->headers;
1350 
1351  return;
1352  } elseif (isset($structure->parts)) {
1353  $data = $structure->parts[0]->body;
1354  $headers = array_merge($structure->headers,
1355  $structure->parts[0]->headers);
1356  if (count($structure->parts) > 1) {
1357  $mime_parts = array_splice($structure->parts,1);
1358  // Prepare the parts for the SOAP parser.
1359 
1360  $c = count($mime_parts);
1361  for ($i = 0; $i < $c; $i++) {
1362  $p =& $mime_parts[$i];
1363  if (isset($p->headers['content-location'])) {
1364  // TODO: modify location per SwA note section 3
1365  // http://www.w3.org/TR/SOAP-attachments
1366  $attachments[$p->headers['content-location']] = $p->body;
1367  } else {
1368  $cid = 'cid:' . substr($p->headers['content-id'], 1, -1);
1369  $attachments[$cid] = $p->body;
1370  }
1371  }
1372  }
1373 
1374  return;
1375  }
1376 
1377  $this->_raiseSoapFault('Mime parsing error', '', '', 'Server');
1378  }
1379 
1380  function _decodeDIMEMessage(&$data, &$headers, &$attachments)
1381  {
1382  global $SOAP_options;
1383 
1384  if (!isset($SOAP_options['DIME'])) {
1385  $this->_raiseSoapFault('DIME Unsupported, install PEAR::Net::DIME', '', '', 'Server');
1386  return;
1387  }
1388 
1389  // This SHOULD be moved to the transport layer, e.g. PHP itself should
1390  // handle parsing DIME ;)
1391  $dime =& new Net_DIME_Message();
1392  $err = $dime->decodeData($data);
1393  if (PEAR::isError($err)) {
1394  $this->_raiseSoapFault('Failed to decode the DIME message!', '', '', 'Server');
1395  return;
1396  }
1397  if (strcasecmp($dime->parts[0]['type'], SOAP_ENVELOP) != 0) {
1398  $this->_raiseSoapFault('DIME record 1 is not a SOAP envelop!', '', '', 'Server');
1399  return;
1400  }
1401 
1402  $data = $dime->parts[0]['data'];
1403  // Fake it for now.
1404  $headers['content-type'] = 'text/xml';
1405  $c = count($dime->parts);
1406  for ($i = 0; $i < $c; $i++) {
1407  $part =& $dime->parts[$i];
1408  // We need to handle URI's better.
1409  $id = strncmp($part['id'], 'cid:', 4)
1410  ? 'cid:' . $part['id']
1411  : $part['id'];
1412  $attachments[$id] = $part['data'];
1413  }
1414  }
1415 
1416  function __set_type_translation($type, $class = null)
1417  {
1418  $tq =& new QName($type);
1419  if (!$class) {
1420  $class = $tq->name;
1421  }
1422  $this->_type_translation[$type]=$class;
1423  }
1424 
1425 }
1426 
1434 class QName
1435 {
1436  var $name = '';
1437  var $ns = '';
1438  var $namespace='';
1439 
1440  function QName($name, $namespace = '')
1441  {
1442  if ($name && $name[0] == '{') {
1443  preg_match('/\{(.*?)\}(.*)/', $name, $m);
1444  $this->name = $m[2];
1445  $this->namespace = $m[1];
1446  } elseif (substr_count($name, ':') == 1) {
1447  $s = explode(':', $name);
1448  $s = array_reverse($s);
1449  $this->name = $s[0];
1450  $this->ns = $s[1];
1451  $this->namespace = $namespace;
1452  } else {
1453  $this->name = $name;
1454  $this->namespace = $namespace;
1455  }
1456 
1457  // A little more magic than should be in a qname.
1458  $p = strpos($this->name, '[');
1459  if ($p) {
1460  // TODO: Need to re-examine this logic later.
1461  // Chop off [].
1462  $this->arraySize = explode(',', substr($this->name, $p + 1, -$p - 2));
1463  $this->arrayInfo = substr($this->name, $p);
1464  $this->name = substr($this->name, 0, $p);
1465  }
1466  }
1467 
1468  function fqn()
1469  {
1470  if ($this->namespace) {
1471  return '{' . $this->namespace . '}' . $this->name;
1472  } elseif ($this->ns) {
1473  return $this->ns . ':' . $this->name;
1474  }
1475  return $this->name;
1476  }
1477 
1478 }