ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
nusoap.php File Reference

Go to the source code of this file.

Data Structures

class  nusoap_base
 nusoap_base More...
 
class  nusoap_fault
 Contains information for a SOAP fault. More...
 
class  soap_fault
 soap_fault class, allows for creation of faults mainly used for returning faults from deployed functions in a server instance. More...
 
class  nusoap_xmlschema
 parses an XML Schema, allows access to it's data, other utility methods. More...
 
class  XMLSchema
 parses an XML Schema, allows access to it's data, other utility methods no validation... More...
 
class  soapval
 for creating serializable abstractions of native PHP types NOTE: this is only really used when WSDL is not available. More...
 
class  soap_transport_http
 transport class for sending/receiving data via HTTP and HTTPS NOTE: PHP must be compiled with the CURL extension for HTTPS support More...
 
class  nusoap_server
 nusoap_server allows the user to create a SOAP server that is capable of receiving messages and returning responses More...
 
class  soap_server
 soap_server allows the user to create a SOAP server that is capable of receiving messages and returning responses More...
 
class  wsdl
 parses a WSDL file, allows access to it's data, other utility methods More...
 
class  nusoap_parser
 nusoap_parser class parses SOAP XML messages into native PHP values More...
 
class  soap_parser
 soap_parser class parses SOAP XML messages into native PHP values More...
 
class  nusoap_client
 [nu]soapclient higher level class for easy usage. More...
 

Functions

 timestamp_to_iso8601 ($timestamp, $utc=true)
 convert unix timestamp to ISO 8601 compliant date string More...
 
 iso8601_to_timestamp ($datestr)
 convert ISO 8601 compliant date string to unix timestamp More...
 
 usleepWindows ($usec)
 sleeps some number of microseconds More...
 

Variables

if(!isset($GLOBALS['_transient'])||!isset($GLOBALS['_transient']['static'])||!isset($GLOBALS['_transient']['static']['nusoap_base'])||!is_object($GLOBALS['_transient']['static']['nusoap_base'])) $GLOBALS [ '_transient'][ 'static'][ 'nusoap_base'] globalDebugLevel = 0
 

Function Documentation

◆ iso8601_to_timestamp()

iso8601_to_timestamp (   $datestr)

convert ISO 8601 compliant date string to unix timestamp

Parameters
string$datestrISO 8601 compliant date string public

Definition at line 943 of file nusoap.php.

943  {
944  $pattern = '/'.
945  '([0-9]{4})-'. // centuries & years CCYY-
946  '([0-9]{2})-'. // months MM-
947  '([0-9]{2})'. // days DD
948  'T'. // separator T
949  '([0-9]{2}):'. // hours hh:
950  '([0-9]{2}):'. // minutes mm:
951  '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
952  '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
953  '/';
954 
955  if(preg_match($pattern,$datestr,$regs)){
956  // not utc
957  if($regs[8] != 'Z'){
958  $op = substr($regs[8],0,1);
959  $h = substr($regs[8],1,2);
960  $m = substr($regs[8],strlen($regs[8])-2,2);
961  if($op == '-'){
962  $regs[4] = $regs[4] + $h;
963  $regs[5] = $regs[5] + $m;
964  } elseif($op == '+'){
965  $regs[4] = $regs[4] - $h;
966  $regs[5] = $regs[5] - $m;
967  }
968  }
969  return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
970 // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
971  } else {
972  return false;
973  }
974 }

◆ timestamp_to_iso8601()

timestamp_to_iso8601 (   $timestamp,
  $utc = true 
)

convert unix timestamp to ISO 8601 compliant date string

Parameters
string$timestampUnix time stamp
boolean$utcWhether the time stamp is UTC or local public

Definition at line 914 of file nusoap.php.

References $timestamp.

914  {
915  $datestr = date('Y-m-d\TH:i:sO',$timestamp);
916  if($utc){
917  $pattern = '/'.
918  '([0-9]{4})-'. // centuries & years CCYY-
919  '([0-9]{2})-'. // months MM-
920  '([0-9]{2})'. // days DD
921  'T'. // separator T
922  '([0-9]{2}):'. // hours hh:
923  '([0-9]{2}):'. // minutes mm:
924  '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
925  '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
926  '/';
927 
928  if(preg_match($pattern,$datestr,$regs)){
929  return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
930  }
931  return false;
932  } else {
933  return $datestr;
934  }
935 }
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:81

◆ usleepWindows()

usleepWindows (   $usec)

sleeps some number of microseconds

Parameters
string$usecthe number of microseconds to sleep public
Deprecated:

For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.

Definition at line 983 of file nusoap.php.

