ILIAS  trunk Revision v11.0_alpha-1715-g7fc467680fb
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator 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
 Backward compatibility. More...
 
class  nusoap_xmlschema
 parses an XML Schema, allows access to it's data, other utility methods. More...
 
class  XMLSchema
 Backward compatibility. More...
 
class  soapval
 For creating serializable abstractions of native PHP types. 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
 Backward compatibility. 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
 Backward compatibility. 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
 This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Learning e.V. More...
 

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 929 of file nusoap.php.

930 {
931  $pattern = '/' .
932  '([0-9]{4})-' . // centuries & years CCYY-
933  '([0-9]{2})-' . // months MM-
934  '([0-9]{2})' . // days DD
935  'T' . // separator T
936  '([0-9]{2}):' . // hours hh:
937  '([0-9]{2}):' . // minutes mm:
938  '([0-9]{2})(\.[0-9]+)?' . // seconds ss.ss...
939  '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
940  '/';
941 
942  if (preg_match($pattern, $datestr, $regs)) {
943  // not utc
944  if ($regs[8] != 'Z') {
945  $op = substr($regs[8], 0, 1);
946  $h = substr($regs[8], 1, 2);
947  $m = substr($regs[8], strlen($regs[8]) - 2, 2);
948  if ($op == '-') {
949  $regs[4] = $regs[4] + $h;
950  $regs[5] = $regs[5] + $m;
951  } elseif ($op == '+') {
952  $regs[4] = $regs[4] - $h;
953  $regs[5] = $regs[5] - $m;
954  }
955  }
956  return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
957  // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
958  } else {
959  return false;
960  }
961 }

◆ 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 899 of file nusoap.php.

References $timestamp.

900 {
901  $datestr = date('Y-m-d\TH:i:sO', $timestamp);
902  if ($utc) {
903  $pattern = '/' .
904  '([0-9]{4})-' . // centuries & years CCYY-
905  '([0-9]{2})-' . // months MM-
906  '([0-9]{2})' . // days DD
907  'T' . // separator T
908  '([0-9]{2}):' . // hours hh:
909  '([0-9]{2}):' . // minutes mm:
910  '([0-9]{2})(\.[0-9]*)?' . // seconds ss.ss...
911  '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
912  '/';
913 
914  if (preg_match($pattern, $datestr, $regs)) {
915  return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ', $regs[1], $regs[2], $regs[3], $regs[4], $regs[5], $regs[6]);
916  }
917  return false;
918  } else {
919  return $datestr;
920  }
921 }
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:70

◆ 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 970 of file nusoap.php.

