SOAP
[ class tree: SOAP ] [ index: SOAP ] [ all elements ]

Source for file Server.php

Documentation is available at Server.php

  1. <?php
  2. /**
  3.  * This file contains the code for the SOAP server.
  4.  *
  5.  * PHP versions 4 and 5
  6.  *
  7.  * LICENSE: This source file is subject to version 2.02 of the PHP license,
  8.  * that is bundled with this package in the file LICENSE, and is available at
  9.  * through the world-wide-web at http://www.php.net/license/2_02.txt.  If you
  10.  * did not receive a copy of the PHP license and are unable to obtain it
  11.  * through the world-wide-web, please send a note to license@php.net so we can
  12.  * mail you a copy immediately.
  13.  *
  14.  * @category   Web Services
  15.  * @package    SOAP
  16.  * @author     Dietrich Ayala <dietrich@ganx4.com> Original Author
  17.  * @author     Shane Caraveo <Shane@Caraveo.com>   Port to PEAR and more
  18.  * @author     Chuck Hagenbuch <chuck@horde.org>   Maintenance
  19.  * @author     Jan Schneider <jan@horde.org>       Maintenance
  20.  * @copyright  2003-2005 The PHP Group
  21.  * @license    http://www.php.net/license/2_02.txt  PHP License 2.02
  22.  * @link       http://pear.php.net/package/SOAP
  23.  */
  24.  
  25. require_once 'SOAP/Base.php';
  26. require_once 'SOAP/Fault.php';
  27. require_once 'SOAP/Parser.php';
  28. require_once 'SOAP/Value.php';
  29. require_once 'SOAP/WSDL.php';
  30.  
  31. /**
  32.  * SOAP Server Class
  33.  *
  34.  * Originaly based on SOAPx4 by Dietrich Ayala
  35.  * http://dietrich.ganx4.com/soapx4
  36.  *
  37.  * @access   public
  38.  * @package  SOAP
  39.  * @author   Shane Caraveo <shane@php.net> Conversion to PEAR and updates
  40.  * @author   Dietrich Ayala <dietrich@ganx4.com> Original Author
  41.  */
  42. class SOAP_Server extends SOAP_Base
  43. {
  44.     /**
  45.      *
  46.      * @var array 
  47.      */
  48.     var $dispatch_map = array()// create empty dispatch map
  49.     var $dispatch_objects = array();
  50.     var $soapobject = null;
  51.     var $call_methodname = null;
  52.     var $callHandler = null;
  53.     var $callValidation = true;
  54.  
  55.     /**
  56.      * A list of headers that are going to be sent back to the client.
  57.      *
  58.      * @var array 
  59.      */
  60.     var $headers = array();
  61.  
  62.     /**
  63.      *
  64.      * @var string 
  65.      */
  66.     var $request = '';
  67.  
  68.     /**
  69.      *
  70.      * @var string  XML-Encoding
  71.      */
  72.     var $xml_encoding = SOAP_DEFAULT_ENCODING;
  73.     var $response_encoding = 'UTF-8';
  74.  
  75.     var $result = 'successful'// for logging interop results to db
  76.  
  77.     var $endpoint = ''// the uri to ME!
  78.  
  79.     var $service = ''//soapaction header
  80.     var $method_namespace = null;
  81.  
  82.     /**
  83.      * Options.
  84.      *
  85.      * @var array 
  86.      */
  87.     var $_options = array('use' => 'encoded',
  88.                           'style' => 'rpc',
  89.                           'parameters' => 0,
  90.                           'http_status_success' => '200 OK',
  91.                           'http_status_fault' => '500 SOAP Fault');
  92.  
  93.     function SOAP_Server($options = null)
  94.     {
  95.         ini_set('track_errors'1);
  96.         parent::SOAP_Base('Server');
  97.  
  98.         if (is_array($options)) {
  99.             if (isset($options['use'])) {
  100.                 $this->_options['use'$options['use'];
  101.             }
  102.             if (isset($options['style'])) {
  103.                 $this->_options['style'$options['style'];
  104.             }
  105.             if (isset($options['parameters'])) {
  106.                 $this->_options['parameters'$options['parameters'];
  107.             }
  108.         }
  109.         // assume we encode with section 5
  110.         $this->_section5 = true;
  111.         if ($this->_options['use'== 'literal'{
  112.             $this->_section5 = false;
  113.         }
  114.     }
  115.  
  116.     /**
  117.      * Error handler for errors that happen in proxied methods.
  118.      *
  119.      * To always return a valid SOAP response even on errors that don't happen
  120.      * in this code, the errors are catched, transformed to a SOAP fault and
  121.      * immediately sent to the client.
  122.      *
  123.      * @see http://www.php.net/set_error_handler
  124.      */
  125.     function _errorHandler($errno$errmsg$filename$linenum)
  126.     {
  127.         /* The error handler should ignore '0' errors, eg. hidden by @ - see
  128.          * the set_error_handler manual page. (thanks to Alan Knowles). */
  129.         if (!$errno || !error_reporting(|| $errno == E_NOTICE ||
  130.             (defined('E_STRICT'&& $errno == constant('E_STRICT'))) {
  131.             return false;
  132.         }
  133.  
  134.         $this->fault = new SOAP_Fault($errmsg'Server''PHP'"Errno: $errno\nFilename: $filename\nLineno: $linenum\n");
  135.  
  136.         $this->_sendResponse();
  137.         exit;
  138.     }
  139.  
  140.     function _getContentEncoding($content_type)
  141.     {
  142.         /* Get the character encoding of the incoming request treat incoming
  143.          * data as UTF-8 if no encoding set. */
  144.         $this->xml_encoding = 'UTF-8';
  145.         if (strpos($content_type'=')) {
  146.             $enc strtoupper(str_replace('"'''substr(strstr($content_type'=')1)));
  147.             if (!in_array($enc$this->_encodings)) {
  148.                 return false;
  149.             }
  150.             $this->xml_encoding = $enc;
  151.         }
  152.  
  153.         return true;
  154.     }
  155.  
  156.  
  157.     /**
  158.      * Parses the request and posts or returns the response.
  159.      *
  160.      * @param string $data      The SOAP request data.
  161.      * @param string $endpoint  The service endpoint. Determined automatically
  162.      *                           if left empty.
  163.      * @param boolean $test 
  164.      * @param boolean $return   Whether to return the SOAP response data
  165.      *                           instead of sending it to the client.
  166.      */
  167.     function service($data$endpoint ''$test = false$return = false)
  168.     {
  169.         $response = null;
  170.         $attachments = array();
  171.         $useEncoding 'DIME';
  172.  
  173.         /* Figure out our endpoint. */
  174.         $this->endpoint = $endpoint;
  175.         if (!$test && !$this->endpoint{
  176.             /* We'll try to build our endpoint. */
  177.             $this->endpoint = 'http://' $_SERVER['SERVER_NAME'];
  178.             if (isset($_SERVER['SERVER_PORT'])) {
  179.                 $this->endpoint .= ':' $_SERVER['SERVER_PORT'];
  180.             }
  181.             $this->endpoint .= $_SERVER['SCRIPT_NAME'];
  182.         }
  183.  
  184.         /* Get the character encoding of the incoming request treat incoming
  185.          * data as UTF-8 if no encoding set. */
  186.         if (isset($_SERVER['CONTENT_TYPE'])) {
  187.             if (strcasecmp($_SERVER['CONTENT_TYPE']'application/dime'== 0{
  188.                 $this->_decodeDIMEMessage($data$this->headers$attachments);
  189.                 $useEncoding 'DIME';
  190.             elseif (stristr($_SERVER['CONTENT_TYPE']'multipart/related')) {
  191.                 /* This is a mime message, let's decode it. */
  192.                 $data 'Content-Type: ' .
  193.                     stripslashes($_SERVER['CONTENT_TYPE'].
  194.                     "\r\n\r\n" $data;
  195.                 $this->_decodeMimeMessage($data$this->headers$attachments);
  196.                 $useEncoding 'Mime';
  197.             }
  198.             if (!isset($this->headers['content-type'])) {
  199.                 $this->headers['content-type'stripslashes($_SERVER['CONTENT_TYPE']);
  200.             }
  201.             if (!$this->fault &&
  202.                 !$this->_getContentEncoding($this->headers['content-type'])) {
  203.                 $this->xml_encoding = SOAP_DEFAULT_ENCODING;
  204.                 /* Found encoding we don't understand; return a fault. */
  205.                 $this->_raiseSoapFault('Unsupported encoding, use one of ISO-8859-1, US-ASCII, UTF-8''''''Server');
  206.             }
  207.         }
  208.  
  209.         /* If this is not a POST with Content-Type text/xml, try to return a
  210.          * WSDL file. */
  211.         if (!$this->fault && !$test &&
  212.             ((isset($_SERVER['REQUEST_METHOD']&&
  213.               $_SERVER['REQUEST_METHOD'!= 'POST'||
  214.              (isset($this->headers['content-type']&&
  215.               strncmp($this->headers['content-type']'text/xml'8!= 0))) {
  216.             /* This is not possibly a valid SOAP request, try to return a WSDL
  217.              * file. */
  218.             $got = isset($this->headers['content-type']$this->headers['content-type''Nothing!';
  219.             $this->_raiseSoapFault('Invalid SOAP request, must be POST with content-type: text/xml, got: ' $got'''''Server');
  220.         }
  221.  
  222.         if (!$this->fault{
  223.             /* $response is a SOAP_Msg object. */
  224.             $soap_msg $this->parseRequest($data$attachments);
  225.  
  226.             /* Handle Mime or DIME encoding. */
  227.             /* TODO: DIME decoding should move to the transport, do it here
  228.              * for now and for ease of getting it done. */
  229.             if (count($this->_attachments)) {
  230.                 if ($useEncoding == 'Mime'{
  231.                     $soap_msg $this->_makeMimeMessage($soap_msg);
  232.                 else {
  233.                     // default is dime
  234.                     $soap_msg $this->_makeDIMEMessage($soap_msg);
  235.                     $this->headers['Content-Type''application/dime';
  236.                 }
  237.                 if (PEAR::isError($soap_msg)) {
  238.                     return $this->_raiseSoapFault($soap_msg);
  239.                 }
  240.             }
  241.  
  242.             if (is_array($soap_msg)) {
  243.                 $response $soap_msg['body'];
  244.                 if (count($soap_msg['headers'])) {
  245.                     $this->headers = $soap_msg['headers'];
  246.                 }
  247.             else {
  248.                 $response $soap_msg;
  249.             }
  250.         }
  251.  
  252.         if ($return{
  253.             if ($this->fault{
  254.                 $response $this->fault->message();
  255.             }
  256.             return $response;
  257.         }
  258.  
  259.         $this->_sendResponse($response);
  260.     }
  261.  
  262.     /**
  263.      * Sends the final HTTP response to the client, including the HTTP header
  264.      * and the HTTP body.
  265.      *
  266.      * If an error happened, it returns a SOAP fault instead of the response
  267.      * body.
  268.      *
  269.      * @param string $response  The response body.
  270.      */
  271.     function _sendResponse($response '')
  272.     {
  273.         /* Make distinction between the different SAPIs, running PHP as CGI or
  274.          * as a module. */
  275.         if (stristr(php_sapi_name()'cgi'=== 0{
  276.             $hdrs_type 'Status:';
  277.         else {
  278.             $hdrs_type 'HTTP/1.1';
  279.         }
  280.  
  281.         if ($this->fault{
  282.             $hdrs $hdrs_type ' ' $this->_options['http_status_fault'"\r\n";
  283.             $response $this->fault->message($this->response_encoding);
  284.         else {
  285.             $hdrs $hdrs_type ' ' $this->_options['http_status_success'"\r\n";
  286.         }
  287.         header($hdrs);
  288.  
  289.         $this->headers['Server'SOAP_LIBRARY_NAME;
  290.         if (!isset($this->headers['Content-Type'])) {
  291.             $this->headers['Content-Type''text/xml; charset=' .
  292.                 $this->response_encoding;
  293.         }
  294.         $this->headers['Content-Length'strlen($response);
  295.  
  296.         foreach ($this->headers as $k => $v{
  297.             header("$k$v");
  298.             $hdrs .= "$k$v\r\n";
  299.         }
  300.  
  301.         $this->response $hdrs "\r\n" $response;
  302.         print $response;
  303.     }
  304.  
  305.     function &callMethod($methodname&$args)
  306.     {
  307.         if ($this->callHandler{
  308.             $ret @call_user_func_array($this->callHandlerarray($methodname$args));
  309.             return $ret;
  310.         }
  311.  
  312.         set_error_handler(array($this'_errorHandler'));
  313.  
  314.         if ($args{
  315.             /* Call method with parameters. */
  316.             if (isset($this->soapobject&& is_object($this->soapobject)) {
  317.                 $ret call_user_func_array(array(&$this->soapobject$methodname)$args);
  318.             else {
  319.                 $ret call_user_func_array($methodname$args);
  320.             }
  321.         else {
  322.             /* Call method withour parameters. */
  323.             if (is_object($this->soapobject)) {
  324.                 $ret call_user_func(array(&$this->soapobject$methodname));
  325.             else {
  326.                 $ret call_user_func($methodname);
  327.             }
  328.         }
  329.  
  330.         restore_error_handler();
  331.  
  332.         return $ret;
  333.     }
  334.  
  335.     /**
  336.      * Creates SOAP_Value objects with return values from method.
  337.      * Uses method signature to determine type.
  338.      *
  339.      * @param mixed $method_response  The result(s).
  340.      * @param array|string$type      The type(s) of the return value(s).
  341.      * @param string $return_name     The name of the return value.
  342.      * @param string $namespace       The namespace of the return value.
  343.      *
  344.      * @return array  List of SOAP_Value objects.
  345.      */
  346.     function buildResult(&$method_response&$return_type,
  347.                          $return_name 'return'$namespace '')
  348.     {
  349.         if (is_a($method_response'SOAP_Value')) {
  350.             $return_val = array($method_response);
  351.         else {
  352.             if (is_array($return_type&& is_array($method_response)) {
  353.                 $i = 0;
  354.  
  355.                 foreach ($return_type as $key => $type{
  356.                     if (is_numeric($key)) {
  357.                         $key 'item';
  358.                     }
  359.                     if (is_a($method_response[$i]'SOAP_Value')) {
  360.                         $return_val[=$method_response[$i++];
  361.                     else {
  362.                         $qn = new QName($key$namespace);
  363.                         $return_val[= new SOAP_Value($qn->fqn()$type$method_response[$i++]);
  364.                     }
  365.                 }
  366.             else {
  367.                 if (is_array($return_type)) {
  368.                     $keys array_keys($return_type);
  369.                     if (!is_numeric($keys[0])) {
  370.                         $return_name $keys[0];
  371.                     }
  372.                     $values array_values($return_type);
  373.                     $return_type $values[0];
  374.                 }
  375.                 $qn = new QName($return_name$namespace);
  376.                 $return_val = array(new SOAP_Value($qn->fqn()$return_type$method_response));
  377.             }
  378.         }
  379.         return $return_val;
  380.     }
  381.  
  382.     function parseRequest($data ''$attachments = null)
  383.     {
  384.         /* Parse response, get SOAP_Parser object. */
  385.         $parser = new SOAP_Parser($data$this->xml_encoding$attachments);
  386.  
  387.         if ($parser->fault{
  388.             /* Fault occurred during message parsing. */
  389.             $this->fault = $parser->fault;
  390.             return null;
  391.         }
  392.         if (!count($parser->root_struct_name)) {
  393.             /* No method specified. */
  394.             $this->_raiseSoapFault('No method specified in request.');
  395.             return null;
  396.         }
  397.  
  398.         /* Handle message headers. */
  399.         $request_headers $parser->getHeaders();
  400.         $header_results = array();
  401.  
  402.         if ($request_headers{
  403.             if (!is_a($request_headers'SOAP_Value')) {
  404.                 $this->_raiseSoapFault('Parser did not return SOAP_Value object: ' $request_headers'''''Server');
  405.                 return null;
  406.             }
  407.             if ($request_headers->value{
  408.                 /* Handle headers now. */
  409.                 foreach ($request_headers->value as $header_val{
  410.                     $f_exists $this->validateMethod($header_val->name$header_val->namespace);
  411.  
  412.                     /* TODO: this does not take into account message routing
  413.                      * yet. */
  414.                     $myactor !$header_val->actor ||
  415.                         $header_val->actor == 'http://schemas.xmlsoap.org/soap/actor/next' ||
  416.                         $header_val->actor == $this->endpoint;
  417.  
  418.                     if (!$f_exists && $header_val->mustunderstand && $myactor{
  419.                         $this->_raiseSoapFault('I don\'t understand header ' $header_val->name'''''MustUnderstand');
  420.                         return null;
  421.                     }
  422.  
  423.                     /* We only handle the header if it's for us. */
  424.                     $isok $f_exists && $myactor;
  425.  
  426.                     if ($isok{
  427.                         /* Call our header now! */
  428.                         $header_method $header_val->name;
  429.                         $header_data = array($this->_decode($header_val));
  430.                         /* If there are parameters to pass. */
  431.                         $hr =$this->callMethod($header_method$header_data);
  432.                         if (PEAR::isError($hr)) {
  433.                             $this->_raiseSoapFault($hr);
  434.                             return null;
  435.                         }
  436.                         $results $this->buildResult($hr$this->return_type$header_method$header_val->namespace);
  437.                         $header_results[$results[0];
  438.                     }
  439.                 }
  440.             }
  441.         }
  442.  
  443.         /* Handle the method call. */
  444.         /* Evaluate message, getting back a SOAP_Value object. */
  445.         $this->call_methodname = $this->methodname $parser->root_struct_name[0];
  446.  
  447.         /* Figure out the method namespace. */
  448.         $this->method_namespace = $parser->message[$parser->root_struct[0]]['namespace'];
  449.  
  450.         if ($this->_wsdl{
  451.             $this->_setSchemaVersion($this->_wsdl->xsd);
  452.             $dataHandler $this->_wsdl->getDataHandler($this->methodname$this->method_namespace);
  453.             if ($dataHandler)
  454.                 $this->call_methodname = $this->methodname $dataHandler;
  455.  
  456.             $this->_portName $this->_wsdl->getPortName($this->methodname);
  457.             if (PEAR::isError($this->_portName)) {
  458.                 $this->_raiseSoapFault($this->_portName);
  459.                 return null;
  460.             }
  461.             $opData $this->_wsdl->getOperationData($this->_portName$this->methodname);
  462.             if (PEAR::isError($opData)) {
  463.                 $this->_raiseSoapFault($opData);
  464.                 return null;
  465.             }
  466.             $this->_options['style'$opData['style'];
  467.             $this->_options['use'$opData['output']['use'];
  468.             $this->_options['parameters'$opData['parameters'];
  469.         }
  470.  
  471.         /* Does method exist? */
  472.         if (!$this->methodname ||
  473.             !$this->validateMethod($this->methodname$this->method_namespace)) {
  474.             $this->_raiseSoapFault('method "' $this->method_namespace . $this->methodname '" not defined in service''''''Server');
  475.             return null;
  476.         }
  477.  
  478.         if (!$request_val $parser->getResponse()) {
  479.             return null;
  480.         }
  481.         if (!is_a($request_val'SOAP_Value')) {
  482.             $this->_raiseSoapFault('Parser did not return SOAP_Value object: ' $request_val'''''Server');
  483.             return null;
  484.         }
  485.  
  486.         /* Verify that SOAP_Value objects in request match the methods
  487.          * signature. */
  488.         if (!$this->verifyMethod($request_val)) {
  489.             /* verifyMethod() creates the fault. */
  490.             return null;
  491.         }
  492.  
  493.         /* Need to set special error detection inside the value class to
  494.          * differentiate between no params passed, and an error decoding. */
  495.         $request_data $this->__decodeRequest($request_val);
  496.         if (PEAR::isError($request_data)) {
  497.             $this->_raiseSoapFault($request_data);
  498.             return null;
  499.         }
  500.         $method_response =$this->callMethod($this->call_methodname$request_data);
  501.         if (PEAR::isError($method_response)) {
  502.             $this->_raiseSoapFault($method_response);
  503.             return null;
  504.         }
  505.  
  506.         if ($this->_options['parameters'||
  507.             !$method_response ||
  508.             $this->_options['style'== 'rpc'{
  509.             /* Get the method result. */
  510.             if (is_null($method_response)) {
  511.                 $return_val = null;
  512.             else {
  513.                 $return_val $this->buildResult($method_response$this->return_type);
  514.             }
  515.  
  516.             $qn = new QName($this->methodname 'Response'$this->method_namespace);
  517.             $methodValue = new SOAP_Value($qn->fqn()'Struct'$return_val);
  518.         else {
  519.             $methodValue =$method_response;
  520.         }
  521.         return $this->makeEnvelope($methodValue$header_results$this->response_encoding);
  522.     }
  523.  
  524.     function &__decodeRequest($request$shift = false)
  525.     {
  526.         if (!$request{
  527.             $decoded = null;
  528.             return $decoded;
  529.         }
  530.  
  531.         /* Check for valid response. */
  532.         if (PEAR::isError($request)) {
  533.             $fault &$this->_raiseSoapFault($request);
  534.             return $fault;
  535.         else if (!is_a($request'SOAP_Value')) {
  536.             $fault &$this->_raiseSoapFault('Invalid data in server::__decodeRequest');
  537.             return $fault;
  538.         }
  539.  
  540.         /* Decode to native php datatype. */
  541.         $requestArray $this->_decode($request);
  542.         /* Fault? */
  543.         if (PEAR::isError($requestArray)) {
  544.             $fault &$this->_raiseSoapFault($requestArray);
  545.             return $fault;
  546.         }
  547.         if (is_object($requestArray&&
  548.             get_class($requestArray== 'stdClass'{
  549.             $requestArray get_object_vars($requestArray);
  550.         elseif ($this->_options['style'== 'document'{
  551.             $requestArray = array($requestArray);
  552.         }
  553.         if (is_array($requestArray)) {
  554.             if (isset($requestArray['faultcode']||
  555.                 isset($requestArray[SOAP_BASE::SOAPENVPrefix().':faultcode'])) {
  556.                 $faultcode $faultstring $faultdetail $faultactor '';
  557.                 foreach ($requestArray as $k => $v{
  558.                     if (stristr($k'faultcode')) {
  559.                         $faultcode $v;
  560.                     }
  561.                     if (stristr($k'faultstring')) {
  562.                         $faultstring $v;
  563.                     }
  564.                     if (stristr($k'detail')) {
  565.                         $faultdetail $v;
  566.                     }
  567.                     if (stristr($k'faultactor')) {
  568.                         $faultactor $v;
  569.                     }
  570.                 }
  571.                 $fault &$this->_raiseSoapFault($faultstring$faultdetail$faultactor$faultcode);
  572.                 return $fault;
  573.             }
  574.             /* Return array of return values. */
  575.             if ($shift && count($requestArray== 1{
  576.                 $decoded array_shift($requestArray);
  577.                 return $decoded;
  578.             }
  579.             return $requestArray;
  580.         }
  581.         return $requestArray;
  582.     }
  583.  
  584.     function verifyMethod($request)
  585.     {
  586.         if (!$this->callValidation{
  587.             return true;
  588.         }
  589.  
  590.         $params $request->value;
  591.  
  592.         /* Get the dispatch map if one exists. */
  593.         $map = null;
  594.         if (array_key_exists($this->methodname$this->dispatch_map)) {
  595.             $map $this->dispatch_map[$this->methodname];
  596.         elseif (isset($this->soapobject)) {
  597.             if (method_exists($this->soapobject'__dispatch')) {
  598.                 $map $this->soapobject->__dispatch($this->methodname);
  599.             elseif (method_exists($this->soapobject$this->methodname)) {
  600.                 /* No map, all public functions are SOAP functions. */
  601.                 return true;
  602.             }
  603.         }
  604.         if (!$map{
  605.             $this->_raiseSoapFault('SOAP request specified an unhandled method "' $this->methodname '"''''''Client');
  606.             return false;
  607.         }
  608.  
  609.         /* If we aliased the SOAP method name to a PHP function, change
  610.          * call_methodname so we do the right thing. */
  611.         if (array_key_exists('alias'$map&& !empty($map['alias'])) {
  612.             $this->call_methodname = $map['alias'];
  613.         }
  614.  
  615.         /* If there are input parameters required. */
  616.         if ($map['in']{
  617.             $this->input_value count($map['in']);
  618.             $this->return_type = false;
  619.             if (is_array($map['out'])) {
  620.                 $this->return_type count($map['out']> 1
  621.                     ? $map['out']
  622.                     : array_shift($map['out']);
  623.             }
  624.             if (is_array($params)) {
  625.                 /* Validate the number of parameters. */
  626.                 if (count($params== count($map['in'])) {
  627.                     /* Make array of param types. */
  628.                     foreach ($params as $param{
  629.                         $p[strtolower($param->type);
  630.                     }
  631.                     $sig_t array_values($map['in']);
  632.                     /* Validate each param's type. */
  633.                     for ($i = 0; $i count($p)$i++{
  634.                         /* If SOAP types do not match, it's still fine if the
  635.                          * mapped php types match this allows using plain PHP
  636.                          * variables to work (i.e. stuff like Decimal would
  637.                          * fail otherwise). We consider this only error if the
  638.                          * types exist in our type maps, and they differ. */
  639.                         if (strcasecmp($sig_t[$i]$p[$i]!= 0 &&
  640.                             isset($this->_typemap[SOAP_XML_SCHEMA_VERSION][$sig_t[$i]]&&
  641.                             strcasecmp($this->_typemap[SOAP_XML_SCHEMA_VERSION][$sig_t[$i]]$this->_typemap[SOAP_XML_SCHEMA_VERSION][$p[$i]]!= 0{
  642.  
  643.                             $param $params[$i];
  644.                             $this->_raiseSoapFault("SOAP request contained mismatching parameters of name $param->name had type [{$p[$i]}], which did not match signature's type: [{$sig_t[$i]}], matched? " . (strcasecmp($sig_t[$i]$p[$i]))'''''Client');
  645.                             return false;
  646.                         }
  647.                     }
  648.                     return true;
  649.                 else {
  650.                     /* Wrong number of params. */
  651.                     $this->_raiseSoapFault('SOAP request contained incorrect number of parameters. method "' $this->methodname '" required ' count($map['in']' and request provided ' count($params)'''''Client');
  652.                     return false;
  653.                 }
  654.             else {
  655.                 /* No params. */
  656.                 $this->_raiseSoapFault('SOAP request contained incorrect number of parameters. method "' $this->methodname '" requires ' count($map['in']' parameters, and request provided none.''''''Client');
  657.                 return false;
  658.             }
  659.         }
  660.  
  661.         /* We'll try it anyway. */
  662.         return true;
  663.     }
  664.  
  665.     function validateMethod($methodname$namespace = null)
  666.     {
  667.         unset($this->soapobject);
  668.  
  669.         if (!$this->callValidation{
  670.             return true;
  671.         }
  672.  
  673.         /* No SOAP access to private functions. */
  674.         if ($methodname[0== '_'{
  675.             return false;
  676.         }
  677.  
  678.         /* if it's in our function list, ok */
  679.         if (array_key_exists($methodname$this->dispatch_map&&
  680.             (!$namespace ||
  681.              !array_key_exists('namespace'$this->dispatch_map[$methodname]||
  682.              $namespace == $this->dispatch_map[$methodname]['namespace'])) {
  683.             if (array_key_exists('namespace'$this->dispatch_map[$methodname]))
  684.                 $this->method_namespace = $this->dispatch_map[$methodname]['namespace'];
  685.             return true;
  686.         }
  687.  
  688.         /* if it's in an object, it's ok */
  689.         if (isset($this->dispatch_objects[$namespace])) {
  690.             $c count($this->dispatch_objects[$namespace]);
  691.             for ($i = 0; $i $c$i++{
  692.                 $obj =$this->dispatch_objects[$namespace][$i];
  693.                 /* If we have a dispatch map, and the function is not in the
  694.                  * dispatch map, then it is not callable! */
  695.                 if (method_exists($obj'__dispatch')) {
  696.                     if ($obj->__dispatch($methodname)) {
  697.                         $this->method_namespace = $namespace;
  698.                         $this->soapobject =$obj;
  699.                         return true;
  700.                     }
  701.                 elseif (method_exists($obj$methodname)) {
  702.                     $this->method_namespace = $namespace;
  703.                     $this->soapobject =$obj;
  704.                     return true;
  705.                 }
  706.             }
  707.         }
  708.  
  709.         return false;
  710.     }
  711.  
  712.     function addObjectMap(&$obj$namespace = null$service_name 'Default',
  713.                           $service_desc '')
  714.     {
  715.         if (!$namespace{
  716.             if (isset($obj->namespace)) {
  717.                 // XXX a bit of backwards compatibility
  718.                 $namespace $obj->namespace;
  719.             else {
  720.                 $this->_raiseSoapFault('No namespace provided for class!''''''Server');
  721.                 return false;
  722.             }
  723.         }
  724.         if (!isset($this->dispatch_objects[$namespace])) {
  725.             $this->dispatch_objects[$namespace= array();
  726.         }
  727.         $this->dispatch_objects[$namespace][=$obj;
  728.  
  729.         // Create internal WSDL structures for object
  730.  
  731.         // XXX Because some internal workings of PEAR::SOAP decide whether to
  732.         // do certain things by the presence or absence of _wsdl, we should
  733.         // only create a _wsdl structure if we know we can fill it; if
  734.         // __dispatch_map or __typedef for the object is missing, we should
  735.         // avoid creating it. Later, when we are using PHP 5 introspection, we
  736.         // will be able to make the data for all objects without any extra
  737.         // information from the developers, and this condition should be
  738.         // dropped.
  739.  
  740.         // XXX Known issue: if imported WSDL (bindWSDL) or another WSDL source
  741.         // is used to add _wsdl structure information, then addObjectWSDL is
  742.         // used, there is a high possibility of _wsdl data corruption;
  743.         // therefore you should avoid using __dispatch_map/__typedef
  744.         // definitions AND other WSDL data sources in the same service. We
  745.         // exclude classes that don't have __typedefs to allow external WSDL
  746.         // files to be used with classes with no internal type definitions
  747.         // (the types are defined in the WSDL file). When addObjectWSDL is
  748.         // refactored to not cause corruption, this restriction can be
  749.         // relaxed.
  750.  
  751.         // In summary, if you add an object with both a dispatch map and type
  752.         // definitions, then previous WSDL file operation and type definitions
  753.         // will be overwritten.
  754.         if (isset($obj->__dispatch_map&& isset($obj->__typedef)) {
  755.             $this->addObjectWSDL($obj$namespace$service_name$service_desc);
  756.         }
  757.  
  758.         return true;
  759.     }
  760.  
  761.     /**
  762.      * Adds a method to the dispatch map.
  763.      */
  764.     function addToMap($methodname$in$out$namespace = null$alias = null)
  765.     {
  766.         if (!$this->callHandler && !function_exists($methodname)) {
  767.             $this->_raiseSoapFault('Error mapping function''''''Server');
  768.             return false;
  769.         }
  770.  
  771.         $this->dispatch_map[$methodname]['in'$in;
  772.         $this->dispatch_map[$methodname]['out'$out;
  773.         $this->dispatch_map[$methodname]['alias'$alias;
  774.         if ($namespace{
  775.             $this->dispatch_map[$methodname]['namespace'$namespace;
  776.         }
  777.  
  778.         return true;
  779.     }
  780.  
  781.     function setCallHandler($callHandler$validation = true)
  782.     {
  783.         $this->callHandler = $callHandler;
  784.         $this->callValidation = $validation;
  785.     }
  786.  
  787.     /**
  788.      * @deprecated use bindWSDL from now on
  789.      */
  790.     function bind($wsdl_url)
  791.     {
  792.         $this->bindWSDL($wsdl_url);
  793.     }
  794.  
  795.     /**
  796.      * @param  string a url to a WSDL resource
  797.      * @return void 
  798.      */
  799.     function bindWSDL($wsdl_url)
  800.     {
  801.         /* Instantiate WSDL class. */
  802.         $this->_wsdl = new SOAP_WSDL($wsdl_url);
  803.         if ($this->_wsdl->fault{
  804.             $this->_raiseSoapFault($this->_wsdl->fault);
  805.         }
  806.     }
  807.  
  808.     /**
  809.      * @return void 
  810.      */
  811.     function addObjectWSDL($wsdl_obj$targetNamespace$service_name,
  812.                            $service_desc '')
  813.     {
  814.         if (!isset($this->_wsdl)) {
  815.             $this->_wsdl = new SOAP_WSDL;
  816.         }
  817.  
  818.         $this->_wsdl->parseObject($wsdl_obj$targetNamespace$service_name$service_desc);
  819.  
  820.         if ($this->_wsdl->fault{
  821.             $this->_raiseSoapFault($this->_wsdl->fault);
  822.         }
  823.     }
  824.  
  825. }

Documentation generated on Mon, 04 Aug 2008 20:00:30 -0400 by phpDocumentor 1.4.0. PEAR Logo Copyright © PHP Group 2004.