984 {
985  $start = gettimeofday();
986 
987  do
988  {
989  $stop = gettimeofday();
990  $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
991  + $stop['usec'] - $start['usec'];
992  }
993  while ($timePassed < $usec);
994 }
995 
996 ?><?php
997 
998 
999 
1008 class nusoap_fault extends nusoap_base {
1014  var $faultcode;
1020  var $faultactor;
1026  var $faultstring;
1032  var $faultdetail;
1033 
1042  function __construct($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
1044  $this->faultcode = $faultcode;
1045  $this->faultactor = $faultactor;
1046  $this->faultstring = $faultstring;
1047  $this->faultdetail = $faultdetail;
1048  }
1049 
1056  function serialize(){
1057  $ns_string = '';
1058  foreach($this->namespaces as $k => $v){
1059  $ns_string .= "\n xmlns:$k=\"$v\"";
1060  }
1061  $return_msg =
1062  '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
1063  '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
1064  '<SOAP-ENV:Body>'.
1065  '<SOAP-ENV:Fault>'.
1066  $this->serialize_val($this->faultcode, 'faultcode').
1067  $this->serialize_val($this->faultstring, 'faultstring').
1068  $this->serialize_val($this->faultactor, 'faultactor').
1069  $this->serialize_val($this->faultdetail, 'detail').
1070  '</SOAP-ENV:Fault>'.
1071  '</SOAP-ENV:Body>'.
1072  '</SOAP-ENV:Envelope>';
1073  return $return_msg;
1074  }
1075 }
1076 
1080 class soap_fault extends nusoap_fault {
1081 }
1082 
1083 ?><?php
1084 
1085 
1086 
1096 class nusoap_xmlschema extends nusoap_base {
1097 
1098  // files
1099  var $schema = '';
1100  var $xml = '';
1101  // namespaces
1102  var $enclosingNamespaces;
1103  // schema info
1104  var $schemaInfo = array();
1105  var $schemaTargetNamespace = '';
1106  // types, elements, attributes defined by the schema
1107  var $attributes = array();
1108  var $complexTypes = array();
1109  var $complexTypeStack = array();
1110  var $currentComplexType = null;
1111  var $elements = array();
1112  var $elementStack = array();
1113  var $currentElement = null;
1114  var $simpleTypes = array();
1115  var $simpleTypeStack = array();
1116  var $currentSimpleType = null;
1117  // imports
1118  var $imports = array();
1119  // parser vars
1120  var $parser;
1121  var $position = 0;
1122  var $depth = 0;
1123  var $depth_array = array();
1124  var $message = array();
1125  var $defaultNamespace = array();
1126 
1135  function __construct($schema='',$xml='',$namespaces=array()){
1137  $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1138  // files
1139  $this->schema = $schema;
1140  $this->xml = $xml;
1141 
1142  // namespaces
1143  $this->enclosingNamespaces = $namespaces;
1144  $this->namespaces = array_merge($this->namespaces, $namespaces);
1145 
1146  // parse schema file
1147  if($schema != ''){
1148  $this->debug('initial schema file: '.$schema);
1149  $this->parseFile($schema, 'schema');
1150  }
1151 
1152  // parse xml file
1153  if($xml != ''){
1154  $this->debug('initial xml file: '.$xml);
1155  $this->parseFile($xml, 'xml');
1156  }
1157 
1158  }
1159 
1168  function parseFile($xml,$type){
1169  // parse xml file
1170  if($xml != ""){
1171  $xmlStr = @join("",@file($xml));
1172  if($xmlStr == ""){
1173  $msg = 'Error reading XML from '.$xml;
1174  $this->setError($msg);
1175  $this->debug($msg);
1176  return false;
1177  } else {
1178  $this->debug("parsing $xml");
1179  $this->parseString($xmlStr,$type);
1180  $this->debug("done parsing $xml");
1181  return true;
1182  }
1183  }
1184  return false;
1185  }
1186 
1194  function parseString($xml,$type){
1195  // parse xml string
1196  if($xml != ""){
1197 
1198  // Create an XML parser.
1199  $this->parser = xml_parser_create();
1200  // Set the options for parsing the XML data.
1201  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1202 
1203  // Set the object for the parser.
1204  xml_set_object($this->parser, $this);
1205 
1206  // Set the element handlers for the parser.
1207  if($type == "schema"){
1208  xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
1209  xml_set_character_data_handler($this->parser,'schemaCharacterData');
1210  } elseif($type == "xml"){
1211  xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
1212  xml_set_character_data_handler($this->parser,'xmlCharacterData');
1213  }
1214 
1215  // Parse the XML file.
1216  if(!xml_parse($this->parser,$xml,true)){
1217  // Display an error message.
1218  $errstr = sprintf('XML error parsing XML schema on line %d: %s',
1219  xml_get_current_line_number($this->parser),
1220  xml_error_string(xml_get_error_code($this->parser))
1221  );
1222  $this->debug($errstr);
1223  $this->debug("XML payload:\n" . $xml);
1224  $this->setError($errstr);
1225  }
1226 
1227  xml_parser_free($this->parser);
1228  } else{
1229  $this->debug('no xml passed to parseString()!!');
1230  $this->setError('no xml passed to parseString()!!');
1231  }
1232  }
1233 
1241  function CreateTypeName($ename) {
1242  $scope = '';
1243  for ($i = 0; $i < count($this->complexTypeStack); $i++) {
1244  $scope .= $this->complexTypeStack[$i] . '_';
1245  }
1246  return $scope . $ename . '_ContainedType';
1247  }
1248 
1257  function schemaStartElement($parser, $name, $attrs) {
1258 
1259  // position in the total number of elements, starting from 0
1260  $pos = $this->position++;
1261  $depth = $this->depth++;
1262  // set self as current value for this depth
1263  $this->depth_array[$depth] = $pos;
1264  $this->message[$pos] = array('cdata' => '');
1265  if ($depth > 0) {
1266  $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1267  } else {
1268  $this->defaultNamespace[$pos] = false;
1269  }
1270 
1271  // get element prefix
1272  if($prefix = $this->getPrefix($name)){
1273  // get unqualified name
1274  $name = $this->getLocalPart($name);
1275  } else {
1276  $prefix = '';
1277  }
1278 
1279  // loop thru attributes, expanding, and registering namespace declarations
1280  if(count($attrs) > 0){
1281  foreach($attrs as $k => $v){
1282  // if ns declarations, add to class level array of valid namespaces
1283  if(preg_match('/^xmlns/',$k)){
1284  //$this->xdebug("$k: $v");
1285  //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1286  if($ns_prefix = substr(strrchr($k,':'),1)){
1287  //$this->xdebug("Add namespace[$ns_prefix] = $v");
1288  $this->namespaces[$ns_prefix] = $v;
1289  } else {
1290  $this->defaultNamespace[$pos] = $v;
1291  if (! $this->getPrefixFromNamespace($v)) {
1292  $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
1293  }
1294  }
1295  if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
1296  $this->XMLSchemaVersion = $v;
1297  $this->namespaces['xsi'] = $v.'-instance';
1298  }
1299  }
1300  }
1301  foreach($attrs as $k => $v){
1302  // expand each attribute
1303  $k = strpos($k,':') ? $this->expandQname($k) : $k;
1304  $v = strpos($v,':') ? $this->expandQname($v) : $v;
1305  $eAttrs[$k] = $v;
1306  }
1307  $attrs = $eAttrs;
1308  } else {
1309  $attrs = array();
1310  }
1311  // find status, register data
1312  switch($name){
1313  case 'all': // (optional) compositor content for a complexType
1314  case 'choice':
1315  case 'group':
1316  case 'sequence':
1317  //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1318  $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1319  //if($name == 'all' || $name == 'sequence'){
1320  // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1321  //}
1322  break;
1323  case 'attribute': // complexType attribute
1324  //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1325  $this->xdebug("parsing attribute:");
1326  $this->appendDebug($this->varDump($attrs));
1327  if (!isset($attrs['form'])) {
1328  $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1329  }
1330  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1331  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1332  if (!strpos($v, ':')) {
1333  // no namespace in arrayType attribute value...
1334  if ($this->defaultNamespace[$pos]) {
1335  // ...so use the default
1336  $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1337  }
1338  }
1339  }
1340  if(isset($attrs['name'])){
1341  $this->attributes[$attrs['name']] = $attrs;
1342  $aname = $attrs['name'];
1343  } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
1344  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1345  $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1346  } else {
1347  $aname = '';
1348  }
1349  } elseif(isset($attrs['ref'])){
1350  $aname = $attrs['ref'];
1351  $this->attributes[$attrs['ref']] = $attrs;
1352  }
1353 
1354  if($this->currentComplexType){ // This should *always* be
1355  $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1356  }
1357  // arrayType attribute
1358  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
1359  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1360  $prefix = $this->getPrefix($aname);
1361  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
1362  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1363  } else {
1364  $v = '';
1365  }
1366  if(strpos($v,'[,]')){
1367  $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1368  }
1369  $v = substr($v,0,strpos($v,'[')); // clip the []
1370  if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
1371  $v = $this->XMLSchemaVersion.':'.$v;
1372  }
1373  $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1374  }
1375  break;
1376  case 'complexContent': // (optional) content for a complexType
1377  break;
1378  case 'complexType':
1379  array_push($this->complexTypeStack, $this->currentComplexType);
1380  if(isset($attrs['name'])){
1381  // TODO: what is the scope of named complexTypes that appear
1382  // nested within other c complexTypes?
1383  $this->xdebug('processing named complexType '.$attrs['name']);
1384  //$this->currentElement = false;
1385  $this->currentComplexType = $attrs['name'];
1386  $this->complexTypes[$this->currentComplexType] = $attrs;
1387  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1388  // This is for constructs like
1389  // <complexType name="ListOfString" base="soap:Array">
1390  // <sequence>
1391  // <element name="string" type="xsd:string"
1392  // minOccurs="0" maxOccurs="unbounded" />
1393  // </sequence>
1394  // </complexType>
1395  if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
1396  $this->xdebug('complexType is unusual array');
1397  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1398  } else {
1399  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1400  }
1401  } else {
1402  $name = $this->CreateTypeName($this->currentElement);
1403  $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
1404  $this->currentComplexType = $name;
1405  //$this->currentElement = false;
1406  $this->complexTypes[$this->currentComplexType] = $attrs;
1407  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1408  // This is for constructs like
1409  // <complexType name="ListOfString" base="soap:Array">
1410  // <sequence>
1411  // <element name="string" type="xsd:string"
1412  // minOccurs="0" maxOccurs="unbounded" />
1413  // </sequence>
1414  // </complexType>
1415  if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
1416  $this->xdebug('complexType is unusual array');
1417  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1418  } else {
1419  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1420  }
1421  }
1422  break;
1423  case 'element':
1424  array_push($this->elementStack, $this->currentElement);
1425  if (!isset($attrs['form'])) {
1426  $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1427  }
1428  if(isset($attrs['type'])){
1429  $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
1430  if (! $this->getPrefix($attrs['type'])) {
1431  if ($this->defaultNamespace[$pos]) {
1432  $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1433  $this->xdebug('used default namespace to make type ' . $attrs['type']);
1434  }
1435  }
1436  // This is for constructs like
1437  // <complexType name="ListOfString" base="soap:Array">
1438  // <sequence>
1439  // <element name="string" type="xsd:string"
1440  // minOccurs="0" maxOccurs="unbounded" />
1441  // </sequence>
1442  // </complexType>
1443  if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
1444  $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1445  $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1446  }
1447  $this->currentElement = $attrs['name'];
1448  $ename = $attrs['name'];
1449  } elseif(isset($attrs['ref'])){
1450  $this->xdebug("processing element as ref to ".$attrs['ref']);
1451  $this->currentElement = "ref to ".$attrs['ref'];
1452  $ename = $this->getLocalPart($attrs['ref']);
1453  } else {
1454  $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
1455  $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
1456  $this->currentElement = $attrs['name'];
1457  $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
1458  $ename = $attrs['name'];
1459  }
1460  if (isset($ename) && $this->currentComplexType) {
1461  $this->xdebug("add element $ename to complexType $this->currentComplexType");
1462  $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1463  } elseif (!isset($attrs['ref'])) {
1464  $this->xdebug("add element $ename to elements array");
1465  $this->elements[ $attrs['name'] ] = $attrs;
1466  $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1467  }
1468  break;
1469  case 'enumeration': // restriction value list member
1470  $this->xdebug('enumeration ' . $attrs['value']);
1471  if ($this->currentSimpleType) {
1472  $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1473  } elseif ($this->currentComplexType) {
1474  $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1475  }
1476  break;
1477  case 'extension': // simpleContent or complexContent type extension
1478  $this->xdebug('extension ' . $attrs['base']);
1479  if ($this->currentComplexType) {
1480  $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1481  }
1482  break;
1483  case 'import':
1484  if (isset($attrs['schemaLocation'])) {
1485  //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1486  $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1487  } else {
1488  //$this->xdebug('import namespace ' . $attrs['namespace']);
1489  $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1490  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
1491  $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
1492  }
1493  }
1494  break;
1495  case 'list': // simpleType value list
1496  break;
1497  case 'restriction': // simpleType, simpleContent or complexContent value restriction
1498  $this->xdebug('restriction ' . $attrs['base']);
1499  if($this->currentSimpleType){
1500  $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1501  } elseif($this->currentComplexType){
1502  $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1503  if(strstr($attrs['base'],':') == ':Array'){
1504  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1505  }
1506  }
1507  break;
1508  case 'schema':
1509  $this->schemaInfo = $attrs;
1510  $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1511  if (isset($attrs['targetNamespace'])) {
1512  $this->schemaTargetNamespace = $attrs['targetNamespace'];
1513  }
1514  if (!isset($attrs['elementFormDefault'])) {
1515  $this->schemaInfo['elementFormDefault'] = 'unqualified';
1516  }
1517  if (!isset($attrs['attributeFormDefault'])) {
1518  $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1519  }
1520  break;
1521  case 'simpleContent': // (optional) content for a complexType
1522  break;
1523  case 'simpleType':
1524  array_push($this->simpleTypeStack, $this->currentSimpleType);
1525  if(isset($attrs['name'])){
1526  $this->xdebug("processing simpleType for name " . $attrs['name']);
1527  $this->currentSimpleType = $attrs['name'];
1528  $this->simpleTypes[ $attrs['name'] ] = $attrs;
1529  $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1530  $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1531  } else {
1532  $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
1533  $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
1534  $this->currentSimpleType = $name;
1535  //$this->currentElement = false;
1536  $this->simpleTypes[$this->currentSimpleType] = $attrs;
1537  $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1538  }
1539  break;
1540  case 'union': // simpleType type list
1541  break;
1542  default:
1543  //$this->xdebug("do not have anything to do for element $name");
1544  }
1545  }
1546 
1554  function schemaEndElement($parser, $name) {
1555  // bring depth down a notch
1556  $this->depth--;
1557  // position of current element is equal to the last value left in depth_array for my depth
1558  if(isset($this->depth_array[$this->depth])){
1559  $pos = $this->depth_array[$this->depth];
1560  }
1561  // get element prefix
1562  if ($prefix = $this->getPrefix($name)){
1563  // get unqualified name
1564  $name = $this->getLocalPart($name);
1565  } else {
1566  $prefix = '';
1567  }
1568  // move on...
1569  if($name == 'complexType'){
1570  $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
1571  $this->currentComplexType = array_pop($this->complexTypeStack);
1572  //$this->currentElement = false;
1573  }
1574  if($name == 'element'){
1575  $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
1576  $this->currentElement = array_pop($this->elementStack);
1577  }
1578  if($name == 'simpleType'){
1579  $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
1580  $this->currentSimpleType = array_pop($this->simpleTypeStack);
1581  }
1582  }
1583 
1591  function schemaCharacterData($parser, $data){
1592  $pos = $this->depth_array[$this->depth - 1];
1593  $this->message[$pos]['cdata'] .= $data;
1594  }
1595 
1601  function serializeSchema(){
1602 
1603  $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1604  $xml = '';
1605  // imports
1606  if (sizeof($this->imports) > 0) {
1607  foreach($this->imports as $ns => $list) {
1608  foreach ($list as $ii) {
1609  if ($ii['location'] != '') {
1610  $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1611  } else {
1612  $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1613  }
1614  }
1615  }
1616  }
1617  // complex types
1618  foreach($this->complexTypes as $typeName => $attrs){
1619  $contentStr = '';
1620  // serialize child elements
1621  if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
1622  foreach($attrs['elements'] as $element => $eParts){
1623  if(isset($eParts['ref'])){
1624  $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
1625  } else {
1626  $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
1627  foreach ($eParts as $aName => $aValue) {
1628  // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1629  if ($aName != 'name' && $aName != 'type') {
1630  $contentStr .= " $aName=\"$aValue\"";
1631  }
1632  }
1633  $contentStr .= "/>\n";
1634  }
1635  }
1636  // compositor wraps elements
1637  if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
1638  $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n";
1639  }
1640  }
1641  // attributes
1642  if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
1643  foreach($attrs['attrs'] as $attr => $aParts){
1644  $contentStr .= " <$schemaPrefix:attribute";
1645  foreach ($aParts as $a => $v) {
1646  if ($a == 'ref' || $a == 'type') {
1647  $contentStr .= " $a=\"".$this->contractQName($v).'"';
1648  } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
1649  $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1650  $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
1651  } else {
1652  $contentStr .= " $a=\"$v\"";
1653  }
1654  }
1655  $contentStr .= "/>\n";
1656  }
1657  }
1658  // if restriction
1659  if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
1660  $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n";
1661  // complex or simple content
1662  if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
1663  $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n";
1664  }
1665  }
1666  // finalize complex type
1667  if($contentStr != ''){
1668  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
1669  } else {
1670  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1671  }
1672  $xml .= $contentStr;
1673  }
1674  // simple types
1675  if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
1676  foreach($this->simpleTypes as $typeName => $eParts){
1677  $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";
1678  if (isset($eParts['enumeration'])) {
1679  foreach ($eParts['enumeration'] as $e) {
1680  $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
1681  }
1682  }
1683  $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
1684  }
1685  }
1686  // elements
1687  if(isset($this->elements) && count($this->elements) > 0){
1688  foreach($this->elements as $element => $eParts){
1689  $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
1690  }
1691  }
1692  // attributes
1693  if(isset($this->attributes) && count($this->attributes) > 0){
1694  foreach($this->attributes as $attr => $aParts){
1695  $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
1696  }
1697  }
1698  // finish 'er up
1699  $attr = '';
1700  foreach ($this->schemaInfo as $k => $v) {
1701  if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
1702  $attr .= " $k=\"$v\"";
1703  }
1704  }
1705  $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
1706  foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1707  $el .= " xmlns:$nsp=\"$ns\"";
1708  }
1709  $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
1710  return $xml;
1711  }
1712 
1719  function xdebug($string){
1720  $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
1721  }
1722 
1735  function getPHPType($type,$ns){
1736  if(isset($this->typemap[$ns][$type])){
1737  //print "found type '$type' and ns $ns in typemap<br>";
1738  return $this->typemap[$ns][$type];
1739  } elseif(isset($this->complexTypes[$type])){
1740  //print "getting type '$type' and ns $ns from complexTypes array<br>";
1741  return $this->complexTypes[$type]['phpType'];
1742  }
1743  return false;
1744  }
1745 
1768  function getTypeDef($type){
1769  //$this->debug("in getTypeDef for type $type");
1770  if (substr($type, -1) == '^') {
1771  $is_element = 1;
1772  $type = substr($type, 0, -1);
1773  } else {
1774  $is_element = 0;
1775  }
1776 
1777  if((! $is_element) && isset($this->complexTypes[$type])){
1778  $this->xdebug("in getTypeDef, found complexType $type");
1779  return $this->complexTypes[$type];
1780  } elseif((! $is_element) && isset($this->simpleTypes[$type])){
1781  $this->xdebug("in getTypeDef, found simpleType $type");
1782  if (!isset($this->simpleTypes[$type]['phpType'])) {
1783  // get info for type to tack onto the simple type
1784  // TODO: can this ever really apply (i.e. what is a simpleType really?)
1785  $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1786  $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1787  $etype = $this->getTypeDef($uqType);
1788  if ($etype) {
1789  $this->xdebug("in getTypeDef, found type for simpleType $type:");
1790  $this->xdebug($this->varDump($etype));
1791  if (isset($etype['phpType'])) {
1792  $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1793  }
1794  if (isset($etype['elements'])) {
1795  $this->simpleTypes[$type]['elements'] = $etype['elements'];
1796  }
1797  }
1798  }
1799  return $this->simpleTypes[$type];
1800  } elseif(isset($this->elements[$type])){
1801  $this->xdebug("in getTypeDef, found element $type");
1802  if (!isset($this->elements[$type]['phpType'])) {
1803  // get info for type to tack onto the element
1804  $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1805  $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1806  $etype = $this->getTypeDef($uqType);
1807  if ($etype) {
1808  $this->xdebug("in getTypeDef, found type for element $type:");
1809  $this->xdebug($this->varDump($etype));
1810  if (isset($etype['phpType'])) {
1811  $this->elements[$type]['phpType'] = $etype['phpType'];
1812  }
1813  if (isset($etype['elements'])) {
1814  $this->elements[$type]['elements'] = $etype['elements'];
1815  }
1816  } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
1817  $this->xdebug("in getTypeDef, element $type is an XSD type");
1818  $this->elements[$type]['phpType'] = 'scalar';
1819  }
1820  }
1821  return $this->elements[$type];
1822  } elseif(isset($this->attributes[$type])){
1823  $this->xdebug("in getTypeDef, found attribute $type");
1824  return $this->attributes[$type];
1825  } elseif (preg_match('/_ContainedType$/', $type)) {
1826  $this->xdebug("in getTypeDef, have an untyped element $type");
1827  $typeDef['typeClass'] = 'simpleType';
1828  $typeDef['phpType'] = 'scalar';
1829  $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
1830  return $typeDef;
1831  }
1832  $this->xdebug("in getTypeDef, did not find $type");
1833  return false;
1834  }
1835 
1844  function serializeTypeDef($type){
1845  //print "in sTD() for type $type<br>";
1846  if($typeDef = $this->getTypeDef($type)){
1847  $str .= '<'.$type;
1848  if(is_array($typeDef['attrs'])){
1849  foreach($typeDef['attrs'] as $attName => $data){
1850  $str .= " $attName=\"{type = ".$data['type']."}\"";
1851  }
1852  }
1853  $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
1854  if(count($typeDef['elements']) > 0){
1855  $str .= ">";
1856  foreach($typeDef['elements'] as $element => $eData){
1857  $str .= $this->serializeTypeDef($element);
1858  }
1859  $str .= "</$type>";
1860  } elseif($typeDef['typeClass'] == 'element') {
1861  $str .= "></$type>";
1862  } else {
1863  $str .= "/>";
1864  }
1865  return $str;
1866  }
1867  return false;
1868  }
1869 
1880  function typeToForm($name,$type){
1881  // get typedef
1882  if($typeDef = $this->getTypeDef($type)){
1883  // if struct
1884  if($typeDef['phpType'] == 'struct'){
1885  $buffer .= '<table>';
1886  foreach($typeDef['elements'] as $child => $childDef){
1887  $buffer .= "
1888  <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
1889  <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
1890  }
1891  $buffer .= '</table>';
1892  // if array
1893  } elseif($typeDef['phpType'] == 'array'){
1894  $buffer .= '<table>';
1895  for($i=0;$i < 3; $i++){
1896  $buffer .= "
1897  <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1898  <td><input type='text' name='parameters[".$name."][]'></td></tr>";
1899  }
1900  $buffer .= '</table>';
1901  // if scalar
1902  } else {
1903  $buffer .= "<input type='text' name='parameters[$name]'>";
1904  }
1905  } else {
1906  $buffer .= "<input type='text' name='parameters[$name]'>";
1907  }
1908  return $buffer;
1909  }
1910 
1952  function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
1953  $this->complexTypes[$name] = array(
1954  'name' => $name,
1955  'typeClass' => $typeClass,
1956  'phpType' => $phpType,
1957  'compositor'=> $compositor,
1958  'restrictionBase' => $restrictionBase,
1959  'elements' => $elements,
1960  'attrs' => $attrs,
1961  'arrayType' => $arrayType
1962  );
1963 
1964  $this->xdebug("addComplexType $name:");
1965  $this->appendDebug($this->varDump($this->complexTypes[$name]));
1966  }
1967 
1980  function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
1981  $this->simpleTypes[$name] = array(
1982  'name' => $name,
1983  'typeClass' => $typeClass,
1984  'phpType' => $phpType,
1985  'type' => $restrictionBase,
1986  'enumeration' => $enumeration
1987  );
1988 
1989  $this->xdebug("addSimpleType $name:");
1990  $this->appendDebug($this->varDump($this->simpleTypes[$name]));
1991  }
1992 
2000  function addElement($attrs) {
2001  if (! $this->getPrefix($attrs['type'])) {
2002  $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
2003  }
2004  $this->elements[ $attrs['name'] ] = $attrs;
2005  $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
2006 
2007  $this->xdebug("addElement " . $attrs['name']);
2008  $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
2009  }
2010 }
2011 
2015 class XMLSchema extends nusoap_xmlschema {
2016 }
2017 
2018 ?><?php
2019 
2020 
2021 
2033 class soapval extends nusoap_base {
2040  var $name;
2047  var $type;
2054  var $value;
2061  var $element_ns;
2068  var $type_ns;
2075  var $attributes;
2076 
2088  function __construct($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
2090  $this->name = $name;
2091  $this->type = $type;
2092  $this->value = $value;
2093  $this->element_ns = $element_ns;
2094  $this->type_ns = $type_ns;
2095  $this->attributes = $attributes;
2096  }
2097 
2105  function serialize($use='encoded') {
2106  return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2107  }
2108 
2115  function decode(){
2116  return $this->value;
2117  }
2118 }
2119 
2120 
2121 
2122 ?><?php
2123 
2124 
2125 
2135 class soap_transport_http extends nusoap_base {
2136 
2137  var $url = '';
2138  var $uri = '';
2139  var $digest_uri = '';
2140  var $scheme = '';
2141  var $host = '';
2142  var $port = '';
2143  var $path = '';
2144  var $request_method = 'POST';
2145  var $protocol_version = '1.0';
2146  var $encoding = '';
2147  var $outgoing_headers = array();
2148  var $incoming_headers = array();
2149  var $incoming_cookies = array();
2150  var $outgoing_payload = '';
2151  var $incoming_payload = '';
2152  var $response_status_line; // HTTP response status line
2153  var $useSOAPAction = true;
2154  var $persistentConnection = false;
2155  var $ch = false; // cURL handle
2156  var $ch_options = array(); // cURL custom options
2157  var $use_curl = false; // force cURL use
2158  var $proxy = null; // proxy information (associative array)
2159  var $username = '';
2160  var $password = '';
2161  var $authtype = '';
2162  var $digestRequest = array();
2163  var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
2164  // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2165  // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2166  // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2167  // passphrase: SSL key password/passphrase
2168  // certpassword: SSL certificate password
2169  // verifypeer: default is 1
2170  // verifyhost: default is 1
2171 
2180  function __construct($url, $curl_options = NULL, $use_curl = false){
2182  $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
2183  $this->appendDebug($this->varDump($curl_options));
2184  $this->setURL($url);
2185  if (is_array($curl_options)) {
2186  $this->ch_options = $curl_options;
2187  }
2188  $this->use_curl = $use_curl;
2189  preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
2190  $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')');
2191  }
2192 
2200  function setCurlOption($option, $value) {
2201  $this->debug("setCurlOption option=$option, value=");
2202  $this->appendDebug($this->varDump($value));
2203  curl_setopt($this->ch, $option, $value);
2204  }
2205 
2213  function setHeader($name, $value) {
2214  $this->outgoing_headers[$name] = $value;
2215  $this->debug("set header $name: $value");
2216  }
2217 
2224  function unsetHeader($name) {
2225  if (isset($this->outgoing_headers[$name])) {
2226  $this->debug("unset header $name");
2227  unset($this->outgoing_headers[$name]);
2228  }
2229  }
2230 
2237  function setURL($url) {
2238  $this->url = $url;
2239 
2240  $u = parse_url($url);
2241  foreach($u as $k => $v){
2242  $this->debug("parsed URL $k = $v");
2243  $this->$k = $v;
2244  }
2245 
2246  // add any GET params to path
2247  if(isset($u['query']) && $u['query'] != ''){
2248  $this->path .= '?' . $u['query'];
2249  }
2250 
2251  // set default port
2252  if(!isset($u['port'])){
2253  if($u['scheme'] == 'https'){
2254  $this->port = 443;
2255  } else {
2256  $this->port = 80;
2257  }
2258  }
2259 
2260  $this->uri = $this->path;
2261  $this->digest_uri = $this->uri;
2262 
2263  // build headers
2264  if (!isset($u['port'])) {
2265  $this->setHeader('Host', $this->host);
2266  } else {
2267  $this->setHeader('Host', $this->host.':'.$this->port);
2268  }
2269 
2270  if (isset($u['user']) && $u['user'] != '') {
2271  $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2272  }
2273  }
2274 
2281  function io_method() {
2282  if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm'))
2283  return 'curl';
2284  if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm'))
2285  return 'socket';
2286  return 'unknown';
2287  }
2288 
2297  function connect($connection_timeout=0,$response_timeout=30){
2298  // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2299  // "regular" socket.
2300  // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2301  // loaded), and until PHP5 stream_get_wrappers is not available.
2302 // if ($this->scheme == 'https') {
2303 // if (version_compare(phpversion(), '4.3.0') >= 0) {
2304 // if (extension_loaded('openssl')) {
2305 // $this->scheme = 'ssl';
2306 // $this->debug('Using SSL over OpenSSL');
2307 // }
2308 // }
2309 // }
2310  $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2311  if ($this->io_method() == 'socket') {
2312  if (!is_array($this->proxy)) {
2313  $host = $this->host;
2314  $port = $this->port;
2315  } else {
2316  $host = $this->proxy['host'];
2317  $port = $this->proxy['port'];
2318  }
2319 
2320  // use persistent connection
2321  if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
2322  if (!feof($this->fp)) {
2323  $this->debug('Re-use persistent connection');
2324  return true;
2325  }
2326  fclose($this->fp);
2327  $this->debug('Closed persistent connection at EOF');
2328  }
2329 
2330  // munge host if using OpenSSL
2331  if ($this->scheme == 'ssl') {
2332  $host = 'ssl://' . $host;
2333  }
2334  $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2335 
2336  // open socket
2337  if($connection_timeout > 0){
2338  $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
2339  } else {
2340  $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
2341  }
2342 
2343  // test pointer
2344  if(!$this->fp) {
2345  $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2346  if ($this->errno) {
2347  $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
2348  } else {
2349  $msg .= ' prior to connect(). This is often a problem looking up the host name.';
2350  }
2351  $this->debug($msg);
2352  $this->setError($msg);
2353  return false;
2354  }
2355 
2356  // set response timeout
2357  $this->debug('set response timeout to ' . $response_timeout);
2358  socket_set_timeout( $this->fp, $response_timeout);
2359 
2360  $this->debug('socket connected');
2361  return true;
2362  } else if ($this->io_method() == 'curl') {
2363  if (!extension_loaded('curl')) {
2364 // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
2365  $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to included cURL.');
2366  return false;
2367  }
2368  // Avoid warnings when PHP does not have these options
2369  if (defined('CURLOPT_CONNECTIONTIMEOUT'))
2370  $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
2371  else
2372  $CURLOPT_CONNECTIONTIMEOUT = 78;
2373  if (defined('CURLOPT_HTTPAUTH'))
2374  $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
2375  else
2376  $CURLOPT_HTTPAUTH = 107;
2377  if (defined('CURLOPT_PROXYAUTH'))
2378  $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
2379  else
2380  $CURLOPT_PROXYAUTH = 111;
2381  if (defined('CURLAUTH_BASIC'))
2382  $CURLAUTH_BASIC = CURLAUTH_BASIC;
2383  else
2384  $CURLAUTH_BASIC = 1;
2385  if (defined('CURLAUTH_DIGEST'))
2386  $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
2387  else
2388  $CURLAUTH_DIGEST = 2;
2389  if (defined('CURLAUTH_NTLM'))
2390  $CURLAUTH_NTLM = CURLAUTH_NTLM;
2391  else
2392  $CURLAUTH_NTLM = 8;
2393 
2394  $this->debug('connect using cURL');
2395  // init CURL
2396  $this->ch = curl_init();
2397  // set url
2398  $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
2399  // add path
2400  $hostURL .= $this->path;
2401  $this->setCurlOption(CURLOPT_URL, $hostURL);
2402  // follow location headers (re-directs)
2403  if (ini_get('safe_mode') || ini_get('open_basedir')) {
2404  $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
2405  $this->debug('safe_mode = ');
2406  $this->appendDebug($this->varDump(ini_get('safe_mode')));
2407  $this->debug('open_basedir = ');
2408  $this->appendDebug($this->varDump(ini_get('open_basedir')));
2409  } else {
2410  $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
2411  }
2412  // ask for headers in the response output
2413  $this->setCurlOption(CURLOPT_HEADER, 1);
2414  // ask for the response output as the return value
2415  $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
2416  // encode
2417  // We manage this ourselves through headers and encoding
2418 // if(function_exists('gzuncompress')){
2419 // $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
2420 // }
2421  // persistent connection
2422  if ($this->persistentConnection) {
2423  // I believe the following comment is now bogus, having applied to
2424  // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
2425  // The way we send data, we cannot use persistent connections, since
2426  // there will be some "junk" at the end of our request.
2427  //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
2428  $this->persistentConnection = false;
2429  $this->setHeader('Connection', 'close');
2430  }
2431  // set timeouts
2432  if ($connection_timeout != 0) {
2433  $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2434  }
2435  if ($response_timeout != 0) {
2436  $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
2437  }
2438 
2439  if ($this->scheme == 'https') {
2440  $this->debug('set cURL SSL verify options');
2441  // recent versions of cURL turn on peer/host checking by default,
2442  // while PHP binaries are not compiled with a default location for the
2443  // CA cert bundle, so disable peer/host checking.
2444  //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
2445  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
2446  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
2447 
2448  // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2449  if ($this->authtype == 'certificate') {
2450  $this->debug('set cURL certificate options');
2451  if (isset($this->certRequest['cainfofile'])) {
2452  $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2453  }
2454  if (isset($this->certRequest['verifypeer'])) {
2455  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2456  } else {
2457  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
2458  }
2459  if (isset($this->certRequest['verifyhost'])) {
2460  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2461  } else {
2462  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
2463  }
2464  if (isset($this->certRequest['sslcertfile'])) {
2465  $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2466  }
2467  if (isset($this->certRequest['sslkeyfile'])) {
2468  $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2469  }
2470  if (isset($this->certRequest['passphrase'])) {
2471  $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
2472  }
2473  if (isset($this->certRequest['certpassword'])) {
2474  $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
2475  }
2476  }
2477  }
2478  if ($this->authtype && ($this->authtype != 'certificate')) {
2479  if ($this->username) {
2480  $this->debug('set cURL username/password');
2481  $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
2482  }
2483  if ($this->authtype == 'basic') {
2484  $this->debug('set cURL for Basic authentication');
2485  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
2486  }
2487  if ($this->authtype == 'digest') {
2488  $this->debug('set cURL for digest authentication');
2489  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
2490  }
2491  if ($this->authtype == 'ntlm') {
2492  $this->debug('set cURL for NTLM authentication');
2493  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
2494  }
2495  }
2496  if (is_array($this->proxy)) {
2497  $this->debug('set cURL proxy options');
2498  if ($this->proxy['port'] != '') {
2499  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']);
2500  } else {
2501  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
2502  }
2503  if ($this->proxy['username'] || $this->proxy['password']) {
2504  $this->debug('set cURL proxy authentication options');
2505  $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']);
2506  if ($this->proxy['authtype'] == 'basic') {
2507  $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
2508  }
2509  if ($this->proxy['authtype'] == 'ntlm') {
2510  $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
2511  }
2512  }
2513  }
2514  $this->debug('cURL connection set up');
2515  return true;
2516  } else {
2517  $this->setError('Unknown scheme ' . $this->scheme);
2518  $this->debug('Unknown scheme ' . $this->scheme);
2519  return false;
2520  }
2521  }
2522 
2533  function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
2534 
2535  $this->debug('entered send() with data of length: '.strlen($data));
2536 
2537  $this->tryagain = true;
2538  $tries = 0;
2539  while ($this->tryagain) {
2540  $this->tryagain = false;
2541  if ($tries++ < 2) {
2542  // make connnection
2543  if (!$this->connect($timeout, $response_timeout)){
2544  return false;
2545  }
2546 
2547  // send request
2548  if (!$this->sendRequest($data, $cookies)){
2549  return false;
2550  }
2551 
2552  // get response
2553  $respdata = $this->getResponse();
2554  } else {
2555  $this->setError("Too many tries to get an OK response ($this->response_status_line)");
2556  }
2557  }
2558  $this->debug('end of send()');
2559  return $respdata;
2560  }
2561 
2562 
2574  function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
2575  return $this->send($data, $timeout, $response_timeout, $cookies);
2576  }
2577 
2588  function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
2589  $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
2590  $this->appendDebug($this->varDump($digestRequest));
2591  $this->debug("certRequest=");
2592  $this->appendDebug($this->varDump($certRequest));
2593  // cf. RFC 2617
2594  if ($authtype == 'basic') {
2595  $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password));
2596  } elseif ($authtype == 'digest') {
2597  if (isset($digestRequest['nonce'])) {
2598  $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2599 
2600  // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2601 
2602  // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2603  $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
2604 
2605  // H(A1) = MD5(A1)
2606  $HA1 = md5($A1);
2607 
2608  // A2 = Method ":" digest-uri-value
2609  $A2 = $this->request_method . ':' . $this->digest_uri;
2610 
2611  // H(A2)
2612  $HA2 = md5($A2);
2613 
2614  // KD(secret, data) = H(concat(secret, ":", data))
2615  // if qop == auth:
2616  // request-digest = <"> < KD ( H(A1), unq(nonce-value)
2617  // ":" nc-value
2618  // ":" unq(cnonce-value)
2619  // ":" unq(qop-value)
2620  // ":" H(A2)
2621  // ) <">
2622  // if qop is missing,
2623  // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2624 
2625  $unhashedDigest = '';
2626  $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
2627  $cnonce = $nonce;
2628  if ($digestRequest['qop'] != '') {
2629  $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2630  } else {
2631  $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2632  }
2633 
2634  $hashedDigest = md5($unhashedDigest);
2635 
2636  $opaque = '';
2637  if (isset($digestRequest['opaque'])) {
2638  $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
2639  }
2640 
2641  $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"');
2642  }
2643  } elseif ($authtype == 'certificate') {
2644  $this->certRequest = $certRequest;
2645  $this->debug('Authorization header not set for certificate');
2646  } elseif ($authtype == 'ntlm') {
2647  // do nothing
2648  $this->debug('Authorization header not set for ntlm');
2649  }
2650  $this->username = $username;
2651  $this->password = $password;
2652  $this->authtype = $authtype;
2653  $this->digestRequest = $digestRequest;
2654  }
2655 
2662  function setSOAPAction($soapaction) {
2663  $this->setHeader('SOAPAction', '"' . $soapaction . '"');
2664  }
2665 
2672  function setEncoding($enc='gzip, deflate') {
2673  if (function_exists('gzdeflate')) {
2674  $this->protocol_version = '1.1';
2675  $this->setHeader('Accept-Encoding', $enc);
2676  if (!isset($this->outgoing_headers['Connection'])) {
2677  $this->setHeader('Connection', 'close');
2678  $this->persistentConnection = false;
2679  }
2680  #set_magic_quotes_runtime(0);
2681  // deprecated
2682  $this->encoding = $enc;
2683  }
2684  }
2685 
2696  function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') {
2697  if ($proxyhost) {
2698  $this->proxy = array(
2699  'host' => $proxyhost,
2700  'port' => $proxyport,
2701  'username' => $proxyusername,
2702  'password' => $proxypassword,
2703  'authtype' => $proxyauthtype
2704  );
2705  if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
2706  $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword));
2707  }
2708  } else {
2709  $this->debug('remove proxy');
2710  $proxy = null;
2711  unsetHeader('Proxy-Authorization');
2712  }
2713  }
2714 
2715 
2724  function isSkippableCurlHeader(&$data) {
2725  $skipHeaders = array( 'HTTP/1.1 100',
2726  'HTTP/1.0 301',
2727  'HTTP/1.1 301',
2728  'HTTP/1.0 302',
2729  'HTTP/1.1 302',
2730  'HTTP/1.0 401',
2731  'HTTP/1.1 401',
2732  'HTTP/1.0 200 Connection established');
2733  foreach ($skipHeaders as $hd) {
2734  $prefix = substr($data, 0, strlen($hd));
2735  if ($prefix == $hd) return true;
2736  }
2737 
2738  return false;
2739  }
2740 
2751  function decodeChunked($buffer, $lb){
2752  // length := 0
2753  $length = 0;
2754  $new = '';
2755 
2756  // read chunk-size, chunk-extension (if any) and CRLF
2757  // get the position of the linebreak
2758  $chunkend = strpos($buffer, $lb);
2759  if ($chunkend == FALSE) {
2760  $this->debug('no linebreak found in decodeChunked');
2761  return $new;
2762  }
2763  $temp = substr($buffer,0,$chunkend);
2764  $chunk_size = hexdec( trim($temp) );
2765  $chunkstart = $chunkend + strlen($lb);
2766  // while (chunk-size > 0) {
2767  while ($chunk_size > 0) {
2768  $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
2769  $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
2770 
2771  // Just in case we got a broken connection
2772  if ($chunkend == FALSE) {
2773  $chunk = substr($buffer,$chunkstart);
2774  // append chunk-data to entity-body
2775  $new .= $chunk;
2776  $length += strlen($chunk);
2777  break;
2778  }
2779 
2780  // read chunk-data and CRLF
2781  $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2782  // append chunk-data to entity-body
2783  $new .= $chunk;
2784  // length := length + chunk-size
2785  $length += strlen($chunk);
2786  // read chunk-size and CRLF
2787  $chunkstart = $chunkend + strlen($lb);
2788 
2789  $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
2790  if ($chunkend == FALSE) {
2791  break; //Just in case we got a broken connection
2792  }
2793  $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2794  $chunk_size = hexdec( trim($temp) );
2795  $chunkstart = $chunkend;
2796  }
2797  return $new;
2798  }
2799 
2808  function buildPayload($data, $cookie_str = '') {
2809  // Note: for cURL connections, $this->outgoing_payload is ignored,
2810  // as is the Content-Length header, but these are still created as
2811  // debugging guides.
2812 
2813  // add content-length header
2814  $this->setHeader('Content-Length', strlen($data));
2815 
2816  // start building outgoing payload:
2817  if ($this->proxy) {
2818  $uri = $this->url;
2819  } else {
2820  $uri = $this->uri;
2821  }
2822  $req = "$this->request_method $uri HTTP/$this->protocol_version";
2823  $this->debug("HTTP request: $req");
2824  $this->outgoing_payload = "$req\r\n";
2825 
2826  // loop thru headers, serializing
2827  foreach($this->outgoing_headers as $k => $v){
2828  $hdr = $k.': '.$v;
2829  $this->debug("HTTP header: $hdr");
2830  $this->outgoing_payload .= "$hdr\r\n";
2831  }
2832 
2833  // add any cookies
2834  if ($cookie_str != '') {
2835  $hdr = 'Cookie: '.$cookie_str;
2836  $this->debug("HTTP header: $hdr");
2837  $this->outgoing_payload .= "$hdr\r\n";
2838  }
2839 
2840  // header/body separator
2841  $this->outgoing_payload .= "\r\n";
2842 
2843  // add data
2844  $this->outgoing_payload .= $data;
2845  }
2846 
2855  function sendRequest($data, $cookies = NULL) {
2856  // build cookie string
2857  $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
2858 
2859  // build payload
2860  $this->buildPayload($data, $cookie_str);
2861 
2862  if ($this->io_method() == 'socket') {
2863  // send payload
2864  if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
2865  $this->setError('couldn\'t write message data to socket');
2866  $this->debug('couldn\'t write message data to socket');
2867  return false;
2868  }
2869  $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
2870  return true;
2871  } else if ($this->io_method() == 'curl') {
2872  // set payload
2873  // cURL does say this should only be the verb, and in fact it
2874  // turns out that the URI and HTTP version are appended to this, which
2875  // some servers refuse to work with (so we no longer use this method!)
2876  //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
2877  $curl_headers = array();
2878  foreach($this->outgoing_headers as $k => $v){
2879  if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
2880  $this->debug("Skip cURL header $k: $v");
2881  } else {
2882  $curl_headers[] = "$k: $v";
2883  }
2884  }
2885  if ($cookie_str != '') {
2886  $curl_headers[] = 'Cookie: ' . $cookie_str;
2887  }
2888  $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
2889  $this->debug('set cURL HTTP headers');
2890  if ($this->request_method == "POST") {
2891  $this->setCurlOption(CURLOPT_POST, 1);
2892  $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
2893  $this->debug('set cURL POST data');
2894  } else {
2895  }
2896  // insert custom user-set cURL options
2897  foreach ($this->ch_options as $key => $val) {
2898  $this->setCurlOption($key, $val);
2899  }
2900 
2901  $this->debug('set cURL payload');
2902  return true;
2903  }
2904  }
2905 
2912  function getResponse(){
2913  $this->incoming_payload = '';
2914 
2915  if ($this->io_method() == 'socket') {
2916  // loop until headers have been retrieved
2917  $data = '';
2918  while (!isset($lb)){
2919 
2920  // We might EOF during header read.
2921  if(feof($this->fp)) {
2922  $this->incoming_payload = $data;
2923  $this->debug('found no headers before EOF after length ' . strlen($data));
2924  $this->debug("received before EOF:\n" . $data);
2925  $this->setError('server failed to send headers');
2926  return false;
2927  }
2928 
2929  $tmp = fgets($this->fp, 256);
2930  $tmplen = strlen($tmp);
2931  $this->debug("read line of $tmplen bytes: " . trim($tmp));
2932 
2933  if ($tmplen == 0) {
2934  $this->incoming_payload = $data;
2935  $this->debug('socket read of headers timed out after length ' . strlen($data));
2936  $this->debug("read before timeout: " . $data);
2937  $this->setError('socket read of headers timed out');
2938  return false;
2939  }
2940 
2941  $data .= $tmp;
2942  $pos = strpos($data,"\r\n\r\n");
2943  if($pos > 1){
2944  $lb = "\r\n";
2945  } else {
2946  $pos = strpos($data,"\n\n");
2947  if($pos > 1){
2948  $lb = "\n";
2949  }
2950  }
2951  // remove 100 headers
2952  if (isset($lb) && preg_match('/^HTTP\/1.1 100/',$data)) {
2953  unset($lb);
2954  $data = '';
2955  }//
2956  }
2957  // store header data
2958  $this->incoming_payload .= $data;
2959  $this->debug('found end of headers after length ' . strlen($data));
2960  // process headers
2961  $header_data = trim(substr($data,0,$pos));
2962  $header_array = explode($lb,$header_data);
2963  $this->incoming_headers = array();
2964  $this->incoming_cookies = array();
2965  foreach($header_array as $header_line){
2966  $arr = explode(':',$header_line, 2);
2967  if(count($arr) > 1){
2968  $header_name = strtolower(trim($arr[0]));
2969  $this->incoming_headers[$header_name] = trim($arr[1]);
2970  if ($header_name == 'set-cookie') {
2971  // TODO: allow multiple cookies from parseCookie
2972  $cookie = $this->parseCookie(trim($arr[1]));
2973  if ($cookie) {
2974  $this->incoming_cookies[] = $cookie;
2975  $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
2976  } else {
2977  $this->debug('did not find cookie in ' . trim($arr[1]));
2978  }
2979  }
2980  } else if (isset($header_name)) {
2981  // append continuation line to previous header
2982  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
2983  }
2984  }
2985 
2986  // loop until msg has been received
2987  if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
2988  $content_length = 2147483647; // ignore any content-length header
2989  $chunked = true;
2990  $this->debug("want to read chunked content");
2991  } elseif (isset($this->incoming_headers['content-length'])) {
2992  $content_length = $this->incoming_headers['content-length'];
2993  $chunked = false;
2994  $this->debug("want to read content of length $content_length");
2995  } else {
2996  $content_length = 2147483647;
2997  $chunked = false;
2998  $this->debug("want to read content to EOF");
2999  }
3000  $data = '';
3001  do {
3002  if ($chunked) {
3003  $tmp = fgets($this->fp, 256);
3004  $tmplen = strlen($tmp);
3005  $this->debug("read chunk line of $tmplen bytes");
3006  if ($tmplen == 0) {
3007  $this->incoming_payload = $data;
3008  $this->debug('socket read of chunk length timed out after length ' . strlen($data));
3009  $this->debug("read before timeout:\n" . $data);
3010  $this->setError('socket read of chunk length timed out');
3011  return false;
3012  }
3013  $content_length = hexdec(trim($tmp));
3014  $this->debug("chunk length $content_length");
3015  }
3016  $strlen = 0;
3017  while (($strlen < $content_length) && (!feof($this->fp))) {
3018  $readlen = min(8192, $content_length - $strlen);
3019  $tmp = fread($this->fp, $readlen);
3020  $tmplen = strlen($tmp);
3021  $this->debug("read buffer of $tmplen bytes");
3022  if (($tmplen == 0) && (!feof($this->fp))) {
3023  $this->incoming_payload = $data;
3024  $this->debug('socket read of body timed out after length ' . strlen($data));
3025  $this->debug("read before timeout:\n" . $data);
3026  $this->setError('socket read of body timed out');
3027  return false;
3028  }
3029  $strlen += $tmplen;
3030  $data .= $tmp;
3031  }
3032  if ($chunked && ($content_length > 0)) {
3033  $tmp = fgets($this->fp, 256);
3034  $tmplen = strlen($tmp);
3035  $this->debug("read chunk terminator of $tmplen bytes");
3036  if ($tmplen == 0) {
3037  $this->incoming_payload = $data;
3038  $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
3039  $this->debug("read before timeout:\n" . $data);
3040  $this->setError('socket read of chunk terminator timed out');
3041  return false;
3042  }
3043  }
3044  } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
3045  if (feof($this->fp)) {
3046  $this->debug('read to EOF');
3047  }
3048  $this->debug('read body of length ' . strlen($data));
3049  $this->incoming_payload .= $data;
3050  $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
3051 
3052  // close filepointer
3053  if(
3054  (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
3055  (! $this->persistentConnection) || feof($this->fp)){
3056  fclose($this->fp);
3057  $this->fp = false;
3058  $this->debug('closed socket');
3059  }
3060 
3061  // connection was closed unexpectedly
3062  if($this->incoming_payload == ''){
3063  $this->setError('no response from server');
3064  return false;
3065  }
3066 
3067  // decode transfer-encoding
3068 // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
3069 // if(!$data = $this->decodeChunked($data, $lb)){
3070 // $this->setError('Decoding of chunked data failed');
3071 // return false;
3072 // }
3073  //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
3074  // set decoded payload
3075 // $this->incoming_payload = $header_data.$lb.$lb.$data;
3076 // }
3077 
3078  } else if ($this->io_method() == 'curl') {
3079  // send and receive
3080  $this->debug('send and receive with cURL');
3081  $this->incoming_payload = curl_exec($this->ch);
3082  $data = $this->incoming_payload;
3083 
3084  $cErr = curl_error($this->ch);
3085  if ($cErr != '') {
3086  $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
3087  // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
3088  foreach(curl_getinfo($this->ch) as $k => $v){
3089  $err .= "$k: $v<br>";
3090  }
3091  $this->debug($err);
3092  $this->setError($err);
3093  curl_close($this->ch);
3094  return false;
3095  } else {
3096  //echo '<pre>';
3097  //var_dump(curl_getinfo($this->ch));
3098  //echo '</pre>';
3099  }
3100  // close curl
3101  $this->debug('No cURL error, closing cURL');
3102  curl_close($this->ch);
3103 
3104  // try removing skippable headers
3105  $savedata = $data;
3106  while ($this->isSkippableCurlHeader($data)) {
3107  $this->debug("Found HTTP header to skip");
3108  if ($pos = strpos($data,"\r\n\r\n")) {
3109  $data = ltrim(substr($data,$pos));
3110  } elseif($pos = strpos($data,"\n\n") ) {
3111  $data = ltrim(substr($data,$pos));
3112  }
3113  }
3114 
3115  if ($data == '') {
3116  // have nothing left; just remove 100 header(s)
3117  $data = $savedata;
3118  while (preg_match('/^HTTP\/1.1 100/',$data)) {
3119  if ($pos = strpos($data,"\r\n\r\n")) {
3120  $data = ltrim(substr($data,$pos));
3121  } elseif($pos = strpos($data,"\n\n") ) {
3122  $data = ltrim(substr($data,$pos));
3123  }
3124  }
3125  }
3126 
3127  // separate content from HTTP headers
3128  if ($pos = strpos($data,"\r\n\r\n")) {
3129  $lb = "\r\n";
3130  } elseif( $pos = strpos($data,"\n\n")) {
3131  $lb = "\n";
3132  } else {
3133  $this->debug('no proper separation of headers and document');
3134  $this->setError('no proper separation of headers and document');
3135  return false;
3136  }
3137  $header_data = trim(substr($data,0,$pos));
3138  $header_array = explode($lb,$header_data);
3139  $data = ltrim(substr($data,$pos));
3140  $this->debug('found proper separation of headers and document');
3141  $this->debug('cleaned data, stringlen: '.strlen($data));
3142  // clean headers
3143  foreach ($header_array as $header_line) {
3144  $arr = explode(':',$header_line,2);
3145  if(count($arr) > 1){
3146  $header_name = strtolower(trim($arr[0]));
3147  $this->incoming_headers[$header_name] = trim($arr[1]);
3148  if ($header_name == 'set-cookie') {
3149  // TODO: allow multiple cookies from parseCookie
3150  $cookie = $this->parseCookie(trim($arr[1]));
3151  if ($cookie) {
3152  $this->incoming_cookies[] = $cookie;
3153  $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3154  } else {
3155  $this->debug('did not find cookie in ' . trim($arr[1]));
3156  }
3157  }
3158  } else if (isset($header_name)) {
3159  // append continuation line to previous header
3160  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3161  }
3162  }
3163  }
3164 
3165  $this->response_status_line = $header_array[0];
3166  $arr = explode(' ', $this->response_status_line, 3);
3167  $http_version = $arr[0];
3168  $http_status = intval($arr[1]);
3169  $http_reason = count($arr) > 2 ? $arr[2] : '';
3170 
3171  // see if we need to resend the request with http digest authentication
3172  if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
3173  $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
3174  $this->setURL($this->incoming_headers['location']);
3175  $this->tryagain = true;
3176  return false;
3177  }
3178 
3179  // see if we need to resend the request with http digest authentication
3180  if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
3181  $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
3182  if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
3183  $this->debug('Server wants digest authentication');
3184  // remove "Digest " from our elements
3185  $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
3186 
3187  // parse elements into array
3188  $digestElements = explode(',', $digestString);
3189  foreach ($digestElements as $val) {
3190  $tempElement = explode('=', trim($val), 2);
3191  $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
3192  }
3193 
3194  // should have (at least) qop, realm, nonce
3195  if (isset($digestRequest['nonce'])) {
3196  $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
3197  $this->tryagain = true;
3198  return false;
3199  }
3200  }
3201  $this->debug('HTTP authentication failed');
3202  $this->setError('HTTP authentication failed');
3203  return false;
3204  }
3205 
3206  if (
3207  ($http_status >= 300 && $http_status <= 307) ||
3208  ($http_status >= 400 && $http_status <= 417) ||
3209  ($http_status >= 501 && $http_status <= 505)
3210  ) {
3211  $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
3212  return false;
3213  }
3214 
3215  // decode content-encoding
3216  if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
3217  if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
3218  // if decoding works, use it. else assume data wasn't gzencoded
3219  if(function_exists('gzinflate')){
3220  //$timer->setMarker('starting decoding of gzip/deflated content');
3221  // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
3222  // this means there are no Zlib headers, although there should be
3223  $this->debug('The gzinflate function exists');
3224  $datalen = strlen($data);
3225  if ($this->incoming_headers['content-encoding'] == 'deflate') {
3226  if ($degzdata = @gzinflate($data)) {
3227  $data = $degzdata;
3228  $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
3229  if (strlen($data) < $datalen) {
3230  // test for the case that the payload has been compressed twice
3231  $this->debug('The inflated payload is smaller than the gzipped one; try again');
3232  if ($degzdata = @gzinflate($data)) {
3233  $data = $degzdata;
3234  $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
3235  }
3236  }
3237  } else {
3238  $this->debug('Error using gzinflate to inflate the payload');
3239  $this->setError('Error using gzinflate to inflate the payload');
3240  }
3241  } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
3242  if ($degzdata = @gzinflate(substr($data, 10))) { // do our best
3243  $data = $degzdata;
3244  $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
3245  if (strlen($data) < $datalen) {
3246  // test for the case that the payload has been compressed twice
3247  $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
3248  if ($degzdata = @gzinflate(substr($data, 10))) {
3249  $data = $degzdata;
3250  $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
3251  }
3252  }
3253  } else {
3254  $this->debug('Error using gzinflate to un-gzip the payload');
3255  $this->setError('Error using gzinflate to un-gzip the payload');
3256  }
3257  }
3258  //$timer->setMarker('finished decoding of gzip/deflated content');
3259  //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
3260  // set decoded payload
3261  $this->incoming_payload = $header_data.$lb.$lb.$data;
3262  } else {
3263  $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3264  $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3265  }
3266  } else {
3267  $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3268  $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3269  }
3270  } else {
3271  $this->debug('No Content-Encoding header');
3272  }
3273 
3274  if(strlen($data) == 0){
3275  $this->debug('no data after headers!');
3276  $this->setError('no data present after HTTP headers');
3277  return false;
3278  }
3279 
3280  return $data;
3281  }
3282 
3290  function setContentType($type, $charset = false) {
3291  $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
3292  }
3293 
3300  function usePersistentConnection(){
3301  if (isset($this->outgoing_headers['Accept-Encoding'])) {
3302  return false;
3303  }
3304  $this->protocol_version = '1.1';
3305  $this->persistentConnection = true;
3306  $this->setHeader('Connection', 'Keep-Alive');
3307  return true;
3308  }
3309 
3317  /*
3318  * TODO: allow a Set-Cookie string to be parsed into multiple cookies
3319  */
3320  function parseCookie($cookie_str) {
3321  $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
3322  $data = preg_split(';', $cookie_str);
3323  $value_str = $data[0];
3324 
3325  $cookie_param = 'domain=';
3326  $start = strpos($cookie_str, $cookie_param);
3327  if ($start > 0) {
3328  $domain = substr($cookie_str, $start + strlen($cookie_param));
3329  $domain = substr($domain, 0, strpos($domain, ';'));
3330  } else {
3331  $domain = '';
3332  }
3333 
3334  $cookie_param = 'expires=';
3335  $start = strpos($cookie_str, $cookie_param);
3336  if ($start > 0) {
3337  $expires = substr($cookie_str, $start + strlen($cookie_param));
3338  $expires = substr($expires, 0, strpos($expires, ';'));
3339  } else {
3340  $expires = '';
3341  }
3342 
3343  $cookie_param = 'path=';
3344  $start = strpos($cookie_str, $cookie_param);
3345  if ( $start > 0 ) {
3346  $path = substr($cookie_str, $start + strlen($cookie_param));
3347  $path = substr($path, 0, strpos($path, ';'));
3348  } else {
3349  $path = '/';
3350  }
3351 
3352  $cookie_param = ';secure;';
3353  if (strpos($cookie_str, $cookie_param) !== FALSE) {
3354  $secure = true;
3355  } else {
3356  $secure = false;
3357  }
3358 
3359  $sep_pos = strpos($value_str, '=');
3360 
3361  if ($sep_pos) {
3362  $name = substr($value_str, 0, $sep_pos);
3363  $value = substr($value_str, $sep_pos + 1);
3364  $cookie= array( 'name' => $name,
3365  'value' => $value,
3366  'domain' => $domain,
3367  'path' => $path,
3368  'expires' => $expires,
3369  'secure' => $secure
3370  );
3371  return $cookie;
3372  }
3373  return false;
3374  }
3375 
3384  function getCookiesForRequest($cookies, $secure=false) {
3385  $cookie_str = '';
3386  if ((! is_null($cookies)) && (is_array($cookies))) {
3387  foreach ($cookies as $cookie) {
3388  if (! is_array($cookie)) {
3389  continue;
3390  }
3391  $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
3392  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
3393  if (strtotime($cookie['expires']) <= time()) {
3394  $this->debug('cookie has expired');
3395  continue;
3396  }
3397  }
3398  if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
3399  $domain = preg_quote($cookie['domain']);
3400  if (! preg_match("'.*$domain$'i", $this->host)) {
3401  $this->debug('cookie has different domain');
3402  continue;
3403  }
3404  }
3405  if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
3406  $path = preg_quote($cookie['path']);
3407  if (! preg_match("'^$path.*'i", $this->path)) {
3408  $this->debug('cookie is for a different path');
3409  continue;
3410  }
3411  }
3412  if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
3413  $this->debug('cookie is secure, transport is not');
3414  continue;
3415  }
3416  $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3417  $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3418  }
3419  }
3420  return $cookie_str;
3421  }
3422 }
3423 
3424 ?><?php
3425 
3426 
3427 
3438 class nusoap_server extends nusoap_base {
3444  var $headers = array();
3450  var $request = '';
3456  var $requestHeaders = '';
3462  var $requestHeader = NULL;
3468  var $document = '';
3474  var $requestSOAP = '';
3480  var $methodURI = '';
3486  var $methodname = '';
3492  var $methodparams = array();
3498  var $SOAPAction = '';
3504  var $xml_encoding = '';
3510  var $decode_utf8 = true;
3511 
3517  var $outgoing_headers = array();
3523  var $response = '';
3529  var $responseHeaders = '';
3535  var $responseSOAP = '';
3541  var $methodreturn = false;
3547  var $methodreturnisliteralxml = false;
3553  var $fault = false;
3559  var $result = 'successful';
3560 
3567  var $operations = array();
3573  var $wsdl = false;
3579  var $externalWSDLURL = false;
3585  var $debug_flag = false;
3586 
3587 
3595  function __construct($wsdl=false){
3597  // turn on debugging?
3598  global $debug;
3599  global $HTTP_SERVER_VARS;
3600 
3601  if (isset($_SERVER)) {
3602  $this->debug("_SERVER is defined:");
3603  $this->appendDebug($this->varDump($_SERVER));
3604  } elseif (isset($HTTP_SERVER_VARS)) {
3605  $this->debug("HTTP_SERVER_VARS is defined:");
3606  $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
3607  } else {
3608  $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
3609  }
3610 
3611  if (isset($debug)) {
3612  $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
3613  $this->debug_flag = $debug;
3614  } elseif (isset($_SERVER['QUERY_STRING'])) {
3615  $qs = explode('&', $_SERVER['QUERY_STRING']);
3616  foreach ($qs as $v) {
3617  if (substr($v, 0, 6) == 'debug=') {
3618  $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
3619  $this->debug_flag = substr($v, 6);
3620  }
3621  }
3622  } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3623  $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
3624  foreach ($qs as $v) {
3625  if (substr($v, 0, 6) == 'debug=') {
3626  $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
3627  $this->debug_flag = substr($v, 6);
3628  }
3629  }
3630  }
3631 
3632  // wsdl
3633  if($wsdl){
3634  $this->debug("In nusoap_server, WSDL is specified");
3635  if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
3636  $this->wsdl = $wsdl;
3637  $this->externalWSDLURL = $this->wsdl->wsdl;
3638  $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3639  } else {
3640  $this->debug('Create wsdl from ' . $wsdl);
3641  $this->wsdl = new wsdl($wsdl);
3642  $this->externalWSDLURL = $wsdl;
3643  }
3644  $this->appendDebug($this->wsdl->getDebug());
3645  $this->wsdl->clearDebug();
3646  if($err = $this->wsdl->getError()){
3647  die('WSDL ERROR: '.$err);
3648  }
3649  }
3650  }
3651 
3658  function service($data){
3659  global $HTTP_SERVER_VARS;
3660 
3661  if (isset($_SERVER['QUERY_STRING'])) {
3662  $qs = $_SERVER['QUERY_STRING'];
3663  } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3664  $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3665  } else {
3666  $qs = '';
3667  }
3668  $this->debug("In service, query string=$qs");
3669 
3670  if (preg_match('/wsdl/', $qs) ){
3671  $this->debug("In service, this is a request for WSDL");
3672  if($this->externalWSDLURL){
3673  if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
3674  header('Location: '.$this->externalWSDLURL);
3675  } else { // assume file
3676  header("Content-Type: text/xml\r\n");
3677  $fp = fopen($this->externalWSDLURL, 'r');
3678  fpassthru($fp);
3679  }
3680  } elseif ($this->wsdl) {
3681  header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
3682  print $this->wsdl->serialize($this->debug_flag);
3683  if ($this->debug_flag) {
3684  $this->debug('wsdl:');
3685  $this->appendDebug($this->varDump($this->wsdl));
3686  print $this->getDebugAsXMLComment();
3687  }
3688  } else {
3689  header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3690  print "This service does not provide WSDL";
3691  }
3692  } elseif ($data == '' && $this->wsdl) {
3693  $this->debug("In service, there is no data, so return Web description");
3694  print $this->wsdl->webDescription();
3695  } else {
3696  $this->debug("In service, invoke the request");
3697  $this->parse_request($data);
3698  if (! $this->fault) {
3699  $this->invoke_method();
3700  }
3701  if (! $this->fault) {
3702  $this->serialize_return();
3703  }
3704  $this->send_response();
3705  }
3706  }
3707 
3720  function parse_http_headers() {
3721  global $HTTP_SERVER_VARS;
3722 
3723  $this->request = '';
3724  $this->SOAPAction = '';
3725  if(function_exists('getallheaders')){
3726  $this->debug("In parse_http_headers, use getallheaders");
3727  $headers = getallheaders();
3728  foreach($headers as $k=>$v){
3729  $k = strtolower($k);
3730  $this->headers[$k] = $v;
3731  $this->request .= "$k: $v\r\n";
3732  $this->debug("$k: $v");
3733  }
3734  // get SOAPAction header
3735  if(isset($this->headers['soapaction'])){
3736  $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
3737  }
3738  // get the character encoding of the incoming request
3739  if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
3740  $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
3741  if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
3742  $this->xml_encoding = strtoupper($enc);
3743  } else {
3744  $this->xml_encoding = 'US-ASCII';
3745  }
3746  } else {
3747  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3748  $this->xml_encoding = 'ISO-8859-1';
3749  }
3750  } elseif(isset($_SERVER) && is_array($_SERVER)){
3751  $this->debug("In parse_http_headers, use _SERVER");
3752  foreach ($_SERVER as $k => $v) {
3753  if (substr($k, 0, 5) == 'HTTP_') {
3754  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3755  } else {
3756  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3757  }
3758  if ($k == 'soapaction') {
3759  // get SOAPAction header
3760  $k = 'SOAPAction';
3761  $v = str_replace('"', '', $v);
3762  $v = str_replace('\\', '', $v);
3763  $this->SOAPAction = $v;
3764  } else if ($k == 'content-type') {
3765  // get the character encoding of the incoming request
3766  if (strpos($v, '=')) {
3767  $enc = substr(strstr($v, '='), 1);
3768  $enc = str_replace('"', '', $enc);
3769  $enc = str_replace('\\', '', $enc);
3770  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
3771  $this->xml_encoding = strtoupper($enc);
3772  } else {
3773  $this->xml_encoding = 'US-ASCII';
3774  }
3775  } else {
3776  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3777  $this->xml_encoding = 'ISO-8859-1';
3778  }
3779  }
3780  $this->headers[$k] = $v;
3781  $this->request .= "$k: $v\r\n";
3782  $this->debug("$k: $v");
3783  }
3784  } elseif (is_array($HTTP_SERVER_VARS)) {
3785  $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
3786  foreach ($HTTP_SERVER_VARS as $k => $v) {
3787  if (substr($k, 0, 5) == 'HTTP_') {
3788  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5));
3789  } else {
3790  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k);
3791  }
3792  if ($k == 'soapaction') {
3793  // get SOAPAction header
3794  $k = 'SOAPAction';
3795  $v = str_replace('"', '', $v);
3796  $v = str_replace('\\', '', $v);
3797  $this->SOAPAction = $v;
3798  } else if ($k == 'content-type') {
3799  // get the character encoding of the incoming request
3800  if (strpos($v, '=')) {
3801  $enc = substr(strstr($v, '='), 1);
3802  $enc = str_replace('"', '', $enc);
3803  $enc = str_replace('\\', '', $enc);
3804  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
3805  $this->xml_encoding = strtoupper($enc);
3806  } else {
3807  $this->xml_encoding = 'US-ASCII';
3808  }
3809  } else {
3810  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3811  $this->xml_encoding = 'ISO-8859-1';
3812  }
3813  }
3814  $this->headers[$k] = $v;
3815  $this->request .= "$k: $v\r\n";
3816  $this->debug("$k: $v");
3817  }
3818  } else {
3819  $this->debug("In parse_http_headers, HTTP headers not accessible");
3820  $this->setError("HTTP headers not accessible");
3821  }
3822  }
3823 
3846  function parse_request($data='') {
3847  $this->debug('entering parse_request()');
3848  $this->parse_http_headers();
3849  $this->debug('got character encoding: '.$this->xml_encoding);
3850  // uncompress if necessary
3851  if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
3852  $this->debug('got content encoding: ' . $this->headers['content-encoding']);
3853  if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
3854  // if decoding works, use it. else assume data wasn't gzencoded
3855  if (function_exists('gzuncompress')) {
3856  if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
3857  $data = $degzdata;
3858  } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
3859  $data = $degzdata;
3860  } else {
3861  $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
3862  return;
3863  }
3864  } else {
3865  $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
3866  return;
3867  }
3868  }
3869  }
3870  $this->request .= "\r\n".$data;
3871  $data = $this->parseRequest($this->headers, $data);
3872  $this->requestSOAP = $data;
3873  $this->debug('leaving parse_request');
3874  }
3875 
3893  function invoke_method() {
3894  $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
3895 
3896  if ($this->wsdl) {
3897  if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
3898  $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
3899  $this->appendDebug('opData=' . $this->varDump($this->opData));
3900  } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
3901  // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
3902  $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
3903  $this->appendDebug('opData=' . $this->varDump($this->opData));
3904  $this->methodname = $this->opData['name'];
3905  } else {
3906  $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
3907  $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
3908  return;
3909  }
3910  } else {
3911  $this->debug('in invoke_method, no WSDL to validate method');
3912  }
3913 
3914  // if a . is present in $this->methodname, we see if there is a class in scope,
3915  // which could be referred to. We will also distinguish between two deliminators,
3916  // to allow methods to be called a the class or an instance
3917  $class = '';
3918  $method = '';
3919  if (strpos($this->methodname, '..') > 0) {
3920  $delim = '..';
3921  } else if (strpos($this->methodname, '.') > 0) {
3922  $delim = '.';
3923  } else {
3924  $delim = '';
3925  }
3926 
3927  if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 &&
3928  class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
3929  // get the class and method name
3930  $class = substr($this->methodname, 0, strpos($this->methodname, $delim));
3931  $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
3932  $this->debug("in invoke_method, class=$class method=$method delim=$delim");
3933  }
3934  // set class handler
3935  // added to support single operations
3936  if ($class == '' && $this->class !='')
3937  {
3938  $class = $this->class;
3939  $delim = "..";
3940  $method = $this->methodname;
3941  }
3942 
3943  // does method exist?
3944  if ($class == '') {
3945  if (!function_exists($this->methodname)) {
3946  $this->debug("in invoke_method, function '$this->methodname' not found!");
3947  $this->result = 'fault: method not found';
3948  $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
3949  return;
3950  }
3951  } else {
3952  $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
3953  if (!in_array($method_to_compare, get_class_methods($class))) {
3954  $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
3955  $this->result = 'fault: method not found';
3956  $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
3957  return;
3958  }
3959  }
3960 
3961  // evaluate message, getting back parameters
3962  // verify that request parameters match the method's signature
3963  if(! $this->verify_method($this->methodname,$this->methodparams)){
3964  // debug
3965  $this->debug('ERROR: request not verified against method signature');
3966  $this->result = 'fault: request failed validation against method signature';
3967  // return fault
3968  $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
3969  return;
3970  }
3971 
3972  // if there are parameters to pass
3973  $this->debug('in invoke_method, params:');
3974  $this->appendDebug($this->varDump($this->methodparams));
3975  $this->debug("in invoke_method, calling '$this->methodname'");
3976  if (!function_exists('call_user_func_array')) {
3977  if ($class == '') {
3978  $this->debug('in invoke_method, calling function using eval()');
3979  $funcCall = "\$this->methodreturn = $this->methodname(";
3980  } else {
3981  if ($delim == '..') {
3982  $this->debug('in invoke_method, calling class method using eval()');
3983  $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
3984  } else {
3985  $this->debug('in invoke_method, calling instance method using eval()');
3986  // generate unique instance name
3987  $instname = "\$inst_".time();
3988  $funcCall = $instname." = new ".$class."(); ";
3989  $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
3990  }
3991  }
3992  if ($this->methodparams) {
3993  foreach ($this->methodparams as $param) {
3994  if (is_array($param) || is_object($param)) {
3995  $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
3996  return;
3997  }
3998  $funcCall .= "\"$param\",";
3999  }
4000  $funcCall = substr($funcCall, 0, -1);
4001  }
4002  $funcCall .= ');';
4003  $this->debug('in invoke_method, function call: '.$funcCall);
4004  @eval($funcCall);
4005  } else {
4006  if ($class == '') {
4007  $this->debug('in invoke_method, calling function using call_user_func_array()');
4008  $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array()
4009  } elseif ($delim == '..') {
4010  $this->debug('in invoke_method, calling class method using call_user_func_array()');
4011  $call_arg = array ($class, $method);
4012  } else {
4013  $this->debug('in invoke_method, calling instance method using call_user_func_array()');
4014  $instance = new $class ();
4015  $call_arg = array(&$instance, $method);
4016  }
4017  if (is_array($this->methodparams)) {
4018  $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
4019  } else {
4020  $this->methodreturn = call_user_func_array($call_arg, array());
4021  }
4022  }
4023  $this->debug('in invoke_method, methodreturn:');
4024  $this->appendDebug($this->varDump($this->methodreturn));
4025  $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn));
4026  }
4027 
4039  function serialize_return() {
4040  $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4041  // if fault
4042  if (isset($this->methodreturn) && ((get_class((object)$this->methodreturn) == 'soap_fault') || (get_class((object)$this->methodreturn) == 'nusoap_fault'))) {
4043  $this->debug('got a fault object from method');
4044  $this->fault = $this->methodreturn;
4045  return;
4046  } elseif ($this->methodreturnisliteralxml) {
4047  $return_val = $this->methodreturn;
4048  // returned value(s)
4049  } else {
4050  $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
4051  $this->debug('serializing return value');
4052  if($this->wsdl){
4053  if (sizeof($this->opData['output']['parts']) > 1) {
4054  $this->debug('more than one output part, so use the method return unchanged');
4055  $opParams = $this->methodreturn;
4056  } elseif (sizeof($this->opData['output']['parts']) == 1) {
4057  $this->debug('exactly one output part, so wrap the method return in a simple array');
4058  // TODO: verify that it is not already wrapped!
4059  //foreach ($this->opData['output']['parts'] as $name => $type) {
4060  // $this->debug('wrap in element named ' . $name);
4061  //}
4062  $opParams = array($this->methodreturn);
4063  }
4064  $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
4065  $this->appendDebug($this->wsdl->getDebug());
4066  $this->wsdl->clearDebug();
4067  if($errstr = $this->wsdl->getError()){
4068  $this->debug('got wsdl error: '.$errstr);
4069  $this->fault('SOAP-ENV:Server', 'unable to serialize result');
4070  return;
4071  }
4072  } else {
4073  if (isset($this->methodreturn)) {
4074  $return_val = $this->serialize_val($this->methodreturn, 'return');
4075  } else {
4076  $return_val = '';
4077  $this->debug('in absence of WSDL, assume void return for backward compatibility');
4078  }
4079  }
4080  }
4081  $this->debug('return value:');
4082  $this->appendDebug($this->varDump($return_val));
4083 
4084  $this->debug('serializing response');
4085  if ($this->wsdl) {
4086  $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
4087  if ($this->opData['style'] == 'rpc') {
4088  $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
4089  if ($this->opData['output']['use'] == 'literal') {
4090  // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
4091  $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4092  } else {
4093  $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4094  }
4095  } else {
4096  $this->debug('style is not rpc for serialization: assume document');
4097  $payload = $return_val;
4098  }
4099  } else {
4100  $this->debug('do not have WSDL for serialization: assume rpc/encoded');
4101  $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4102  }
4103  $this->result = 'successful';
4104  if($this->wsdl){
4105  //if($this->debug_flag){
4106  $this->appendDebug($this->wsdl->getDebug());
4107  // }
4108  if (isset($opData['output']['encodingStyle'])) {
4109  $encodingStyle = $opData['output']['encodingStyle'];
4110  } else {
4111  $encodingStyle = '';
4112  }
4113  // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
4114  $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle);
4115  } else {
4116  $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
4117  }
4118  $this->debug("Leaving serialize_return");
4119  }
4120 
4131  function send_response() {
4132  $this->debug('Enter send_response');
4133  if ($this->fault) {
4134  $payload = $this->fault->serialize();
4135  $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
4136  $this->outgoing_headers[] = "Status: 500 Internal Server Error";
4137  } else {
4138  $payload = $this->responseSOAP;
4139  // Some combinations of PHP+Web server allow the Status
4140  // to come through as a header. Since OK is the default
4141  // just do nothing.
4142  // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
4143  // $this->outgoing_headers[] = "Status: 200 OK";
4144  }
4145  // add debug data if in debug mode
4146  if(isset($this->debug_flag) && $this->debug_flag){
4147  $payload .= $this->getDebugAsXMLComment();
4148  }
4149  $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
4150  preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
4151  $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
4152  // Let the Web server decide about this
4153  //$this->outgoing_headers[] = "Connection: Close\r\n";
4154  $payload = $this->getHTTPBody($payload);
4155  $type = $this->getHTTPContentType();
4156  $charset = $this->getHTTPContentTypeCharset();
4157  $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
4158  //begin code to compress payload - by John
4159  // NOTE: there is no way to know whether the Web server will also compress
4160  // this data.
4161  if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
4162  if (strstr($this->headers['accept-encoding'], 'gzip')) {
4163  if (function_exists('gzencode')) {
4164  if (isset($this->debug_flag) && $this->debug_flag) {
4165  $payload .= "<!-- Content being gzipped -->";
4166  }
4167  $this->outgoing_headers[] = "Content-Encoding: gzip";
4168  $payload = gzencode($payload);
4169  } else {
4170  if (isset($this->debug_flag) && $this->debug_flag) {
4171  $payload .= "<!-- Content will not be gzipped: no gzencode -->";
4172  }
4173  }
4174  } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
4175  // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
4176  // instead of gzcompress output,
4177  // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
4178  if (function_exists('gzdeflate')) {
4179  if (isset($this->debug_flag) && $this->debug_flag) {
4180  $payload .= "<!-- Content being deflated -->";
4181  }
4182  $this->outgoing_headers[] = "Content-Encoding: deflate";
4183  $payload = gzdeflate($payload);
4184  } else {
4185  if (isset($this->debug_flag) && $this->debug_flag) {
4186  $payload .= "<!-- Content will not be deflated: no gzcompress -->";
4187  }
4188  }
4189  }
4190  }
4191  //end code
4192  $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
4193  reset($this->outgoing_headers);
4194  foreach($this->outgoing_headers as $hdr){
4195  header($hdr, false);
4196  }
4197  print $payload;
4198  $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
4199  }
4200 
4210  function verify_method($operation,$request){
4211  if(isset($this->wsdl) && is_object($this->wsdl)){
4212  if($this->wsdl->getOperationData($operation)){
4213  return true;
4214  }
4215  } elseif(isset($this->operations[$operation])){
4216  return true;
4217  }
4218  return false;
4219  }
4220 
4229  function parseRequest($headers, $data) {
4230  $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
4231  if (!strstr($headers['content-type'], 'text/xml')) {
4232  $this->setError('Request not of type text/xml');
4233  return false;
4234  }
4235  if (strpos($headers['content-type'], '=')) {
4236  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
4237  $this->debug('Got response encoding: ' . $enc);
4238  if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
4239  $this->xml_encoding = strtoupper($enc);
4240  } else {
4241  $this->xml_encoding = 'US-ASCII';
4242  }
4243  } else {
4244  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4245  $this->xml_encoding = 'ISO-8859-1';
4246  }
4247  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
4248  // parse response, get soap parser obj
4249  $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
4250  // parser debug
4251  $this->debug("parser debug: \n".$parser->getDebug());
4252  // if fault occurred during message parsing
4253  if($err = $parser->getError()){
4254  $this->result = 'fault: error in msg parsing: '.$err;
4255  $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err);
4256  // else successfully parsed request into soapval object
4257  } else {
4258  // get/set methodname
4259  $this->methodURI = $parser->root_struct_namespace;
4260  $this->methodname = $parser->root_struct_name;
4261  $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
4262  $this->debug('calling parser->get_soapbody()');
4263  $this->methodparams = $parser->get_soapbody();
4264  // get SOAP headers
4265  $this->requestHeaders = $parser->getHeaders();
4266  // get SOAP Header
4267  $this->requestHeader = $parser->get_soapheader();
4268  // add document for doclit support
4269  $this->document = $parser->document;
4270  }
4271  }
4272 
4280  function getHTTPBody($soapmsg) {
4281  return $soapmsg;
4282  }
4283 
4292  function getHTTPContentType() {
4293  return 'text/xml';
4294  }
4295 
4305  function getHTTPContentTypeCharset() {
4306  return $this->soap_defencoding;
4307  }
4308 
4318  function add_to_map($methodname,$in,$out){
4319  $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
4320  }
4321 
4336  function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){
4337  global $HTTP_SERVER_VARS;
4338 
4339  if($this->externalWSDLURL){
4340  die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
4341  }
4342  if (! $name) {
4343  die('You must specify a name when you register an operation');
4344  }
4345  if (!is_array($in)) {
4346  die('You must provide an array for operation inputs');
4347  }
4348  if (!is_array($out)) {
4349  die('You must provide an array for operation outputs');
4350  }
4351  if(false == $namespace) {
4352  }
4353  if(false == $soapaction) {
4354  if (isset($_SERVER)) {
4355  $SERVER_NAME = $_SERVER['SERVER_NAME'];
4356  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4357  $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4358  } elseif (isset($HTTP_SERVER_VARS)) {
4359  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4360  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4361  $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4362  } else {
4363  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4364  }
4365  if ($HTTPS == '1' || $HTTPS == 'on') {
4366  $SCHEME = 'https';
4367  } else {
4368  $SCHEME = 'http';
4369  }
4370  $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
4371  }
4372  if(false == $style) {
4373  $style = "rpc";
4374  }
4375  if(false == $use) {
4376  $use = "encoded";
4377  }
4378  if ($use == 'encoded' && $encodingStyle = '') {
4379  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
4380  }
4381 
4382  $this->operations[$name] = array(
4383  'name' => $name,
4384  'in' => $in,
4385  'out' => $out,
4386  'namespace' => $namespace,
4387  'soapaction' => $soapaction,
4388  'style' => $style);
4389  if($this->wsdl){
4390  $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
4391  }
4392  return true;
4393  }
4394 
4405  function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
4406  if ($faultdetail == '' && $this->debug_flag) {
4407  $faultdetail = $this->getDebug();
4408  }
4409  $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
4410  $this->fault->soap_defencoding = $this->soap_defencoding;
4411  }
4412 
4424  function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
4425  {
4426  global $HTTP_SERVER_VARS;
4427 
4428  if (isset($_SERVER)) {
4429  $SERVER_NAME = $_SERVER['SERVER_NAME'];
4430  $SERVER_PORT = $_SERVER['SERVER_PORT'];
4431  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4432  $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4433  } elseif (isset($HTTP_SERVER_VARS)) {
4434  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4435  $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
4436  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4437  $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4438  } else {
4439  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4440  }
4441  // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
4442  $colon = strpos($SERVER_NAME,":");
4443  if ($colon) {
4444  $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
4445  }
4446  if ($SERVER_PORT == 80) {
4447  $SERVER_PORT = '';
4448  } else {
4449  $SERVER_PORT = ':' . $SERVER_PORT;
4450  }
4451  if(false == $namespace) {
4452  $namespace = "http://$SERVER_NAME/soap/$serviceName";
4453  }
4454 
4455  if(false == $endpoint) {
4456  if ($HTTPS == '1' || $HTTPS == 'on') {
4457  $SCHEME = 'https';
4458  } else {
4459  $SCHEME = 'http';
4460  }
4461  $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
4462  }
4463 
4464  if(false == $schemaTargetNamespace) {
4465  $schemaTargetNamespace = $namespace;
4466  }
4467 
4468  $this->wsdl = new wsdl;
4469  $this->wsdl->serviceName = $serviceName;
4470  $this->wsdl->endpoint = $endpoint;
4471  $this->wsdl->namespaces['tns'] = $namespace;
4472  $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
4473  $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
4474  if ($schemaTargetNamespace != $namespace) {
4475  $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4476  }
4477  $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
4478  if ($style == 'document') {
4479  $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
4480  }
4481  $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
4482  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
4483  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
4484  $this->wsdl->bindings[$serviceName.'Binding'] = array(
4485  'name'=>$serviceName.'Binding',
4486  'style'=>$style,
4487  'transport'=>$transport,
4488  'portType'=>$serviceName.'PortType');
4489  $this->wsdl->ports[$serviceName.'Port'] = array(
4490  'binding'=>$serviceName.'Binding',
4491  'location'=>$endpoint,
4492  'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
4493  }
4494 }
4495 
4499 class soap_server extends nusoap_server {
4500 }
4501 
4502 ?><?php
4503 
4504 
4505 
4515 class wsdl extends nusoap_base {
4516  // URL or filename of the root of this WSDL
4517  var $wsdl;
4518  // define internal arrays of bindings, ports, operations, messages, etc.
4519  var $schemas = array();
4520  var $currentSchema;
4521  var $message = array();
4522  var $complexTypes = array();
4523  var $messages = array();
4524  var $currentMessage;
4525  var $currentOperation;
4526  var $portTypes = array();
4527  var $currentPortType;
4528  var $bindings = array();
4529  var $currentBinding;
4530  var $ports = array();
4531  var $currentPort;
4532  var $opData = array();
4533  var $status = '';
4534  var $documentation = false;
4535  var $endpoint = '';
4536  // array of wsdl docs to import
4537  var $import = array();
4538  // parser vars
4539  var $parser;
4540  var $position = 0;
4541  var $depth = 0;
4542  var $depth_array = array();
4543  // for getting wsdl
4544  var $proxyhost = '';
4545  var $proxyport = '';
4546  var $proxyusername = '';
4547  var $proxypassword = '';
4548  var $timeout = 0;
4549  var $response_timeout = 30;
4550  var $curl_options = array(); // User-specified cURL options
4551  var $use_curl = false; // whether to always try to use cURL
4552  // for HTTP authentication
4553  var $username = ''; // Username for HTTP authentication
4554  var $password = ''; // Password for HTTP authentication
4555  var $authtype = ''; // Type of HTTP authentication
4556  var $certRequest = array(); // Certificate for HTTP SSL authentication
4557 
4572  function __construct($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){
4574  $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
4575  $this->proxyhost = $proxyhost;
4576  $this->proxyport = $proxyport;
4577  $this->proxyusername = $proxyusername;
4578  $this->proxypassword = $proxypassword;
4579  $this->timeout = $timeout;
4580  $this->response_timeout = $response_timeout;
4581  if (is_array($curl_options))
4582  $this->curl_options = $curl_options;
4583  $this->use_curl = $use_curl;
4584  $this->fetchWSDL($wsdl);
4585  }
4586 
4592  function fetchWSDL($wsdl) {
4593  $this->debug("parse and process WSDL path=$wsdl");
4594  $this->wsdl = $wsdl;
4595  // parse wsdl file
4596  if ($this->wsdl != "") {
4597  $this->parseWSDL($this->wsdl);
4598  }
4599  // imports
4600  // TODO: handle imports more properly, grabbing them in-line and nesting them
4601  $imported_urls = array();
4602  $imported = 1;
4603  while ($imported > 0) {
4604  $imported = 0;
4605  // Schema imports
4606  foreach ($this->schemas as $ns => $list) {
4607  foreach ($list as $xs) {
4608  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4609  foreach ($xs->imports as $ns2 => $list2) {
4610  for ($ii = 0; $ii < count($list2); $ii++) {
4611  if (! $list2[$ii]['loaded']) {
4612  $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
4613  $url = $list2[$ii]['location'];
4614  if ($url != '') {
4615  $urlparts = parse_url($url);
4616  if (!isset($urlparts['host'])) {
4617  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
4618  substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
4619  }
4620  if (! in_array($url, $imported_urls)) {
4621  $this->parseWSDL($url);
4622  $imported++;
4623  $imported_urls[] = $url;
4624  }
4625  } else {
4626  $this->debug("Unexpected scenario: empty URL for unloaded import");
4627  }
4628  }
4629  }
4630  }
4631  }
4632  }
4633  // WSDL imports
4634  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4635  foreach ($this->import as $ns => $list) {
4636  for ($ii = 0; $ii < count($list); $ii++) {
4637  if (! $list[$ii]['loaded']) {
4638  $this->import[$ns][$ii]['loaded'] = true;
4639  $url = $list[$ii]['location'];
4640  if ($url != '') {
4641  $urlparts = parse_url($url);
4642  if (!isset($urlparts['host'])) {
4643  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4644  substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
4645  }
4646  if (! in_array($url, $imported_urls)) {
4647  $this->parseWSDL($url);
4648  $imported++;
4649  $imported_urls[] = $url;
4650  }
4651  } else {
4652  $this->debug("Unexpected scenario: empty URL for unloaded import");
4653  }
4654  }
4655  }
4656  }
4657  }
4658  // add new data to operation data
4659  foreach($this->bindings as $binding => $bindingData) {
4660  if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
4661  foreach($bindingData['operations'] as $operation => $data) {
4662  $this->debug('post-parse data gathering for ' . $operation);
4663  $this->bindings[$binding]['operations'][$operation]['input'] =
4664  isset($this->bindings[$binding]['operations'][$operation]['input']) ?
4665  array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
4666  $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
4667  $this->bindings[$binding]['operations'][$operation]['output'] =
4668  isset($this->bindings[$binding]['operations'][$operation]['output']) ?
4669  array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
4670  $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
4671  if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
4672  $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
4673  }
4674  if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
4675  $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
4676  }
4677  // Set operation style if necessary, but do not override one already provided
4678  if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
4679  $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
4680  }
4681  $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
4682  $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
4683  $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
4684  }
4685  }
4686  }
4687  }
4688 
4695  function parseWSDL($wsdl = '') {
4696  $this->debug("parse WSDL at path=$wsdl");
4697 
4698  if ($wsdl == '') {
4699  $this->debug('no wsdl passed to parseWSDL()!!');
4700  $this->setError('no wsdl passed to parseWSDL()!!');
4701  return false;
4702  }
4703 
4704  // parse $wsdl for url format
4705  $wsdl_props = parse_url($wsdl);
4706 
4707  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
4708  $this->debug('getting WSDL http(s) URL ' . $wsdl);
4709  // get wsdl
4710  $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
4711  $tr->request_method = 'GET';
4712  $tr->useSOAPAction = false;
4713  if($this->proxyhost && $this->proxyport){
4714  $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
4715  }
4716  if ($this->authtype != '') {
4717  $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
4718  }
4719  $tr->setEncoding('gzip, deflate');
4720  $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
4721  //$this->debug("WSDL request\n" . $tr->outgoing_payload);
4722  //$this->debug("WSDL response\n" . $tr->incoming_payload);
4723  $this->appendDebug($tr->getDebug());
4724  // catch errors
4725  if($err = $tr->getError() ){
4726  $errstr = 'HTTP ERROR: '.$err;
4727  $this->debug($errstr);
4728  $this->setError($errstr);
4729  unset($tr);
4730  return false;
4731  }
4732  unset($tr);
4733  $this->debug("got WSDL URL");
4734  } else {
4735  // $wsdl is not http(s), so treat it as a file URL or plain file path
4736  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
4737  $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
4738  } else {
4739  $path = $wsdl;
4740  }
4741  $this->debug('getting WSDL file ' . $path);
4742  if ($fp = @fopen($path, 'r')) {
4743  $wsdl_string = '';
4744  while ($data = fread($fp, 32768)) {
4745  $wsdl_string .= $data;
4746  }
4747  fclose($fp);
4748  } else {
4749  $errstr = "Bad path to WSDL file $path";
4750  $this->debug($errstr);
4751  $this->setError($errstr);
4752  return false;
4753  }
4754  }
4755  $this->debug('Parse WSDL');
4756  // end new code added
4757  // Create an XML parser.
4758  $this->parser = xml_parser_create();
4759  // Set the options for parsing the XML data.
4760  // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
4761  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
4762  // Set the object for the parser.
4763  xml_set_object($this->parser, $this);
4764  // Set the element handlers for the parser.
4765  xml_set_element_handler($this->parser, 'start_element', 'end_element');
4766  xml_set_character_data_handler($this->parser, 'character_data');
4767  // Parse the XML file.
4768  if (!xml_parse($this->parser, $wsdl_string, true)) {
4769  // Display an error message.
4770  $errstr = sprintf(
4771  'XML error parsing WSDL from %s on line %d: %s',
4772  $wsdl,
4773  xml_get_current_line_number($this->parser),
4774  xml_error_string(xml_get_error_code($this->parser))
4775  );
4776  $this->debug($errstr);
4777  $this->debug("XML payload:\n" . $wsdl_string);
4778  $this->setError($errstr);
4779  return false;
4780  }
4781  // free the parser
4782  xml_parser_free($this->parser);
4783  $this->debug('Parsing WSDL done');
4784  // catch wsdl parse errors
4785  if($this->getError()){
4786  return false;
4787  }
4788  return true;
4789  }
4790 
4799  function start_element($parser, $name, $attrs)
4800  {
4801  if ($this->status == 'schema') {
4802  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4803  $this->appendDebug($this->currentSchema->getDebug());
4804  $this->currentSchema->clearDebug();
4805  } elseif (preg_match('/schema$/', $name)) {
4806  $this->debug('Parsing WSDL schema');
4807  // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
4808  $this->status = 'schema';
4809  $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
4810  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4811  $this->appendDebug($this->currentSchema->getDebug());
4812  $this->currentSchema->clearDebug();
4813  } else {
4814  // position in the total number of elements, starting from 0
4815  $pos = $this->position++;
4816  $depth = $this->depth++;
4817  // set self as current value for this depth
4818  $this->depth_array[$depth] = $pos;
4819  $this->message[$pos] = array('cdata' => '');
4820  // process attributes
4821  if (count($attrs) > 0) {
4822  // register namespace declarations
4823  foreach($attrs as $k => $v) {
4824  if (preg_match('/^xmlns/',$k)) {
4825  if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
4826  $this->namespaces[$ns_prefix] = $v;
4827  } else {
4828  $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
4829  }
4830  if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
4831  $this->XMLSchemaVersion = $v;
4832  $this->namespaces['xsi'] = $v . '-instance';
4833  }
4834  }
4835  }
4836  // expand each attribute prefix to its namespace
4837  foreach($attrs as $k => $v) {
4838  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
4839  if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
4840  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
4841  }
4842  $eAttrs[$k] = $v;
4843  }
4844  $attrs = $eAttrs;
4845  } else {
4846  $attrs = array();
4847  }
4848  // get element prefix, namespace and name
4849  if (preg_match('/:/', $name)) {
4850  // get ns prefix
4851  $prefix = substr($name, 0, strpos($name, ':'));
4852  // get ns
4853  $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
4854  // get unqualified name
4855  $name = substr(strstr($name, ':'), 1);
4856  }
4857  // process attributes, expanding any prefixes to namespaces
4858  // find status, register data
4859  switch ($this->status) {
4860  case 'message':
4861  if ($name == 'part') {
4862  if (isset($attrs['type'])) {
4863  $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
4864  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
4865  }
4866  if (isset($attrs['element'])) {
4867  $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
4868  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
4869  }
4870  }
4871  break;
4872  case 'portType':
4873  switch ($name) {
4874  case 'operation':
4875  $this->currentPortOperation = $attrs['name'];
4876  $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
4877  if (isset($attrs['parameterOrder'])) {
4878  $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
4879  }
4880  break;
4881  case 'documentation':
4882  $this->documentation = true;
4883  break;
4884  // merge input/output data
4885  default:
4886  $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
4887  $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
4888  break;
4889  }
4890  break;
4891  case 'binding':
4892  switch ($name) {
4893  case 'binding':
4894  // get ns prefix
4895  if (isset($attrs['style'])) {
4896  $this->bindings[$this->currentBinding]['prefix'] = $prefix;
4897  }
4898  $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
4899  break;
4900  case 'header':
4901  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
4902  break;
4903  case 'operation':
4904  if (isset($attrs['soapAction'])) {
4905  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
4906  }
4907  if (isset($attrs['style'])) {
4908  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
4909  }
4910  if (isset($attrs['name'])) {
4911  $this->currentOperation = $attrs['name'];
4912  $this->debug("current binding operation: $this->currentOperation");
4913  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
4914  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
4915  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
4916  }
4917  break;
4918  case 'input':
4919  $this->opStatus = 'input';
4920  break;
4921  case 'output':
4922  $this->opStatus = 'output';
4923  break;
4924  case 'body':
4925  if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
4926  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
4927  } else {
4928  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
4929  }
4930  break;
4931  }
4932  break;
4933  case 'service':
4934  switch ($name) {
4935  case 'port':
4936  $this->currentPort = $attrs['name'];
4937  $this->debug('current port: ' . $this->currentPort);
4938  $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
4939 
4940  break;
4941  case 'address':
4942  $this->ports[$this->currentPort]['location'] = $attrs['location'];
4943  $this->ports[$this->currentPort]['bindingType'] = $namespace;
4944  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
4945  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
4946  break;
4947  }
4948  break;
4949  }
4950  // set status
4951  switch ($name) {
4952  case 'import':
4953  if (isset($attrs['location'])) {
4954  $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
4955  $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
4956  } else {
4957  $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
4958  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
4959  $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
4960  }
4961  $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
4962  }
4963  break;
4964  //wait for schema
4965  //case 'types':
4966  // $this->status = 'schema';
4967  // break;
4968  case 'message':
4969  $this->status = 'message';
4970  $this->messages[$attrs['name']] = array();
4971  $this->currentMessage = $attrs['name'];
4972  break;
4973  case 'portType':
4974  $this->status = 'portType';
4975  $this->portTypes[$attrs['name']] = array();
4976  $this->currentPortType = $attrs['name'];
4977  break;
4978  case "binding":
4979  if (isset($attrs['name'])) {
4980  // get binding name
4981  if (strpos($attrs['name'], ':')) {
4982  $this->currentBinding = $this->getLocalPart($attrs['name']);
4983  } else {
4984  $this->currentBinding = $attrs['name'];
4985  }
4986  $this->status = 'binding';
4987  $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
4988  $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
4989  }
4990  break;
4991  case 'service':
4992  $this->serviceName = $attrs['name'];
4993  $this->status = 'service';
4994  $this->debug('current service: ' . $this->serviceName);
4995  break;
4996  case 'definitions':
4997  foreach ($attrs as $name => $value) {
4998  $this->wsdl_info[$name] = $value;
4999  }
5000  break;
5001  }
5002  }
5003  }
5004 
5012  function end_element($parser, $name){
5013  // unset schema status
5014  if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) {
5015  $this->status = "";
5016  $this->appendDebug($this->currentSchema->getDebug());
5017  $this->currentSchema->clearDebug();
5018  $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
5019  $this->debug('Parsing WSDL schema done');
5020  }
5021  if ($this->status == 'schema') {
5022  $this->currentSchema->schemaEndElement($parser, $name);
5023  } else {
5024  // bring depth down a notch
5025  $this->depth--;
5026  }
5027  // end documentation
5028  if ($this->documentation) {
5029  //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
5030  //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
5031  $this->documentation = false;
5032  }
5033  }
5034 
5042  function character_data($parser, $data)
5043  {
5044  $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
5045  if (isset($this->message[$pos]['cdata'])) {
5046  $this->message[$pos]['cdata'] .= $data;
5047  }
5048  if ($this->documentation) {
5049  $this->documentation .= $data;
5050  }
5051  }
5052 
5062  function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
5063  $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
5064  $this->appendDebug($this->varDump($certRequest));
5065  $this->username = $username;
5066  $this->password = $password;
5067  $this->authtype = $authtype;
5068  $this->certRequest = $certRequest;
5069  }
5070 
5071  function getBindingData($binding)
5072  {
5073  if (is_array($this->bindings[$binding])) {
5074  return $this->bindings[$binding];
5075  }
5076  }
5077 
5085  function getOperations($bindingType = 'soap') {
5086  $ops = array();
5087  if ($bindingType == 'soap') {
5088  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5089  } elseif ($bindingType == 'soap12') {
5090  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5091  }
5092  // loop thru ports
5093  foreach($this->ports as $port => $portData) {
5094  // binding type of port matches parameter
5095  if ($portData['bindingType'] == $bindingType) {
5096  //$this->debug("getOperations for port $port");
5097  //$this->debug("port data: " . $this->varDump($portData));
5098  //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
5099  // merge bindings
5100  if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
5101  $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
5102  }
5103  }
5104  }
5105  return $ops;
5106  }
5107 
5116  function getOperationData($operation, $bindingType = 'soap')
5117  {
5118  if ($bindingType == 'soap') {
5119  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5120  } elseif ($bindingType == 'soap12') {
5121  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5122  }
5123  // loop thru ports
5124  foreach($this->ports as $port => $portData) {
5125  // binding type of port matches parameter
5126  if ($portData['bindingType'] == $bindingType) {
5127  // get binding
5128  //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5129  foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
5130  // note that we could/should also check the namespace here
5131  if ($operation == $bOperation) {
5132  $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
5133  return $opData;
5134  }
5135  }
5136  }
5137  }
5138  }
5139 
5148  function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
5149  if ($bindingType == 'soap') {
5150  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5151  } elseif ($bindingType == 'soap12') {
5152  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5153  }
5154  // loop thru ports
5155  foreach($this->ports as $port => $portData) {
5156  // binding type of port matches parameter
5157  if ($portData['bindingType'] == $bindingType) {
5158  // loop through operations for the binding
5159  foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5160  if ($opData['soapAction'] == $soapAction) {
5161  return $opData;
5162  }
5163  }
5164  }
5165  }
5166  }
5167 
5186  function getTypeDef($type, $ns) {
5187  $this->debug("in getTypeDef: type=$type, ns=$ns");
5188  if ((! $ns) && isset($this->namespaces['tns'])) {
5189  $ns = $this->namespaces['tns'];
5190  $this->debug("in getTypeDef: type namespace forced to $ns");
5191  }
5192  if (!isset($this->schemas[$ns])) {
5193  foreach ($this->schemas as $ns0 => $schema0) {
5194  if (strcasecmp($ns, $ns0) == 0) {
5195  $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
5196  $ns = $ns0;
5197  break;
5198  }
5199  }
5200  }
5201  if (isset($this->schemas[$ns])) {
5202  $this->debug("in getTypeDef: have schema for namespace $ns");
5203  for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
5204  $xs = &$this->schemas[$ns][$i];
5205  $t = $xs->getTypeDef($type);
5206  //$this->appendDebug($xs->getDebug());
5207  //$xs->clearDebug();
5208  if ($t) {
5209  if (!isset($t['phpType'])) {
5210  // get info for type to tack onto the element
5211  $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
5212  $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
5213  $etype = $this->getTypeDef($uqType, $ns);
5214  if ($etype) {
5215  $this->debug("found type for [element] $type:");
5216  $this->debug($this->varDump($etype));
5217  if (isset($etype['phpType'])) {
5218  $t['phpType'] = $etype['phpType'];
5219  }
5220  if (isset($etype['elements'])) {
5221  $t['elements'] = $etype['elements'];
5222  }
5223  if (isset($etype['attrs'])) {
5224  $t['attrs'] = $etype['attrs'];
5225  }
5226  }
5227  }
5228  return $t;
5229  }
5230  }
5231  } else {
5232  $this->debug("in getTypeDef: do not have schema for namespace $ns");
5233  }
5234  return false;
5235  }
5236 
5242  function webDescription(){
5243  global $HTTP_SERVER_VARS;
5244 
5245  if (isset($_SERVER)) {
5246  $PHP_SELF = $_SERVER['PHP_SELF'];
5247  } elseif (isset($HTTP_SERVER_VARS)) {
5248  $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
5249  } else {
5250  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
5251  }
5252  // begin-patch: https://mantis.ilias.de/view.php?id=28866
5253  $PHP_SELF = filter_var($PHP_SELF, FILTER_SANITIZE_STRING);
5254  // end-patch
5255 
5256  $b = '
5257  <html><head><title>NuSOAP: '.$this->serviceName.'</title>
5258  <style type="text/css">
5259  body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
5260  p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
5261  pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
5262  ul { margin-top: 10px; margin-left: 20px; }
5263  li { list-style-type: none; margin-top: 10px; color: #000000; }
5264  .content{
5265  margin-left: 0px; padding-bottom: 2em; }
5266  .nav {
5267  padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
5268  margin-top: 10px; margin-left: 0px; color: #000000;
5269  background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
5270  .title {
5271  font-family: arial; font-size: 26px; color: #ffffff;
5272  background-color: #999999; width: 105%; margin-left: 0px;
5273  padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
5274  .hidden {
5275  position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
5276  font-family: arial; overflow: hidden; width: 600;
5277  padding: 20px; font-size: 10px; background-color: #999999;
5278  layer-background-color:#FFFFFF; }
5279  a,a:active { color: charcoal; font-weight: bold; }
5280  a:visited { color: #666666; font-weight: bold; }
5281  a:hover { color: cc3300; font-weight: bold; }
5282  </style>
5283  <script language="JavaScript" type="text/javascript">
5284  <!--
5285  // POP-UP CAPTIONS...
5286  function lib_bwcheck(){ //Browsercheck (needed)
5287  this.ver=navigator.appVersion
5288  this.agent=navigator.userAgent
5289  this.dom=document.getElementById?1:0
5290  this.opera5=this.agent.indexOf("Opera 5")>-1
5291  this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
5292  this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
5293  this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
5294  this.ie=this.ie4||this.ie5||this.ie6
5295  this.mac=this.agent.indexOf("Mac")>-1
5296  this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
5297  this.ns4=(document.layers && !this.dom)?1:0;
5298  this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
5299  return this
5300  }
5301  var bw = new lib_bwcheck()
5302  //Makes crossbrowser object.
5303  function makeObj(obj){
5304  this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
5305  if(!this.evnt) return false
5306  this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
5307  this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
5308  this.writeIt=b_writeIt;
5309  return this
5310  }
5311  // A unit of measure that will be added when setting the position of a layer.
5312  //var px = bw.ns4||window.opera?"":"px";
5313  function b_writeIt(text){
5314  if (bw.ns4){this.wref.write(text);this.wref.close()}
5315  else this.wref.innerHTML = text
5316  }
5317  //Shows the messages
5318  var oDesc;
5319  function popup(divid){
5320  if(oDesc = new makeObj(divid)){
5321  oDesc.css.visibility = "visible"
5322  }
5323  }
5324  function popout(){ // Hides message
5325  if(oDesc) oDesc.css.visibility = "hidden"
5326  }
5327  //-->
5328  </script>
5329  </head>
5330  <body>
5331  <div class=content>
5332  <br><br>
5333  <div class=title>'.$this->serviceName.'</div>
5334  <div class=nav>
5335  <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.
5336  Click on an operation name to view it&apos;s details.</p>
5337  <ul>';
5338  foreach($this->getOperations() as $op => $data){
5339  // begin-patch: https://mantis.ilias.de/view.php?id=28866
5340  if (isset($data['endpoint'])) {
5341  $data['endpoint'] = filter_var($data['endpoint'], FILTER_SANITIZE_STRING);
5342  }
5343  // end-patch
5344  $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
5345  // create hidden div
5346  $b .= "<div id='$op' class='hidden'>
5347  <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
5348  foreach($data as $donnie => $marie){ // loop through opdata
5349  if($donnie == 'input' || $donnie == 'output'){ // show input/output data
5350  $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
5351  foreach($marie as $captain => $tenille){ // loop through data
5352  if($captain == 'parts'){ // loop thru parts
5353  $b .= "&nbsp;&nbsp;$captain:<br>";
5354  //if(is_array($tenille)){
5355  foreach($tenille as $joanie => $chachi){
5356  $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
5357  }
5358  //}
5359  } else {
5360  $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
5361  }
5362  }
5363  } else {
5364  $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
5365  }
5366  }
5367  $b .= '</div>';
5368  }
5369  $b .= '
5370  <ul>
5371  </div>
5372  </div></body></html>';
5373  return $b;
5374  }
5375 
5383  function serialize($debug = 0)
5384  {
5385  $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
5386  $xml .= "\n<definitions";
5387  foreach($this->namespaces as $k => $v) {
5388  $xml .= " xmlns:$k=\"$v\"";
5389  }
5390  // 10.9.02 - add poulter fix for wsdl and tns declarations
5391  if (isset($this->namespaces['wsdl'])) {
5392  $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
5393  }
5394  if (isset($this->namespaces['tns'])) {
5395  $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
5396  }
5397  $xml .= '>';
5398  // imports
5399  if (sizeof($this->import) > 0) {
5400  foreach($this->import as $ns => $list) {
5401  foreach ($list as $ii) {
5402  if ($ii['location'] != '') {
5403  $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
5404  } else {
5405  $xml .= '<import namespace="' . $ns . '" />';
5406  }
5407  }
5408  }
5409  }
5410  // types
5411  if (count($this->schemas)>=1) {
5412  $xml .= "\n<types>\n";
5413  foreach ($this->schemas as $ns => $list) {
5414  foreach ($list as $xs) {
5415  $xml .= $xs->serializeSchema();
5416  }
5417  }
5418  $xml .= '</types>';
5419  }
5420  // messages
5421  if (count($this->messages) >= 1) {
5422  foreach($this->messages as $msgName => $msgParts) {
5423  $xml .= "\n<message name=\"" . $msgName . '">';
5424  if(is_array($msgParts)){
5425  foreach($msgParts as $partName => $partType) {
5426  // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
5427  if (strpos($partType, ':')) {
5428  $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
5429  } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
5430  // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
5431  $typePrefix = 'xsd';
5432  } else {
5433  foreach($this->typemap as $ns => $types) {
5434  if (isset($types[$partType])) {
5435  $typePrefix = $this->getPrefixFromNamespace($ns);
5436  }
5437  }
5438  if (!isset($typePrefix)) {
5439  die("$partType has no namespace!");
5440  }
5441  }
5442  $ns = $this->getNamespaceFromPrefix($typePrefix);
5443  $localPart = $this->getLocalPart($partType);
5444  $typeDef = $this->getTypeDef($localPart, $ns);
5445  if ($typeDef['typeClass'] == 'element') {
5446  $elementortype = 'element';
5447  if (substr($localPart, -1) == '^') {
5448  $localPart = substr($localPart, 0, -1);
5449  }
5450  } else {
5451  $elementortype = 'type';
5452  }
5453  $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
5454  }
5455  }
5456  $xml .= '</message>';
5457  }
5458  }
5459  // bindings & porttypes
5460  if (count($this->bindings) >= 1) {
5461  $binding_xml = '';
5462  $portType_xml = '';
5463  foreach($this->bindings as $bindingName => $attrs) {
5464  $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
5465  $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
5466  $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
5467  foreach($attrs['operations'] as $opName => $opParts) {
5468  $binding_xml .= "\n" . ' <operation name="' . $opName . '">';
5469  $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
5470  if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
5471  $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
5472  } else {
5473  $enc_style = '';
5474  }
5475  $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
5476  if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
5477  $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
5478  } else {
5479  $enc_style = '';
5480  }
5481  $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
5482  $binding_xml .= "\n" . ' </operation>';
5483  $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"';
5484  if (isset($opParts['parameterOrder'])) {
5485  $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
5486  }
5487  $portType_xml .= '>';
5488  if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
5489  $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
5490  }
5491  $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>';
5492  $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>';
5493  $portType_xml .= "\n" . ' </operation>';
5494  }
5495  $portType_xml .= "\n" . '</portType>';
5496  $binding_xml .= "\n" . '</binding>';
5497  }
5498  $xml .= $portType_xml . $binding_xml;
5499  }
5500  // services
5501  $xml .= "\n<service name=\"" . $this->serviceName . '">';
5502  $has_client = isset($_GET['client_id']);
5503  if (count($this->ports) >= 1) {
5504  foreach($this->ports as $pName => $attrs) {
5505  $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5506  $address = $attrs['location'] . ($debug || $has_client ? "?" : "")
5507  . ($debug ? 'debug=1' : '') . ($debug && $has_client ? "&amp;" : "")
5508  . ($has_client ? 'client_id=' . $_GET['client_id'] : '');
5509  $xml .= "\n" . ' <soap:address location="' . $address. '"/>';
5510  $xml .= "\n" . ' </port>';
5511  }
5512  }
5513 
5514  $xml .= "\n" . '</service>';
5515  return $xml . "\n</definitions>";
5516  }
5517 
5527  function parametersMatchWrapped($type, &$parameters) {
5528  $this->debug("in parametersMatchWrapped type=$type, parameters=");
5529  $this->appendDebug($this->varDump($parameters));
5530 
5531  // split type into namespace:unqualified-type
5532  if (strpos($type, ':')) {
5533  $uqType = substr($type, strrpos($type, ':') + 1);
5534  $ns = substr($type, 0, strrpos($type, ':'));
5535  $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
5536  if ($this->getNamespaceFromPrefix($ns)) {
5537  $ns = $this->getNamespaceFromPrefix($ns);
5538  $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
5539  }
5540  } else {
5541  // TODO: should the type be compared to types in XSD, and the namespace
5542  // set to XSD if the type matches?
5543  $this->debug("in parametersMatchWrapped: No namespace for type $type");
5544  $ns = '';
5545  $uqType = $type;
5546  }
5547 
5548  // get the type information
5549  if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
5550  $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
5551  return false;
5552  }
5553  $this->debug("in parametersMatchWrapped: found typeDef=");
5554  $this->appendDebug($this->varDump($typeDef));
5555  if (substr($uqType, -1) == '^') {
5556  $uqType = substr($uqType, 0, -1);
5557  }
5558  $phpType = $typeDef['phpType'];
5559  $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
5560  $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
5561 
5562  // we expect a complexType or element of complexType
5563  if ($phpType != 'struct') {
5564  $this->debug("in parametersMatchWrapped: not a struct");
5565  return false;
5566  }
5567 
5568  // see whether the parameter names match the elements
5569  if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
5570  $elements = 0;
5571  $matches = 0;
5572  $change = false;
5573  if ($this->isArraySimpleOrStruct($parameters) == 'arraySimple' && count($parameters) == count($typeDef['elements'])) {
5574  $this->debug("in parametersMatchWrapped: (wrapped return value kludge) correct number of elements in simple array, so change array and wrap");
5575  $change = true;
5576  }
5577  foreach ($typeDef['elements'] as $name => $attrs) {
5578  if ($change) {
5579  $this->debug("in parametersMatchWrapped: change parameter $element to name $name");
5580  $parameters[$name] = $parameters[$elements];
5581  unset($parameters[$elements]);
5582  $matches++;
5583  } elseif (isset($parameters[$name])) {
5584  $this->debug("in parametersMatchWrapped: have parameter named $name");
5585  $matches++;
5586  } else {
5587  $this->debug("in parametersMatchWrapped: do not have parameter named $name");
5588  }
5589  $elements++;
5590  }
5591 
5592  $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
5593  if ($matches == 0) {
5594  return false;
5595  }
5596  return true;
5597  }
5598 
5599  // since there are no elements for the type, if the user passed no
5600  // parameters, the parameters match wrapped.
5601  $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
5602  return count($parameters) == 0;
5603  }
5604 
5620  function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') {
5621  $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
5622  $this->appendDebug('parameters=' . $this->varDump($parameters));
5623 
5624  if ($direction != 'input' && $direction != 'output') {
5625  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5626  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5627  return false;
5628  }
5629  if (!$opData = $this->getOperationData($operation, $bindingType)) {
5630  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5631  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5632  return false;
5633  }
5634  $this->debug('in serializeRPCParameters: opData:');
5635  $this->appendDebug($this->varDump($opData));
5636 
5637  // Get encoding style for output and set to current
5638  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5639  if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5640  $encodingStyle = $opData['output']['encodingStyle'];
5641  $enc_style = $encodingStyle;
5642  }
5643 
5644  // set input params
5645  $xml = '';
5646  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5647  $parts = &$opData[$direction]['parts'];
5648  $part_count = sizeof($parts);
5649  $style = $opData['style'];
5650  $use = $opData[$direction]['use'];
5651  $this->debug("have $part_count part(s) to serialize using $style/$use");
5652  if (is_array($parameters)) {
5653  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5654  $parameter_count = count($parameters);
5655  $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
5656  // check for Microsoft-style wrapped parameters
5657  if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
5658  $this->debug('check whether the caller has wrapped the parameters');
5659  if ((($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) || ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1)) {
5660  $this->debug('check whether caller\'s parameters match the wrapped ones');
5661  if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
5662  $this->debug('wrap the parameters for the caller');
5663  $parameters = array('parameters' => $parameters);
5664  $parameter_count = 1;
5665  }
5666  }
5667  }
5668  foreach ($parts as $name => $type) {
5669  $this->debug("serializing part $name of type $type");
5670  // Track encoding style
5671  if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5672  $encodingStyle = $opData[$direction]['encodingStyle'];
5673  $enc_style = $encodingStyle;
5674  } else {
5675  $enc_style = false;
5676  }
5677  // NOTE: add error handling here
5678  // if serializeType returns false, then catch global error and fault
5679  if ($parametersArrayType == 'arraySimple') {
5680  $p = array_shift($parameters);
5681  $this->debug('calling serializeType w/indexed param');
5682  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5683  } elseif (isset($parameters[$name])) {
5684  $this->debug('calling serializeType w/named param');
5685  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5686  } else {
5687  // TODO: only send nillable
5688  $this->debug('calling serializeType w/null param');
5689  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5690  }
5691  }
5692  } else {
5693  $this->debug('no parameters passed.');
5694  }
5695  }
5696  $this->debug("serializeRPCParameters returning: $xml");
5697  return $xml;
5698  }
5699 
5714  function serializeParameters($operation, $direction, $parameters)
5715  {
5716  $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
5717  $this->appendDebug('parameters=' . $this->varDump($parameters));
5718 
5719  if ($direction != 'input' && $direction != 'output') {
5720  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5721  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5722  return false;
5723  }
5724  if (!$opData = $this->getOperationData($operation)) {
5725  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
5726  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
5727  return false;
5728  }
5729  $this->debug('opData:');
5730  $this->appendDebug($this->varDump($opData));
5731 
5732  // Get encoding style for output and set to current
5733  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5734  if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5735  $encodingStyle = $opData['output']['encodingStyle'];
5736  $enc_style = $encodingStyle;
5737  }
5738 
5739  // set input params
5740  $xml = '';
5741  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5742 
5743  $use = $opData[$direction]['use'];
5744  $this->debug("use=$use");
5745  $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
5746  if (is_array($parameters)) {
5747  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5748  $this->debug('have ' . $parametersArrayType . ' parameters');
5749  foreach($opData[$direction]['parts'] as $name => $type) {
5750  $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
5751  // Track encoding style
5752  if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5753  $encodingStyle = $opData[$direction]['encodingStyle'];
5754  $enc_style = $encodingStyle;
5755  } else {
5756  $enc_style = false;
5757  }
5758  // NOTE: add error handling here
5759  // if serializeType returns false, then catch global error and fault
5760  if ($parametersArrayType == 'arraySimple') {
5761  $p = array_shift($parameters);
5762  $this->debug('calling serializeType w/indexed param');
5763  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5764  } elseif (isset($parameters[$name])) {
5765  $this->debug('calling serializeType w/named param');
5766  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5767  } else {
5768  // TODO: only send nillable
5769  $this->debug('calling serializeType w/null param');
5770  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5771  }
5772  }
5773  } else {
5774  $this->debug('no parameters passed.');
5775  }
5776  }
5777  $this->debug("serializeParameters returning: $xml");
5778  return $xml;
5779  }
5780 
5793  function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
5794  {
5795  $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
5796  $this->appendDebug("value=" . $this->varDump($value));
5797  if($use == 'encoded' && $encodingStyle) {
5798  $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
5799  }
5800 
5801  // if a soapval has been supplied, let its type override the WSDL
5802  if (is_object($value) && get_class($value) == 'soapval') {
5803  if ($value->type_ns) {
5804  $type = $value->type_ns . ':' . $value->type;
5805  $forceType = true;
5806  $this->debug("in serializeType: soapval overrides type to $type");
5807  } elseif ($value->type) {
5808  $type = $value->type;
5809  $forceType = true;
5810  $this->debug("in serializeType: soapval overrides type to $type");
5811  } else {
5812  $forceType = false;
5813  $this->debug("in serializeType: soapval does not override type");
5814  }
5815  $attrs = $value->attributes;
5816  $value = $value->value;
5817  $this->debug("in serializeType: soapval overrides value to $value");
5818  if ($attrs) {
5819  if (!is_array($value)) {
5820  $value['!'] = $value;
5821  }
5822  foreach ($attrs as $n => $v) {
5823  $value['!' . $n] = $v;
5824  }
5825  $this->debug("in serializeType: soapval provides attributes");
5826  }
5827  } else {
5828  $forceType = false;
5829  }
5830 
5831  $xml = '';
5832  if (strpos($type, ':')) {
5833  $uqType = substr($type, strrpos($type, ':') + 1);
5834  $ns = substr($type, 0, strrpos($type, ':'));
5835  $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
5836  if ($this->getNamespaceFromPrefix($ns)) {
5837  $ns = $this->getNamespaceFromPrefix($ns);
5838  $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
5839  }
5840 
5841  if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){
5842  $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
5843  if ($unqualified && $use == 'literal') {
5844  $elementNS = " xmlns=\"\"";
5845  } else {
5846  $elementNS = '';
5847  }
5848  if (is_null($value)) {
5849  if ($use == 'literal') {
5850  // TODO: depends on minOccurs
5851  $xml = "<$name$elementNS/>";
5852  } else {
5853  // TODO: depends on nillable, which should be checked before calling this method
5854  $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5855  }
5856  $this->debug("in serializeType: returning: $xml");
5857  return $xml;
5858  }
5859  if ($uqType == 'Array') {
5860  // JBoss/Axis does this sometimes
5861  return $this->serialize_val($value, $name, false, false, false, false, $use);
5862  }
5863  if ($uqType == 'boolean') {
5864  if ((is_string($value) && $value == 'false') || (! $value)) {
5865  $value = 'false';
5866  } else {
5867  $value = 'true';
5868  }
5869  }
5870  if ($uqType == 'string' && gettype($value) == 'string') {
5871  $value = $this->expandEntities($value);
5872  }
5873  if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
5874  $value = sprintf("%.0lf", $value);
5875  }
5876  // it's a scalar
5877  // TODO: what about null/nil values?
5878  // check type isn't a custom type extending xmlschema namespace
5879  if (!$this->getTypeDef($uqType, $ns)) {
5880  if ($use == 'literal') {
5881  if ($forceType) {
5882  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
5883  } else {
5884  $xml = "<$name$elementNS>$value</$name>";
5885  }
5886  } else {
5887  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
5888  }
5889  $this->debug("in serializeType: returning: $xml");
5890  return $xml;
5891  }
5892  $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
5893  } else if ($ns == 'http://xml.apache.org/xml-soap') {
5894  $this->debug('in serializeType: appears to be Apache SOAP type');
5895  if ($uqType == 'Map') {
5896  $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5897  if (! $tt_prefix) {
5898  $this->debug('in serializeType: Add namespace for Apache SOAP type');
5899  $tt_prefix = 'ns' . rand(1000, 9999);
5900  $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
5901  // force this to be added to usedNamespaces
5902  $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5903  }
5904  $contents = '';
5905  foreach($value as $k => $v) {
5906  $this->debug("serializing map element: key $k, value $v");
5907  $contents .= '<item>';
5908  $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
5909  $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
5910  $contents .= '</item>';
5911  }
5912  if ($use == 'literal') {
5913  if ($forceType) {
5914  $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
5915  } else {
5916  $xml = "<$name>$contents</$name>";
5917  }
5918  } else {
5919  $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
5920  }
5921  $this->debug("in serializeType: returning: $xml");
5922  return $xml;
5923  }
5924  $this->debug('in serializeType: Apache SOAP type, but only support Map');
5925  }
5926  } else {
5927  // TODO: should the type be compared to types in XSD, and the namespace
5928  // set to XSD if the type matches?
5929  $this->debug("in serializeType: No namespace for type $type");
5930  $ns = '';
5931  $uqType = $type;
5932  }
5933  if(!$typeDef = $this->getTypeDef($uqType, $ns)){
5934  $this->setError("$type ($uqType) is not a supported type.");
5935  $this->debug("in serializeType: $type ($uqType) is not a supported type.");
5936  return false;
5937  } else {
5938  $this->debug("in serializeType: found typeDef");
5939  $this->appendDebug('typeDef=' . $this->varDump($typeDef));
5940  if (substr($uqType, -1) == '^') {
5941  $uqType = substr($uqType, 0, -1);
5942  }
5943  }
5944  $phpType = $typeDef['phpType'];
5945  $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );
5946  // if php type == struct, map value to the <all> element names
5947  if ($phpType == 'struct') {
5948  if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
5949  $elementName = $uqType;
5950  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
5951  $elementNS = " xmlns=\"$ns\"";
5952  } else {
5953  $elementNS = " xmlns=\"\"";
5954  }
5955  } else {
5956  $elementName = $name;
5957  if ($unqualified) {
5958  $elementNS = " xmlns=\"\"";
5959  } else {
5960  $elementNS = '';
5961  }
5962  }
5963  if (is_null($value)) {
5964  if ($use == 'literal') {
5965  // TODO: depends on minOccurs
5966  $xml = "<$elementName$elementNS/>";
5967  } else {
5968  $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5969  }
5970  $this->debug("in serializeType: returning: $xml");
5971  return $xml;
5972  }
5973  if (is_object($value)) {
5974  $value = get_object_vars($value);
5975  }
5976  if (is_array($value)) {
5977  $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
5978  if ($use == 'literal') {
5979  if ($forceType) {
5980  $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
5981  } else {
5982  $xml = "<$elementName$elementNS$elementAttrs>";
5983  }
5984  } else {
5985  $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
5986  }
5987 
5988  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
5989  $xml .= "</$elementName>";
5990  } else {
5991  $this->debug("in serializeType: phpType is struct, but value is not an array");
5992  $this->setError("phpType is struct, but value is not an array: see debug output for details");
5993  $xml = '';
5994  }
5995  } elseif ($phpType == 'array') {
5996  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
5997  $elementNS = " xmlns=\"$ns\"";
5998  } else {
5999  if ($unqualified) {
6000  $elementNS = " xmlns=\"\"";
6001  } else {
6002  $elementNS = '';
6003  }
6004  }
6005  if (is_null($value)) {
6006  if ($use == 'literal') {
6007  // TODO: depends on minOccurs
6008  $xml = "<$name$elementNS/>";
6009  } else {
6010  $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
6011  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
6012  ":Array\" " .
6013  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
6014  ':arrayType="' .
6015  $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
6016  ':' .
6017  $this->getLocalPart($typeDef['arrayType'])."[0]\"/>";
6018  }
6019  $this->debug("in serializeType: returning: $xml");
6020  return $xml;
6021  }
6022  if (isset($typeDef['multidimensional'])) {
6023  $nv = array();
6024  foreach($value as $v) {
6025  $cols = ',' . sizeof($v);
6026  $nv = array_merge($nv, $v);
6027  }
6028  $value = $nv;
6029  } else {
6030  $cols = '';
6031  }
6032  if (is_array($value) && sizeof($value) >= 1) {
6033  $rows = sizeof($value);
6034  $contents = '';
6035  foreach($value as $k => $v) {
6036  $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
6037  //if (strpos($typeDef['arrayType'], ':') ) {
6038  if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
6039  $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
6040  } else {
6041  $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
6042  }
6043  }
6044  } else {
6045  $rows = 0;
6046  $contents = null;
6047  }
6048  // TODO: for now, an empty value will be serialized as a zero element
6049  // array. Revisit this when coding the handling of null/nil values.
6050  if ($use == 'literal') {
6051  $xml = "<$name$elementNS>"
6052  .$contents
6053  ."</$name>";
6054  } else {
6055  $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
6056  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6057  .':arrayType="'
6058  .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
6059  .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
6060  .$contents
6061  ."</$name>";
6062  }
6063  } elseif ($phpType == 'scalar') {
6064  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6065  $elementNS = " xmlns=\"$ns\"";
6066  } else {
6067  if ($unqualified) {
6068  $elementNS = " xmlns=\"\"";
6069  } else {
6070  $elementNS = '';
6071  }
6072  }
6073  if ($use == 'literal') {
6074  if ($forceType) {
6075  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6076  } else {
6077  $xml = "<$name$elementNS>$value</$name>";
6078  }
6079  } else {
6080  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6081  }
6082  }
6083  $this->debug("in serializeType: returning: $xml");
6084  return $xml;
6085  }
6086 
6097  function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {
6098  $xml = '';
6099  if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
6100  $this->debug("serialize attributes for XML Schema type $ns:$uqType");
6101  if (is_array($value)) {
6102  $xvalue = $value;
6103  } elseif (is_object($value)) {
6104  $xvalue = get_object_vars($value);
6105  } else {
6106  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6107  $xvalue = array();
6108  }
6109  foreach ($typeDef['attrs'] as $aName => $attrs) {
6110  if (isset($xvalue['!' . $aName])) {
6111  $xname = '!' . $aName;
6112  $this->debug("value provided for attribute $aName with key $xname");
6113  } elseif (isset($xvalue[$aName])) {
6114  $xname = $aName;
6115  $this->debug("value provided for attribute $aName with key $xname");
6116  } elseif (isset($attrs['default'])) {
6117  $xname = '!' . $aName;
6118  $xvalue[$xname] = $attrs['default'];
6119  $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
6120  } else {
6121  $xname = '';
6122  $this->debug("no value provided for attribute $aName");
6123  }
6124  if ($xname) {
6125  $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
6126  }
6127  }
6128  } else {
6129  $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
6130  }
6131  if (isset($typeDef['extensionBase'])) {
6132  $ns = $this->getPrefix($typeDef['extensionBase']);
6133  $uqType = $this->getLocalPart($typeDef['extensionBase']);
6134  if ($this->getNamespaceFromPrefix($ns)) {
6135  $ns = $this->getNamespaceFromPrefix($ns);
6136  }
6137  if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6138  $this->debug("serialize attributes for extension base $ns:$uqType");
6139  $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6140  } else {
6141  $this->debug("extension base $ns:$uqType is not a supported type");
6142  }
6143  }
6144  return $xml;
6145  }
6146 
6159  function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {
6160  $xml = '';
6161  if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6162  $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
6163  if (is_array($value)) {
6164  $xvalue = $value;
6165  } elseif (is_object($value)) {
6166  $xvalue = get_object_vars($value);
6167  } else {
6168  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6169  $xvalue = array();
6170  }
6171  // toggle whether all elements are present - ideally should validate against schema
6172  if (count($typeDef['elements']) != count($xvalue)){
6173  $optionals = true;
6174  }
6175  foreach ($typeDef['elements'] as $eName => $attrs) {
6176  if (!isset($xvalue[$eName])) {
6177  if (isset($attrs['default'])) {
6178  $xvalue[$eName] = $attrs['default'];
6179  $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
6180  }
6181  }
6182  // if user took advantage of a minOccurs=0, then only serialize named parameters
6183  if (isset($optionals)
6184  && (!isset($xvalue[$eName]))
6185  && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
6186  ){
6187  if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
6188  $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
6189  }
6190  // do nothing
6191  $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
6192  } else {
6193  // get value
6194  if (isset($xvalue[$eName])) {
6195  $v = $xvalue[$eName];
6196  } else {
6197  $v = null;
6198  }
6199  if (isset($attrs['form'])) {
6200  $unqualified = ($attrs['form'] == 'unqualified');
6201  } else {
6202  $unqualified = false;
6203  }
6204  if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
6205  $vv = $v;
6206  foreach ($vv as $k => $v) {
6207  if (isset($attrs['type']) || isset($attrs['ref'])) {
6208  // serialize schema-defined type
6209  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6210  } else {
6211  // serialize generic type (can this ever really happen?)
6212  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6213  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6214  }
6215  }
6216  } else {
6217  if (isset($attrs['type']) || isset($attrs['ref'])) {
6218  // serialize schema-defined type
6219  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6220  } else {
6221  // serialize generic type (can this ever really happen?)
6222  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6223  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6224  }
6225  }
6226  }
6227  }
6228  } else {
6229  $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
6230  }
6231  if (isset($typeDef['extensionBase'])) {
6232  $ns = $this->getPrefix($typeDef['extensionBase']);
6233  $uqType = $this->getLocalPart($typeDef['extensionBase']);
6234  if ($this->getNamespaceFromPrefix($ns)) {
6235  $ns = $this->getNamespaceFromPrefix($ns);
6236  }
6237  if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6238  $this->debug("serialize elements for extension base $ns:$uqType");
6239  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6240  } else {
6241  $this->debug("extension base $ns:$uqType is not a supported type");
6242  }
6243  }
6244  return $xml;
6245  }
6246 
6261  function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
6262  if (count($elements) > 0) {
6263  $eElements = array();
6264  foreach($elements as $n => $e){
6265  // expand each element
6266  $ee = array();
6267  foreach ($e as $k => $v) {
6268  $k = strpos($k,':') ? $this->expandQname($k) : $k;
6269  $v = strpos($v,':') ? $this->expandQname($v) : $v;
6270  $ee[$k] = $v;
6271  }
6272  $eElements[$n] = $ee;
6273  }
6274  $elements = $eElements;
6275  }
6276 
6277  if (count($attrs) > 0) {
6278  foreach($attrs as $n => $a){
6279  // expand each attribute
6280  foreach ($a as $k => $v) {
6281  $k = strpos($k,':') ? $this->expandQname($k) : $k;
6282  $v = strpos($v,':') ? $this->expandQname($v) : $v;
6283  $aa[$k] = $v;
6284  }
6285  $eAttrs[$n] = $aa;
6286  }
6287  $attrs = $eAttrs;
6288  }
6289 
6290  $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6291  $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
6292 
6293  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6294  $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
6295  }
6296 
6308  function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
6309  $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6310 
6311  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6312  $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
6313  }
6314 
6322  function addElement($attrs) {
6323  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6324  $this->schemas[$typens][0]->addElement($attrs);
6325  }
6326 
6341  function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){
6342  if ($use == 'encoded' && $encodingStyle == '') {
6343  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6344  }
6345 
6346  if ($style == 'document') {
6347  $elements = array();
6348  foreach ($in as $n => $t) {
6349  $elements[$n] = array('name' => $n, 'type' => $t);
6350  }
6351  $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
6352  $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
6353  $in = array('parameters' => 'tns:' . $name . '^');
6354 
6355  $elements = array();
6356  foreach ($out as $n => $t) {
6357  $elements[$n] = array('name' => $n, 'type' => $t);
6358  }
6359  $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
6360  $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
6361  $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
6362  }
6363 
6364  // get binding
6365  $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
6366  array(
6367  'name' => $name,
6368  'binding' => $this->serviceName . 'Binding',
6369  'endpoint' => $this->endpoint,
6370  'soapAction' => $soapaction,
6371  'style' => $style,
6372  'input' => array(
6373  'use' => $use,
6374  'namespace' => $namespace,
6375  'encodingStyle' => $encodingStyle,
6376  'message' => $name . 'Request',
6377  'parts' => $in),
6378  'output' => array(
6379  'use' => $use,
6380  'namespace' => $namespace,
6381  'encodingStyle' => $encodingStyle,
6382  'message' => $name . 'Response',
6383  'parts' => $out),
6384  'namespace' => $namespace,
6385  'transport' => 'http://schemas.xmlsoap.org/soap/http',
6386  'documentation' => $documentation);
6387  // add portTypes
6388  // add messages
6389  if($in)
6390  {
6391  foreach($in as $pName => $pType)
6392  {
6393  if(strpos($pType,':')) {
6394  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
6395  }
6396  $this->messages[$name.'Request'][$pName] = $pType;
6397  }
6398  } else {
6399  $this->messages[$name.'Request']= '0';
6400  }
6401  if($out)
6402  {
6403  foreach($out as $pName => $pType)
6404  {
6405  if(strpos($pType,':')) {
6406  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
6407  }
6408  $this->messages[$name.'Response'][$pName] = $pType;
6409  }
6410  } else {
6411  $this->messages[$name.'Response']= '0';
6412  }
6413  return true;
6414  }
6415 }
6416 ?><?php
6417 
6418 
6419 
6429 class nusoap_parser extends nusoap_base {
6430 
6431  var $xml = '';
6432  var $xml_encoding = '';
6433  var $method = '';
6434  var $root_struct = '';
6435  var $root_struct_name = '';
6436  var $root_struct_namespace = '';
6437  var $root_header = '';
6438  var $document = ''; // incoming SOAP body (text)
6439  // determines where in the message we are (envelope,header,body,method)
6440  var $status = '';
6441  var $position = 0;
6442  var $depth = 0;
6443  var $default_namespace = '';
6444  var $namespaces = array();
6445  var $message = array();
6446  var $parent = '';
6447  var $fault = false;
6448  var $fault_code = '';
6449  var $fault_str = '';
6450  var $fault_detail = '';
6451  var $depth_array = array();
6452  var $debug_flag = true;
6453  var $soapresponse = NULL; // parsed SOAP Body
6454  var $soapheader = NULL; // parsed SOAP Header
6455  var $responseHeaders = ''; // incoming SOAP headers (text)
6456  var $body_position = 0;
6457  // for multiref parsing:
6458  // array of id => pos
6459  var $ids = array();
6460  // array of id => hrefs => pos
6461  var $multirefs = array();
6462  // toggle for auto-decoding element content
6463  var $decode_utf8 = true;
6464 
6474  function __construct($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
6476  $this->xml = $xml;
6477  $this->xml_encoding = $encoding;
6478  $this->method = $method;
6479  $this->decode_utf8 = $decode_utf8;
6480 
6481  // Check whether content has been read.
6482  if(!empty($xml)){
6483  // Check XML encoding
6484  $pos_xml = strpos($xml, '<?xml');
6485  if ($pos_xml !== FALSE) {
6486  $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
6487  if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
6488  $xml_encoding = $res[1];
6489  if (strtoupper($xml_encoding) != $encoding) {
6490  $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
6491  $this->debug($err);
6492  if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
6493  $this->setError($err);
6494  return;
6495  }
6496  // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
6497  } else {
6498  $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
6499  }
6500  } else {
6501  $this->debug('No encoding specified in XML declaration');
6502  }
6503  } else {
6504  $this->debug('No XML declaration');
6505  }
6506  $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding);
6507  // Create an XML parser - why not xml_parser_create_ns?
6508  $this->parser = xml_parser_create($this->xml_encoding);
6509  // Set the options for parsing the XML data.
6510  //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
6511  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
6512  xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
6513  // Set the object for the parser.
6514  xml_set_object($this->parser, $this);
6515  // Set the element handlers for the parser.
6516  xml_set_element_handler($this->parser, 'start_element','end_element');
6517  xml_set_character_data_handler($this->parser,'character_data');
6518 
6519  // Parse the XML file.
6520  if(!xml_parse($this->parser,$xml,true)){
6521  // Display an error message.
6522  $err = sprintf('XML error parsing SOAP payload on line %d: %s',
6523  xml_get_current_line_number($this->parser),
6524  xml_error_string(xml_get_error_code($this->parser)));
6525  $this->debug($err);
6526  $this->debug("XML payload:\n" . $xml);
6527  $this->setError($err);
6528  } else {
6529  $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
6530  // get final value
6531  $this->soapresponse = $this->message[$this->root_struct]['result'];
6532  // get header value
6533  if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
6534  $this->soapheader = $this->message[$this->root_header]['result'];
6535  }
6536  // resolve hrefs/ids
6537  if(sizeof($this->multirefs) > 0){
6538  foreach($this->multirefs as $id => $hrefs){
6539  $this->debug('resolving multirefs for id: '.$id);
6540  $idVal = $this->buildVal($this->ids[$id]);
6541  if (is_array($idVal) && isset($idVal['!id'])) {
6542  unset($idVal['!id']);
6543  }
6544  foreach($hrefs as $refPos => $ref){
6545  $this->debug('resolving href at pos '.$refPos);
6546  $this->multirefs[$id][$refPos] = $idVal;
6547  }
6548  }
6549  }
6550  }
6551  xml_parser_free($this->parser);
6552  } else {
6553  $this->debug('xml was empty, didn\'t parse!');
6554  $this->setError('xml was empty, didn\'t parse!');
6555  }
6556  }
6557 
6566  function start_element($parser, $name, $attrs) {
6567  // position in a total number of elements, starting from 0
6568  // update class level pos
6569  $pos = $this->position++;
6570  // and set mine
6571  $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
6572  // depth = how many levels removed from root?
6573  // set mine as current global depth and increment global depth value
6574  $this->message[$pos]['depth'] = $this->depth++;
6575 
6576  // else add self as child to whoever the current parent is
6577  if($pos != 0){
6578  $this->message[$this->parent]['children'] .= '|'.$pos;
6579  }
6580  // set my parent
6581  $this->message[$pos]['parent'] = $this->parent;
6582  // set self as current parent
6583  $this->parent = $pos;
6584  // set self as current value for this depth
6585  $this->depth_array[$this->depth] = $pos;
6586  // get element prefix
6587  if(strpos($name,':')){
6588  // get ns prefix
6589  $prefix = substr($name,0,strpos($name,':'));
6590  // get unqualified name
6591  $name = substr(strstr($name,':'),1);
6592  }
6593  // set status
6594  if($name == 'Envelope'){
6595  $this->status = 'envelope';
6596  } elseif($name == 'Header' && $this->status = 'envelope'){
6597  $this->root_header = $pos;
6598  $this->status = 'header';
6599  } elseif($name == 'Body' && $this->status = 'envelope'){
6600  $this->status = 'body';
6601  $this->body_position = $pos;
6602  // set method
6603  } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
6604  $this->status = 'method';
6605  $this->root_struct_name = $name;
6606  $this->root_struct = $pos;
6607  $this->message[$pos]['type'] = 'struct';
6608  $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
6609  }
6610  // set my status
6611  $this->message[$pos]['status'] = $this->status;
6612  // set name
6613  $this->message[$pos]['name'] = htmlspecialchars($name);
6614  // set attrs
6615  $this->message[$pos]['attrs'] = $attrs;
6616 
6617  // loop through atts, logging ns and type declarations
6618  $attstr = '';
6619  foreach($attrs as $key => $value){
6620  $key_prefix = $this->getPrefix($key);
6621  $key_localpart = $this->getLocalPart($key);
6622  // if ns declarations, add to class level array of valid namespaces
6623  if($key_prefix == 'xmlns'){
6624  if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){
6625  $this->XMLSchemaVersion = $value;
6626  $this->namespaces['xsd'] = $this->XMLSchemaVersion;
6627  $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
6628  }
6629  $this->namespaces[$key_localpart] = $value;
6630  // set method namespace
6631  if($name == $this->root_struct_name){
6632  $this->methodNamespace = $value;
6633  }
6634  // if it's a type declaration, set type
6635  } elseif($key_localpart == 'type'){
6636  if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
6637  // do nothing: already processed arrayType
6638  } else {
6639  $value_prefix = $this->getPrefix($value);
6640  $value_localpart = $this->getLocalPart($value);
6641  $this->message[$pos]['type'] = $value_localpart;
6642  $this->message[$pos]['typePrefix'] = $value_prefix;
6643  if(isset($this->namespaces[$value_prefix])){
6644  $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
6645  } else if(isset($attrs['xmlns:'.$value_prefix])) {
6646  $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
6647  }
6648  // should do something here with the namespace of specified type?
6649  }
6650  } elseif($key_localpart == 'arrayType'){
6651  $this->message[$pos]['type'] = 'array';
6652  /* do arrayType ereg here
6653  [1] arrayTypeValue ::= atype asize
6654  [2] atype ::= QName rank*
6655  [3] rank ::= '[' (',')* ']'
6656  [4] asize ::= '[' length~ ']'
6657  [5] length ::= nextDimension* Digit+
6658  [6] nextDimension ::= Digit+ ','
6659  */
6660  $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
6661  if(preg_match($expr,$value,$regs)){
6662  $this->message[$pos]['typePrefix'] = $regs[1];
6663  $this->message[$pos]['arrayTypePrefix'] = $regs[1];
6664  if (isset($this->namespaces[$regs[1]])) {
6665  $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
6666  } else if (isset($attrs['xmlns:'.$regs[1]])) {
6667  $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
6668  }
6669  $this->message[$pos]['arrayType'] = $regs[2];
6670  $this->message[$pos]['arraySize'] = $regs[3];
6671  $this->message[$pos]['arrayCols'] = $regs[4];
6672  }
6673  // specifies nil value (or not)
6674  } elseif ($key_localpart == 'nil'){
6675  $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
6676  // some other attribute
6677  } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
6678  $this->message[$pos]['xattrs']['!' . $key] = $value;
6679  }
6680 
6681  if ($key == 'xmlns') {
6682  $this->default_namespace = $value;
6683  }
6684  // log id
6685  if($key == 'id'){
6686  $this->ids[$value] = $pos;
6687  }
6688  // root
6689  if($key_localpart == 'root' && $value == 1){
6690  $this->status = 'method';
6691  $this->root_struct_name = $name;
6692  $this->root_struct = $pos;
6693  $this->debug("found root struct $this->root_struct_name, pos $pos");
6694  }
6695  // for doclit
6696  $attstr .= " $key=\"$value\"";
6697  }
6698  // get namespace - must be done after namespace atts are processed
6699  if(isset($prefix)){
6700  $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
6701  $this->default_namespace = $this->namespaces[$prefix];
6702  } else {
6703  $this->message[$pos]['namespace'] = $this->default_namespace;
6704  }
6705  if($this->status == 'header'){
6706  if ($this->root_header != $pos) {
6707  $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6708  }
6709  } elseif($this->root_struct_name != ''){
6710  $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6711  }
6712  }
6713 
6721  function end_element($parser, $name) {
6722  // position of current element is equal to the last value left in depth_array for my depth
6723  $pos = $this->depth_array[$this->depth--];
6724 
6725  // get element prefix
6726  if(strpos($name,':')){
6727  // get ns prefix
6728  $prefix = substr($name,0,strpos($name,':'));
6729  // get unqualified name
6730  $name = substr(strstr($name,':'),1);
6731  }
6732 
6733  // build to native type
6734  if(isset($this->body_position) && $pos > $this->body_position){
6735  // deal w/ multirefs
6736  if(isset($this->message[$pos]['attrs']['href'])){
6737  // get id
6738  $id = substr($this->message[$pos]['attrs']['href'],1);
6739  // add placeholder to href array
6740  $this->multirefs[$id][$pos] = 'placeholder';
6741  // add set a reference to it as the result value
6742  $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
6743  // build complexType values
6744  } elseif($this->message[$pos]['children'] != ''){
6745  // if result has already been generated (struct/array)
6746  if(!isset($this->message[$pos]['result'])){
6747  $this->message[$pos]['result'] = $this->buildVal($pos);
6748  }
6749  // build complexType values of attributes and possibly simpleContent
6750  } elseif (isset($this->message[$pos]['xattrs'])) {
6751  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6752  $this->message[$pos]['xattrs']['!'] = null;
6753  } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
6754  if (isset($this->message[$pos]['type'])) {
6755  $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6756  } else {
6757  $parent = $this->message[$pos]['parent'];
6758  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6759  $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6760  } else {
6761  $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
6762  }
6763  }
6764  }
6765  $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
6766  // set value of simpleType (or nil complexType)
6767  } else {
6768  //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
6769  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6770  $this->message[$pos]['xattrs']['!'] = null;
6771  } elseif (isset($this->message[$pos]['type'])) {
6772  $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6773  } else {
6774  $parent = $this->message[$pos]['parent'];
6775  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6776  $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6777  } else {
6778  $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
6779  }
6780  }
6781 
6782  /* add value to parent's result, if parent is struct/array
6783  $parent = $this->message[$pos]['parent'];
6784  if($this->message[$parent]['type'] != 'map'){
6785  if(strtolower($this->message[$parent]['type']) == 'array'){
6786  $this->message[$parent]['result'][] = $this->message[$pos]['result'];
6787  } else {
6788  $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
6789  }
6790  }
6791  */
6792  }
6793  }
6794 
6795  // for doclit
6796  if($this->status == 'header'){
6797  if ($this->root_header != $pos) {
6798  $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6799  }
6800  } elseif($pos >= $this->root_struct){
6801  $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6802  }
6803  // switch status
6804  if($pos == $this->root_struct){
6805  $this->status = 'body';
6806  $this->root_struct_namespace = $this->message[$pos]['namespace'];
6807  } elseif($name == 'Body'){
6808  $this->status = 'envelope';
6809  } elseif($name == 'Header'){
6810  $this->status = 'envelope';
6811  } elseif($name == 'Envelope'){
6812  //
6813  }
6814  // set parent back to my parent
6815  $this->parent = $this->message[$pos]['parent'];
6816  }
6817 
6825  function character_data($parser, $data){
6826  $pos = $this->depth_array[$this->depth];
6827  if ($this->xml_encoding=='UTF-8'){
6828  // TODO: add an option to disable this for folks who want
6829  // raw UTF-8 that, e.g., might not map to iso-8859-1
6830  // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
6831  if($this->decode_utf8){
6832  $data = utf8_decode($data);
6833  }
6834  }
6835  $this->message[$pos]['cdata'] .= $data;
6836  // for doclit
6837  if($this->status == 'header'){
6838  $this->responseHeaders .= $data;
6839  } else {
6840  $this->document .= $data;
6841  }
6842  }
6843 
6851  function get_response(){
6852  return $this->soapresponse;
6853  }
6854 
6861  function get_soapbody(){
6862  return $this->soapresponse;
6863  }
6864 
6871  function get_soapheader(){
6872  return $this->soapheader;
6873  }
6874 
6881  function getHeaders(){
6882  return $this->responseHeaders;
6883  }
6884 
6894  function decodeSimple($value, $type, $typens) {
6895  // TODO: use the namespace!
6896  if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
6897  return (string) $value;
6898  }
6899  if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
6900  return (int) $value;
6901  }
6902  if ($type == 'float' || $type == 'double' || $type == 'decimal') {
6903  return (double) $value;
6904  }
6905  if ($type == 'boolean') {
6906  if (strtolower($value) == 'false' || strtolower($value) == 'f') {
6907  return false;
6908  }
6909  return (boolean) $value;
6910  }
6911  if ($type == 'base64' || $type == 'base64Binary') {
6912  $this->debug('Decode base64 value');
6913  return base64_decode($value);
6914  }
6915  // obscure numeric types
6916  if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
6917  || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
6918  || $type == 'unsignedInt'
6919  || $type == 'unsignedShort' || $type == 'unsignedByte') {
6920  return (int) $value;
6921  }
6922  // bogus: parser treats array with no elements as a simple type
6923  if ($type == 'array') {
6924  return array();
6925  }
6926  // everything else
6927  return (string) $value;
6928  }
6929 
6938  function buildVal($pos){
6939  if(!isset($this->message[$pos]['type'])){
6940  $this->message[$pos]['type'] = '';
6941  }
6942  $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
6943  // if there are children...
6944  if($this->message[$pos]['children'] != ''){
6945  $this->debug('in buildVal, there are children');
6946  $children = explode('|',$this->message[$pos]['children']);
6947  array_shift($children); // knock off empty
6948  // md array
6949  if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
6950  $r=0; // rowcount
6951  $c=0; // colcount
6952  foreach($children as $child_pos){
6953  $this->debug("in buildVal, got an MD array element: $r, $c");
6954  $params[$r][] = $this->message[$child_pos]['result'];
6955  $c++;
6956  if($c == $this->message[$pos]['arrayCols']){
6957  $c = 0;
6958  $r++;
6959  }
6960  }
6961  // array
6962  } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
6963  $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
6964  foreach($children as $child_pos){
6965  $params[] = &$this->message[$child_pos]['result'];
6966  }
6967  // apache Map type: java hashtable
6968  } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
6969  $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
6970  foreach($children as $child_pos){
6971  $kv = explode("|",$this->message[$child_pos]['children']);
6972  $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
6973  }
6974  // generic compound type
6975  //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
6976  } else {
6977  // Apache Vector type: treat as an array
6978  $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']);
6979  if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
6980  $notstruct = 1;
6981  } else {
6982  $notstruct = 0;
6983  }
6984  //
6985  foreach($children as $child_pos){
6986  if($notstruct){
6987  $params[] = &$this->message[$child_pos]['result'];
6988  } else {
6989  if (isset($params[$this->message[$child_pos]['name']])) {
6990  // de-serialize repeated element name into an array
6991  if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
6992  $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
6993  }
6994  $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
6995  } else {
6996  $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
6997  }
6998  }
6999  }
7000  }
7001  if (isset($this->message[$pos]['xattrs'])) {
7002  $this->debug('in buildVal, handling attributes');
7003  foreach ($this->message[$pos]['xattrs'] as $n => $v) {
7004  $params[$n] = $v;
7005  }
7006  }
7007  // handle simpleContent
7008  if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
7009  $this->debug('in buildVal, handling simpleContent');
7010  if (isset($this->message[$pos]['type'])) {
7011  $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7012  } else {
7013  $parent = $this->message[$pos]['parent'];
7014  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
7015  $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7016  } else {
7017  $params['!'] = $this->message[$pos]['cdata'];
7018  }
7019  }
7020  }
7021  $ret = is_array($params) ? $params : array();
7022  $this->debug('in buildVal, return:');
7023  $this->appendDebug($this->varDump($ret));
7024  return $ret;
7025  } else {
7026  $this->debug('in buildVal, no children, building scalar');
7027  $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
7028  if (isset($this->message[$pos]['type'])) {
7029  $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7030  $this->debug("in buildVal, return: $ret");
7031  return $ret;
7032  }
7033  $parent = $this->message[$pos]['parent'];
7034  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
7035  $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7036  $this->debug("in buildVal, return: $ret");
7037  return $ret;
7038  }
7039  $ret = $this->message[$pos]['cdata'];
7040  $this->debug("in buildVal, return: $ret");
7041  return $ret;
7042  }
7043  }
7044 }
7045 
7049 class soap_parser extends nusoap_parser {
7050 }
7051 
7052 ?><?php
7053 
7054 
7055 
7076 class nusoap_client extends nusoap_base {
7077 
7078  var $username = ''; // Username for HTTP authentication
7079  var $password = ''; // Password for HTTP authentication
7080  var $authtype = ''; // Type of HTTP authentication
7081  var $certRequest = array(); // Certificate for HTTP SSL authentication
7082  var $requestHeaders = false; // SOAP headers in request (text)
7083  var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
7084  var $responseHeader = NULL; // SOAP Header from response (parsed)
7085  var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
7086  var $endpoint;
7087  var $forceEndpoint = ''; // overrides WSDL endpoint
7088  var $proxyhost = '';
7089  var $proxyport = '';
7090  var $proxyusername = '';
7091  var $proxypassword = '';
7092  var $xml_encoding = ''; // character set encoding of incoming (response) messages
7093  var $http_encoding = false;
7094  var $timeout = 0; // HTTP connection timeout
7095  var $response_timeout = 30; // HTTP response timeout
7096  var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error
7097  var $persistentConnection = false;
7098  var $defaultRpcParams = false; // This is no longer used
7099  var $request = ''; // HTTP request
7100  var $response = ''; // HTTP response
7101  var $responseData = ''; // SOAP payload of response
7102  var $cookies = array(); // Cookies from response or for request
7103  var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
7104  var $operations = array(); // WSDL operations, empty for WSDL initialization error
7105  var $curl_options = array(); // User-specified cURL options
7106  var $bindingType = ''; // WSDL operation binding type
7107  var $use_curl = false; // whether to always try to use cURL
7108 
7109  /*
7110  * fault related variables
7111  */
7116  var $fault;
7121  var $faultcode;
7126  var $faultstring;
7131  var $faultdetail;
7132 
7147  function __construct($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
7149  $this->endpoint = $endpoint;
7150  $this->proxyhost = $proxyhost;
7151  $this->proxyport = $proxyport;
7152  $this->proxyusername = $proxyusername;
7153  $this->proxypassword = $proxypassword;
7154  $this->timeout = $timeout;
7155  $this->response_timeout = $response_timeout;
7156 
7157  $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
7158  $this->appendDebug('endpoint=' . $this->varDump($endpoint));
7159 
7160  // make values
7161  if($wsdl){
7162  if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
7163  $this->wsdl = $endpoint;
7164  $this->endpoint = $this->wsdl->wsdl;
7165  $this->wsdlFile = $this->endpoint;
7166  $this->debug('existing wsdl instance created from ' . $this->endpoint);
7167  $this->checkWSDL();
7168  } else {
7169  $this->wsdlFile = $this->endpoint;
7170  $this->wsdl = null;
7171  $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
7172  }
7173  $this->endpointType = 'wsdl';
7174  } else {
7175  $this->debug("instantiate SOAP with endpoint at $endpoint");
7176  $this->endpointType = 'soap';
7177  }
7178  }
7179 
7205  function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
7206  $this->operation = $operation;
7207  $this->fault = false;
7208  $this->setError('');
7209  $this->request = '';
7210  $this->response = '';
7211  $this->responseData = '';
7212  $this->faultstring = '';
7213  $this->faultcode = '';
7214  $this->opData = array();
7215 
7216  $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
7217  $this->appendDebug('params=' . $this->varDump($params));
7218  $this->appendDebug('headers=' . $this->varDump($headers));
7219  if ($headers) {
7220  $this->requestHeaders = $headers;
7221  }
7222  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7223  $this->loadWSDL();
7224  if ($this->getError())
7225  return false;
7226  }
7227  // serialize parameters
7228  if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
7229  // use WSDL for operation
7230  $this->opData = $opData;
7231  $this->debug("found operation");
7232  $this->appendDebug('opData=' . $this->varDump($opData));
7233  if (isset($opData['soapAction'])) {
7234  $soapAction = $opData['soapAction'];
7235  }
7236  if (! $this->forceEndpoint) {
7237  $this->endpoint = $opData['endpoint'];
7238  } else {
7239  $this->endpoint = $this->forceEndpoint;
7240  }
7241  $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace;
7242  $style = $opData['style'];
7243  $use = $opData['input']['use'];
7244  // add ns to ns array
7245  if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
7246  $nsPrefix = 'ns' . rand(1000, 9999);
7247  $this->wsdl->namespaces[$nsPrefix] = $namespace;
7248  }
7249  $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
7250  // serialize payload
7251  if (is_string($params)) {
7252  $this->debug("serializing param string for WSDL operation $operation");
7253  $payload = $params;
7254  } elseif (is_array($params)) {
7255  $this->debug("serializing param array for WSDL operation $operation");
7256  $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType);
7257  } else {
7258  $this->debug('params must be array or string');
7259  $this->setError('params must be array or string');
7260  return false;
7261  }
7262  $usedNamespaces = $this->wsdl->usedNamespaces;
7263  if (isset($opData['input']['encodingStyle'])) {
7264  $encodingStyle = $opData['input']['encodingStyle'];
7265  } else {
7266  $encodingStyle = '';
7267  }
7268  $this->appendDebug($this->wsdl->getDebug());
7269  $this->wsdl->clearDebug();
7270  if ($errstr = $this->wsdl->getError()) {
7271  $this->debug('got wsdl error: '.$errstr);
7272  $this->setError('wsdl error: '.$errstr);
7273  return false;
7274  }
7275  } elseif($this->endpointType == 'wsdl') {
7276  // operation not in WSDL
7277  $this->appendDebug($this->wsdl->getDebug());
7278  $this->wsdl->clearDebug();
7279  $this->setError( 'operation '.$operation.' not present.');
7280  $this->debug("operation '$operation' not present.");
7281  return false;
7282  } else {
7283  // no WSDL
7284  //$this->namespaces['ns1'] = $namespace;
7285  $nsPrefix = 'ns' . rand(1000, 9999);
7286  // serialize
7287  $payload = '';
7288  if (is_string($params)) {
7289  $this->debug("serializing param string for operation $operation");
7290  $payload = $params;
7291  } elseif (is_array($params)) {
7292  $this->debug("serializing param array for operation $operation");
7293  foreach($params as $k => $v){
7294  $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
7295  }
7296  } else {
7297  $this->debug('params must be array or string');
7298  $this->setError('params must be array or string');
7299  return false;
7300  }
7301  $usedNamespaces = array();
7302  if ($use == 'encoded') {
7303  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7304  } else {
7305  $encodingStyle = '';
7306  }
7307  }
7308  // wrap RPC calls with method element
7309  if ($style == 'rpc') {
7310  if ($use == 'literal') {
7311  $this->debug("wrapping RPC request with literal method element");
7312  if ($namespace) {
7313  // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
7314  $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7315  $payload .
7316  "</$nsPrefix:$operation>";
7317  } else {
7318  $payload = "<$operation>" . $payload . "</$operation>";
7319  }
7320  } else {
7321  $this->debug("wrapping RPC request with encoded method element");
7322  if ($namespace) {
7323  $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7324  $payload .
7325  "</$nsPrefix:$operation>";
7326  } else {
7327  $payload = "<$operation>" .
7328  $payload .
7329  "</$operation>";
7330  }
7331  }
7332  }
7333  // serialize envelope
7334  $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);
7335  $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
7336  $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
7337  // send
7338  $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
7339  if($errstr = $this->getError()){
7340  $this->debug('Error: '.$errstr);
7341  return false;
7342  } else {
7343  $this->return = $return;
7344  $this->debug('sent message successfully and got a(n) '.gettype($return));
7345  $this->appendDebug('return=' . $this->varDump($return));
7346 
7347  // fault?
7348  if(is_array($return) && isset($return['faultcode'])){
7349  $this->debug('got fault');
7350  $this->setError($return['faultcode'].': '.$return['faultstring']);
7351  $this->fault = true;
7352  foreach($return as $k => $v){
7353  $this->$k = $v;
7354  $this->debug("$k = $v<br>");
7355  }
7356  return $return;
7357  } elseif ($style == 'document') {
7358  // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
7359  // we are only going to return the first part here...sorry about that
7360  return $return;
7361  } else {
7362  // array of return values
7363  if(is_array($return)){
7364  // multiple 'out' parameters, which we return wrapped up
7365  // in the array
7366  if(sizeof($return) > 1){
7367  return $return;
7368  }
7369  // single 'out' parameter (normally the return value)
7370  $return = array_shift($return);
7371  $this->debug('return shifted value: ');
7372  $this->appendDebug($this->varDump($return));
7373  return $return;
7374  // nothing returned (ie, echoVoid)
7375  } else {
7376  return "";
7377  }
7378  }
7379  }
7380  }
7381 
7387  function checkWSDL() {
7388  $this->appendDebug($this->wsdl->getDebug());
7389  $this->wsdl->clearDebug();
7390  $this->debug('checkWSDL');
7391  // catch errors
7392  if ($errstr = $this->wsdl->getError()) {
7393  $this->debug('got wsdl error: '.$errstr);
7394  $this->setError('wsdl error: '.$errstr);
7395  } elseif ($this->operations = $this->wsdl->getOperations('soap')) {
7396  $this->bindingType = 'soap';
7397  $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
7398  } elseif ($this->operations = $this->wsdl->getOperations('soap12')) {
7399  $this->bindingType = 'soap12';
7400  $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
7401  $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
7402  } else {
7403  $this->debug('getOperations returned false');
7404  $this->setError('no operations defined in the WSDL document!');
7405  }
7406  }
7407 
7413  function loadWSDL() {
7414  $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile);
7415  $this->wsdl = new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl);
7416  $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
7417  $this->wsdl->fetchWSDL($this->wsdlFile);
7418  $this->checkWSDL();
7419  }
7420 
7428  function getOperationData($operation){
7429  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7430  $this->loadWSDL();
7431  if ($this->getError())
7432  return false;
7433  }
7434  if(isset($this->operations[$operation])){
7435  return $this->operations[$operation];
7436  }
7437  $this->debug("No data for operation: $operation");
7438  }
7439 
7454  function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
7455  $this->checkCookies();
7456  // detect transport
7457  switch(true){
7458  // http(s)
7459  case preg_match('/^http/',$this->endpoint):
7460  $this->debug('transporting via HTTP');
7461  if($this->persistentConnection == true && is_object($this->persistentConnection)){
7462  $http =& $this->persistentConnection;
7463  } else {
7464  $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
7465  if ($this->persistentConnection) {
7466  $http->usePersistentConnection();
7467  }
7468  }
7469  $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
7470  $http->setSOAPAction($soapaction);
7471  if($this->proxyhost && $this->proxyport){
7472  $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
7473  }
7474  if($this->authtype != '') {
7475  $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
7476  }
7477  if($this->http_encoding != ''){
7478  $http->setEncoding($this->http_encoding);
7479  }
7480  $this->debug('sending message, length='.strlen($msg));
7481  if(preg_match('/^http:/',$this->endpoint)){
7482  //if(strpos($this->endpoint,'http:')){
7483  $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);
7484  } elseif(preg_match('/^https/',$this->endpoint)){
7485  //} elseif(strpos($this->endpoint,'https:')){
7486  //if(phpversion() == '4.3.0-dev'){
7487  //$response = $http->send($msg,$timeout,$response_timeout);
7488  //$this->request = $http->outgoing_payload;
7489  //$this->response = $http->incoming_payload;
7490  //} else
7491  $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);
7492  } else {
7493  $this->setError('no http/s in endpoint url');
7494  }
7495  $this->request = $http->outgoing_payload;
7496  $this->response = $http->incoming_payload;
7497  $this->appendDebug($http->getDebug());
7498  $this->UpdateCookies($http->incoming_cookies);
7499 
7500  // save transport object if using persistent connections
7501  if ($this->persistentConnection) {
7502  $http->clearDebug();
7503  if (!is_object($this->persistentConnection)) {
7504  $this->persistentConnection = $http;
7505  }
7506  }
7507 
7508  if($err = $http->getError()){
7509  $this->setError('HTTP Error: '.$err);
7510  return false;
7511  } elseif($this->getError()){
7512  return false;
7513  } else {
7514  $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
7515  return $this->parseResponse($http->incoming_headers, $this->responseData);
7516  }
7517  break;
7518  default:
7519  $this->setError('no transport found, or selected transport is not yet supported!');
7520  return false;
7521  break;
7522  }
7523  }
7524 
7533  function parseResponse($headers, $data) {
7534  $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
7535  $this->appendDebug($this->varDump($headers));
7536  if (!strstr($headers['content-type'], 'text/xml')) {
7537  $this->setError('Response not of type text/xml: ' . $headers['content-type']);
7538  return false;
7539  }
7540  if (strpos($headers['content-type'], '=')) {
7541  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
7542  $this->debug('Got response encoding: ' . $enc);
7543  if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
7544  $this->xml_encoding = strtoupper($enc);
7545  } else {
7546  $this->xml_encoding = 'US-ASCII';
7547  }
7548  } else {
7549  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
7550  $this->xml_encoding = 'ISO-8859-1';
7551  }
7552  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
7553  $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
7554  // add parser debug data to our debug
7555  $this->appendDebug($parser->getDebug());
7556  // if parse errors
7557  if($errstr = $parser->getError()){
7558  $this->setError( $errstr);
7559  // destroy the parser object
7560  unset($parser);
7561  return false;
7562  } else {
7563  // get SOAP headers
7564  $this->responseHeaders = $parser->getHeaders();
7565  // get SOAP headers
7566  $this->responseHeader = $parser->get_soapheader();
7567  // get decoded message
7568  $return = $parser->get_soapbody();
7569  // add document for doclit support
7570  $this->document = $parser->document;
7571  // destroy the parser object
7572  unset($parser);
7573  // return decode message
7574  return $return;
7575  }
7576  }
7577 
7585  function setCurlOption($option, $value) {
7586  $this->debug("setCurlOption option=$option, value=");
7587  $this->appendDebug($this->varDump($value));
7588  $this->curl_options[$option] = $value;
7589  }
7590 
7597  function setEndpoint($endpoint) {
7598  $this->debug("setEndpoint(\"$endpoint\")");
7599  $this->forceEndpoint = $endpoint;
7600  }
7601 
7608  function setHeaders($headers){
7609  $this->debug("setHeaders headers=");
7610  $this->appendDebug($this->varDump($headers));
7611  $this->requestHeaders = $headers;
7612  }
7613 
7620  function getHeaders(){
7621  return $this->responseHeaders;
7622  }
7623 
7630  function getHeader(){
7631  return $this->responseHeader;
7632  }
7633 
7643  function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
7644  $this->proxyhost = $proxyhost;
7645  $this->proxyport = $proxyport;
7646  $this->proxyusername = $proxyusername;
7647  $this->proxypassword = $proxypassword;
7648  }
7649 
7659  function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
7660  $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
7661  $this->appendDebug($this->varDump($certRequest));
7662  $this->username = $username;
7663  $this->password = $password;
7664  $this->authtype = $authtype;
7665  $this->certRequest = $certRequest;
7666  }
7667 
7674  function setHTTPEncoding($enc='gzip, deflate'){
7675  $this->debug("setHTTPEncoding(\"$enc\")");
7676  $this->http_encoding = $enc;
7677  }
7678 
7685  function setUseCURL($use) {
7686  $this->debug("setUseCURL($use)");
7687  $this->use_curl = $use;
7688  }
7689 
7695  function useHTTPPersistentConnection(){
7696  $this->debug("useHTTPPersistentConnection");
7697  $this->persistentConnection = true;
7698  }
7699 
7711  function getDefaultRpcParams() {
7712  return $this->defaultRpcParams;
7713  }
7714 
7726  function setDefaultRpcParams($rpcParams) {
7727  $this->defaultRpcParams = $rpcParams;
7728  }
7729 
7737  function getProxy() {
7738  $r = rand();
7739  $evalStr = $this->_getProxyClassCode($r);
7740  //$this->debug("proxy class: $evalStr");
7741  if ($this->getError()) {
7742  $this->debug("Error from _getProxyClassCode, so return NULL");
7743  return null;
7744  }
7745  // eval the class
7746  eval($evalStr);
7747  // instantiate proxy object
7748  eval("\$proxy = new nusoap_proxy_$r('');");
7749  // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
7750  $proxy->endpointType = 'wsdl';
7751  $proxy->wsdlFile = $this->wsdlFile;
7752  $proxy->wsdl = $this->wsdl;
7753  $proxy->operations = $this->operations;
7754  $proxy->defaultRpcParams = $this->defaultRpcParams;
7755  // transfer other state
7756  $proxy->soap_defencoding = $this->soap_defencoding;
7757  $proxy->username = $this->username;
7758  $proxy->password = $this->password;
7759  $proxy->authtype = $this->authtype;
7760  $proxy->certRequest = $this->certRequest;
7761  $proxy->requestHeaders = $this->requestHeaders;
7762  $proxy->endpoint = $this->endpoint;
7763  $proxy->forceEndpoint = $this->forceEndpoint;
7764  $proxy->proxyhost = $this->proxyhost;
7765  $proxy->proxyport = $this->proxyport;
7766  $proxy->proxyusername = $this->proxyusername;
7767  $proxy->proxypassword = $this->proxypassword;
7768  $proxy->http_encoding = $this->http_encoding;
7769  $proxy->timeout = $this->timeout;
7770  $proxy->response_timeout = $this->response_timeout;
7771  $proxy->persistentConnection = &$this->persistentConnection;
7772  $proxy->decode_utf8 = $this->decode_utf8;
7773  $proxy->curl_options = $this->curl_options;
7774  $proxy->bindingType = $this->bindingType;
7775  $proxy->use_curl = $this->use_curl;
7776  return $proxy;
7777  }
7778 
7785  function _getProxyClassCode($r) {
7786  $this->debug("in getProxy endpointType=$this->endpointType");
7787  $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
7788  if ($this->endpointType != 'wsdl') {
7789  $evalStr = 'A proxy can only be created for a WSDL client';
7790  $this->setError($evalStr);
7791  $evalStr = "echo \"$evalStr\";";
7792  return $evalStr;
7793  }
7794  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7795  $this->loadWSDL();
7796  if ($this->getError()) {
7797  return "echo \"" . $this->getError() . "\";";
7798  }
7799  }
7800  $evalStr = '';
7801  foreach ($this->operations as $operation => $opData) {
7802  if ($operation != '') {
7803  // create param string and param comment string
7804  if (sizeof($opData['input']['parts']) > 0) {
7805  $paramStr = '';
7806  $paramArrayStr = '';
7807  $paramCommentStr = '';
7808  foreach ($opData['input']['parts'] as $name => $type) {
7809  $paramStr .= "\$$name, ";
7810  $paramArrayStr .= "'$name' => \$$name, ";
7811  $paramCommentStr .= "$type \$$name, ";
7812  }
7813  $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
7814  $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
7815  $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
7816  } else {
7817  $paramStr = '';
7818  $paramArrayStr = '';
7819  $paramCommentStr = 'void';
7820  }
7821  $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
7822  $evalStr .= "// $paramCommentStr
7823  function " . str_replace('.', '__', $operation) . "($paramStr) {
7824  \$params = array($paramArrayStr);
7825  return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
7826  }
7827  ";
7828  unset($paramStr);
7829  unset($paramCommentStr);
7830  }
7831  }
7832  $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client {
7833  '.$evalStr.'
7834 }';
7835  return $evalStr;
7836  }
7837 
7844  function getProxyClassCode() {
7845  $r = rand();
7846  return $this->_getProxyClassCode($r);
7847  }
7848 
7856  function getHTTPBody($soapmsg) {
7857  return $soapmsg;
7858  }
7859 
7868  function getHTTPContentType() {
7869  return 'text/xml';
7870  }
7871 
7881  function getHTTPContentTypeCharset() {
7882  return $this->soap_defencoding;
7883  }
7884 
7885  /*
7886  * whether or not parser should decode utf8 element content
7887  *
7888  * @return always returns true
7889  * @access public
7890  */
7891  function decodeUTF8($bool){
7892  $this->decode_utf8 = $bool;
7893  return true;
7894  }
7895 
7904  function setCookie($name, $value) {
7905  if (strlen($name) == 0) {
7906  return false;
7907  }
7908  $this->cookies[] = array('name' => $name, 'value' => $value);
7909  return true;
7910  }
7911 
7918  function getCookies() {
7919  return $this->cookies;
7920  }
7921 
7928  function checkCookies() {
7929  if (sizeof($this->cookies) == 0) {
7930  return true;
7931  }
7932  $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
7933  $curr_cookies = $this->cookies;
7934  $this->cookies = array();
7935  foreach ($curr_cookies as $cookie) {
7936  if (! is_array($cookie)) {
7937  $this->debug('Remove cookie that is not an array');
7938  continue;
7939  }
7940  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
7941  if (strtotime($cookie['expires']) > time()) {
7942  $this->cookies[] = $cookie;
7943  } else {
7944  $this->debug('Remove expired cookie ' . $cookie['name']);
7945  }
7946  } else {
7947  $this->cookies[] = $cookie;
7948  }
7949  }
7950  $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');
7951  return true;
7952  }
7953 
7961  function UpdateCookies($cookies) {
7962  if (sizeof($this->cookies) == 0) {
7963  // no existing cookies: take whatever is new
7964  if (sizeof($cookies) > 0) {
7965  $this->debug('Setting new cookie(s)');
7966  $this->cookies = $cookies;
7967  }
7968  return true;
7969  }
7970  if (sizeof($cookies) == 0) {
7971  // no new cookies: keep what we've got
7972  return true;
7973  }
7974  // merge
7975  foreach ($cookies as $newCookie) {
7976  if (!is_array($newCookie)) {
7977  continue;
7978  }
7979  if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
7980  continue;
7981  }
7982  $newName = $newCookie['name'];
7983 
7984  $found = false;
7985  for ($i = 0; $i < count($this->cookies); $i++) {
7986  $cookie = $this->cookies[$i];
7987  if (!is_array($cookie)) {
7988  continue;
7989  }
7990  if (!isset($cookie['name'])) {
7991  continue;
7992  }
7993  if ($newName != $cookie['name']) {
7994  continue;
7995  }
7996  $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
7997  $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
7998  if ($newDomain != $domain) {
7999  continue;
8000  }
8001  $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
8002  $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
8003  if ($newPath != $path) {
8004  continue;
8005  }
8006  $this->cookies[$i] = $newCookie;
8007  $found = true;
8008  $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
8009  break;
8010  }
8011  if (! $found) {
8012  $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
8013  $this->cookies[] = $newCookie;
8014  }
8015  }
8016  return true;
8017  }
8018 }
8019 
8020 if (!extension_loaded('soap')) {
8024  class soapclient extends nusoap_client {
8025  }
8026 }
if($err=$client->getError()) $namespace
appendDebug($string)
adds debug data to the instance debug string without formatting
Definition: nusoap.php:298
$attributes
Definition: metadata.php:231
soap_server allows the user to create a SOAP server that is capable of receiving messages and returni...
Definition: nusoap.php:2313
& getDebugAsXMLComment()
gets the current debug data for this instance as an XML comment this may change the contents of the d...
Definition: nusoap.php:336
serializeEnvelope($body, $headers=false, $namespaces=array(), $style='rpc', $use='encoded')
serialize message
Definition: nusoap.php:417
setError($str)
sets error string
Definition: nusoap.php:184
Contains information for a SOAP fault.
Definition: nusoap.php:1008
transport class for sending/receiving data via HTTP and HTTPS NOTE: PHP must be compiled with the CUR...
Definition: nusoap.php:1552
& getDebug()
gets the current debug data for this instance
Definition: nusoap.php:323
$data
Definition: storeScorm.php:23
$c
Definition: cli.php:37
$result
isArraySimpleOrStruct($val)
detect if array is a simple array or a struct (associative array)
Definition: nusoap.php:195
parses a WSDL file, allows access to it&#39;s data, other utility methods
Definition: nusoap.php:3133
$type
$_GET["client_id"]
getOperationDataForSoapAction($soapAction, $bindingType='soap')
returns an associative array of data necessary for calling an operation
Definition: nusoap.php:5148
$XMLSchemaVersion
Definition: nusoap.php:78
soap_fault class, allows for creation of faults mainly used for returning faults from deployed functi...
Definition: nusoap.php:669
nusoap_server allows the user to create a SOAP server that is capable of receiving messages and retur...
Definition: nusoap.php:3438
serialize()
serialize the parsed wsdl
Definition: nusoap.php:3741
addOperation($name, $in=false, $out=false, $namespace=false, $soapaction=false, $style='rpc', $use='encoded', $documentation='')
register a service with the server
Definition: nusoap.php:4362
getLocalPart($str)
returns the local part of a prefixed string returns the original string, if not prefixed ...
Definition: nusoap.php:508
__construct()
constructor
Definition: nusoap.php:236
parses an XML Schema, allows access to it&#39;s data, other utility methods no validation...
Definition: nusoap.php:734
for creating serializable abstractions of native PHP types NOTE: this is only really used when WSDL i...
Definition: nusoap.php:1495
getError()
returns error string if present
Definition: nusoap.php:171
debug($string)
adds debug data to the class level debug string
Definition: nusoap.php:144
if($format !==null) $name
Definition: metadata.php:230
soap_parser class parses SOAP XML messages into native PHP values
Definition: nusoap.php:4431
$messages
Definition: xapiexit.php:5
foreach($_POST as $key=> $value) $res
getPrefixFromNamespace($ns)
returns the prefix for a given namespace (or prefix) or false if no prefixes registered for the given...
Definition: nusoap.php:557
expandQname($qname)
expands a qualified name
Definition: nusoap.php:483
parses an XML Schema, allows access to it&#39;s data, other utility methods.
Definition: nusoap.php:1096
setCredentials($username, $password, $authtype='basic', $certRequest=array())
if authenticating, set user credentials here
Definition: nusoap.php:5062
nusoap_base
Definition: nusoap.php:61
$_SERVER['HTTP_HOST']
Definition: raiseError.php:10
webDescription()
prints html description of services
Definition: nusoap.php:5242
$param
Definition: xapitoken.php:29
[nu]soapclient higher level class for easy usage.
Definition: nusoap.php:7076
$xml
Definition: metadata.php:332
serialize_val($val, $name=false, $type=false, $name_ns=false, $type_ns=false, $attributes=false, $use='encoded')
serializes PHP values in accordance w/ section 5.
Definition: nusoap.php:212
wsdl($wsdl='', $proxyhost=false, $proxyport=false, $proxyusername=false, $proxypassword=false, $timeout=0, $response_timeout=30)
constructor
Definition: nusoap.php:3181
$n
Definition: RandomTest.php:85
$http
Definition: raiseError.php:7
varDump($data)
Definition: nusoap.php:567
getPrefix($str)
returns the prefix part of a prefixed string returns false, if not prefixed
Definition: nusoap.php:525
getOperations($bindingType='soap')
returns an assoc array of operation names => operation data
Definition: nusoap.php:3649
if(php_sapi_name() !='cli') $in
Definition: Utf8Test.php:37
$rows
Definition: xhr_table.php:10
$password
Definition: cron.php:14
serialize()
serialize a fault
Definition: nusoap.php:1056
$soap_defencoding
Definition: nusoap.php:86
__construct(Container $dic, ilPlugin $plugin)
expandEntities($val)
expands entities, e.g.
Definition: nusoap.php:154
serializeRPCParameters($operation, $direction, $parameters)
serialize a PHP value according to a WSDL message definition
Definition: nusoap.php:3870
$ret
Definition: parser.php:6
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
getNamespaceFromPrefix($prefix)
pass it a prefix, it returns a namespace returns false if no namespace registered with the given pref...
Definition: nusoap.php:541
nusoap_parser class parses SOAP XML messages into native PHP values
Definition: nusoap.php:6429
$message
Definition: xapiexit.php:14
getOperationData($operation, $bindingType='soap')
returns an associative array of data necessary for calling an operation
Definition: nusoap.php:3679
$url
clearDebug()
clears the current debug data for this instance
Definition: nusoap.php:311
$response
fetchWSDL($wsdl)
fetches the WSDL document and parses it
Definition: nusoap.php:4592
$cols
Definition: xhr_table.php:11
catch(ilCmiXapiException $e) send($response)
Definition: xapitoken.php:82
$i
Definition: metadata.php:24

Variable Documentation

◆ globalDebugLevel

if (!isset( $GLOBALS[ '_transient'])||!isset( $GLOBALS[ '_transient'][ 'static'])||!isset( $GLOBALS[ '_transient'][ 'static'][ 'nusoap_base'])||!is_object( $GLOBALS[ '_transient'][ 'static'][ 'nusoap_base'])) $GLOBALS ['_transient']['static']['nusoap_base'] globalDebugLevel = 0

Definition at line 85 of file nusoap.php.