971 {
972  $start = gettimeofday();
973 
974  do {
975  $stop = gettimeofday();
976  $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
977  + $stop['usec'] - $start['usec'];
978  } while ($timePassed < $usec);
979 }
980 
981 ?><?php
982 
983 
984 
993 class nusoap_fault extends nusoap_base
994 {
1000  public $faultcode;
1006  public $faultactor;
1012  public $faultstring;
1018  public $faultdetail;
1019 
1028  public function __construct($faultcode, $faultactor = '', $faultstring = '', $faultdetail = '')
1029  {
1031  $this->faultcode = $faultcode;
1032  $this->faultactor = $faultactor;
1033  $this->faultstring = $faultstring;
1034  $this->faultdetail = $faultdetail;
1035  }
1036 
1043  public function serialize()
1044  {
1045  $ns_string = '';
1046  foreach ($this->namespaces as $k => $v) {
1047  $ns_string .= "\n xmlns:$k=\"$v\"";
1048  }
1049  $return_msg =
1050  '<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?>' .
1051  '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string . ">\n" .
1052  '<SOAP-ENV:Body>' .
1053  '<SOAP-ENV:Fault>' .
1054  $this->serialize_val($this->faultcode, 'faultcode') .
1055  $this->serialize_val($this->faultstring, 'faultstring') .
1056  $this->serialize_val($this->faultactor, 'faultactor') .
1057  $this->serialize_val($this->faultdetail, 'detail') .
1058  '</SOAP-ENV:Fault>' .
1059  '</SOAP-ENV:Body>' .
1060  '</SOAP-ENV:Envelope>';
1061  return $return_msg;
1062  }
1063 }
1064 
1068 class soap_fault extends nusoap_fault
1069 {
1070 }
1071 
1072 ?><?php
1073 
1074 
1075 
1085 class nusoap_xmlschema extends nusoap_base
1086 {
1087  // files
1088  public $schema = '';
1089  public $xml = '';
1090  // namespaces
1091  public $enclosingNamespaces;
1092  // schema info
1093  public $schemaInfo = array();
1094  public $schemaTargetNamespace = '';
1095  // types, elements, attributes defined by the schema
1096  public $attributes = array();
1097  public $complexTypes = array();
1098  public $complexTypeStack = array();
1099  public $currentComplexType = null;
1100  public $elements = array();
1101  public $elementStack = array();
1102  public $currentElement = null;
1103  public $simpleTypes = array();
1104  public $simpleTypeStack = array();
1105  public $currentSimpleType = null;
1106  // imports
1107  public $imports = array();
1108  // parser vars
1109  public $parser;
1110  public $position = 0;
1111  public $depth = 0;
1112  public $depth_array = array();
1113  public $message = array();
1114  public $defaultNamespace = array();
1115 
1124  public function __construct($schema = '', $xml = '', $namespaces = array())
1125  {
1127  $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1128  // files
1129  $this->schema = $schema;
1130  $this->xml = $xml;
1131 
1132  // namespaces
1133  $this->enclosingNamespaces = $namespaces;
1134  $this->namespaces = array_merge($this->namespaces, $namespaces);
1135 
1136  // parse schema file
1137  if ($schema != '') {
1138  $this->debug('initial schema file: ' . $schema);
1139  $this->parseFile($schema, 'schema');
1140  }
1141 
1142  // parse xml file
1143  if ($xml != '') {
1144  $this->debug('initial xml file: ' . $xml);
1145  $this->parseFile($xml, 'xml');
1146  }
1147  }
1148 
1157  public function parseFile($xml, $type)
1158  {
1159  // parse xml file
1160  if ($xml != "") {
1161  $xmlStr = @join("", @file($xml));
1162  if ($xmlStr == "") {
1163  $msg = 'Error reading XML from ' . $xml;
1164  $this->setError($msg);
1165  $this->debug($msg);
1166  return false;
1167  } else {
1168  $this->debug("parsing $xml");
1169  $this->parseString($xmlStr, $type);
1170  $this->debug("done parsing $xml");
1171  return true;
1172  }
1173  }
1174  return false;
1175  }
1176 
1184  public function parseString($xml, $type)
1185  {
1186  // parse xml string
1187  if ($xml != "") {
1188  // Create an XML parser.
1189  $this->parser = xml_parser_create();
1190  // Set the options for parsing the XML data.
1191  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1192 
1193  // Set the element handlers for the parser.
1194  if ($type == "schema") {
1195  xml_set_element_handler($this->parser, $this->schemaStartElement(...), $this->schemaEndElement(...));
1196  xml_set_character_data_handler($this->parser, $this->schemaCharacterData(...));
1197  } elseif ($type == "xml") {
1198  xml_set_element_handler($this->parser, $this->xmlStartElement(...), $this->xmlEndElement(...));
1199  xml_set_character_data_handler($this->parser, $this->xmlCharacterData(...));
1200  }
1201 
1202  // Parse the XML file.
1203  if (!xml_parse($this->parser, $xml, true)) {
1204  // Display an error message.
1205  $errstr = sprintf(
1206  'XML error parsing XML schema on line %d: %s',
1207  xml_get_current_line_number($this->parser),
1208  xml_error_string(xml_get_error_code($this->parser))
1209  );
1210  $this->debug($errstr);
1211  $this->debug("XML payload:\n" . $xml);
1212  $this->setError($errstr);
1213  }
1214 
1215  xml_parser_free($this->parser);
1216  } else {
1217  $this->debug('no xml passed to parseString()!!');
1218  $this->setError('no xml passed to parseString()!!');
1219  }
1220  }
1221 
1229  public function CreateTypeName($ename)
1230  {
1231  $scope = '';
1232  for ($i = 0; $i < count($this->complexTypeStack); $i++) {
1233  $scope .= $this->complexTypeStack[$i] . '_';
1234  }
1235  return $scope . $ename . '_ContainedType';
1236  }
1237 
1246  public function schemaStartElement($parser, $name, $attrs)
1247  {
1248 
1249  // position in the total number of elements, starting from 0
1250  $pos = $this->position++;
1251  $depth = $this->depth++;
1252  // set self as current value for this depth
1253  $this->depth_array[$depth] = $pos;
1254  $this->message[$pos] = array('cdata' => '');
1255  if ($depth > 0) {
1256  $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1257  } else {
1258  $this->defaultNamespace[$pos] = false;
1259  }
1260 
1261  // get element prefix
1262  if ($prefix = $this->getPrefix($name)) {
1263  // get unqualified name
1264  $name = $this->getLocalPart($name);
1265  } else {
1266  $prefix = '';
1267  }
1268 
1269  // loop thru attributes, expanding, and registering namespace declarations
1270  if (count($attrs) > 0) {
1271  foreach ($attrs as $k => $v) {
1272  // if ns declarations, add to class level array of valid namespaces
1273  if (preg_match('/^xmlns/', $k)) {
1274  //$this->xdebug("$k: $v");
1275  //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1276  if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
1277  //$this->xdebug("Add namespace[$ns_prefix] = $v");
1278  $this->namespaces[$ns_prefix] = $v;
1279  } else {
1280  $this->defaultNamespace[$pos] = $v;
1281  if (! $this->getPrefixFromNamespace($v)) {
1282  $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
1283  }
1284  }
1285  if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
1286  $this->XMLSchemaVersion = $v;
1287  $this->namespaces['xsi'] = $v . '-instance';
1288  }
1289  }
1290  }
1291  foreach ($attrs as $k => $v) {
1292  // expand each attribute
1293  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
1294  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
1295  $eAttrs[$k] = $v;
1296  }
1297  $attrs = $eAttrs;
1298  } else {
1299  $attrs = array();
1300  }
1301  // find status, register data
1302  switch ($name) {
1303  case 'all': // (optional) compositor content for a complexType
1304  case 'choice':
1305  case 'group':
1306  case 'sequence':
1307  //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1308  $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1309  //if($name == 'all' || $name == 'sequence'){
1310  // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1311  //}
1312  break;
1313  case 'attribute': // complexType attribute
1314  //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1315  $this->xdebug("parsing attribute:");
1316  $this->appendDebug($this->varDump($attrs));
1317  if (!isset($attrs['form'])) {
1318  $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1319  }
1320  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1321  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1322  if (!strpos($v, ':')) {
1323  // no namespace in arrayType attribute value...
1324  if ($this->defaultNamespace[$pos]) {
1325  // ...so use the default
1326  $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1327  }
1328  }
1329  }
1330  if (isset($attrs['name'])) {
1331  $this->attributes[$attrs['name']] = $attrs;
1332  $aname = $attrs['name'];
1333  } elseif (isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType') {
1334  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1335  $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1336  } else {
1337  $aname = '';
1338  }
1339  } elseif (isset($attrs['ref'])) {
1340  $aname = $attrs['ref'];
1341  $this->attributes[$attrs['ref']] = $attrs;
1342  }
1343 
1344  if ($this->currentComplexType) { // This should *always* be
1345  $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1346  }
1347  // arrayType attribute
1348  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType') {
1349  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1350  $prefix = $this->getPrefix($aname);
1351  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1352  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1353  } else {
1354  $v = '';
1355  }
1356  if (strpos($v, '[,]')) {
1357  $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1358  }
1359  $v = substr($v, 0, strpos($v, '[')); // clip the []
1360  if (!strpos($v, ':') && isset($this->typemap[$this->XMLSchemaVersion][$v])) {
1361  $v = $this->XMLSchemaVersion . ':' . $v;
1362  }
1363  $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1364  }
1365  break;
1366  case 'complexContent': // (optional) content for a complexType
1367  break;
1368  case 'complexType':
1369  array_push($this->complexTypeStack, $this->currentComplexType);
1370  if (isset($attrs['name'])) {
1371  // TODO: what is the scope of named complexTypes that appear
1372  // nested within other c complexTypes?
1373  $this->xdebug('processing named complexType ' . $attrs['name']);
1374  //$this->currentElement = false;
1375  $this->currentComplexType = $attrs['name'];
1376  $this->complexTypes[$this->currentComplexType] = $attrs;
1377  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1378  // This is for constructs like
1379  // <complexType name="ListOfString" base="soap:Array">
1380  // <sequence>
1381  // <element name="string" type="xsd:string"
1382  // minOccurs="0" maxOccurs="unbounded" />
1383  // </sequence>
1384  // </complexType>
1385  if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
1386  $this->xdebug('complexType is unusual array');
1387  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1388  } else {
1389  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1390  }
1391  } else {
1392  $name = $this->CreateTypeName($this->currentElement);
1393  $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
1394  $this->currentComplexType = $name;
1395  //$this->currentElement = false;
1396  $this->complexTypes[$this->currentComplexType] = $attrs;
1397  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1398  // This is for constructs like
1399  // <complexType name="ListOfString" base="soap:Array">
1400  // <sequence>
1401  // <element name="string" type="xsd:string"
1402  // minOccurs="0" maxOccurs="unbounded" />
1403  // </sequence>
1404  // </complexType>
1405  if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
1406  $this->xdebug('complexType is unusual array');
1407  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1408  } else {
1409  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1410  }
1411  }
1412  break;
1413  case 'element':
1414  array_push($this->elementStack, $this->currentElement);
1415  if (!isset($attrs['form'])) {
1416  $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1417  }
1418  if (isset($attrs['type'])) {
1419  $this->xdebug("processing typed element " . $attrs['name'] . " of type " . $attrs['type']);
1420  if (! $this->getPrefix($attrs['type'])) {
1421  if ($this->defaultNamespace[$pos]) {
1422  $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1423  $this->xdebug('used default namespace to make type ' . $attrs['type']);
1424  }
1425  }
1426  // This is for constructs like
1427  // <complexType name="ListOfString" base="soap:Array">
1428  // <sequence>
1429  // <element name="string" type="xsd:string"
1430  // minOccurs="0" maxOccurs="unbounded" />
1431  // </sequence>
1432  // </complexType>
1433  if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
1434  $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1435  $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1436  }
1437  $this->currentElement = $attrs['name'];
1438  $ename = $attrs['name'];
1439  } elseif (isset($attrs['ref'])) {
1440  $this->xdebug("processing element as ref to " . $attrs['ref']);
1441  $this->currentElement = "ref to " . $attrs['ref'];
1442  $ename = $this->getLocalPart($attrs['ref']);
1443  } else {
1444  $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
1445  $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
1446  $this->currentElement = $attrs['name'];
1447  $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
1448  $ename = $attrs['name'];
1449  }
1450  if (isset($ename) && $this->currentComplexType) {
1451  $this->xdebug("add element $ename to complexType $this->currentComplexType");
1452  $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1453  } elseif (!isset($attrs['ref'])) {
1454  $this->xdebug("add element $ename to elements array");
1455  $this->elements[ $attrs['name'] ] = $attrs;
1456  $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1457  }
1458  break;
1459  case 'enumeration': // restriction value list member
1460  $this->xdebug('enumeration ' . $attrs['value']);
1461  if ($this->currentSimpleType) {
1462  $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1463  } elseif ($this->currentComplexType) {
1464  $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1465  }
1466  break;
1467  case 'extension': // simpleContent or complexContent type extension
1468  $this->xdebug('extension ' . $attrs['base']);
1469  if ($this->currentComplexType) {
1470  $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1471  }
1472  break;
1473  case 'import':
1474  if (isset($attrs['schemaLocation'])) {
1475  //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1476  $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1477  } else {
1478  //$this->xdebug('import namespace ' . $attrs['namespace']);
1479  $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1480  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
1481  $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace'];
1482  }
1483  }
1484  break;
1485  case 'list': // simpleType value list
1486  break;
1487  case 'restriction': // simpleType, simpleContent or complexContent value restriction
1488  $this->xdebug('restriction ' . $attrs['base']);
1489  if ($this->currentSimpleType) {
1490  $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1491  } elseif ($this->currentComplexType) {
1492  $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1493  if (strstr($attrs['base'], ':') == ':Array') {
1494  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1495  }
1496  }
1497  break;
1498  case 'schema':
1499  $this->schemaInfo = $attrs;
1500  $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1501  if (isset($attrs['targetNamespace'])) {
1502  $this->schemaTargetNamespace = $attrs['targetNamespace'];
1503  }
1504  if (!isset($attrs['elementFormDefault'])) {
1505  $this->schemaInfo['elementFormDefault'] = 'unqualified';
1506  }
1507  if (!isset($attrs['attributeFormDefault'])) {
1508  $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1509  }
1510  break;
1511  case 'simpleContent': // (optional) content for a complexType
1512  break;
1513  case 'simpleType':
1514  array_push($this->simpleTypeStack, $this->currentSimpleType);
1515  if (isset($attrs['name'])) {
1516  $this->xdebug("processing simpleType for name " . $attrs['name']);
1517  $this->currentSimpleType = $attrs['name'];
1518  $this->simpleTypes[ $attrs['name'] ] = $attrs;
1519  $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1520  $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1521  } else {
1522  $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
1523  $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
1524  $this->currentSimpleType = $name;
1525  //$this->currentElement = false;
1526  $this->simpleTypes[$this->currentSimpleType] = $attrs;
1527  $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1528  }
1529  break;
1530  case 'union': // simpleType type list
1531  break;
1532  default:
1533  //$this->xdebug("do not have anything to do for element $name");
1534  }
1535  }
1536 
1544  public function schemaEndElement($parser, $name)
1545  {
1546  // bring depth down a notch
1547  $this->depth--;
1548  // position of current element is equal to the last value left in depth_array for my depth
1549  if (isset($this->depth_array[$this->depth])) {
1550  $pos = $this->depth_array[$this->depth];
1551  }
1552  // get element prefix
1553  if ($prefix = $this->getPrefix($name)) {
1554  // get unqualified name
1555  $name = $this->getLocalPart($name);
1556  } else {
1557  $prefix = '';
1558  }
1559  // move on...
1560  if ($name == 'complexType') {
1561  $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
1562  $this->currentComplexType = array_pop($this->complexTypeStack);
1563  //$this->currentElement = false;
1564  }
1565  if ($name == 'element') {
1566  $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
1567  $this->currentElement = array_pop($this->elementStack);
1568  }
1569  if ($name == 'simpleType') {
1570  $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
1571  $this->currentSimpleType = array_pop($this->simpleTypeStack);
1572  }
1573  }
1574 
1582  public function schemaCharacterData($parser, $data)
1583  {
1584  $pos = $this->depth_array[$this->depth - 1];
1585  $this->message[$pos]['cdata'] .= $data;
1586  }
1587 
1593  public function serializeSchema()
1594  {
1595  $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1596  $xml = '';
1597  // imports
1598  if (sizeof($this->imports) > 0) {
1599  foreach ($this->imports as $ns => $list) {
1600  foreach ($list as $ii) {
1601  if ($ii['location'] != '') {
1602  $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1603  } else {
1604  $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1605  }
1606  }
1607  }
1608  }
1609  // complex types
1610  foreach ($this->complexTypes as $typeName => $attrs) {
1611  $contentStr = '';
1612  // serialize child elements
1613  if (isset($attrs['elements']) && (count($attrs['elements']) > 0)) {
1614  foreach ($attrs['elements'] as $element => $eParts) {
1615  if (isset($eParts['ref'])) {
1616  $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
1617  } else {
1618  $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
1619  foreach ($eParts as $aName => $aValue) {
1620  // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1621  if ($aName != 'name' && $aName != 'type') {
1622  $contentStr .= " $aName=\"$aValue\"";
1623  }
1624  }
1625  $contentStr .= "/>\n";
1626  }
1627  }
1628  // compositor wraps elements
1629  if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
1630  $contentStr = " <$schemaPrefix:$attrs[compositor]>\n" . $contentStr . " </$schemaPrefix:$attrs[compositor]>\n";
1631  }
1632  }
1633  // attributes
1634  if (isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)) {
1635  foreach ($attrs['attrs'] as $attr => $aParts) {
1636  $contentStr .= " <$schemaPrefix:attribute";
1637  foreach ($aParts as $a => $v) {
1638  if ($a == 'ref' || $a == 'type') {
1639  $contentStr .= " $a=\"" . $this->contractQName($v) . '"';
1640  } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
1641  $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1642  $contentStr .= ' wsdl:arrayType="' . $this->contractQName($v) . '"';
1643  } else {
1644  $contentStr .= " $a=\"$v\"";
1645  }
1646  }
1647  $contentStr .= "/>\n";
1648  }
1649  }
1650  // if restriction
1651  if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != '') {
1652  $contentStr = " <$schemaPrefix:restriction base=\"" . $this->contractQName($attrs['restrictionBase']) . "\">\n" . $contentStr . " </$schemaPrefix:restriction>\n";
1653  // complex or simple content
1654  if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)) {
1655  $contentStr = " <$schemaPrefix:complexContent>\n" . $contentStr . " </$schemaPrefix:complexContent>\n";
1656  }
1657  }
1658  // finalize complex type
1659  if ($contentStr != '') {
1660  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n" . $contentStr . " </$schemaPrefix:complexType>\n";
1661  } else {
1662  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1663  }
1664  $xml .= $contentStr;
1665  }
1666  // simple types
1667  if (isset($this->simpleTypes) && count($this->simpleTypes) > 0) {
1668  foreach ($this->simpleTypes as $typeName => $eParts) {
1669  $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"" . $this->contractQName($eParts['type']) . "\">\n";
1670  if (isset($eParts['enumeration'])) {
1671  foreach ($eParts['enumeration'] as $e) {
1672  $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
1673  }
1674  }
1675  $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
1676  }
1677  }
1678  // elements
1679  if (isset($this->elements) && count($this->elements) > 0) {
1680  foreach ($this->elements as $element => $eParts) {
1681  $xml .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"/>\n";
1682  }
1683  }
1684  // attributes
1685  if (isset($this->attributes) && count($this->attributes) > 0) {
1686  foreach ($this->attributes as $attr => $aParts) {
1687  $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"" . $this->contractQName($aParts['type']) . "\"\n/>";
1688  }
1689  }
1690  // finish 'er up
1691  $attr = '';
1692  foreach ($this->schemaInfo as $k => $v) {
1693  if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
1694  $attr .= " $k=\"$v\"";
1695  }
1696  }
1697  $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
1698  foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1699  $el .= " xmlns:$nsp=\"$ns\"";
1700  }
1701  $xml = $el . ">\n" . $xml . "</$schemaPrefix:schema>\n";
1702  return $xml;
1703  }
1704 
1711  public function xdebug($string)
1712  {
1713  $this->debug('<' . $this->schemaTargetNamespace . '> ' . $string);
1714  }
1715 
1728  public function getPHPType($type, $ns)
1729  {
1730  if (isset($this->typemap[$ns][$type])) {
1731  //print "found type '$type' and ns $ns in typemap<br>";
1732  return $this->typemap[$ns][$type];
1733  } elseif (isset($this->complexTypes[$type])) {
1734  //print "getting type '$type' and ns $ns from complexTypes array<br>";
1735  return $this->complexTypes[$type]['phpType'];
1736  }
1737  return false;
1738  }
1739 
1762  public function getTypeDef($type)
1763  {
1764  //$this->debug("in getTypeDef for type $type");
1765  if (substr($type, -1) == '^') {
1766  $is_element = 1;
1767  $type = substr($type, 0, -1);
1768  } else {
1769  $is_element = 0;
1770  }
1771 
1772  if ((! $is_element) && isset($this->complexTypes[$type])) {
1773  $this->xdebug("in getTypeDef, found complexType $type");
1774  return $this->complexTypes[$type];
1775  } elseif ((! $is_element) && isset($this->simpleTypes[$type])) {
1776  $this->xdebug("in getTypeDef, found simpleType $type");
1777  if (!isset($this->simpleTypes[$type]['phpType'])) {
1778  // get info for type to tack onto the simple type
1779  // TODO: can this ever really apply (i.e. what is a simpleType really?)
1780  $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1781  $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1782  $etype = $this->getTypeDef($uqType);
1783  if ($etype) {
1784  $this->xdebug("in getTypeDef, found type for simpleType $type:");
1785  $this->xdebug($this->varDump($etype));
1786  if (isset($etype['phpType'])) {
1787  $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1788  }
1789  if (isset($etype['elements'])) {
1790  $this->simpleTypes[$type]['elements'] = $etype['elements'];
1791  }
1792  }
1793  }
1794  return $this->simpleTypes[$type];
1795  } elseif (isset($this->elements[$type])) {
1796  $this->xdebug("in getTypeDef, found element $type");
1797  if (!isset($this->elements[$type]['phpType'])) {
1798  // get info for type to tack onto the element
1799  $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1800  $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1801  $etype = $this->getTypeDef($uqType);
1802  if ($etype) {
1803  $this->xdebug("in getTypeDef, found type for element $type:");
1804  $this->xdebug($this->varDump($etype));
1805  if (isset($etype['phpType'])) {
1806  $this->elements[$type]['phpType'] = $etype['phpType'];
1807  }
1808  if (isset($etype['elements'])) {
1809  $this->elements[$type]['elements'] = $etype['elements'];
1810  }
1811  } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
1812  $this->xdebug("in getTypeDef, element $type is an XSD type");
1813  $this->elements[$type]['phpType'] = 'scalar';
1814  }
1815  }
1816  return $this->elements[$type];
1817  } elseif (isset($this->attributes[$type])) {
1818  $this->xdebug("in getTypeDef, found attribute $type");
1819  return $this->attributes[$type];
1820  } elseif (preg_match('/_ContainedType$/', $type)) {
1821  $this->xdebug("in getTypeDef, have an untyped element $type");
1822  $typeDef['typeClass'] = 'simpleType';
1823  $typeDef['phpType'] = 'scalar';
1824  $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
1825  return $typeDef;
1826  }
1827  $this->xdebug("in getTypeDef, did not find $type");
1828  return false;
1829  }
1830 
1839  public function serializeTypeDef($type)
1840  {
1841  //print "in sTD() for type $type<br>";
1842  if ($typeDef = $this->getTypeDef($type)) {
1843  $str .= '<' . $type;
1844  if (is_array($typeDef['attrs'])) {
1845  foreach ($typeDef['attrs'] as $attName => $data) {
1846  $str .= " $attName=\"{type = " . $data['type'] . "}\"";
1847  }
1848  }
1849  $str .= " xmlns=\"" . $this->schema['targetNamespace'] . "\"";
1850  if (count($typeDef['elements']) > 0) {
1851  $str .= ">";
1852  foreach ($typeDef['elements'] as $element => $eData) {
1853  $str .= $this->serializeTypeDef($element);
1854  }
1855  $str .= "</$type>";
1856  } elseif ($typeDef['typeClass'] == 'element') {
1857  $str .= "></$type>";
1858  } else {
1859  $str .= "/>";
1860  }
1861  return $str;
1862  }
1863  return false;
1864  }
1865 
1876  public function typeToForm($name, $type)
1877  {
1878  // get typedef
1879  if ($typeDef = $this->getTypeDef($type)) {
1880  // if struct
1881  if ($typeDef['phpType'] == 'struct') {
1882  $buffer .= '<table>';
1883  foreach ($typeDef['elements'] as $child => $childDef) {
1884  $buffer .= "
1885  <tr><td align='right'>$childDef[name] (type: " . $this->getLocalPart($childDef['type']) . "):</td>
1886  <td><input type='text' name='parameters[" . $name . "][$childDef[name]]'></td></tr>";
1887  }
1888  $buffer .= '</table>';
1889  // if array
1890  } elseif ($typeDef['phpType'] == 'array') {
1891  $buffer .= '<table>';
1892  for ($i = 0;$i < 3; $i++) {
1893  $buffer .= "
1894  <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1895  <td><input type='text' name='parameters[" . $name . "][]'></td></tr>";
1896  }
1897  $buffer .= '</table>';
1898  // if scalar
1899  } else {
1900  $buffer .= "<input type='text' name='parameters[$name]'>";
1901  }
1902  } else {
1903  $buffer .= "<input type='text' name='parameters[$name]'>";
1904  }
1905  return $buffer;
1906  }
1907 
1949  public function addComplexType($name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '')
1950  {
1951  $this->complexTypes[$name] = array(
1952  'name' => $name,
1953  'typeClass' => $typeClass,
1954  'phpType' => $phpType,
1955  'compositor' => $compositor,
1956  'restrictionBase' => $restrictionBase,
1957  'elements' => $elements,
1958  'attrs' => $attrs,
1959  'arrayType' => $arrayType
1960  );
1961 
1962  $this->xdebug("addComplexType $name:");
1963  $this->appendDebug($this->varDump($this->complexTypes[$name]));
1964  }
1965 
1978  public function addSimpleType($name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array())
1979  {
1980  $this->simpleTypes[$name] = array(
1981  'name' => $name,
1982  'typeClass' => $typeClass,
1983  'phpType' => $phpType,
1984  'type' => $restrictionBase,
1985  'enumeration' => $enumeration
1986  );
1987 
1988  $this->xdebug("addSimpleType $name:");
1989  $this->appendDebug($this->varDump($this->simpleTypes[$name]));
1990  }
1991 
1999  public function addElement($attrs)
2000  {
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 
2019 ?><?php
2020 
2021 
2022 
2034 class soapval extends nusoap_base
2035 {
2042  public $name;
2049  public $type;
2056  public $value;
2063  public $element_ns;
2070  public $type_ns;
2077  public $attributes;
2078 
2090  public function __construct($name = 'soapval', $type = false, $value = -1, $element_ns = false, $type_ns = false, $attributes = false)
2091  {
2093  $this->name = $name;
2094  $this->type = $type;
2095  $this->value = $value;
2096  $this->element_ns = $element_ns;
2097  $this->type_ns = $type_ns;
2098  $this->attributes = $attributes;
2099  }
2100 
2108  public function serialize($use = 'encoded')
2109  {
2110  return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2111  }
2112 
2119  public function decode()
2120  {
2121  return $this->value;
2122  }
2123 }
2124 
2125 
2126 
2127 ?><?php
2128 
2129 
2130 
2140 class soap_transport_http extends nusoap_base
2141 {
2142  public $fp;
2143  public $tryagain;
2144  public $url = '';
2145  public $uri = '';
2146  public $digest_uri = '';
2147  public $scheme = '';
2148  public $host = '';
2149  public $port = '';
2150  public $path = '';
2151  public $request_method = 'POST';
2152  public $protocol_version = '1.0';
2153  public $encoding = '';
2154  public $outgoing_headers = array();
2155  public $incoming_headers = array();
2156  public $incoming_cookies = array();
2157  public $outgoing_payload = '';
2158  public $incoming_payload = '';
2159  public $response_status_line; // HTTP response status line
2160  public $useSOAPAction = true;
2161  public $persistentConnection = false;
2162  public $ch = false; // cURL handle
2163  public $ch_options = array(); // cURL custom options
2164  public $use_curl = false; // force cURL use
2165  public $proxy = null; // proxy information (associative array)
2166  public $username = '';
2167  public $password = '';
2168  public $authtype = '';
2169  public $digestRequest = array();
2170  public $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
2171  // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2172  // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2173  // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2174  // passphrase: SSL key password/passphrase
2175  // certpassword: SSL certificate password
2176  // verifypeer: default is 1
2177  // verifyhost: default is 1
2178 
2187  public function __construct($url, $curl_options = null, $use_curl = false)
2188  {
2190  $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
2191  $this->appendDebug($this->varDump($curl_options));
2192  $this->setURL($url);
2193  if (is_array($curl_options)) {
2194  $this->ch_options = $curl_options;
2195  }
2196  $this->use_curl = $use_curl;
2197  preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
2198  // begin-patch php8
2199  $this->setHeader('User-Agent', $this->title . '/' . $this->version . ' (' . ($rev[1] ?? '1.1') . ')');
2200  }
2201 
2209  public function setCurlOption($option, $value)
2210  {
2211  $this->debug("setCurlOption option=$option, value=");
2212  $this->appendDebug($this->varDump($value));
2213  curl_setopt($this->ch, $option, $value);
2214  }
2215 
2223  public function setHeader($name, $value)
2224  {
2225  $this->outgoing_headers[$name] = $value;
2226  $this->debug("set header $name: $value");
2227  }
2228 
2235  public function unsetHeader($name)
2236  {
2237  if (isset($this->outgoing_headers[$name])) {
2238  $this->debug("unset header $name");
2239  unset($this->outgoing_headers[$name]);
2240  }
2241  }
2242 
2249  public function setURL($url)
2250  {
2251  $this->url = $url;
2252 
2253  $u = parse_url($url);
2254  foreach ($u as $k => $v) {
2255  $this->debug("parsed URL $k = $v");
2256  $this->$k = $v;
2257  }
2258 
2259  // add any GET params to path
2260  if (isset($u['query']) && $u['query'] != '') {
2261  $this->path .= '?' . $u['query'];
2262  }
2263 
2264  // set default port
2265  if (!isset($u['port'])) {
2266  if ($u['scheme'] == 'https') {
2267  $this->port = 443;
2268  } else {
2269  $this->port = 80;
2270  }
2271  }
2272 
2273  $this->uri = $this->path;
2274  $this->digest_uri = $this->uri;
2275 
2276  // build headers
2277  if (!isset($u['port'])) {
2278  $this->setHeader('Host', $this->host);
2279  } else {
2280  $this->setHeader('Host', $this->host . ':' . $this->port);
2281  }
2282 
2283  if (isset($u['user']) && $u['user'] != '') {
2284  $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2285  }
2286  }
2287 
2294  public function io_method()
2295  {
2296  if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) {
2297  return 'curl';
2298  }
2299  if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) {
2300  return 'socket';
2301  }
2302  return 'unknown';
2303  }
2304 
2313  public function connect($connection_timeout = 0, $response_timeout = 30)
2314  {
2315  // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2316  // "regular" socket.
2317  // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2318  // loaded), and until PHP5 stream_get_wrappers is not available.
2319  // if ($this->scheme == 'https') {
2320  // if (version_compare(phpversion(), '4.3.0') >= 0) {
2321  // if (extension_loaded('openssl')) {
2322  // $this->scheme = 'ssl';
2323  // $this->debug('Using SSL over OpenSSL');
2324  // }
2325  // }
2326  // }
2327  $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2328  if ($this->io_method() == 'socket') {
2329  if (!is_array($this->proxy)) {
2330  $host = $this->host;
2331  $port = $this->port;
2332  } else {
2333  $host = $this->proxy['host'];
2334  $port = $this->proxy['port'];
2335  }
2336 
2337  // use persistent connection
2338  if ($this->persistentConnection && isset($this->fp) && is_resource($this->fp)) {
2339  if (!feof($this->fp)) {
2340  $this->debug('Re-use persistent connection');
2341  return true;
2342  }
2343  fclose($this->fp);
2344  $this->debug('Closed persistent connection at EOF');
2345  }
2346 
2347  // munge host if using OpenSSL
2348  if ($this->scheme == 'ssl') {
2349  $host = 'ssl://' . $host;
2350  }
2351  $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2352 
2353  // open socket
2354  if ($connection_timeout > 0) {
2355  $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str, $connection_timeout);
2356  } else {
2357  $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str);
2358  }
2359 
2360  // test pointer
2361  if (!$this->fp) {
2362  $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2363  if ($this->errno) {
2364  $msg .= ', Error (' . $this->errno . '): ' . $this->error_str;
2365  } else {
2366  $msg .= ' prior to connect(). This is often a problem looking up the host name.';
2367  }
2368  $this->debug($msg);
2369  $this->setError($msg);
2370  return false;
2371  }
2372 
2373  // set response timeout
2374  $this->debug('set response timeout to ' . $response_timeout);
2375  socket_set_timeout($this->fp, $response_timeout);
2376 
2377  $this->debug('socket connected');
2378  return true;
2379  } elseif ($this->io_method() == 'curl') {
2380  if (!extension_loaded('curl')) {
2381  // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
2382  $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.');
2383  return false;
2384  }
2385  // Avoid warnings when PHP does not have these options
2386  if (defined('CURLOPT_CONNECTIONTIMEOUT')) {
2387  $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
2388  } else {
2389  $CURLOPT_CONNECTIONTIMEOUT = 78;
2390  }
2391  if (defined('CURLOPT_HTTPAUTH')) {
2392  $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
2393  } else {
2394  $CURLOPT_HTTPAUTH = 107;
2395  }
2396  if (defined('CURLOPT_PROXYAUTH')) {
2397  $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
2398  } else {
2399  $CURLOPT_PROXYAUTH = 111;
2400  }
2401  if (defined('CURLAUTH_BASIC')) {
2402  $CURLAUTH_BASIC = CURLAUTH_BASIC;
2403  } else {
2404  $CURLAUTH_BASIC = 1;
2405  }
2406  if (defined('CURLAUTH_DIGEST')) {
2407  $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
2408  } else {
2409  $CURLAUTH_DIGEST = 2;
2410  }
2411  if (defined('CURLAUTH_NTLM')) {
2412  $CURLAUTH_NTLM = CURLAUTH_NTLM;
2413  } else {
2414  $CURLAUTH_NTLM = 8;
2415  }
2416 
2417  $this->debug('connect using cURL');
2418  // init CURL
2419  $this->ch = curl_init();
2420  // set url
2421  $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
2422  // add path
2423  $hostURL .= $this->path;
2424  $this->setCurlOption(CURLOPT_URL, $hostURL);
2425  // follow location headers (re-directs)
2426  if (ini_get('safe_mode') || ini_get('open_basedir')) {
2427  $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
2428  $this->debug('safe_mode = ');
2429  $this->appendDebug($this->varDump(ini_get('safe_mode')));
2430  $this->debug('open_basedir = ');
2431  $this->appendDebug($this->varDump(ini_get('open_basedir')));
2432  } else {
2433  $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
2434  }
2435  // ask for headers in the response output
2436  $this->setCurlOption(CURLOPT_HEADER, 1);
2437  // ask for the response output as the return value
2438  $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
2439  // encode
2440  // We manage this ourselves through headers and encoding
2441  // if(function_exists('gzuncompress')){
2442  // $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
2443  // }
2444  // persistent connection
2445  if ($this->persistentConnection) {
2446  // I believe the following comment is now bogus, having applied to
2447  // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
2448  // The way we send data, we cannot use persistent connections, since
2449  // there will be some "junk" at the end of our request.
2450  //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
2451  $this->persistentConnection = false;
2452  $this->setHeader('Connection', 'close');
2453  }
2454  // set timeouts
2455  if ($connection_timeout != 0) {
2456  $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2457  }
2458  if ($response_timeout != 0) {
2459  $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
2460  }
2461 
2462  if ($this->scheme == 'https') {
2463  $this->debug('set cURL SSL verify options');
2464  // recent versions of cURL turn on peer/host checking by default,
2465  // while PHP binaries are not compiled with a default location for the
2466  // CA cert bundle, so disable peer/host checking.
2467  //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
2468  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
2469  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
2470 
2471  // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2472  if ($this->authtype == 'certificate') {
2473  $this->debug('set cURL certificate options');
2474  if (isset($this->certRequest['cainfofile'])) {
2475  $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2476  }
2477  if (isset($this->certRequest['verifypeer'])) {
2478  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2479  } else {
2480  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
2481  }
2482  if (isset($this->certRequest['verifyhost'])) {
2483  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2484  } else {
2485  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
2486  }
2487  if (isset($this->certRequest['sslcertfile'])) {
2488  $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2489  }
2490  if (isset($this->certRequest['sslkeyfile'])) {
2491  $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2492  }
2493  if (isset($this->certRequest['passphrase'])) {
2494  $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
2495  }
2496  if (isset($this->certRequest['certpassword'])) {
2497  $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
2498  }
2499  }
2500  }
2501  if ($this->authtype && ($this->authtype != 'certificate')) {
2502  if ($this->username) {
2503  $this->debug('set cURL username/password');
2504  $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
2505  }
2506  if ($this->authtype == 'basic') {
2507  $this->debug('set cURL for Basic authentication');
2508  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
2509  }
2510  if ($this->authtype == 'digest') {
2511  $this->debug('set cURL for digest authentication');
2512  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
2513  }
2514  if ($this->authtype == 'ntlm') {
2515  $this->debug('set cURL for NTLM authentication');
2516  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
2517  }
2518  }
2519  if (is_array($this->proxy)) {
2520  $this->debug('set cURL proxy options');
2521  if ($this->proxy['port'] != '') {
2522  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'] . ':' . $this->proxy['port']);
2523  } else {
2524  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
2525  }
2526  if ($this->proxy['username'] || $this->proxy['password']) {
2527  $this->debug('set cURL proxy authentication options');
2528  $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'] . ':' . $this->proxy['password']);
2529  if ($this->proxy['authtype'] == 'basic') {
2530  $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
2531  }
2532  if ($this->proxy['authtype'] == 'ntlm') {
2533  $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
2534  }
2535  }
2536  }
2537  $this->debug('cURL connection set up');
2538  return true;
2539  } else {
2540  $this->setError('Unknown scheme ' . $this->scheme);
2541  $this->debug('Unknown scheme ' . $this->scheme);
2542  return false;
2543  }
2544  }
2545 
2556  public function send($data, $timeout = 0, $response_timeout = 30, $cookies = null)
2557  {
2558  $this->debug('entered send() with data of length: ' . strlen($data));
2559 
2560  $this->tryagain = true;
2561  $tries = 0;
2562  while ($this->tryagain) {
2563  $this->tryagain = false;
2564  if ($tries++ < 2) {
2565  // make connnection
2566  if (!$this->connect($timeout, $response_timeout)) {
2567  return false;
2568  }
2569 
2570  // send request
2571  if (!$this->sendRequest($data, $cookies)) {
2572  return false;
2573  }
2574 
2575  // get response
2576  $respdata = $this->getResponse();
2577  } else {
2578  $this->setError("Too many tries to get an OK response ($this->response_status_line)");
2579  }
2580  }
2581  $this->debug('end of send()');
2582  return $respdata;
2583  }
2584 
2585 
2597  public function sendHTTPS($data, $timeout = 0, $response_timeout = 30, $cookies = null)
2598  {
2599  return $this->send($data, $timeout, $response_timeout, $cookies);
2600  }
2601 
2612  public function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array())
2613  {
2614  $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
2615  $this->appendDebug($this->varDump($digestRequest));
2616  $this->debug("certRequest=");
2617  $this->appendDebug($this->varDump($certRequest));
2618  // cf. RFC 2617
2619  if ($authtype == 'basic') {
2620  $this->setHeader('Authorization', 'Basic ' . base64_encode(str_replace(':', '', $username) . ':' . $password));
2621  } elseif ($authtype == 'digest') {
2622  if (isset($digestRequest['nonce'])) {
2623  $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2624 
2625  // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2626 
2627  // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2628  $A1 = $username . ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
2629 
2630  // H(A1) = MD5(A1)
2631  $HA1 = md5($A1);
2632 
2633  // A2 = Method ":" digest-uri-value
2634  $A2 = $this->request_method . ':' . $this->digest_uri;
2635 
2636  // H(A2)
2637  $HA2 = md5($A2);
2638 
2639  // KD(secret, data) = H(concat(secret, ":", data))
2640  // if qop == auth:
2641  // request-digest = <"> < KD ( H(A1), unq(nonce-value)
2642  // ":" nc-value
2643  // ":" unq(cnonce-value)
2644  // ":" unq(qop-value)
2645  // ":" H(A2)
2646  // ) <">
2647  // if qop is missing,
2648  // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2649 
2650  $unhashedDigest = '';
2651  $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
2652  $cnonce = $nonce;
2653  if ($digestRequest['qop'] != '') {
2654  $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2655  } else {
2656  $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2657  }
2658 
2659  $hashedDigest = md5($unhashedDigest);
2660 
2661  $opaque = '';
2662  if (isset($digestRequest['opaque'])) {
2663  $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
2664  }
2665 
2666  $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 . '"');
2667  }
2668  } elseif ($authtype == 'certificate') {
2669  $this->certRequest = $certRequest;
2670  $this->debug('Authorization header not set for certificate');
2671  } elseif ($authtype == 'ntlm') {
2672  // do nothing
2673  $this->debug('Authorization header not set for ntlm');
2674  }
2675  $this->username = $username;
2676  $this->password = $password;
2677  $this->authtype = $authtype;
2678  $this->digestRequest = $digestRequest;
2679  }
2680 
2687  public function setSOAPAction($soapaction)
2688  {
2689  $this->setHeader('SOAPAction', '"' . $soapaction . '"');
2690  }
2691 
2698  public function setEncoding($enc = 'gzip, deflate')
2699  {
2700  if (function_exists('gzdeflate')) {
2701  $this->protocol_version = '1.1';
2702  $this->setHeader('Accept-Encoding', $enc);
2703  if (!isset($this->outgoing_headers['Connection'])) {
2704  $this->setHeader('Connection', 'close');
2705  $this->persistentConnection = false;
2706  }
2707  #set_magic_quotes_runtime(0);
2708  // deprecated
2709  $this->encoding = $enc;
2710  }
2711  }
2712 
2723  public function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic')
2724  {
2725  if ($proxyhost) {
2726  $this->proxy = array(
2727  'host' => $proxyhost,
2728  'port' => $proxyport,
2729  'username' => $proxyusername,
2730  'password' => $proxypassword,
2731  'authtype' => $proxyauthtype
2732  );
2733  if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
2734  $this->setHeader('Proxy-Authorization', ' Basic ' . base64_encode($proxyusername . ':' . $proxypassword));
2735  }
2736  } else {
2737  $this->debug('remove proxy');
2738  $proxy = null;
2739  unsetHeader('Proxy-Authorization');
2740  }
2741  }
2742 
2743 
2752  public function isSkippableCurlHeader(&$data)
2753  {
2754  $skipHeaders = array( 'HTTP/1.1 100',
2755  'HTTP/1.0 301',
2756  'HTTP/1.1 301',
2757  'HTTP/1.0 302',
2758  'HTTP/1.1 302',
2759  'HTTP/1.0 401',
2760  'HTTP/1.1 401',
2761  'HTTP/1.0 200 Connection established');
2762  foreach ($skipHeaders as $hd) {
2763  $prefix = substr($data, 0, strlen($hd));
2764  if ($prefix == $hd) {
2765  return true;
2766  }
2767  }
2768 
2769  return false;
2770  }
2771 
2782  public function decodeChunked($buffer, $lb)
2783  {
2784  // length := 0
2785  $length = 0;
2786  $new = '';
2787 
2788  // read chunk-size, chunk-extension (if any) and CRLF
2789  // get the position of the linebreak
2790  $chunkend = strpos($buffer, $lb);
2791  if ($chunkend == false) {
2792  $this->debug('no linebreak found in decodeChunked');
2793  return $new;
2794  }
2795  $temp = substr($buffer, 0, $chunkend);
2796  $chunk_size = hexdec(trim($temp));
2797  $chunkstart = $chunkend + strlen($lb);
2798  // while (chunk-size > 0) {
2799  while ($chunk_size > 0) {
2800  $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
2801  $chunkend = strpos($buffer, $lb, $chunkstart + $chunk_size);
2802 
2803  // Just in case we got a broken connection
2804  if ($chunkend == false) {
2805  $chunk = substr($buffer, $chunkstart);
2806  // append chunk-data to entity-body
2807  $new .= $chunk;
2808  $length += strlen($chunk);
2809  break;
2810  }
2811 
2812  // read chunk-data and CRLF
2813  $chunk = substr($buffer, $chunkstart, $chunkend - $chunkstart);
2814  // append chunk-data to entity-body
2815  $new .= $chunk;
2816  // length := length + chunk-size
2817  $length += strlen($chunk);
2818  // read chunk-size and CRLF
2819  $chunkstart = $chunkend + strlen($lb);
2820 
2821  $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
2822  if ($chunkend == false) {
2823  break; //Just in case we got a broken connection
2824  }
2825  $temp = substr($buffer, $chunkstart, $chunkend - $chunkstart);
2826  $chunk_size = hexdec(trim($temp));
2827  $chunkstart = $chunkend;
2828  }
2829  return $new;
2830  }
2831 
2840  public function buildPayload($data, $cookie_str = '')
2841  {
2842  // Note: for cURL connections, $this->outgoing_payload is ignored,
2843  // as is the Content-Length header, but these are still created as
2844  // debugging guides.
2845 
2846  // add content-length header
2847  $this->setHeader('Content-Length', strlen($data));
2848 
2849  // start building outgoing payload:
2850  if ($this->proxy) {
2851  $uri = $this->url;
2852  } else {
2853  $uri = $this->uri;
2854  }
2855  $req = "$this->request_method $uri HTTP/$this->protocol_version";
2856  $this->debug("HTTP request: $req");
2857  $this->outgoing_payload = "$req\r\n";
2858 
2859  // loop thru headers, serializing
2860  foreach ($this->outgoing_headers as $k => $v) {
2861  $hdr = $k . ': ' . $v;
2862  $this->debug("HTTP header: $hdr");
2863  $this->outgoing_payload .= "$hdr\r\n";
2864  }
2865 
2866  // add any cookies
2867  if ($cookie_str != '') {
2868  $hdr = 'Cookie: ' . $cookie_str;
2869  $this->debug("HTTP header: $hdr");
2870  $this->outgoing_payload .= "$hdr\r\n";
2871  }
2872 
2873  // header/body separator
2874  $this->outgoing_payload .= "\r\n";
2875 
2876  // add data
2877  $this->outgoing_payload .= $data;
2878  }
2879 
2888  public function sendRequest($data, $cookies = null)
2889  {
2890  // build cookie string
2891  $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
2892 
2893  // build payload
2894  $this->buildPayload($data, $cookie_str);
2895 
2896  if ($this->io_method() == 'socket') {
2897  // send payload
2898  if (!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
2899  $this->setError('couldn\'t write message data to socket');
2900  $this->debug('couldn\'t write message data to socket');
2901  return false;
2902  }
2903  $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
2904  return true;
2905  } elseif ($this->io_method() == 'curl') {
2906  // set payload
2907  // cURL does say this should only be the verb, and in fact it
2908  // turns out that the URI and HTTP version are appended to this, which
2909  // some servers refuse to work with (so we no longer use this method!)
2910  //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
2911  $curl_headers = array();
2912  foreach ($this->outgoing_headers as $k => $v) {
2913  if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
2914  $this->debug("Skip cURL header $k: $v");
2915  } else {
2916  $curl_headers[] = "$k: $v";
2917  }
2918  }
2919  if ($cookie_str != '') {
2920  $curl_headers[] = 'Cookie: ' . $cookie_str;
2921  }
2922  $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
2923  $this->debug('set cURL HTTP headers');
2924  if ($this->request_method == "POST") {
2925  $this->setCurlOption(CURLOPT_POST, 1);
2926  $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
2927  $this->debug('set cURL POST data');
2928  } else {
2929  }
2930  // insert custom user-set cURL options
2931  foreach ($this->ch_options as $key => $val) {
2932  $this->setCurlOption($key, $val);
2933  }
2934 
2935  $this->debug('set cURL payload');
2936  return true;
2937  }
2938  }
2939 
2946  public function getResponse()
2947  {
2948  $this->incoming_payload = '';
2949 
2950  if ($this->io_method() == 'socket') {
2951  // loop until headers have been retrieved
2952  $data = '';
2953  while (!isset($lb)) {
2954  // We might EOF during header read.
2955  if (feof($this->fp)) {
2956  $this->incoming_payload = $data;
2957  $this->debug('found no headers before EOF after length ' . strlen($data));
2958  $this->debug("received before EOF:\n" . $data);
2959  $this->setError('server failed to send headers');
2960  return false;
2961  }
2962 
2963  $tmp = fgets($this->fp, 256);
2964  $tmplen = strlen($tmp);
2965  $this->debug("read line of $tmplen bytes: " . trim($tmp));
2966 
2967  if ($tmplen == 0) {
2968  $this->incoming_payload = $data;
2969  $this->debug('socket read of headers timed out after length ' . strlen($data));
2970  $this->debug("read before timeout: " . $data);
2971  $this->setError('socket read of headers timed out');
2972  return false;
2973  }
2974 
2975  $data .= $tmp;
2976  $pos = strpos($data, "\r\n\r\n");
2977  if ($pos > 1) {
2978  $lb = "\r\n";
2979  } else {
2980  $pos = strpos($data, "\n\n");
2981  if ($pos > 1) {
2982  $lb = "\n";
2983  }
2984  }
2985  // remove 100 headers
2986  if (isset($lb) && preg_match('/^HTTP\/1.1 100/', $data)) {
2987  unset($lb);
2988  $data = '';
2989  }//
2990  }
2991  // store header data
2992  $this->incoming_payload .= $data;
2993  $this->debug('found end of headers after length ' . strlen($data));
2994  // process headers
2995  $header_data = trim(substr($data, 0, $pos));
2996  $header_array = explode($lb, $header_data);
2997  $this->incoming_headers = array();
2998  $this->incoming_cookies = array();
2999  foreach ($header_array as $header_line) {
3000  $arr = explode(':', $header_line, 2);
3001  if (count($arr) > 1) {
3002  $header_name = strtolower(trim($arr[0]));
3003  $this->incoming_headers[$header_name] = trim($arr[1]);
3004  if ($header_name == 'set-cookie') {
3005  // TODO: allow multiple cookies from parseCookie
3006  $cookie = $this->parseCookie(trim($arr[1]));
3007  if ($cookie) {
3008  $this->incoming_cookies[] = $cookie;
3009  $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3010  } else {
3011  $this->debug('did not find cookie in ' . trim($arr[1]));
3012  }
3013  }
3014  } elseif (isset($header_name)) {
3015  // append continuation line to previous header
3016  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3017  }
3018  }
3019 
3020  // loop until msg has been received
3021  if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
3022  $content_length = 2147483647; // ignore any content-length header
3023  $chunked = true;
3024  $this->debug("want to read chunked content");
3025  } elseif (isset($this->incoming_headers['content-length'])) {
3026  $content_length = $this->incoming_headers['content-length'];
3027  $chunked = false;
3028  $this->debug("want to read content of length $content_length");
3029  } else {
3030  $content_length = 2147483647;
3031  $chunked = false;
3032  $this->debug("want to read content to EOF");
3033  }
3034  $data = '';
3035  do {
3036  if ($chunked) {
3037  $tmp = fgets($this->fp, 256);
3038  $tmplen = strlen($tmp);
3039  $this->debug("read chunk line of $tmplen bytes");
3040  if ($tmplen == 0) {
3041  $this->incoming_payload = $data;
3042  $this->debug('socket read of chunk length timed out after length ' . strlen($data));
3043  $this->debug("read before timeout:\n" . $data);
3044  $this->setError('socket read of chunk length timed out');
3045  return false;
3046  }
3047  $content_length = hexdec(trim($tmp));
3048  $this->debug("chunk length $content_length");
3049  }
3050  $strlen = 0;
3051  while (($strlen < $content_length) && (!feof($this->fp))) {
3052  $readlen = min(8192, $content_length - $strlen);
3053  $tmp = fread($this->fp, $readlen);
3054  $tmplen = strlen($tmp);
3055  $this->debug("read buffer of $tmplen bytes");
3056  if (($tmplen == 0) && (!feof($this->fp))) {
3057  $this->incoming_payload = $data;
3058  $this->debug('socket read of body timed out after length ' . strlen($data));
3059  $this->debug("read before timeout:\n" . $data);
3060  $this->setError('socket read of body timed out');
3061  return false;
3062  }
3063  $strlen += $tmplen;
3064  $data .= $tmp;
3065  }
3066  if ($chunked && ($content_length > 0)) {
3067  $tmp = fgets($this->fp, 256);
3068  $tmplen = strlen($tmp);
3069  $this->debug("read chunk terminator of $tmplen bytes");
3070  if ($tmplen == 0) {
3071  $this->incoming_payload = $data;
3072  $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
3073  $this->debug("read before timeout:\n" . $data);
3074  $this->setError('socket read of chunk terminator timed out');
3075  return false;
3076  }
3077  }
3078  } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
3079  if (feof($this->fp)) {
3080  $this->debug('read to EOF');
3081  }
3082  $this->debug('read body of length ' . strlen($data));
3083  $this->incoming_payload .= $data;
3084  $this->debug('received a total of ' . strlen($this->incoming_payload) . ' bytes of data from server');
3085 
3086  // close filepointer
3087  if (
3088  (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
3089  (! $this->persistentConnection) || feof($this->fp)) {
3090  fclose($this->fp);
3091  $this->fp = false;
3092  $this->debug('closed socket');
3093  }
3094 
3095  // connection was closed unexpectedly
3096  if ($this->incoming_payload == '') {
3097  $this->setError('no response from server');
3098  return false;
3099  }
3100 
3101  // decode transfer-encoding
3102  // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
3103  // if(!$data = $this->decodeChunked($data, $lb)){
3104  // $this->setError('Decoding of chunked data failed');
3105  // return false;
3106  // }
3107  //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
3108  // set decoded payload
3109  // $this->incoming_payload = $header_data.$lb.$lb.$data;
3110  // }
3111  } elseif ($this->io_method() == 'curl') {
3112  // send and receive
3113  $this->debug('send and receive with cURL');
3114  $this->incoming_payload = curl_exec($this->ch);
3115  $data = $this->incoming_payload;
3116 
3117  $cErr = curl_error($this->ch);
3118  if ($cErr != '') {
3119  $err = 'cURL ERROR: ' . curl_errno($this->ch) . ': ' . $cErr . '<br>';
3120  // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
3121  foreach (curl_getinfo($this->ch) as $k => $v) {
3122  $err .= "$k: $v<br>";
3123  }
3124  $this->debug($err);
3125  $this->setError($err);
3126  curl_close($this->ch);
3127  return false;
3128  } else {
3129  //echo '<pre>';
3130  //var_dump(curl_getinfo($this->ch));
3131  //echo '</pre>';
3132  }
3133  // close curl
3134  $this->debug('No cURL error, closing cURL');
3135  curl_close($this->ch);
3136 
3137  // try removing skippable headers
3138  $savedata = $data;
3139  while ($this->isSkippableCurlHeader($data)) {
3140  $this->debug("Found HTTP header to skip");
3141  if ($pos = strpos($data, "\r\n\r\n")) {
3142  $data = ltrim(substr($data, $pos));
3143  } elseif ($pos = strpos($data, "\n\n")) {
3144  $data = ltrim(substr($data, $pos));
3145  }
3146  }
3147 
3148  if ($data == '') {
3149  // have nothing left; just remove 100 header(s)
3150  $data = $savedata;
3151  while (preg_match('/^HTTP\/1.1 100/', $data)) {
3152  if ($pos = strpos($data, "\r\n\r\n")) {
3153  $data = ltrim(substr($data, $pos));
3154  } elseif ($pos = strpos($data, "\n\n")) {
3155  $data = ltrim(substr($data, $pos));
3156  }
3157  }
3158  }
3159 
3160  // separate content from HTTP headers
3161  if ($pos = strpos($data, "\r\n\r\n")) {
3162  $lb = "\r\n";
3163  } elseif ($pos = strpos($data, "\n\n")) {
3164  $lb = "\n";
3165  } else {
3166  $this->debug('no proper separation of headers and document');
3167  $this->setError('no proper separation of headers and document');
3168  return false;
3169  }
3170  $header_data = trim(substr($data, 0, $pos));
3171  $header_array = explode($lb, $header_data);
3172  $data = ltrim(substr($data, $pos));
3173  $this->debug('found proper separation of headers and document');
3174  $this->debug('cleaned data, stringlen: ' . strlen($data));
3175  // clean headers
3176  foreach ($header_array as $header_line) {
3177  $arr = explode(':', $header_line, 2);
3178  if (count($arr) > 1) {
3179  $header_name = strtolower(trim($arr[0]));
3180  $this->incoming_headers[$header_name] = trim($arr[1]);
3181  if ($header_name == 'set-cookie') {
3182  // TODO: allow multiple cookies from parseCookie
3183  $cookie = $this->parseCookie(trim($arr[1]));
3184  if ($cookie) {
3185  $this->incoming_cookies[] = $cookie;
3186  $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3187  } else {
3188  $this->debug('did not find cookie in ' . trim($arr[1]));
3189  }
3190  }
3191  } elseif (isset($header_name)) {
3192  // append continuation line to previous header
3193  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3194  }
3195  }
3196  }
3197 
3198  $this->response_status_line = $header_array[0];
3199  $arr = explode(' ', $this->response_status_line, 3);
3200  $http_version = $arr[0];
3201  $http_status = intval($arr[1]);
3202  $http_reason = count($arr) > 2 ? $arr[2] : '';
3203 
3204  // see if we need to resend the request with http digest authentication
3205  if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
3206  $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
3207  $this->setURL($this->incoming_headers['location']);
3208  $this->tryagain = true;
3209  return false;
3210  }
3211 
3212  // see if we need to resend the request with http digest authentication
3213  if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
3214  $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
3215  if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
3216  $this->debug('Server wants digest authentication');
3217  // remove "Digest " from our elements
3218  $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
3219 
3220  // parse elements into array
3221  $digestElements = explode(',', $digestString);
3222  foreach ($digestElements as $val) {
3223  $tempElement = explode('=', trim($val), 2);
3224  $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
3225  }
3226 
3227  // should have (at least) qop, realm, nonce
3228  if (isset($digestRequest['nonce'])) {
3229  $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
3230  $this->tryagain = true;
3231  return false;
3232  }
3233  }
3234  $this->debug('HTTP authentication failed');
3235  $this->setError('HTTP authentication failed');
3236  return false;
3237  }
3238 
3239  if (
3240  ($http_status >= 300 && $http_status <= 307) ||
3241  ($http_status >= 400 && $http_status <= 417) ||
3242  ($http_status >= 501 && $http_status <= 505)
3243  ) {
3244  $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
3245  return false;
3246  }
3247 
3248  // decode content-encoding
3249  if (isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != '') {
3250  if (strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip') {
3251  // if decoding works, use it. else assume data wasn't gzencoded
3252  if (function_exists('gzinflate')) {
3253  //$timer->setMarker('starting decoding of gzip/deflated content');
3254  // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
3255  // this means there are no Zlib headers, although there should be
3256  $this->debug('The gzinflate function exists');
3257  $datalen = strlen($data);
3258  if ($this->incoming_headers['content-encoding'] == 'deflate') {
3259  if ($degzdata = @gzinflate($data)) {
3260  $data = $degzdata;
3261  $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
3262  if (strlen($data) < $datalen) {
3263  // test for the case that the payload has been compressed twice
3264  $this->debug('The inflated payload is smaller than the gzipped one; try again');
3265  if ($degzdata = @gzinflate($data)) {
3266  $data = $degzdata;
3267  $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
3268  }
3269  }
3270  } else {
3271  $this->debug('Error using gzinflate to inflate the payload');
3272  $this->setError('Error using gzinflate to inflate the payload');
3273  }
3274  } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
3275  if ($degzdata = @gzinflate(substr($data, 10))) { // do our best
3276  $data = $degzdata;
3277  $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
3278  if (strlen($data) < $datalen) {
3279  // test for the case that the payload has been compressed twice
3280  $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
3281  if ($degzdata = @gzinflate(substr($data, 10))) {
3282  $data = $degzdata;
3283  $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
3284  }
3285  }
3286  } else {
3287  $this->debug('Error using gzinflate to un-gzip the payload');
3288  $this->setError('Error using gzinflate to un-gzip the payload');
3289  }
3290  }
3291  //$timer->setMarker('finished decoding of gzip/deflated content');
3292  //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
3293  // set decoded payload
3294  $this->incoming_payload = $header_data . $lb . $lb . $data;
3295  } else {
3296  $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3297  $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3298  }
3299  } else {
3300  $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3301  $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3302  }
3303  } else {
3304  $this->debug('No Content-Encoding header');
3305  }
3306 
3307  if (strlen($data) == 0) {
3308  $this->debug('no data after headers!');
3309  $this->setError('no data present after HTTP headers');
3310  return false;
3311  }
3312 
3313  return $data;
3314  }
3315 
3323  public function setContentType($type, $charset = false)
3324  {
3325  $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
3326  }
3327 
3334  public function usePersistentConnection()
3335  {
3336  if (isset($this->outgoing_headers['Accept-Encoding'])) {
3337  return false;
3338  }
3339  $this->protocol_version = '1.1';
3340  $this->persistentConnection = true;
3341  $this->setHeader('Connection', 'Keep-Alive');
3342  return true;
3343  }
3344 
3352  /*
3353  * TODO: allow a Set-Cookie string to be parsed into multiple cookies
3354  */
3355  public function parseCookie($cookie_str)
3356  {
3357  $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
3358  // begin-patch php8
3359  //$data = split(';', $cookie_str);
3360  $data = explode(';', $cookie_str);
3361  $value_str = $data[0];
3362 
3363  $cookie_param = 'domain=';
3364  $start = strpos($cookie_str, $cookie_param);
3365  if ($start > 0) {
3366  $domain = substr($cookie_str, $start + strlen($cookie_param));
3367  $domain = substr($domain, 0, strpos($domain, ';'));
3368  } else {
3369  $domain = '';
3370  }
3371 
3372  $cookie_param = 'expires=';
3373  $start = strpos($cookie_str, $cookie_param);
3374  if ($start > 0) {
3375  $expires = substr($cookie_str, $start + strlen($cookie_param));
3376  $expires = substr($expires, 0, strpos($expires, ';'));
3377  } else {
3378  $expires = '';
3379  }
3380 
3381  $cookie_param = 'path=';
3382  $start = strpos($cookie_str, $cookie_param);
3383  if ($start > 0) {
3384  $path = substr($cookie_str, $start + strlen($cookie_param));
3385  $path = substr($path, 0, strpos($path, ';'));
3386  } else {
3387  $path = '/';
3388  }
3389 
3390  $cookie_param = ';secure;';
3391  if (strpos($cookie_str, $cookie_param) !== false) {
3392  $secure = true;
3393  } else {
3394  $secure = false;
3395  }
3396 
3397  $sep_pos = strpos($value_str, '=');
3398 
3399  if ($sep_pos) {
3400  $name = substr($value_str, 0, $sep_pos);
3401  $value = substr($value_str, $sep_pos + 1);
3402  $cookie = array( 'name' => $name,
3403  'value' => $value,
3404  'domain' => $domain,
3405  'path' => $path,
3406  'expires' => $expires,
3407  'secure' => $secure
3408  );
3409  return $cookie;
3410  }
3411  return false;
3412  }
3413 
3422  public function getCookiesForRequest($cookies, $secure = false)
3423  {
3424  $cookie_str = '';
3425  if ((! is_null($cookies)) && (is_array($cookies))) {
3426  foreach ($cookies as $cookie) {
3427  if (! is_array($cookie)) {
3428  continue;
3429  }
3430  $this->debug("check cookie for validity: " . $cookie['name'] . '=' . $cookie['value']);
3431  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
3432  if (strtotime($cookie['expires']) <= time()) {
3433  $this->debug('cookie has expired');
3434  continue;
3435  }
3436  }
3437  if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
3438  $domain = preg_quote($cookie['domain']);
3439  if (! preg_match("'.*$domain$'i", $this->host)) {
3440  $this->debug('cookie has different domain');
3441  continue;
3442  }
3443  }
3444  if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
3445  $path = preg_quote($cookie['path']);
3446  if (! preg_match("'^$path.*'i", $this->path)) {
3447  $this->debug('cookie is for a different path');
3448  continue;
3449  }
3450  }
3451  if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
3452  $this->debug('cookie is secure, transport is not');
3453  continue;
3454  }
3455  $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3456  $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3457  }
3458  }
3459  return $cookie_str;
3460  }
3461 }
3462 
3463 ?><?php
3464 
3465 
3466 
3477 class nusoap_server extends nusoap_base
3478 {
3479  public $opData;
3485  public $headers = array();
3491  public $request = '';
3497  public $requestHeaders = '';
3503  public $requestHeader = null;
3509  public $document = '';
3515  public $requestSOAP = '';
3521  public $methodURI = '';
3527  public $methodname = '';
3533  public $methodparams = array();
3539  public $SOAPAction = '';
3545  public $xml_encoding = '';
3551  public $decode_utf8 = true;
3552  public $class;
3553 
3559  public $outgoing_headers = array();
3565  public $response = '';
3571  public $responseHeaders = '';
3577  public $responseSOAP = '';
3583  public $methodreturn = false;
3589  public $methodreturnisliteralxml = false;
3595  public $fault = false;
3601  public $result = 'successful';
3602 
3609  public $operations = array();
3615  public $wsdl = false;
3621  public $externalWSDLURL = false;
3627  public $debug_flag = false;
3628 
3629 
3637  public function __construct($wsdl = false)
3638  {
3640  // turn on debugging?
3641  global $debug;
3642  global $HTTP_SERVER_VARS;
3643 
3644  if (isset($_SERVER)) {
3645  $this->debug("_SERVER is defined:");
3646  $this->appendDebug($this->varDump($_SERVER));
3647  } elseif (isset($HTTP_SERVER_VARS)) {
3648  $this->debug("HTTP_SERVER_VARS is defined:");
3649  $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
3650  } else {
3651  $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
3652  }
3653 
3654  if (isset($debug)) {
3655  $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
3656  $this->debug_flag = $debug;
3657  } elseif (isset($_SERVER['QUERY_STRING'])) {
3658  $qs = explode('&', $_SERVER['QUERY_STRING']);
3659  foreach ($qs as $v) {
3660  if (substr($v, 0, 6) == 'debug=') {
3661  $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
3662  $this->debug_flag = substr($v, 6);
3663  }
3664  }
3665  } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3666  $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
3667  foreach ($qs as $v) {
3668  if (substr($v, 0, 6) == 'debug=') {
3669  $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
3670  $this->debug_flag = substr($v, 6);
3671  }
3672  }
3673  }
3674 
3675  // wsdl
3676  if ($wsdl) {
3677  $this->debug("In nusoap_server, WSDL is specified");
3678  if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
3679  $this->wsdl = $wsdl;
3680  $this->externalWSDLURL = $this->wsdl->wsdl;
3681  $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3682  } else {
3683  $this->debug('Create wsdl from ' . $wsdl);
3684  $this->wsdl = new wsdl($wsdl);
3685  $this->externalWSDLURL = $wsdl;
3686  }
3687  $this->appendDebug($this->wsdl->getDebug());
3688  $this->wsdl->clearDebug();
3689  if ($err = $this->wsdl->getError()) {
3690  die('WSDL ERROR: ' . $err);
3691  }
3692  }
3693  }
3694 
3701  public function service($data)
3702  {
3703  global $HTTP_SERVER_VARS;
3704 
3705  if (isset($_SERVER['QUERY_STRING'])) {
3706  $qs = $_SERVER['QUERY_STRING'];
3707  } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3708  $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3709  } else {
3710  $qs = '';
3711  }
3712  $this->debug("In service, query string=$qs");
3713 
3714  if (preg_match('/wsdl/', $qs)) {
3715  $this->debug("In service, this is a request for WSDL");
3716  if ($this->externalWSDLURL) {
3717  if (strpos($this->externalWSDLURL, "://") !== false) { // assume URL
3718  header('Location: ' . $this->externalWSDLURL);
3719  } else { // assume file
3720  header("Content-Type: text/xml\r\n");
3721  $fp = fopen($this->externalWSDLURL, 'r');
3722  fpassthru($fp);
3723  }
3724  } elseif ($this->wsdl) {
3725  header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
3726  print $this->wsdl->serialize($this->debug_flag);
3727  if ($this->debug_flag) {
3728  $this->debug('wsdl:');
3729  $this->appendDebug($this->varDump($this->wsdl));
3730  print $this->getDebugAsXMLComment();
3731  }
3732  } else {
3733  header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3734  print "This service does not provide WSDL";
3735  }
3736  } elseif ($data == '' && $this->wsdl) {
3737  $this->debug("In service, there is no data, so return Web description");
3738  print $this->wsdl->webDescription();
3739  } else {
3740  $this->debug("In service, invoke the request");
3741  $this->parse_request($data);
3742  if (! $this->fault) {
3743  $this->invoke_method();
3744  }
3745  if (! $this->fault) {
3746  $this->serialize_return();
3747  }
3748  $this->send_response();
3749  }
3750  }
3751 
3764  public function parse_http_headers()
3765  {
3766  global $HTTP_SERVER_VARS;
3767 
3768  $this->request = '';
3769  $this->SOAPAction = '';
3770  if (function_exists('getallheaders')) {
3771  $this->debug("In parse_http_headers, use getallheaders");
3772  $headers = getallheaders();
3773  foreach ($headers as $k => $v) {
3774  $k = strtolower($k);
3775  $this->headers[$k] = $v;
3776  $this->request .= "$k: $v\r\n";
3777  $this->debug("$k: $v");
3778  }
3779  // get SOAPAction header
3780  if (isset($this->headers['soapaction'])) {
3781  $this->SOAPAction = str_replace('"', '', $this->headers['soapaction']);
3782  }
3783  // get the character encoding of the incoming request
3784  if (isset($this->headers['content-type']) && strpos($this->headers['content-type'], '=')) {
3785  $enc = str_replace('"', '', substr(strstr($this->headers["content-type"], '='), 1));
3786  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3787  $this->xml_encoding = strtoupper($enc);
3788  } else {
3789  $this->xml_encoding = 'US-ASCII';
3790  }
3791  } else {
3792  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3793  $this->xml_encoding = 'ISO-8859-1';
3794  }
3795  } elseif (isset($_SERVER) && is_array($_SERVER)) {
3796  $this->debug("In parse_http_headers, use _SERVER");
3797  foreach ($_SERVER as $k => $v) {
3798  if (substr($k, 0, 5) == 'HTTP_') {
3799  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3800  } else {
3801  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3802  }
3803  if ($k == 'soapaction') {
3804  // get SOAPAction header
3805  $k = 'SOAPAction';
3806  $v = str_replace('"', '', $v);
3807  $v = str_replace('\\', '', $v);
3808  $this->SOAPAction = $v;
3809  } elseif ($k == 'content-type') {
3810  // get the character encoding of the incoming request
3811  if (strpos($v, '=')) {
3812  $enc = substr(strstr($v, '='), 1);
3813  $enc = str_replace('"', '', $enc);
3814  $enc = str_replace('\\', '', $enc);
3815  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3816  $this->xml_encoding = strtoupper($enc);
3817  } else {
3818  $this->xml_encoding = 'US-ASCII';
3819  }
3820  } else {
3821  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3822  $this->xml_encoding = 'ISO-8859-1';
3823  }
3824  }
3825  $this->headers[$k] = $v;
3826  $this->request .= "$k: $v\r\n";
3827  $this->debug("$k: $v");
3828  }
3829  } elseif (is_array($HTTP_SERVER_VARS)) {
3830  $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
3831  foreach ($HTTP_SERVER_VARS as $k => $v) {
3832  if (substr($k, 0, 5) == 'HTTP_') {
3833  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3834  $k = strtolower(substr($k, 5));
3835  } else {
3836  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3837  $k = strtolower($k);
3838  }
3839  if ($k == 'soapaction') {
3840  // get SOAPAction header
3841  $k = 'SOAPAction';
3842  $v = str_replace('"', '', $v);
3843  $v = str_replace('\\', '', $v);
3844  $this->SOAPAction = $v;
3845  } elseif ($k == 'content-type') {
3846  // get the character encoding of the incoming request
3847  if (strpos($v, '=')) {
3848  $enc = substr(strstr($v, '='), 1);
3849  $enc = str_replace('"', '', $enc);
3850  $enc = str_replace('\\', '', $enc);
3851  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3852  $this->xml_encoding = strtoupper($enc);
3853  } else {
3854  $this->xml_encoding = 'US-ASCII';
3855  }
3856  } else {
3857  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3858  $this->xml_encoding = 'ISO-8859-1';
3859  }
3860  }
3861  $this->headers[$k] = $v;
3862  $this->request .= "$k: $v\r\n";
3863  $this->debug("$k: $v");
3864  }
3865  } else {
3866  $this->debug("In parse_http_headers, HTTP headers not accessible");
3867  $this->setError("HTTP headers not accessible");
3868  }
3869  }
3870 
3893  public function parse_request($data = '')
3894  {
3895  $this->debug('entering parse_request()');
3896  $this->parse_http_headers();
3897  $this->debug('got character encoding: ' . $this->xml_encoding);
3898  // uncompress if necessary
3899  if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
3900  $this->debug('got content encoding: ' . $this->headers['content-encoding']);
3901  if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
3902  // if decoding works, use it. else assume data wasn't gzencoded
3903  if (function_exists('gzuncompress')) {
3904  if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
3905  $data = $degzdata;
3906  } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
3907  $data = $degzdata;
3908  } else {
3909  $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
3910  return;
3911  }
3912  } else {
3913  $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
3914  return;
3915  }
3916  }
3917  }
3918  $this->request .= "\r\n" . $data;
3919  $data = $this->parseRequest($this->headers, $data);
3920  $this->requestSOAP = $data;
3921  $this->debug('leaving parse_request');
3922  }
3923 
3941  public function invoke_method()
3942  {
3943  $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
3944 
3945  if ($this->wsdl) {
3946  if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
3947  $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
3948  $this->appendDebug('opData=' . $this->varDump($this->opData));
3949  } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
3950  // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
3951  $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
3952  $this->appendDebug('opData=' . $this->varDump($this->opData));
3953  $this->methodname = $this->opData['name'];
3954  } else {
3955  $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
3956  $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
3957  return;
3958  }
3959  } else {
3960  $this->debug('in invoke_method, no WSDL to validate method');
3961  }
3962 
3963  // if a . is present in $this->methodname, we see if there is a class in scope,
3964  // which could be referred to. We will also distinguish between two deliminators,
3965  // to allow methods to be called a the class or an instance
3966  $class = '';
3967  $method = '';
3968  if (strpos($this->methodname, '..') > 0) {
3969  $delim = '..';
3970  } elseif (strpos($this->methodname, '.') > 0) {
3971  $delim = '.';
3972  } else {
3973  $delim = '';
3974  }
3975 
3976  if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 &&
3977  class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
3978  // get the class and method name
3979  $class = substr($this->methodname, 0, strpos($this->methodname, $delim));
3980  $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
3981  $this->debug("in invoke_method, class=$class method=$method delim=$delim");
3982  }
3983  // set class handler
3984  // added to support single operations
3985  if ($class == '' && $this->class != '') {
3986  $class = $this->class;
3987  $delim = "..";
3988  $method = $this->methodname;
3989  }
3990 
3991  // does method exist?
3992  if ($class == '') {
3993  if (!function_exists($this->methodname)) {
3994  $this->debug("in invoke_method, function '$this->methodname' not found!");
3995  $this->result = 'fault: method not found';
3996  $this->fault('SOAP-ENV:Client', "method '$this->methodname' not defined in service");
3997  return;
3998  }
3999  } else {
4000  $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
4001  if (!in_array($method_to_compare, get_class_methods($class))) {
4002  $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
4003  $this->result = 'fault: method not found';
4004  $this->fault('SOAP-ENV:Client', "method '$this->methodname' not defined in service");
4005  return;
4006  }
4007  }
4008 
4009  // evaluate message, getting back parameters
4010  // verify that request parameters match the method's signature
4011  if (! $this->verify_method($this->methodname, $this->methodparams)) {
4012  // debug
4013  $this->debug('ERROR: request not verified against method signature');
4014  $this->result = 'fault: request failed validation against method signature';
4015  // return fault
4016  $this->fault('SOAP-ENV:Client', "Operation '$this->methodname' not defined in service.");
4017  return;
4018  }
4019 
4020  // if there are parameters to pass
4021  $this->debug('in invoke_method, params:');
4022  $this->appendDebug($this->varDump($this->methodparams));
4023  $this->debug("in invoke_method, calling '$this->methodname'");
4024  if (!function_exists('call_user_func_array')) {
4025  if ($class == '') {
4026  $this->debug('in invoke_method, calling function using eval()');
4027  $funcCall = "\$this->methodreturn = $this->methodname(";
4028  } else {
4029  if ($delim == '..') {
4030  $this->debug('in invoke_method, calling class method using eval()');
4031  $funcCall = "\$this->methodreturn = " . $class . "::" . $method . "(";
4032  } else {
4033  $this->debug('in invoke_method, calling instance method using eval()');
4034  // generate unique instance name
4035  $instname = "\$inst_" . time();
4036  $funcCall = $instname . " = new " . $class . "(); ";
4037  $funcCall .= "\$this->methodreturn = " . $instname . "->" . $method . "(";
4038  }
4039  }
4040  if ($this->methodparams) {
4041  foreach ($this->methodparams as $param) {
4042  if (is_array($param) || is_object($param)) {
4043  $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
4044  return;
4045  }
4046  $funcCall .= "\"$param\",";
4047  }
4048  $funcCall = substr($funcCall, 0, -1);
4049  }
4050  $funcCall .= ');';
4051  $this->debug('in invoke_method, function call: ' . $funcCall);
4052  @eval($funcCall);
4053  } else {
4054  if ($class == '') {
4055  $this->debug('in invoke_method, calling function using call_user_func_array()');
4056  $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array()
4057  } elseif ($delim == '..') {
4058  $this->debug('in invoke_method, calling class method using call_user_func_array()');
4059  $call_arg = array($class, $method);
4060  } else {
4061  $this->debug('in invoke_method, calling instance method using call_user_func_array()');
4062  $instance = new $class();
4063  $call_arg = array(&$instance, $method);
4064  }
4065  if (is_array($this->methodparams)) {
4066  $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
4067  } else {
4068  $this->methodreturn = call_user_func_array($call_arg, array());
4069  }
4070  }
4071  $this->debug('in invoke_method, methodreturn:');
4072  $this->appendDebug($this->varDump($this->methodreturn));
4073  $this->debug("in invoke_method, called method $this->methodname, received data of type " . gettype($this->methodreturn));
4074  }
4075 
4087  public function serialize_return()
4088  {
4089  $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4090  // if fault
4091  if (isset($this->methodreturn) && ((get_class((object) $this->methodreturn) == 'soap_fault') || (get_class((object) $this->methodreturn) == 'nusoap_fault'))) {
4092  $this->debug('got a fault object from method');
4093  $this->fault = $this->methodreturn;
4094  return;
4095  } elseif ($this->methodreturnisliteralxml) {
4096  $return_val = $this->methodreturn;
4097  // returned value(s)
4098  } else {
4099  $this->debug('got a(n) ' . gettype($this->methodreturn) . ' from method');
4100  $this->debug('serializing return value');
4101  if ($this->wsdl) {
4102  if (sizeof($this->opData['output']['parts']) > 1) {
4103  $this->debug('more than one output part, so use the method return unchanged');
4104  $opParams = $this->methodreturn;
4105  } elseif (sizeof($this->opData['output']['parts']) == 1) {
4106  $this->debug('exactly one output part, so wrap the method return in a simple array');
4107  // TODO: verify that it is not already wrapped!
4108  //foreach ($this->opData['output']['parts'] as $name => $type) {
4109  // $this->debug('wrap in element named ' . $name);
4110  //}
4111  $opParams = array($this->methodreturn);
4112  }
4113  $return_val = $this->wsdl->serializeRPCParameters($this->methodname, 'output', $opParams);
4114  $this->appendDebug($this->wsdl->getDebug());
4115  $this->wsdl->clearDebug();
4116  if ($errstr = $this->wsdl->getError()) {
4117  $this->debug('got wsdl error: ' . $errstr);
4118  $this->fault('SOAP-ENV:Server', 'unable to serialize result');
4119  return;
4120  }
4121  } else {
4122  if (isset($this->methodreturn)) {
4123  $return_val = $this->serialize_val($this->methodreturn, 'return');
4124  } else {
4125  $return_val = '';
4126  $this->debug('in absence of WSDL, assume void return for backward compatibility');
4127  }
4128  }
4129  }
4130  $this->debug('return value:');
4131  $this->appendDebug($this->varDump($return_val));
4132 
4133  $this->debug('serializing response');
4134  if ($this->wsdl) {
4135  $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
4136  if ($this->opData['style'] == 'rpc') {
4137  $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
4138  if ($this->opData['output']['use'] == 'literal') {
4139  // 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
4140  $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4141  } else {
4142  $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4143  }
4144  } else {
4145  $this->debug('style is not rpc for serialization: assume document');
4146  $payload = $return_val;
4147  }
4148  } else {
4149  $this->debug('do not have WSDL for serialization: assume rpc/encoded');
4150  $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4151  }
4152  $this->result = 'successful';
4153  if ($this->wsdl) {
4154  //if($this->debug_flag){
4155  $this->appendDebug($this->wsdl->getDebug());
4156  // }
4157  if (isset($opData['output']['encodingStyle'])) {
4158  $encodingStyle = $opData['output']['encodingStyle'];
4159  } else {
4160  $encodingStyle = '';
4161  }
4162  // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
4163  $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders, $this->wsdl->usedNamespaces, $this->opData['style'], $this->opData['output']['use'], $encodingStyle);
4164  } else {
4165  $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders);
4166  }
4167  $this->debug("Leaving serialize_return");
4168  }
4169 
4180  public function send_response()
4181  {
4182  $this->debug('Enter send_response');
4183  if ($this->fault) {
4184  $payload = $this->fault->serialize();
4185  $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
4186  $this->outgoing_headers[] = "Status: 500 Internal Server Error";
4187  } else {
4188  $payload = $this->responseSOAP;
4189  // Some combinations of PHP+Web server allow the Status
4190  // to come through as a header. Since OK is the default
4191  // just do nothing.
4192  // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
4193  // $this->outgoing_headers[] = "Status: 200 OK";
4194  }
4195  // add debug data if in debug mode
4196  if (isset($this->debug_flag) && $this->debug_flag) {
4197  $payload .= $this->getDebugAsXMLComment();
4198  }
4199  $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
4200  preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
4201  $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (" . $rev[1] . ")";
4202  // Let the Web server decide about this
4203  //$this->outgoing_headers[] = "Connection: Close\r\n";
4204  $payload = $this->getHTTPBody($payload);
4205  $type = $this->getHTTPContentType();
4206  $charset = $this->getHTTPContentTypeCharset();
4207  $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
4208  //begin code to compress payload - by John
4209  // NOTE: there is no way to know whether the Web server will also compress
4210  // this data.
4211  if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
4212  if (strstr($this->headers['accept-encoding'], 'gzip')) {
4213  if (function_exists('gzencode')) {
4214  if (isset($this->debug_flag) && $this->debug_flag) {
4215  $payload .= "<!-- Content being gzipped -->";
4216  }
4217  $this->outgoing_headers[] = "Content-Encoding: gzip";
4218  $payload = gzencode($payload);
4219  } else {
4220  if (isset($this->debug_flag) && $this->debug_flag) {
4221  $payload .= "<!-- Content will not be gzipped: no gzencode -->";
4222  }
4223  }
4224  } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
4225  // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
4226  // instead of gzcompress output,
4227  // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
4228  if (function_exists('gzdeflate')) {
4229  if (isset($this->debug_flag) && $this->debug_flag) {
4230  $payload .= "<!-- Content being deflated -->";
4231  }
4232  $this->outgoing_headers[] = "Content-Encoding: deflate";
4233  $payload = gzdeflate($payload);
4234  } else {
4235  if (isset($this->debug_flag) && $this->debug_flag) {
4236  $payload .= "<!-- Content will not be deflated: no gzcompress -->";
4237  }
4238  }
4239  }
4240  }
4241  //end code
4242  $this->outgoing_headers[] = "Content-Length: " . strlen($payload);
4243  reset($this->outgoing_headers);
4244  foreach ($this->outgoing_headers as $hdr) {
4245  header($hdr, false);
4246  }
4247  print $payload;
4248  $this->response = join("\r\n", $this->outgoing_headers) . "\r\n\r\n" . $payload;
4249  }
4250 
4260  public function verify_method($operation, $request)
4261  {
4262  if (isset($this->wsdl) && is_object($this->wsdl)) {
4263  if ($this->wsdl->getOperationData($operation)) {
4264  return true;
4265  }
4266  } elseif (isset($this->operations[$operation])) {
4267  return true;
4268  }
4269  return false;
4270  }
4271 
4280  public function parseRequest($headers, $data)
4281  {
4282  $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
4283  if (!strstr($headers['content-type'], 'text/xml')) {
4284  $this->setError('Request not of type text/xml');
4285  return false;
4286  }
4287  if (strpos($headers['content-type'], '=')) {
4288  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
4289  $this->debug('Got response encoding: ' . $enc);
4290  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4291  $this->xml_encoding = strtoupper($enc);
4292  } else {
4293  $this->xml_encoding = 'US-ASCII';
4294  }
4295  } else {
4296  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4297  $this->xml_encoding = 'ISO-8859-1';
4298  }
4299  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
4300  // parse response, get soap parser obj
4301  $parser = new nusoap_parser($data, $this->xml_encoding, '', $this->decode_utf8);
4302  // parser debug
4303  $this->debug("parser debug: \n" . $parser->getDebug());
4304  // if fault occurred during message parsing
4305  if ($err = $parser->getError()) {
4306  $this->result = 'fault: error in msg parsing: ' . $err;
4307  $this->fault('SOAP-ENV:Client', "error in msg parsing:\n" . $err);
4308  // else successfully parsed request into soapval object
4309  } else {
4310  // get/set methodname
4311  $this->methodURI = $parser->root_struct_namespace;
4312  $this->methodname = $parser->root_struct_name;
4313  $this->debug('methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4314  $this->debug('calling parser->get_soapbody()');
4315  $this->methodparams = $parser->get_soapbody();
4316  // get SOAP headers
4317  $this->requestHeaders = $parser->getHeaders();
4318  // get SOAP Header
4319  $this->requestHeader = $parser->get_soapheader();
4320  // add document for doclit support
4321  $this->document = $parser->document;
4322  }
4323  }
4324 
4332  public function getHTTPBody($soapmsg)
4333  {
4334  return $soapmsg;
4335  }
4336 
4345  public function getHTTPContentType()
4346  {
4347  return 'text/xml';
4348  }
4349 
4359  public function getHTTPContentTypeCharset()
4360  {
4361  return $this->soap_defencoding;
4362  }
4363 
4373  public function add_to_map($methodname, $in, $out)
4374  {
4375  $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
4376  }
4377 
4392  public function register($name, $in = array(), $out = array(), $namespace = false, $soapaction = false, $style = false, $use = false, $documentation = '', $encodingStyle = '')
4393  {
4394  global $HTTP_SERVER_VARS;
4395 
4396  if ($this->externalWSDLURL) {
4397  die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
4398  }
4399  if (! $name) {
4400  die('You must specify a name when you register an operation');
4401  }
4402  if (!is_array($in)) {
4403  die('You must provide an array for operation inputs');
4404  }
4405  if (!is_array($out)) {
4406  die('You must provide an array for operation outputs');
4407  }
4408  if (false == $namespace) {
4409  }
4410  if (false == $soapaction) {
4411  if (isset($_SERVER)) {
4412  $SERVER_NAME = $_SERVER['SERVER_NAME'];
4413  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4414  $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4415  } elseif (isset($HTTP_SERVER_VARS)) {
4416  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4417  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4418  $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4419  } else {
4420  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4421  }
4422  if ($HTTPS == '1' || $HTTPS == 'on') {
4423  $SCHEME = 'https';
4424  } else {
4425  $SCHEME = 'http';
4426  }
4427  $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
4428  }
4429  if (false == $style) {
4430  $style = "rpc";
4431  }
4432  if (false == $use) {
4433  $use = "encoded";
4434  }
4435  if ($use == 'encoded' && $encodingStyle = '') {
4436  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
4437  }
4438 
4439  $this->operations[$name] = array(
4440  'name' => $name,
4441  'in' => $in,
4442  'out' => $out,
4443  'namespace' => $namespace,
4444  'soapaction' => $soapaction,
4445  'style' => $style);
4446  if ($this->wsdl) {
4447  $this->wsdl->addOperation($name, $in, $out, $namespace, $soapaction, $style, $use, $documentation, $encodingStyle);
4448  }
4449  return true;
4450  }
4451 
4462  public function fault($faultcode, $faultstring, $faultactor = '', $faultdetail = '')
4463  {
4464  if ($faultdetail == '' && $this->debug_flag) {
4465  $faultdetail = $this->getDebug();
4466  }
4467  $this->fault = new nusoap_fault($faultcode, $faultactor, $faultstring, $faultdetail);
4468  $this->fault->soap_defencoding = $this->soap_defencoding;
4469  }
4470 
4482  public function configureWSDL($serviceName, $namespace = false, $endpoint = false, $style = 'rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
4483  {
4484  global $HTTP_SERVER_VARS;
4485 
4486  if (isset($_SERVER)) {
4487  $SERVER_NAME = $_SERVER['SERVER_NAME'];
4488  $SERVER_PORT = $_SERVER['SERVER_PORT'];
4489  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4490  $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4491  } elseif (isset($HTTP_SERVER_VARS)) {
4492  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4493  $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
4494  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4495  $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4496  } else {
4497  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4498  }
4499  // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
4500  $colon = strpos($SERVER_NAME, ":");
4501  if ($colon) {
4502  $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
4503  }
4504  if ($SERVER_PORT == 80) {
4505  $SERVER_PORT = '';
4506  } else {
4507  $SERVER_PORT = ':' . $SERVER_PORT;
4508  }
4509  if (false == $namespace) {
4510  $namespace = "http://$SERVER_NAME/soap/$serviceName";
4511  }
4512 
4513  if (false == $endpoint) {
4514  if ($HTTPS == '1' || $HTTPS == 'on') {
4515  $SCHEME = 'https';
4516  } else {
4517  $SCHEME = 'http';
4518  }
4519  $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
4520  }
4521 
4522  if (false == $schemaTargetNamespace) {
4523  $schemaTargetNamespace = $namespace;
4524  }
4525 
4526  $this->wsdl = new wsdl();
4527  $this->wsdl->serviceName = $serviceName;
4528  $this->wsdl->endpoint = $endpoint;
4529  $this->wsdl->namespaces['tns'] = $namespace;
4530  $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
4531  $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
4532  if ($schemaTargetNamespace != $namespace) {
4533  $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4534  }
4535  $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
4536  if ($style == 'document') {
4537  $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
4538  }
4539  $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
4540  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
4541  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
4542  $this->wsdl->bindings[$serviceName . 'Binding'] = array(
4543  'name' => $serviceName . 'Binding',
4544  'style' => $style,
4545  'transport' => $transport,
4546  'portType' => $serviceName . 'PortType');
4547  $this->wsdl->ports[$serviceName . 'Port'] = array(
4548  'binding' => $serviceName . 'Binding',
4549  'location' => $endpoint,
4550  'bindingType' => 'http://schemas.xmlsoap.org/wsdl/soap/');
4551  }
4552 
4553  public function addInternalPort(string $serviceName, string $url): void
4554  {
4555  $port = $this->wsdl->ports[$serviceName . 'Port'] ?? [
4556  'binding' => $serviceName . 'Binding',
4557  'location' => [],
4558  'bindingType' => 'http://schemas.xmlsoap.org/wsdl/soap/'
4559  ];
4560 
4561  $port['location'] = is_array($port['location']) ? array_merge($port['location'], [$url]) : [$port['location'], $url];
4562 
4563  $this->wsdl->ports[$serviceName . 'Port'] = $port;
4564  }
4565 }
4566 
4570 class soap_server extends nusoap_server
4571 {
4572 }
4573 
4574 ?><?php
4575 
4576 
4577 
4587 class wsdl extends nusoap_base
4588 {
4589  // URL or filename of the root of this WSDL
4590  public $serviceName;
4591  public $opStatus;
4592  public $currentPortOperation;
4593  public $wsdl;
4594  // define internal arrays of bindings, ports, operations, messages, etc.
4595  public $schemas = array();
4596  public $currentSchema;
4597  public $message = array();
4598  public $complexTypes = array();
4599  public $messages = array();
4600  public $currentMessage;
4601  public $currentOperation;
4602  public $portTypes = array();
4603  public $currentPortType;
4604  public $bindings = array();
4605  public $currentBinding;
4606  public $ports = array();
4607  public $currentPort;
4608  public $opData = array();
4609  public $status = '';
4610  public $documentation = false;
4611  public $endpoint = '';
4612  // array of wsdl docs to import
4613  public $import = array();
4614  // parser vars
4615  public $parser;
4616  public $position = 0;
4617  public $depth = 0;
4618  public $depth_array = array();
4619  // for getting wsdl
4620  public $proxyhost = '';
4621  public $proxyport = '';
4622  public $proxyusername = '';
4623  public $proxypassword = '';
4624  public $timeout = 0;
4625  public $response_timeout = 30;
4626  public $curl_options = array(); // User-specified cURL options
4627  public $use_curl = false; // whether to always try to use cURL
4628  // for HTTP authentication
4629  public $username = ''; // Username for HTTP authentication
4630  public $password = ''; // Password for HTTP authentication
4631  public $authtype = ''; // Type of HTTP authentication
4632  public $certRequest = array(); // Certificate for HTTP SSL authentication
4633 
4648  public function __construct($wsdl = '', $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $curl_options = null, $use_curl = false)
4649  {
4651  $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
4652  $this->proxyhost = $proxyhost;
4653  $this->proxyport = $proxyport;
4654  $this->proxyusername = $proxyusername;
4655  $this->proxypassword = $proxypassword;
4656  $this->timeout = $timeout;
4657  $this->response_timeout = $response_timeout;
4658  if (is_array($curl_options)) {
4659  $this->curl_options = $curl_options;
4660  }
4661  $this->use_curl = $use_curl;
4662  $this->fetchWSDL($wsdl);
4663  }
4664 
4670  public function fetchWSDL($wsdl)
4671  {
4672  $this->debug("parse and process WSDL path=$wsdl");
4673  $this->wsdl = $wsdl;
4674  // parse wsdl file
4675  if ($this->wsdl != "") {
4676  $this->parseWSDL($this->wsdl);
4677  }
4678  // imports
4679  // TODO: handle imports more properly, grabbing them in-line and nesting them
4680  $imported_urls = array();
4681  $imported = 1;
4682  while ($imported > 0) {
4683  $imported = 0;
4684  // Schema imports
4685  foreach ($this->schemas as $ns => $list) {
4686  foreach ($list as $xs) {
4687  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4688  foreach ($xs->imports as $ns2 => $list2) {
4689  for ($ii = 0; $ii < count($list2); $ii++) {
4690  if (! $list2[$ii]['loaded']) {
4691  $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
4692  $url = $list2[$ii]['location'];
4693  if ($url != '') {
4694  $urlparts = parse_url($url);
4695  if (!isset($urlparts['host'])) {
4696  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4697  substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
4698  }
4699  if (! in_array($url, $imported_urls)) {
4700  $this->parseWSDL($url);
4701  $imported++;
4702  $imported_urls[] = $url;
4703  }
4704  } else {
4705  $this->debug("Unexpected scenario: empty URL for unloaded import");
4706  }
4707  }
4708  }
4709  }
4710  }
4711  }
4712  // WSDL imports
4713  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4714  foreach ($this->import as $ns => $list) {
4715  for ($ii = 0; $ii < count($list); $ii++) {
4716  if (! $list[$ii]['loaded']) {
4717  $this->import[$ns][$ii]['loaded'] = true;
4718  $url = $list[$ii]['location'];
4719  if ($url != '') {
4720  $urlparts = parse_url($url);
4721  if (!isset($urlparts['host'])) {
4722  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4723  substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
4724  }
4725  if (! in_array($url, $imported_urls)) {
4726  $this->parseWSDL($url);
4727  $imported++;
4728  $imported_urls[] = $url;
4729  }
4730  } else {
4731  $this->debug("Unexpected scenario: empty URL for unloaded import");
4732  }
4733  }
4734  }
4735  }
4736  }
4737  // add new data to operation data
4738  foreach ($this->bindings as $binding => $bindingData) {
4739  if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
4740  foreach ($bindingData['operations'] as $operation => $data) {
4741  $this->debug('post-parse data gathering for ' . $operation);
4742  $this->bindings[$binding]['operations'][$operation]['input'] =
4743  isset($this->bindings[$binding]['operations'][$operation]['input']) ?
4744  array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
4745  $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
4746  $this->bindings[$binding]['operations'][$operation]['output'] =
4747  isset($this->bindings[$binding]['operations'][$operation]['output']) ?
4748  array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
4749  $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
4750  if (isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])) {
4751  $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
4752  }
4753  if (isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])) {
4754  $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
4755  }
4756  // Set operation style if necessary, but do not override one already provided
4757  if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
4758  $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
4759  }
4760  $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
4761  $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
4762  $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
4763  }
4764  }
4765  }
4766  }
4767 
4774  public function parseWSDL($wsdl = '')
4775  {
4776  $this->debug("parse WSDL at path=$wsdl");
4777 
4778  if ($wsdl == '') {
4779  $this->debug('no wsdl passed to parseWSDL()!!');
4780  $this->setError('no wsdl passed to parseWSDL()!!');
4781  return false;
4782  }
4783 
4784  // parse $wsdl for url format
4785  $wsdl_props = parse_url($wsdl);
4786 
4787  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
4788  $this->debug('getting WSDL http(s) URL ' . $wsdl);
4789  // get wsdl
4790  $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
4791  $tr->request_method = 'GET';
4792  $tr->useSOAPAction = false;
4793  if ($this->proxyhost && $this->proxyport) {
4794  $tr->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
4795  }
4796  if ($this->authtype != '') {
4797  $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
4798  }
4799  $tr->setEncoding('gzip, deflate');
4800  $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
4801  //$this->debug("WSDL request\n" . $tr->outgoing_payload);
4802  //$this->debug("WSDL response\n" . $tr->incoming_payload);
4803  $this->appendDebug($tr->getDebug());
4804  // catch errors
4805  if ($err = $tr->getError()) {
4806  $errstr = 'HTTP ERROR: ' . $err;
4807  $this->debug($errstr);
4808  $this->setError($errstr);
4809  unset($tr);
4810  return false;
4811  }
4812  unset($tr);
4813  $this->debug("got WSDL URL");
4814  } else {
4815  // $wsdl is not http(s), so treat it as a file URL or plain file path
4816  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
4817  $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
4818  } else {
4819  $path = $wsdl;
4820  }
4821  $this->debug('getting WSDL file ' . $path);
4822  if ($fp = @fopen($path, 'r')) {
4823  $wsdl_string = '';
4824  while ($data = fread($fp, 32768)) {
4825  $wsdl_string .= $data;
4826  }
4827  fclose($fp);
4828  } else {
4829  $errstr = "Bad path to WSDL file $path";
4830  $this->debug($errstr);
4831  $this->setError($errstr);
4832  return false;
4833  }
4834  }
4835  $this->debug('Parse WSDL');
4836  // end new code added
4837  // Create an XML parser.
4838  $this->parser = xml_parser_create();
4839  // Set the options for parsing the XML data.
4840  // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
4841  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
4842  // Set the object for the parser.
4843  // Set the element handlers for the parser.
4844  xml_set_element_handler($this->parser, $this->start_element(...), $this->end_element(...));
4845  xml_set_character_data_handler($this->parser, $this->character_data(...));
4846  // Parse the XML file.
4847  if (!xml_parse($this->parser, $wsdl_string, true)) {
4848  // Display an error message.
4849  $errstr = sprintf(
4850  'XML error parsing WSDL from %s on line %d: %s',
4851  $wsdl,
4852  xml_get_current_line_number($this->parser),
4853  xml_error_string(xml_get_error_code($this->parser))
4854  );
4855  $this->debug($errstr);
4856  $this->debug("XML payload:\n" . $wsdl_string);
4857  $this->setError($errstr);
4858  return false;
4859  }
4860  // free the parser
4861  xml_parser_free($this->parser);
4862  $this->debug('Parsing WSDL done');
4863  // catch wsdl parse errors
4864  if ($this->getError()) {
4865  return false;
4866  }
4867  return true;
4868  }
4869 
4878  public function start_element($parser, $name, $attrs)
4879  {
4880  if ($this->status == 'schema') {
4881  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4882  $this->appendDebug($this->currentSchema->getDebug());
4883  $this->currentSchema->clearDebug();
4884  } elseif (preg_match('/schema$/', $name)) {
4885  $this->debug('Parsing WSDL schema');
4886  // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
4887  $this->status = 'schema';
4888  $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
4889  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4890  $this->appendDebug($this->currentSchema->getDebug());
4891  $this->currentSchema->clearDebug();
4892  } else {
4893  // position in the total number of elements, starting from 0
4894  $pos = $this->position++;
4895  $depth = $this->depth++;
4896  // set self as current value for this depth
4897  $this->depth_array[$depth] = $pos;
4898  $this->message[$pos] = array('cdata' => '');
4899  // process attributes
4900  if (count($attrs) > 0) {
4901  // register namespace declarations
4902  foreach ($attrs as $k => $v) {
4903  if (preg_match('/^xmlns/', $k)) {
4904  if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
4905  $this->namespaces[$ns_prefix] = $v;
4906  } else {
4907  $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
4908  }
4909  if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
4910  $this->XMLSchemaVersion = $v;
4911  $this->namespaces['xsi'] = $v . '-instance';
4912  }
4913  }
4914  }
4915  // expand each attribute prefix to its namespace
4916  foreach ($attrs as $k => $v) {
4917  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
4918  if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
4919  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
4920  }
4921  $eAttrs[$k] = $v;
4922  }
4923  $attrs = $eAttrs;
4924  } else {
4925  $attrs = array();
4926  }
4927  // get element prefix, namespace and name
4928  if (preg_match('/:/', $name)) {
4929  // get ns prefix
4930  $prefix = substr($name, 0, strpos($name, ':'));
4931  // get ns
4932  $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
4933  // get unqualified name
4934  $name = substr(strstr($name, ':'), 1);
4935  }
4936  // process attributes, expanding any prefixes to namespaces
4937  // find status, register data
4938  switch ($this->status) {
4939  case 'message':
4940  if ($name == 'part') {
4941  if (isset($attrs['type'])) {
4942  $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
4943  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
4944  }
4945  if (isset($attrs['element'])) {
4946  $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
4947  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
4948  }
4949  }
4950  break;
4951  case 'portType':
4952  switch ($name) {
4953  case 'operation':
4954  $this->currentPortOperation = $attrs['name'];
4955  $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
4956  if (isset($attrs['parameterOrder'])) {
4957  $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
4958  }
4959  break;
4960  case 'documentation':
4961  $this->documentation = true;
4962  break;
4963  // merge input/output data
4964  default:
4965  $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
4966  $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
4967  break;
4968  }
4969  break;
4970  case 'binding':
4971  switch ($name) {
4972  case 'binding':
4973  // get ns prefix
4974  if (isset($attrs['style'])) {
4975  $this->bindings[$this->currentBinding]['prefix'] = $prefix;
4976  }
4977  $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
4978  break;
4979  case 'header':
4980  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
4981  break;
4982  case 'operation':
4983  if (isset($attrs['soapAction'])) {
4984  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
4985  }
4986  if (isset($attrs['style'])) {
4987  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
4988  }
4989  if (isset($attrs['name'])) {
4990  $this->currentOperation = $attrs['name'];
4991  $this->debug("current binding operation: $this->currentOperation");
4992  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
4993  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
4994  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
4995  }
4996  break;
4997  case 'input':
4998  $this->opStatus = 'input';
4999  break;
5000  case 'output':
5001  $this->opStatus = 'output';
5002  break;
5003  case 'body':
5004  if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
5005  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
5006  } else {
5007  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
5008  }
5009  break;
5010  }
5011  break;
5012  case 'service':
5013  switch ($name) {
5014  case 'port':
5015  $this->currentPort = $attrs['name'];
5016  $this->debug('current port: ' . $this->currentPort);
5017  $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
5018 
5019  break;
5020  case 'address':
5021  $this->ports[$this->currentPort]['location'] = $attrs['location'];
5022  $this->ports[$this->currentPort]['bindingType'] = $namespace;
5023  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
5024  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
5025  break;
5026  }
5027  break;
5028  }
5029  // set status
5030  switch ($name) {
5031  case 'import':
5032  if (isset($attrs['location'])) {
5033  $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
5034  $this->debug('parsing import ' . $attrs['namespace'] . ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]) . ')');
5035  } else {
5036  $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
5037  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
5038  $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace'];
5039  }
5040  $this->debug('parsing import ' . $attrs['namespace'] . ' - [no location] (' . count($this->import[$attrs['namespace']]) . ')');
5041  }
5042  break;
5043  //wait for schema
5044  //case 'types':
5045  // $this->status = 'schema';
5046  // break;
5047  case 'message':
5048  $this->status = 'message';
5049  $this->messages[$attrs['name']] = array();
5050  $this->currentMessage = $attrs['name'];
5051  break;
5052  case 'portType':
5053  $this->status = 'portType';
5054  $this->portTypes[$attrs['name']] = array();
5055  $this->currentPortType = $attrs['name'];
5056  break;
5057  case "binding":
5058  if (isset($attrs['name'])) {
5059  // get binding name
5060  if (strpos($attrs['name'], ':')) {
5061  $this->currentBinding = $this->getLocalPart($attrs['name']);
5062  } else {
5063  $this->currentBinding = $attrs['name'];
5064  }
5065  $this->status = 'binding';
5066  $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
5067  $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
5068  }
5069  break;
5070  case 'service':
5071  $this->serviceName = $attrs['name'];
5072  $this->status = 'service';
5073  $this->debug('current service: ' . $this->serviceName);
5074  break;
5075  case 'definitions':
5076  foreach ($attrs as $name => $value) {
5077  $this->wsdl_info[$name] = $value;
5078  }
5079  break;
5080  }
5081  }
5082  }
5083 
5091  public function end_element($parser, $name)
5092  {
5093  // unset schema status
5094  if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) {
5095  $this->status = "";
5096  $this->appendDebug($this->currentSchema->getDebug());
5097  $this->currentSchema->clearDebug();
5098  $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
5099  $this->debug('Parsing WSDL schema done');
5100  }
5101  if ($this->status == 'schema') {
5102  $this->currentSchema->schemaEndElement($parser, $name);
5103  } else {
5104  // bring depth down a notch
5105  $this->depth--;
5106  }
5107  // end documentation
5108  if ($this->documentation) {
5109  //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
5110  //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
5111  $this->documentation = false;
5112  }
5113  }
5114 
5122  public function character_data($parser, $data)
5123  {
5124  $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
5125  if (isset($this->message[$pos]['cdata'])) {
5126  $this->message[$pos]['cdata'] .= $data;
5127  }
5128  if ($this->documentation) {
5129  $this->documentation .= $data;
5130  }
5131  }
5132 
5142  public function setCredentials($username, $password, $authtype = 'basic', $certRequest = array())
5143  {
5144  $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
5145  $this->appendDebug($this->varDump($certRequest));
5146  $this->username = $username;
5147  $this->password = $password;
5148  $this->authtype = $authtype;
5149  $this->certRequest = $certRequest;
5150  }
5151 
5152  public function getBindingData($binding)
5153  {
5154  if (is_array($this->bindings[$binding])) {
5155  return $this->bindings[$binding];
5156  }
5157  }
5158 
5166  public function getOperations($bindingType = 'soap')
5167  {
5168  $ops = array();
5169  if ($bindingType == 'soap') {
5170  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5171  } elseif ($bindingType == 'soap12') {
5172  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5173  }
5174  // loop thru ports
5175  foreach ($this->ports as $port => $portData) {
5176  // binding type of port matches parameter
5177  if ($portData['bindingType'] == $bindingType) {
5178  //$this->debug("getOperations for port $port");
5179  //$this->debug("port data: " . $this->varDump($portData));
5180  //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
5181  // merge bindings
5182  if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
5183  $ops = array_merge($ops, $this->bindings[ $portData['binding'] ]['operations']);
5184  }
5185  }
5186  }
5187  return $ops;
5188  }
5189 
5198  public function getOperationData($operation, $bindingType = 'soap')
5199  {
5200  if ($bindingType == 'soap') {
5201  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5202  } elseif ($bindingType == 'soap12') {
5203  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5204  }
5205  // loop thru ports
5206  foreach ($this->ports as $port => $portData) {
5207  // binding type of port matches parameter
5208  if ($portData['bindingType'] == $bindingType) {
5209  // get binding
5210  //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5211  foreach (array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
5212  // note that we could/should also check the namespace here
5213  if ($operation == $bOperation) {
5214  $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
5215  return $opData;
5216  }
5217  }
5218  }
5219  }
5220  }
5221 
5230  public function getOperationDataForSoapAction($soapAction, $bindingType = 'soap')
5231  {
5232  if ($bindingType == 'soap') {
5233  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5234  } elseif ($bindingType == 'soap12') {
5235  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5236  }
5237  // loop thru ports
5238  foreach ($this->ports as $port => $portData) {
5239  // binding type of port matches parameter
5240  if ($portData['bindingType'] == $bindingType) {
5241  // loop through operations for the binding
5242  foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5243  if ($opData['soapAction'] == $soapAction) {
5244  return $opData;
5245  }
5246  }
5247  }
5248  }
5249  }
5250 
5269  public function getTypeDef($type, $ns)
5270  {
5271  $this->debug("in getTypeDef: type=$type, ns=$ns");
5272  if ((! $ns) && isset($this->namespaces['tns'])) {
5273  $ns = $this->namespaces['tns'];
5274  $this->debug("in getTypeDef: type namespace forced to $ns");
5275  }
5276  if (!isset($this->schemas[$ns])) {
5277  foreach ($this->schemas as $ns0 => $schema0) {
5278  if (strcasecmp($ns, $ns0) == 0) {
5279  $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
5280  $ns = $ns0;
5281  break;
5282  }
5283  }
5284  }
5285  if (isset($this->schemas[$ns])) {
5286  $this->debug("in getTypeDef: have schema for namespace $ns");
5287  for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
5288  $xs = &$this->schemas[$ns][$i];
5289  $t = $xs->getTypeDef($type);
5290  //$this->appendDebug($xs->getDebug());
5291  //$xs->clearDebug();
5292  if ($t) {
5293  if (!isset($t['phpType'])) {
5294  // get info for type to tack onto the element
5295  $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
5296  $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
5297  $etype = $this->getTypeDef($uqType, $ns);
5298  if ($etype) {
5299  $this->debug("found type for [element] $type:");
5300  $this->debug($this->varDump($etype));
5301  if (isset($etype['phpType'])) {
5302  $t['phpType'] = $etype['phpType'];
5303  }
5304  if (isset($etype['elements'])) {
5305  $t['elements'] = $etype['elements'];
5306  }
5307  if (isset($etype['attrs'])) {
5308  $t['attrs'] = $etype['attrs'];
5309  }
5310  }
5311  }
5312  return $t;
5313  }
5314  }
5315  } else {
5316  $this->debug("in getTypeDef: do not have schema for namespace $ns");
5317  }
5318  return false;
5319  }
5320 
5326  public function webDescription()
5327  {
5328  global $HTTP_SERVER_VARS;
5329 
5330  if (isset($_SERVER)) {
5331  $PHP_SELF = $_SERVER['PHP_SELF'];
5332  } elseif (isset($HTTP_SERVER_VARS)) {
5333  $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
5334  } else {
5335  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
5336  }
5337  // begin-patch: https://mantis.ilias.de/view.php?id=28866
5338  $PHP_SELF = htmlspecialchars($PHP_SELF, ENT_QUOTES | ENT_HTML5, 'UTF-8');
5339  // end-patch
5340 
5341  $b = '
5342  <html><head><title>NuSOAP: ' . $this->serviceName . '</title>
5343  <style type="text/css">
5344  body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
5345  p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
5346  pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
5347  ul { margin-top: 10px; margin-left: 20px; }
5348  li { list-style-type: none; margin-top: 10px; color: #000000; }
5349  .content{
5350  margin-left: 0px; padding-bottom: 2em; }
5351  .nav {
5352  padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
5353  margin-top: 10px; margin-left: 0px; color: #000000;
5354  background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
5355  .title {
5356  font-family: arial; font-size: 26px; color: #ffffff;
5357  background-color: #999999; width: 105%; margin-left: 0px;
5358  padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
5359  .hidden {
5360  position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
5361  font-family: arial; overflow: hidden; width: 600;
5362  padding: 20px; font-size: 10px; background-color: #999999;
5363  layer-background-color:#FFFFFF; }
5364  a,a:active { color: charcoal; font-weight: bold; }
5365  a:visited { color: #666666; font-weight: bold; }
5366  a:hover { color: cc3300; font-weight: bold; }
5367  </style>
5368  <script language="JavaScript" type="text/javascript">
5369  <!--
5370  // POP-UP CAPTIONS...
5371  function lib_bwcheck(){ //Browsercheck (needed)
5372  this.ver=navigator.appVersion
5373  this.agent=navigator.userAgent
5374  this.dom=document.getElementById?1:0
5375  this.opera5=this.agent.indexOf("Opera 5")>-1
5376  this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
5377  this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
5378  this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
5379  this.ie=this.ie4||this.ie5||this.ie6
5380  this.mac=this.agent.indexOf("Mac")>-1
5381  this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
5382  this.ns4=(document.layers && !this.dom)?1:0;
5383  this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
5384  return this
5385  }
5386  var bw = new lib_bwcheck()
5387  //Makes crossbrowser object.
5388  function makeObj(obj){
5389  this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
5390  if(!this.evnt) return false
5391  this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
5392  this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
5393  this.writeIt=b_writeIt;
5394  return this
5395  }
5396  // A unit of measure that will be added when setting the position of a layer.
5397  //var px = bw.ns4||window.opera?"":"px";
5398  function b_writeIt(text){
5399  if (bw.ns4){this.wref.write(text);this.wref.close()}
5400  else this.wref.innerHTML = text
5401  }
5402  //Shows the messages
5403  var oDesc;
5404  function popup(divid){
5405  if(oDesc = new makeObj(divid)){
5406  oDesc.css.visibility = "visible"
5407  }
5408  }
5409  function popout(){ // Hides message
5410  if(oDesc) oDesc.css.visibility = "hidden"
5411  }
5412  //-->
5413  </script>
5414  </head>
5415  <body>
5416  <div class=content>
5417  <br><br>
5418  <div class=title>' . $this->serviceName . '</div>
5419  <div class=nav>
5420  <p>View the <a href="' . $PHP_SELF . '?wsdl">WSDL</a> for the service.
5421  Click on an operation name to view it&apos;s details.</p>
5422  <ul>';
5423  foreach ($this->getOperations() as $op => $data) {
5424  // begin-patch: https://mantis.ilias.de/view.php?id=28866
5425  if (isset($data['endpoint'])) {
5426  $data['endpoint'] = htmlspecialchars($data['endpoint'], ENT_QUOTES | ENT_HTML5, 'UTF-8');
5427  }
5428  // end-patch
5429  $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
5430  // create hidden div
5431  $b .= "<div id='$op' class='hidden'>
5432  <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
5433  foreach ($data as $donnie => $marie) { // loop through opdata
5434  if ($donnie == 'input' || $donnie == 'output') { // show input/output data
5435  $b .= "<font color='white'>" . ucfirst($donnie) . ':</font><br>';
5436  foreach ($marie as $captain => $tenille) { // loop through data
5437  if ($captain == 'parts') { // loop thru parts
5438  $b .= "&nbsp;&nbsp;$captain:<br>";
5439  //if(is_array($tenille)){
5440  foreach ($tenille as $joanie => $chachi) {
5441  $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
5442  }
5443  //}
5444  } else {
5445  $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
5446  }
5447  }
5448  } else {
5449  $b .= "<font color='white'>" . ucfirst($donnie) . ":</font> $marie<br>";
5450  }
5451  }
5452  $b .= '</div>';
5453  }
5454  $b .= '
5455  <ul>
5456  </div>
5457  </div></body></html>';
5458  return $b;
5459  }
5460 
5468  public function serialize($debug = 0)
5469  {
5470  $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
5471  $xml .= "\n<definitions";
5472  foreach ($this->namespaces as $k => $v) {
5473  $xml .= " xmlns:$k=\"$v\"";
5474  }
5475  // 10.9.02 - add poulter fix for wsdl and tns declarations
5476  if (isset($this->namespaces['wsdl'])) {
5477  $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
5478  }
5479  if (isset($this->namespaces['tns'])) {
5480  $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
5481  }
5482  $xml .= '>';
5483  // imports
5484  if (sizeof($this->import) > 0) {
5485  foreach ($this->import as $ns => $list) {
5486  foreach ($list as $ii) {
5487  if ($ii['location'] != '') {
5488  $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
5489  } else {
5490  $xml .= '<import namespace="' . $ns . '" />';
5491  }
5492  }
5493  }
5494  }
5495  // types
5496  if (count($this->schemas) >= 1) {
5497  $xml .= "\n<types>\n";
5498  foreach ($this->schemas as $ns => $list) {
5499  foreach ($list as $xs) {
5500  $xml .= $xs->serializeSchema();
5501  }
5502  }
5503  $xml .= '</types>';
5504  }
5505  // messages
5506  if (count($this->messages) >= 1) {
5507  foreach ($this->messages as $msgName => $msgParts) {
5508  $xml .= "\n<message name=\"" . $msgName . '">';
5509  if (is_array($msgParts)) {
5510  foreach ($msgParts as $partName => $partType) {
5511  // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
5512  if (strpos($partType, ':')) {
5513  $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
5514  } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
5515  // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
5516  $typePrefix = 'xsd';
5517  } else {
5518  foreach ($this->typemap as $ns => $types) {
5519  if (isset($types[$partType])) {
5520  $typePrefix = $this->getPrefixFromNamespace($ns);
5521  }
5522  }
5523  if (!isset($typePrefix)) {
5524  die("$partType has no namespace!");
5525  }
5526  }
5527  $ns = $this->getNamespaceFromPrefix($typePrefix);
5528  $localPart = $this->getLocalPart($partType);
5529  $typeDef = $this->getTypeDef($localPart, $ns);
5530  if (($typeDef['typeClass'] ?? '') == 'element') {
5531  $elementortype = 'element';
5532  if (substr($localPart, -1) == '^') {
5533  $localPart = substr($localPart, 0, -1);
5534  }
5535  } else {
5536  $elementortype = 'type';
5537  }
5538  $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
5539  }
5540  }
5541  $xml .= '</message>';
5542  }
5543  }
5544  // bindings & porttypes
5545  if (count($this->bindings) >= 1) {
5546  $binding_xml = '';
5547  $portType_xml = '';
5548  foreach ($this->bindings as $bindingName => $attrs) {
5549  $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
5550  $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
5551  $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
5552  foreach ($attrs['operations'] as $opName => $opParts) {
5553  $binding_xml .= "\n" . ' <operation name="' . $opName . '">';
5554  $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="' . $opParts['style'] . '"/>';
5555  if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
5556  $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
5557  } else {
5558  $enc_style = '';
5559  }
5560  $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
5561  if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
5562  $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
5563  } else {
5564  $enc_style = '';
5565  }
5566  $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
5567  $binding_xml .= "\n" . ' </operation>';
5568  $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"';
5569  if (isset($opParts['parameterOrder'])) {
5570  $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
5571  }
5572  $portType_xml .= '>';
5573  if (isset($opParts['documentation']) && $opParts['documentation'] != '') {
5574  $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
5575  }
5576  $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>';
5577  $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>';
5578  $portType_xml .= "\n" . ' </operation>';
5579  }
5580  $portType_xml .= "\n" . '</portType>';
5581  $binding_xml .= "\n" . '</binding>';
5582  }
5583  $xml .= $portType_xml . $binding_xml;
5584  }
5585  // services
5586  $xml .= "\n<service name=\"" . $this->serviceName . '">';
5587  $has_client = isset($_GET['client_id']);
5588  if (count($this->ports) >= 1) {
5589  foreach ($this->ports as $pName => $attrs) {
5590  $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5591  $locations = $attrs['location'];
5592  $locations = is_array($locations) ? $locations : [$locations];
5593  foreach ($locations as $location) {
5594  $address = $location . ($debug || $has_client ? "?" : "")
5595  . ($debug ? 'debug=1' : '') . ($debug && $has_client ? "&amp;" : "")
5596  . ($has_client ? 'client_id=' . $_GET['client_id'] : '');
5597  $xml .= "\n" . ' <soap:address location="' . $address . '"/>';
5598  }
5599  $xml .= "\n" . ' </port>';
5600  }
5601  }
5602 
5603  $xml .= "\n" . '</service>';
5604  return $xml . "\n</definitions>";
5605  }
5606 
5616  public function parametersMatchWrapped($type, &$parameters)
5617  {
5618  $this->debug("in parametersMatchWrapped type=$type, parameters=");
5619  $this->appendDebug($this->varDump($parameters));
5620 
5621  // split type into namespace:unqualified-type
5622  if (strpos($type, ':')) {
5623  $uqType = substr($type, strrpos($type, ':') + 1);
5624  $ns = substr($type, 0, strrpos($type, ':'));
5625  $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
5626  if ($this->getNamespaceFromPrefix($ns)) {
5627  $ns = $this->getNamespaceFromPrefix($ns);
5628  $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
5629  }
5630  } else {
5631  // TODO: should the type be compared to types in XSD, and the namespace
5632  // set to XSD if the type matches?
5633  $this->debug("in parametersMatchWrapped: No namespace for type $type");
5634  $ns = '';
5635  $uqType = $type;
5636  }
5637 
5638  // get the type information
5639  if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
5640  $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
5641  return false;
5642  }
5643  $this->debug("in parametersMatchWrapped: found typeDef=");
5644  $this->appendDebug($this->varDump($typeDef));
5645  if (substr($uqType, -1) == '^') {
5646  $uqType = substr($uqType, 0, -1);
5647  }
5648  $phpType = $typeDef['phpType'];
5649  $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
5650  $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
5651 
5652  // we expect a complexType or element of complexType
5653  if ($phpType != 'struct') {
5654  $this->debug("in parametersMatchWrapped: not a struct");
5655  return false;
5656  }
5657 
5658  // see whether the parameter names match the elements
5659  if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
5660  $elements = 0;
5661  $matches = 0;
5662  $change = false;
5663  if ($this->isArraySimpleOrStruct($parameters) == 'arraySimple' && count($parameters) == count($typeDef['elements'])) {
5664  $this->debug("in parametersMatchWrapped: (wrapped return value kludge) correct number of elements in simple array, so change array and wrap");
5665  $change = true;
5666  }
5667  foreach ($typeDef['elements'] as $name => $attrs) {
5668  if ($change) {
5669  $this->debug("in parametersMatchWrapped: change parameter $element to name $name");
5670  $parameters[$name] = $parameters[$elements];
5671  unset($parameters[$elements]);
5672  $matches++;
5673  } elseif (isset($parameters[$name])) {
5674  $this->debug("in parametersMatchWrapped: have parameter named $name");
5675  $matches++;
5676  } else {
5677  $this->debug("in parametersMatchWrapped: do not have parameter named $name");
5678  }
5679  $elements++;
5680  }
5681 
5682  $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
5683  if ($matches == 0) {
5684  return false;
5685  }
5686  return true;
5687  }
5688 
5689  // since there are no elements for the type, if the user passed no
5690  // parameters, the parameters match wrapped.
5691  $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
5692  return count($parameters) == 0;
5693  }
5694 
5710  public function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap')
5711  {
5712  $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
5713  $this->appendDebug('parameters=' . $this->varDump($parameters));
5714 
5715  if ($direction != 'input' && $direction != 'output') {
5716  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5717  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5718  return false;
5719  }
5720  if (!$opData = $this->getOperationData($operation, $bindingType)) {
5721  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5722  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5723  return false;
5724  }
5725  $this->debug('in serializeRPCParameters: opData:');
5726  $this->appendDebug($this->varDump($opData));
5727 
5728  // Get encoding style for output and set to current
5729  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5730  if (($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5731  $encodingStyle = $opData['output']['encodingStyle'];
5732  $enc_style = $encodingStyle;
5733  }
5734 
5735  // set input params
5736  $xml = '';
5737  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5738  $parts = &$opData[$direction]['parts'];
5739  $part_count = sizeof($parts);
5740  $style = $opData['style'];
5741  $use = $opData[$direction]['use'];
5742  $this->debug("have $part_count part(s) to serialize using $style/$use");
5743  if (is_array($parameters)) {
5744  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5745  $parameter_count = count($parameters);
5746  $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
5747  // check for Microsoft-style wrapped parameters
5748  if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
5749  $this->debug('check whether the caller has wrapped the parameters');
5750  if ((($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) || ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1)) {
5751  $this->debug('check whether caller\'s parameters match the wrapped ones');
5752  if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
5753  $this->debug('wrap the parameters for the caller');
5754  $parameters = array('parameters' => $parameters);
5755  $parameter_count = 1;
5756  }
5757  }
5758  }
5759  foreach ($parts as $name => $type) {
5760  $this->debug("serializing part $name of type $type");
5761  // Track encoding style
5762  if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5763  $encodingStyle = $opData[$direction]['encodingStyle'];
5764  $enc_style = $encodingStyle;
5765  } else {
5766  $enc_style = false;
5767  }
5768  // NOTE: add error handling here
5769  // if serializeType returns false, then catch global error and fault
5770  if ($parametersArrayType == 'arraySimple') {
5771  $p = array_shift($parameters);
5772  $this->debug('calling serializeType w/indexed param');
5773  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5774  } elseif (isset($parameters[$name])) {
5775  $this->debug('calling serializeType w/named param');
5776  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5777  } else {
5778  // TODO: only send nillable
5779  $this->debug('calling serializeType w/null param');
5780  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5781  }
5782  }
5783  } else {
5784  $this->debug('no parameters passed.');
5785  }
5786  }
5787  $this->debug("serializeRPCParameters returning: $xml");
5788  return $xml;
5789  }
5790 
5805  public function serializeParameters($operation, $direction, $parameters)
5806  {
5807  $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
5808  $this->appendDebug('parameters=' . $this->varDump($parameters));
5809 
5810  if ($direction != 'input' && $direction != 'output') {
5811  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5812  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5813  return false;
5814  }
5815  if (!$opData = $this->getOperationData($operation)) {
5816  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
5817  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
5818  return false;
5819  }
5820  $this->debug('opData:');
5821  $this->appendDebug($this->varDump($opData));
5822 
5823  // Get encoding style for output and set to current
5824  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5825  if (($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5826  $encodingStyle = $opData['output']['encodingStyle'];
5827  $enc_style = $encodingStyle;
5828  }
5829 
5830  // set input params
5831  $xml = '';
5832  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5833  $use = $opData[$direction]['use'];
5834  $this->debug("use=$use");
5835  $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
5836  if (is_array($parameters)) {
5837  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5838  $this->debug('have ' . $parametersArrayType . ' parameters');
5839  foreach ($opData[$direction]['parts'] as $name => $type) {
5840  $this->debug('serializing part "' . $name . '" of type "' . $type . '"');
5841  // Track encoding style
5842  if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5843  $encodingStyle = $opData[$direction]['encodingStyle'];
5844  $enc_style = $encodingStyle;
5845  } else {
5846  $enc_style = false;
5847  }
5848  // NOTE: add error handling here
5849  // if serializeType returns false, then catch global error and fault
5850  if ($parametersArrayType == 'arraySimple') {
5851  $p = array_shift($parameters);
5852  $this->debug('calling serializeType w/indexed param');
5853  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5854  } elseif (isset($parameters[$name])) {
5855  $this->debug('calling serializeType w/named param');
5856  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5857  } else {
5858  // TODO: only send nillable
5859  $this->debug('calling serializeType w/null param');
5860  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5861  }
5862  }
5863  } else {
5864  $this->debug('no parameters passed.');
5865  }
5866  }
5867  $this->debug("serializeParameters returning: $xml");
5868  return $xml;
5869  }
5870 
5883  public function serializeType($name, $type, $value, $use = 'encoded', $encodingStyle = false, $unqualified = false)
5884  {
5885  $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
5886  $this->appendDebug("value=" . $this->varDump($value));
5887  if ($use == 'encoded' && $encodingStyle) {
5888  $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
5889  }
5890 
5891  // if a soapval has been supplied, let its type override the WSDL
5892  if (is_object($value) && get_class($value) == 'soapval') {
5893  if ($value->type_ns) {
5894  $type = $value->type_ns . ':' . $value->type;
5895  $forceType = true;
5896  $this->debug("in serializeType: soapval overrides type to $type");
5897  } elseif ($value->type) {
5898  $type = $value->type;
5899  $forceType = true;
5900  $this->debug("in serializeType: soapval overrides type to $type");
5901  } else {
5902  $forceType = false;
5903  $this->debug("in serializeType: soapval does not override type");
5904  }
5905  $attrs = $value->attributes;
5906  $value = $value->value;
5907  $this->debug("in serializeType: soapval overrides value to $value");
5908  if ($attrs) {
5909  if (!is_array($value)) {
5910  $value['!'] = $value;
5911  }
5912  foreach ($attrs as $n => $v) {
5913  $value['!' . $n] = $v;
5914  }
5915  $this->debug("in serializeType: soapval provides attributes");
5916  }
5917  } else {
5918  $forceType = false;
5919  }
5920 
5921  $xml = '';
5922  if (strpos($type, ':')) {
5923  $uqType = substr($type, strrpos($type, ':') + 1);
5924  $ns = substr($type, 0, strrpos($type, ':'));
5925  $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
5926  if ($this->getNamespaceFromPrefix($ns)) {
5927  $ns = $this->getNamespaceFromPrefix($ns);
5928  $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
5929  }
5930 
5931  if ($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/') {
5932  $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
5933  if ($unqualified && $use == 'literal') {
5934  $elementNS = " xmlns=\"\"";
5935  } else {
5936  $elementNS = '';
5937  }
5938  if (is_null($value)) {
5939  if ($use == 'literal') {
5940  // TODO: depends on minOccurs
5941  $xml = "<$name$elementNS/>";
5942  } else {
5943  // TODO: depends on nillable, which should be checked before calling this method
5944  $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5945  }
5946  $this->debug("in serializeType: returning: $xml");
5947  return $xml;
5948  }
5949  if ($uqType == 'Array') {
5950  // JBoss/Axis does this sometimes
5951  return $this->serialize_val($value, $name, false, false, false, false, $use);
5952  }
5953  if ($uqType == 'boolean') {
5954  if ((is_string($value) && $value == 'false') || (! $value)) {
5955  $value = 'false';
5956  } else {
5957  $value = 'true';
5958  }
5959  }
5960  if ($uqType == 'string' && gettype($value) == 'string') {
5961  $value = $this->expandEntities($value);
5962  }
5963  if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
5964  $value = sprintf("%.0lf", $value);
5965  }
5966  // it's a scalar
5967  // TODO: what about null/nil values?
5968  // check type isn't a custom type extending xmlschema namespace
5969  if (!$this->getTypeDef($uqType, $ns)) {
5970  if ($use == 'literal') {
5971  if ($forceType) {
5972  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
5973  } else {
5974  $xml = "<$name$elementNS>$value</$name>";
5975  }
5976  } else {
5977  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
5978  }
5979  $this->debug("in serializeType: returning: $xml");
5980  return $xml;
5981  }
5982  $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
5983  } elseif ($ns == 'http://xml.apache.org/xml-soap') {
5984  $this->debug('in serializeType: appears to be Apache SOAP type');
5985  if ($uqType == 'Map') {
5986  $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5987  if (! $tt_prefix) {
5988  $this->debug('in serializeType: Add namespace for Apache SOAP type');
5989  $tt_prefix = 'ns' . rand(1000, 9999);
5990  $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
5991  // force this to be added to usedNamespaces
5992  $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5993  }
5994  $contents = '';
5995  foreach ($value as $k => $v) {
5996  $this->debug("serializing map element: key $k, value $v");
5997  $contents .= '<item>';
5998  $contents .= $this->serialize_val($k, 'key', false, false, false, false, $use);
5999  $contents .= $this->serialize_val($v, 'value', false, false, false, false, $use);
6000  $contents .= '</item>';
6001  }
6002  if ($use == 'literal') {
6003  if ($forceType) {
6004  $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
6005  } else {
6006  $xml = "<$name>$contents</$name>";
6007  }
6008  } else {
6009  $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
6010  }
6011  $this->debug("in serializeType: returning: $xml");
6012  return $xml;
6013  }
6014  $this->debug('in serializeType: Apache SOAP type, but only support Map');
6015  }
6016  } else {
6017  // TODO: should the type be compared to types in XSD, and the namespace
6018  // set to XSD if the type matches?
6019  $this->debug("in serializeType: No namespace for type $type");
6020  $ns = '';
6021  $uqType = $type;
6022  }
6023  if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
6024  $this->setError("$type ($uqType) is not a supported type.");
6025  $this->debug("in serializeType: $type ($uqType) is not a supported type.");
6026  return false;
6027  } else {
6028  $this->debug("in serializeType: found typeDef");
6029  $this->appendDebug('typeDef=' . $this->varDump($typeDef));
6030  if (substr($uqType, -1) == '^') {
6031  $uqType = substr($uqType, 0, -1);
6032  }
6033  }
6034  $phpType = $typeDef['phpType'];
6035  $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''));
6036  // if php type == struct, map value to the <all> element names
6037  if ($phpType == 'struct') {
6038  if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
6039  $elementName = $uqType;
6040  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6041  $elementNS = " xmlns=\"$ns\"";
6042  } else {
6043  $elementNS = " xmlns=\"\"";
6044  }
6045  } else {
6046  $elementName = $name;
6047  if ($unqualified) {
6048  $elementNS = " xmlns=\"\"";
6049  } else {
6050  $elementNS = '';
6051  }
6052  }
6053  if (is_null($value)) {
6054  if ($use == 'literal') {
6055  // TODO: depends on minOccurs
6056  $xml = "<$elementName$elementNS/>";
6057  } else {
6058  $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
6059  }
6060  $this->debug("in serializeType: returning: $xml");
6061  return $xml;
6062  }
6063  if (is_object($value)) {
6064  $value = get_object_vars($value);
6065  }
6066  if (is_array($value)) {
6067  $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6068  if ($use == 'literal') {
6069  if ($forceType) {
6070  $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
6071  } else {
6072  $xml = "<$elementName$elementNS$elementAttrs>";
6073  }
6074  } else {
6075  $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
6076  }
6077 
6078  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6079  $xml .= "</$elementName>";
6080  } else {
6081  $this->debug("in serializeType: phpType is struct, but value is not an array");
6082  $this->setError("phpType is struct, but value is not an array: see debug output for details");
6083  $xml = '';
6084  }
6085  } elseif ($phpType == 'array') {
6086  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6087  $elementNS = " xmlns=\"$ns\"";
6088  } else {
6089  if ($unqualified) {
6090  $elementNS = " xmlns=\"\"";
6091  } else {
6092  $elementNS = '';
6093  }
6094  }
6095  if (is_null($value)) {
6096  if ($use == 'literal') {
6097  // TODO: depends on minOccurs
6098  $xml = "<$name$elementNS/>";
6099  } else {
6100  $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
6101  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
6102  ":Array\" " .
6103  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
6104  ':arrayType="' .
6105  $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
6106  ':' .
6107  $this->getLocalPart($typeDef['arrayType']) . "[0]\"/>";
6108  }
6109  $this->debug("in serializeType: returning: $xml");
6110  return $xml;
6111  }
6112  if (isset($typeDef['multidimensional'])) {
6113  $nv = array();
6114  foreach ($value as $v) {
6115  $cols = ',' . sizeof($v);
6116  $nv = array_merge($nv, $v);
6117  }
6118  $value = $nv;
6119  } else {
6120  $cols = '';
6121  }
6122  if (is_array($value) && sizeof($value) >= 1) {
6123  $rows = sizeof($value);
6124  $contents = '';
6125  foreach ($value as $k => $v) {
6126  $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
6127  //if (strpos($typeDef['arrayType'], ':') ) {
6128  if (!in_array($typeDef['arrayType'], $this->typemap['http://www.w3.org/2001/XMLSchema'])) {
6129  $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
6130  } else {
6131  $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
6132  }
6133  }
6134  } else {
6135  $rows = 0;
6136  $contents = null;
6137  }
6138  // TODO: for now, an empty value will be serialized as a zero element
6139  // array. Revisit this when coding the handling of null/nil values.
6140  if ($use == 'literal') {
6141  $xml = "<$name$elementNS>"
6142  . $contents
6143  . "</$name>";
6144  } else {
6145  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ':Array" ' .
6146  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6147  . ':arrayType="'
6148  . $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
6149  . ":" . $this->getLocalPart($typeDef['arrayType']) . "[$rows$cols]\">"
6150  . $contents
6151  . "</$name>";
6152  }
6153  } elseif ($phpType == 'scalar') {
6154  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6155  $elementNS = " xmlns=\"$ns\"";
6156  } else {
6157  if ($unqualified) {
6158  $elementNS = " xmlns=\"\"";
6159  } else {
6160  $elementNS = '';
6161  }
6162  }
6163  if ($use == 'literal') {
6164  if ($forceType) {
6165  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6166  } else {
6167  $xml = "<$name$elementNS>$value</$name>";
6168  }
6169  } else {
6170  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6171  }
6172  }
6173  $this->debug("in serializeType: returning: $xml");
6174  return $xml;
6175  }
6176 
6187  public function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType)
6188  {
6189  $xml = '';
6190  if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
6191  $this->debug("serialize attributes for XML Schema type $ns:$uqType");
6192  if (is_array($value)) {
6193  $xvalue = $value;
6194  } elseif (is_object($value)) {
6195  $xvalue = get_object_vars($value);
6196  } else {
6197  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6198  $xvalue = array();
6199  }
6200  foreach ($typeDef['attrs'] as $aName => $attrs) {
6201  if (isset($xvalue['!' . $aName])) {
6202  $xname = '!' . $aName;
6203  $this->debug("value provided for attribute $aName with key $xname");
6204  } elseif (isset($xvalue[$aName])) {
6205  $xname = $aName;
6206  $this->debug("value provided for attribute $aName with key $xname");
6207  } elseif (isset($attrs['default'])) {
6208  $xname = '!' . $aName;
6209  $xvalue[$xname] = $attrs['default'];
6210  $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
6211  } else {
6212  $xname = '';
6213  $this->debug("no value provided for attribute $aName");
6214  }
6215  if ($xname) {
6216  $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
6217  }
6218  }
6219  } else {
6220  $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
6221  }
6222  if (isset($typeDef['extensionBase'])) {
6223  $ns = $this->getPrefix($typeDef['extensionBase']);
6224  $uqType = $this->getLocalPart($typeDef['extensionBase']);
6225  if ($this->getNamespaceFromPrefix($ns)) {
6226  $ns = $this->getNamespaceFromPrefix($ns);
6227  }
6228  if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6229  $this->debug("serialize attributes for extension base $ns:$uqType");
6230  $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6231  } else {
6232  $this->debug("extension base $ns:$uqType is not a supported type");
6233  }
6234  }
6235  return $xml;
6236  }
6237 
6250  public function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use = 'encoded', $encodingStyle = false)
6251  {
6252  $xml = '';
6253  if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6254  $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
6255  if (is_array($value)) {
6256  $xvalue = $value;
6257  } elseif (is_object($value)) {
6258  $xvalue = get_object_vars($value);
6259  } else {
6260  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6261  $xvalue = array();
6262  }
6263  // toggle whether all elements are present - ideally should validate against schema
6264  if (count($typeDef['elements']) != count($xvalue)) {
6265  $optionals = true;
6266  }
6267  foreach ($typeDef['elements'] as $eName => $attrs) {
6268  if (!isset($xvalue[$eName])) {
6269  if (isset($attrs['default'])) {
6270  $xvalue[$eName] = $attrs['default'];
6271  $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
6272  }
6273  }
6274  // if user took advantage of a minOccurs=0, then only serialize named parameters
6275  if (isset($optionals)
6276  && (!isset($xvalue[$eName]))
6277  && ((!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
6278  ) {
6279  if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
6280  $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
6281  }
6282  // do nothing
6283  $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
6284  } else {
6285  // get value
6286  if (isset($xvalue[$eName])) {
6287  $v = $xvalue[$eName];
6288  } else {
6289  $v = null;
6290  }
6291  if (isset($attrs['form'])) {
6292  $unqualified = ($attrs['form'] == 'unqualified');
6293  } else {
6294  $unqualified = false;
6295  }
6296  if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
6297  $vv = $v;
6298  foreach ($vv as $k => $v) {
6299  if (isset($attrs['type']) || isset($attrs['ref'])) {
6300  // serialize schema-defined type
6301  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6302  } else {
6303  // serialize generic type (can this ever really happen?)
6304  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6305  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6306  }
6307  }
6308  } else {
6309  if (isset($attrs['type']) || isset($attrs['ref'])) {
6310  // serialize schema-defined type
6311  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6312  } else {
6313  // serialize generic type (can this ever really happen?)
6314  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6315  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6316  }
6317  }
6318  }
6319  }
6320  } else {
6321  $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
6322  }
6323  if (isset($typeDef['extensionBase'])) {
6324  $ns = $this->getPrefix($typeDef['extensionBase']);
6325  $uqType = $this->getLocalPart($typeDef['extensionBase']);
6326  if ($this->getNamespaceFromPrefix($ns)) {
6327  $ns = $this->getNamespaceFromPrefix($ns);
6328  }
6329  if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6330  $this->debug("serialize elements for extension base $ns:$uqType");
6331  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6332  } else {
6333  $this->debug("extension base $ns:$uqType is not a supported type");
6334  }
6335  }
6336  return $xml;
6337  }
6338 
6353  public function addComplexType($name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '')
6354  {
6355  if (count($elements) > 0) {
6356  $eElements = array();
6357  foreach ($elements as $n => $e) {
6358  // expand each element
6359  $ee = array();
6360  foreach ($e as $k => $v) {
6361  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
6362  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
6363  $ee[$k] = $v;
6364  }
6365  $eElements[$n] = $ee;
6366  }
6367  $elements = $eElements;
6368  }
6369 
6370  if (count($attrs) > 0) {
6371  foreach ($attrs as $n => $a) {
6372  // expand each attribute
6373  foreach ($a as $k => $v) {
6374  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
6375  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
6376  $aa[$k] = $v;
6377  }
6378  $eAttrs[$n] = $aa;
6379  }
6380  $attrs = $eAttrs;
6381  }
6382 
6383  $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6384  $arrayType = strpos($arrayType, ':') ? $this->expandQname($arrayType) : $arrayType;
6385 
6386  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6387  $this->schemas[$typens][0]->addComplexType($name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType);
6388  }
6389 
6401  public function addSimpleType($name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array())
6402  {
6403  $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6404 
6405  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6406  $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
6407  }
6408 
6416  public function addElement($attrs)
6417  {
6418  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6419  $this->schemas[$typens][0]->addElement($attrs);
6420  }
6421 
6436  public function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = '')
6437  {
6438  if ($use == 'encoded' && $encodingStyle == '') {
6439  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6440  }
6441 
6442  if ($style == 'document') {
6443  $elements = array();
6444  foreach ($in as $n => $t) {
6445  $elements[$n] = array('name' => $n, 'type' => $t);
6446  }
6447  $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
6448  $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
6449  $in = array('parameters' => 'tns:' . $name . '^');
6450 
6451  $elements = array();
6452  foreach ($out as $n => $t) {
6453  $elements[$n] = array('name' => $n, 'type' => $t);
6454  }
6455  $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
6456  $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
6457  $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
6458  }
6459 
6460  // get binding
6461  $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
6462  array(
6463  'name' => $name,
6464  'binding' => $this->serviceName . 'Binding',
6465  'endpoint' => $this->endpoint,
6466  'soapAction' => $soapaction,
6467  'style' => $style,
6468  'input' => array(
6469  'use' => $use,
6470  'namespace' => $namespace,
6471  'encodingStyle' => $encodingStyle,
6472  'message' => $name . 'Request',
6473  'parts' => $in),
6474  'output' => array(
6475  'use' => $use,
6476  'namespace' => $namespace,
6477  'encodingStyle' => $encodingStyle,
6478  'message' => $name . 'Response',
6479  'parts' => $out),
6480  'namespace' => $namespace,
6481  'transport' => 'http://schemas.xmlsoap.org/soap/http',
6482  'documentation' => $documentation);
6483  // add portTypes
6484  // add messages
6485  if ($in) {
6486  foreach ($in as $pName => $pType) {
6487  if (strpos($pType, ':')) {
6488  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ":" . $this->getLocalPart($pType);
6489  }
6490  $this->messages[$name . 'Request'][$pName] = $pType;
6491  }
6492  } else {
6493  $this->messages[$name . 'Request'] = '0';
6494  }
6495  if ($out) {
6496  foreach ($out as $pName => $pType) {
6497  if (strpos($pType, ':')) {
6498  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ":" . $this->getLocalPart($pType);
6499  }
6500  $this->messages[$name . 'Response'][$pName] = $pType;
6501  }
6502  } else {
6503  $this->messages[$name . 'Response'] = '0';
6504  }
6505  return true;
6506  }
6507 }
6508 ?><?php
6509 
6510 
6511 
6521 class nusoap_parser extends nusoap_base
6522 {
6523  public $methodNamespace;
6524  public $parser;
6525  public $xml = '';
6526  public $xml_encoding = '';
6527  public $method = '';
6528  public $root_struct = '';
6529  public $root_struct_name = '';
6530  public $root_struct_namespace = '';
6531  public $root_header = '';
6532  public $document = ''; // incoming SOAP body (text)
6533  // determines where in the message we are (envelope,header,body,method)
6534  public $status = '';
6535  public $position = 0;
6536  public $depth = 0;
6537  public $default_namespace = '';
6538  public $namespaces = array();
6539  public $message = array();
6540  public $parent = '';
6541  public $fault = false;
6542  public $fault_code = '';
6543  public $fault_str = '';
6544  public $fault_detail = '';
6545  public $depth_array = array();
6546  public $debug_flag = true;
6547  public $soapresponse = null; // parsed SOAP Body
6548  public $soapheader = null; // parsed SOAP Header
6549  public $responseHeaders = ''; // incoming SOAP headers (text)
6550  public $body_position = 0;
6551  // for multiref parsing:
6552  // array of id => pos
6553  public $ids = array();
6554  // array of id => hrefs => pos
6555  public $multirefs = array();
6556  // toggle for auto-decoding element content
6557  public $decode_utf8 = true;
6558 
6568  public function __construct($xml, $encoding = 'UTF-8', $method = '', $decode_utf8 = true)
6569  {
6571  $this->xml = $xml;
6572  $this->xml_encoding = $encoding;
6573  $this->method = $method;
6574  $this->decode_utf8 = $decode_utf8;
6575 
6576  // Check whether content has been read.
6577  if (!empty($xml)) {
6578  // Check XML encoding
6579  $pos_xml = strpos($xml, '<?xml');
6580  if ($pos_xml !== false) {
6581  $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
6582  if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
6583  $xml_encoding = $res[1];
6584  if (strtoupper($xml_encoding) != $encoding) {
6585  $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
6586  $this->debug($err);
6587  if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
6588  $this->setError($err);
6589  return;
6590  }
6591  // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
6592  } else {
6593  $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
6594  }
6595  } else {
6596  $this->debug('No encoding specified in XML declaration');
6597  }
6598  } else {
6599  $this->debug('No XML declaration');
6600  }
6601  $this->debug('Entering nusoap_parser(), length=' . strlen($xml) . ', encoding=' . $encoding);
6602  // Create an XML parser - why not xml_parser_create_ns?
6603  $this->parser = xml_parser_create($this->xml_encoding);
6604  // Set the options for parsing the XML data.
6605  //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
6606  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
6607  xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
6608  // Set the object for the parser.
6609  // Set the element handlers for the parser.
6610  xml_set_element_handler($this->parser, $this->start_element(...), $this->end_element(...));
6611  xml_set_character_data_handler($this->parser, $this->character_data(...));
6612 
6613  // Parse the XML file.
6614  if (!xml_parse($this->parser, $xml, true)) {
6615  // Display an error message.
6616  $err = sprintf(
6617  'XML error parsing SOAP payload on line %d: %s',
6618  xml_get_current_line_number($this->parser),
6619  xml_error_string(xml_get_error_code($this->parser))
6620  );
6621  $this->debug($err);
6622  $this->debug("XML payload:\n" . $xml);
6623  $this->setError($err);
6624  } else {
6625  $this->debug('parsed successfully, found root struct: ' . $this->root_struct . ' of name ' . $this->root_struct_name);
6626  // get final value
6627  $this->soapresponse = $this->message[$this->root_struct]['result'];
6628  // get header value
6629  if ($this->root_header != '' && isset($this->message[$this->root_header]['result'])) {
6630  $this->soapheader = $this->message[$this->root_header]['result'];
6631  }
6632  // resolve hrefs/ids
6633  if (sizeof($this->multirefs) > 0) {
6634  foreach ($this->multirefs as $id => $hrefs) {
6635  $this->debug('resolving multirefs for id: ' . $id);
6636  $idVal = $this->buildVal($this->ids[$id]);
6637  if (is_array($idVal) && isset($idVal['!id'])) {
6638  unset($idVal['!id']);
6639  }
6640  foreach ($hrefs as $refPos => $ref) {
6641  $this->debug('resolving href at pos ' . $refPos);
6642  $this->multirefs[$id][$refPos] = $idVal;
6643  }
6644  }
6645  }
6646  }
6647  xml_parser_free($this->parser);
6648  } else {
6649  $this->debug('xml was empty, didn\'t parse!');
6650  $this->setError('xml was empty, didn\'t parse!');
6651  }
6652  }
6653 
6662  public function start_element($parser, $name, $attrs)
6663  {
6664  // position in a total number of elements, starting from 0
6665  // update class level pos
6666  $pos = $this->position++;
6667  // and set mine
6668  $this->message[$pos] = array('pos' => $pos,'children' => '','cdata' => '');
6669  // depth = how many levels removed from root?
6670  // set mine as current global depth and increment global depth value
6671  $this->message[$pos]['depth'] = $this->depth++;
6672 
6673  // else add self as child to whoever the current parent is
6674  if ($pos != 0) {
6675  $this->message[$this->parent]['children'] .= '|' . $pos;
6676  }
6677  // set my parent
6678  $this->message[$pos]['parent'] = $this->parent;
6679  // set self as current parent
6680  $this->parent = $pos;
6681  // set self as current value for this depth
6682  $this->depth_array[$this->depth] = $pos;
6683  // get element prefix
6684  if (strpos($name, ':')) {
6685  // get ns prefix
6686  $prefix = substr($name, 0, strpos($name, ':'));
6687  // get unqualified name
6688  $name = substr(strstr($name, ':'), 1);
6689  }
6690  // set status
6691  if ($name == 'Envelope') {
6692  $this->status = 'envelope';
6693  } elseif ($name == 'Header' && $this->status = 'envelope') {
6694  $this->root_header = $pos;
6695  $this->status = 'header';
6696  } elseif ($name == 'Body' && $this->status = 'envelope') {
6697  $this->status = 'body';
6698  $this->body_position = $pos;
6699  // set method
6700  } elseif ($this->status == 'body' && $pos == ($this->body_position + 1)) {
6701  $this->status = 'method';
6702  $this->root_struct_name = $name;
6703  $this->root_struct = $pos;
6704  $this->message[$pos]['type'] = 'struct';
6705  $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
6706  }
6707  // set my status
6708  $this->message[$pos]['status'] = $this->status;
6709  // set name
6710  $this->message[$pos]['name'] = htmlspecialchars($name);
6711  // set attrs
6712  $this->message[$pos]['attrs'] = $attrs;
6713 
6714  // loop through atts, logging ns and type declarations
6715  $attstr = '';
6716  foreach ($attrs as $key => $value) {
6717  $key_prefix = $this->getPrefix($key);
6718  $key_localpart = $this->getLocalPart($key);
6719  // if ns declarations, add to class level array of valid namespaces
6720  if ($key_prefix == 'xmlns') {
6721  if (preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/', $value)) {
6722  $this->XMLSchemaVersion = $value;
6723  $this->namespaces['xsd'] = $this->XMLSchemaVersion;
6724  $this->namespaces['xsi'] = $this->XMLSchemaVersion . '-instance';
6725  }
6726  $this->namespaces[$key_localpart] = $value;
6727  // set method namespace
6728  if ($name == $this->root_struct_name) {
6729  $this->methodNamespace = $value;
6730  }
6731  // if it's a type declaration, set type
6732  } elseif ($key_localpart == 'type') {
6733  if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
6734  // do nothing: already processed arrayType
6735  } else {
6736  $value_prefix = $this->getPrefix($value);
6737  $value_localpart = $this->getLocalPart($value);
6738  $this->message[$pos]['type'] = $value_localpart;
6739  $this->message[$pos]['typePrefix'] = $value_prefix;
6740  if (isset($this->namespaces[$value_prefix])) {
6741  $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
6742  } elseif (isset($attrs['xmlns:' . $value_prefix])) {
6743  $this->message[$pos]['type_namespace'] = $attrs['xmlns:' . $value_prefix];
6744  }
6745  // should do something here with the namespace of specified type?
6746  }
6747  } elseif ($key_localpart == 'arrayType') {
6748  $this->message[$pos]['type'] = 'array';
6749  /* do arrayType ereg here
6750  [1] arrayTypeValue ::= atype asize
6751  [2] atype ::= QName rank*
6752  [3] rank ::= '[' (',')* ']'
6753  [4] asize ::= '[' length~ ']'
6754  [5] length ::= nextDimension* Digit+
6755  [6] nextDimension ::= Digit+ ','
6756  */
6757  $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
6758  if (preg_match($expr, $value, $regs)) {
6759  $this->message[$pos]['typePrefix'] = $regs[1];
6760  $this->message[$pos]['arrayTypePrefix'] = $regs[1];
6761  if (isset($this->namespaces[$regs[1]])) {
6762  $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
6763  } elseif (isset($attrs['xmlns:' . $regs[1]])) {
6764  $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:' . $regs[1]];
6765  }
6766  $this->message[$pos]['arrayType'] = $regs[2];
6767  $this->message[$pos]['arraySize'] = $regs[3];
6768  $this->message[$pos]['arrayCols'] = $regs[4];
6769  }
6770  // specifies nil value (or not)
6771  } elseif ($key_localpart == 'nil') {
6772  $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
6773  // some other attribute
6774  } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
6775  $this->message[$pos]['xattrs']['!' . $key] = $value;
6776  }
6777 
6778  if ($key == 'xmlns') {
6779  $this->default_namespace = $value;
6780  }
6781  // log id
6782  if ($key == 'id') {
6783  $this->ids[$value] = $pos;
6784  }
6785  // root
6786  if ($key_localpart == 'root' && $value == 1) {
6787  $this->status = 'method';
6788  $this->root_struct_name = $name;
6789  $this->root_struct = $pos;
6790  $this->debug("found root struct $this->root_struct_name, pos $pos");
6791  }
6792  // for doclit
6793  $attstr .= " $key=\"$value\"";
6794  }
6795  // get namespace - must be done after namespace atts are processed
6796  if (isset($prefix)) {
6797  $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
6798  $this->default_namespace = $this->namespaces[$prefix];
6799  } else {
6800  $this->message[$pos]['namespace'] = $this->default_namespace;
6801  }
6802  if ($this->status == 'header') {
6803  if ($this->root_header != $pos) {
6804  $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6805  }
6806  } elseif ($this->root_struct_name != '') {
6807  $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6808  }
6809  }
6810 
6818  public function end_element($parser, $name)
6819  {
6820  // position of current element is equal to the last value left in depth_array for my depth
6821  $pos = $this->depth_array[$this->depth--];
6822 
6823  // get element prefix
6824  if (strpos($name, ':')) {
6825  // get ns prefix
6826  $prefix = substr($name, 0, strpos($name, ':'));
6827  // get unqualified name
6828  $name = substr(strstr($name, ':'), 1);
6829  }
6830 
6831  // build to native type
6832  if (isset($this->body_position) && $pos > $this->body_position) {
6833  // deal w/ multirefs
6834  if (isset($this->message[$pos]['attrs']['href'])) {
6835  // get id
6836  $id = substr($this->message[$pos]['attrs']['href'], 1);
6837  // add placeholder to href array
6838  $this->multirefs[$id][$pos] = 'placeholder';
6839  // add set a reference to it as the result value
6840  $this->message[$pos]['result'] = & $this->multirefs[$id][$pos];
6841  // build complexType values
6842  } elseif ($this->message[$pos]['children'] != '') {
6843  // if result has already been generated (struct/array)
6844  if (!isset($this->message[$pos]['result'])) {
6845  $this->message[$pos]['result'] = $this->buildVal($pos);
6846  }
6847  // build complexType values of attributes and possibly simpleContent
6848  } elseif (isset($this->message[$pos]['xattrs'])) {
6849  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6850  $this->message[$pos]['xattrs']['!'] = null;
6851  } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
6852  if (isset($this->message[$pos]['type'])) {
6853  $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'] : '');
6854  } else {
6855  $parent = $this->message[$pos]['parent'];
6856  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6857  $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6858  } else {
6859  $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
6860  }
6861  }
6862  }
6863  $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
6864  // set value of simpleType (or nil complexType)
6865  } else {
6866  //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
6867  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6868  $this->message[$pos]['xattrs']['!'] = null;
6869  } elseif (isset($this->message[$pos]['type'])) {
6870  $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'] : '');
6871  } else {
6872  $parent = $this->message[$pos]['parent'];
6873  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6874  $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6875  } else {
6876  $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
6877  }
6878  }
6879 
6880  /* add value to parent's result, if parent is struct/array
6881  $parent = $this->message[$pos]['parent'];
6882  if($this->message[$parent]['type'] != 'map'){
6883  if(strtolower($this->message[$parent]['type']) == 'array'){
6884  $this->message[$parent]['result'][] = $this->message[$pos]['result'];
6885  } else {
6886  $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
6887  }
6888  }
6889  */
6890  }
6891  }
6892 
6893  // for doclit
6894  if ($this->status == 'header') {
6895  if ($this->root_header != $pos) {
6896  $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6897  }
6898  } elseif ($pos >= $this->root_struct) {
6899  $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6900  }
6901  // switch status
6902  if ($pos == $this->root_struct) {
6903  $this->status = 'body';
6904  $this->root_struct_namespace = $this->message[$pos]['namespace'];
6905  } elseif ($name == 'Body') {
6906  $this->status = 'envelope';
6907  } elseif ($name == 'Header') {
6908  $this->status = 'envelope';
6909  } elseif ($name == 'Envelope') {
6910  //
6911  }
6912  // set parent back to my parent
6913  $this->parent = $this->message[$pos]['parent'];
6914  }
6915 
6923  public function character_data($parser, $data)
6924  {
6925  $pos = $this->depth_array[$this->depth];
6926  if ($this->xml_encoding == 'UTF-8') {
6927  // TODO: add an option to disable this for folks who want
6928  // raw UTF-8 that, e.g., might not map to iso-8859-1
6929  // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
6930  if ($this->decode_utf8) {
6931  $data = utf8_decode($data);
6932  }
6933  }
6934  $this->message[$pos]['cdata'] .= $data;
6935  // for doclit
6936  if ($this->status == 'header') {
6937  $this->responseHeaders .= $data;
6938  } else {
6939  $this->document .= $data;
6940  }
6941  }
6942 
6950  public function get_response()
6951  {
6952  return $this->soapresponse;
6953  }
6954 
6961  public function get_soapbody()
6962  {
6963  return $this->soapresponse;
6964  }
6965 
6972  public function get_soapheader()
6973  {
6974  return $this->soapheader;
6975  }
6976 
6983  public function getHeaders()
6984  {
6985  return $this->responseHeaders;
6986  }
6987 
6997  public function decodeSimple($value, $type, $typens)
6998  {
6999  // TODO: use the namespace!
7000  if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
7001  return (string) $value;
7002  }
7003  if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
7004  return (int) $value;
7005  }
7006  if ($type == 'float' || $type == 'double' || $type == 'decimal') {
7007  return (float) $value;
7008  }
7009  if ($type == 'boolean') {
7010  if (strtolower($value) == 'false' || strtolower($value) == 'f') {
7011  return false;
7012  }
7013  return (bool) $value;
7014  }
7015  if ($type == 'base64' || $type == 'base64Binary') {
7016  $this->debug('Decode base64 value');
7017  return base64_decode($value);
7018  }
7019  // obscure numeric types
7020  if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
7021  || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
7022  || $type == 'unsignedInt'
7023  || $type == 'unsignedShort' || $type == 'unsignedByte') {
7024  return (int) $value;
7025  }
7026  // bogus: parser treats array with no elements as a simple type
7027  if ($type == 'array') {
7028  return array();
7029  }
7030  // everything else
7031  return (string) $value;
7032  }
7033 
7042  public function buildVal($pos)
7043  {
7044  if (!isset($this->message[$pos]['type'])) {
7045  $this->message[$pos]['type'] = '';
7046  }
7047  $this->debug('in buildVal() for ' . $this->message[$pos]['name'] . "(pos $pos) of type " . $this->message[$pos]['type']);
7048  // if there are children...
7049  if ($this->message[$pos]['children'] != '') {
7050  $this->debug('in buildVal, there are children');
7051  $children = explode('|', $this->message[$pos]['children']);
7052  array_shift($children); // knock off empty
7053  // md array
7054  if (isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != '') {
7055  $r = 0; // rowcount
7056  $c = 0; // colcount
7057  foreach ($children as $child_pos) {
7058  $this->debug("in buildVal, got an MD array element: $r, $c");
7059  $params[$r][] = $this->message[$child_pos]['result'];
7060  $c++;
7061  if ($c == $this->message[$pos]['arrayCols']) {
7062  $c = 0;
7063  $r++;
7064  }
7065  }
7066  // array
7067  } elseif ($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array') {
7068  $this->debug('in buildVal, adding array ' . $this->message[$pos]['name']);
7069  foreach ($children as $child_pos) {
7070  $params[] = &$this->message[$child_pos]['result'];
7071  }
7072  // apache Map type: java hashtable
7073  } elseif ($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
7074  $this->debug('in buildVal, Java Map ' . $this->message[$pos]['name']);
7075  foreach ($children as $child_pos) {
7076  $kv = explode("|", $this->message[$child_pos]['children']);
7077  $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
7078  }
7079  // generic compound type
7080  //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
7081  } else {
7082  // Apache Vector type: treat as an array
7083  $this->debug('in buildVal, adding Java Vector or generic compound type ' . $this->message[$pos]['name']);
7084  if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
7085  $notstruct = 1;
7086  } else {
7087  $notstruct = 0;
7088  }
7089  //
7090  foreach ($children as $child_pos) {
7091  if ($notstruct) {
7092  $params[] = &$this->message[$child_pos]['result'];
7093  } else {
7094  if (isset($params[$this->message[$child_pos]['name']])) {
7095  // de-serialize repeated element name into an array
7096  if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
7097  $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
7098  }
7099  $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
7100  } else {
7101  $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
7102  }
7103  }
7104  }
7105  }
7106  if (isset($this->message[$pos]['xattrs'])) {
7107  $this->debug('in buildVal, handling attributes');
7108  foreach ($this->message[$pos]['xattrs'] as $n => $v) {
7109  $params[$n] = $v;
7110  }
7111  }
7112  // handle simpleContent
7113  if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
7114  $this->debug('in buildVal, handling simpleContent');
7115  if (isset($this->message[$pos]['type'])) {
7116  $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7117  } else {
7118  $parent = $this->message[$pos]['parent'];
7119  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
7120  $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7121  } else {
7122  $params['!'] = $this->message[$pos]['cdata'];
7123  }
7124  }
7125  }
7126  $ret = is_array($params) ? $params : array();
7127  $this->debug('in buildVal, return:');
7128  $this->appendDebug($this->varDump($ret));
7129  return $ret;
7130  } else {
7131  $this->debug('in buildVal, no children, building scalar');
7132  $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
7133  if (isset($this->message[$pos]['type'])) {
7134  $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7135  $this->debug("in buildVal, return: $ret");
7136  return $ret;
7137  }
7138  $parent = $this->message[$pos]['parent'];
7139  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
7140  $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7141  $this->debug("in buildVal, return: $ret");
7142  return $ret;
7143  }
7144  $ret = $this->message[$pos]['cdata'];
7145  $this->debug("in buildVal, return: $ret");
7146  return $ret;
7147  }
7148  }
7149 }
7150 
7154 class soap_parser extends nusoap_parser
7155 {
7156 }
7157 
7158 ?><?php
7159 
7160 
7161 
7182 class nusoap_client extends nusoap_base
7183 {
7184  public $return;
7185  public $wsdl;
7186  public $wsdlFile;
7187  public $opData;
7188  public $operation;
7189  public $username = ''; // Username for HTTP authentication
7190  public $password = ''; // Password for HTTP authentication
7191  public $authtype = ''; // Type of HTTP authentication
7192  public $certRequest = array(); // Certificate for HTTP SSL authentication
7193  public $requestHeaders = false; // SOAP headers in request (text)
7194  public $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
7195  public $responseHeader = null; // SOAP Header from response (parsed)
7196  public $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
7197  public $endpoint;
7198  public $forceEndpoint = ''; // overrides WSDL endpoint
7199  public $proxyhost = '';
7200  public $proxyport = '';
7201  public $proxyusername = '';
7202  public $proxypassword = '';
7203  public $xml_encoding = ''; // character set encoding of incoming (response) messages
7204  public $http_encoding = false;
7205  public $timeout = 0; // HTTP connection timeout
7206  public $response_timeout = 30; // HTTP response timeout
7207  public $endpointType = ''; // soap|wsdl, empty for WSDL initialization error
7208  public $persistentConnection = false;
7209  public $defaultRpcParams = false; // This is no longer used
7210  public $request = ''; // HTTP request
7211  public $response = ''; // HTTP response
7212  public $responseData = ''; // SOAP payload of response
7213  public $cookies = array(); // Cookies from response or for request
7214  public $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
7215  public $operations = array(); // WSDL operations, empty for WSDL initialization error
7216  public $curl_options = array(); // User-specified cURL options
7217  public $bindingType = ''; // WSDL operation binding type
7218  public $use_curl = false; // whether to always try to use cURL
7219 
7220  /*
7221  * fault related variables
7222  */
7227  public $fault;
7232  public $faultcode;
7237  public $faultstring;
7242  public $faultdetail;
7243 
7258  public function __construct($endpoint, $wsdl = false, $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30)
7259  {
7261  $this->endpoint = $endpoint;
7262  $this->proxyhost = $proxyhost;
7263  $this->proxyport = $proxyport;
7264  $this->proxyusername = $proxyusername;
7265  $this->proxypassword = $proxypassword;
7266  $this->timeout = $timeout;
7267  $this->response_timeout = $response_timeout;
7268 
7269  $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
7270  $this->appendDebug('endpoint=' . $this->varDump($endpoint));
7271 
7272  // make values
7273  if ($wsdl) {
7274  if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
7275  $this->wsdl = $endpoint;
7276  $this->endpoint = $this->wsdl->wsdl;
7277  $this->wsdlFile = $this->endpoint;
7278  $this->debug('existing wsdl instance created from ' . $this->endpoint);
7279  $this->checkWSDL();
7280  } else {
7281  $this->wsdlFile = $this->endpoint;
7282  $this->wsdl = null;
7283  $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
7284  }
7285  $this->endpointType = 'wsdl';
7286  } else {
7287  $this->debug("instantiate SOAP with endpoint at $endpoint");
7288  $this->endpointType = 'soap';
7289  }
7290  }
7291 
7317  public function call($operation, $params = array(), $namespace = 'http://tempuri.org', $soapAction = '', $headers = false, $rpcParams = null, $style = 'rpc', $use = 'encoded')
7318  {
7319  $this->operation = $operation;
7320  $this->fault = false;
7321  $this->setError('');
7322  $this->request = '';
7323  $this->response = '';
7324  $this->responseData = '';
7325  $this->faultstring = '';
7326  $this->faultcode = '';
7327  $this->opData = array();
7328 
7329  $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
7330  $this->appendDebug('params=' . $this->varDump($params));
7331  $this->appendDebug('headers=' . $this->varDump($headers));
7332  if ($headers) {
7333  $this->requestHeaders = $headers;
7334  }
7335  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7336  $this->loadWSDL();
7337  if ($this->getError()) {
7338  return false;
7339  }
7340  }
7341  // serialize parameters
7342  if ($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)) {
7343  // use WSDL for operation
7344  $this->opData = $opData;
7345  $this->debug("found operation");
7346  $this->appendDebug('opData=' . $this->varDump($opData));
7347  if (isset($opData['soapAction'])) {
7348  $soapAction = $opData['soapAction'];
7349  }
7350  if (! $this->forceEndpoint) {
7351  $this->endpoint = $opData['endpoint'];
7352  } else {
7353  $this->endpoint = $this->forceEndpoint;
7354  }
7355  $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace;
7356  $style = $opData['style'];
7357  $use = $opData['input']['use'];
7358  // add ns to ns array
7359  if ($namespace != '' && !isset($this->wsdl->namespaces[$namespace])) {
7360  $nsPrefix = 'ns' . rand(1000, 9999);
7361  $this->wsdl->namespaces[$nsPrefix] = $namespace;
7362  }
7363  $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
7364  // serialize payload
7365  if (is_string($params)) {
7366  $this->debug("serializing param string for WSDL operation $operation");
7367  $payload = $params;
7368  } elseif (is_array($params)) {
7369  $this->debug("serializing param array for WSDL operation $operation");
7370  $payload = $this->wsdl->serializeRPCParameters($operation, 'input', $params, $this->bindingType);
7371  } else {
7372  $this->debug('params must be array or string');
7373  $this->setError('params must be array or string');
7374  return false;
7375  }
7376  $usedNamespaces = $this->wsdl->usedNamespaces;
7377  if (isset($opData['input']['encodingStyle'])) {
7378  $encodingStyle = $opData['input']['encodingStyle'];
7379  } else {
7380  $encodingStyle = '';
7381  }
7382  $this->appendDebug($this->wsdl->getDebug());
7383  $this->wsdl->clearDebug();
7384  if ($errstr = $this->wsdl->getError()) {
7385  $this->debug('got wsdl error: ' . $errstr);
7386  $this->setError('wsdl error: ' . $errstr);
7387  return false;
7388  }
7389  } elseif ($this->endpointType == 'wsdl') {
7390  // operation not in WSDL
7391  $this->appendDebug($this->wsdl->getDebug());
7392  $this->wsdl->clearDebug();
7393  $this->setError('operation ' . $operation . ' not present.');
7394  $this->debug("operation '$operation' not present.");
7395  return false;
7396  } else {
7397  // no WSDL
7398  //$this->namespaces['ns1'] = $namespace;
7399  $nsPrefix = 'ns' . rand(1000, 9999);
7400  // serialize
7401  $payload = '';
7402  if (is_string($params)) {
7403  $this->debug("serializing param string for operation $operation");
7404  $payload = $params;
7405  } elseif (is_array($params)) {
7406  $this->debug("serializing param array for operation $operation");
7407  foreach ($params as $k => $v) {
7408  $payload .= $this->serialize_val($v, $k, false, false, false, false, $use);
7409  }
7410  } else {
7411  $this->debug('params must be array or string');
7412  $this->setError('params must be array or string');
7413  return false;
7414  }
7415  $usedNamespaces = array();
7416  if ($use == 'encoded') {
7417  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7418  } else {
7419  $encodingStyle = '';
7420  }
7421  }
7422  // wrap RPC calls with method element
7423  if ($style == 'rpc') {
7424  if ($use == 'literal') {
7425  $this->debug("wrapping RPC request with literal method element");
7426  if ($namespace) {
7427  // 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
7428  $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7429  $payload .
7430  "</$nsPrefix:$operation>";
7431  } else {
7432  $payload = "<$operation>" . $payload . "</$operation>";
7433  }
7434  } else {
7435  $this->debug("wrapping RPC request with encoded method element");
7436  if ($namespace) {
7437  $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7438  $payload .
7439  "</$nsPrefix:$operation>";
7440  } else {
7441  $payload = "<$operation>" .
7442  $payload .
7443  "</$operation>";
7444  }
7445  }
7446  }
7447  // serialize envelope
7448  $soapmsg = $this->serializeEnvelope($payload, $this->requestHeaders, $usedNamespaces, $style, $use, $encodingStyle);
7449  $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
7450  $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
7451  // send
7452  $return = $this->send($this->getHTTPBody($soapmsg), $soapAction, $this->timeout, $this->response_timeout);
7453  if ($errstr = $this->getError()) {
7454  $this->debug('Error: ' . $errstr);
7455  return false;
7456  } else {
7457  $this->return = $return;
7458  $this->debug('sent message successfully and got a(n) ' . gettype($return));
7459  $this->appendDebug('return=' . $this->varDump($return));
7460 
7461  // fault?
7462  if (is_array($return) && isset($return['faultcode'])) {
7463  $this->debug('got fault');
7464  $this->setError($return['faultcode'] . ': ' . $return['faultstring']);
7465  $this->fault = true;
7466  foreach ($return as $k => $v) {
7467  $this->$k = $v;
7468  $this->debug("$k = $v<br>");
7469  }
7470  return $return;
7471  } elseif ($style == 'document') {
7472  // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
7473  // we are only going to return the first part here...sorry about that
7474  return $return;
7475  } else {
7476  // array of return values
7477  if (is_array($return)) {
7478  // multiple 'out' parameters, which we return wrapped up
7479  // in the array
7480  if (sizeof($return) > 1) {
7481  return $return;
7482  }
7483  // single 'out' parameter (normally the return value)
7484  $return = array_shift($return);
7485  $this->debug('return shifted value: ');
7486  $this->appendDebug($this->varDump($return));
7487  return $return;
7488  // nothing returned (ie, echoVoid)
7489  } else {
7490  return "";
7491  }
7492  }
7493  }
7494  }
7495 
7501  public function checkWSDL()
7502  {
7503  $this->appendDebug($this->wsdl->getDebug());
7504  $this->wsdl->clearDebug();
7505  $this->debug('checkWSDL');
7506  // catch errors
7507  if ($errstr = $this->wsdl->getError()) {
7508  $this->debug('got wsdl error: ' . $errstr);
7509  $this->setError('wsdl error: ' . $errstr);
7510  } elseif ($this->operations = $this->wsdl->getOperations('soap')) {
7511  $this->bindingType = 'soap';
7512  $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType);
7513  } elseif ($this->operations = $this->wsdl->getOperations('soap12')) {
7514  $this->bindingType = 'soap12';
7515  $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType);
7516  $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
7517  } else {
7518  $this->debug('getOperations returned false');
7519  $this->setError('no operations defined in the WSDL document!');
7520  }
7521  }
7522 
7528  public function loadWSDL()
7529  {
7530  $this->debug('instantiating wsdl class with doc: ' . $this->wsdlFile);
7531  $this->wsdl = new wsdl('', $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword, $this->timeout, $this->response_timeout, $this->curl_options, $this->use_curl);
7532  $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
7533  $this->wsdl->fetchWSDL($this->wsdlFile);
7534  $this->checkWSDL();
7535  }
7536 
7544  public function getOperationData($operation)
7545  {
7546  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7547  $this->loadWSDL();
7548  if ($this->getError()) {
7549  return false;
7550  }
7551  }
7552  if (isset($this->operations[$operation])) {
7553  return $this->operations[$operation];
7554  }
7555  $this->debug("No data for operation: $operation");
7556  }
7557 
7572  public function send($msg, $soapaction = '', $timeout = 0, $response_timeout = 30)
7573  {
7574  $this->checkCookies();
7575  // detect transport
7576  switch (true) {
7577  // http(s)
7578  case preg_match('/^http/', $this->endpoint):
7579  $this->debug('transporting via HTTP');
7580  if ($this->persistentConnection == true && is_object($this->persistentConnection)) {
7581  $http = & $this->persistentConnection;
7582  } else {
7583  $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
7584  if ($this->persistentConnection) {
7585  $http->usePersistentConnection();
7586  }
7587  }
7588  $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
7589  $http->setSOAPAction($soapaction);
7590  if ($this->proxyhost && $this->proxyport) {
7591  $http->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
7592  }
7593  if ($this->authtype != '') {
7594  $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
7595  }
7596  if ($this->http_encoding != '') {
7597  $http->setEncoding($this->http_encoding);
7598  }
7599  $this->debug('sending message, length=' . strlen($msg));
7600  if (preg_match('/^http:/', $this->endpoint)) {
7601  //if(strpos($this->endpoint,'http:')){
7602  $this->responseData = $http->send($msg, $timeout, $response_timeout, $this->cookies);
7603  } elseif (preg_match('/^https/', $this->endpoint)) {
7604  //} elseif(strpos($this->endpoint,'https:')){
7605  //if(phpversion() == '4.3.0-dev'){
7606  //$response = $http->send($msg,$timeout,$response_timeout);
7607  //$this->request = $http->outgoing_payload;
7608  //$this->response = $http->incoming_payload;
7609  //} else
7610  $this->responseData = $http->sendHTTPS($msg, $timeout, $response_timeout, $this->cookies);
7611  } else {
7612  $this->setError('no http/s in endpoint url');
7613  }
7614  $this->request = $http->outgoing_payload;
7615  $this->response = $http->incoming_payload;
7616  $this->appendDebug($http->getDebug());
7617  $this->UpdateCookies($http->incoming_cookies);
7618 
7619  // save transport object if using persistent connections
7620  if ($this->persistentConnection) {
7621  $http->clearDebug();
7622  if (!is_object($this->persistentConnection)) {
7623  $this->persistentConnection = $http;
7624  }
7625  }
7626 
7627  if ($err = $http->getError()) {
7628  $this->setError('HTTP Error: ' . $err);
7629  return false;
7630  } elseif ($this->getError()) {
7631  return false;
7632  } else {
7633  $this->debug('got response, length=' . strlen($this->responseData) . ' type=' . $http->incoming_headers['content-type']);
7634  return $this->parseResponse($http->incoming_headers, $this->responseData);
7635  }
7636  break;
7637  default:
7638  $this->setError('no transport found, or selected transport is not yet supported!');
7639  return false;
7640  break;
7641  }
7642  }
7643 
7652  public function parseResponse($headers, $data)
7653  {
7654  $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
7655  $this->appendDebug($this->varDump($headers));
7656  if (!strstr($headers['content-type'], 'text/xml')) {
7657  $this->setError('Response not of type text/xml: ' . $headers['content-type']);
7658  return false;
7659  }
7660  if (strpos($headers['content-type'], '=')) {
7661  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
7662  $this->debug('Got response encoding: ' . $enc);
7663  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
7664  $this->xml_encoding = strtoupper($enc);
7665  } else {
7666  $this->xml_encoding = 'US-ASCII';
7667  }
7668  } else {
7669  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
7670  $this->xml_encoding = 'ISO-8859-1';
7671  }
7672  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
7673  $parser = new nusoap_parser($data, $this->xml_encoding, $this->operation, $this->decode_utf8);
7674  // add parser debug data to our debug
7675  $this->appendDebug($parser->getDebug());
7676  // if parse errors
7677  if ($errstr = $parser->getError()) {
7678  $this->setError($errstr);
7679  // destroy the parser object
7680  unset($parser);
7681  return false;
7682  } else {
7683  // get SOAP headers
7684  $this->responseHeaders = $parser->getHeaders();
7685  // get SOAP headers
7686  $this->responseHeader = $parser->get_soapheader();
7687  // get decoded message
7688  $return = $parser->get_soapbody();
7689  // add document for doclit support
7690  $this->document = $parser->document;
7691  // destroy the parser object
7692  unset($parser);
7693  // return decode message
7694  return $return;
7695  }
7696  }
7697 
7705  public function setCurlOption($option, $value)
7706  {
7707  $this->debug("setCurlOption option=$option, value=");
7708  $this->appendDebug($this->varDump($value));
7709  $this->curl_options[$option] = $value;
7710  }
7711 
7718  public function setEndpoint($endpoint)
7719  {
7720  $this->debug("setEndpoint(\"$endpoint\")");
7721  $this->forceEndpoint = $endpoint;
7722  }
7723 
7730  public function setHeaders($headers)
7731  {
7732  $this->debug("setHeaders headers=");
7733  $this->appendDebug($this->varDump($headers));
7734  $this->requestHeaders = $headers;
7735  }
7736 
7743  public function getHeaders()
7744  {
7745  return $this->responseHeaders;
7746  }
7747 
7754  public function getHeader()
7755  {
7756  return $this->responseHeader;
7757  }
7758 
7768  public function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '')
7769  {
7770  $this->proxyhost = $proxyhost;
7771  $this->proxyport = $proxyport;
7772  $this->proxyusername = $proxyusername;
7773  $this->proxypassword = $proxypassword;
7774  }
7775 
7785  public function setCredentials($username, $password, $authtype = 'basic', $certRequest = array())
7786  {
7787  $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
7788  $this->appendDebug($this->varDump($certRequest));
7789  $this->username = $username;
7790  $this->password = $password;
7791  $this->authtype = $authtype;
7792  $this->certRequest = $certRequest;
7793  }
7794 
7801  public function setHTTPEncoding($enc = 'gzip, deflate')
7802  {
7803  $this->debug("setHTTPEncoding(\"$enc\")");
7804  $this->http_encoding = $enc;
7805  }
7806 
7813  public function setUseCURL($use)
7814  {
7815  $this->debug("setUseCURL($use)");
7816  $this->use_curl = $use;
7817  }
7818 
7824  public function useHTTPPersistentConnection()
7825  {
7826  $this->debug("useHTTPPersistentConnection");
7827  $this->persistentConnection = true;
7828  }
7829 
7841  public function getDefaultRpcParams()
7842  {
7843  return $this->defaultRpcParams;
7844  }
7845 
7857  public function setDefaultRpcParams($rpcParams)
7858  {
7859  $this->defaultRpcParams = $rpcParams;
7860  }
7861 
7869  public function getProxy()
7870  {
7871  $r = rand();
7872  $evalStr = $this->_getProxyClassCode($r);
7873  //$this->debug("proxy class: $evalStr");
7874  if ($this->getError()) {
7875  $this->debug("Error from _getProxyClassCode, so return NULL");
7876  return null;
7877  }
7878  // eval the class
7879  eval($evalStr);
7880  // instantiate proxy object
7881  eval("\$proxy = new nusoap_proxy_$r('');");
7882  // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
7883  $proxy->endpointType = 'wsdl';
7884  $proxy->wsdlFile = $this->wsdlFile;
7885  $proxy->wsdl = $this->wsdl;
7886  $proxy->operations = $this->operations;
7887  $proxy->defaultRpcParams = $this->defaultRpcParams;
7888  // transfer other state
7889  $proxy->soap_defencoding = $this->soap_defencoding;
7890  $proxy->username = $this->username;
7891  $proxy->password = $this->password;
7892  $proxy->authtype = $this->authtype;
7893  $proxy->certRequest = $this->certRequest;
7894  $proxy->requestHeaders = $this->requestHeaders;
7895  $proxy->endpoint = $this->endpoint;
7896  $proxy->forceEndpoint = $this->forceEndpoint;
7897  $proxy->proxyhost = $this->proxyhost;
7898  $proxy->proxyport = $this->proxyport;
7899  $proxy->proxyusername = $this->proxyusername;
7900  $proxy->proxypassword = $this->proxypassword;
7901  $proxy->http_encoding = $this->http_encoding;
7902  $proxy->timeout = $this->timeout;
7903  $proxy->response_timeout = $this->response_timeout;
7904  $proxy->persistentConnection = &$this->persistentConnection;
7905  $proxy->decode_utf8 = $this->decode_utf8;
7906  $proxy->curl_options = $this->curl_options;
7907  $proxy->bindingType = $this->bindingType;
7908  $proxy->use_curl = $this->use_curl;
7909  return $proxy;
7910  }
7911 
7918  public function _getProxyClassCode($r)
7919  {
7920  $this->debug("in getProxy endpointType=$this->endpointType");
7921  $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
7922  if ($this->endpointType != 'wsdl') {
7923  $evalStr = 'A proxy can only be created for a WSDL client';
7924  $this->setError($evalStr);
7925  $evalStr = "echo \"$evalStr\";";
7926  return $evalStr;
7927  }
7928  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7929  $this->loadWSDL();
7930  if ($this->getError()) {
7931  return "echo \"" . $this->getError() . "\";";
7932  }
7933  }
7934  $evalStr = '';
7935  foreach ($this->operations as $operation => $opData) {
7936  if ($operation != '') {
7937  // create param string and param comment string
7938  if (sizeof($opData['input']['parts']) > 0) {
7939  $paramStr = '';
7940  $paramArrayStr = '';
7941  $paramCommentStr = '';
7942  foreach ($opData['input']['parts'] as $name => $type) {
7943  $paramStr .= "\$$name, ";
7944  $paramArrayStr .= "'$name' => \$$name, ";
7945  $paramCommentStr .= "$type \$$name, ";
7946  }
7947  $paramStr = substr($paramStr, 0, strlen($paramStr) - 2);
7948  $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr) - 2);
7949  $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr) - 2);
7950  } else {
7951  $paramStr = '';
7952  $paramArrayStr = '';
7953  $paramCommentStr = 'void';
7954  }
7955  $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
7956  $evalStr .= "// $paramCommentStr
7957  function " . str_replace('.', '__', $operation) . "($paramStr) {
7958  \$params = array($paramArrayStr);
7959  return \$this->call('$operation', \$params, '" . $opData['namespace'] . "', '" . (isset($opData['soapAction']) ? $opData['soapAction'] : '') . "');
7960  }
7961  ";
7962  unset($paramStr);
7963  unset($paramCommentStr);
7964  }
7965  }
7966  $evalStr = 'class nusoap_proxy_' . $r . ' extends nusoap_client {
7967  ' . $evalStr . '
7968 }';
7969  return $evalStr;
7970  }
7971 
7978  public function getProxyClassCode()
7979  {
7980  $r = rand();
7981  return $this->_getProxyClassCode($r);
7982  }
7983 
7991  public function getHTTPBody($soapmsg)
7992  {
7993  return $soapmsg;
7994  }
7995 
8004  public function getHTTPContentType()
8005  {
8006  return 'text/xml';
8007  }
8008 
8018  public function getHTTPContentTypeCharset()
8019  {
8020  return $this->soap_defencoding;
8021  }
8022 
8023  /*
8024  * whether or not parser should decode utf8 element content
8025  *
8026  * @return always returns true
8027  * @access public
8028  */
8029  public function decodeUTF8($bool)
8030  {
8031  $this->decode_utf8 = $bool;
8032  return true;
8033  }
8034 
8043  public function setCookie($name, $value)
8044  {
8045  if (strlen($name) == 0) {
8046  return false;
8047  }
8048  $this->cookies[] = array('name' => $name, 'value' => $value);
8049  return true;
8050  }
8051 
8058  public function getCookies()
8059  {
8060  return $this->cookies;
8061  }
8062 
8069  public function checkCookies()
8070  {
8071  if (sizeof($this->cookies) == 0) {
8072  return true;
8073  }
8074  $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
8075  $curr_cookies = $this->cookies;
8076  $this->cookies = array();
8077  foreach ($curr_cookies as $cookie) {
8078  if (! is_array($cookie)) {
8079  $this->debug('Remove cookie that is not an array');
8080  continue;
8081  }
8082  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
8083  if (strtotime($cookie['expires']) > time()) {
8084  $this->cookies[] = $cookie;
8085  } else {
8086  $this->debug('Remove expired cookie ' . $cookie['name']);
8087  }
8088  } else {
8089  $this->cookies[] = $cookie;
8090  }
8091  }
8092  $this->debug('checkCookie: ' . sizeof($this->cookies) . ' cookies left in array');
8093  return true;
8094  }
8095 
8103  public function UpdateCookies($cookies)
8104  {
8105  if (sizeof($this->cookies) == 0) {
8106  // no existing cookies: take whatever is new
8107  if (sizeof($cookies) > 0) {
8108  $this->debug('Setting new cookie(s)');
8109  $this->cookies = $cookies;
8110  }
8111  return true;
8112  }
8113  if (sizeof($cookies) == 0) {
8114  // no new cookies: keep what we've got
8115  return true;
8116  }
8117  // merge
8118  foreach ($cookies as $newCookie) {
8119  if (!is_array($newCookie)) {
8120  continue;
8121  }
8122  if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
8123  continue;
8124  }
8125  $newName = $newCookie['name'];
8126 
8127  $found = false;
8128  for ($i = 0; $i < count($this->cookies); $i++) {
8129  $cookie = $this->cookies[$i];
8130  if (!is_array($cookie)) {
8131  continue;
8132  }
8133  if (!isset($cookie['name'])) {
8134  continue;
8135  }
8136  if ($newName != $cookie['name']) {
8137  continue;
8138  }
8139  $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
8140  $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
8141  if ($newDomain != $domain) {
8142  continue;
8143  }
8144  $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
8145  $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
8146  if ($newPath != $path) {
8147  continue;
8148  }
8149  $this->cookies[$i] = $newCookie;
8150  $found = true;
8151  $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
8152  break;
8153  }
8154  if (! $found) {
8155  $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
8156  $this->cookies[] = $newCookie;
8157  }
8158  }
8159  return true;
8160  }
8161 }
8162 
8163 if (!extension_loaded('soap')) {
8167  class soapclient extends nusoap_client
8168  {
8169  }
8170 }
if($err=$client->getError()) $namespace
appendDebug($string)
adds debug data to the instance debug string without formatting
Definition: nusoap.php:263
Backward compatibility.
Definition: nusoap.php:4570
$res
Definition: ltiservices.php:66
& getDebugAsXMLComment()
gets the current debug data for this instance as an XML comment this may change the contents of the d...
Definition: nusoap.php:304
setError($str)
sets error string
Definition: nusoap.php:353
$_GET["client_id"]
Definition: webdav.php:30
Contains information for a SOAP fault.
Definition: nusoap.php:993
$scope
Definition: ltiregstart.php:47
transport class for sending/receiving data via HTTP and HTTPS NOTE: PHP must be compiled with the CUR...
Definition: nusoap.php:2140
& getDebug()
gets the current debug data for this instance
Definition: nusoap.php:290
if(empty($path)) $serviceName
Definition: ltiservices.php:35
isArraySimpleOrStruct($val)
detect if array is a simple array or a struct (associative array)
Definition: nusoap.php:365
parses a WSDL file, allows access to it&#39;s data, other utility methods.
Definition: nusoap.php:4587
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:61
$location
Definition: buildRTE.php:22
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:31
getOperationDataForSoapAction($soapAction, $bindingType='soap')
returns an associative array of data necessary for calling an operation
Definition: nusoap.php:5230
if(count($parts) !=3) $payload
Definition: ltitoken.php:67
$XMLSchemaVersion
Definition: nusoap.php:113
Backward compatibility.
Definition: nusoap.php:1068
nusoap_server allows the user to create a SOAP server that is capable of receiving messages and retur...
Definition: nusoap.php:3477
$response
Definition: xapitoken.php:93
$url
Definition: shib_logout.php:66
getLocalPart($str)
returns the local part of a prefixed string returns the original string, if not prefixed ...
Definition: nusoap.php:779
$responseData
$http
Definition: deliver.php:30
serialize($debug=0)
serialize the parsed wsdl
Definition: nusoap.php:5468
$c
Definition: deliver.php:25
__construct()
constructor
Definition: nusoap.php:195
Backward compatibility.
Definition: nusoap.php:2015
$path
Definition: ltiservices.php:29
For creating serializable abstractions of native PHP types.
Definition: nusoap.php:2034
catch(\Exception $e) $req
Definition: xapiproxy.php:91
getError()
returns error string if present
Definition: nusoap.php:339
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
debug($string)
adds debug data to the instance debug string with formatting
Definition: nusoap.php:250
Backward compatibility.
Definition: nusoap.php:7154
$messages
Definition: xapiexit.php:21
serializeRPCParameters($operation, $direction, $parameters, $bindingType='soap')
serialize PHP values according to a WSDL message definition contrary to the method name...
Definition: nusoap.php:5710
getPrefixFromNamespace($ns)
returns the prefix for a given namespace (or prefix) or false if no prefixes registered for the given...
Definition: nusoap.php:830
expandQname($qname)
expands (changes prefix to namespace) a qualified name
Definition: nusoap.php:753
parses an XML Schema, allows access to it&#39;s data, other utility methods.
Definition: nusoap.php:1085
setCredentials($username, $password, $authtype='basic', $certRequest=array())
if authenticating, set user credentials here
Definition: nusoap.php:5142
nusoap_base
Definition: nusoap.php:54
$_SERVER['HTTP_HOST']
Definition: raiseError.php:26
webDescription()
prints html description of services
Definition: nusoap.php:5326
$param
Definition: xapitoken.php:46
$out
Definition: buildRTE.php:24
[nu]soapclient higher level class for easy usage.
Definition: nusoap.php:7182
serializeEnvelope($body, $headers=false, $namespaces=array(), $style='rpc', $use='encoded', $encodingStyle='http://schemas.xmlsoap.org/soap/encoding/')
serializes a message
Definition: nusoap.php:658
varDump($data)
Returns a string with the output of var_dump.
Definition: nusoap.php:867
getPrefix($str)
returns the prefix part of a prefixed string returns false, if not prefixed
Definition: nusoap.php:797
getOperations($bindingType='soap')
returns an assoc array of operation names => operation data
Definition: nusoap.php:5166
serialize()
serialize a fault
Definition: nusoap.php:1043
$soap_defencoding
Definition: nusoap.php:122
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
__construct(Container $dic, ilPlugin $plugin)
expandEntities($val)
expands entities, e.g.
Definition: nusoap.php:321
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
getNamespaceFromPrefix($prefix)
pass it a prefix, it returns a namespace
Definition: nusoap.php:813
nusoap_parser class parses SOAP XML messages into native PHP values
Definition: nusoap.php:6521
$message
Definition: xapiexit.php:31
addOperation($name, $in=false, $out=false, $namespace=false, $soapaction=false, $style='rpc', $use='encoded', $documentation='', $encodingStyle='')
register an operation with the server
Definition: nusoap.php:6436
getOperationData($operation, $bindingType='soap')
returns an associative array of data necessary for calling an operation
Definition: nusoap.php:5198
clearDebug()
clears the current debug data for this instance
Definition: nusoap.php:277
header()
expected output: > ILIAS shows the rendered Component.
Definition: header.php:29
fetchWSDL($wsdl)
fetches the WSDL document and parses it
Definition: nusoap.php:4670
serialize_val($val, $name=false, $type=false, $name_ns=false, $type_ns=false, $attributes=false, $use='encoded', $soapval=false)
serializes PHP values in accordance w/ section 5.
Definition: nusoap.php:391
catch(ilCmiXapiException $e) send($response)
Definition: xapitoken.php:100
$r

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

This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Learning e.V.

ILIAS is licensed with the GPL-3.0, see https://www.gnu.org/licenses/gpl-3.0.en.html You should have received a copy of said license along with the source code, too.

If this is not the case or you just want to try ILIAS, you'll find us at: https://www.ilias.de https://github.com/ILIAS-eLearning

Definition at line 43 of file nusoap.php.