Back to index

php5  5.3.10
php_packet_soap.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Authors: Brad Lafountain <rodif_bl@yahoo.com>                        |
00016   |          Shane Caraveo <shane@caraveo.com>                           |
00017   |          Dmitry Stogov <dmitry@zend.com>                             |
00018   +----------------------------------------------------------------------+
00019 */
00020 /* $Id: php_packet_soap.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include "php_soap.h"
00023 
00024 /* SOAP client calls this function to parse response from SOAP server */
00025 int parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctionPtr fn, char *fn_name, zval *return_value, zval *soap_headers TSRMLS_DC)
00026 {
00027        char* envelope_ns = NULL;
00028        xmlDocPtr response;
00029        xmlNodePtr trav, env, head, body, resp, cur, fault;
00030        xmlAttrPtr attr;
00031        int param_count = 0;
00032        int soap_version = SOAP_1_1;
00033        HashTable *hdrs = NULL;
00034 
00035        ZVAL_NULL(return_value);
00036 
00037        /* Response for one-way opearation */
00038        if (buffer_size == 0) {
00039               return TRUE;
00040        }
00041 
00042        /* Parse XML packet */
00043        response = soap_xmlParseMemory(buffer, buffer_size);
00044 
00045        if (!response) {
00046               add_soap_fault(this_ptr, "Client", "looks like we got no XML document", NULL, NULL TSRMLS_CC);
00047               return FALSE;
00048        }
00049        if (xmlGetIntSubset(response) != NULL) {
00050               add_soap_fault(this_ptr, "Client", "DTD are not supported by SOAP", NULL, NULL TSRMLS_CC);
00051               xmlFreeDoc(response);
00052               return FALSE;
00053        }
00054 
00055        /* Get <Envelope> element */
00056        env = NULL;
00057        trav = response->children;
00058        while (trav != NULL) {
00059               if (trav->type == XML_ELEMENT_NODE) {
00060                      if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_1_ENV_NAMESPACE)) {
00061                             env = trav;
00062                             envelope_ns = SOAP_1_1_ENV_NAMESPACE;
00063                             soap_version = SOAP_1_1;
00064                      } else if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_2_ENV_NAMESPACE)) {
00065                             env = trav;
00066                             envelope_ns = SOAP_1_2_ENV_NAMESPACE;
00067                             soap_version = SOAP_1_2;
00068                      } else {
00069                             add_soap_fault(this_ptr, "VersionMismatch", "Wrong Version", NULL, NULL TSRMLS_CC);
00070                             xmlFreeDoc(response);
00071                             return FALSE;
00072                      }
00073               }
00074               trav = trav->next;
00075        }
00076        if (env == NULL) {
00077               add_soap_fault(this_ptr, "Client", "looks like we got XML without \"Envelope\" element", NULL, NULL TSRMLS_CC);
00078               xmlFreeDoc(response);
00079               return FALSE;
00080        }
00081 
00082        attr = env->properties;
00083        while (attr != NULL) {
00084               if (attr->ns == NULL) {
00085                      add_soap_fault(this_ptr, "Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC);
00086                      xmlFreeDoc(response);
00087                      return FALSE;
00088               } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
00089                      if (soap_version == SOAP_1_2) {
00090                             add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL TSRMLS_CC);
00091                             xmlFreeDoc(response);
00092                             return FALSE;
00093                      } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) {
00094                             add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC);
00095                             xmlFreeDoc(response);
00096                             return FALSE;
00097                      }
00098               }
00099               attr = attr->next;
00100        }
00101 
00102        /* Get <Header> element */
00103        head = NULL;
00104        trav = env->children;
00105        while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
00106               trav = trav->next;
00107        }
00108        if (trav != NULL && node_is_equal_ex(trav,"Header",envelope_ns)) {
00109               head = trav;
00110               trav = trav->next;
00111        }
00112 
00113        /* Get <Body> element */
00114        body = NULL;
00115        while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
00116               trav = trav->next;
00117        }
00118        if (trav != NULL && node_is_equal_ex(trav,"Body",envelope_ns)) {
00119               body = trav;
00120               trav = trav->next;
00121        }
00122        while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
00123               trav = trav->next;
00124        }
00125        if (body == NULL) {
00126               add_soap_fault(this_ptr, "Client", "Body must be present in a SOAP envelope", NULL, NULL TSRMLS_CC);
00127               xmlFreeDoc(response);
00128               return FALSE;
00129        }
00130        attr = body->properties;
00131        while (attr != NULL) {
00132               if (attr->ns == NULL) {
00133                      if (soap_version == SOAP_1_2) {
00134                             add_soap_fault(this_ptr, "Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC);
00135                             xmlFreeDoc(response);
00136                             return FALSE;
00137                      }
00138               } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
00139                      if (soap_version == SOAP_1_2) {
00140                             add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Body", NULL, NULL TSRMLS_CC);
00141                             xmlFreeDoc(response);
00142                             return FALSE;
00143                      } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) {
00144                             add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC);
00145                             xmlFreeDoc(response);
00146                             return FALSE;
00147                      }
00148               }
00149               attr = attr->next;
00150        }
00151        if (trav != NULL && soap_version == SOAP_1_2) {
00152               add_soap_fault(this_ptr, "Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL TSRMLS_CC);
00153               xmlFreeDoc(response);
00154               return FALSE;
00155        }
00156 
00157        if (head != NULL) {
00158               attr = head->properties;
00159               while (attr != NULL) {
00160                      if (attr->ns == NULL) {
00161                             add_soap_fault(this_ptr, "Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC);
00162                             xmlFreeDoc(response);
00163                             return FALSE;
00164                      } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
00165                             if (soap_version == SOAP_1_2) {
00166                                    add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Header", NULL, NULL TSRMLS_CC);
00167                                    xmlFreeDoc(response);
00168                                    return FALSE;
00169                             } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) {
00170                                    add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC);
00171                                    xmlFreeDoc(response);
00172                                    return FALSE;
00173                             }
00174                      }
00175                      attr = attr->next;
00176               }
00177        }
00178 
00179        /* Check if <Body> contains <Fault> element */
00180        fault = get_node_ex(body->children,"Fault",envelope_ns);
00181        if (fault != NULL) {
00182               char *faultcode = NULL, *faultstring = NULL, *faultactor = NULL;
00183               zval *details = NULL;
00184               xmlNodePtr tmp;
00185 
00186               if (soap_version == SOAP_1_1) {
00187                      tmp = get_node(fault->children, "faultcode");
00188                      if (tmp != NULL && tmp->children != NULL) {
00189                             faultcode = (char*)tmp->children->content;
00190                      }
00191 
00192                      tmp = get_node(fault->children, "faultstring");
00193                      if (tmp != NULL && tmp->children != NULL) {
00194                             zval *zv = master_to_zval(get_conversion(IS_STRING), tmp);
00195                             faultstring = Z_STRVAL_P(zv);
00196                             FREE_ZVAL(zv);
00197                      }
00198 
00199                      tmp = get_node(fault->children, "faultactor");
00200                      if (tmp != NULL && tmp->children != NULL) {
00201                             zval *zv = master_to_zval(get_conversion(IS_STRING), tmp);
00202                             faultactor = Z_STRVAL_P(zv);
00203                             FREE_ZVAL(zv);
00204                      }
00205 
00206                      tmp = get_node(fault->children, "detail");
00207                      if (tmp != NULL) {
00208                             details = master_to_zval(NULL, tmp);
00209                      }
00210               } else {
00211                      tmp = get_node(fault->children, "Code");
00212                      if (tmp != NULL && tmp->children != NULL) {
00213                             tmp = get_node(tmp->children, "Value");
00214                             if (tmp != NULL && tmp->children != NULL) {
00215                                    faultcode = (char*)tmp->children->content;
00216                             }
00217                      }
00218 
00219                      tmp = get_node(fault->children,"Reason");
00220                      if (tmp != NULL && tmp->children != NULL) {
00221                             /* TODO: lang attribute */
00222                             tmp = get_node(tmp->children,"Text");
00223                             if (tmp != NULL && tmp->children != NULL) {
00224                                    zval *zv = master_to_zval(get_conversion(IS_STRING), tmp);
00225                                    faultstring = Z_STRVAL_P(zv);
00226                                    FREE_ZVAL(zv);
00227                             }
00228                      }
00229 
00230                      tmp = get_node(fault->children,"Detail");
00231                      if (tmp != NULL) {
00232                             details = master_to_zval(NULL, tmp);
00233                      }
00234               }
00235               add_soap_fault(this_ptr, faultcode, faultstring, faultactor, details TSRMLS_CC);
00236               if (faultstring) {
00237                      efree(faultstring);
00238               }
00239               if (faultactor) {
00240                      efree(faultactor);
00241               }
00242 #ifdef ZEND_ENGINE_2
00243               if (details) {
00244                      Z_DELREF_P(details);
00245               }
00246 #endif
00247               xmlFreeDoc(response);
00248               return FALSE;
00249        }
00250 
00251        /* Parse content of <Body> element */
00252        array_init(return_value);
00253        resp = body->children;
00254        while (resp != NULL && resp->type != XML_ELEMENT_NODE) {
00255               resp = resp->next;
00256        }
00257        if (resp != NULL) {
00258               if (fn != NULL && fn->binding && fn->binding->bindingType == BINDING_SOAP) {
00259                 /* Function has WSDL description */
00260                      sdlParamPtr *h_param, param = NULL;
00261                      xmlNodePtr val = NULL;
00262                      char *name, *ns = NULL;
00263                      zval* tmp;
00264                      sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes;
00265                      int res_count;
00266 
00267                      hdrs = fnb->output.headers;
00268 
00269                      if (fn->responseParameters) {
00270                        res_count = zend_hash_num_elements(fn->responseParameters);
00271                             zend_hash_internal_pointer_reset(fn->responseParameters);
00272                             while (zend_hash_get_current_data(fn->responseParameters, (void **)&h_param) == SUCCESS) {
00273                                    param = (*h_param);
00274                                    if (fnb->style == SOAP_DOCUMENT) {
00275                                           if (param->element) {
00276                                                  name = param->element->name;
00277                                                  ns = param->element->namens;
00278 /*
00279                                                  name = param->encode->details.type_str;
00280                                                  ns = param->encode->details.ns;
00281 */
00282                                           } else {
00283                                                  name = param->paramName;
00284                                           }
00285                                    } else {
00286                                           name = fn->responseName;
00287                                           /* ns = ? */
00288                                    }
00289 
00290                                    /* Get value of parameter */
00291                                    cur = get_node_ex(resp, name, ns);
00292                                    if (!cur) {
00293                                           cur = get_node(resp, name);
00294                                           /* TODO: produce warning invalid ns */
00295                                    }
00296                                    if (!cur && fnb->style == SOAP_RPC) {
00297                                      cur = resp;
00298                                    }
00299                                    if (cur) {
00300                                           if (fnb->style == SOAP_DOCUMENT) {
00301                                                  val = cur;
00302                                           } else {
00303                                                  val = get_node(cur->children, param->paramName);
00304                                                  if (res_count == 1) {
00305                                                         if (val == NULL) {
00306                                                                val = get_node(cur->children, "return");
00307                                                         }
00308                                                         if (val == NULL) {
00309                                                                val = get_node(cur->children, "result");
00310                                                         }
00311                                                         if (val == NULL && cur->children && cur->children->next == NULL) {
00312                                                                val = cur->children;                                                    
00313                                                         }
00314                                                  }
00315                                           }
00316                                    }
00317 
00318                                    if (!val) {
00319                                           /* TODO: may be "nil" is not OK? */
00320                                           MAKE_STD_ZVAL(tmp);
00321                                           ZVAL_NULL(tmp);
00322 /*
00323                                           add_soap_fault(this_ptr, "Client", "Can't find response data", NULL, NULL TSRMLS_CC);
00324                                           xmlFreeDoc(response);
00325                                           return FALSE;
00326 */
00327                                    } else {
00328                                           /* Decoding value of parameter */
00329                                           if (param != NULL) {
00330                                                  tmp = master_to_zval(param->encode, val);
00331                                           } else {
00332                                                  tmp = master_to_zval(NULL, val);
00333                                           }
00334                                    }
00335                                    add_assoc_zval(return_value, param->paramName, tmp);
00336 
00337                                    param_count++;
00338 
00339                                    zend_hash_move_forward(fn->responseParameters);
00340                             }
00341                      }
00342               } else {
00343                 /* Function has no WSDL description */
00344                      xmlNodePtr val;
00345                      val = resp->children;
00346                      while (val != NULL) {
00347                             while (val && val->type != XML_ELEMENT_NODE) {
00348                                    val = val->next;
00349                             }
00350                             if (val != NULL) {
00351                                    if (!node_is_equal_ex(val,"result",RPC_SOAP12_NAMESPACE)) {
00352                                           zval *tmp;
00353                                           zval **arr;
00354 
00355                                           tmp = master_to_zval(NULL, val);
00356                                           if (val->name) {
00357                                                  if (zend_hash_find(Z_ARRVAL_P(return_value), (char*)val->name, strlen((char*)val->name)+1, (void**)&arr) == SUCCESS) {
00358                                                         add_next_index_zval(*arr, tmp);
00359                                                  } else if (val->next && get_node(val->next, (char*)val->name)) {
00360                                                         zval *arr;
00361 
00362                                                         MAKE_STD_ZVAL(arr);
00363                                                         array_init(arr);
00364                                                         add_next_index_zval(arr, tmp);
00365                                                         add_assoc_zval(return_value, (char*)val->name, arr);
00366                                                  } else {
00367                                                         add_assoc_zval(return_value, (char*)val->name, tmp);
00368                                                  }
00369                                           } else {
00370                                                  add_next_index_zval(return_value, tmp);
00371                                           }
00372                                           ++param_count;
00373                                    }
00374                                    val = val->next;
00375                             }
00376                      }
00377               }
00378        }
00379 
00380        if (Z_TYPE_P(return_value) == IS_ARRAY) {
00381               if (param_count == 0) {
00382                      zval_dtor(return_value);
00383                      ZVAL_NULL(return_value);
00384               } else if (param_count == 1) {
00385                      zval *tmp;
00386 
00387                      zend_hash_internal_pointer_reset(Z_ARRVAL_P(return_value));
00388                      zend_hash_get_current_data(Z_ARRVAL_P(return_value), (void**)&tmp);
00389                      tmp = *(zval**)tmp;
00390                      Z_ADDREF_P(tmp);
00391                      zval_dtor(return_value);
00392                      *return_value = *tmp;
00393                      FREE_ZVAL(tmp);
00394               }
00395        }
00396 
00397        if (soap_headers && head) {
00398               trav = head->children;
00399               while (trav != NULL) {
00400                      if (trav->type == XML_ELEMENT_NODE) {
00401                             encodePtr enc = NULL;
00402                             zval* val;
00403 
00404                             if (hdrs) {
00405                                    smart_str key = {0};
00406                                    sdlSoapBindingFunctionHeaderPtr *hdr;
00407 
00408                                    if (trav->ns) {
00409                                           smart_str_appends(&key, (char*)trav->ns->href);
00410                                           smart_str_appendc(&key,':');
00411                                    }
00412                                    smart_str_appends(&key, (char*)trav->name);
00413                                    smart_str_0(&key);
00414                                    if (zend_hash_find(hdrs, key.c, key.len+1, (void**)&hdr) == SUCCESS) {
00415                                           enc = (*hdr)->encode;
00416                                    }
00417                                    smart_str_free(&key);
00418                             }
00419                             val = master_to_zval(enc, trav);
00420                             add_assoc_zval(soap_headers, (char*)trav->name, val);
00421                      }
00422                      trav = trav->next;
00423               }
00424        }
00425 
00426        xmlFreeDoc(response);
00427        return TRUE;
00428 }