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

Source for file WSDL.php

Documentation is available at WSDL.php

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Shane Caraveo <Shane@Caraveo.com>   Port to PEAR and more   |
  17. // | Authors: Dietrich Ayala <dietrich@ganx4.com> Original Author         |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: WSDL.php,v 1.51.2.4 2004/08/22 20:39:31 arnaud Exp $
  21. //
  22. require_once 'SOAP/Base.php';
  23. require_once 'SOAP/Fault.php';
  24. require_once 'HTTP/Request.php';
  25.  
  26. define('WSDL_CACHE_MAX_AGE'43200);
  27. define('WSDL_CACHE_USE',     0)// set to zero to turn off caching
  28.  
  29. /**
  30.  *  SOAP_WSDL
  31.  *  this class parses wsdl files, and can be used by SOAP::Client to properly register
  32.  * soap values for services
  33.  *
  34.  * originaly based on SOAPx4 by Dietrich Ayala http://dietrich.ganx4.com/soapx4
  35.  *
  36.  * TODO:
  37.  *    add wsdl caching
  38.  *   refactor namespace handling ($namespace/$ns)
  39.  *    implement IDL type syntax declaration so we can generate WSDL
  40.  *
  41.  * @access public
  42.  * @version $Id: WSDL.php,v 1.51.2.4 2004/08/22 20:39:31 arnaud Exp $
  43.  * @package SOAP::Client
  44.  * @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
  45.  * @author Dietrich Ayala <dietrich@ganx4.com> Original Author
  46.  */
  47. class SOAP_WSDL extends SOAP_Base
  48. {
  49.     var $tns = null;
  50.     var $definition = array();
  51.     var $namespaces = array();
  52.     var $ns = array();
  53.     var $xsd = SOAP_XML_SCHEMA_VERSION;
  54.     var $complexTypes = array();
  55.     var $elements = array();
  56.     var $messages = array();
  57.     var $portTypes = array();
  58.     var $bindings = array();
  59.     var $imports = array();
  60.     var $services = array();
  61.     var $service = '';
  62.     var $uri = '';
  63.  
  64.     /**
  65.      * Proxy parameters
  66.      *
  67.      * @var array 
  68.      */
  69.     var $proxy = null;
  70.  
  71.     var $trace = 0;
  72.  
  73.     /**
  74.      * Use WSDL cache
  75.      *
  76.      * @var boolean 
  77.      */
  78.     var $cacheUse = null;
  79.  
  80.     /**
  81.      * Cache max lifetime (in seconds)
  82.      *
  83.      * @var int 
  84.      */
  85.     var $cacheMaxAge = null;
  86.  
  87.     /**
  88.     * SOAP_WSDL constructor
  89.     *
  90.     * @param string  endpoint_uri (URL to WSDL file)
  91.     * @param array   contains options for HTTP_Request class (see HTTP/Request.php)
  92.     * @param boolean use WSDL caching
  93.     * @param int     cache max lifetime (in seconds)
  94.     * @access public
  95.     */
  96.     function SOAP_WSDL($wsdl_uri = false$proxy = array(),
  97.                        $cacheUse    = WSDL_CACHE_USE,
  98.                        $cacheMaxAge = WSDL_CACHE_MAX_AGE{
  99.         parent::SOAP_Base('WSDL');
  100.         $this->uri         = $wsdl_uri;
  101.         $this->proxy       = $proxy;
  102.         $this->cacheUse    = $cacheUse;
  103.         $this->cacheMaxAge = $cacheMaxAge;
  104.         if ($wsdl_uri{
  105.             $this->parseURL($wsdl_uri);
  106.             reset($this->services);
  107.             $this->service = key($this->services);
  108.         }
  109.     }
  110.  
  111.     function set_service($service{
  112.         if (array_key_exists($service$this->services)) {
  113.             $this->service = $service;
  114.         }
  115.     }
  116.  
  117.     /**
  118.      * @deprecated use parseURL instead
  119.      */
  120.     function parse($wsdl_uri$proxy = array()) {
  121.         $this->parseURL($wsdl_uri$proxy);
  122.     }
  123.  
  124.     /**
  125.      * Fill the WSDL array tree with data from a WSDL file
  126.      *
  127.      * @param  string 
  128.      * @param  array  proxi related parameters
  129.      * @return void 
  130.      */
  131.     function parseURL($wsdl_uri$proxy = array()) {
  132.         $parser =new SOAP_WSDL_Parser($wsdl_uri$this);
  133.  
  134.         if ($parser->fault{
  135.             $this->_raiseSoapFault($parser->fault);
  136.         }
  137.     }
  138.  
  139.     /**
  140.      * Fill the WSDL array tree with data from one or more PHP class objects
  141.      *
  142.      * @param  mixed  $wsdl_obj An object or array of objects to add to the internal WSDL tree
  143.      * @param  string  $service_name Name of the WSDL <service>
  144.      * @param  string  $service_desc Optional description of the WSDL <service>
  145.      * @return void 
  146.      */
  147.     function parseObject(&$wsdl_obj$targetNamespace$service_name$service_desc '')
  148.     {
  149.         $parser =new SOAP_WSDL_ObjectParser($wsdl_obj$this$targetNamespace$service_name$service_desc);
  150.  
  151.          if ($parser->fault{
  152.              $this->_raiseSoapFault($parser->fault);
  153.          }
  154.     }
  155.  
  156.     function getEndpoint($portName)
  157.     {
  158.         return (isset($this->services[$this->service]['ports'][$portName]['address']['location']))
  159.                 ? $this->services[$this->service]['ports'][$portName]['address']['location']
  160.                 : $this->_raiseSoapFault("no endpoint for port for $portName"$this->uri);
  161.     }
  162.  
  163.     function _getPortName($operation,$service{
  164.         if (isset($this->services[$service]['ports'])) {
  165.             foreach ($this->services[$service]['ports'as $port => $portAttrs{
  166.                 $type $this->services[$service]['ports'][$port]['type'];
  167.                 if ($type == 'soap' &&
  168.                     isset($this->bindings[$portAttrs['binding']]['operations'][$operation])) {
  169.                         return $port;
  170.                 }
  171.             }
  172.         }
  173.         return null;
  174.     }
  175.  
  176.     // find the name of the first port that contains an operation of name $operation
  177.     // always returns a the soap portName
  178.     function getPortName($operation$service = null)
  179.     {
  180.         if (!$service$service $this->service;
  181.         if (isset($this->services[$service]['ports'])) {
  182.             $portName $this->_getPortName($operation,$service);
  183.             if ($portNamereturn $portName;
  184.         }
  185.         // try any service in the wsdl
  186.         foreach ($this->services as $serviceName=>$service{
  187.             if (isset($this->services[$serviceName]['ports'])) {
  188.                 $portName $this->_getPortName($operation,$serviceName);
  189.                 if ($portName{
  190.                     $this->service = $serviceName;
  191.                     return $portName;
  192.                 }
  193.             }
  194.         }
  195.         return $this->_raiseSoapFault("no operation $operation in wsdl"$this->uri);
  196.     }
  197.  
  198.     function getOperationData($portName,$operation)
  199.     {
  200.         if (isset($this->services[$this->service]['ports'][$portName]['binding'])
  201.             && $binding $this->services[$this->service]['ports'][$portName]['binding']{
  202.             // get operation data from binding
  203.             if (is_array($this->bindings[$binding]['operations'][$operation])) {
  204.                 $opData $this->bindings[$binding]['operations'][$operation];
  205.             }
  206.             // get operation data from porttype
  207.             $portType $this->bindings[$binding]['type'];
  208.             if (!$portType{
  209.                 return $this->_raiseSoapFault("no port type for binding $binding in wsdl " . $this->uri);
  210.             }
  211.             if (is_array($this->portTypes[$portType][$operation])) {
  212.                 if (isset($this->portTypes[$portType][$operation]['parameterOrder']))
  213.                     $opData['parameterOrder'$this->portTypes[$portType][$operation]['parameterOrder'];
  214.                 $opData['input'array_merge($opData['input']$this->portTypes[$portType][$operation]['input']);
  215.                 $opData['output'array_merge($opData['output']$this->portTypes[$portType][$operation]['output']);
  216.             }
  217.             if (!$opData)
  218.                 return $this->_raiseSoapFault("no operation $operation for port $portName, in wsdl"$this->uri);
  219.             $opData['parameters'= false;
  220.             if (isset($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace']))
  221.                 $opData['namespace'$this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace'];
  222.             // message data from messages
  223.             $inputMsg $opData['input']['message'];
  224.             if (is_array($this->messages[$inputMsg])) {
  225.             foreach ($this->messages[$inputMsgas $pname => $pattrs{
  226.                 if ($opData['style'== 'document' && $opData['input']['use'== 'literal'
  227.                     && $pname == 'parameters'{
  228.                         $opData['parameters'= true;
  229.                         $opData['namespace'$this->namespaces[$pattrs['namespace']];
  230.                         $el $this->elements[$pattrs['namespace']][$pattrs['type']];
  231.                         if (isset($el['elements'])) {
  232.                             foreach ($el['elements'as $elname => $elattrs{
  233.                                 $opData['input']['parts'][$elname$elattrs;
  234.                             }
  235.                         }
  236.                 else {
  237.                     $opData['input']['parts'][$pname$pattrs;
  238.                 }
  239.             }
  240.             }
  241.             $outputMsg $opData['output']['message'];
  242.             if (is_array($this->messages[$outputMsg])) {
  243.             foreach ($this->messages[$outputMsgas $pname => $pattrs{
  244.                 if ($opData['style'== 'document' && $opData['output']['use'== 'literal'
  245.                     && $pname == 'parameters'{
  246.  
  247.                         $el $this->elements[$pattrs['namespace']][$pattrs['type']];
  248.                         if (isset($el['elements'])) {
  249.                             foreach ($el['elements'as $elname => $elattrs{
  250.                                 $opData['output']['parts'][$elname$elattrs;
  251.                             }
  252.                         }
  253.  
  254.                 else {
  255.                     $opData['output']['parts'][$pname$pattrs;
  256.                 }
  257.             }
  258.             }
  259.             return $opData;
  260.         }
  261.         return $this->_raiseSoapFault("no binding for port $portName in wsdl"$this->uri);
  262.     }
  263.  
  264.     function matchMethod(&$operation{
  265.         // Overloading lowercases function names :(
  266.         foreach ($this->services[$this->service]['ports'as $port => $portAttrs{
  267.             foreach (array_keys($this->bindings[$portAttrs['binding']]['operations']as $op{
  268.                 if (strcasecmp($op$operation== 0{
  269.                     $operation $op;
  270.                 }
  271.             }
  272.         }
  273.     }
  274.  
  275.     /**
  276.      * getDataHandler
  277.      *
  278.      * Given a datatype, what function handles the processing?
  279.      * this is used for doc/literal requests where we receive
  280.      * a datatype, and we need to pass it to a method in out
  281.      * server class
  282.      *
  283.      * @param string datatype
  284.      * @param string namespace
  285.      * @returns string methodname
  286.      * @access public
  287.      */
  288.     function getDataHandler($datatype$namespace{
  289.         // see if we have an element by this name
  290.         if (isset($this->namespaces[$namespace]))
  291.             $namespace $this->namespaces[$namespace];
  292.         if (isset($this->ns[$namespace])) {
  293.             $nsp $this->ns[$namespace];
  294.             #if (!isset($this->elements[$nsp]))
  295.             #    $nsp = $this->namespaces[$nsp];
  296.             if (isset($this->elements[$nsp][$datatype])) {
  297.                 $checkmessages = array();
  298.                 // find what messages use this datatype
  299.                 foreach ($this->messages as $messagename=>$message{
  300.                     foreach ($message as $partname=>$part{
  301.                         if ($part['type']==$datatype{
  302.                             $checkmessages[$messagename;
  303.                             break;
  304.                         }
  305.                     }
  306.                 }
  307.                 // find the operation that uses this message
  308.                 $dataHandler = NULL;
  309.                 foreach($this->portTypes as $portname=>$porttype{
  310.                     foreach ($porttype as $opname=>$opinfo{
  311.                         foreach ($checkmessages as $messagename{
  312.                             if ($opinfo['input']['message'== $messagename{
  313.                                 return $opname;
  314.                             }
  315.                         }
  316.                     }
  317.                 }
  318.             }
  319.         }
  320.         return null;
  321.     }
  322.  
  323.     function getSoapAction($portName$operation)
  324.     {
  325.         if (isset($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['soapAction']&&
  326.             $soapAction $this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['soapAction']{
  327.             return $soapAction;
  328.         }
  329.         return false;
  330.     }
  331.  
  332.     function getNamespace($portName$operation)
  333.     {
  334.         if (isset($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]&&
  335.             isset($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace']&&
  336.             $namespace $this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace']{
  337.             return $namespace;
  338.         }
  339.         return false;
  340.     }
  341.  
  342.     function getNamespaceAttributeName($namespace{
  343.         /* if it doesn't exist at first, flip the array and check again */
  344.         if (!array_key_exists($namespace$this->ns)) {
  345.             $this->ns = array_flip($this->namespaces);
  346.         }
  347.         /* if it doesn't exist now, add it */
  348.         if (!array_key_exists($namespace$this->ns)) {
  349.             return $this->addNamespace($namespace);
  350.         }
  351.         return $this->ns[$namespace];
  352.     }
  353.  
  354.     function addNamespace($namespace{
  355.         if (array_key_exists($namespace$this->ns)) {
  356.             return $this->ns[$namespace];
  357.         }
  358.         $n count($this->ns);
  359.         $attr 'ns'.$n;
  360.         $this->namespaces['ns'.$n$namespace;
  361.         $this->ns[$namespace$attr;
  362.         return $attr;
  363.     }
  364.  
  365.     function _validateString($string{
  366.         // XXX this should be done sooner or later
  367.         return true;
  368.         #if (preg_match("/^[\w_:#\/]+$/",$string)) return true;
  369.         #return false;
  370.     }
  371.  
  372.     function _addArg(&$args&$argarray$argname)
  373.     {
  374.         if ($args$args .= ", ";
  375.         $args .= "\$".$argname;
  376.         if (!$this->_validateString($argname)) return NULL;
  377.         if ($argarray$argarray .= ", ";
  378.         $argarray .= "\"$argname\"=>\$".$argname;
  379.     }
  380.  
  381.     function _elementArg(&$args&$argarray&$_argtype$_argname)
  382.     {
  383.         $comments '';
  384.         $el $this->elements[$_argtype['namespace']][$_argtype['type']];
  385.         $tns = isset($this->ns[$el['namespace']])?$this->ns[$el['namespace']]:$_argtype['namespace'];
  386.         if (isset($this->complexTypes[$tns][$el['type']])) {
  387.             // the element is actually a complex type!
  388.             $comments = "        // {$el['type']} is a ComplexType, refer to wsdl for more info\n";
  389.             $attrname = "{$_argtype['type']}_attr";
  390.             if (isset($this->complexTypes[$tns][$el['type']]['attribute'])) {
  391.                 $comments .= "        // {$el['type']} may require attributes, refer to wsdl for more info\n";
  392.             }
  393.             $comments .= "        \${$attrname}['xmlns'] = '{$this->namespaces[$_argtype['namespace']]}';\n";
  394.             $comments .= "        \${$_argtype['type']} =& new SOAP_Value('{$_argtype['type']}',false,\${$_argtype['type']},\$$attrname);\n";
  395.             $this->_addArg($args,$argarray,$_argtype['type']);
  396.             if (isset($this->complexTypes[$tns][$el['type']]['attribute'])) {
  397.                 if ($args$args .= ", ";
  398.                 $args .= "\$".$attrname;
  399.             }
  400.             #$comments = $this->_complexTypeArg($args,$argarray,$el,$_argtype['type']);
  401.         else if (isset($el['elements'])) {
  402.             foreach ($el['elements'as $ename => $element{
  403.                 $comments .= "        \$$ename =& new SOAP_Value('{{$this->namespaces[$element['namespace']]}}$ename','{$element['type']}',\$$ename);\n";
  404.                 $this->_addArg($args,$argarray,$ename);
  405.             }
  406.         else {
  407.             #$echoStringParam =& new SOAP_Value('{http://soapinterop.org/xsd}echoStringParam',false,$echoStringParam);
  408.             $comments .= "        \$$_argname =& new SOAP_Value('{{$this->namespaces[$tns]}}$_argname','{$el['type']}',\$$_argname);\n";
  409.             $this->_addArg($args,$argarray,$_argname);
  410.         }
  411.         return $comments;
  412.     }
  413.  
  414.     function _complexTypeArg(&$args&$argarray&$_argtype$_argname)
  415.     {
  416.         $comments '';
  417.         if (isset($this->complexTypes[$_argtype['namespace']][$_argtype['type']])) {
  418.             $comments  = "        // $_argname is a ComplexType {$_argtype['type']},\n";
  419.             $comments .= "        //refer to wsdl for more info\n";
  420.             if (isset($this->complexTypes[$_argtype['namespace']][$_argtype['type']]['attribute'])) {
  421.                 $comments .= "        // $_argname may require attributes, refer to wsdl for more info\n";
  422.             }
  423.             $wrapname '{'.$this->namespaces[$_argtype['namespace']].'}'.$_argtype['type'];
  424.             $comments .= "        \$$_argname =& new SOAP_Value('$_argname','$wrapname',\$$_argname);\n";
  425.  
  426.         }
  427.         $this->_addArg($args,$argarray,$_argname);
  428.         return $comments;
  429.     }
  430.  
  431.     /**
  432.      * generateProxyCode
  433.      * generates stub code from the wsdl that can be saved to a file, or eval'd into existence
  434.      */
  435.     function generateProxyCode($port ''$classname='')
  436.     {
  437.         $multiport count($this->services[$this->service]['ports']> 1;
  438.         if (!$port{
  439.             reset($this->services[$this->service]['ports']);
  440.             $port current($this->services[$this->service]['ports']);
  441.         }
  442.         // XXX currently do not support HTTP ports
  443.         if ($port['type'!= 'soap'return NULL;
  444.  
  445.         // XXX currentPort is BAD
  446.         $clienturl $port['address']['location'];
  447.         if (!$classname{
  448.             if ($multiport || $port{
  449.                 $classname 'WebService_'.$this->service.'_'.$port['name'];
  450.             else {
  451.                 $classname 'WebService_'.$this->service;
  452.             }
  453.             $classname str_replace('-','_',$classname);
  454.         }
  455.  
  456.         if (!$this->_validateString($classname)) return NULL;
  457.  
  458.         if (is_array($this->proxy&& count($this->proxy> 0{
  459.             $class = "class $classname extends SOAP_Client\n{\n".
  460.             "    function $classname()\n{\n".
  461.             "        \$this->SOAP_Client(\"$clienturl\", 0, 0,
  462.                     array(";
  463.  
  464.             foreach($this->proxy as $key => $val{
  465.                 if (is_array($val)) {
  466.                     $class .= "\"$key\" => array(";
  467.                     foreach ($val as $key2 => $val2{
  468.                         $class .= "\"$key2\" => \"$val2\",";
  469.                     }
  470.                     $class .= ')';
  471.                 else {
  472.                     $class .= "\"$key\"=>\"$val\",";
  473.                 }
  474.             }
  475.             $class .= "));\n }\n";
  476.             $class str_replace(',))''))'$class);
  477.         else {
  478.             $class = "class $classname extends SOAP_Client\n{\n".
  479.             "    function $classname()\n{\n".
  480.             "        \$this->SOAP_Client(\"$clienturl\", 0);\n".
  481.             "    }\n";
  482.         }
  483.  
  484.         // get the binding, from that get the port type
  485.         $primaryBinding $port['binding']//$this->services[$this->service]['ports'][$port['name']]["binding"];
  486.         $primaryBinding preg_replace("/^(.*:)/","",$primaryBinding);
  487.         $portType $this->bindings[$primaryBinding]['type'];
  488.         $portType preg_replace("/^(.*:)/","",$portType);
  489.         $style $this->bindings[$primaryBinding]['style'];
  490.  
  491.         // XXX currentPortType is BAD
  492.         foreach ($this->portTypes[$portTypeas $opname => $operation{
  493.             $soapaction $this->bindings[$primaryBinding]['operations'][$opname]['soapAction'];
  494.             if (isset($this->bindings[$primaryBinding]['operations'][$opname]['style'])) {
  495.                 $opstyle $this->bindings[$primaryBinding]['operations'][$opname]['style'];
  496.             else {
  497.                 $opstyle $style;
  498.             }
  499.             $use $this->bindings[$primaryBinding]['operations'][$opname]['input']['use'];
  500.             if ($use == 'encoded'{
  501.                 $namespace $this->bindings[$primaryBinding]['operations'][$opname]['input']['namespace'];
  502.             else {
  503.                 $bindingType $this->bindings[$primaryBinding]['type'];
  504.                 $ns $this->portTypes[$bindingType][$opname]['input']['namespace'];
  505.                 $namespace $this->namespaces[$ns];
  506.             }
  507.  
  508.             $args '';
  509.             $argarray '';
  510.             $comments '';
  511.             $wrappers '';
  512.             foreach ($operation['input'as $argname => $argtype{
  513.                 if ($argname == "message"{
  514.                     foreach ($this->messages[$argtypeas $_argname => $_argtype{
  515.                         $comments '';
  516.                         if ($opstyle == 'document' && $use == 'literal' &&
  517.                             $_argtype['name'== 'parameters'{
  518.                                 // the type or element refered to is used for parameters!
  519.                                 $elattrs = null;
  520.                                 $element $_argtype['element'];
  521.                                 $el $this->elements[$_argtype['namespace']][$_argtype['type']];
  522.  
  523.                                 if($el['complex']{
  524.                                     $namespace $this->namespaces[$_argtype['namespace']];
  525.                                     // XXX need to wrap the parameters in a soap_value
  526.                                 }
  527.                                 if (isset($el['elements'])) {
  528.                                     foreach ($el['elements'as $elname => $elattrs{
  529.                                         // is the element a complex type?
  530.                                         if (isset($this->complexTypes[$elattrs['namespace']][$elname])) {
  531.                                             $comments .= $this->_complexTypeArg($args$argarray$_argtype$_argname);
  532.                                         else {
  533.                                             $this->_addArg($args$argarray$elname);
  534.                                         }
  535.                                     }
  536.                                 }/* else {
  537.                                     $comments = $this->_complexTypeArg($args, $argarray, $elattrs, $elattrs['name']);
  538.                                 }*/
  539.                                 if($el['complex'&& $argarray{
  540.                                     $wrapname '{'.$this->namespaces[$_argtype['namespace']].'}'.$el['name'];
  541.                                     $comments .= "        \${$el['name']} =& new SOAP_Value('$wrapname',false,\$v=array($argarray));\n";
  542.                                     $argarray = "'{$el['name']}'=>\${$el['name']}";
  543.                                 }
  544.                         else
  545.                         if (isset($_argtype['element'])) {
  546.                             // element argument
  547.                             $comments $this->_elementArg($args$argarray$_argtype$_argtype['type']);
  548.                         else {
  549.                             // complex type argument
  550.                             $comments $this->_complexTypeArg($args$argarray$_argtype$_argname);
  551.                         }
  552.                     }
  553.                 }
  554.             }
  555.  
  556.             // validate entries
  557.             if (!$this->_validateString($opname)) return NULL;
  558.             if (!$this->_validateString($namespace)) return NULL;
  559.             if (!$this->_validateString($soapaction)) return NULL;
  560.  
  561.             if ($argarray{
  562.                 $argarray = "array($argarray)";
  563.             else {
  564.                 $argarray 'null';
  565.             }
  566.  
  567.             $class .= "    function &$opname($args) {\n$comments$wrappers".
  568.             "        return \$this->call(\"$opname\", \n".
  569.             "                        \$v = $argarray, \n".
  570.             "                        array('namespace'=>'$namespace',\n".
  571.             "                            'soapaction'=>'$soapaction',\n".
  572.             "                            'style'=>'$opstyle',\n".
  573.             "                            'use'=>'$use'".
  574.             ($this->trace?",'trace'=>1":"")." ));\n".
  575.             "    }\n";
  576.         }
  577.         $class .= "}\n";
  578.         return $class;
  579.     }
  580.  
  581.     function generateAllProxies()
  582.     {
  583.         $proxycode '';
  584.         foreach (array_keys($this->services[$this->service]['ports']as $key{
  585.             $port =$this->services[$this->service]['ports'][$key];
  586.             $proxycode .= $this->generateProxyCode($port);
  587.         }
  588.         return $proxycode;
  589.     }
  590.  
  591.     function &getProxy($port ''$name '')
  592.     {
  593.         $multiport count($this->services[$this->service]['ports']> 1;
  594.  
  595.         if (!$port{
  596.             reset($this->services[$this->service]['ports']);
  597.             $port current($this->services[$this->service]['ports']);
  598.         }
  599.  
  600.         if ($multiport || $port{
  601.             $classname 'WebService_' $this->service . '_' $port['name'];
  602.         else {
  603.             $classname 'WebService_' $this->service;
  604.         }
  605.  
  606.         if ($name{
  607.             $classname $name '_' $classname;
  608.         }
  609.  
  610.         $classname preg_replace('/[ .\-\(\)]+/''_'$classname);
  611.  
  612.         if (!class_exists($classname)) {
  613.             $proxy $this->generateProxyCode($port$classname);
  614.             eval($proxy);
  615.         }
  616.  
  617.         return new $classname;
  618.     }
  619.  
  620.     function &_getComplexTypeForElement($name$namespace)
  621.     {
  622.         $t = NULL;
  623.         if (isset($this->ns[$namespace]&&
  624.             isset($this->elements[$this->ns[$namespace]][$name]['type'])) {
  625.  
  626.             $type $this->elements[$this->ns[$namespace]][$name]['type'];
  627.             $ns $this->elements[$this->ns[$namespace]][$name]['namespace'];
  628.  
  629.             if (isset($this->complexTypes[$ns][$type])) {
  630.                 $t $this->complexTypes[$ns][$type];
  631.             }
  632.         }
  633.         return $t;
  634.     }
  635.  
  636.     function getComplexTypeNameForElement($name$namespace)
  637.     {
  638.         $t $this->_getComplexTypeForElement($name$namespace);
  639.         if ($t{
  640.             return $t['name'];
  641.         }
  642.         return NULL;
  643.     }
  644.  
  645.     function getComplexTypeChildType($ns$name$child_ns$child_name{
  646.         // is the type an element?
  647.         $t $this->_getComplexTypeForElement($name$ns);
  648.         if ($t{
  649.             // no, get it from complex types directly
  650.             if (isset($t['elements'][$child_name]['type']))
  651.                 return $t['elements'][$child_name]['type'];
  652.         }
  653.         return NULL;
  654.     }
  655.  
  656.     function getSchemaType($type$name$type_namespace)
  657.     {
  658.         # see if it's a complex type so we can deal properly with SOAPENC:arrayType
  659.         if ($name && $type{
  660.             # XXX TODO:
  661.             # look up the name in the wsdl and validate the type
  662.             foreach ($this->complexTypes as $ns=> $types{
  663.                 if (array_key_exists($type$types)) {
  664.                     if (array_key_exists('type'$types[$type])) {
  665.                         list($arraytype_ns$arraytype$array_depth= isset($types[$type]['arrayType'])?
  666.                             $this->_getDeepestArrayType($types[$type]['namespace']$types[$type]['arrayType'])
  667.                             : array($this->namespaces[$types[$type]['namespace']]NULL0);
  668.                         return array($types[$type]['type']$arraytype$arraytype_ns$array_depth);
  669.                     }
  670.                     if (array_key_exists('arrayType'$types[$type])) {
  671.                         list($arraytype_ns$arraytype$array_depth=
  672.                                 $this->_getDeepestArrayType($types[$type]['namespace']$types[$type]['arrayType']);
  673.                         return array('Array'$arraytype$arraytype_ns$array_depth);
  674.                     }
  675.                     if (array_key_exists('elements'$types[$type]&&
  676.                         array_key_exists($name$types[$type]['elements'])) {
  677.                         $type $types[$type]['elements']['type'];
  678.                         return array($typeNULL$this->namespaces[$types[$type]['namespace']]NULL);
  679.                     }
  680.                 }
  681.             }
  682.         }
  683.         if ($type && $type_namespace{
  684.             $arrayType = NULL;
  685.             # XXX TODO:
  686.             # this code currently handles only one way of encoding array types in wsdl
  687.             # need to do a generalized function to figure out complex types
  688.             $p $this->ns[$type_namespace];
  689.             if ($p &&
  690.                 array_key_exists($p$this->complexTypes&&
  691.                 array_key_exists($type$this->complexTypes[$p])) {
  692.                 if ($arrayType $this->complexTypes[$p][$type]['arrayType']{
  693.                     $type 'Array';
  694.                 else if ($this->complexTypes[$p][$type]['order']=='sequence' &&
  695.                            array_key_exists('elements'$this->complexTypes[$p][$type])) {
  696.                     reset($this->complexTypes[$p][$type]['elements']);
  697.                     # assume an array
  698.                     if (count($this->complexTypes[$p][$type]['elements']== 1{
  699.                         $arg current($this->complexTypes[$p][$type]['elements']);
  700.                         $arrayType $arg['type'];
  701.                         $type 'Array';
  702.                     else {
  703.                         foreach($this->complexTypes[$p][$type]['elements'as $element{
  704.                             if ($element['name'== $type{
  705.                                 $arrayType $element['type'];
  706.                                 $type $element['type'];
  707.                             }
  708.                         }
  709.                     }
  710.                 else {
  711.                     $type 'Struct';
  712.                 }
  713.                 return array($type$arrayType$type_namespacenull);
  714.             }
  715.         }
  716.         return array(nullnullnullnull);
  717.     }
  718.  
  719.     /** Recurse through the WSDL structure looking for the innermost array type of multi-dimensional arrays.
  720.      *
  721.      *  Takes a namespace prefix and a type, which can be in the form 'type' or 'type[]',
  722.      *  and returns the full namespace URI, the type of the most deeply nested array type found,
  723.      *  and the number of levels of nesting.
  724.      *
  725.      * @access private
  726.      * @return mixed array or nothing
  727.      */
  728.     function _getDeepestArrayType($nsPrefix$arrayType)
  729.     {
  730.         static $trail = array();
  731.  
  732.         $arrayType = ereg_replace('\[\]$'''$arrayType);
  733.  
  734.         // Protect against circular references
  735.         // XXX We really need to remove trail from this altogether (it's very inefficient and
  736.         // in the wrong place!) and put circular reference checking in when the WSDL info
  737.         // is generated in the first place
  738.         if (array_search($nsPrefix ':' $arrayType$trail)) {
  739.             return array(NULLNULL-count($trail));
  740.         }
  741.  
  742.         if (array_key_exists($nsPrefix$this->complexTypes&&
  743.             array_key_exists($arrayType$this->complexTypes[$nsPrefix]&&
  744.             array_key_exists('arrayType'$this->complexTypes[$nsPrefix][$arrayType])) {
  745.             $trail[$nsPrefix ':' $arrayType;
  746.             $result $this->_getDeepestArrayType$this->complexTypes[$nsPrefix][$arrayType]['namespace'],
  747.                                                    $this->complexTypes[$nsPrefix][$arrayType]['arrayType']);
  748.             return array($result[0]$result[1]$result[2+ 1);
  749.         }
  750.         return array($this->namespaces[$nsPrefix]$arrayType0);
  751.     }
  752. }
  753.  
  754. class SOAP_WSDL_Cache extends SOAP_Base
  755. {
  756.     // Cache settings
  757.  
  758.     /**
  759.      * Use WSDL cache
  760.      *
  761.      * @var boolean 
  762.      */
  763.     var $_cacheUse = null;
  764.  
  765.     /**
  766.      * Cache max lifetime (in seconds)
  767.      *
  768.      * @var int 
  769.      */
  770.     var $_cacheMaxAge = null;
  771.  
  772.     /**
  773.      * SOAP_WSDL_Cache constructor
  774.      *
  775.      * @param  boolean use caching
  776.      * @param  int     cache max lifetime (in seconds)
  777.      * @access public
  778.      */
  779.     function SOAP_WSDL_Cache($cacheUse = WSDL_CACHE_USE,
  780.                              $cacheMaxAge = WSDL_CACHE_MAX_AGE{
  781.         parent::SOAP_Base('WSDLCACHE');
  782.         $this->_cacheUse $cacheUse;
  783.         $this->_cacheMaxAge $cacheMaxAge;
  784.     }
  785.  
  786.     /**
  787.      * _cacheDir
  788.      * return the path to the cache, if it doesn't exist, make it
  789.      */
  790.     function _cacheDir({
  791.         $dir getenv("WSDLCACHE");
  792.         if (!$dir$dir "./wsdlcache";
  793.         @mkdir($dir0700);
  794.         return $dir;
  795.     }
  796.  
  797.     /**
  798.      * Retrieves a file from cache if it exists, otherwise retreive from net,
  799.      * add to cache, and return from cache.
  800.      *
  801.      * @param  string   URL to WSDL
  802.      * @param  array    proxy parameters
  803.      * @param  int      expected MD5 of WSDL URL
  804.      * @access public
  805.      * @return string  data
  806.      */
  807.     function get($wsdl_fname$proxy_params = array()$cache = 0{
  808.         $cachename $md5_wsdl $file_data '';
  809.         if ($this->_cacheUse{
  810.             // Try to retrieve WSDL from cache
  811.             $cachename SOAP_WSDL_Cache::_cacheDir('/' md5($wsdl_fname)'.wsdl';
  812.             if (file_exists($cachename)) {
  813.                 $wf fopen($cachename,'rb');
  814.                 if ($wf{
  815.                     // Reading cached file
  816.                     $file_data fread($wffilesize($cachename));
  817.                     $md5_wsdl md5($file_data);
  818.                     fclose($wf);
  819.                 }
  820.                 if ($cache{
  821.                     if ($cache != $md5_wsdl{
  822.                         return $this->_raiseSoapFault('WSDL Checksum error!'$wsdl_fname);
  823.                     }
  824.                 else {
  825.                     $fi stat($cachename);
  826.                     $cache_mtime $fi[8];
  827.                     #print cache_mtime, time()
  828.                     if ($cache_mtime $this->_cacheMaxAge time()) {
  829.                         # expired
  830.                         $md5_wsdl ''# refetch
  831.                     }
  832.                 }
  833.             }
  834.         }
  835.  
  836.         if (!$md5_wsdl{
  837.             // Not cached or not using cache. Retrieve WSDL from URL
  838.  
  839.             // is it a local file?
  840.             // this section should be replace by curl at some point
  841.             if (!preg_match('/^(https?|file):\/\//',$wsdl_fname)) {
  842.                 if (!file_exists($wsdl_fname)) {
  843.                     return $this->_raiseSoapFault("Unable to read local WSDL $wsdl_fname"$wsdl_fname);
  844.                 }
  845.                 if (function_exists('file_get_contents')) {
  846.                     $file_data file_get_contents($wsdl_fname);
  847.                 else {
  848.                     $file_data implode('',file($wsdl_fname));
  849.                 }
  850.             else {
  851.                 $uri explode('?',$wsdl_fname);
  852.                 $rq =new HTTP_Request($uri[0]$proxy_params);
  853.                 // the user agent HTTP_Request uses fouls things up
  854.                 if (isset($uri[1])) {
  855.                     $rq->addRawQueryString($uri[1]);
  856.                 }
  857.  
  858.                 if (isset($proxy_params['proxy_host']&&
  859.                     isset($proxy_params['proxy_port']&&
  860.                     isset($proxy_params['proxy_user']&&
  861.                     isset($proxy_params['proxy_pass'])) {
  862.                     $rq->setProxy($proxy_params['proxy_host']$proxy_params['proxy_port'],
  863.                                   $proxy_params['proxy_user']$proxy_params['proxy_pass']);
  864.                 elseif (isset($proxy_params['proxy_host']&&
  865.                           isset($proxy_params['proxy_port'])) {
  866.                     $rq->setProxy($proxy_params['proxy_host']$proxy_params['proxy_port']);
  867.                 }
  868.  
  869.                 $result $rq->sendRequest();
  870.                 if (PEAR::isError($result)) {
  871.                     return $this->_raiseSoapFault("Unable to retrieve WSDL $wsdl_fname," . $rq->getResponseCode()$wsdl_fname);
  872.             }
  873.                $file_data $rq->getResponseBody();
  874.                 if (!$file_data{
  875.                     return $this->_raiseSoapFault("Unable to retrieve WSDL $wsdl_fname, no http body"$wsdl_fname);
  876.                 }
  877.             }
  878.  
  879.             $md5_wsdl md5($file_data);
  880.  
  881.             if ($this->_cacheUse{
  882.                 $fp fopen($cachename"wb");
  883.                 fwrite($fp$file_data);
  884.                 fclose($fp);
  885.             }
  886.         }
  887.         if ($this->_cacheUse && $cache && $cache != $md5_wsdl{
  888.             return $this->_raiseSoapFault("WSDL Checksum error!"$wsdl_fname);
  889.         }
  890.         return $file_data;
  891.     }
  892. }
  893.  
  894. class SOAP_WSDL_Parser extends SOAP_Base
  895. {
  896.     // define internal arrays of bindings, ports, operations, messages, etc.
  897.     var $currentMessage;
  898.     var $currentOperation;
  899.     var $currentPortType;
  900.     var $currentBinding;
  901.     var $currentPort;
  902.  
  903.     // parser vars
  904.     var $cache;
  905.  
  906.     var $tns = null;
  907.     var $soapns = array('soap');
  908.     var $uri = '';
  909.     var $wsdl = null;
  910.  
  911.     var $status = '';
  912.     var $element_stack = array();
  913.     var $parentElement = '';
  914.  
  915.     var $schema = '';
  916.     var $schemaStatus = '';
  917.     var $schema_stack = array();
  918.     var $currentComplexType;
  919.     var $schema_element_stack = array();
  920.     var $currentElement;
  921.  
  922.     // constructor
  923.     function SOAP_WSDL_Parser($uri&$wsdl$docs = false{
  924.         parent::SOAP_Base('WSDLPARSER');
  925.         $this->cache =new SOAP_WSDL_Cache($wsdl->cacheUse$wsdl->cacheMaxAge);
  926.         $this->uri = $uri;
  927.         $this->wsdl = &$wsdl;
  928.         $this->docs $docs;
  929.         $this->parse($uri);
  930.     }
  931.  
  932.     function parse($uri{
  933.         // Check whether content has been read.
  934.         $fd $this->cache->get($uri$this->wsdl->proxy);
  935.         if (PEAR::isError($fd)) {
  936.             return $this->_raiseSoapFault($fd);
  937.         }
  938.  
  939.         // Create an XML parser.
  940.         $parser xml_parser_create();
  941.         xml_parser_set_option($parserXML_OPTION_CASE_FOLDING0);
  942.         xml_set_object($parser$this);
  943.         xml_set_element_handler($parser'startElement''endElement');
  944.         if ($this->docs{
  945.             xml_set_character_data_handler($parser'characterData');
  946.         }
  947.  
  948.         if (!xml_parse($parser,$fdtrue)) {
  949.             $detail sprintf('XML error on line %d: %s',
  950.                                     xml_get_current_line_number($parser),
  951.                                     xml_error_string(xml_get_error_code($parser)));
  952.             //print $fd;
  953.             return $this->_raiseSoapFault("Unable to parse WSDL file $uri\n$detail");
  954.         }
  955.         xml_parser_free($parser);
  956.         return true;
  957.     }
  958.  
  959.     // start-element handler
  960.     function startElement($parser$name$attrs{
  961.         // get element prefix
  962.         $qname =new QName($name);
  963.         if ($qname->ns{
  964.             $ns $qname->ns;
  965.             if ($ns && ((!$this->tns && strcasecmp($qname->name,'definitions'== 0|| $ns == $this->tns)) {
  966.                 $name $qname->name;
  967.             }
  968.         }
  969.         $this->currentTag $qname->name;
  970.         $this->parentElement = '';
  971.         $stack_size count($this->element_stack);
  972.         if ($stack_size > 0{
  973.             $this->parentElement = $this->element_stack[$stack_size-1];
  974.         }
  975.         $this->element_stack[$this->currentTag;
  976.  
  977.         // find status, register data
  978.         switch($this->status{
  979.         case 'types':
  980.             // sect 2.2 wsdl:types
  981.             // children: xsd:schema
  982.             $parent_tag '';
  983.             $stack_size count($this->schema_stack);
  984.             if ($stack_size > 0{
  985.                 $parent_tag $this->schema_stack[$stack_size-1];
  986.             }
  987.  
  988.             switch($qname->name{
  989.             case 'schema':
  990.                 // no parent should be in the stack
  991.                 if (!$parent_tag || $parent_tag == 'types'{
  992.                     if (array_key_exists('targetNamespace'$attrs)) {
  993.                         $this->schema = $this->wsdl->getNamespaceAttributeName($attrs['targetNamespace']);
  994.                     else {
  995.                         $this->schema = $this->wsdl->getNamespaceAttributeName($this->wsdl->tns);
  996.                     }
  997.                     $this->wsdl->complexTypes[$this->schema= array();
  998.                     $this->wsdl->elements[$this->schema= array();
  999.                 }
  1000.             break;
  1001.             case 'complexType':
  1002.                 if ($parent_tag == 'schema'{
  1003.                     $this->currentComplexType = $attrs['name'];
  1004.                     if (!isset($attrs['namespace'])) $attrs['namespace'$this->schema;
  1005.                     $this->wsdl->complexTypes[$this->schema][$this->currentComplexType$attrs;
  1006.                     if (array_key_exists('base',$attrs)) {
  1007.                         $qn =new QName($attrs['base']);
  1008.                         $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'$qn->name;
  1009.                         $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'$qn->ns;
  1010.                     else {
  1011.                         $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type''Struct';
  1012.                     }
  1013.                     $this->schemaStatus = 'complexType';
  1014.                 else {
  1015.                     $this->wsdl->elements[$this->schema][$this->currentElement]['complex'= TRUE;
  1016.                 }
  1017.             break;
  1018.             case 'element':
  1019.                 if (isset($attrs['type'])) {
  1020.                     $qn =new QName($attrs['type']);
  1021.                     $attrs['type'$qn->name;
  1022.                     #$this->wsdl->getNamespaceAttributeName
  1023.                     if ($qn->ns && array_key_exists($qn->ns$this->wsdl->namespaces)) {
  1024.                         $attrs['namespace'$qn->ns;
  1025.                     }
  1026.                 }
  1027.  
  1028.                 $parentElement '';
  1029.                 $stack_size count($this->schema_element_stack);
  1030.                 if ($stack_size > 0{
  1031.                     $parentElement $this->schema_element_stack[$stack_size-1];
  1032.                 }
  1033.  
  1034.                 if (isset($attrs['ref'])) {
  1035.                     $this->currentElement = $attrs['ref'];
  1036.                 else {
  1037.                     $this->currentElement = $attrs['name'];
  1038.                 }
  1039.                 $this->schema_element_stack[$this->currentElement;
  1040.                 if (!isset($attrs['namespace'])) $attrs['namespace'$this->schema;
  1041.  
  1042.                 if ($parent_tag == 'schema'{
  1043.                     $this->wsdl->elements[$this->schema][$this->currentElement$attrs;
  1044.                     $this->wsdl->elements[$this->schema][$this->currentElement]['complex'= FALSE;
  1045.                     $this->schemaStatus = 'element';
  1046.                 else if ($this->currentComplexType{
  1047.                     // we're inside a complexType
  1048.                     if ((isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order']&&
  1049.                          $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'== 'sequence')
  1050.                         && $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'== 'Array'{
  1051.                             $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['arrayType'$attrs['type'];
  1052.                     }
  1053.                     $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements'][$this->currentElement$attrs;
  1054.                 else {
  1055.                     $this->wsdl->elements[$this->schema][$parentElement]['elements'][$this->currentElement$attrs;
  1056.                 }
  1057.             break;
  1058.             case 'complexContent':
  1059.             case 'simpleContent':
  1060.             break;
  1061.             case 'extension':
  1062.             case 'restriction':
  1063.                 if ($this->schemaStatus == 'complexType'{
  1064.                     if ($attrs['base']{
  1065.                         $qn =new QName($attrs['base']);
  1066.                         $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'$qn->name;
  1067.                         $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'$qn->ns;
  1068.                     else {
  1069.                         $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type''Struct';
  1070.                     }
  1071.                 }
  1072.             break;
  1073.             case 'sequence':
  1074.                 if ($this->schemaStatus == 'complexType'{
  1075.                     $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'$qname->name;
  1076.                     #if (!array_key_exists('type',$this->wsdl->complexTypes[$this->schema][$this->currentComplexType])) {
  1077.                         $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type''Array';
  1078.                     #}
  1079.                 }
  1080.             break;
  1081.             case 'all':
  1082.                 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'$qname->name;
  1083.                 if (!array_key_exists('type',$this->wsdl->complexTypes[$this->schema][$this->currentComplexType])) {
  1084.                     $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type''Struct';
  1085.                 }
  1086.             break;
  1087.             case 'choice':
  1088.                 $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'$qname->name;
  1089.                 if (!array_key_exists('type',$this->wsdl->complexTypes[$this->schema][$this->currentComplexType])) {
  1090.                     $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type''Array';
  1091.                 }
  1092.             case 'attribute':
  1093.                 if ($this->schemaStatus == 'complexType'{
  1094.                     if (isset($attrs['name'])) {
  1095.                         $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['attribute'][$attrs['name']] $attrs;
  1096.                     else
  1097.                     if (isset($attrs['ref'])) {
  1098.                         $q =new QName($attrs['ref']);
  1099.                         foreach ($attrs as $k => $v{
  1100.                             if ($k != 'ref' && strstr($k$q->name)) {
  1101.                                 $vq =new QName($v);
  1102.                                 if ($q->name == 'arrayType'{
  1103.                                     $this->wsdl->complexTypes[$this->schema][$this->currentComplexType][$q->name$vq->name.$vq->arrayInfo;
  1104.                                     $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type''Array';
  1105.                                     $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'$vq->ns;
  1106.                                 else {
  1107.                                     $this->wsdl->complexTypes[$this->schema][$this->currentComplexType][$q->name$vq->name;
  1108.                                 }
  1109.                             }
  1110.                         }
  1111.                     }
  1112.                 }
  1113.             break;
  1114.             }
  1115.  
  1116.             $this->schema_stack[$qname->name;
  1117.  
  1118.         break;
  1119.         case 'message':
  1120.             // sect 2.3 wsdl:message child wsdl:part
  1121.             switch($qname->name{
  1122.             case 'part':
  1123.                 $qn = NULL;
  1124.                 if (isset($attrs['type'])) {
  1125.                     $qn =new QName($attrs['type']);
  1126.                 else if (isset($attrs['element'])) {
  1127.                     $qn =new QName($attrs['element']);
  1128.                 }
  1129.                 if ($qn{
  1130.                     $attrs['type'$qn->name;
  1131.                     $attrs['namespace'$qn->ns;
  1132.                 }
  1133.                 $this->wsdl->messages[$this->currentMessage][$attrs['name']] $attrs;
  1134.                 // error in wsdl
  1135.             case 'documentation':
  1136.                 break;
  1137.             default:
  1138.                 break;
  1139.             }
  1140.         break;
  1141.         case 'portType':
  1142.             // sect 2.4
  1143.             switch($qname->name{
  1144.             case 'operation':
  1145.                 // attributes: name
  1146.                 // children: wsdl:input wsdl:output wsdl:fault
  1147.                 $this->currentOperation = $attrs['name'];
  1148.                 #$this->wsdl->portTypes[$this->currentPortType][$this->currentOperation]['parameterOrder'] = $attrs['parameterOrder'];
  1149.                 $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation$attrs;
  1150.                 break;
  1151.             case 'input':
  1152.             case 'output':
  1153.             case 'fault':
  1154.                 // wsdl:input wsdl:output wsdl:fault
  1155.                 // attributes: name message parameterOrder(optional)
  1156.                 if ($this->currentOperation{
  1157.                     if (isset($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name])) {
  1158.                         $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$namearray_merge($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name],$attrs);
  1159.                     else {
  1160.                         $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name$attrs;
  1161.                     }
  1162.                     if (array_key_exists('message',$attrs)) {
  1163.                         $qn =new QName($attrs['message']);
  1164.                         $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name]['message'$qn->name;
  1165.                         $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name]['namespace'$qn->ns;
  1166.                     }
  1167.                 }
  1168.                 break;
  1169.             case 'documentation':
  1170.                 break;
  1171.             default:
  1172.                 break;
  1173.             }
  1174.         break;
  1175.         case 'binding':
  1176.             $ns $qname->ns ? $this->wsdl->namespaces[$qname->nsSCHEMA_WSDL;
  1177.             switch($ns{
  1178.             case SCHEMA_SOAP:
  1179.                 // this deals with wsdl section 3 soap binding
  1180.                 switch($qname->name{
  1181.                 case 'binding':
  1182.                     // sect 3.3
  1183.                     // soap:binding, attributes: transport(required), style(optional, default = document)
  1184.                     // if style is missing, it is assumed to be 'document'
  1185.                     if (!isset($attrs['style'])) $attrs['style''document';
  1186.                     $this->wsdl->bindings[$this->currentBindingarray_merge($this->wsdl->bindings[$this->currentBinding],$attrs);
  1187.                     break;
  1188.                 case 'operation':
  1189.                     // sect 3.4
  1190.                     // soap:operation, attributes: soapAction(required), style(optional, default = soap:binding:style)
  1191.                     if (!isset($attrs['style'])) $attrs['style'$this->wsdl->bindings[$this->currentBinding]['style'];
  1192.                     if (isset($this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation])) {
  1193.                         $this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperationarray_merge($this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation],$attrs);
  1194.                     else {
  1195.                         $this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation$attrs;
  1196.                     }
  1197.                     break;
  1198.                 case 'body':
  1199.                     // sect 3.5
  1200.                     // soap:body attributes:
  1201.                     // part - optional.  listed parts must appear in body, missing means all parts appear in body
  1202.                     // use - required. encoded|literal
  1203.                     // encodingStyle - optional.  space seperated list of encodings (uri's)
  1204.                     $this->wsdl->bindings[$this->currentBinding]
  1205.                                     ['operations'][$this->currentOperation][$this->opStatus$attrs;
  1206.                     break;
  1207.                 case 'fault':
  1208.                     // sect 3.6
  1209.                     // soap:fault attributes: name use  encodingStyle namespace
  1210.                     $this->wsdl->bindings[$this->currentBinding]
  1211.                                     ['operations'][$this->currentOperation][$this->opStatus$attrs;
  1212.                     break;
  1213.                 case 'header':
  1214.                     // sect 3.7
  1215.                     // soap:header attributes: message part use encodingStyle namespace
  1216.                     $this->wsdl->bindings[$this->currentBinding]
  1217.                                     ['operations'][$this->currentOperation][$this->opStatus]['headers'][$attrs;
  1218.                     break;
  1219.                 case 'headerfault':
  1220.                     // sect 3.7
  1221.                     // soap:header attributes: message part use encodingStyle namespace
  1222.                     $header count($this->wsdl->bindings[$this->currentBinding]
  1223.                                     ['operations'][$this->currentOperation][$this->opStatus]['headers'])-1;
  1224.                     $this->wsdl->bindings[$this->currentBinding]
  1225.                                     ['operations'][$this->currentOperation][$this->opStatus]['headers'][$header]['fault'$attrs;
  1226.                     break;
  1227.                 case 'documentation':
  1228.                     break;
  1229.                 default:
  1230.                     // error!  not a valid element inside binding
  1231.                     break;
  1232.                 }
  1233.                 break;
  1234.             case SCHEMA_WSDL:
  1235.                 // XXX verify correct namespace
  1236.                 // for now, default is the 'wsdl' namespace
  1237.                 // other possible namespaces include smtp, http, etc. for alternate bindings
  1238.                 switch($qname->name{
  1239.                 case 'operation':
  1240.                     // sect 2.5
  1241.                     // wsdl:operation attributes: name
  1242.                     $this->currentOperation = $attrs['name'];
  1243.                     break;
  1244.                 case 'output':
  1245.                 case 'input':
  1246.                 case 'fault':
  1247.                     // sect 2.5
  1248.                     // wsdl:input attributes: name
  1249.                     $this->opStatus $qname->name;
  1250.                     break;
  1251.                 case 'documentation':
  1252.                     break;
  1253.                 default:
  1254.                     break;
  1255.                 }
  1256.                 break;
  1257.             case SCHEMA_WSDL_HTTP:
  1258.                 switch($qname->name{
  1259.                 case 'binding':
  1260.                     // sect 4.4
  1261.                     // http:binding attributes: verb
  1262.                     // parent: wsdl:binding
  1263.                     $this->wsdl->bindings[$this->currentBindingarray_merge($this->wsdl->bindings[$this->currentBinding],$attrs);
  1264.                     break;
  1265.                 case 'operation':
  1266.                     // sect 4.5
  1267.                     // http:operation attributes: location
  1268.                     // parent: wsdl:operation
  1269.                     $this->wsdl->bindings[$this->currentBinding]['operations']
  1270.                                                         [$this->currentOperation$attrs;
  1271.                     break;
  1272.                 case 'urlEncoded':
  1273.                     // sect 4.6
  1274.                     // http:urlEncoded attributes: location
  1275.                     // parent: wsdl:input wsdl:output etc.
  1276.                     $this->wsdl->bindings[$this->currentBinding]['operations'][$this->opStatus]
  1277.                                                         [$this->currentOperation]['uri''urlEncoded';
  1278.                     break;
  1279.                 case 'urlReplacement':
  1280.                     // sect 4.7
  1281.                     // http:urlReplacement attributes: location
  1282.                     // parent: wsdl:input wsdl:output etc.
  1283.                     $this->wsdl->bindings[$this->currentBinding]['operations'][$this->opStatus]
  1284.                                                         [$this->currentOperation]['uri''urlReplacement';
  1285.                     break;
  1286.                 case 'documentation':
  1287.                     break;
  1288.                 default:
  1289.                     // error
  1290.                     break;
  1291.                 }
  1292.             case SCHEMA_MIME:
  1293.                 // sect 5
  1294.                 // all mime parts are children of wsdl:input, wsdl:output, etc.
  1295.                 // unsuported as of yet
  1296.                 switch($qname->name{
  1297.                 case 'content':
  1298.                     // sect 5.3 mime:content
  1299.                     // <mime:content part="nmtoken"? type="string"?/>
  1300.                     // part attribute only required if content is child of multipart related,
  1301.                     //        it contains the name of the part
  1302.                     // type attribute contains the mime type
  1303.                 case 'multipartRelated':
  1304.                     // sect 5.4 mime:multipartRelated
  1305.                 case 'part':
  1306.                 case 'mimeXml':
  1307.                     // sect 5.6 mime:mimeXml
  1308.                     // <mime:mimeXml part="nmtoken"?/>
  1309.                     //
  1310.                 case 'documentation':
  1311.                     break;
  1312.                 default:
  1313.                     // error
  1314.                     break;
  1315.                 }
  1316.             case SCHEMA_DIME:
  1317.                 // DIME is defined in:
  1318.                 // http://gotdotnet.com/team/xml_wsspecs/dime/WSDL-Extension-for-DIME.htm
  1319.                 // all DIME parts are children of wsdl:input, wsdl:output, etc.
  1320.                 // unsuported as of yet
  1321.                 switch($qname->name{
  1322.                 case 'message':
  1323.                     // sect 4.1 dime:message
  1324.                     // appears in binding section
  1325.                     $this->wsdl->bindings[$this->currentBinding]['dime'$attrs;
  1326.                     break;
  1327.                 default:
  1328.                     break;
  1329.                 }
  1330.             default:
  1331.                 break;
  1332.             }
  1333.         break;
  1334.         case 'service':
  1335.             $ns $qname->ns ? $this->wsdl->namespaces[$qname->nsSCHEMA_WSDL;
  1336.  
  1337.             switch($qname->name{
  1338.             case 'port':
  1339.                 // sect 2.6 wsdl:port attributes: name binding
  1340.                 $this->currentPort = $attrs['name'];
  1341.                 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort$attrs;
  1342.                 // XXX hack to deal with binding namespaces
  1343.                 $qn =new QName($attrs['binding']);
  1344.                 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['binding'$qn->name;
  1345.                 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['namespace'$qn->ns;
  1346.             break;
  1347.             case 'address':
  1348.                 $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['address'$attrs;
  1349.                 // what TYPE of port is it?  SOAP or HTTP?
  1350.                 $ns $qname->ns ? $this->wsdl->namespaces[$qname->nsSCHEMA_WSDL;
  1351.                 switch($ns{
  1352.                 case SCHEMA_WSDL_HTTP:
  1353.                     $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='http';
  1354.                     break;
  1355.                 case SCHEMA_SOAP:
  1356.                     $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='soap';
  1357.                     break;
  1358.                 default:
  1359.                     // shouldn't happen, we'll assume soap
  1360.                     $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='soap';
  1361.                 }
  1362.  
  1363.             break;
  1364.             case 'documentation':
  1365.                 break;
  1366.             default:
  1367.                 break;
  1368.             }
  1369.         }
  1370.  
  1371.         // top level elements found under wsdl:definitions
  1372.         // set status
  1373.         switch($qname->name{
  1374.         case 'import':
  1375.             // sect 2.1.1 wsdl:import attributes: namespace location
  1376.             if (array_key_exists('location',$attrs&&
  1377.                 !isset($this->wsdl->imports[$attrs['namespace']])) {
  1378.                 $uri $attrs['location'];
  1379.                 $location parse_url($uri);
  1380.                 if (!isset($location['scheme'])) {
  1381.                     $base parse_url($this->uri);
  1382.                     $uri $this->merge_url($base,$uri);
  1383.                 }
  1384.                 $import_parser =new SOAP_WSDL_Parser($uri$this->wsdl);
  1385.                 if ($import_parser->fault{
  1386.                     return FALSE;
  1387.                 }
  1388.                 $this->currentImport $attrs['namespace'];
  1389.                 $this->wsdl->imports[$this->currentImport$attrs;
  1390.             }
  1391.             $this->status = '';
  1392.         case 'types':
  1393.             // sect 2.2 wsdl:types
  1394.             $this->status = 'types';
  1395.         break;
  1396.         case 'message':
  1397.             // sect 2.3 wsdl:message attributes: name children:wsdl:part
  1398.             $this->status = 'message';
  1399.             if (isset($attrs['name'])) {
  1400.                 $this->currentMessage = $attrs['name'];
  1401.                 $this->wsdl->messages[$this->currentMessage= array();
  1402.             }
  1403.         break;
  1404.         case 'portType':
  1405.             // sect 2.4 wsdl:portType
  1406.             // attributes: name
  1407.             // children: wsdl:operation
  1408.             $this->status = 'portType';
  1409.             $this->currentPortType = $attrs['name'];
  1410.             $this->wsdl->portTypes[$this->currentPortType= array();
  1411.         break;
  1412.         case 'binding':
  1413.             // sect 2.5 wsdl:binding attributes: name type
  1414.             // children: wsdl:operation soap:binding http:binding
  1415.             if ($qname->ns && $qname->ns != $this->tnsbreak;
  1416.             $this->status = 'binding';
  1417.             $this->currentBinding = $attrs['name'];
  1418.             $qn =new QName($attrs['type']);
  1419.             $this->wsdl->bindings[$this->currentBinding]['type'$qn->name;
  1420.             $this->wsdl->bindings[$this->currentBinding]['namespace'$qn->ns;
  1421.         break;
  1422.         case 'service':
  1423.             // sect 2.7 wsdl:service attributes: name children: ports
  1424.             $this->currentService $attrs['name'];
  1425.             $this->wsdl->services[$this->currentService]['ports'= array();
  1426.             $this->status = 'service';
  1427.         break;
  1428.         case 'definitions':
  1429.             // sec 2.1 wsdl:definitions
  1430.             // attributes: name targetNamespace xmlns:*
  1431.             // children: wsdl:import wsdl:types wsdl:message wsdl:portType wsdl:binding wsdl:service
  1432.             #$this->status = 'definitions';
  1433.             $this->wsdl->definition = $attrs;
  1434.             foreach ($attrs as $key => $value{
  1435.                 if (strstr($key,'xmlns:'!== FALSE{
  1436.                     $qn =new QName($key);
  1437.                     // XXX need to refactor ns handling
  1438.                     $this->wsdl->namespaces[$qn->name$value;
  1439.                     $this->wsdl->ns[$value$qn->name;
  1440.                     if ($key == 'targetNamespace' ||
  1441.                         strcasecmp($value,SOAP_SCHEMA== 0{
  1442.                         $this->soapns[$qn->name;
  1443.                     else {
  1444.                         if (in_array($value$this->_XMLSchema)) {
  1445.                             $this->wsdl->xsd = $value;
  1446.                         }
  1447.                     }
  1448.                 }
  1449.             }
  1450.             if (isset($ns&& $ns{
  1451.                 $namespace 'xmlns:'.$ns;
  1452.                 if (!$this->wsdl->definition[$namespace]{
  1453.                     return $this->_raiseSoapFault("parse error, no namespace for $namespace",$this->uri);
  1454.                 }
  1455.                 $this->tns = $ns;
  1456.             }
  1457.         break;
  1458.         }
  1459.     }
  1460.  
  1461.  
  1462.     // end-element handler
  1463.     function endElement($parser$name)
  1464.     {
  1465.         $stacksize count($this->element_stack);
  1466.         if ($stacksize > 0{
  1467.             if ($this->element_stack[count($this->element_stack)-1==  'definitions'{
  1468.                 $this->status = '';
  1469.             }
  1470.             array_pop($this->element_stack);
  1471.         }
  1472.         if (stristr($name,'schema')) {
  1473.             array_pop($this->schema_stack);
  1474.             $this->schema = '';
  1475.         }
  1476.         if ($this->schema{
  1477.             array_pop($this->schema_stack);
  1478.             if (count($this->schema_stack<= 1{
  1479.                 /* correct the type for sequences with multiple elements */
  1480.                 if (isset($this->currentComplexType&& isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])
  1481.                     && $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'== 'Array'
  1482.                     && array_key_exists('elements',$this->wsdl->complexTypes[$this->schema][$this->currentComplexType])
  1483.                     && count($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements']> 1{
  1484.                         $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type''Struct';
  1485.                 }
  1486.             }
  1487.             if (stristr($name,'complexType')) {
  1488.                 $this->currentComplexType = '';
  1489.                 if (count($this->schema_element_stack> 0)
  1490.                     $this->currentElement = array_pop($this->schema_element_stack);
  1491.                 else
  1492.                     $this->currentElement = '';
  1493.             else if (stristr($name,'element')) {
  1494.                 if (count($this->schema_element_stack> 0)
  1495.                     $this->currentElement = array_pop($this->schema_element_stack);
  1496.                 else
  1497.                     $this->currentElement = '';
  1498.             }
  1499.         }
  1500.         // position of current element is equal to the last value left in depth_array for my depth
  1501.         //$pos = $this->depth_array[$this->depth];
  1502.         // bring depth down a notch
  1503.         //$this->depth--;
  1504.     }
  1505.  
  1506.     // element content handler
  1507.     function characterData($parser$data)
  1508.     {
  1509.         # store the documentation in the WSDL file
  1510.         if ($this->currentTag == 'documentation'{
  1511.             if ($this->status ==  'service'{
  1512.                 $this->wsdl->services[$this->currentService][$this->currentTag.= $data;
  1513.             else if ($this->status ==  'portType'{
  1514.                 if ($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag])
  1515.                     $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag.= data;
  1516.                 else
  1517.                     $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag= data;
  1518.             else if ($this->status ==  'binding'{
  1519.                 if ($this->wsdl->bindings[$this->currentBinding][$this->currentTag])
  1520.                     $this->wsdl->bindings[$this->currentBinding][$this->currentTag.= data;
  1521.                 else
  1522.                     $this->wsdl->bindings[$this->currentBinding][$this->currentTag= data;
  1523.             else if ($this->status ==  'message'{
  1524.                 if ($this->wsdl->messages[$this->currentMessage][$this->currentTag])
  1525.                     $this->wsdl->messages[$this->currentMessage][$this->currentTag.= data;
  1526.                 else
  1527.                     $this->wsdl->messages[$this->currentMessage][$this->currentTag= data;
  1528.             else if ($this->status ==  'operation'{
  1529.                 if ($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag])
  1530.                     $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag.= data;
  1531.                 else
  1532.                     $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$this->currentTag= data;
  1533.             }
  1534.         }
  1535.     }
  1536.  
  1537.  
  1538.     // $parsed is a parse_url() resulting array
  1539.     function merge_url($parsed,$path{
  1540.  
  1541.         if (is_array($parsed)) return false;
  1542.  
  1543.         if (isset($parsed['scheme'])) {
  1544.             $sep (strtolower($parsed['scheme']== 'mailto' ':' '://');
  1545.             $uri $parsed['scheme'$sep;
  1546.         else {
  1547.             $uri '';
  1548.         }
  1549.  
  1550.         if (isset($parsed['pass'])) {
  1551.             $uri .= "$parsed[user]:$parsed[pass]@";
  1552.         elseif (isset($parsed['user'])) {
  1553.             $uri .= "$parsed[user]@";
  1554.         }
  1555.  
  1556.         if (isset($parsed['host']))     $uri .= $parsed['host'];
  1557.         if (isset($parsed['port']))     $uri .= ":$parsed[port]";
  1558.         if ($path[0]!='/' && isset($parsed['path'])) {
  1559.             if ($parsed['path'][strlen($parsed['path'])-1!= '/'{
  1560.                 $path dirname($parsed['path']).'/'.$path;
  1561.             else {
  1562.                 $path $parsed['path'].$path;
  1563.             }
  1564.             $path $this->_normalize($path);
  1565.         }
  1566.         $sep $path[0]=='/'?'':'/';
  1567.         $uri .= $sep.$path;
  1568.  
  1569.         return $uri;
  1570.     }
  1571.  
  1572.     function _normalize($path_str){
  1573.         $pwd='';
  1574.         $strArr=preg_split("/(\/)/",$path_str,-1,PREG_SPLIT_NO_EMPTY);
  1575.         $pwdArr="";
  1576.         $j=0;
  1577.         for($i=0;$i<count($strArr);$i++){
  1578.             if($strArr[$i]!=".."){
  1579.                 if($strArr[$i]!="."){
  1580.                 $pwdArr[$j]=$strArr[$i];
  1581.                 $j++;
  1582.                 }
  1583.             }else{
  1584.                 array_pop($pwdArr);
  1585.                 $j--;
  1586.             }
  1587.         }
  1588.         $pStr=implode("/",$pwdArr);
  1589.         $pwd=(strlen($pStr)>0("/".$pStr"/";
  1590.         return $pwd;
  1591.     }
  1592. }
  1593.  
  1594. /**
  1595.  * Parses the types and methods used in web service objects into the internal
  1596.  * data structures used by SOAP_WSDL.
  1597.  *
  1598.  * Assumes the SOAP_WSDL class is unpopulated to start with.
  1599.  *
  1600.  * @author Chris Coe <info@intelligentstreaming.com>
  1601.  */
  1602. {
  1603.     // Target namespace for the WSDL document will have the following prefix
  1604.     var $tnsPrefix = 'tns';
  1605.  
  1606.     // Reference to the SOAP_WSDL object to populate
  1607.     var $wsdl = null;
  1608.  
  1609.     /** Constructor
  1610.      *
  1611.      * @param  $objects Reference to the object or array of objects to parse
  1612.      * @param  $wsdl Reference to the SOAP_WSDL object to populate
  1613.      * @param  $targetNamespace The target namespace of schema types etc.
  1614.      * @param  $service_name Name of the WSDL <service>
  1615.      * @param  $service_desc Optional description of the WSDL <service>
  1616.      */
  1617.     function SOAP_WSDL_ObjectParser(&$objects&$wsdl$targetNamespace$service_name$service_desc ''{
  1618.         parent::SOAP_Base('WSDLOBJECTPARSER');
  1619.  
  1620.         $this->wsdl = &$wsdl;
  1621.  
  1622.         // Set up the SOAP_WSDL object
  1623.         $this->_initialise($service_name);
  1624.  
  1625.         // Parse each web service object
  1626.         $wsdl_ref (is_array($objects)$objects : array(&$objects));
  1627.  
  1628.         foreach ($wsdl_ref as $ref_item{
  1629.             if (!is_object($ref_item))
  1630.                 return $this->_raiseSoapFault('Invalid web service object passed to object parser''urn:' get_class($object));
  1631.  
  1632.             if ($this->_parse($ref_item$targetNamespace$service_name!= true)
  1633.                 break;
  1634.         }
  1635.  
  1636.         // Build bindings from abstract data
  1637.         if ($this->fault == NULL)
  1638.             $this->_generateBindingsAndServices($targetNamespace$service_name$service_desc);
  1639.     }
  1640.  
  1641.     /** Initialise the SOAP_WSDL tree (destructive)
  1642.      *
  1643.      * If the object has already been initialised, the only effect will be to
  1644.      * change the tns namespace to the new service name
  1645.      *
  1646.      * @param  $service_name Name of the WSDL <service>
  1647.      * @access private
  1648.      */
  1649.     function _initialise($service_name{
  1650.         // Set up the basic namespaces that all WSDL definitions use
  1651.  
  1652.         $this->wsdl->namespaces['wsdl'SCHEMA_WSDL;                                      // WSDL language
  1653.         $this->wsdl->namespaces['soap'SCHEMA_SOAP;                                      // WSDL SOAP bindings
  1654.         $this->wsdl->namespaces[$this->tnsPrefix'urn:' $service_name;                 // Target namespace
  1655.         $this->wsdl->namespaces['xsd'array_search('xsd'$this->_namespaces);           // XML Schema
  1656.         $this->wsdl->namespaces['SOAP-ENC'array_search('SOAP-ENC'$this->_namespaces)// SOAP types
  1657.  
  1658.         // XXX Refactor $namespace/$ns for Shane :-)
  1659.         unset($this->wsdl->ns['urn:' $service_name]);
  1660.         $this->wsdl->ns += array_flip($this->wsdl->namespaces);
  1661.  
  1662.         // Imports are not implemented in WSDL generation from classes
  1663.         // *** <wsdl:import> ***
  1664.     }
  1665.  
  1666.     /** Parser - takes a single object to add to tree (non-destructive)
  1667.      *
  1668.      * @param  $object Reference to the object to parse
  1669.      * @param  $service_name Name of the WSDL <service>
  1670.      * @access private
  1671.      */
  1672.     function _parse(&$object$schemaNamespace$service_name{
  1673.         // Create namespace prefix for the schema
  1674.         // XXX not very elegant :-(
  1675.  
  1676.         list ($schPrefix$foo$this->_getTypeNs('{'.$schemaNamespace.'}');
  1677.         unset($foo);
  1678.  
  1679.         // Parse all the types defined by the object in whatever
  1680.         // schema language we are using (currently __typedef arrays)
  1681.         // *** <wsdl:types> ***
  1682.  
  1683.         foreach ($object->__typedef as $typeName => $typeValue)
  1684.         {
  1685.             // Get/create namespace definition
  1686.  
  1687.             list($nsPrefix$typeName$this->_getTypeNs($typeName);
  1688.  
  1689.             // Create type definition
  1690.  
  1691.             $this->wsdl->complexTypes[$schPrefix][$typeName= array("name" => $typeName);
  1692.             $thisType =$this->wsdl->complexTypes[$schPrefix][$typeName];
  1693.  
  1694.             // According to Dmitri's documentation, __typedef comes in two
  1695.             // flavors:
  1696.             // Array = array(array("item" => "value"))
  1697.             // Struct = array("item1" => "value1", "item2" => "value2", ...)
  1698.  
  1699.             if (is_array($typeValue))
  1700.             {
  1701.                 reset($typeValue);
  1702.                 if (is_array(current($typeValue)) && count($typeValue== 1
  1703.                         && count(current($typeValue)) == 1)
  1704.                 {
  1705.                     // It's an array
  1706.  
  1707.                     $thisType['type''Array';
  1708.                     reset(current($typeValue));
  1709.                     list($nsPrefix$typeName$this->_getTypeNs(current(current($typeValue)));
  1710.                     $thisType['namespace'$nsPrefix;
  1711.                     $thisType['arrayType'$typeName '[]';
  1712.  
  1713.                 }
  1714.                 else if (!is_array(current($typeValue)))
  1715.                 {
  1716.                     // It's a struct
  1717.  
  1718.                     $thisType['type''Struct';
  1719.                     $thisType['order''all';
  1720.                     $thisType['namespace'$nsPrefix;
  1721.                     $thisType['elements'= array();
  1722.  
  1723.                     foreach ($typeValue as $elementName => $elementType)
  1724.                     {
  1725.                         list($nsPrefix$typeName$this->_getTypeNs($elementType);
  1726.                         $thisType['elements'][$elementName]['name'$elementName;
  1727.                         $thisType['elements'][$elementName]['type'$typeName;
  1728.                         $thisType['elements'][$elementName]['namespace'$nsPrefix;
  1729.                     }
  1730.                 }
  1731.                 else
  1732.                 {
  1733.                     // It's erroneous
  1734.  
  1735.                     return $this->_raiseSoapFault("The type definition for $nsPrefix:$typeName is invalid."'urn:' get_class($object));
  1736.                 }
  1737.             else {
  1738.                 // It's erroneous
  1739.  
  1740.                return $this->_raiseSoapFault("The type definition for $nsPrefix:$typeName is invalid."'urn:' get_class($object));
  1741.             }
  1742.         }
  1743.  
  1744.         // Create an empty element array with the target namespace prefix,
  1745.         // to match the results of WSDL parsing
  1746.  
  1747.         $this->wsdl->elements[$schPrefix= array();
  1748.  
  1749.         // Populate tree with message information
  1750.         // *** <wsdl:message> ***
  1751.  
  1752.         foreach ($object->__dispatch_map as $operationName => $messages)
  1753.         {
  1754.             foreach ($messages as $messageType => $messageParts)
  1755.             {
  1756.                 unset($thisMessage);
  1757.  
  1758.                 switch ($messageType{
  1759.                 case 'in':
  1760.                     $this->wsdl->messages[$operationName 'Request'= array();
  1761.                     $thisMessage =$this->wsdl->messages[$operationName 'Request'];
  1762.                     break;
  1763.  
  1764.                 case 'out':
  1765.                     $this->wsdl->messages[$operationName 'Response'= array();
  1766.                     $thisMessage =$this->wsdl->messages[$operationName 'Response'];
  1767.                     break;
  1768.  
  1769.                 case 'alias':
  1770.                     // Do nothing
  1771.                     break;
  1772.  
  1773.                 default:
  1774.                     // Error condition
  1775.                     break;
  1776.                 }
  1777.  
  1778.                 if (isset($thisMessage))
  1779.                 {
  1780.                     foreach ($messageParts as $partName => $partType)
  1781.                     {
  1782.                         list ($nsPrefix$typeName$this->_getTypeNs($partType);
  1783.  
  1784.                         $thisMessage[$partName= array(
  1785.                             'name' => $partName,
  1786.                             'type' => $typeName,
  1787.                             'namespace' => $nsPrefix
  1788.                             );
  1789.                     }
  1790.                 }
  1791.             }
  1792.         }
  1793.  
  1794.         // Populate tree with portType information
  1795.         // XXX Current implementation only supports one portType that
  1796.         // encompasses all of the operations available.
  1797.         // *** <wsdl:portType> ***
  1798.  
  1799.         if (!isset($this->wsdl->portTypes[$service_name 'Port']))
  1800.             $this->wsdl->portTypes[$service_name 'Port'= array();
  1801.         $thisPortType =$this->wsdl->portTypes[$service_name 'Port'];
  1802.  
  1803.         foreach ($object->__dispatch_map as $operationName => $messages)
  1804.         {
  1805.             $thisPortType[$operationName= array('name' => $operationName);
  1806.  
  1807.             foreach ($messages as $messageType => $messageParts)
  1808.             {
  1809.                 switch ($messageType{
  1810.                 case 'in':
  1811.                     $thisPortType[$operationName]['input'= array(
  1812.                             'message' => $operationName 'Request',
  1813.                             'namespace' => $this->tnsPrefix);
  1814.                     break;
  1815.  
  1816.                 case 'out':
  1817.                     $thisPortType[$operationName]['output'= array(
  1818.                             'message' => $operationName 'Response',
  1819.                             'namespace' => $this->tnsPrefix);
  1820.                     break;
  1821.  
  1822.                 default:
  1823.                     break;
  1824.                 }
  1825.             }
  1826.         }
  1827.  
  1828.         return true;
  1829.     }
  1830.  
  1831.     /** Take all the abstract WSDL data and build concrete bindings and services (destructive)
  1832.      *
  1833.      * XXX Current implementation discards $service_desc.
  1834.      *
  1835.      * @param  $schemaNamespace Namespace for types etc.
  1836.      * @param  $service_name Name of the WSDL <service>
  1837.      * @param  $service_desc Optional description of the WSDL <service>
  1838.      * @access private
  1839.      */
  1840.     function _generateBindingsAndServices($schemaNamespace$service_name$service_desc '')
  1841.     {
  1842.         // Populate tree with bindings information
  1843.         // XXX Current implementation only supports one binding that
  1844.         // matches the single portType and all of its operations.
  1845.         // XXX Is this the correct use of $schemaNamespace here?
  1846.         // *** <wsdl:binding> ***
  1847.  
  1848.         $this->wsdl->bindings[$service_name 'Binding'= array(
  1849.                 'type' => $service_name 'Port',
  1850.                 'namespace' => $this->tnsPrefix,
  1851.                 'style' => 'rpc',
  1852.                 'transport' => SCHEMA_SOAP_HTTP,
  1853.                 'operations' => array());
  1854.         $thisBinding =$this->wsdl->bindings[$service_name 'Binding'];
  1855.  
  1856.         foreach ($this->wsdl->portTypes[$service_name 'Port'as $operationName => $operationData)
  1857.         {
  1858.             $thisBinding['operations'][$operationName= array(
  1859.                 'soapAction' => $schemaNamespace '#' $operationName,
  1860.                 'style' => $thisBinding['style']);
  1861.  
  1862.             foreach (array('input''output'as $messageType)
  1863.                 if (isset($operationData[$messageType]))
  1864.                     $thisBinding['operations'][$operationName][$messageType= array(
  1865.                             'use' => 'encoded',
  1866.                             'namespace' => $schemaNamespace,
  1867.                             'encodingStyle' => SOAP_SCHEMA_ENCODING);
  1868.         }
  1869.  
  1870.         // Populate tree with service information
  1871.         // XXX Current implementation supports one service which groups
  1872.         // all of the ports together, one port per binding
  1873.         // XXX What about https?
  1874.         // *** <wsdl:service> ***
  1875.  
  1876.         $this->wsdl->services[$service_name 'Service'= array('ports' => array());
  1877.         $thisService =$this->wsdl->services[$service_name 'Service']['ports'];
  1878.  
  1879.         foreach ($this->wsdl->bindings as $bindingName => $bindingData)
  1880.         {
  1881.             $thisService[$bindingData['type']] = array(
  1882.                     'name' => $bindingData['type'],
  1883.                     'binding' => $bindingName,
  1884.                     'namespace' => $this->tnsPrefix,
  1885.                     'address' => array('location' =>
  1886.                         'http://' $_SERVER['SERVER_NAME'$_SERVER['PHP_SELF'.
  1887.                         (isset($_SERVER['QUERY_STRING']'?' $_SERVER['QUERY_STRING''')),
  1888.                     'type' => 'soap');
  1889.         }
  1890.  
  1891.         // Set service
  1892.         $this->wsdl->set_service($service_name 'Service');
  1893.         $this->wsdl->uri = $this->wsdl->namespaces[$this->tnsPrefix];
  1894.  
  1895.         // Create WSDL definition
  1896.         // *** <wsdl:definitions> ***
  1897.  
  1898.         $this->wsdl->definition = array(
  1899.                 'name' => $service_name,
  1900.                 'targetNamespace' => $this->wsdl->namespaces[$this->tnsPrefix],
  1901.                 'xmlns' => SCHEMA_WSDL);
  1902.  
  1903.         foreach ($this->wsdl->namespaces as $nsPrefix => $namespace)
  1904.             $this->wsdl->definition['xmlns:' $nsPrefix$namespace;
  1905.     }
  1906.  
  1907.     // This function is adapted from Dmitri V's implementation of
  1908.     // DISCO/WSDL generation. It separates namespace from type name in a
  1909.     // __typedef key and creates a new namespace entry in the WSDL structure
  1910.     // if the namespace has not been used before. The namespace prefix and
  1911.     // type name are returned. If no namespace is specified, xsd is assumed.
  1912.     //
  1913.     // We will not need this function anymore once __typedef is eliminated.
  1914.     function _getTypeNs($type{
  1915.         preg_match_all("'\{(.*)\}'sm",$type,$m);
  1916.         if (isset($m[1][0]&& $m[1][0!= ''{
  1917.             if (!array_key_exists($m[1][0],$this->wsdl->ns)) {
  1918.                 $ns_pref 'ns' count($this->wsdl->namespaces);
  1919.                 $this->wsdl->ns[$m[1][0]] $ns_pref;
  1920.                 $this->wsdl->namespaces[$ns_pref$m[1][0];
  1921.             }
  1922.             $typens $this->wsdl->ns[$m[1][0]];
  1923.             $type ereg_replace($m[0][0],'',$type);
  1924.         else {
  1925.             $typens 'xsd';
  1926.         }
  1927.         return array($typens,$type);
  1928.     }
  1929. }
  1930. ?>

Documentation generated on Mon, 11 Mar 2019 13:59:48 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.