ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
class.ilBMFClient.php
Go to the documentation of this file.
1<?php
25require_once dirname(__FILE__).'/class.ilBMFValue.php';
26require_once dirname(__FILE__).'/class.ilBMFBase.php';
27require_once dirname(__FILE__).'/class.ilBMFTransport.php';
28require_once dirname(__FILE__).'/class.ilBMFWSDL.php';
29require_once dirname(__FILE__).'/class.ilBMFFault.php';
30require_once dirname(__FILE__).'/class.ilBMFParser.php';
31
32// Arnaud: the following code was taken from DataObject and adapted to suit
33
34// this will be horrifically slow!!!!
35// NOTE: Overload SEGFAULTS ON PHP4 + Zend Optimizer
36// these two are BC/FC handlers for call in PHP4/5
37
38if (!class_exists('ilBMFClient_Overload')) {
39 if (substr(phpversion(), 0, 1) == 5) {
40 class ilBMFClient_Overload extends ilBMFBase {
41 function __call($method, $args)
42 {
43 $return = null;
44 $this->_call($method, $args, $return);
45 return $return;
46 }
47 }
48 } else {
49 if (!function_exists('clone')) {
50 eval('function clone($t) { return $t; }');
51 }
52 eval('
53 class ilBMFClient_Overload extends ilBMFBase {
54 function __call($method, $args, &$return)
55 {
56 return $this->_call($method, $args, $return);
57 }
58 }');
59 }
60}
61
82{
98 var $_endpoint = '';
99
105 var $_portName = '';
106
113
119 var $xml;
120
126 var $wire;
127 var $__last_request = null;
129
135 var $__options = array('trace'=>0);
136
143
149 var $headersOut = null;
150
156 var $headersIn = null;
157
163 var $__proxy_params = array();
164
166
178 function ilBMFClient($endpoint, $wsdl = false, $portName = false,
179 $proxy_params = array())
180 {
181 parent::ilBMFBase('Client');
182
183 $this->_endpoint = $endpoint;
184 $this->_portName = $portName;
185 $this->__proxy_params = $proxy_params;
186
187 // This hack should perhaps be removed as it might cause unexpected
188 // behaviour.
189 $wsdl = $wsdl
190 ? $wsdl
191 : strtolower(substr($endpoint, -4)) == 'wsdl';
192
193 // make values
194 if ($wsdl) {
195 $this->__endpointType = 'wsdl';
196 // instantiate wsdl class
197 $this->_wsdl =& new ilBMFWSDL($this->_endpoint,
198 $this->__proxy_params);
199 if ($this->_wsdl->fault) {
200 $this->_raiseSoapFault($this->_wsdl->fault);
201 }
202 }
203 }
204
205 function _reset()
206 {
207 $this->xml = null;
208 $this->wire = null;
209 $this->__last_request = null;
210 $this->__last_response = null;
211 $this->headersIn = null;
212 $this->headersOut = null;
213 }
214
226 function setEncoding($encoding)
227 {
228 if (in_array($encoding, $this->_encodings)) {
229 $this->_encoding = $encoding;
230 return;
231 }
232 return $this->_raiseSoapFault('Invalid Encoding');
233 }
234
245 function addHeader(&$soap_value)
246 {
247 // Add a new header to the message.
248 if (is_a($soap_value, 'ilBMFHeader')) {
249 $this->headersOut[] =& $soap_value;
250 } elseif (is_array($soap_value)) {
251 // name, value, namespace, mustunderstand, actor
252 $this->headersOut[] =& new ilBMFHeader($soap_value[0],
253 null,
254 $soap_value[1],
255 $soap_value[2],
256 $soap_value[3]);;
257 } else {
258 $this->_raiseSoapFault('Invalid parameter provided to addHeader(). Must be an array or a SOAP_Header.');
259 }
260 }
261
290 function &call($method, &$params, $namespace = false, $soapAction = false)
291 {
292 $this->headersIn = null;
293 $this->__last_request = null;
294 $this->__last_response = null;
295 $this->wire = null;
296 $this->xml = null;
297
298 $soap_data =& $this->__generate($method, $params, $namespace, $soapAction);
299 if (PEAR::isError($soap_data)) {
300 $fault =& $this->_raiseSoapFault($soap_data);
301 return $fault;
302 }
303
304 // __generate() may have changed the endpoint if the WSDL has more
305 // than one service, so we need to see if we need to generate a new
306 // transport to hook to a different URI. Since the transport protocol
307 // can also change, we need to get an entirely new object. This could
308 // probably be optimized.
309 if (!$this->_soap_transport ||
310 $this->_endpoint != $this->_soap_transport->url) {
311 $this->_soap_transport =& ilBMFTransport::getTransport($this->_endpoint);
312 if (PEAR::isError($this->_soap_transport)) {
313 $fault =& $this->_soap_transport;
314 $this->_soap_transport = null;
315 $fault =& $this->_raiseSoapFault($fault);
316 return $fault;
317 }
318 }
319 $this->_soap_transport->encoding = $this->_encoding;
320
321 // Send the message.
322 $transport_options = array_merge_recursive($this->__proxy_params,
323 $this->__options);
324 $this->xml = $this->_soap_transport->send($soap_data, $transport_options);
325
326 // Save the wire information for debugging.
327 if ($this->__options['trace'] > 0) {
328 $this->__last_request =& $this->_soap_transport->outgoing_payload;
329 $this->__last_response =& $this->_soap_transport->incoming_payload;
330 $this->wire = $this->__get_wire();
331 }
332 if ($this->_soap_transport->fault) {
333 $fault =& $this->_raiseSoapFault($this->xml);
334 return $fault;
335 }
336
337 $this->__attachments =& $this->_soap_transport->attachments;
338 $this->__result_encoding = $this->_soap_transport->result_encoding;
339
340 if (isset($this->__options['result']) &&
341 $this->__options['result'] != 'parse') {
342 return $this->xml;
343 }
344
345 $result = &$this->__parse($this->xml, $this->__result_encoding, $this->__attachments);
346
347 return $result;
348 }
349
368 function setOpt($category, $option, $value = null)
369 {
370 if (!is_null($value)) {
371 if (!isset($this->__options[$category])) {
372 $this->__options[$category] = array();
373 }
374 $this->__options[$category][$option] = $value;
375 } else {
376 $this->__options[$category] = $option;
377 }
378 }
379
399 function _call($method, $params, &$return_value)
400 {
401 // Overloading lowercases the method name, we need to look into the
402 // wsdl and try to find the correct method name to get the correct
403 // case for the call.
404 if ($this->_wsdl) {
405 $this->_wsdl->matchMethod($method);
406 }
407
408 $return_value =& $this->call($method, $params);
409
410 return true;
411 }
412
414 {
415 $request =& $this->__last_request;
416 return $request;
417 }
418
420 {
421 $response =& $this->__last_response;
422 return $response;
423 }
424
425 function __use($use)
426 {
427 $this->__options['use'] = $use;
428 }
429
430 function __style($style)
431 {
432 $this->__options['style'] = $style;
433 }
434
435 function __trace($level)
436 {
437 $this->__options['trace'] = $level;
438 }
439
440 function &__generate($method, &$params, $namespace = false,
441 $soapAction = false)
442 {
443 $this->fault = null;
444 $this->__options['input']='parse';
445 $this->__options['result']='parse';
446 $this->__options['parameters'] = false;
447
448 if ($params && gettype($params) != 'array') {
449 $params = array($params);
450 }
451
452 if (gettype($namespace) == 'array') {
453 foreach ($namespace as $optname => $opt) {
454 $this->__options[strtolower($optname)] = $opt;
455 }
456 if (isset($this->__options['namespace'])) {
457 $namespace = $this->__options['namespace'];
458 } else {
459 $namespace = false;
460 }
461 } else {
462 // We'll place $soapAction into our array for usage in the
463 // transport.
464 $this->__options['soapaction'] = $soapAction;
465 $this->__options['namespace'] = $namespace;
466 }
467
468 if ($this->__endpointType == 'wsdl') {
469 $this->_setSchemaVersion($this->_wsdl->xsd);
470
471 // Get port name.
472 if (!$this->_portName) {
473 $this->_portName = $this->_wsdl->getPortName($method);
474 }
475 if (PEAR::isError($this->_portName)) {
476 $fault =& $this->_raiseSoapFault($this->_portName);
477 return $fault;
478 }
479
480 // Get endpoint.
481 $this->_endpoint = $this->_wsdl->getEndpoint($this->_portName);
482 if (PEAR::isError($this->_endpoint)) {
483 $fault =& $this->_raiseSoapFault($this->_endpoint);
484 return $fault;
485 }
486
487 // Get operation data.
488 $opData = $this->_wsdl->getOperationData($this->_portName, $method);
489
490 if (PEAR::isError($opData)) {
491 $fault =& $this->_raiseSoapFault($opData);
492 return $fault;
493 }
494 $namespace = $opData['namespace'];
495 $this->__options['style'] = $opData['style'];
496 $this->__options['use'] = $opData['input']['use'];
497 $this->__options['soapaction'] = $opData['soapAction'];
498
499 // Set input parameters.
500 if ($this->__options['input'] == 'parse') {
501 $this->__options['parameters'] = $opData['parameters'];
502 $nparams = array();
503 if (isset($opData['input']['parts']) &&
504 count($opData['input']['parts'])) {
505 $i = 0;
506 foreach ($opData['input']['parts'] as $name => $part) {
507 $xmlns = '';
508 $attrs = array();
509 // Is the name a complex type?
510 if (isset($part['element'])) {
511 $xmlns = $this->_wsdl->namespaces[$part['namespace']];
512 $part = $this->_wsdl->elements[$part['namespace']][$part['type']];
513 $name = $part['name'];
514 }
515 if (isset($params[$name]) ||
516 $this->_wsdl->getDataHandler($name, $part['namespace'])) {
517 $nparams[$name] =& $params[$name];
518 } else {
519 // We now force an associative array for
520 // parameters if using WSDL.
521 $fault =& $this->_raiseSoapFault("The named parameter $name is not in the call parameters.");
522 return $fault;
523 }
524 if (gettype($nparams[$name]) != 'object' ||
525 !is_a($nparams[$name], 'ilBMFValue')) {
526 // Type is likely a qname, split it apart, and get
527 // the type namespace from WSDL.
528 $qname =& new QName($part['type']);
529 if ($qname->ns) {
530 $type_namespace = $this->_wsdl->namespaces[$qname->ns];
531 } elseif (isset($part['namespace'])) {
532 $type_namespace = $this->_wsdl->namespaces[$part['namespace']];
533 } else {
534 $type_namespace = null;
535 }
536 $qname->namespace = $type_namespace;
537 $type = $qname->name;
538 $pqname = $name;
539 if ($xmlns) {
540 $pqname = '{' . $xmlns . '}' . $name;
541 }
542 $nparams[$name] =& new ilBMFValue($pqname,
543 $qname->fqn(),
544 $nparams[$name],
545 $attrs);
546 } else {
547 // WSDL fixups to the SOAP value.
548 }
549 }
550 }
551 $params =& $nparams;
552 unset($nparams);
553 }
554 } else {
555 $this->_setSchemaVersion(SOAP_XML_SCHEMA_VERSION);
556 }
557
558 // Serialize the message.
559 $this->_section5 = (!isset($this->__options['use']) ||
560 $this->__options['use'] != 'literal');
561
562 if (!isset($this->__options['style']) ||
563 $this->__options['style'] == 'rpc') {
564 $this->__options['style'] = 'rpc';
565 $this->docparams = true;
566 $mqname =& new QName($method, $namespace);
567 $methodValue =& new ilBMFValue($mqname->fqn(), 'Struct', $params);
568 $soap_msg = $this->_makeEnvelope($methodValue,
569 $this->headersOut,
570 $this->_encoding,
571 $this->__options);
572 } else {
573 if (!$params) {
574 $mqname =& new QName($method, $namespace);
575 $mynull = null;
576 $params =& new ilBMFValue($mqname->fqn(), 'Struct', $mynull);
577 } elseif ($this->__options['input'] == 'parse') {
578 if (is_array($params)) {
579 $nparams = array();
580 $keys = array_keys($params);
581 foreach ($keys as $k) {
582 if (gettype($params[$k]) != 'object') {
583 $nparams[] =& new ilBMFValue($k,
584 false,
585 $params[$k]);
586 } else {
587 $nparams[] =& $params[$k];
588 }
589 }
590 $params =& $nparams;
591 }
592 if ($this->__options['parameters']) {
593 $mqname =& new QName($method, $namespace);
594 $params =& new ilBMFValue($mqname->fqn(),
595 'Struct',
596 $params);
597 }
598 }
599 $soap_msg = $this->_makeEnvelope($params,
600 $this->headersOut,
601 $this->_encoding,
602 $this->__options);
603 }
604 unset($this->headersOut);
605
606 if (PEAR::isError($soap_msg)) {
607 $fault =& $this->_raiseSoapFault($soap_msg);
608 return $fault;
609 }
610
611 // Handle MIME or DIME encoding.
612 // TODO: DIME encoding should move to the transport, do it here for
613 // now and for ease of getting it done.
614 if (count($this->__attachments)) {
615 if ((isset($this->__options['attachments']) &&
616 $this->__options['attachments'] == 'Mime') ||
617 isset($this->__options['Mime'])) {
618 $soap_msg =& $this->_makeMimeMessage($soap_msg,
619 $this->_encoding);
620 } else {
621 // default is dime
622 $soap_msg =& $this->_makeDIMEMessage($soap_msg,
623 $this->_encoding);
624 $this->__options['headers']['Content-Type'] = 'application/dime';
625 }
626 if (PEAR::isError($soap_msg)) {
627 $fault =& $this->_raiseSoapFault($soap_msg);
628 return $fault;
629 }
630 }
631
632 // Instantiate client.
633 if (is_array($soap_msg)) {
634 $soap_data =& $soap_msg['body'];
635 if (count($soap_msg['headers'])) {
636 if (isset($this->__options['headers'])) {
637 $this->__options['headers'] = array_merge($this->__options['headers'], $soap_msg['headers']);
638 } else {
639 $this->__options['headers'] = $soap_msg['headers'];
640 }
641 }
642 } else {
643 $soap_data =& $soap_msg;
644 }
645
646 return $soap_data;
647 }
648
649 function &__parse(&$response, $encoding, &$attachments)
650 {
651 // Parse the response.
652 $response =& new ilBMFParser($response, $encoding, $attachments);
653 if ($response->fault) {
654 $fault =& $this->_raiseSoapFault($response->fault);
655 return $fault;
656 }
657
658 // Return array of parameters.
659 $return =& $response->getResponse();
660 $headers =& $response->getHeaders();
661 if ($headers) {
662 $this->headersIn =& $this->__decodeResponse($headers, false);
663 }
664
665 $decoded = &$this->__decodeResponse($return);
666 return $decoded;
667 }
668
669 function &__decodeResponse(&$response, $shift = true)
670 {
671 if (!$response) {
672 $decoded = null;
673 return $decoded;
674 }
675
676 // Check for valid response.
677 if (PEAR::isError($response)) {
678 $fault =& $this->_raiseSoapFault($response);
679 return $fault;
680 } elseif (!is_a($response, 'ilbmfvalue')) {
681 $fault =& $this->_raiseSoapFault("Didn't get ilBMFValue object back from client");
682 return $fault;
683 }
684
685 // Decode to native php datatype.
686 $returnArray =& $this->_decode($response);
687
688 // Fault?
689 if (PEAR::isError($returnArray)) {
690 $fault =& $this->_raiseSoapFault($returnArray);
691 return $fault;
692 }
693
694 if (is_object($returnArray) &&
695 strcasecmp(get_class($returnArray), 'stdClass') == 0) {
696 $returnArray = get_object_vars($returnArray);
697 }
698 if (is_array($returnArray)) {
699 if (isset($returnArray['faultcode']) ||
700 isset($returnArray['SOAP-ENV:faultcode'])) {
701 $faultcode = $faultstring = $faultdetail = $faultactor = '';
702 foreach ($returnArray as $k => $v) {
703 if (stristr($k, 'faultcode')) $faultcode = $v;
704 if (stristr($k, 'faultstring')) $faultstring = $v;
705 if (stristr($k, 'detail')) $faultdetail = $v;
706 if (stristr($k, 'faultactor')) $faultactor = $v;
707 }
708 $fault =& $this->_raiseSoapFault($faultstring, $faultdetail, $faultactor, $faultcode);
709 return $fault;
710 }
711 // Return array of return values.
712 if ($shift && count($returnArray) == 1) {
713 $decoded = array_shift($returnArray);
714 return $decoded;
715 }
716 return $returnArray;
717 }
718 return $returnArray;
719 }
720
721 function __get_wire()
722 {
723 if ($this->__options['trace'] > 0 &&
724 ($this->__last_request || $this->__last_response)) {
725 return "OUTGOING:\n\n" .
726 $this->__last_request .
727 "\n\nINCOMING\n\n" .
728 preg_replace("/></",">\r\n<", $this->__last_response);
729 }
730
731 return null;
732 }
733
734}
$result
isError($data, $code=null)
Tell whether a value is a PEAR error.
Definition: PEAR.php:279
const SOAP_XML_SCHEMA_VERSION
const SOAP_DEFAULT_ENCODING
& __decodeResponse(&$response, $shift=true)
setEncoding($encoding)
Sets the character encoding.
setOpt($category, $option, $value=null)
Sets an option to use with the transport layers.
& __generate($method, &$params, $namespace=false, $soapAction=false)
ilBMFClient($endpoint, $wsdl=false, $portName=false, $proxy_params=array())
Constructor.
& call($method, &$params, $namespace=false, $soapAction=false)
Calls a method on the SOAP endpoint.
& __parse(&$response, $encoding, &$attachments)
addHeader(&$soap_value)
Adds a header to the envelope.
_call($method, $params, &$return_value)
Call method supporting the overload extension.
& getTransport($url, $encoding=SOAP_DEFAULT_ENCODING)
if($err=$client->getError()) $namespace
$style
Definition: example_012.php:70
$params
Definition: example_049.php:96