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