00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 require_once dirname(__FILE__).'/class.ilBMFBase.php';
00023 require_once dirname(__FILE__).'/class.ilBMFFault.php';
00024 require_once 'HTTP/Request.php';
00025
00026 define('WSDL_CACHE_MAX_AGE', 43200);
00027 define('WSDL_CACHE_USE', 0);
00028
00047 class ilBMFWSDL extends ilBMFBase
00048 {
00049 var $tns = null;
00050 var $definition = array();
00051 var $namespaces = array();
00052 var $ns = array();
00053 var $xsd = SOAP_XML_SCHEMA_VERSION;
00054 var $complexTypes = array();
00055 var $elements = array();
00056 var $messages = array();
00057 var $portTypes = array();
00058 var $bindings = array();
00059 var $imports = array();
00060 var $services = array();
00061 var $service = '';
00062 var $uri = '';
00063
00069 var $proxy = null;
00070
00071 var $trace = 0;
00072
00078 var $cacheUse = null;
00079
00085 var $cacheMaxAge = null;
00086
00096 function ilBMFWSDL($wsdl_uri = false, $proxy = array(),
00097 $cacheUse = WSDL_CACHE_USE,
00098 $cacheMaxAge = WSDL_CACHE_MAX_AGE) {
00099 parent::ilBMFBase('WSDL');
00100 $this->uri = $wsdl_uri;
00101 $this->proxy = $proxy;
00102 $this->cacheUse = $cacheUse;
00103 $this->cacheMaxAge = $cacheMaxAge;
00104 if ($wsdl_uri) {
00105 $this->parseURL($wsdl_uri);
00106 reset($this->services);
00107 $this->service = key($this->services);
00108 }
00109 }
00110
00111 function set_service($service) {
00112 if (array_key_exists($service, $this->services)) {
00113 $this->service = $service;
00114 }
00115 }
00116
00120 function parse($wsdl_uri, $proxy = array()) {
00121 $this->parseURL($wsdl_uri, $proxy);
00122 }
00123
00131 function parseURL($wsdl_uri, $proxy = array()) {
00132 $parser =& new ilBMFWSDL_Parser($wsdl_uri, $this);
00133
00134 if ($parser->fault) {
00135 $this->_raiseSoapFault($parser->fault);
00136 }
00137 }
00138
00147 function parseObject(&$wsdl_obj, $targetNamespace, $service_name, $service_desc = '')
00148 {
00149 $parser =& new ilBMFWSDL_ObjectParser($wsdl_obj, $this, $targetNamespace, $service_name, $service_desc);
00150
00151 if ($parser->fault) {
00152 $this->_raiseSoapFault($parser->fault);
00153 }
00154 }
00155
00156 function getEndpoint($portName)
00157 {
00158 return (isset($this->services[$this->service]['ports'][$portName]['address']['location']))
00159 ? $this->services[$this->service]['ports'][$portName]['address']['location']
00160 : $this->_raiseSoapFault("no endpoint for port for $portName", $this->uri);
00161 }
00162
00163 function _getPortName($operation,$service) {
00164 if (isset($this->services[$service]['ports'])) {
00165 foreach ($this->services[$service]['ports'] as $port => $portAttrs) {
00166 $type = $this->services[$service]['ports'][$port]['type'];
00167 if ($type == 'soap' &&
00168 isset($this->bindings[$portAttrs['binding']]['operations'][$operation])) {
00169 return $port;
00170 }
00171 }
00172 }
00173 return null;
00174 }
00175
00176
00177
00178 function getPortName($operation, $service = null)
00179 {
00180 if (!$service) $service = $this->service;
00181 if (isset($this->services[$service]['ports'])) {
00182 $portName = $this->_getPortName($operation,$service);
00183 if ($portName) return $portName;
00184 }
00185
00186 foreach ($this->services as $serviceName=>$service) {
00187 if (isset($this->services[$serviceName]['ports'])) {
00188 $portName = $this->_getPortName($operation,$serviceName);
00189 if ($portName) {
00190 $this->service = $serviceName;
00191 return $portName;
00192 }
00193 }
00194 }
00195 return $this->_raiseSoapFault("no operation $operation in wsdl", $this->uri);
00196 }
00197
00198 function getOperationData($portName,$operation)
00199 {
00200 if (isset($this->services[$this->service]['ports'][$portName]['binding'])
00201 && $binding = $this->services[$this->service]['ports'][$portName]['binding']) {
00202
00203 if (is_array($this->bindings[$binding]['operations'][$operation])) {
00204 $opData = $this->bindings[$binding]['operations'][$operation];
00205 }
00206
00207 $portType = $this->bindings[$binding]['type'];
00208 if (!$portType) {
00209 return $this->_raiseSoapFault("no port type for binding $binding in wsdl " . $this->uri);
00210 }
00211 if (is_array($this->portTypes[$portType][$operation])) {
00212 if (isset($this->portTypes[$portType][$operation]['parameterOrder']))
00213 $opData['parameterOrder'] = $this->portTypes[$portType][$operation]['parameterOrder'];
00214 $opData['input'] = array_merge($opData['input'], $this->portTypes[$portType][$operation]['input']);
00215 $opData['output'] = array_merge($opData['output'], $this->portTypes[$portType][$operation]['output']);
00216 }
00217 if (!$opData)
00218 return $this->_raiseSoapFault("no operation $operation for port $portName, in wsdl", $this->uri);
00219 $opData['parameters'] = false;
00220 if (isset($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace']))
00221 $opData['namespace'] = $this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace'];
00222
00223 $inputMsg = $opData['input']['message'];
00224 if (is_array($this->messages[$inputMsg])) {
00225 foreach ($this->messages[$inputMsg] as $pname => $pattrs) {
00226 if ($opData['style'] == 'document' && $opData['input']['use'] == 'literal'
00227 && $pname == 'parameters') {
00228 $opData['parameters'] = true;
00229 $opData['namespace'] = $this->namespaces[$pattrs['namespace']];
00230 $el = $this->elements[$pattrs['namespace']][$pattrs['type']];
00231 if (isset($el['elements'])) {
00232 foreach ($el['elements'] as $elname => $elattrs) {
00233 $opData['input']['parts'][$elname] = $elattrs;
00234 }
00235 }
00236 } else {
00237 $opData['input']['parts'][$pname] = $pattrs;
00238 }
00239 }
00240 }
00241 $outputMsg = $opData['output']['message'];
00242 if (is_array($this->messages[$outputMsg])) {
00243 foreach ($this->messages[$outputMsg] as $pname => $pattrs) {
00244 if ($opData['style'] == 'document' && $opData['output']['use'] == 'literal'
00245 && $pname == 'parameters') {
00246
00247 $el = $this->elements[$pattrs['namespace']][$pattrs['type']];
00248 if (isset($el['elements'])) {
00249 foreach ($el['elements'] as $elname => $elattrs) {
00250 $opData['output']['parts'][$elname] = $elattrs;
00251 }
00252 }
00253
00254 } else {
00255 $opData['output']['parts'][$pname] = $pattrs;
00256 }
00257 }
00258 }
00259 return $opData;
00260 }
00261 return $this->_raiseSoapFault("no binding for port $portName in wsdl", $this->uri);
00262 }
00263
00264 function matchMethod(&$operation) {
00265
00266 foreach ($this->services[$this->service]['ports'] as $port => $portAttrs) {
00267 foreach (array_keys($this->bindings[$portAttrs['binding']]['operations']) as $op) {
00268 if (strcasecmp($op, $operation) == 0) {
00269 $operation = $op;
00270 }
00271 }
00272 }
00273 }
00274
00288 function getDataHandler($datatype, $namespace) {
00289
00290 if (isset($this->namespaces[$namespace]))
00291 $namespace = $this->namespaces[$namespace];
00292 if (isset($this->ns[$namespace])) {
00293 $nsp = $this->ns[$namespace];
00294 #if (!isset($this->elements[$nsp]))
00295 # $nsp = $this->namespaces[$nsp];
00296 if (isset($this->elements[$nsp][$datatype])) {
00297 $checkmessages = array();
00298
00299 foreach ($this->messages as $messagename=>$message) {
00300 foreach ($message as $partname=>$part) {
00301 if ($part['type']==$datatype) {
00302 $checkmessages[] = $messagename;
00303 break;
00304 }
00305 }
00306 }
00307
00308 $dataHandler = NULL;
00309 foreach($this->portTypes as $portname=>$porttype) {
00310 foreach ($porttype as $opname=>$opinfo) {
00311 foreach ($checkmessages as $messagename) {
00312 if ($opinfo['input']['message'] == $messagename) {
00313 return $opname;
00314 }
00315 }
00316 }
00317 }
00318 }
00319 }
00320 return null;
00321 }
00322
00323 function getSoapAction($portName, $operation)
00324 {
00325 if (isset($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['soapAction']) &&
00326 $soapAction = $this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['soapAction']) {
00327 return $soapAction;
00328 }
00329 return false;
00330 }
00331
00332 function getNamespace($portName, $operation)
00333 {
00334 if (isset($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]) &&
00335 isset($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace']) &&
00336 $namespace = $this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace']) {
00337 return $namespace;
00338 }
00339 return false;
00340 }
00341
00342 function getNamespaceAttributeName($namespace) {
00343
00344 if (!array_key_exists($namespace, $this->ns)) {
00345 $this->ns = array_flip($this->namespaces);
00346 }
00347
00348 if (!array_key_exists($namespace, $this->ns)) {
00349 return $this->addNamespace($namespace);
00350 }
00351 return $this->ns[$namespace];
00352 }
00353
00354 function addNamespace($namespace) {
00355 if (array_key_exists($namespace, $this->ns)) {
00356 return $this->ns[$namespace];
00357 }
00358 $n = count($this->ns);
00359 $attr = 'ns'.$n;
00360 $this->namespaces['ns'.$n] = $namespace;
00361 $this->ns[$namespace] = $attr;
00362 return $attr;
00363 }
00364
00365 function _validateString($string) {
00366
00367 return true;
00368 #if (preg_match("/^[\w_:#\/]+$/",$string)) return true;
00369 #return false;
00370 }
00371
00372 function _addArg(&$args, &$argarray, $argname)
00373 {
00374 if ($args) $args .= ", ";
00375 $args .= "\$".$argname;
00376 if (!$this->_validateString($argname)) return NULL;
00377 if ($argarray) $argarray .= ", ";
00378 $argarray .= "\"$argname\"=>\$".$argname;
00379 }
00380
00381 function _elementArg(&$args, &$argarray, &$_argtype, $_argname)
00382 {
00383 $comments = '';
00384 $el = $this->elements[$_argtype['namespace']][$_argtype['type']];
00385 $tns = isset($this->ns[$el['namespace']])?$this->ns[$el['namespace']]:$_argtype['namespace'];
00386 if (isset($this->complexTypes[$tns][$el['type']])) {
00387
00388 $comments = " // {$el['type']} is a ComplexType, refer to wsdl for more info\n";
00389 $attrname = "{$_argtype['type']}_attr";
00390 if (isset($this->complexTypes[$tns][$el['type']]['attribute'])) {
00391 $comments .= " // {$el['type']} may require attributes, refer to wsdl for more info\n";
00392 }
00393 $comments .= " \${$attrname}['xmlns'] = '{$this->namespaces[$_argtype['namespace']]}';\n";
00394 $comments .= " \${$_argtype['type']} =& new ilBMFValue('{$_argtype['type']}',false,\${$_argtype['type']},\$$attrname);\n";
00395 $this->_addArg($args,$argarray,$_argtype['type']);
00396 if (isset($this->complexTypes[$tns][$el['type']]['attribute'])) {
00397 if ($args) $args .= ", ";
00398 $args .= "\$".$attrname;
00399 }
00400 #$comments = $this->_complexTypeArg($args,$argarray,$el,$_argtype['type']);
00401 } else if (isset($el['elements'])) {
00402 foreach ($el['elements'] as $ename => $element) {
00403 $comments .= " \$$ename =& new ilBMFValue('{{$this->namespaces[$element['namespace']]}}$ename','{$element['type']}',\$$ename);\n";
00404 $this->_addArg($args,$argarray,$ename);
00405 }
00406 } else {
00407 #$echoStringParam =& new ilBMFValue('{http://soapinterop.org/xsd}echoStringParam',false,$echoStringParam);
00408 $comments .= " \$$_argname =& new ilBMFValue('{{$this->namespaces[$tns]}}$_argname','{$el['type']}',\$$_argname);\n";
00409 $this->_addArg($args,$argarray,$_argname);
00410 }
00411 return $comments;
00412 }
00413
00414 function _complexTypeArg(&$args, &$argarray, &$_argtype, $_argname)
00415 {
00416 $comments = '';
00417 if (isset($this->complexTypes[$_argtype['namespace']][$_argtype['type']])) {
00418 $comments = " // $_argname is a ComplexType {$_argtype['type']},\n";
00419 $comments .= " //refer to wsdl for more info\n";
00420 if (isset($this->complexTypes[$_argtype['namespace']][$_argtype['type']]['attribute'])) {
00421 $comments .= " // $_argname may require attributes, refer to wsdl for more info\n";
00422 }
00423 $wrapname = '{'.$this->namespaces[$_argtype['namespace']].'}'.$_argtype['type'];
00424 $comments .= " \$$_argname =& new ilBMFValue('$_argname','$wrapname',\$$_argname);\n";
00425
00426 }
00427 $this->_addArg($args,$argarray,$_argname);
00428 return $comments;
00429 }
00430
00435 function generateProxyCode($port = '', $classname='')
00436 {
00437 $multiport = count($this->services[$this->service]['ports']) > 1;
00438 if (!$port) {
00439 reset($this->services[$this->service]['ports']);
00440 $port = current($this->services[$this->service]['ports']);
00441 }
00442
00443 if ($port['type'] != 'soap') return NULL;
00444
00445
00446 $clienturl = $port['address']['location'];
00447 if (!$classname) {
00448 if ($multiport || $port) {
00449 $classname = 'WebService_'.$this->service.'_'.$port['name'];
00450 } else {
00451 $classname = 'WebService_'.$this->service;
00452 }
00453 $classname = str_replace('-','_',$classname);
00454 }
00455
00456 if (!$this->_validateString($classname)) return NULL;
00457
00458 if (is_array($this->proxy) && count($this->proxy) > 0) {
00459 $class = "class $classname extends ilBMFClient\n{\n".
00460 " function $classname()\n{\n".
00461 " \$this->ilBMFClient(\"$clienturl\", 0, 0,
00462 array(";
00463
00464 foreach($this->proxy as $key => $val) {
00465 if (is_array($val)) {
00466 $class .= "\"$key\" => array(";
00467 foreach ($val as $key2 => $val2) {
00468 $class .= "\"$key2\" => \"$val2\",";
00469 }
00470 $class .= ')';
00471 } else {
00472 $class .= "\"$key\"=>\"$val\",";
00473 }
00474 }
00475 $class .= "));\n }\n";
00476 $class = str_replace(',))', '))', $class);
00477 } else {
00478 $class = "class $classname extends ilBMFClient\n{\n".
00479 " function $classname()\n{\n".
00480 " \$this->ilBMFClient(\"$clienturl\", 0);\n".
00481 " }\n";
00482 }
00483
00484
00485 $primaryBinding = $port['binding'];
00486 $primaryBinding = preg_replace("/^(.*:)/","",$primaryBinding);
00487 $portType = $this->bindings[$primaryBinding]['type'];
00488 $portType = preg_replace("/^(.*:)/","",$portType);
00489 $style = $this->bindings[$primaryBinding]['style'];
00490
00491
00492 foreach ($this->portTypes[$portType] as $opname => $operation) {
00493 $soapaction = $this->bindings[$primaryBinding]['operations'][$opname]['soapAction'];
00494 if (isset($this->bindings[$primaryBinding]['operations'][$opname]['style'])) {
00495 $opstyle = $this->bindings[$primaryBinding]['operations'][$opname]['style'];
00496 } else {
00497 $opstyle = $style;
00498 }
00499 $use = $this->bindings[$primaryBinding]['operations'][$opname]['input']['use'];
00500 if ($use == 'encoded') {
00501 $namespace = $this->bindings[$primaryBinding]['operations'][$opname]['input']['namespace'];
00502 } else {
00503 $bindingType = $this->bindings[$primaryBinding]['type'];
00504 $ns = $this->portTypes[$bindingType][$opname]['input']['namespace'];
00505 $namespace = $this->namespaces[$ns];
00506 }
00507
00508 $args = '';
00509 $argarray = '';
00510 $comments = '';
00511 $wrappers = '';
00512 foreach ($operation['input'] as $argname => $argtype) {
00513 if ($argname == "message") {
00514 foreach ($this->messages[$argtype] as $_argname => $_argtype) {
00515 $comments = '';
00516 if ($opstyle == 'document' && $use == 'literal' &&
00517 $_argtype['name'] == 'parameters') {
00518
00519 $elattrs = null;
00520 $element = $_argtype['element'];
00521 $el = $this->elements[$_argtype['namespace']][$_argtype['type']];
00522
00523 if($el['complex']) {
00524 $namespace = $this->namespaces[$_argtype['namespace']];
00525
00526 }
00527 if (isset($el['elements'])) {
00528 foreach ($el['elements'] as $elname => $elattrs) {
00529
00530 if (isset($this->complexTypes[$elattrs['namespace']][$elname])) {
00531 $comments .= $this->_complexTypeArg($args, $argarray, $_argtype, $_argname);
00532 } else {
00533 $this->_addArg($args, $argarray, $elname);
00534 }
00535 }
00536 }
00537
00538
00539 if($el['complex'] && $argarray) {
00540 $wrapname = '{'.$this->namespaces[$_argtype['namespace']].'}'.$el['name'];
00541 $comments .= " \${$el['name']} =& new ilBMFValue('$wrapname',false,\$v=array($argarray));\n";
00542 $argarray = "'{$el['name']}'=>\${$el['name']}";
00543 }
00544 } else
00545 if (isset($_argtype['element'])) {
00546
00547 $comments = $this->_elementArg($args, $argarray, $_argtype, $_argtype['type']);
00548 } else {
00549
00550 $comments = $this->_complexTypeArg($args, $argarray, $_argtype, $_argname);
00551 }
00552 }
00553 }
00554 }
00555
00556
00557 if (!$this->_validateString($opname)) return NULL;
00558 if (!$this->_validateString($namespace)) return NULL;
00559 if (!$this->_validateString($soapaction)) return NULL;
00560
00561 if ($argarray) {
00562 $argarray = "array($argarray)";
00563 } else {
00564 $argarray = 'null';
00565 }
00566
00567 $class .= " function &$opname($args) {\n$comments$wrappers".
00568 " return \$this->call(\"$opname\", \n".
00569 " \$v = $argarray, \n".
00570 " array('namespace'=>'$namespace',\n".
00571 " 'soapaction'=>'$soapaction',\n".
00572 " 'style'=>'$opstyle',\n".
00573 " 'use'=>'$use'".
00574 ($this->trace?",'trace'=>1":"")." ));\n".
00575 " }\n";
00576 }
00577 $class .= "}\n";
00578 return $class;
00579 }
00580
00581 function generateAllProxies()
00582 {
00583 $proxycode = '';
00584 foreach (array_keys($this->services[$this->service]['ports']) as $key) {
00585 $port =& $this->services[$this->service]['ports'][$key];
00586 $proxycode .= $this->generateProxyCode($port);
00587 }
00588 return $proxycode;
00589 }
00590
00591 function &getProxy($port = '', $name = '')
00592 {
00593 $multiport = count($this->services[$this->service]['ports']) > 1;
00594
00595 if (!$port) {
00596 reset($this->services[$this->service]['ports']);
00597 $port = current($this->services[$this->service]['ports']);
00598 }
00599
00600 if ($multiport || $port) {
00601 $classname = 'WebService_' . $this->service . '_' . $port['name'];
00602 } else {
00603 $classname = 'WebService_' . $this->service;
00604 }
00605
00606 if ($name) {
00607 $classname = $name . '_' . $classname;
00608 }
00609
00610 $classname = preg_replace('/[ .\-\(\)]+/', '_', $classname);
00611
00612 if (!class_exists($classname)) {
00613 $proxy = $this->generateProxyCode($port, $classname);
00614 eval($proxy);
00615 }
00616
00617 return new $classname;
00618 }
00619
00620 function &_getComplexTypeForElement($name, $namespace)
00621 {
00622 $t = NULL;
00623 if (isset($this->ns[$namespace]) &&
00624 isset($this->elements[$this->ns[$namespace]][$name]['type'])) {
00625
00626 $type = $this->elements[$this->ns[$namespace]][$name]['type'];
00627 $ns = $this->elements[$this->ns[$namespace]][$name]['namespace'];
00628
00629 if (isset($this->complexTypes[$ns][$type])) {
00630 $t = $this->complexTypes[$ns][$type];
00631 }
00632 }
00633 return $t;
00634 }
00635
00636 function getComplexTypeNameForElement($name, $namespace)
00637 {
00638 $t = $this->_getComplexTypeForElement($name, $namespace);
00639 if ($t) {
00640 return $t['name'];
00641 }
00642 return NULL;
00643 }
00644
00645 function getComplexTypeChildType($ns, $name, $child_ns, $child_name) {
00646
00647 $t = $this->_getComplexTypeForElement($name, $ns);
00648 if ($t) {
00649
00650 if (isset($t['elements'][$child_name]['type']))
00651 return $t['elements'][$child_name]['type'];
00652 }
00653 return NULL;
00654 }
00655
00656 function getSchemaType($type, $name, $type_namespace)
00657 {
00658 # see if it's a complex type so we can deal properly with SOAPENC:arrayType
00659 if ($name && $type) {
00660 # XXX TODO:
00661 # look up the name in the wsdl and validate the type
00662 foreach ($this->complexTypes as $ns=> $types) {
00663 if (array_key_exists($type, $types)) {
00664 if (array_key_exists('type', $types[$type])) {
00665 list($arraytype_ns, $arraytype, $array_depth) = isset($types[$type]['arrayType'])?
00666 $this->_getDeepestArrayType($types[$type]['namespace'], $types[$type]['arrayType'])
00667 : array($this->namespaces[$types[$type]['namespace']], NULL, 0);
00668 return array($types[$type]['type'], $arraytype, $arraytype_ns, $array_depth);
00669 }
00670 if (array_key_exists('arrayType', $types[$type])) {
00671 list($arraytype_ns, $arraytype, $array_depth) =
00672 $this->_getDeepestArrayType($types[$type]['namespace'], $types[$type]['arrayType']);
00673 return array('Array', $arraytype, $arraytype_ns, $array_depth);
00674 }
00675 if (array_key_exists('elements', $types[$type]) &&
00676 array_key_exists($name, $types[$type]['elements'])) {
00677 $type = $types[$type]['elements']['type'];
00678 return array($type, NULL, $this->namespaces[$types[$type]['namespace']], NULL);
00679 }
00680 }
00681 }
00682 }
00683 if ($type && $type_namespace) {
00684 $arrayType = NULL;
00685 # XXX TODO:
00686 # this code currently handles only one way of encoding array types in wsdl
00687 # need to do a generalized function to figure out complex types
00688 $p = $this->ns[$type_namespace];
00689 if ($p &&
00690 array_key_exists($p, $this->complexTypes) &&
00691 array_key_exists($type, $this->complexTypes[$p])) {
00692 if ($arrayType = $this->complexTypes[$p][$type]['arrayType']) {
00693 $type = 'Array';
00694 } else if ($this->complexTypes[$p][$type]['order']=='sequence' &&
00695 array_key_exists('elements', $this->complexTypes[$p][$type])) {
00696 reset($this->complexTypes[$p][$type]['elements']);
00697 # assume an array
00698 if (count($this->complexTypes[$p][$type]['elements']) == 1) {
00699 $arg = current($this->complexTypes[$p][$type]['elements']);
00700 $arrayType = $arg['type'];
00701 $type = 'Array';
00702 } else {
00703 foreach($this->complexTypes[$p][$type]['elements'] as $element) {
00704 if ($element['name'] == $type) {
00705 $arrayType = $element['type'];
00706 $type = $element['type'];
00707 }
00708 }
00709 }
00710 } else {
00711 $type = 'Struct';
00712 }
00713 return array($type, $arrayType, $type_namespace, null);
00714 }
00715 }
00716 return array(null, null, null, null);
00717 }
00718
00728 function _getDeepestArrayType($nsPrefix, $arrayType)
00729 {
00730 static $trail = array();
00731
00732 $arrayType = ereg_replace('\[\]$', '', $arrayType);
00733
00734
00735
00736
00737
00738 if (array_search($nsPrefix . ':' . $arrayType, $trail)) {
00739 return array(NULL, NULL, -count($trail));
00740 }
00741
00742 if (array_key_exists($nsPrefix, $this->complexTypes) &&
00743 array_key_exists($arrayType, $this->complexTypes[$nsPrefix]) &&
00744 array_key_exists('arrayType', $this->complexTypes[$nsPrefix][$arrayType])) {
00745 $trail[] = $nsPrefix . ':' . $arrayType;
00746 $result = $this->_getDeepestArrayType( $this->complexTypes[$nsPrefix][$arrayType]['namespace'],
00747 $this->complexTypes[$nsPrefix][$arrayType]['arrayType']);
00748 return array($result[0], $result[1], $result[2] + 1);
00749 }
00750 return array($this->namespaces[$nsPrefix], $arrayType, 0);
00751 }
00752 }
00753
00754 class ilBMFWSDL_Cache extends ilBMFBase
00755 {
00756
00757
00763 var $_cacheUse = null;
00764
00770 var $_cacheMaxAge = null;
00771
00779 function ilBMFWSDL_Cache($cacheUse = WSDL_CACHE_USE,
00780 $cacheMaxAge = WSDL_CACHE_MAX_AGE) {
00781 parent::ilBMFBase('WSDLCACHE');
00782 $this->_cacheUse = $cacheUse;
00783 $this->_cacheMaxAge = $cacheMaxAge;
00784 }
00785
00790 function _cacheDir() {
00791 $dir = getenv("WSDLCACHE");
00792 if (!$dir) $dir = "./wsdlcache";
00793 @mkdir($dir, 0700);
00794 return $dir;
00795 }
00796
00807 function get($wsdl_fname, $proxy_params = array(), $cache = 0) {
00808 $cachename = $md5_wsdl = $file_data = '';
00809 if ($this->_cacheUse) {
00810
00811 $cachename = ilBMFWSDL_Cache::_cacheDir() . '/' . md5($wsdl_fname). '.wsdl';
00812 if (file_exists($cachename)) {
00813 $wf = fopen($cachename,'rb');
00814 if ($wf) {
00815
00816 $file_data = fread($wf, filesize($cachename));
00817 $md5_wsdl = md5($file_data);
00818 fclose($wf);
00819 }
00820 if ($cache) {
00821 if ($cache != $md5_wsdl) {
00822 return $this->_raiseSoapFault('WSDL Checksum error!', $wsdl_fname);
00823 }
00824 } else {
00825 $fi = stat($cachename);
00826 $cache_mtime = $fi[8];
00827 #print cache_mtime, time()
00828 if ($cache_mtime + $this->_cacheMaxAge < time()) {
00829 # expired
00830 $md5_wsdl = ''; # refetch
00831 }
00832 }
00833 }
00834 }
00835
00836 if (!$md5_wsdl) {
00837
00838
00839
00840
00841 if (!preg_match('/^(https?|file):\/\//',$wsdl_fname)) {
00842 if (!file_exists($wsdl_fname)) {
00843 return $this->_raiseSoapFault("Unable to read local WSDL $wsdl_fname", $wsdl_fname);
00844 }
00845 if (function_exists('file_get_contents')) {
00846 $file_data = file_get_contents($wsdl_fname);
00847 } else {
00848 $file_data = implode('',file($wsdl_fname));
00849 }
00850 } else {
00851 $uri = explode('?',$wsdl_fname);
00852 $rq =& new HTTP_Request($uri[0], $proxy_params);
00853
00854 if (isset($uri[1])) {
00855 $rq->addRawQueryString($uri[1]);
00856 }
00857
00858 if (isset($proxy_params['proxy_host']) &&
00859 isset($proxy_params['proxy_port']) &&
00860 isset($proxy_params['proxy_user']) &&
00861 isset($proxy_params['proxy_pass'])) {
00862 $rq->setProxy($proxy_params['proxy_host'], $proxy_params['proxy_port'],
00863 $proxy_params['proxy_user'], $proxy_params['proxy_pass']);
00864 } elseif (isset($proxy_params['proxy_host']) &&
00865 isset($proxy_params['proxy_port'])) {
00866 $rq->setProxy($proxy_params['proxy_host'], $proxy_params['proxy_port']);
00867 }
00868
00869 $result = $rq->sendRequest();
00870 if (PEAR::isError($result)) {
00871 return $this->_raiseSoapFault("Unable to retrieve WSDL $wsdl_fname," . $rq->getResponseCode(), $wsdl_fname);
00872 }
00873 $file_data = $rq->getResponseBody();
00874 if (!$file_data) {
00875 return $this->_raiseSoapFault("Unable to retrieve WSDL $wsdl_fname, no http body", $wsdl_fname);
00876 }
00877 }
00878
00879 $md5_wsdl = md5($file_data);
00880
00881 if ($this->_cacheUse) {
00882 $fp = fopen($cachename, "wb");
00883 fwrite($fp, $file_data);
00884 fclose($fp);
00885 }
00886 }
00887 if ($this->_cacheUse && $cache && $cache != $md5_wsdl) {
00888 return $this->_raiseSoapFault("WSDL Checksum error!", $wsdl_fname);
00889 }
00890 return $file_data;
00891 }
00892 }
00893
00894 class ilBMFWSDL_Parser extends ilBMFBase
00895 {
00896
00897 var $currentMessage;
00898 var $currentOperation;
00899 var $currentPortType;
00900 var $currentBinding;
00901 var $currentPort;
00902
00903
00904 var $cache;
00905
00906 var $tns = null;
00907 var $soapns = array('soap');
00908 var $uri = '';
00909 var $wsdl = null;
00910
00911 var $status = '';
00912 var $element_stack = array();
00913 var $parentElement = '';
00914
00915 var $schema = '';
00916 var $schemaStatus = '';
00917 var $schema_stack = array();
00918 var $currentComplexType;
00919 var $schema_element_stack = array();
00920 var $currentElement;
00921
00922
00923 function ilBMFWSDL_Parser($uri, &$wsdl, $docs = false) {
00924 parent::ilBMFBase('WSDLPARSER');
00925 $this->cache =& new ilBMFWSDL_Cache($wsdl->cacheUse, $wsdl->cacheMaxAge);
00926 $this->uri = $uri;
00927 $this->wsdl = &$wsdl;
00928 $this->docs = $docs;
00929 $this->parse($uri);
00930 }
00931
00932 function parse($uri) {
00933
00934 $fd = $this->cache->get($uri, $this->wsdl->proxy);
00935 if (PEAR::isError($fd)) {
00936 return $this->_raiseSoapFault($fd);
00937 }
00938
00939
00940 $parser = xml_parser_create();
00941 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
00942 xml_set_object($parser, $this);
00943 xml_set_element_handler($parser, 'startElement', 'endElement');
00944 if ($this->docs) {
00945 xml_set_character_data_handler($parser, 'characterData');
00946 }
00947
00948 if (!xml_parse($parser,$fd, true)) {
00949 $detail = sprintf('XML error on line %d: %s',
00950 xml_get_current_line_number($parser),
00951 xml_error_string(xml_get_error_code($parser)));
00952
00953 return $this->_raiseSoapFault("Unable to parse WSDL file $uri\n$detail");
00954 }
00955 xml_parser_free($parser);
00956 return true;
00957 }
00958
00959
00960 function startElement($parser, $name, $attrs) {
00961
00962 $qname =& new ilBMFQName($name);
00963 if ($qname->ns) {
00964 $ns = $qname->ns;
00965 if ($ns && ((!$this->tns && strcasecmp($qname->name,'definitions') == 0) || $ns == $this->tns)) {
00966 $name = $qname->name;
00967 }
00968 }
00969 $this->currentTag = $qname->name;
00970 $this->parentElement = '';
00971 $stack_size = count($this->element_stack);
00972 if ($stack_size > 0) {
00973 $this->parentElement = $this->element_stack[$stack_size-1];
00974 }
00975 $this->element_stack[] = $this->currentTag;
00976
00977
00978 switch($this->status) {
00979 case 'types':
00980
00981
00982 $parent_tag = '';
00983 $stack_size = count($this->schema_stack);
00984 if ($stack_size > 0) {
00985 $parent_tag = $this->schema_stack[$stack_size-1];
00986 }
00987
00988 switch($qname->name) {
00989 case 'schema':
00990
00991 if (!$parent_tag || $parent_tag == 'types') {
00992 if (array_key_exists('targetNamespace', $attrs)) {
00993 $this->schema = $this->wsdl->getNamespaceAttributeName($attrs['targetNamespace']);
00994 } else {
00995 $this->schema = $this->wsdl->getNamespaceAttributeName($this->wsdl->tns);
00996 }
00997 $this->wsdl->complexTypes[$this->schema] = array();
00998 $this->wsdl->elements[$this->schema] = array();
00999 }
01000 break;
01001 case 'complexType':
01002 if ($parent_tag == 'schema') {
01003 $this->currentComplexType = $attrs['name'];
01004 if (!isset($attrs['namespace'])) $attrs['namespace'] = $this->schema;
01005 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType] = $attrs;
01006 if (array_key_exists('base',$attrs)) {
01007 $qn =& new ilBMFQName($attrs['base']);
01008 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = $qn->name;
01009 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'] = $qn->ns;
01010 } else {
01011 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
01012 }
01013 $this->schemaStatus = 'complexType';
01014 } else {
01015 $this->wsdl->elements[$this->schema][$this->currentElement]['complex'] = TRUE;
01016 }
01017 break;
01018 case 'element':
01019 if (isset($attrs['type'])) {
01020 $qn =& new ilBMFQName($attrs['type']);
01021 $attrs['type'] = $qn->name;
01022 #$this->wsdl->getNamespaceAttributeName
01023 if ($qn->ns && array_key_exists($qn->ns, $this->wsdl->namespaces)) {
01024 $attrs['namespace'] = $qn->ns;
01025 }
01026 }
01027
01028 $parentElement = '';
01029 $stack_size = count($this->schema_element_stack);
01030 if ($stack_size > 0) {
01031 $parentElement = $this->schema_element_stack[$stack_size-1];
01032 }
01033
01034 if (isset($attrs['ref'])) {
01035 $this->currentElement = $attrs['ref'];
01036 } else {
01037 $this->currentElement = $attrs['name'];
01038 }
01039 $this->schema_element_stack[] = $this->currentElement;
01040 if (!isset($attrs['namespace'])) $attrs['namespace'] = $this->schema;
01041
01042 if ($parent_tag == 'schema') {
01043 $this->wsdl->elements[$this->schema][$this->currentElement] = $attrs;
01044 $this->wsdl->elements[$this->schema][$this->currentElement]['complex'] = FALSE;
01045 $this->schemaStatus = 'element';
01046 } else if ($this->currentComplexType) {
01047
01048 if ((isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order']) &&
01049 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] == 'sequence')
01050 && $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] == 'Array') {
01051 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['arrayType'] = $attrs['type'];
01052 }
01053 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements'][$this->currentElement] = $attrs;
01054 } else {
01055 $this->wsdl->elements[$this->schema][$parentElement]['elements'][$this->currentElement] = $attrs;
01056 }
01057 break;
01058 case 'complexContent':
01059 case 'simpleContent':
01060 break;
01061 case 'extension':
01062 case 'restriction':
01063 if ($this->schemaStatus == 'complexType') {
01064 if ($attrs['base']) {
01065 $qn =& new ilBMFQName($attrs['base']);
01066 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = $qn->name;
01067 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'] = $qn->ns;
01068 } else {
01069 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
01070 }
01071 }
01072 break;
01073 case 'sequence':
01074 if ($this->schemaStatus == 'complexType') {
01075 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name;
01076 #if (!array_key_exists('type',$this->wsdl->complexTypes[$this->schema][$this->currentComplexType])) {
01077 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array';
01078 #}
01079 }
01080 break;
01081 case 'all':
01082 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name;
01083 if (!array_key_exists('type',$this->wsdl->complexTypes[$this->schema][$this->currentComplexType])) {
01084 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
01085 }
01086 break;
01087 case 'choice':
01088 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name;
01089 if (!array_key_exists('type',$this->wsdl->complexTypes[$this->schema][$this->currentComplexType])) {
01090 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array';
01091 }
01092 case 'attribute':
01093 if ($this->schemaStatus == 'complexType') {
01094 if (isset($attrs['name'])) {
01095 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['attribute'][$attrs['name']] = $attrs;
01096 } else
01097 if (isset($attrs['ref'])) {
01098 $q =& new ilBMFQName($attrs['ref']);
01099 foreach ($attrs as $k => $v) {
01100 if ($k != 'ref' && strstr($k, $q->name)) {
01101 $vq =& new ilBMFQName($v);
01102 if ($q->name == 'arrayType') {
01103 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType][$q->name] = $vq->name.$vq->arrayInfo;
01104 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array';
01105 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'] = $vq->ns;
01106 } else {
01107 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType][$q->name] = $vq->name;
01108 }
01109 }
01110 }
01111 }
01112 }
01113 break;
01114 }
01115
01116 $this->schema_stack[] = $qname->name;
01117
01118 break;
01119 case 'message':
01120
01121 switch($qname->name) {
01122 case 'part':
01123 $qn = NULL;
01124 if (isset($attrs['type'])) {
01125 $qn =& new ilBMFQName($attrs['type']);
01126 } else if (isset($attrs['element'])) {
01127 $qn =& new ilBMFQName($attrs['element']);
01128 }
01129 if ($qn) {
01130 $attrs['type'] = $qn->name;
01131 $attrs['namespace'] = $qn->ns;
01132 }
01133 $this->wsdl->messages[$this->currentMessage][$attrs['name']] = $attrs;
01134
01135 case 'documentation':
01136 break;
01137 default:
01138 break;
01139 }
01140 break;
01141 case 'portType':
01142
01143 switch($qname->name) {
01144 case 'operation':
01145
01146
01147 $this->currentOperation = $attrs['name'];
01148 #$this->wsdl->portTypes[$this->currentPortType][$this->currentOperation]['parameterOrder'] = $attrs['parameterOrder'];
01149 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation] = $attrs;
01150 break;
01151 case 'input':
01152 case 'output':
01153 case 'fault':
01154
01155
01156 if ($this->currentOperation) {
01157 if (isset($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name])) {
01158 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name] = array_merge($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name],$attrs);
01159 } else {
01160 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name] = $attrs;
01161 }
01162 if (array_key_exists('message',$attrs)) {
01163 $qn =& new ilBMFQName($attrs['message']);
01164 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name]['message'] = $qn->name;
01165 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name]['namespace'] = $qn->ns;
01166 }
01167 }
01168 break;
01169 case 'documentation':
01170 break;
01171 default:
01172 break;
01173 }
01174 break;
01175 case 'binding':
01176 $ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL;
01177 switch($ns) {
01178 case SCHEMA_SOAP:
01179
01180 switch($qname->name) {
01181 case 'binding':
01182
01183
01184
01185 if (!isset($attrs['style'])) $attrs['style'] = 'document';
01186 $this->wsdl->bindings[$this->currentBinding] = array_merge($this->wsdl->bindings[$this->currentBinding],$attrs);
01187 break;
01188 case 'operation':
01189
01190
01191 if (!isset($attrs['style'])) $attrs['style'] = $this->wsdl->bindings[$this->currentBinding]['style'];
01192 if (isset($this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation])) {
01193 $this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation] = array_merge($this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation],$attrs);
01194 } else {
01195 $this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation] = $attrs;
01196 }
01197 break;
01198 case 'body':
01199
01200
01201
01202
01203
01204 $this->wsdl->bindings[$this->currentBinding]
01205 ['operations'][$this->currentOperation][$this->opStatus] = $attrs;
01206 break;
01207 case 'fault':
01208
01209
01210 $this->wsdl->bindings[$this->currentBinding]
01211 ['operations'][$this->currentOperation][$this->opStatus] = $attrs;
01212 break;
01213 case 'header':
01214
01215
01216 $this->wsdl->bindings[$this->currentBinding]
01217 ['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
01218 break;
01219 case 'headerfault':
01220
01221
01222 $header = count($this->wsdl->bindings[$this->currentBinding]
01223 ['operations'][$this->currentOperation][$this->opStatus]['headers'])-1;
01224 $this->wsdl->bindings[$this->currentBinding]
01225 ['operations'][$this->currentOperation][$this->opStatus]['headers'][$header]['fault'] = $attrs;
01226 break;
01227 case 'documentation':
01228 break;
01229 default:
01230
01231 break;
01232 }
01233 break;
01234 case SCHEMA_WSDL:
01235
01236
01237
01238 switch($qname->name) {
01239 case 'operation':
01240
01241
01242 $this->currentOperation = $attrs['name'];
01243 break;
01244 case 'output':
01245 case 'input':
01246 case 'fault':
01247
01248
01249 $this->opStatus = $qname->name;
01250 break;
01251 case 'documentation':
01252 break;
01253 default:
01254 break;
01255 }
01256 break;
01257 case SCHEMA_WSDL_HTTP:
01258 switch($qname->name) {
01259 case 'binding':
01260
01261
01262
01263 $this->wsdl->bindings[$this->currentBinding] = array_merge($this->wsdl->bindings[$this->currentBinding],$attrs);
01264 break;
01265 case 'operation':
01266
01267
01268
01269 $this->wsdl->bindings[$this->currentBinding]['operations']
01270 [$this->currentOperation] = $attrs;
01271 break;
01272 case 'urlEncoded':
01273
01274
01275
01276 $this->wsdl->bindings[$this->currentBinding]['operations'][$this->opStatus]
01277 [$this->currentOperation]['uri'] = 'urlEncoded';
01278 break;
01279 case 'urlReplacement':
01280
01281
01282
01283 $this->wsdl->bindings[$this->currentBinding]['operations'][$this->opStatus]
01284 [$this->currentOperation]['uri'] = 'urlReplacement';
01285 break;
01286 case 'documentation':
01287 break;
01288 default:
01289
01290 break;
01291 }
01292 case SCHEMA_MIME:
01293
01294
01295
01296 switch($qname->name) {
01297 case 'content':
01298
01299
01300
01301
01302
01303 case 'multipartRelated':
01304
01305 case 'part':
01306 case 'mimeXml':
01307
01308
01309
01310 case 'documentation':
01311 break;
01312 default:
01313
01314 break;
01315 }
01316 case SCHEMA_DIME:
01317
01318
01319
01320
01321 switch($qname->name) {
01322 case 'message':
01323
01324
01325 $this->wsdl->bindings[$this->currentBinding]['dime'] = $attrs;
01326 break;
01327 default:
01328 break;
01329 }
01330 default:
01331 break;
01332 }
01333 break;
01334 case 'service':
01335 $ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL;
01336
01337 switch($qname->name) {
01338 case 'port':
01339
01340 $this->currentPort = $attrs['name'];
01341 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort] = $attrs;
01342
01343 $qn =& new ilBMFQName($attrs['binding']);
01344 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['binding'] = $qn->name;
01345 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['namespace'] = $qn->ns;
01346 break;
01347 case 'address':
01348 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['address'] = $attrs;
01349
01350 $ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL;
01351 switch($ns) {
01352 case SCHEMA_WSDL_HTTP:
01353 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='http';
01354 break;
01355 case SCHEMA_SOAP:
01356 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='soap';
01357 break;
01358 default:
01359
01360 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='soap';
01361 }
01362
01363 break;
01364 case 'documentation':
01365 break;
01366 default:
01367 break;
01368 }
01369 }
01370
01371
01372
01373 switch($qname->name) {
01374 case 'import':
01375
01376 if (array_key_exists('location',$attrs) &&
01377 !isset($this->wsdl->imports[$attrs['namespace']])) {
01378 $uri = $attrs['location'];
01379 $location = parse_url($uri);
01380 if (!isset($location['scheme'])) {
01381 $base = parse_url($this->uri);
01382 $uri = $this->merge_url($base,$uri);
01383 }
01384 $import_parser =& new ilBMFWSDL_Parser($uri, $this->wsdl);
01385 if ($import_parser->fault) {
01386 return FALSE;
01387 }
01388 $this->currentImport = $attrs['namespace'];
01389 $this->wsdl->imports[$this->currentImport] = $attrs;
01390 }
01391 $this->status = '';
01392 case 'types':
01393
01394 $this->status = 'types';
01395 break;
01396 case 'message':
01397
01398 $this->status = 'message';
01399 if (isset($attrs['name'])) {
01400 $this->currentMessage = $attrs['name'];
01401 $this->wsdl->messages[$this->currentMessage] = array();
01402 }
01403 break;
01404 case 'portType':
01405
01406
01407
01408 $this->status = 'portType';
01409 $this->currentPortType = $attrs['name'];
01410 $this->wsdl->portTypes[$this->currentPortType] = array();
01411 break;
01412 case 'binding':
01413
01414
01415 if ($qname->ns && $qname->ns != $this->tns) break;
01416 $this->status = 'binding';
01417 $this->currentBinding = $attrs['name'];
01418 $qn =& new ilBMFQName($attrs['type']);
01419 $this->wsdl->bindings[$this->currentBinding]['type'] = $qn->name;
01420 $this->wsdl->bindings[$this->currentBinding]['namespace'] = $qn->ns;
01421 break;
01422 case 'service':
01423
01424 $this->currentService = $attrs['name'];
01425 $this->wsdl->services[$this->currentService]['ports'] = array();
01426 $this->status = 'service';
01427 break;
01428 case 'definitions':
01429
01430
01431
01432 #$this->status = 'definitions';
01433 $this->wsdl->definition = $attrs;
01434 foreach ($attrs as $key => $value) {
01435 if (strstr($key,'xmlns:') !== FALSE) {
01436 $qn =& new ilBMFQName($key);
01437
01438 $this->wsdl->namespaces[$qn->name] = $value;
01439 $this->wsdl->ns[$value] = $qn->name;
01440 if ($key == 'targetNamespace' ||
01441 strcasecmp($value,SOAP_SCHEMA) == 0) {
01442 $this->soapns[] = $qn->name;
01443 } else {
01444 if (in_array($value, $this->_XMLSchema)) {
01445 $this->wsdl->xsd = $value;
01446 }
01447 }
01448 }
01449 }
01450 if (isset($ns) && $ns) {
01451 $namespace = 'xmlns:'.$ns;
01452 if (!$this->wsdl->definition[$namespace]) {
01453 return $this->_raiseSoapFault("parse error, no namespace for $namespace",$this->uri);
01454 }
01455 $this->tns = $ns;
01456 }
01457 break;
01458 }
01459 }
01460
01461
01462
01463 function endElement($parser, $name)
01464 {
01465 $stacksize = count($this->element_stack);
01466 if ($stacksize > 0) {
01467 if ($this->element_stack[count($this->element_stack)-1] == 'definitions') {
01468 $this->status = '';
01469 }
01470 array_pop($this->element_stack);
01471 }
01472 if (stristr($name,'schema')) {
01473 array_pop($this->schema_stack);
01474 $this->schema = '';
01475 }
01476 if ($this->schema) {
01477 array_pop($this->schema_stack);
01478 if (count($this->schema_stack) <= 1) {
01479
01480 if (isset($this->currentComplexType) && isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])
01481 && $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] == 'Array'
01482 && array_key_exists('elements',$this->wsdl->complexTypes[$this->schema][$this->currentComplexType])
01483 && count($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements']) > 1) {
01484 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
01485 }
01486 }
01487 if (stristr($name,'complexType')) {
01488 $this->currentComplexType = '';
01489 if (count($this->schema_element_stack) > 0)
01490 $this->currentElement = array_pop($this->schema_element_stack);
01491 else
01492 $this->currentElement = '';
01493 } else if (stristr($name,'element')) {
01494 if (count($this->schema_element_stack) > 0)
01495 $this->currentElement = array_pop($this->schema_element_stack);
01496 else
01497 $this->currentElement = '';
01498 }
01499 }
01500
01501
01502
01503
01504 }
01505
01506
01507 function characterData($parser, $data)
01508 {
01509 # store the documentation in the WSDL file
01510 if ($this->currentTag == 'documentation') {
01511 if ($this->status == 'service') {
01512 $this->wsdl->services[$this->currentService][$this->currentTag] .= $data;
01513 } else if ($this->status == 'portType') {
01514 if ($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag])
01515 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag] .= data;
01516 else
01517 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag] = data;
01518 } else if ($this->status == 'binding') {
01519 if ($this->wsdl->bindings[$this->currentBinding][$this->currentTag])
01520 $this->wsdl->bindings[$this->currentBinding][$this->currentTag] .= data;
01521 else
01522 $this->wsdl->bindings[$this->currentBinding][$this->currentTag] = data;
01523 } else if ($this->status == 'message') {
01524 if ($this->wsdl->messages[$this->currentMessage][$this->currentTag])
01525 $this->wsdl->messages[$this->currentMessage][$this->currentTag] .= data;
01526 else
01527 $this->wsdl->messages[$this->currentMessage][$this->currentTag] = data;
01528 } else if ($this->status == 'operation') {
01529 if ($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag])
01530 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag] .= data;
01531 else
01532 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag] = data;
01533 }
01534 }
01535 }
01536
01537
01538
01539 function merge_url($parsed,$path) {
01540
01541 if (! is_array($parsed)) return false;
01542
01543 if (isset($parsed['scheme'])) {
01544 $sep = (strtolower($parsed['scheme']) == 'mailto' ? ':' : '://');
01545 $uri = $parsed['scheme'] . $sep;
01546 } else {
01547 $uri = '';
01548 }
01549
01550 if (isset($parsed['pass'])) {
01551 $uri .= "$parsed[user]:$parsed[pass]@";
01552 } elseif (isset($parsed['user'])) {
01553 $uri .= "$parsed[user]@";
01554 }
01555
01556 if (isset($parsed['host'])) $uri .= $parsed['host'];
01557 if (isset($parsed['port'])) $uri .= ":$parsed[port]";
01558 if ($path[0]!='/' && isset($parsed['path'])) {
01559 if ($parsed['path'][strlen($parsed['path'])-1] != '/') {
01560 $path = dirname($parsed['path']).'/'.$path;
01561 } else {
01562 $path = $parsed['path'].$path;
01563 }
01564 $path = $this->_normalize($path);
01565 }
01566 $sep = $path[0]=='/'?'':'/';
01567 $uri .= $sep.$path;
01568
01569 return $uri;
01570 }
01571
01572 function _normalize($path_str){
01573 $pwd='';
01574 $strArr=preg_split("/(\/)/",$path_str,-1,PREG_SPLIT_NO_EMPTY);
01575 $pwdArr="";
01576 $j=0;
01577 for($i=0;$i<count($strArr);$i++){
01578 if($strArr[$i]!=".."){
01579 if($strArr[$i]!="."){
01580 $pwdArr[$j]=$strArr[$i];
01581 $j++;
01582 }
01583 }else{
01584 array_pop($pwdArr);
01585 $j--;
01586 }
01587 }
01588 $pStr=implode("/",$pwdArr);
01589 $pwd=(strlen($pStr)>0) ? ("/".$pStr) : "/";
01590 return $pwd;
01591 }
01592 }
01593
01602 class ilBMFWSDL_ObjectParser extends ilBMFBase
01603 {
01604
01605 var $tnsPrefix = 'tns';
01606
01607
01608 var $wsdl = null;
01609
01618 function ilBMFWSDL_ObjectParser(&$objects, &$wsdl, $targetNamespace, $service_name, $service_desc = '') {
01619 parent::ilBMFBase('WSDLOBJECTPARSER');
01620
01621 $this->wsdl = &$wsdl;
01622
01623
01624 $this->_initialise($service_name);
01625
01626
01627 $wsdl_ref = (is_array($objects)? $objects : array(&$objects));
01628
01629 foreach ($wsdl_ref as $ref_item) {
01630 if (!is_object($ref_item))
01631 return $this->_raiseSoapFault('Invalid web service object passed to object parser', 'urn:' . get_class($object));
01632
01633 if ($this->_parse($ref_item, $targetNamespace, $service_name) != true)
01634 break;
01635 }
01636
01637
01638 if ($this->fault == NULL)
01639 $this->_generateBindingsAndServices($targetNamespace, $service_name, $service_desc);
01640 }
01641
01650 function _initialise($service_name) {
01651
01652
01653 $this->wsdl->namespaces['wsdl'] = SCHEMA_WSDL;
01654 $this->wsdl->namespaces['soap'] = SCHEMA_SOAP;
01655 $this->wsdl->namespaces[$this->tnsPrefix] = 'urn:' . $service_name;
01656 $this->wsdl->namespaces['xsd'] = array_search('xsd', $this->_namespaces);
01657 $this->wsdl->namespaces['SOAP-ENC'] = array_search('SOAP-ENC', $this->_namespaces);
01658
01659
01660 unset($this->wsdl->ns['urn:' . $service_name]);
01661 $this->wsdl->ns += array_flip($this->wsdl->namespaces);
01662
01663
01664
01665 }
01666
01673 function _parse(&$object, $schemaNamespace, $service_name) {
01674
01675
01676
01677 list ($schPrefix, $foo) = $this->_getTypeNs('{'.$schemaNamespace.'}');
01678 unset($foo);
01679
01680
01681
01682
01683
01684 foreach ($object->__typedef as $typeName => $typeValue)
01685 {
01686
01687
01688 list($nsPrefix, $typeName) = $this->_getTypeNs($typeName);
01689
01690
01691
01692 $this->wsdl->complexTypes[$schPrefix][$typeName] = array("name" => $typeName);
01693 $thisType =& $this->wsdl->complexTypes[$schPrefix][$typeName];
01694
01695
01696
01697
01698
01699
01700 if (is_array($typeValue))
01701 {
01702 reset($typeValue);
01703 if (is_array(current($typeValue)) && count($typeValue) == 1
01704 && count(current($typeValue)) == 1)
01705 {
01706
01707
01708 $thisType['type'] = 'Array';
01709 reset(current($typeValue));
01710 list($nsPrefix, $typeName) = $this->_getTypeNs(current(current($typeValue)));
01711 $thisType['namespace'] = $nsPrefix;
01712 $thisType['arrayType'] = $typeName . '[]';
01713
01714 }
01715 else if (!is_array(current($typeValue)))
01716 {
01717
01718
01719 $thisType['type'] = 'Struct';
01720 $thisType['order'] = 'all';
01721 $thisType['namespace'] = $nsPrefix;
01722 $thisType['elements'] = array();
01723
01724 foreach ($typeValue as $elementName => $elementType)
01725 {
01726 list($nsPrefix, $typeName) = $this->_getTypeNs($elementType);
01727 $thisType['elements'][$elementName]['name'] = $elementName;
01728 $thisType['elements'][$elementName]['type'] = $typeName;
01729 $thisType['elements'][$elementName]['namespace'] = $nsPrefix;
01730 }
01731 }
01732 else
01733 {
01734
01735
01736 return $this->_raiseSoapFault("The type definition for $nsPrefix:$typeName is invalid.", 'urn:' . get_class($object));
01737 }
01738 } else {
01739
01740
01741 return $this->_raiseSoapFault("The type definition for $nsPrefix:$typeName is invalid.", 'urn:' . get_class($object));
01742 }
01743 }
01744
01745
01746
01747
01748 $this->wsdl->elements[$schPrefix] = array();
01749
01750
01751
01752
01753 foreach ($object->__dispatch_map as $operationName => $messages)
01754 {
01755 foreach ($messages as $messageType => $messageParts)
01756 {
01757 unset($thisMessage);
01758
01759 switch ($messageType) {
01760 case 'in':
01761 $this->wsdl->messages[$operationName . 'Request'] = array();
01762 $thisMessage =& $this->wsdl->messages[$operationName . 'Request'];
01763 break;
01764
01765 case 'out':
01766 $this->wsdl->messages[$operationName . 'Response'] = array();
01767 $thisMessage =& $this->wsdl->messages[$operationName . 'Response'];
01768 break;
01769
01770 case 'alias':
01771
01772 break;
01773
01774 default:
01775
01776 break;
01777 }
01778
01779 if (isset($thisMessage))
01780 {
01781 foreach ($messageParts as $partName => $partType)
01782 {
01783 list ($nsPrefix, $typeName) = $this->_getTypeNs($partType);
01784
01785 $thisMessage[$partName] = array(
01786 'name' => $partName,
01787 'type' => $typeName,
01788 'namespace' => $nsPrefix
01789 );
01790 }
01791 }
01792 }
01793 }
01794
01795
01796
01797
01798
01799
01800 if (!isset($this->wsdl->portTypes[$service_name . 'Port']))
01801 $this->wsdl->portTypes[$service_name . 'Port'] = array();
01802 $thisPortType =& $this->wsdl->portTypes[$service_name . 'Port'];
01803
01804 foreach ($object->__dispatch_map as $operationName => $messages)
01805 {
01806 $thisPortType[$operationName] = array('name' => $operationName);
01807
01808 foreach ($messages as $messageType => $messageParts)
01809 {
01810 switch ($messageType) {
01811 case 'in':
01812 $thisPortType[$operationName]['input'] = array(
01813 'message' => $operationName . 'Request',
01814 'namespace' => $this->tnsPrefix);
01815 break;
01816
01817 case 'out':
01818 $thisPortType[$operationName]['output'] = array(
01819 'message' => $operationName . 'Response',
01820 'namespace' => $this->tnsPrefix);
01821 break;
01822
01823 default:
01824 break;
01825 }
01826 }
01827 }
01828
01829 return true;
01830 }
01831
01841 function _generateBindingsAndServices($schemaNamespace, $service_name, $service_desc = '')
01842 {
01843
01844
01845
01846
01847
01848
01849 $this->wsdl->bindings[$service_name . 'Binding'] = array(
01850 'type' => $service_name . 'Port',
01851 'namespace' => $this->tnsPrefix,
01852 'style' => 'rpc',
01853 'transport' => SCHEMA_SOAP_HTTP,
01854 'operations' => array());
01855 $thisBinding =& $this->wsdl->bindings[$service_name . 'Binding'];
01856
01857 foreach ($this->wsdl->portTypes[$service_name . 'Port'] as $operationName => $operationData)
01858 {
01859 $thisBinding['operations'][$operationName] = array(
01860 'soapAction' => $schemaNamespace . '#' . $operationName,
01861 'style' => $thisBinding['style']);
01862
01863 foreach (array('input', 'output') as $messageType)
01864 if (isset($operationData[$messageType]))
01865 $thisBinding['operations'][$operationName][$messageType] = array(
01866 'use' => 'encoded',
01867 'namespace' => $schemaNamespace,
01868 'encodingStyle' => SOAP_SCHEMA_ENCODING);
01869 }
01870
01871
01872
01873
01874
01875
01876
01877 $this->wsdl->services[$service_name . 'Service'] = array('ports' => array());
01878 $thisService =& $this->wsdl->services[$service_name . 'Service']['ports'];
01879
01880 foreach ($this->wsdl->bindings as $bindingName => $bindingData)
01881 {
01882 $thisService[$bindingData['type']] = array(
01883 'name' => $bindingData['type'],
01884 'binding' => $bindingName,
01885 'namespace' => $this->tnsPrefix,
01886 'address' => array('location' =>
01887 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'] .
01888 (isset($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '')),
01889 'type' => 'soap');
01890 }
01891
01892
01893 $this->wsdl->set_service($service_name . 'Service');
01894 $this->wsdl->uri = $this->wsdl->namespaces[$this->tnsPrefix];
01895
01896
01897
01898
01899 $this->wsdl->definition = array(
01900 'name' => $service_name,
01901 'targetNamespace' => $this->wsdl->namespaces[$this->tnsPrefix],
01902 'xmlns' => SCHEMA_WSDL);
01903
01904 foreach ($this->wsdl->namespaces as $nsPrefix => $namespace)
01905 $this->wsdl->definition['xmlns:' . $nsPrefix] = $namespace;
01906 }
01907
01908
01909
01910
01911
01912
01913
01914
01915 function _getTypeNs($type) {
01916 preg_match_all("'\{(.*)\}'sm",$type,$m);
01917 if (isset($m[1][0]) && $m[1][0] != '') {
01918 if (!array_key_exists($m[1][0],$this->wsdl->ns)) {
01919 $ns_pref = 'ns' . count($this->wsdl->namespaces);
01920 $this->wsdl->ns[$m[1][0]] = $ns_pref;
01921 $this->wsdl->namespaces[$ns_pref] = $m[1][0];
01922 }
01923 $typens = $this->wsdl->ns[$m[1][0]];
01924 $type = ereg_replace($m[0][0],'',$type);
01925 } else {
01926 $typens = 'xsd';
01927 }
01928 return array($typens,$type);
01929 }
01930 }
01931 ?>