00001 <?php
00025 require_once dirname(__FILE__).'/class.ilBMFBase.php';
00026 require_once dirname(__FILE__).'/class.ilBMFFault.php';
00027 require_once 'HTTP/Request.php';
00028
00029 define('WSDL_CACHE_MAX_AGE', 43200);
00030 define('WSDL_CACHE_USE', 0);
00031
00049 class ilBMFWSDL extends ilBMFBase
00050 {
00051 var $tns = null;
00052 var $definition = array();
00053 var $namespaces = array();
00054 var $ns = array();
00055 var $xsd = SOAP_XML_SCHEMA_VERSION;
00056 var $complexTypes = array();
00057 var $elements = array();
00058 var $messages = array();
00059 var $portTypes = array();
00060 var $bindings = array();
00061 var $imports = array();
00062 var $services = array();
00063 var $service = '';
00064 var $uri = '';
00065 var $docs = false;
00066
00072 var $proxy = null;
00073
00074 var $trace = 0;
00075
00081 var $cacheUse = null;
00082
00088 var $cacheMaxAge = null;
00089
00096 var $wsdlParserClass = 'ilBMFWSDL_Parser';
00097
00111 function ilBMFWSDL($wsdl_uri = false,
00112 $proxy = array(),
00113 $cacheUse = WSDL_CACHE_USE,
00114 $cacheMaxAge = WSDL_CACHE_MAX_AGE,
00115 $docs = false)
00116 {
00117 parent::ilBMFBase('WSDL');
00118 $this->uri = $wsdl_uri;
00119 $this->proxy = $proxy;
00120 $this->cacheUse = $cacheUse;
00121 $this->cacheMaxAge = $cacheMaxAge;
00122 $this->docs = $docs;
00123
00124 if ($wsdl_uri) {
00125 if (!PEAR::isError($this->parseURL($wsdl_uri))) {
00126 reset($this->services);
00127 $this->service = key($this->services);
00128 }
00129 }
00130 }
00131
00132 function set_service($service)
00133 {
00134 if (array_key_exists($service, $this->services)) {
00135 $this->service = $service;
00136 }
00137 }
00138
00142 function parse($wsdl_uri, $proxy = array())
00143 {
00144 $this->parseURL($wsdl_uri, $proxy);
00145 }
00146
00154 function parseURL($wsdl_uri, $proxy = array())
00155 {
00156 $parser =& new $this->wsdlParserClass($wsdl_uri, $this, $this->docs);
00157
00158 if ($parser->fault) {
00159 $this->_raiseSoapFault($parser->fault);
00160 }
00161 }
00162
00174 function parseObject(&$wsdl_obj, $targetNamespace, $service_name,
00175 $service_desc = '')
00176 {
00177 $parser =& new ilBMFWSDL_ObjectParser($wsdl_obj, $this,
00178 $targetNamespace, $service_name,
00179 $service_desc);
00180
00181 if ($parser->fault) {
00182 $this->_raiseSoapFault($parser->fault);
00183 }
00184 }
00185
00186 function getEndpoint($portName)
00187 {
00188 if ($this->__isfault()) {
00189 return $this->__getfault();
00190 }
00191
00192 return (isset($this->services[$this->service]['ports'][$portName]['address']['location']))
00193 ? $this->services[$this->service]['ports'][$portName]['address']['location']
00194 : $this->_raiseSoapFault("No endpoint for port for $portName", $this->uri);
00195 }
00196
00197 function _getPortName($operation, $service)
00198 {
00199 if (isset($this->services[$service]['ports'])) {
00200 $ports = $this->services[$service]['ports'];
00201 foreach ($ports as $port => $portAttrs) {
00202 $type = $ports[$port]['type'];
00203 if ($type == 'soap' &&
00204 isset($this->bindings[$portAttrs['binding']]['operations'][$operation])) {
00205 return $port;
00206 }
00207 }
00208 }
00209 return null;
00210 }
00211
00216 function getPortName($operation, $service = null)
00217 {
00218 if ($this->__isfault()) {
00219 return $this->__getfault();
00220 }
00221
00222 if (!$service) {
00223 $service = $this->service;
00224 }
00225 if (isset($this->services[$service]['ports'])) {
00226 if ($portName = $this->_getPortName($operation, $service)) {
00227 return $portName;
00228 }
00229 }
00230
00231 foreach ($this->services as $serviceName => $service) {
00232 if (isset($this->services[$serviceName]['ports'])) {
00233 if ($portName = $this->_getPortName($operation, $serviceName)) {
00234 $this->service = $serviceName;
00235 return $portName;
00236 }
00237 }
00238 }
00239 return $this->_raiseSoapFault("No operation $operation in WSDL.", $this->uri);
00240 }
00241
00242 function getOperationData($portName, $operation)
00243 {
00244 if ($this->__isfault()) {
00245 return $this->__getfault();
00246 }
00247
00248 if (!isset($this->services[$this->service]['ports'][$portName]['binding']) ||
00249 !($binding = $this->services[$this->service]['ports'][$portName]['binding'])) {
00250 return $this->_raiseSoapFault("No binding for port $portName in WSDL.", $this->uri);
00251 }
00252
00253
00254 if (is_array($this->bindings[$binding]['operations'][$operation])) {
00255 $opData = $this->bindings[$binding]['operations'][$operation];
00256 }
00257
00258 $portType = $this->bindings[$binding]['type'];
00259 if (!$portType) {
00260 return $this->_raiseSoapFault("No port type for binding $binding in WSDL.", $this->uri);
00261 }
00262 if (is_array($type = $this->portTypes[$portType][$operation])) {
00263 if (isset($type['parameterOrder'])) {
00264 $opData['parameterOrder'] = $type['parameterOrder'];
00265 }
00266 $opData['input'] = array_merge($opData['input'], $type['input']);
00267 $opData['output'] = array_merge($opData['output'], $type['output']);
00268 }
00269 if (!$opData)
00270 return $this->_raiseSoapFault("No operation $operation for port $portName in WSDL.", $this->uri);
00271 $opData['parameters'] = false;
00272 if (isset($this->bindings[$binding]['operations'][$operation]['input']['namespace']))
00273 $opData['namespace'] = $this->bindings[$binding]['operations'][$operation]['input']['namespace'];
00274
00275 $inputMsg = $opData['input']['message'];
00276 if (is_array($this->messages[$inputMsg])) {
00277 foreach ($this->messages[$inputMsg] as $pname => $pattrs) {
00278 if ($opData['style'] == 'document' &&
00279 $opData['input']['use'] == 'literal' &&
00280 $pname == 'parameters') {
00281 $opData['parameters'] = true;
00282 $opData['namespace'] = $this->namespaces[$pattrs['namespace']];
00283 $el = $this->elements[$pattrs['namespace']][$pattrs['type']];
00284 if (isset($el['elements'])) {
00285 foreach ($el['elements'] as $elname => $elattrs) {
00286 $opData['input']['parts'][$elname] = $elattrs;
00287 }
00288 }
00289 } else {
00290 $opData['input']['parts'][$pname] = $pattrs;
00291 }
00292 }
00293 }
00294 $outputMsg = $opData['output']['message'];
00295 if (is_array($this->messages[$outputMsg])) {
00296 foreach ($this->messages[$outputMsg] as $pname => $pattrs) {
00297 if ($opData['style'] == 'document' &&
00298 $opData['output']['use'] == 'literal' &&
00299 $pname == 'parameters') {
00300
00301 $el = $this->elements[$pattrs['namespace']][$pattrs['type']];
00302 if (isset($el['elements'])) {
00303 foreach ($el['elements'] as $elname => $elattrs) {
00304 $opData['output']['parts'][$elname] = $elattrs;
00305 }
00306 }
00307 } else {
00308 $opData['output']['parts'][$pname] = $pattrs;
00309 }
00310 }
00311 }
00312 return $opData;
00313 }
00314
00315 function matchMethod(&$operation)
00316 {
00317 if ($this->__isfault()) {
00318 return $this->__getfault();
00319 }
00320
00321
00322 foreach ($this->services[$this->service]['ports'] as $port => $portAttrs) {
00323 foreach (array_keys($this->bindings[$portAttrs['binding']]['operations']) as $op) {
00324 if (strcasecmp($op, $operation) == 0) {
00325 $operation = $op;
00326 }
00327 }
00328 }
00329 }
00330
00342 function getDataHandler($datatype, $namespace)
00343 {
00344
00345 if (isset($this->namespaces[$namespace])) {
00346 $namespace = $this->namespaces[$namespace];
00347 }
00348
00349 if (isset($this->ns[$namespace])) {
00350 $nsp = $this->ns[$namespace];
00351
00352
00353 if (isset($this->elements[$nsp][$datatype])) {
00354 $checkmessages = array();
00355
00356 foreach ($this->messages as $messagename => $message) {
00357 foreach ($message as $partname => $part) {
00358 if ($part['type'] == $datatype) {
00359 $checkmessages[] = $messagename;
00360 break;
00361 }
00362 }
00363 }
00364
00365 $dataHandler = null;
00366 foreach($this->portTypes as $portname => $porttype) {
00367 foreach ($porttype as $opname => $opinfo) {
00368 foreach ($checkmessages as $messagename) {
00369 if ($opinfo['input']['message'] == $messagename) {
00370 return $opname;
00371 }
00372 }
00373 }
00374 }
00375 }
00376 }
00377
00378 return null;
00379 }
00380
00381 function getSoapAction($portName, $operation)
00382 {
00383 if ($this->__isfault()) {
00384 return $this->__getfault();
00385 }
00386
00387 if (!empty($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['soapAction'])) {
00388 return $this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['soapAction'];
00389 }
00390
00391 return false;
00392 }
00393
00394 function getNamespace($portName, $operation)
00395 {
00396 if ($this->__isfault()) {
00397 return $this->__getfault();
00398 }
00399
00400 if (!empty($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace'])) {
00401 return $this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace'];
00402 }
00403
00404 return false;
00405 }
00406
00407 function getNamespaceAttributeName($namespace)
00408 {
00409
00410 if (empty($this->ns[$namespace])) {
00411 $this->ns = array_flip($this->namespaces);
00412 }
00413
00414
00415 if (empty($this->ns[$namespace])) {
00416 return $this->addNamespace($namespace);
00417 }
00418
00419 return $this->ns[$namespace];
00420 }
00421
00422 function addNamespace($namespace)
00423 {
00424 if (!empty($this->ns[$namespace])) {
00425 return $this->ns[$namespace];
00426 }
00427
00428 $n = count($this->ns);
00429 $attr = 'ns' . $n;
00430 $this->namespaces['ns' . $n] = $namespace;
00431 $this->ns[$namespace] = $attr;
00432
00433 return $attr;
00434 }
00435
00436 function _validateString($string)
00437 {
00438 return preg_match('/^[\w_:#\/]+$/', $string);
00439 }
00440
00441 function _addArg(&$args, &$argarray, $argname)
00442 {
00443 if ($args) {
00444 $args .= ', ';
00445 }
00446 $args .= '$' . $argname;
00447 if (!$this->_validateString($argname)) {
00448 return;
00449 }
00450 if ($argarray) {
00451 $argarray .= ', ';
00452 }
00453 $argarray .= "'$argname' => $" . $argname;
00454 }
00455
00456 function _elementArg(&$args, &$argarray, &$_argtype, $_argname)
00457 {
00458 $comments = '';
00459 $el = $this->elements[$_argtype['namespace']][$_argtype['type']];
00460 $tns = isset($this->ns[$el['namespace']])
00461 ? $this->ns[$el['namespace']]
00462 : $_argtype['namespace'];
00463
00464 if (!empty($el['complex']) ||
00465 (isset($el['type']) &&
00466 isset($this->complexTypes[$tns][$el['type']]))) {
00467
00468 $comments .= " // {$_argtype['type']} is a ComplexType, refer to the WSDL for more info.\n";
00469 $attrname = "{$_argtype['type']}_attr";
00470 if (isset($el['type']) &&
00471 isset($this->complexTypes[$tns][$el['type']]['attribute'])) {
00472 $comments .= " // {$_argtype['type']} may require attributes, refer to the WSDL for more info.\n";
00473 }
00474 $comments .= " \${$attrname}['xmlns'] = '{$this->namespaces[$_argtype['namespace']]}';\n";
00475 $comments .= " \${$_argtype['type']} =& new ilBMFValue('{$_argtype['type']}', false, \${$_argtype['type']}, \$$attrname);\n";
00476 $this->_addArg($args, $argarray, $_argtype['type']);
00477 if (isset($el['type']) &&
00478 isset($this->complexTypes[$tns][$el['type']]['attribute'])) {
00479 if ($args) {
00480 $args .= ', ';
00481 }
00482 $args .= '$' . $attrname;
00483 }
00484 } elseif (isset($el['elements'])) {
00485 foreach ($el['elements'] as $ename => $element) {
00486 $comments .= " \$$ename =& new ilBMFValue('{{$this->namespaces[$element['namespace']]}}$ename', '" .
00487 (isset($element['type']) ? $element['type'] : false) .
00488 "', \$$ename);\n";
00489 $this->_addArg($args, $argarray, $ename);
00490 }
00491 } else {
00492 $comments .= " \$$_argname =& new ilBMFValue('{{$this->namespaces[$tns]}}$_argname', '{$el['type']}', \$$_argname);\n";
00493 $this->_addArg($args, $argarray, $_argname);
00494 }
00495
00496 return $comments;
00497 }
00498
00499 function _complexTypeArg(&$args, &$argarray, &$_argtype, $_argname)
00500 {
00501 $comments = '';
00502 if (isset($this->complexTypes[$_argtype['namespace']][$_argtype['type']])) {
00503 $comments = " // $_argname is a ComplexType {$_argtype['type']},\n" .
00504 " // refer to wsdl for more info\n";
00505 if (isset($this->complexTypes[$_argtype['namespace']][$_argtype['type']]['attribute'])) {
00506 $comments .= " // $_argname may require attributes, refer to wsdl for more info\n";
00507 }
00508 $wrapname = '{' . $this->namespaces[$_argtype['namespace']].'}' . $_argtype['type'];
00509 $comments .= " \$$_argname =& new ilBMFValue('$_argname', '$wrapname', \$$_argname);\n";
00510 }
00511
00512 $this->_addArg($args, $argarray, $_argname);
00513
00514 return $comments;
00515 }
00516
00521 function generateProxyCode($port = '', $classname = '')
00522 {
00523 if ($this->__isfault()) {
00524 return $this->__getfault();
00525 }
00526
00527 $multiport = count($this->services[$this->service]['ports']) > 1;
00528 if (!$port) {
00529 reset($this->services[$this->service]['ports']);
00530 $port = current($this->services[$this->service]['ports']);
00531 }
00532
00533 if ($port['type'] != 'soap') {
00534 return null;
00535 }
00536
00537
00538 $clienturl = $port['address']['location'];
00539 if (!$classname) {
00540 if ($multiport || $port) {
00541 $classname = 'WebService_' . $this->service . '_' . $port['name'];
00542 } else {
00543 $classname = 'WebService_' . $this->service;
00544 }
00545 $classname = preg_replace('/[ .\-\(\)]+/', '_', $classname);
00546 }
00547
00548 if (!$this->_validateString($classname)) {
00549 return null;
00550 }
00551
00552 if (is_array($this->proxy) && count($this->proxy)) {
00553 $class = "class $classname extends ilBMFClient\n{\n" .
00554 " function $classname(\$path = '$clienturl')\n {\n" .
00555 " \$this->ilBMFClient(\$path, 0, 0,\n" .
00556 ' array(';
00557
00558 foreach ($this->proxy as $key => $val) {
00559 if (is_array($val)) {
00560 $class .= "'$key' => array(";
00561 foreach ($val as $key2 => $val2) {
00562 $class .= "'$key2' => '$val2', ";
00563 }
00564 $class .= ')';
00565 } else {
00566 $class .= "'$key' => '$val', ";
00567 }
00568 }
00569 $class .= "));\n }\n";
00570 $class = str_replace(', ))', '))', $class);
00571 } else {
00572 $class = "class $classname extends ilBMFClient\n{\n" .
00573 " function $classname(\$path = '$clienturl')\n {\n" .
00574 " \$this->ilBMFClient(\$path, 0);\n" .
00575 " }\n";
00576 }
00577
00578
00579 $primaryBinding = $port['binding'];
00580 $primaryBinding = preg_replace("/^(.*:)/", '', $primaryBinding);
00581 $portType = $this->bindings[$primaryBinding]['type'];
00582 $portType = preg_replace("/^(.*:)/", '', $portType);
00583 $style = $this->bindings[$primaryBinding]['style'];
00584
00585
00586 foreach ($this->portTypes[$portType] as $opname => $operation) {
00587 $binding = $this->bindings[$primaryBinding]['operations'][$opname];
00588 if (isset($binding['soapAction'])) {
00589 $soapaction = $binding['soapAction'];
00590 } else {
00591 $soapaction = null;
00592 }
00593 if (isset($binding['style'])) {
00594 $opstyle = $binding['style'];
00595 } else {
00596 $opstyle = $style;
00597 }
00598 $use = $binding['input']['use'];
00599 if ($use == 'encoded') {
00600 $namespace = $binding['input']['namespace'];
00601 } else {
00602 $bindingType = $this->bindings[$primaryBinding]['type'];
00603 $ns = $this->portTypes[$bindingType][$opname]['input']['namespace'];
00604 $namespace = $this->namespaces[$ns];
00605 }
00606
00607 $args = '';
00608 $argarray = '';
00609 $comments = '';
00610 $wrappers = '';
00611 foreach ($operation['input'] as $argname => $argtype) {
00612 if ($argname == 'message') {
00613 foreach ($this->messages[$argtype] as $_argname => $_argtype) {
00614 if ($opstyle == 'document' && $use == 'literal' &&
00615 $_argtype['name'] == 'parameters') {
00616
00617
00618 $elattrs = null;
00619 $element = $_argtype['element'];
00620 $el = $this->elements[$_argtype['namespace']][$_argtype['type']];
00621
00622 if ($el['complex']) {
00623 $namespace = $this->namespaces[$_argtype['namespace']];
00624
00625
00626 }
00627 if (isset($el['elements'])) {
00628 foreach ($el['elements'] as $elname => $elattrs) {
00629
00630 if (isset($this->complexTypes[$elattrs['namespace']][$elname])) {
00631 $comments .= $this->_complexTypeArg($args, $argarray, $_argtype, $_argname);
00632 } else {
00633 $this->_addArg($args, $argarray, $elname);
00634 }
00635 }
00636 }
00637 if ($el['complex'] && $argarray) {
00638 $wrapname = '{' . $this->namespaces[$_argtype['namespace']].'}' . $el['name'];
00639 $comments .= " \${$el['name']} =& new ilBMFValue('$wrapname', false, \$v = array($argarray));\n";
00640 $argarray = "'{$el['name']}' => \${$el['name']}";
00641 }
00642 } else {
00643 if (isset($_argtype['element'])) {
00644
00645 $comments .= $this->_elementArg($args, $argarray, $_argtype, $_argtype['type']);
00646 } else {
00647
00648 $comments .= $this->_complexTypeArg($args, $argarray, $_argtype, $_argname);
00649 }
00650 }
00651 }
00652 }
00653 }
00654
00655
00656
00657
00658
00659
00660
00661 $opname_php = preg_replace('/[ .\-\(\)]+/', '_', $opname);
00662 if (!$this->_validateString($opname_php)) {
00663 return null;
00664 }
00665
00666 if ($argarray) {
00667 $argarray = "array($argarray)";
00668 } else {
00669 $argarray = 'null';
00670 }
00671
00672 $class .= " function &$opname_php($args)\n {\n$comments$wrappers" .
00673 " \$result = \$this->call('$opname',\n" .
00674 " \$v = $argarray,\n" .
00675 " array('namespace' => '$namespace',\n" .
00676 " 'soapaction' => '$soapaction',\n" .
00677 " 'style' => '$opstyle',\n" .
00678 " 'use' => '$use'" .
00679 ($this->trace?",\n 'trace' => 1" : '') . "));\n" .
00680 " return \$result;\n" .
00681 " }\n";
00682 }
00683
00684 $class .= "}\n";
00685
00686 return $class;
00687 }
00688
00689 function generateAllProxies()
00690 {
00691 $proxycode = '';
00692 foreach (array_keys($this->services[$this->service]['ports']) as $key) {
00693 $port =& $this->services[$this->service]['ports'][$key];
00694 $proxycode .= $this->generateProxyCode($port);
00695 }
00696 return $proxycode;
00697 }
00698
00699 function &getProxy($port = '', $name = '')
00700 {
00701 if ($this->__isfault()) {
00702 $fault =& $this->__getfault();
00703 return $fault;
00704 }
00705
00706 $multiport = count($this->services[$this->service]['ports']) > 1;
00707
00708 if (!$port) {
00709 reset($this->services[$this->service]['ports']);
00710 $port = current($this->services[$this->service]['ports']);
00711 }
00712
00713 if ($multiport || $port) {
00714 $classname = 'WebService_' . $this->service . '_' . $port['name'];
00715 } else {
00716 $classname = 'WebService_' . $this->service;
00717 }
00718
00719 if ($name) {
00720 $classname = $name . '_' . $classname;
00721 }
00722
00723 $classname = preg_replace('/[ .\-\(\)]+/', '_', $classname);
00724 if (!class_exists($classname)) {
00725 $proxy = $this->generateProxyCode($port, $classname);
00726 require_once 'SOAP/Client.php';
00727 eval($proxy);
00728 }
00729 $proxy =& new $classname;
00730
00731 return $proxy;
00732 }
00733
00734 function &_getComplexTypeForElement($name, $namespace)
00735 {
00736 $t = null;
00737 if (isset($this->ns[$namespace]) &&
00738 isset($this->elements[$this->ns[$namespace]][$name]['type'])) {
00739
00740 $type = $this->elements[$this->ns[$namespace]][$name]['type'];
00741 $ns = $this->elements[$this->ns[$namespace]][$name]['namespace'];
00742
00743 if (isset($this->complexTypes[$ns][$type])) {
00744 $t = $this->complexTypes[$ns][$type];
00745 }
00746 }
00747 return $t;
00748 }
00749
00750 function getComplexTypeNameForElement($name, $namespace)
00751 {
00752 $t = $this->_getComplexTypeForElement($name, $namespace);
00753 if ($t) {
00754 return $t['name'];
00755 }
00756 return null;
00757 }
00758
00759 function getComplexTypeChildType($ns, $name, $child_ns, $child_name)
00760 {
00761
00762 $t = $this->_getComplexTypeForElement($name, $ns);
00763 if ($t) {
00764
00765 if (isset($t['elements'][$child_name]['type']))
00766 return $t['elements'][$child_name]['type'];
00767 }
00768 return null;
00769 }
00770
00771 function getSchemaType($type, $name, $type_namespace)
00772 {
00773
00774
00775 if ($name && $type) {
00776
00777
00778 foreach ($this->complexTypes as $ns => $types) {
00779 if (array_key_exists($type, $types)) {
00780 if (array_key_exists('type', $types[$type])) {
00781 list($arraytype_ns, $arraytype, $array_depth) = isset($types[$type]['arrayType'])?
00782 $this->_getDeepestArrayType($types[$type]['namespace'], $types[$type]['arrayType'])
00783 : array($this->namespaces[$types[$type]['namespace']], null, 0);
00784 return array($types[$type]['type'], $arraytype, $arraytype_ns, $array_depth);
00785 }
00786 if (array_key_exists('arrayType', $types[$type])) {
00787 list($arraytype_ns, $arraytype, $array_depth) =
00788 $this->_getDeepestArrayType($types[$type]['namespace'], $types[$type]['arrayType']);
00789 return array('Array', $arraytype, $arraytype_ns, $array_depth);
00790 }
00791 if (array_key_exists('elements', $types[$type]) &&
00792 array_key_exists($name, $types[$type]['elements'])) {
00793 $type = $types[$type]['elements']['type'];
00794 return array($type, null, $this->namespaces[$types[$type]['namespace']], null);
00795 }
00796 }
00797 }
00798 }
00799 if ($type && $type_namespace) {
00800 $arrayType = null;
00801
00802
00803
00804 $p = $this->ns[$type_namespace];
00805 if ($p &&
00806 array_key_exists($p, $this->complexTypes) &&
00807 array_key_exists($type, $this->complexTypes[$p])) {
00808 if ($arrayType = $this->complexTypes[$p][$type]['arrayType']) {
00809 $type = 'Array';
00810 } elseif ($this->complexTypes[$p][$type]['order']=='sequence' &&
00811 array_key_exists('elements', $this->complexTypes[$p][$type])) {
00812 reset($this->complexTypes[$p][$type]['elements']);
00813
00814 if (count($this->complexTypes[$p][$type]['elements']) == 1) {
00815 $arg = current($this->complexTypes[$p][$type]['elements']);
00816 $arrayType = $arg['type'];
00817 $type = 'Array';
00818 } else {
00819 foreach ($this->complexTypes[$p][$type]['elements'] as $element) {
00820 if ($element['name'] == $type) {
00821 $arrayType = $element['type'];
00822 $type = $element['type'];
00823 }
00824 }
00825 }
00826 } else {
00827 $type = 'Struct';
00828 }
00829 return array($type, $arrayType, $type_namespace, null);
00830 }
00831 }
00832 return array(null, null, null, null);
00833 }
00834
00846 function _getDeepestArrayType($nsPrefix, $arrayType)
00847 {
00848 static $trail = array();
00849
00850 $arrayType = ereg_replace('\[\]$', '', $arrayType);
00851
00852
00853
00854
00855
00856 if (array_search($nsPrefix . ':' . $arrayType, $trail)) {
00857 return array(null, null, -count($trail));
00858 }
00859
00860 if (array_key_exists($nsPrefix, $this->complexTypes) &&
00861 array_key_exists($arrayType, $this->complexTypes[$nsPrefix]) &&
00862 array_key_exists('arrayType', $this->complexTypes[$nsPrefix][$arrayType])) {
00863 $trail[] = $nsPrefix . ':' . $arrayType;
00864 $result = $this->_getDeepestArrayType($this->complexTypes[$nsPrefix][$arrayType]['namespace'],
00865 $this->complexTypes[$nsPrefix][$arrayType]['arrayType']);
00866 return array($result[0], $result[1], $result[2] + 1);
00867 }
00868 return array($this->namespaces[$nsPrefix], $arrayType, 0);
00869 }
00870
00871 }
00872
00873 class ilBMFWSDL_Cache extends ilBMFBase
00874 {
00875
00876
00882 var $_cacheUse = null;
00883
00889 var $_cacheMaxAge = null;
00890
00898 function ilBMFWSDL_Cache($cacheUse = WSDL_CACHE_USE,
00899 $cacheMaxAge = WSDL_CACHE_MAX_AGE)
00900 {
00901 parent::ilBMFBase('WSDLCACHE');
00902 $this->_cacheUse = $cacheUse;
00903 $this->_cacheMaxAge = $cacheMaxAge;
00904 }
00905
00910 function _cacheDir()
00911 {
00912 $dir = getenv("WSDLCACHE");
00913 if (!$dir) $dir = " ./wsdlcache";
00914 @mkdir($dir, 0700);
00915 return $dir;
00916 }
00917
00928 function get($wsdl_fname, $proxy_params = array(), $cache = 0)
00929 {
00930 $cachename = $md5_wsdl = $file_data = '';
00931 if ($this->_cacheUse) {
00932
00933 $cachename = ilBMFWSDL_Cache::_cacheDir() . '/' . md5($wsdl_fname). ' .wsdl';
00934 if (file_exists($cachename)) {
00935 $wf = fopen($cachename, 'rb');
00936 if ($wf) {
00937
00938 $file_data = fread($wf, filesize($cachename));
00939 $md5_wsdl = md5($file_data);
00940 fclose($wf);
00941 }
00942 if ($cache) {
00943 if ($cache != $md5_wsdl) {
00944 return $this->_raiseSoapFault('WSDL Checksum error!', $wsdl_fname);
00945 }
00946 } else {
00947 $fi = stat($cachename);
00948 $cache_mtime = $fi[8];
00949
00950 if ($cache_mtime + $this->_cacheMaxAge < time()) {
00951
00952 $md5_wsdl = '';
00953 }
00954 }
00955 }
00956 }
00957
00958 if (!$md5_wsdl) {
00959
00960
00961
00962
00963 if (!preg_match('/^(https?|file):\/\//', $wsdl_fname)) {
00964 if (!file_exists($wsdl_fname)) {
00965 return $this->_raiseSoapFault("Unable to read local WSDL $wsdl_fname", $wsdl_fname);
00966 }
00967 if (function_exists('file_get_contents')) {
00968 $file_data = file_get_contents($wsdl_fname);
00969 } else {
00970 $file_data = implode('',file($wsdl_fname));
00971 }
00972 } else {
00973 $uri = explode('?', $wsdl_fname);
00974 $rq =& new HTTP_Request($uri[0], $proxy_params);
00975
00976 if (isset($uri[1])) {
00977 $rq->addRawQueryString($uri[1]);
00978 }
00979
00980 if (isset($proxy_params['proxy_host']) &&
00981 isset($proxy_params['proxy_port']) &&
00982 isset($proxy_params['proxy_user']) &&
00983 isset($proxy_params['proxy_pass'])) {
00984 $rq->setProxy($proxy_params['proxy_host'], $proxy_params['proxy_port'],
00985 $proxy_params['proxy_user'], $proxy_params['proxy_pass']);
00986 } elseif (isset($proxy_params['proxy_host']) &&
00987 isset($proxy_params['proxy_port'])) {
00988 $rq->setProxy($proxy_params['proxy_host'], $proxy_params['proxy_port']);
00989 }
00990
00991 $result = $rq->sendRequest();
00992 if (PEAR::isError($result)) {
00993 return $this->_raiseSoapFault("Unable to retrieve WSDL $wsdl_fname," . $rq->getResponseCode(), $wsdl_fname);
00994 }
00995 $file_data = $rq->getResponseBody();
00996 if (!$file_data) {
00997 return $this->_raiseSoapFault("Unable to retrieve WSDL $wsdl_fname, no http body", $wsdl_fname);
00998 }
00999 }
01000
01001 $md5_wsdl = md5($file_data);
01002
01003 if ($this->_cacheUse) {
01004 $fp = fopen($cachename, "wb");
01005 fwrite($fp, $file_data);
01006 fclose($fp);
01007 }
01008 }
01009 if ($this->_cacheUse && $cache && $cache != $md5_wsdl) {
01010 return $this->_raiseSoapFault("WSDL Checksum error!", $wsdl_fname);
01011 }
01012 return $file_data;
01013 }
01014
01015 }
01016
01017 class ilBMFWSDL_Parser extends ilBMFBase
01018 {
01019
01024 var $currentMessage;
01025 var $currentOperation;
01026 var $currentPortType;
01027 var $currentBinding;
01028 var $currentPort;
01029
01033 var $cache;
01034
01035 var $tns = null;
01036 var $soapns = array('soap');
01037 var $uri = '';
01038 var $wsdl = null;
01039
01040 var $status = '';
01041 var $element_stack = array();
01042 var $parentElement = '';
01043
01044 var $schema = '';
01045 var $schemaStatus = '';
01046 var $schema_stack = array();
01047 var $currentComplexType;
01048 var $schema_element_stack = array();
01049 var $currentElement;
01050
01054 function ilBMFWSDL_Parser($uri, &$wsdl, $docs = false)
01055 {
01056 parent::ilBMFBase('WSDLPARSER');
01057 $this->cache =& new ilBMFWSDL_Cache($wsdl->cacheUse, $wsdl->cacheMaxAge);
01058 $this->uri = $uri;
01059 $this->wsdl = &$wsdl;
01060 $this->docs = $docs;
01061 $this->parse($uri);
01062 }
01063
01064 function parse($uri)
01065 {
01066
01067 $fd = $this->cache->get($uri, $this->wsdl->proxy);
01068 if (PEAR::isError($fd)) {
01069 return $this->_raiseSoapFault($fd);
01070 }
01071
01072
01073 $parser = xml_parser_create();
01074 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
01075 xml_set_object($parser, $this);
01076 xml_set_element_handler($parser, 'startElement', 'endElement');
01077 if ($this->docs) {
01078 xml_set_character_data_handler($parser, 'characterData');
01079 }
01080
01081 if (!xml_parse($parser, $fd, true)) {
01082 $detail = sprintf('XML error on line %d: %s',
01083 xml_get_current_line_number($parser),
01084 xml_error_string(xml_get_error_code($parser)));
01085 return $this->_raiseSoapFault("Unable to parse WSDL file $uri\n$detail");
01086 }
01087 xml_parser_free($parser);
01088 return true;
01089 }
01090
01094 function startElement($parser, $name, $attrs)
01095 {
01096
01097 $qname =& new QName($name);
01098 if ($qname->ns) {
01099 $ns = $qname->ns;
01100 if ($ns && ((!$this->tns && strcasecmp($qname->name, 'definitions') == 0) || $ns == $this->tns)) {
01101 $name = $qname->name;
01102 }
01103 }
01104 $this->currentTag = $qname->name;
01105 $this->parentElement = '';
01106 $stack_size = count($this->element_stack);
01107 if ($stack_size) {
01108 $this->parentElement = $this->element_stack[$stack_size - 1];
01109 }
01110 $this->element_stack[] = $this->currentTag;
01111
01112
01113 switch ($this->status) {
01114 case 'types':
01115
01116
01117 $parent_tag = '';
01118 $stack_size = count($this->schema_stack);
01119 if ($stack_size) {
01120 $parent_tag = $this->schema_stack[$stack_size - 1];
01121 }
01122
01123 switch ($qname->name) {
01124 case 'schema':
01125
01126 if (!$parent_tag || $parent_tag == 'types') {
01127 if (array_key_exists('targetNamespace', $attrs)) {
01128 $this->schema = $this->wsdl->getNamespaceAttributeName($attrs['targetNamespace']);
01129 } else {
01130 $this->schema = $this->wsdl->getNamespaceAttributeName($this->wsdl->tns);
01131 }
01132 $this->wsdl->complexTypes[$this->schema] = array();
01133 $this->wsdl->elements[$this->schema] = array();
01134 }
01135 break;
01136
01137 case 'complexType':
01138 if ($parent_tag == 'schema') {
01139 $this->currentComplexType = $attrs['name'];
01140 if (!isset($attrs['namespace'])) {
01141 $attrs['namespace'] = $this->schema;
01142 }
01143 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType] = $attrs;
01144 if (array_key_exists('base', $attrs)) {
01145 $qn =& new QName($attrs['base']);
01146 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = $qn->name;
01147 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'] = $qn->ns;
01148 } else {
01149 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
01150 }
01151 $this->schemaStatus = 'complexType';
01152 } else {
01153 $this->wsdl->elements[$this->schema][$this->currentElement]['complex'] = true;
01154 }
01155 break;
01156
01157 case 'element':
01158 if (isset($attrs['type'])) {
01159 $qn =& new QName($attrs['type']);
01160 $attrs['type'] = $qn->name;
01161 if ($qn->ns && array_key_exists($qn->ns, $this->wsdl->namespaces)) {
01162 $attrs['namespace'] = $qn->ns;
01163 }
01164 }
01165
01166 $parentElement = '';
01167 $stack_size = count($this->schema_element_stack);
01168 if ($stack_size > 0) {
01169 $parentElement = $this->schema_element_stack[$stack_size - 1];
01170 }
01171
01172 if (isset($attrs['ref'])) {
01173 $qn =& new QName($attrs['ref']);
01174 $this->currentElement = $qn->name;
01175 } else {
01176 $this->currentElement = $attrs['name'];
01177 }
01178 $this->schema_element_stack[] = $this->currentElement;
01179 if (!isset($attrs['namespace'])) {
01180 $attrs['namespace'] = $this->schema;
01181 }
01182
01183 if ($parent_tag == 'schema') {
01184 $this->wsdl->elements[$this->schema][$this->currentElement] = $attrs;
01185 $this->wsdl->elements[$this->schema][$this->currentElement]['complex'] = false;
01186 $this->schemaStatus = 'element';
01187 } elseif ($this->currentComplexType) {
01188
01189 if ((isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order']) &&
01190 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] == 'sequence')
01191 && $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] == 'Array') {
01192 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['arrayType'] = isset($attrs['type']) ? $attrs['type'] : null;
01193 }
01194 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements'][$this->currentElement] = $attrs;
01195 } else {
01196 $this->wsdl->elements[$this->schema][$parentElement]['elements'][$this->currentElement] = $attrs;
01197 }
01198 break;
01199
01200 case 'complexContent':
01201 case 'simpleContent':
01202 break;
01203
01204 case 'extension':
01205 case 'restriction':
01206 if ($this->schemaStatus == 'complexType') {
01207 if (!empty($attrs['base'])) {
01208 $qn =& new QName($attrs['base']);
01209 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = $qn->name;
01210
01211
01212
01213
01214
01215
01216 if ($qname->name == 'extension') {
01217 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['extends'] = $qn->name;
01218 }
01219 } else {
01220 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
01221 }
01222 }
01223 break;
01224
01225 case 'sequence':
01226 if ($this->schemaStatus == 'complexType') {
01227 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name;
01228 if (!isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])) {
01229 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array';
01230 }
01231 }
01232 break;
01233
01234 case 'all':
01235 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name;
01236 if (!isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])) {
01237 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
01238 }
01239 break;
01240
01241 case 'choice':
01242 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name;
01243 if (!isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])) {
01244 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array';
01245 }
01246
01247 case 'attribute':
01248 if ($this->schemaStatus == 'complexType') {
01249 if (isset($attrs['name'])) {
01250 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['attribute'][$attrs['name']] = $attrs;
01251 } else {
01252 if (isset($attrs['ref'])) {
01253 $q =& new QName($attrs['ref']);
01254 foreach ($attrs as $k => $v) {
01255 if ($k != 'ref' && strstr($k, $q->name)) {
01256 $vq =& new QName($v);
01257 if ($q->name == 'arrayType') {
01258 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType][$q->name] = $vq->name. $vq->arrayInfo;
01259 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array';
01260 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'] = $vq->ns;
01261 } else {
01262 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType][$q->name] = $vq->name;
01263 }
01264 }
01265 }
01266 }
01267 }
01268 }
01269 break;
01270 }
01271
01272 $this->schema_stack[] = $qname->name;
01273 break;
01274
01275 case 'message':
01276
01277 switch ($qname->name) {
01278 case 'part':
01279 $qn = null;
01280 if (isset($attrs['type'])) {
01281 $qn =& new QName($attrs['type']);
01282 } elseif (isset($attrs['element'])) {
01283 $qn =& new QName($attrs['element']);
01284 }
01285 if ($qn) {
01286 $attrs['type'] = $qn->name;
01287 $attrs['namespace'] = $qn->ns;
01288 }
01289 $this->wsdl->messages[$this->currentMessage][$attrs['name']] = $attrs;
01290
01291
01292 case 'documentation':
01293 break;
01294
01295 default:
01296 break;
01297 }
01298 break;
01299
01300 case 'portType':
01301
01302 switch ($qname->name) {
01303 case 'operation':
01304
01305
01306 $this->currentOperation = $attrs['name'];
01307 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation] = $attrs;
01308 break;
01309
01310 case 'input':
01311 case 'output':
01312 case 'fault':
01313
01314
01315 if ($this->currentOperation) {
01316 if (isset($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name])) {
01317 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name] = array_merge($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name], $attrs);
01318 } else {
01319 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name] = $attrs;
01320 }
01321 if (array_key_exists('message', $attrs)) {
01322 $qn =& new QName($attrs['message']);
01323 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name]['message'] = $qn->name;
01324 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name]['namespace'] = $qn->ns;
01325 }
01326 }
01327 break;
01328
01329 case 'documentation':
01330 break;
01331
01332 default:
01333 break;
01334 }
01335 break;
01336
01337 case 'binding':
01338 $ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL;
01339 switch ($ns) {
01340 case SCHEMA_SOAP:
01341
01342 switch ($qname->name) {
01343 case 'binding':
01344
01345
01346
01347 if (!isset($attrs['style'])) {
01348 $attrs['style'] = 'document';
01349 }
01350 $this->wsdl->bindings[$this->currentBinding] = array_merge($this->wsdl->bindings[$this->currentBinding], $attrs);
01351 break;
01352
01353 case 'operation':
01354
01355
01356 if (!isset($attrs['style'])) {
01357 $attrs['style'] = $this->wsdl->bindings[$this->currentBinding]['style'];
01358 }
01359 if (isset($this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation])) {
01360 $this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation] = array_merge($this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation], $attrs);
01361 } else {
01362 $this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation] = $attrs;
01363 }
01364 break;
01365
01366 case 'body':
01367
01368
01369
01370
01371
01372 $this->wsdl->bindings[$this->currentBinding]
01373 ['operations'][$this->currentOperation][$this->opStatus] = $attrs;
01374 break;
01375
01376 case 'fault':
01377
01378
01379 $this->wsdl->bindings[$this->currentBinding]
01380 ['operations'][$this->currentOperation][$this->opStatus] = $attrs;
01381 break;
01382
01383 case 'header':
01384
01385
01386 $this->wsdl->bindings[$this->currentBinding]
01387 ['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
01388 break;
01389
01390 case 'headerfault':
01391
01392
01393 $header = count($this->wsdl->bindings[$this->currentBinding]
01394 ['operations'][$this->currentOperation][$this->opStatus]['headers'])-1;
01395 $this->wsdl->bindings[$this->currentBinding]
01396 ['operations'][$this->currentOperation][$this->opStatus]['headers'][$header]['fault'] = $attrs;
01397 break;
01398
01399 case 'documentation':
01400 break;
01401
01402 default:
01403
01404 break;
01405 }
01406 break;
01407
01408 case SCHEMA_WSDL:
01409
01410
01411
01412 switch ($qname->name) {
01413 case 'operation':
01414
01415
01416 $this->currentOperation = $attrs['name'];
01417 break;
01418
01419 case 'output':
01420 case 'input':
01421 case 'fault':
01422
01423
01424 $this->opStatus = $qname->name;
01425 break;
01426
01427 case 'documentation':
01428 break;
01429
01430 default:
01431 break;
01432 }
01433 break;
01434
01435 case SCHEMA_WSDL_HTTP:
01436 switch ($qname->name) {
01437 case 'binding':
01438
01439
01440
01441 $this->wsdl->bindings[$this->currentBinding] = array_merge($this->wsdl->bindings[$this->currentBinding], $attrs);
01442 break;
01443
01444 case 'operation':
01445
01446
01447
01448 $this->wsdl->bindings[$this->currentBinding]['operations']
01449 [$this->currentOperation] = $attrs;
01450 break;
01451
01452 case 'urlEncoded':
01453
01454
01455
01456 $this->wsdl->bindings[$this->currentBinding]['operations'][$this->opStatus]
01457 [$this->currentOperation]['uri'] = 'urlEncoded';
01458 break;
01459
01460 case 'urlReplacement':
01461
01462
01463
01464 $this->wsdl->bindings[$this->currentBinding]['operations'][$this->opStatus]
01465 [$this->currentOperation]['uri'] = 'urlReplacement';
01466 break;
01467
01468 case 'documentation':
01469 break;
01470
01471 default:
01472
01473 break;
01474 }
01475
01476 case SCHEMA_MIME:
01477
01478
01479
01480 switch ($qname->name) {
01481 case 'content':
01482
01483
01484
01485
01486
01487 case 'multipartRelated':
01488
01489 case 'part':
01490 case 'mimeXml':
01491
01492
01493
01494 case 'documentation':
01495 break;
01496
01497 default:
01498
01499 break;
01500 }
01501
01502 case SCHEMA_DIME:
01503
01504
01505
01506
01507 switch ($qname->name) {
01508 case 'message':
01509
01510
01511 $this->wsdl->bindings[$this->currentBinding]['dime'] = $attrs;
01512 break;
01513
01514 default:
01515 break;
01516 }
01517
01518 default:
01519 break;
01520 }
01521 break;
01522
01523 case 'service':
01524 $ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL;
01525
01526 switch ($qname->name) {
01527 case 'port':
01528
01529 $this->currentPort = $attrs['name'];
01530 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort] = $attrs;
01531
01532 $qn =& new QName($attrs['binding']);
01533 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['binding'] = $qn->name;
01534 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['namespace'] = $qn->ns;
01535 break;
01536
01537 case 'address':
01538 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['address'] = $attrs;
01539
01540 $ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL;
01541 switch ($ns) {
01542 case SCHEMA_WSDL_HTTP:
01543 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='http';
01544 break;
01545
01546 case SCHEMA_SOAP:
01547 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='soap';
01548 break;
01549
01550 default:
01551
01552 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='soap';
01553 }
01554
01555 break;
01556
01557 case 'documentation':
01558 break;
01559
01560 default:
01561 break;
01562 }
01563 }
01564
01565
01566 switch ($qname->name) {
01567 case 'import':
01568
01569 if ((isset($attrs['location']) || isset($attrs['schemaLocation'])) &&
01570 !isset($this->wsdl->imports[$attrs['namespace']])) {
01571 $uri = isset($attrs['location']) ? $attrs['location'] : $attrs['schemaLocation'];
01572 $location = @parse_url($uri);
01573 if (!isset($location['scheme'])) {
01574 $base = @parse_url($this->uri);
01575 $uri = $this->mergeUrl($base, $uri);
01576 }
01577
01578 $this->wsdl->imports[$attrs['namespace']] = $attrs;
01579 $import_parser_class = get_class($this);
01580 $import_parser =& new $import_parser_class($uri, $this->wsdl, $this->docs);
01581 if ($import_parser->fault) {
01582 unset($this->wsdl->imports[$attrs['namespace']]);
01583 return false;
01584 }
01585 $this->currentImport = $attrs['namespace'];
01586 }
01587
01588
01589
01590 case 'types':
01591
01592 $this->status = 'types';
01593 break;
01594
01595 case 'schema':
01596
01597
01598 if (!empty($attrs['targetNamespace'])) {
01599 $this->schema = $this->wsdl->getNamespaceAttributeName($attrs['targetNamespace']);
01600 } else {
01601 $this->schema = $this->wsdl->getNamespaceAttributeName($this->wsdl->tns);
01602 }
01603 $this->wsdl->complexTypes[$this->schema] = array();
01604 $this->wsdl->elements[$this->schema] = array();
01605 $this->schema_stack[] = $qname->name;
01606 $this->status = 'types';
01607 break;
01608
01609 case 'message':
01610
01611 $this->status = 'message';
01612 if (isset($attrs['name'])) {
01613 $this->currentMessage = $attrs['name'];
01614 $this->wsdl->messages[$this->currentMessage] = array();
01615 }
01616 break;
01617
01618 case 'portType':
01619
01620
01621
01622 $this->status = 'portType';
01623 $this->currentPortType = $attrs['name'];
01624 $this->wsdl->portTypes[$this->currentPortType] = array();
01625 break;
01626
01627 case 'binding':
01628
01629
01630 if ($qname->ns && $qname->ns != $this->tns) {
01631 break;
01632 }
01633 $this->status = 'binding';
01634 $this->currentBinding = $attrs['name'];
01635 $qn =& new QName($attrs['type']);
01636 $this->wsdl->bindings[$this->currentBinding]['type'] = $qn->name;
01637 $this->wsdl->bindings[$this->currentBinding]['namespace'] = $qn->ns;
01638 break;
01639
01640 case 'service':
01641
01642 $this->currentService = $attrs['name'];
01643 $this->wsdl->services[$this->currentService]['ports'] = array();
01644 $this->status = 'service';
01645 break;
01646
01647 case 'definitions':
01648
01649
01650
01651 $this->wsdl->definition = $attrs;
01652 foreach ($attrs as $key => $value) {
01653 if (strstr($key, 'xmlns:') !== false) {
01654 $qn =& new QName($key);
01655
01656 $this->wsdl->namespaces[$qn->name] = $value;
01657 $this->wsdl->ns[$value] = $qn->name;
01658 if ($key == 'targetNamespace' ||
01659 strcasecmp($value,SOAP_SCHEMA) == 0) {
01660 $this->soapns[] = $qn->name;
01661 } else {
01662 if (in_array($value, $this->_XMLSchema)) {
01663 $this->wsdl->xsd = $value;
01664 }
01665 }
01666 }
01667 }
01668 if (isset($ns) && $ns) {
01669 $namespace = 'xmlns:' . $ns;
01670 if (!$this->wsdl->definition[$namespace]) {
01671 return $this->_raiseSoapFault("parse error, no namespace for $namespace", $this->uri);
01672 }
01673 $this->tns = $ns;
01674 }
01675 break;
01676 }
01677 }
01678
01682 function endElement($parser, $name)
01683 {
01684 $stacksize = count($this->element_stack);
01685 if ($stacksize) {
01686 if ($this->element_stack[$stacksize - 1] == 'definitions') {
01687 $this->status = '';
01688 }
01689 array_pop($this->element_stack);
01690 }
01691
01692 if (stristr($name, 'schema')) {
01693 array_pop($this->schema_stack);
01694 $this->schema = '';
01695 }
01696
01697 if ($this->schema) {
01698 array_pop($this->schema_stack);
01699 if (count($this->schema_stack) <= 1) {
01700
01701
01702 if (isset($this->currentComplexType) && isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])
01703 && $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] == 'Array'
01704 && array_key_exists('elements', $this->wsdl->complexTypes[$this->schema][$this->currentComplexType])
01705 && count($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements']) > 1) {
01706 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
01707 }
01708 }
01709 if (stristr($name, 'complexType')) {
01710 $this->currentComplexType = '';
01711 if (count($this->schema_element_stack)) {
01712 $this->currentElement = array_pop($this->schema_element_stack);
01713 } else {
01714 $this->currentElement = '';
01715 }
01716 } elseif (stristr($name, 'element')) {
01717 if (count($this->schema_element_stack)) {
01718 $this->currentElement = array_pop($this->schema_element_stack);
01719 } else {
01720 $this->currentElement = '';
01721 }
01722 }
01723 }
01724 }
01725
01729 function characterData($parser, $data)
01730 {
01731
01732 if ($this->currentTag == 'documentation') {
01733 $data = trim(preg_replace('/\s+/', ' ', $data));
01734 if (!strlen($data)) {
01735 return;
01736 }
01737
01738 switch ($this->status) {
01739 case 'service':
01740 $ptr =& $this->wsdl->services[$this->currentService];
01741 break;
01742
01743 case 'portType':
01744 $ptr =& $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation];
01745 break;
01746
01747 case 'binding':
01748 $ptr =& $this->wsdl->bindings[$this->currentBinding];
01749 break;
01750
01751 case 'message':
01752 $ptr =& $this->wsdl->messages[$this->currentMessage];
01753 break;
01754
01755 case 'operation':
01756 break;
01757
01758 case 'types':
01759 if (isset($this->currentComplexType) &&
01760 isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType])) {
01761 if ($this->currentElement) {
01762 $ptr =& $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements'][$this->currentElement];
01763 } else {
01764 $ptr =& $this->wsdl->complexTypes[$this->schema][$this->currentComplexType];
01765 }
01766 }
01767 break;
01768 }
01769
01770 if (isset($ptr)) {
01771 if (!isset($ptr['documentation'])) {
01772 $ptr['documentation'] = '';
01773 } else {
01774 $ptr['documentation'] .= ' ';
01775 }
01776 $ptr['documentation'] .= $data;
01777 }
01778 }
01779 }
01780
01786 function mergeUrl($parsed, $path)
01787 {
01788 if (!is_array($parsed)) {
01789 return false;
01790 }
01791
01792 $uri = '';
01793 if (!empty($parsed['scheme'])) {
01794 $sep = (strtolower($parsed['scheme']) == 'mailto' ? ':' : '://');
01795 $uri = $parsed['scheme'] . $sep;
01796 }
01797
01798 if (isset($parsed['pass'])) {
01799 $uri .= "$parsed[user]:$parsed[pass]@";
01800 } elseif (isset($parsed['user'])) {
01801 $uri .= "$parsed[user]@";
01802 }
01803
01804 if (isset($parsed['host'])) {
01805 $uri .= $parsed['host'];
01806 }
01807 if (isset($parsed['port'])) {
01808 $uri .= ":$parsed[port]";
01809 }
01810 if ($path[0] != '/' && isset($parsed['path'])) {
01811 if ($parsed['path'][strlen($parsed['path']) - 1] != '/') {
01812 $path = dirname($parsed['path']) . '/' . $path;
01813 } else {
01814 $path = $parsed['path'] . $path;
01815 }
01816 $path = $this->_normalize($path);
01817 }
01818 $sep = $path[0] == '/' ? '' : '/';
01819 $uri .= $sep . $path;
01820
01821 return $uri;
01822 }
01823
01824 function _normalize($path_str)
01825 {
01826 $pwd = '';
01827 $strArr = preg_split('/(\/)/', $path_str, -1, PREG_SPLIT_NO_EMPTY);
01828 $pwdArr = '';
01829 $j = 0;
01830 for ($i = 0; $i < count($strArr); $i++) {
01831 if ($strArr[$i] != ' ..') {
01832 if ($strArr[$i] != ' .') {
01833 $pwdArr[$j] = $strArr[$i];
01834 $j++;
01835 }
01836 } else {
01837 array_pop($pwdArr);
01838 $j--;
01839 }
01840 }
01841 $pStr = implode('/', $pwdArr);
01842 $pwd = (strlen($pStr) > 0) ? ('/' . $pStr) : '/';
01843 return $pwd;
01844 }
01845
01846 }
01847
01856 class ilBMFWSDL_ObjectParser extends ilBMFBase
01857 {
01862 var $tnsPrefix = 'tns';
01863
01867 var $wsdl = null;
01868
01877 function ilBMFWSDL_ObjectParser(&$objects, &$wsdl, $targetNamespace, $service_name, $service_desc = '')
01878 {
01879 parent::ilBMFBase('WSDLOBJECTPARSER');
01880
01881 $this->wsdl = &$wsdl;
01882
01883
01884 $this->_initialise($service_name);
01885
01886
01887 $wsdl_ref = (is_array($objects)? $objects : array(&$objects));
01888
01889 foreach ($wsdl_ref as $ref_item) {
01890 if (!is_object($ref_item))
01891 return $this->_raiseSoapFault('Invalid web service object passed to object parser', 'urn:' . get_class($object));
01892
01893 if ($this->_parse($ref_item, $targetNamespace, $service_name) != true)
01894 break;
01895 }
01896
01897
01898 if ($this->fault == null) {
01899 $this->_generateBindingsAndServices($targetNamespace, $service_name, $service_desc);
01900 }
01901 }
01902
01912 function _initialise($service_name)
01913 {
01914
01915 $this->wsdl->namespaces['wsdl'] = SCHEMA_WSDL;
01916 $this->wsdl->namespaces['soap'] = SCHEMA_SOAP;
01917 $this->wsdl->namespaces[$this->tnsPrefix] = 'urn:' . $service_name;
01918 $this->wsdl->namespaces['xsd'] = array_search('xsd', $this->_namespaces);
01919 $this->wsdl->namespaces['SOAP-ENC'] = array_search('SOAP-ENC', $this->_namespaces);
01920
01921
01922 unset($this->wsdl->ns['urn:' . $service_name]);
01923 $this->wsdl->ns += array_flip($this->wsdl->namespaces);
01924
01925
01926
01927 }
01928
01937 function _parse(&$object, $schemaNamespace, $service_name)
01938 {
01939
01940
01941
01942 list($schPrefix, $foo) = $this->_getTypeNs('{' . $schemaNamespace.'}');
01943 unset($foo);
01944
01945
01946
01947
01948
01949 foreach ($object->__typedef as $typeName => $typeValue) {
01950
01951
01952 list($nsPrefix, $typeName) = $this->_getTypeNs($typeName);
01953
01954
01955
01956 $this->wsdl->complexTypes[$schPrefix][$typeName] = array('name' => $typeName);
01957 $thisType =& $this->wsdl->complexTypes[$schPrefix][$typeName];
01958
01959
01960
01961
01962
01963
01964 if (is_array($typeValue)) {
01965 if (is_array(current($typeValue)) && count($typeValue) == 1
01966 && count(current($typeValue)) == 1) {
01967
01968
01969 $thisType['type'] = 'Array';
01970 list($nsPrefix, $typeName) = $this->_getTypeNs(current(current($typeValue)));
01971 $thisType['namespace'] = $nsPrefix;
01972 $thisType['arrayType'] = $typeName . '[]';
01973 } elseif (!is_array(current($typeValue))) {
01974
01975
01976 $thisType['type'] = 'Struct';
01977 $thisType['order'] = 'all';
01978 $thisType['namespace'] = $nsPrefix;
01979 $thisType['elements'] = array();
01980
01981 foreach ($typeValue as $elementName => $elementType) {
01982 list($nsPrefix, $typeName) = $this->_getTypeNs($elementType);
01983 $thisType['elements'][$elementName]['name'] = $elementName;
01984 $thisType['elements'][$elementName]['type'] = $typeName;
01985 $thisType['elements'][$elementName]['namespace'] = $nsPrefix;
01986 }
01987 } else {
01988
01989 return $this->_raiseSoapFault("The type definition for $nsPrefix:$typeName is invalid.", 'urn:' . get_class($object));
01990 }
01991 } else {
01992
01993 return $this->_raiseSoapFault("The type definition for $nsPrefix:$typeName is invalid.", 'urn:' . get_class($object));
01994 }
01995 }
01996
01997
01998
01999
02000 $this->wsdl->elements[$schPrefix] = array();
02001
02002
02003
02004
02005 foreach ($object->__dispatch_map as $operationName => $messages) {
02006 foreach ($messages as $messageType => $messageParts) {
02007 unset($thisMessage);
02008
02009 switch ($messageType) {
02010 case 'in':
02011 $this->wsdl->messages[$operationName . 'Request'] = array();
02012 $thisMessage =& $this->wsdl->messages[$operationName . 'Request'];
02013 break;
02014
02015 case 'out':
02016 $this->wsdl->messages[$operationName . 'Response'] = array();
02017 $thisMessage =& $this->wsdl->messages[$operationName . 'Response'];
02018 break;
02019
02020 case 'alias':
02021
02022 break;
02023
02024 default:
02025
02026 break;
02027 }
02028
02029 if (isset($thisMessage)) {
02030 foreach ($messageParts as $partName => $partType) {
02031 list ($nsPrefix, $typeName) = $this->_getTypeNs($partType);
02032
02033 $thisMessage[$partName] = array(
02034 'name' => $partName,
02035 'type' => $typeName,
02036 'namespace' => $nsPrefix
02037 );
02038 }
02039 }
02040 }
02041 }
02042
02043
02044
02045
02046
02047
02048 if (!isset($this->wsdl->portTypes[$service_name . 'Port'])) {
02049 $this->wsdl->portTypes[$service_name . 'Port'] = array();
02050 }
02051 $thisPortType =& $this->wsdl->portTypes[$service_name . 'Port'];
02052
02053 foreach ($object->__dispatch_map as $operationName => $messages) {
02054 $thisPortType[$operationName] = array('name' => $operationName);
02055
02056 foreach ($messages as $messageType => $messageParts) {
02057 switch ($messageType) {
02058 case 'in':
02059 $thisPortType[$operationName]['input'] = array(
02060 'message' => $operationName . 'Request',
02061 'namespace' => $this->tnsPrefix);
02062 break;
02063
02064 case 'out':
02065 $thisPortType[$operationName]['output'] = array(
02066 'message' => $operationName . 'Response',
02067 'namespace' => $this->tnsPrefix);
02068 break;
02069 }
02070 }
02071 }
02072
02073 return true;
02074 }
02075
02087 function _generateBindingsAndServices($schemaNamespace, $service_name, $service_desc = '')
02088 {
02089
02090
02091
02092
02093
02094
02095 $this->wsdl->bindings[$service_name . 'Binding'] = array(
02096 'type' => $service_name . 'Port',
02097 'namespace' => $this->tnsPrefix,
02098 'style' => 'rpc',
02099 'transport' => SCHEMA_SOAP_HTTP,
02100 'operations' => array());
02101 $thisBinding =& $this->wsdl->bindings[$service_name . 'Binding'];
02102
02103 foreach ($this->wsdl->portTypes[$service_name . 'Port'] as $operationName => $operationData) {
02104 $thisBinding['operations'][$operationName] = array(
02105 'soapAction' => $schemaNamespace . '#' . $operationName,
02106 'style' => $thisBinding['style']);
02107
02108 foreach (array('input', 'output') as $messageType)
02109 if (isset($operationData[$messageType])) {
02110 $thisBinding['operations'][$operationName][$messageType] = array(
02111 'use' => 'encoded',
02112 'namespace' => $schemaNamespace,
02113 'encodingStyle' => SOAP_SCHEMA_ENCODING);
02114 }
02115 }
02116
02117
02118
02119
02120
02121
02122
02123 $this->wsdl->services[$service_name . 'Service'] = array('ports' => array());
02124 $thisService =& $this->wsdl->services[$service_name . 'Service']['ports'];
02125
02126 foreach ($this->wsdl->bindings as $bindingName => $bindingData) {
02127 $thisService[$bindingData['type']] = array(
02128 'name' => $bindingData['type'],
02129 'binding' => $bindingName,
02130 'namespace' => $this->tnsPrefix,
02131 'address' => array('location' =>
02132 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'] .
02133 (isset($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '')),
02134 'type' => 'soap');
02135 }
02136
02137
02138 $this->wsdl->set_service($service_name . 'Service');
02139 $this->wsdl->uri = $this->wsdl->namespaces[$this->tnsPrefix];
02140
02141
02142
02143
02144 $this->wsdl->definition = array(
02145 'name' => $service_name,
02146 'targetNamespace' => $this->wsdl->namespaces[$this->tnsPrefix],
02147 'xmlns' => SCHEMA_WSDL);
02148
02149 foreach ($this->wsdl->namespaces as $nsPrefix => $namespace) {
02150 $this->wsdl->definition['xmlns:' . $nsPrefix] = $namespace;
02151 }
02152 }
02153
02165 function _getTypeNs($type)
02166 {
02167 preg_match_all("'\{(.*)\}'sm", $type, $m);
02168 if (isset($m[1][0]) && $m[1][0] != '') {
02169 if (!array_key_exists($m[1][0], $this->wsdl->ns)) {
02170 $ns_pref = 'ns' . count($this->wsdl->namespaces);
02171 $this->wsdl->ns[$m[1][0]] = $ns_pref;
02172 $this->wsdl->namespaces[$ns_pref] = $m[1][0];
02173 }
02174 $typens = $this->wsdl->ns[$m[1][0]];
02175 $type = ereg_replace($m[0][0], '', $type);
02176 } else {
02177 $typens = 'xsd';
02178 }
02179
02180 return array($typens, $type);
02181 }
02182
02183 }