eZ Publish  [4.0]
ezsoapresponse.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // $Id$
00004 //
00005 // Definition of eZSOAPResponse class
00006 //
00007 // Bård Farstad <bf@ez.no>
00008 // Created on: <19-Feb-2002 16:51:10 bf>
00009 //
00010 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00011 // SOFTWARE NAME: eZ Publish
00012 // SOFTWARE RELEASE: 4.0.x
00013 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS
00014 // SOFTWARE LICENSE: GNU General Public License v2.0
00015 // NOTICE: >
00016 //   This program is free software; you can redistribute it and/or
00017 //   modify it under the terms of version 2.0  of the GNU General
00018 //   Public License as published by the Free Software Foundation.
00019 //
00020 //   This program is distributed in the hope that it will be useful,
00021 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 //   GNU General Public License for more details.
00024 //
00025 //   You should have received a copy of version 2.0 of the GNU General
00026 //   Public License along with this program; if not, write to the Free
00027 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00028 //   MA 02110-1301, USA.
00029 //
00030 //
00031 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00032 //
00033 
00034 /*!
00035   \class eZSOAPResponse ezsoapresponse.php
00036   \ingroup eZSOAP
00037   \brief eZSOAPResponse handles SOAP response packages
00038 
00039 */
00040 
00041 require_once( "lib/ezutils/classes/ezdebug.php" );
00042 //include_once( 'lib/ezsoap/classes/ezsoapcodec.php' );
00043 //include_once( "lib/ezsoap/classes/ezsoapenvelope.php" );
00044 
00045 class eZSOAPResponse extends eZSOAPEnvelope
00046 {
00047     /*!
00048       Constructs a new SOAP response
00049     */
00050     function eZSOAPResponse( $name="", $namespace="" )
00051     {
00052         $this->Name = $name;
00053         $this->Namespace = $namespace;
00054 
00055         // call the parents constructor
00056         $this->eZSOAPEnvelope();
00057     }
00058 
00059     /*!
00060       Decodes the SOAP response stream
00061     */
00062     function decodeStream( $request, $stream )
00063     {
00064         $dom = new DOMDocument( "1.0" );
00065 
00066         $dom->loadXML( $this->stripHTTPHeader( $stream ) );
00067         $this->DOMDocument = $dom;
00068 
00069         if ( !empty( $dom ) )
00070         {
00071             // check for fault
00072             $response = $dom->getElementsByTagNameNS( eZSOAPEnvelope::ENV, 'Fault' );
00073 
00074             if ( $response->length  == 1 )
00075             {
00076                 $this->IsFault = 1;
00077                 foreach( $dom->getElementsByTagName( "faultstring" ) as $faultNode )
00078                 {
00079                     $this->FaultString = $faultNode->textContent;
00080                     break;
00081                 }
00082 
00083                 foreach( $dom->getElementsByTagName( "faultcode" ) as $faultNode )
00084                 {
00085                     $this->FaultCode = $faultNode->textContent;
00086                     break;
00087                 }
00088                 return;
00089             }
00090 
00091             // get the response
00092             $response = $dom->getElementsByTagNameNS( $request->namespace(), $request->name() . "Response" );
00093 
00094             /* Some protocols do not use namespaces, and do not work with an empty namespace.
00095             So, if we get no response, try again without namespace.
00096             */
00097             if ( $response->length == 0 )
00098             {
00099                 $response = $dom->getElementsByTagName( $request->name() . "Response" );
00100             }
00101 
00102             $response = $response->item(0);
00103 
00104             if ( !empty( $response ) )
00105             {
00106                 /* Cut from the SOAP spec:
00107                 The method response is viewed as a single struct containing an accessor
00108                 for the return value and each [out] or [in/out] parameter.
00109                 The first accessor is the return value followed by the parameters
00110                 in the same order as in the method signature.
00111 
00112                 Each parameter accessor has a name corresponding to the name
00113                 of the parameter and type corresponding to the type of the parameter.
00114                 The name of the return value accessor is not significant.
00115                 Likewise, the name of the struct is not significant.
00116                 However, a convention is to name it after the method name
00117                 with the string "Response" appended.
00118                 */
00119 
00120                 $responseAccessors = $response->getElementsByTagName( 'return' );
00121                 if ( $responseAccessors->length > 0 )
00122                 {
00123                     $returnObject = $responseAccessors->item( 0 );
00124                     $this->Value  = $this->decodeDataTypes( $returnObject );
00125                 }
00126             }
00127             else
00128             {
00129                 eZDebug::writeError( "Got error from server" );
00130             }
00131         }
00132         else
00133         {
00134             eZDebug::writeError( "Could not process XML in response" );
00135         }
00136     }
00137 
00138     /*!
00139       \static
00140       Decodes a DOM node and returns the PHP datatype instance of it.
00141     */
00142     static function decodeDataTypes( $node, $type = "" )
00143     {
00144         $returnValue = false;
00145 
00146         $attributeValue = '';
00147         $attribute = $node->getAttributeNodeNS( eZSOAPEnvelope::SCHEMA_INSTANCE, 'type' );
00148         if ( !$attribute )
00149         {
00150             $attribute = $node->getAttributeNodeNS( 'http://www.w3.org/1999/XMLSchema-instance', 'type' );
00151         }
00152         $attributeValue = $attribute->value;
00153 
00154         $dataType = $type;
00155         $attrParts = explode( ":", $attributeValue );
00156         if ( $attrParts[1] )
00157         {
00158             $dataType = $attrParts[1];
00159         }
00160 
00161 /*
00162         $typeNamespacePrefix = $this->DOMDocument->namespaceByAlias( $attrParts[0] );
00163 
00164         check that this is a namespace type definition
00165                 if ( ( $typeNamespacePrefix == eZSOAPEnvelope::SCHEMA_DATA ) ||
00166                      ( $typeNamespacePrefix == eZSOAPEnvelope::ENC )
00167                      )
00168 TODO: add encoding checks with schema validation.
00169 */
00170 
00171         switch ( $dataType )
00172         {
00173             case "string" :
00174             case "int" :
00175             case "float" :
00176             case 'double' :
00177             {
00178                 $returnValue = $node->textContent;
00179             } break;
00180 
00181             case "boolean" :
00182             {
00183                 if ( $node->textContent == "true" )
00184                     $returnValue = true;
00185                 else
00186                     $returnValue = false;
00187             } break;
00188 
00189             case "base64" :
00190             {
00191                 $returnValue = base64_decode( $node->textContent );
00192             } break;
00193 
00194             case "Array" :
00195             {
00196                 // Get array type
00197                 $arrayType = $node->getAttributeNodeNS( eZSOAPEnvelope::ENC, 'arrayType' )->value;
00198                 $arrayTypeParts = explode( ":", $arrayType );
00199 
00200                 preg_match( "#(.*)\[(.*)\]#",  $arrayTypeParts[1], $matches );
00201 
00202                 $type = $matches[1];
00203                 $count = $matches[2];
00204 
00205                 $returnValue = array();
00206                 foreach( $node->childNodes as $child )
00207                 {
00208                     if ( $child instanceof DOMElement )
00209                     {
00210                         $returnValue[] = eZSOAPResponse::decodeDataTypes( $child, $type );
00211                     }
00212                 }
00213             }break;
00214 
00215             case "SOAPStruct" :
00216             {
00217                 $returnValue = array();
00218 
00219                 foreach( $node->childNodes as $child )
00220                 {
00221                     if ( $child instanceof DOMElement )
00222                     {
00223                         $returnValue[$child->tagName] = eZSOAPResponse::decodeDataTypes( $child );
00224                     }
00225                 }
00226             }break;
00227 
00228             default:
00229             {
00230                 foreach ( $node->childNodes as $childNode )
00231                 {
00232                     if ( $childNode instanceof DOMElement )
00233                     {
00234                         // check data type for child
00235                         $attr = $childNode->getAttributeNodeNS( eZSOAPEnvelope::SCHEMA_INSTANCE, 'type' )->value;
00236 
00237                         $dataType = false;
00238                         $attrParts = explode( ":", $attr );
00239                         $dataType = $attrParts[1];
00240 
00241                         $returnValue[$childNode->tagName] = eZSOAPResponse::decodeDataTypes( $childNode );
00242                     }
00243                 }
00244 
00245             } break;
00246         }
00247 
00248         return $returnValue;
00249     }
00250 
00251     /*!
00252       Returns the XML payload for the response.
00253     */
00254     function payload( )
00255     {
00256         $doc = new DOMDocument( '1.0', 'utf-8' );
00257         $doc->name = "eZSOAP message";
00258 
00259         $root = $doc->createElementNS( eZSOAPEnvelope::ENV, eZSOAPEnvelope::ENV_PREFIX . ':Envelope' );
00260 
00261         $root->setAttribute( 'xmlns:' . eZSOAPEnvelope::XSI_PREFIX, eZSOAPEnvelope::SCHEMA_INSTANCE );
00262         $root->setAttribute( 'xmlns:' . eZSOAPEnvelope::XSD_PREFIX, eZSOAPEnvelope::SCHEMA_DATA );
00263         $root->setAttribute( 'xmlns:' . eZSOAPEnvelope::ENC_PREFIX, eZSOAPEnvelope::ENC );
00264 
00265         // add the body
00266         $body = $doc->createElement(  eZSOAPEnvelope::ENV_PREFIX . ':Body' );
00267         $root->appendChild( $body );
00268 
00269         // Check if it's a fault
00270         if ( $this->Value instanceof eZSOAPFault )
00271         {
00272             $fault = $doc->createElement( eZSOAPEnvelope::ENV_PREFIX . ':Fault' );
00273 
00274             $faultCodeNode = $doc->createElement( "faultcode", $this->Value->faultCode() );
00275             $fault->appendChild( $faultCodeNode );
00276 
00277             $faultStringNode = $doc->createElement( "faultstring", $this->Value->faultString() );
00278             $fault->appendChild( $faultStringNode );
00279 
00280             $body->appendChild( $fault );
00281         }
00282         else
00283         {
00284             // add the request
00285             $responseName = $this->Name . "Response";
00286             if ( $this->Namespace == '' )
00287                 $response = $doc->createElement( "resp:".$responseName );
00288             else
00289                 $response = $doc->createElementNS( $this->Namespace, "resp:".$responseName );
00290 
00291             $return = $doc->createElement( "return" );
00292 
00293             $value = eZSOAPCodec::encodeValue( $doc, "return", $this->Value );
00294 
00295             $body->appendChild( $response );
00296 
00297             $response->appendChild( $value );
00298         }
00299 
00300         $doc->appendChild( $root );
00301 
00302         return $doc->saveXML();
00303     }
00304 
00305     /*!
00306       \static
00307       \private
00308       Strips the header information from the HTTP raw response.
00309     */
00310     function stripHTTPHeader( $data )
00311     {
00312         $missingxml = false;
00313         $start = strpos( $data, "<?xml" );
00314         if ( $start == 0 )
00315         {
00316             eZDebug::writeWarning( "missing <?xml ...> in HTTP response, attempting workaround",
00317                                    "eZSoapResponse::stripHTTPHeader" );
00318             $start = strpos( $data, "<E:Envelope" );
00319             $missingxml = true;
00320         }
00321         $data = substr( $data, $start, strlen( $data ) - $start );
00322 
00323         if ( $missingxml == true )
00324         {
00325             $data = '<?xml version="1.0"?>' . $data;
00326         }
00327 
00328         return $data;
00329     }
00330 
00331     /*!
00332       Returns the response value.
00333     */
00334     function value()
00335     {
00336         return $this->Value;
00337     }
00338 
00339     /*!
00340      Sets the value of the response.
00341     */
00342     function setValue( $value )
00343     {
00344         $this->Value = $value;
00345     }
00346 
00347     /*!
00348      Returns true if the response was a fault
00349     */
00350     function isFault()
00351     {
00352         return $this->IsFault;
00353     }
00354 
00355     /*!
00356      Returns the fault code
00357     */
00358     function faultCode()
00359     {
00360         return $this->FaultCode;
00361     }
00362 
00363     /*!
00364      Returns the fault string
00365     */
00366     function faultString()
00367     {
00368         return $this->FaultString;
00369     }
00370 
00371     /// Contains the response value
00372     public $Value = false;
00373     /// Contains the response type
00374     public $Type = false;
00375     /// Contains fault string
00376     public $FaultString = false;
00377     /// Contains the fault code
00378     public $FaultCode = false;
00379     /// Contains true if the response was an fault
00380     public $IsFault = false;
00381     /// Contains the name of the response, i.e. function call name
00382     public $Name;
00383     /// Contains the target namespace for the response
00384     public $Namespace;
00385 
00386     /// Contains the DOM document for the current SOAP response
00387     public $DOMDocument = false;
00388 }
00389 
00390 ?>