ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
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
 

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

972 {
973  $pattern = '/' .
974  '([0-9]{4})-' . // centuries & years CCYY-
975  '([0-9]{2})-' . // months MM-
976  '([0-9]{2})' . // days DD
977  'T' . // separator T
978  '([0-9]{2}):' . // hours hh:
979  '([0-9]{2}):' . // minutes mm:
980  '([0-9]{2})(\.[0-9]+)?' . // seconds ss.ss...
981  '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
982  '/';
983 
984  if (preg_match($pattern, $datestr, $regs)) {
985  // not utc
986  if ($regs[8] != 'Z') {
987  $op = substr($regs[8], 0, 1);
988  $h = substr($regs[8], 1, 2);
989  $m = substr($regs[8], strlen($regs[8])-2, 2);
990  if ($op == '-') {
991  $regs[4] = $regs[4] + $h;
992  $regs[5] = $regs[5] + $m;
993  } elseif ($op == '+') {
994  $regs[4] = $regs[4] - $h;
995  $regs[5] = $regs[5] - $m;
996  }
997  }
998  return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
999  // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
1000  } else {
1001  return false;
1002  }
1003 }

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

References $timestamp.

942 {
943  $datestr = date('Y-m-d\TH:i:sO', $timestamp);
944  if ($utc) {
945  $pattern = '/' .
946  '([0-9]{4})-' . // centuries & years CCYY-
947  '([0-9]{2})-' . // months MM-
948  '([0-9]{2})' . // days DD
949  'T' . // separator T
950  '([0-9]{2}):' . // hours hh:
951  '([0-9]{2}):' . // minutes mm:
952  '([0-9]{2})(\.[0-9]*)?' . // seconds ss.ss...
953  '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
954  '/';
955 
956  if (preg_match($pattern, $datestr, $regs)) {
957  return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ', $regs[1], $regs[2], $regs[3], $regs[4], $regs[5], $regs[6]);
958  }
959  return false;
960  } else {
961  return $datestr;
962  }
963 }
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 1012 of file nusoap.php.

1013 {
1014  $start = gettimeofday();
1015 
1016  do {
1017  $stop = gettimeofday();
1018  $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
1019  + $stop['usec'] - $start['usec'];
1020  } while ($timePassed < $usec);
1021 }
1022 
1023 ?><?php
1024 
1025 
1026 
1035 class nusoap_fault extends nusoap_base
1036 {
1042  public $faultcode;
1048  public $faultactor;
1054  public $faultstring;
1060  public $faultdetail;
1061 
1070  public function __construct($faultcode, $faultactor='', $faultstring='', $faultdetail='')
1071  {
1073  $this->faultcode = $faultcode;
1074  $this->faultactor = $faultactor;
1075  $this->faultstring = $faultstring;
1076  $this->faultdetail = $faultdetail;
1077  }
1078 
1085  public function serialize()
1086  {
1087  $ns_string = '';
1088  foreach ($this->namespaces as $k => $v) {
1089  $ns_string .= "\n xmlns:$k=\"$v\"";
1090  }
1091  $return_msg =
1092  '<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?>' .
1093  '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string . ">\n" .
1094  '<SOAP-ENV:Body>' .
1095  '<SOAP-ENV:Fault>' .
1096  $this->serialize_val($this->faultcode, 'faultcode') .
1097  $this->serialize_val($this->faultstring, 'faultstring') .
1098  $this->serialize_val($this->faultactor, 'faultactor') .
1099  $this->serialize_val($this->faultdetail, 'detail') .
1100  '</SOAP-ENV:Fault>' .
1101  '</SOAP-ENV:Body>' .
1102  '</SOAP-ENV:Envelope>';
1103  return $return_msg;
1104  }
1105 }
1106 
1110 class soap_fault extends nusoap_fault
1111 {
1112 }
1113 
1114 ?><?php
1115 
1116 
1117 
1127 class nusoap_xmlschema extends nusoap_base
1128 {
1129  // files
1130  public $schema = '';
1131  public $xml = '';
1132  // namespaces
1133  public $enclosingNamespaces;
1134  // schema info
1135  public $schemaInfo = array();
1136  public $schemaTargetNamespace = '';
1137  // types, elements, attributes defined by the schema
1138  public $attributes = array();
1139  public $complexTypes = array();
1140  public $complexTypeStack = array();
1141  public $currentComplexType = null;
1142  public $elements = array();
1143  public $elementStack = array();
1144  public $currentElement = null;
1145  public $simpleTypes = array();
1146  public $simpleTypeStack = array();
1147  public $currentSimpleType = null;
1148  // imports
1149  public $imports = array();
1150  // parser vars
1151  public $parser;
1152  public $position = 0;
1153  public $depth = 0;
1154  public $depth_array = array();
1155  public $message = array();
1156  public $defaultNamespace = array();
1157 
1166  public function __construct($schema='', $xml='', $namespaces=array())
1167  {
1169  $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1170  // files
1171  $this->schema = $schema;
1172  $this->xml = $xml;
1173 
1174  // namespaces
1175  $this->enclosingNamespaces = $namespaces;
1176  $this->namespaces = array_merge($this->namespaces, $namespaces);
1177 
1178  // parse schema file
1179  if ($schema != '') {
1180  $this->debug('initial schema file: ' . $schema);
1181  $this->parseFile($schema, 'schema');
1182  }
1183 
1184  // parse xml file
1185  if ($xml != '') {
1186  $this->debug('initial xml file: ' . $xml);
1187  $this->parseFile($xml, 'xml');
1188  }
1189  }
1190 
1199  public function parseFile($xml, $type)
1200  {
1201  // parse xml file
1202  if ($xml != "") {
1203  $xmlStr = @join("", @file($xml));
1204  if ($xmlStr == "") {
1205  $msg = 'Error reading XML from ' . $xml;
1206  $this->setError($msg);
1207  $this->debug($msg);
1208  return false;
1209  } else {
1210  $this->debug("parsing $xml");
1211  $this->parseString($xmlStr, $type);
1212  $this->debug("done parsing $xml");
1213  return true;
1214  }
1215  }
1216  return false;
1217  }
1218 
1226  public function parseString($xml, $type)
1227  {
1228  // parse xml string
1229  if ($xml != "") {
1230  // Create an XML parser.
1231  $this->parser = xml_parser_create();
1232  // Set the options for parsing the XML data.
1233  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1234 
1235  // Set the object for the parser.
1236  xml_set_object($this->parser, $this);
1237 
1238  // Set the element handlers for the parser.
1239  if ($type == "schema") {
1240  xml_set_element_handler($this->parser, 'schemaStartElement', 'schemaEndElement');
1241  xml_set_character_data_handler($this->parser, 'schemaCharacterData');
1242  } elseif ($type == "xml") {
1243  xml_set_element_handler($this->parser, 'xmlStartElement', 'xmlEndElement');
1244  xml_set_character_data_handler($this->parser, 'xmlCharacterData');
1245  }
1246 
1247  // Parse the XML file.
1248  if (!xml_parse($this->parser, $xml, true)) {
1249  // Display an error message.
1250  $errstr = sprintf(
1251  'XML error parsing XML schema on line %d: %s',
1252  xml_get_current_line_number($this->parser),
1253  xml_error_string(xml_get_error_code($this->parser))
1254  );
1255  $this->debug($errstr);
1256  $this->debug("XML payload:\n" . $xml);
1257  $this->setError($errstr);
1258  }
1259 
1260  xml_parser_free($this->parser);
1261  } else {
1262  $this->debug('no xml passed to parseString()!!');
1263  $this->setError('no xml passed to parseString()!!');
1264  }
1265  }
1266 
1274  public function CreateTypeName($ename)
1275  {
1276  $scope = '';
1277  for ($i = 0; $i < count($this->complexTypeStack); $i++) {
1278  $scope .= $this->complexTypeStack[$i] . '_';
1279  }
1280  return $scope . $ename . '_ContainedType';
1281  }
1282 
1291  public function schemaStartElement($parser, $name, $attrs)
1292  {
1293 
1294  // position in the total number of elements, starting from 0
1295  $pos = $this->position++;
1296  $depth = $this->depth++;
1297  // set self as current value for this depth
1298  $this->depth_array[$depth] = $pos;
1299  $this->message[$pos] = array('cdata' => '');
1300  if ($depth > 0) {
1301  $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1302  } else {
1303  $this->defaultNamespace[$pos] = false;
1304  }
1305 
1306  // get element prefix
1307  if ($prefix = $this->getPrefix($name)) {
1308  // get unqualified name
1309  $name = $this->getLocalPart($name);
1310  } else {
1311  $prefix = '';
1312  }
1313 
1314  // loop thru attributes, expanding, and registering namespace declarations
1315  if (count($attrs) > 0) {
1316  foreach ($attrs as $k => $v) {
1317  // if ns declarations, add to class level array of valid namespaces
1318  if (preg_match('/^xmlns/', $k)) {
1319  //$this->xdebug("$k: $v");
1320  //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1321  if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
1322  //$this->xdebug("Add namespace[$ns_prefix] = $v");
1323  $this->namespaces[$ns_prefix] = $v;
1324  } else {
1325  $this->defaultNamespace[$pos] = $v;
1326  if (! $this->getPrefixFromNamespace($v)) {
1327  $this->namespaces['ns' . (count($this->namespaces)+1)] = $v;
1328  }
1329  }
1330  if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
1331  $this->XMLSchemaVersion = $v;
1332  $this->namespaces['xsi'] = $v . '-instance';
1333  }
1334  }
1335  }
1336  foreach ($attrs as $k => $v) {
1337  // expand each attribute
1338  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
1339  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
1340  $eAttrs[$k] = $v;
1341  }
1342  $attrs = $eAttrs;
1343  } else {
1344  $attrs = array();
1345  }
1346  // find status, register data
1347  switch ($name) {
1348  case 'all': // (optional) compositor content for a complexType
1349  case 'choice':
1350  case 'group':
1351  case 'sequence':
1352  //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1353  $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1354  //if($name == 'all' || $name == 'sequence'){
1355  // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1356  //}
1357  break;
1358  case 'attribute': // complexType attribute
1359  //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1360  $this->xdebug("parsing attribute:");
1361  $this->appendDebug($this->varDump($attrs));
1362  if (!isset($attrs['form'])) {
1363  $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1364  }
1365  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1366  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1367  if (!strpos($v, ':')) {
1368  // no namespace in arrayType attribute value...
1369  if ($this->defaultNamespace[$pos]) {
1370  // ...so use the default
1371  $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1372  }
1373  }
1374  }
1375  if (isset($attrs['name'])) {
1376  $this->attributes[$attrs['name']] = $attrs;
1377  $aname = $attrs['name'];
1378  } elseif (isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType') {
1379  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1380  $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1381  } else {
1382  $aname = '';
1383  }
1384  } elseif (isset($attrs['ref'])) {
1385  $aname = $attrs['ref'];
1386  $this->attributes[$attrs['ref']] = $attrs;
1387  }
1388 
1389  if ($this->currentComplexType) { // This should *always* be
1390  $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1391  }
1392  // arrayType attribute
1393  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType') {
1394  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1395  $prefix = $this->getPrefix($aname);
1396  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1397  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1398  } else {
1399  $v = '';
1400  }
1401  if (strpos($v, '[,]')) {
1402  $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1403  }
1404  $v = substr($v, 0, strpos($v, '[')); // clip the []
1405  if (!strpos($v, ':') && isset($this->typemap[$this->XMLSchemaVersion][$v])) {
1406  $v = $this->XMLSchemaVersion . ':' . $v;
1407  }
1408  $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1409  }
1410  break;
1411  case 'complexContent': // (optional) content for a complexType
1412  break;
1413  case 'complexType':
1414  array_push($this->complexTypeStack, $this->currentComplexType);
1415  if (isset($attrs['name'])) {
1416  // TODO: what is the scope of named complexTypes that appear
1417  // nested within other c complexTypes?
1418  $this->xdebug('processing named complexType ' . $attrs['name']);
1419  //$this->currentElement = false;
1420  $this->currentComplexType = $attrs['name'];
1421  $this->complexTypes[$this->currentComplexType] = $attrs;
1422  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1423  // This is for constructs like
1424  // <complexType name="ListOfString" base="soap:Array">
1425  // <sequence>
1426  // <element name="string" type="xsd:string"
1427  // minOccurs="0" maxOccurs="unbounded" />
1428  // </sequence>
1429  // </complexType>
1430  if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
1431  $this->xdebug('complexType is unusual array');
1432  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1433  } else {
1434  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1435  }
1436  } else {
1437  $name = $this->CreateTypeName($this->currentElement);
1438  $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
1439  $this->currentComplexType = $name;
1440  //$this->currentElement = false;
1441  $this->complexTypes[$this->currentComplexType] = $attrs;
1442  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1443  // This is for constructs like
1444  // <complexType name="ListOfString" base="soap:Array">
1445  // <sequence>
1446  // <element name="string" type="xsd:string"
1447  // minOccurs="0" maxOccurs="unbounded" />
1448  // </sequence>
1449  // </complexType>
1450  if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
1451  $this->xdebug('complexType is unusual array');
1452  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1453  } else {
1454  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1455  }
1456  }
1457  break;
1458  case 'element':
1459  array_push($this->elementStack, $this->currentElement);
1460  if (!isset($attrs['form'])) {
1461  $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1462  }
1463  if (isset($attrs['type'])) {
1464  $this->xdebug("processing typed element " . $attrs['name'] . " of type " . $attrs['type']);
1465  if (! $this->getPrefix($attrs['type'])) {
1466  if ($this->defaultNamespace[$pos]) {
1467  $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1468  $this->xdebug('used default namespace to make type ' . $attrs['type']);
1469  }
1470  }
1471  // This is for constructs like
1472  // <complexType name="ListOfString" base="soap:Array">
1473  // <sequence>
1474  // <element name="string" type="xsd:string"
1475  // minOccurs="0" maxOccurs="unbounded" />
1476  // </sequence>
1477  // </complexType>
1478  if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
1479  $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1480  $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1481  }
1482  $this->currentElement = $attrs['name'];
1483  $ename = $attrs['name'];
1484  } elseif (isset($attrs['ref'])) {
1485  $this->xdebug("processing element as ref to " . $attrs['ref']);
1486  $this->currentElement = "ref to " . $attrs['ref'];
1487  $ename = $this->getLocalPart($attrs['ref']);
1488  } else {
1489  $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
1490  $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
1491  $this->currentElement = $attrs['name'];
1492  $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
1493  $ename = $attrs['name'];
1494  }
1495  if (isset($ename) && $this->currentComplexType) {
1496  $this->xdebug("add element $ename to complexType $this->currentComplexType");
1497  $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1498  } elseif (!isset($attrs['ref'])) {
1499  $this->xdebug("add element $ename to elements array");
1500  $this->elements[ $attrs['name'] ] = $attrs;
1501  $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1502  }
1503  break;
1504  case 'enumeration': // restriction value list member
1505  $this->xdebug('enumeration ' . $attrs['value']);
1506  if ($this->currentSimpleType) {
1507  $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1508  } elseif ($this->currentComplexType) {
1509  $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1510  }
1511  break;
1512  case 'extension': // simpleContent or complexContent type extension
1513  $this->xdebug('extension ' . $attrs['base']);
1514  if ($this->currentComplexType) {
1515  $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1516  }
1517  break;
1518  case 'import':
1519  if (isset($attrs['schemaLocation'])) {
1520  //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1521  $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1522  } else {
1523  //$this->xdebug('import namespace ' . $attrs['namespace']);
1524  $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1525  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
1526  $this->namespaces['ns' . (count($this->namespaces)+1)] = $attrs['namespace'];
1527  }
1528  }
1529  break;
1530  case 'list': // simpleType value list
1531  break;
1532  case 'restriction': // simpleType, simpleContent or complexContent value restriction
1533  $this->xdebug('restriction ' . $attrs['base']);
1534  if ($this->currentSimpleType) {
1535  $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1536  } elseif ($this->currentComplexType) {
1537  $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1538  if (strstr($attrs['base'], ':') == ':Array') {
1539  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1540  }
1541  }
1542  break;
1543  case 'schema':
1544  $this->schemaInfo = $attrs;
1545  $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1546  if (isset($attrs['targetNamespace'])) {
1547  $this->schemaTargetNamespace = $attrs['targetNamespace'];
1548  }
1549  if (!isset($attrs['elementFormDefault'])) {
1550  $this->schemaInfo['elementFormDefault'] = 'unqualified';
1551  }
1552  if (!isset($attrs['attributeFormDefault'])) {
1553  $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1554  }
1555  break;
1556  case 'simpleContent': // (optional) content for a complexType
1557  break;
1558  case 'simpleType':
1559  array_push($this->simpleTypeStack, $this->currentSimpleType);
1560  if (isset($attrs['name'])) {
1561  $this->xdebug("processing simpleType for name " . $attrs['name']);
1562  $this->currentSimpleType = $attrs['name'];
1563  $this->simpleTypes[ $attrs['name'] ] = $attrs;
1564  $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1565  $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1566  } else {
1567  $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
1568  $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
1569  $this->currentSimpleType = $name;
1570  //$this->currentElement = false;
1571  $this->simpleTypes[$this->currentSimpleType] = $attrs;
1572  $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1573  }
1574  break;
1575  case 'union': // simpleType type list
1576  break;
1577  default:
1578  //$this->xdebug("do not have anything to do for element $name");
1579  }
1580  }
1581 
1589  public function schemaEndElement($parser, $name)
1590  {
1591  // bring depth down a notch
1592  $this->depth--;
1593  // position of current element is equal to the last value left in depth_array for my depth
1594  if (isset($this->depth_array[$this->depth])) {
1595  $pos = $this->depth_array[$this->depth];
1596  }
1597  // get element prefix
1598  if ($prefix = $this->getPrefix($name)) {
1599  // get unqualified name
1600  $name = $this->getLocalPart($name);
1601  } else {
1602  $prefix = '';
1603  }
1604  // move on...
1605  if ($name == 'complexType') {
1606  $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
1607  $this->currentComplexType = array_pop($this->complexTypeStack);
1608  //$this->currentElement = false;
1609  }
1610  if ($name == 'element') {
1611  $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
1612  $this->currentElement = array_pop($this->elementStack);
1613  }
1614  if ($name == 'simpleType') {
1615  $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
1616  $this->currentSimpleType = array_pop($this->simpleTypeStack);
1617  }
1618  }
1619 
1627  public function schemaCharacterData($parser, $data)
1628  {
1629  $pos = $this->depth_array[$this->depth - 1];
1630  $this->message[$pos]['cdata'] .= $data;
1631  }
1632 
1638  public function serializeSchema()
1639  {
1640  $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1641  $xml = '';
1642  // imports
1643  if (sizeof($this->imports) > 0) {
1644  foreach ($this->imports as $ns => $list) {
1645  foreach ($list as $ii) {
1646  if ($ii['location'] != '') {
1647  $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1648  } else {
1649  $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1650  }
1651  }
1652  }
1653  }
1654  // complex types
1655  foreach ($this->complexTypes as $typeName => $attrs) {
1656  $contentStr = '';
1657  // serialize child elements
1658  if (isset($attrs['elements']) && (count($attrs['elements']) > 0)) {
1659  foreach ($attrs['elements'] as $element => $eParts) {
1660  if (isset($eParts['ref'])) {
1661  $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
1662  } else {
1663  $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
1664  foreach ($eParts as $aName => $aValue) {
1665  // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1666  if ($aName != 'name' && $aName != 'type') {
1667  $contentStr .= " $aName=\"$aValue\"";
1668  }
1669  }
1670  $contentStr .= "/>\n";
1671  }
1672  }
1673  // compositor wraps elements
1674  if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
1675  $contentStr = " <$schemaPrefix:$attrs[compositor]>\n" . $contentStr . " </$schemaPrefix:$attrs[compositor]>\n";
1676  }
1677  }
1678  // attributes
1679  if (isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)) {
1680  foreach ($attrs['attrs'] as $attr => $aParts) {
1681  $contentStr .= " <$schemaPrefix:attribute";
1682  foreach ($aParts as $a => $v) {
1683  if ($a == 'ref' || $a == 'type') {
1684  $contentStr .= " $a=\"" . $this->contractQName($v) . '"';
1685  } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
1686  $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1687  $contentStr .= ' wsdl:arrayType="' . $this->contractQName($v) . '"';
1688  } else {
1689  $contentStr .= " $a=\"$v\"";
1690  }
1691  }
1692  $contentStr .= "/>\n";
1693  }
1694  }
1695  // if restriction
1696  if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != '') {
1697  $contentStr = " <$schemaPrefix:restriction base=\"" . $this->contractQName($attrs['restrictionBase']) . "\">\n" . $contentStr . " </$schemaPrefix:restriction>\n";
1698  // complex or simple content
1699  if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)) {
1700  $contentStr = " <$schemaPrefix:complexContent>\n" . $contentStr . " </$schemaPrefix:complexContent>\n";
1701  }
1702  }
1703  // finalize complex type
1704  if ($contentStr != '') {
1705  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n" . $contentStr . " </$schemaPrefix:complexType>\n";
1706  } else {
1707  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1708  }
1709  $xml .= $contentStr;
1710  }
1711  // simple types
1712  if (isset($this->simpleTypes) && count($this->simpleTypes) > 0) {
1713  foreach ($this->simpleTypes as $typeName => $eParts) {
1714  $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"" . $this->contractQName($eParts['type']) . "\">\n";
1715  if (isset($eParts['enumeration'])) {
1716  foreach ($eParts['enumeration'] as $e) {
1717  $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
1718  }
1719  }
1720  $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
1721  }
1722  }
1723  // elements
1724  if (isset($this->elements) && count($this->elements) > 0) {
1725  foreach ($this->elements as $element => $eParts) {
1726  $xml .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"/>\n";
1727  }
1728  }
1729  // attributes
1730  if (isset($this->attributes) && count($this->attributes) > 0) {
1731  foreach ($this->attributes as $attr => $aParts) {
1732  $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"" . $this->contractQName($aParts['type']) . "\"\n/>";
1733  }
1734  }
1735  // finish 'er up
1736  $attr = '';
1737  foreach ($this->schemaInfo as $k => $v) {
1738  if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
1739  $attr .= " $k=\"$v\"";
1740  }
1741  }
1742  $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
1743  foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1744  $el .= " xmlns:$nsp=\"$ns\"";
1745  }
1746  $xml = $el . ">\n" . $xml . "</$schemaPrefix:schema>\n";
1747  return $xml;
1748  }
1749 
1756  public function xdebug($string)
1757  {
1758  $this->debug('<' . $this->schemaTargetNamespace . '> ' . $string);
1759  }
1760 
1773  public function getPHPType($type, $ns)
1774  {
1775  if (isset($this->typemap[$ns][$type])) {
1776  //print "found type '$type' and ns $ns in typemap<br>";
1777  return $this->typemap[$ns][$type];
1778  } elseif (isset($this->complexTypes[$type])) {
1779  //print "getting type '$type' and ns $ns from complexTypes array<br>";
1780  return $this->complexTypes[$type]['phpType'];
1781  }
1782  return false;
1783  }
1784 
1807  public function getTypeDef($type)
1808  {
1809  //$this->debug("in getTypeDef for type $type");
1810  if (substr($type, -1) == '^') {
1811  $is_element = 1;
1812  $type = substr($type, 0, -1);
1813  } else {
1814  $is_element = 0;
1815  }
1816 
1817  if ((! $is_element) && isset($this->complexTypes[$type])) {
1818  $this->xdebug("in getTypeDef, found complexType $type");
1819  return $this->complexTypes[$type];
1820  } elseif ((! $is_element) && isset($this->simpleTypes[$type])) {
1821  $this->xdebug("in getTypeDef, found simpleType $type");
1822  if (!isset($this->simpleTypes[$type]['phpType'])) {
1823  // get info for type to tack onto the simple type
1824  // TODO: can this ever really apply (i.e. what is a simpleType really?)
1825  $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1826  $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1827  $etype = $this->getTypeDef($uqType);
1828  if ($etype) {
1829  $this->xdebug("in getTypeDef, found type for simpleType $type:");
1830  $this->xdebug($this->varDump($etype));
1831  if (isset($etype['phpType'])) {
1832  $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1833  }
1834  if (isset($etype['elements'])) {
1835  $this->simpleTypes[$type]['elements'] = $etype['elements'];
1836  }
1837  }
1838  }
1839  return $this->simpleTypes[$type];
1840  } elseif (isset($this->elements[$type])) {
1841  $this->xdebug("in getTypeDef, found element $type");
1842  if (!isset($this->elements[$type]['phpType'])) {
1843  // get info for type to tack onto the element
1844  $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1845  $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1846  $etype = $this->getTypeDef($uqType);
1847  if ($etype) {
1848  $this->xdebug("in getTypeDef, found type for element $type:");
1849  $this->xdebug($this->varDump($etype));
1850  if (isset($etype['phpType'])) {
1851  $this->elements[$type]['phpType'] = $etype['phpType'];
1852  }
1853  if (isset($etype['elements'])) {
1854  $this->elements[$type]['elements'] = $etype['elements'];
1855  }
1856  } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
1857  $this->xdebug("in getTypeDef, element $type is an XSD type");
1858  $this->elements[$type]['phpType'] = 'scalar';
1859  }
1860  }
1861  return $this->elements[$type];
1862  } elseif (isset($this->attributes[$type])) {
1863  $this->xdebug("in getTypeDef, found attribute $type");
1864  return $this->attributes[$type];
1865  } elseif (preg_match('/_ContainedType$/', $type)) {
1866  $this->xdebug("in getTypeDef, have an untyped element $type");
1867  $typeDef['typeClass'] = 'simpleType';
1868  $typeDef['phpType'] = 'scalar';
1869  $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
1870  return $typeDef;
1871  }
1872  $this->xdebug("in getTypeDef, did not find $type");
1873  return false;
1874  }
1875 
1884  public function serializeTypeDef($type)
1885  {
1886  //print "in sTD() for type $type<br>";
1887  if ($typeDef = $this->getTypeDef($type)) {
1888  $str .= '<' . $type;
1889  if (is_array($typeDef['attrs'])) {
1890  foreach ($typeDef['attrs'] as $attName => $data) {
1891  $str .= " $attName=\"{type = " . $data['type'] . "}\"";
1892  }
1893  }
1894  $str .= " xmlns=\"" . $this->schema['targetNamespace'] . "\"";
1895  if (count($typeDef['elements']) > 0) {
1896  $str .= ">";
1897  foreach ($typeDef['elements'] as $element => $eData) {
1898  $str .= $this->serializeTypeDef($element);
1899  }
1900  $str .= "</$type>";
1901  } elseif ($typeDef['typeClass'] == 'element') {
1902  $str .= "></$type>";
1903  } else {
1904  $str .= "/>";
1905  }
1906  return $str;
1907  }
1908  return false;
1909  }
1910 
1921  public function typeToForm($name, $type)
1922  {
1923  // get typedef
1924  if ($typeDef = $this->getTypeDef($type)) {
1925  // if struct
1926  if ($typeDef['phpType'] == 'struct') {
1927  $buffer .= '<table>';
1928  foreach ($typeDef['elements'] as $child => $childDef) {
1929  $buffer .= "
1930  <tr><td align='right'>$childDef[name] (type: " . $this->getLocalPart($childDef['type']) . "):</td>
1931  <td><input type='text' name='parameters[" . $name . "][$childDef[name]]'></td></tr>";
1932  }
1933  $buffer .= '</table>';
1934  // if array
1935  } elseif ($typeDef['phpType'] == 'array') {
1936  $buffer .= '<table>';
1937  for ($i=0;$i < 3; $i++) {
1938  $buffer .= "
1939  <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1940  <td><input type='text' name='parameters[" . $name . "][]'></td></tr>";
1941  }
1942  $buffer .= '</table>';
1943  // if scalar
1944  } else {
1945  $buffer .= "<input type='text' name='parameters[$name]'>";
1946  }
1947  } else {
1948  $buffer .= "<input type='text' name='parameters[$name]'>";
1949  }
1950  return $buffer;
1951  }
1952 
1994  public function addComplexType($name, $typeClass='complexType', $phpType='array', $compositor='', $restrictionBase='', $elements=array(), $attrs=array(), $arrayType='')
1995  {
1996  $this->complexTypes[$name] = array(
1997  'name' => $name,
1998  'typeClass' => $typeClass,
1999  'phpType' => $phpType,
2000  'compositor'=> $compositor,
2001  'restrictionBase' => $restrictionBase,
2002  'elements' => $elements,
2003  'attrs' => $attrs,
2004  'arrayType' => $arrayType
2005  );
2006 
2007  $this->xdebug("addComplexType $name:");
2008  $this->appendDebug($this->varDump($this->complexTypes[$name]));
2009  }
2010 
2023  public function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array())
2024  {
2025  $this->simpleTypes[$name] = array(
2026  'name' => $name,
2027  'typeClass' => $typeClass,
2028  'phpType' => $phpType,
2029  'type' => $restrictionBase,
2030  'enumeration' => $enumeration
2031  );
2032 
2033  $this->xdebug("addSimpleType $name:");
2034  $this->appendDebug($this->varDump($this->simpleTypes[$name]));
2035  }
2036 
2044  public function addElement($attrs)
2045  {
2046  if (! $this->getPrefix($attrs['type'])) {
2047  $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
2048  }
2049  $this->elements[ $attrs['name'] ] = $attrs;
2050  $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
2051 
2052  $this->xdebug("addElement " . $attrs['name']);
2053  $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
2054  }
2055 }
2056 
2060 class XMLSchema extends nusoap_xmlschema
2061 {
2062 }
2063 
2064 ?><?php
2065 
2066 
2067 
2079 class soapval extends nusoap_base
2080 {
2087  public $name;
2094  public $type;
2101  public $value;
2108  public $element_ns;
2115  public $type_ns;
2122  public $attributes;
2123 
2135  public function __construct($name='soapval', $type=false, $value=-1, $element_ns=false, $type_ns=false, $attributes=false)
2136  {
2138  $this->name = $name;
2139  $this->type = $type;
2140  $this->value = $value;
2141  $this->element_ns = $element_ns;
2142  $this->type_ns = $type_ns;
2143  $this->attributes = $attributes;
2144  }
2145 
2153  public function serialize($use='encoded')
2154  {
2155  return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2156  }
2157 
2164  public function decode()
2165  {
2166  return $this->value;
2167  }
2168 }
2169 
2170 
2171 
2172 ?><?php
2173 
2174 
2175 
2185 class soap_transport_http extends nusoap_base
2186 {
2187  public $url = '';
2188  public $uri = '';
2189  public $digest_uri = '';
2190  public $scheme = '';
2191  public $host = '';
2192  public $port = '';
2193  public $path = '';
2194  public $request_method = 'POST';
2195  public $protocol_version = '1.0';
2196  public $encoding = '';
2197  public $outgoing_headers = array();
2198  public $incoming_headers = array();
2199  public $incoming_cookies = array();
2200  public $outgoing_payload = '';
2201  public $incoming_payload = '';
2202  public $response_status_line; // HTTP response status line
2203  public $useSOAPAction = true;
2204  public $persistentConnection = false;
2205  public $ch = false; // cURL handle
2206  public $ch_options = array(); // cURL custom options
2207  public $use_curl = false; // force cURL use
2208  public $proxy = null; // proxy information (associative array)
2209  public $username = '';
2210  public $password = '';
2211  public $authtype = '';
2212  public $digestRequest = array();
2213  public $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
2214  // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2215  // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2216  // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2217  // passphrase: SSL key password/passphrase
2218  // certpassword: SSL certificate password
2219  // verifypeer: default is 1
2220  // verifyhost: default is 1
2221 
2230  public function __construct($url, $curl_options = null, $use_curl = false)
2231  {
2233  $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
2234  $this->appendDebug($this->varDump($curl_options));
2235  $this->setURL($url);
2236  if (is_array($curl_options)) {
2237  $this->ch_options = $curl_options;
2238  }
2239  $this->use_curl = $use_curl;
2240  preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
2241  // begin-patch php8
2242  $this->setHeader('User-Agent', $this->title . '/' . $this->version . ' (' . ($rev[1] ?? '1.1') . ')');
2243  }
2244 
2252  public function setCurlOption($option, $value)
2253  {
2254  $this->debug("setCurlOption option=$option, value=");
2255  $this->appendDebug($this->varDump($value));
2256  curl_setopt($this->ch, $option, $value);
2257  }
2258 
2266  public function setHeader($name, $value)
2267  {
2268  $this->outgoing_headers[$name] = $value;
2269  $this->debug("set header $name: $value");
2270  }
2271 
2278  public function unsetHeader($name)
2279  {
2280  if (isset($this->outgoing_headers[$name])) {
2281  $this->debug("unset header $name");
2282  unset($this->outgoing_headers[$name]);
2283  }
2284  }
2285 
2292  public function setURL($url)
2293  {
2294  $this->url = $url;
2295 
2296  $u = parse_url($url);
2297  foreach ($u as $k => $v) {
2298  $this->debug("parsed URL $k = $v");
2299  $this->$k = $v;
2300  }
2301 
2302  // add any GET params to path
2303  if (isset($u['query']) && $u['query'] != '') {
2304  $this->path .= '?' . $u['query'];
2305  }
2306 
2307  // set default port
2308  if (!isset($u['port'])) {
2309  if ($u['scheme'] == 'https') {
2310  $this->port = 443;
2311  } else {
2312  $this->port = 80;
2313  }
2314  }
2315 
2316  $this->uri = $this->path;
2317  $this->digest_uri = $this->uri;
2318 
2319  // build headers
2320  if (!isset($u['port'])) {
2321  $this->setHeader('Host', $this->host);
2322  } else {
2323  $this->setHeader('Host', $this->host . ':' . $this->port);
2324  }
2325 
2326  if (isset($u['user']) && $u['user'] != '') {
2327  $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2328  }
2329  }
2330 
2337  public function io_method()
2338  {
2339  if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) {
2340  return 'curl';
2341  }
2342  if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) {
2343  return 'socket';
2344  }
2345  return 'unknown';
2346  }
2347 
2356  public function connect($connection_timeout=0, $response_timeout=30)
2357  {
2358  // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2359  // "regular" socket.
2360  // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2361  // loaded), and until PHP5 stream_get_wrappers is not available.
2362  // if ($this->scheme == 'https') {
2363  // if (version_compare(phpversion(), '4.3.0') >= 0) {
2364  // if (extension_loaded('openssl')) {
2365  // $this->scheme = 'ssl';
2366  // $this->debug('Using SSL over OpenSSL');
2367  // }
2368  // }
2369  // }
2370  $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2371  if ($this->io_method() == 'socket') {
2372  if (!is_array($this->proxy)) {
2373  $host = $this->host;
2374  $port = $this->port;
2375  } else {
2376  $host = $this->proxy['host'];
2377  $port = $this->proxy['port'];
2378  }
2379 
2380  // use persistent connection
2381  if ($this->persistentConnection && isset($this->fp) && is_resource($this->fp)) {
2382  if (!feof($this->fp)) {
2383  $this->debug('Re-use persistent connection');
2384  return true;
2385  }
2386  fclose($this->fp);
2387  $this->debug('Closed persistent connection at EOF');
2388  }
2389 
2390  // munge host if using OpenSSL
2391  if ($this->scheme == 'ssl') {
2392  $host = 'ssl://' . $host;
2393  }
2394  $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2395 
2396  // open socket
2397  if ($connection_timeout > 0) {
2398  $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str, $connection_timeout);
2399  } else {
2400  $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str);
2401  }
2402 
2403  // test pointer
2404  if (!$this->fp) {
2405  $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2406  if ($this->errno) {
2407  $msg .= ', Error (' . $this->errno . '): ' . $this->error_str;
2408  } else {
2409  $msg .= ' prior to connect(). This is often a problem looking up the host name.';
2410  }
2411  $this->debug($msg);
2412  $this->setError($msg);
2413  return false;
2414  }
2415 
2416  // set response timeout
2417  $this->debug('set response timeout to ' . $response_timeout);
2418  socket_set_timeout($this->fp, $response_timeout);
2419 
2420  $this->debug('socket connected');
2421  return true;
2422  } elseif ($this->io_method() == 'curl') {
2423  if (!extension_loaded('curl')) {
2424  // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
2425  $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.');
2426  return false;
2427  }
2428  // Avoid warnings when PHP does not have these options
2429  if (defined('CURLOPT_CONNECTIONTIMEOUT')) {
2430  $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
2431  } else {
2432  $CURLOPT_CONNECTIONTIMEOUT = 78;
2433  }
2434  if (defined('CURLOPT_HTTPAUTH')) {
2435  $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
2436  } else {
2437  $CURLOPT_HTTPAUTH = 107;
2438  }
2439  if (defined('CURLOPT_PROXYAUTH')) {
2440  $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
2441  } else {
2442  $CURLOPT_PROXYAUTH = 111;
2443  }
2444  if (defined('CURLAUTH_BASIC')) {
2445  $CURLAUTH_BASIC = CURLAUTH_BASIC;
2446  } else {
2447  $CURLAUTH_BASIC = 1;
2448  }
2449  if (defined('CURLAUTH_DIGEST')) {
2450  $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
2451  } else {
2452  $CURLAUTH_DIGEST = 2;
2453  }
2454  if (defined('CURLAUTH_NTLM')) {
2455  $CURLAUTH_NTLM = CURLAUTH_NTLM;
2456  } else {
2457  $CURLAUTH_NTLM = 8;
2458  }
2459 
2460  $this->debug('connect using cURL');
2461  // init CURL
2462  $this->ch = curl_init();
2463  // set url
2464  $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
2465  // add path
2466  $hostURL .= $this->path;
2467  $this->setCurlOption(CURLOPT_URL, $hostURL);
2468  // follow location headers (re-directs)
2469  if (ini_get('safe_mode') || ini_get('open_basedir')) {
2470  $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
2471  $this->debug('safe_mode = ');
2472  $this->appendDebug($this->varDump(ini_get('safe_mode')));
2473  $this->debug('open_basedir = ');
2474  $this->appendDebug($this->varDump(ini_get('open_basedir')));
2475  } else {
2476  $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
2477  }
2478  // ask for headers in the response output
2479  $this->setCurlOption(CURLOPT_HEADER, 1);
2480  // ask for the response output as the return value
2481  $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
2482  // encode
2483  // We manage this ourselves through headers and encoding
2484  // if(function_exists('gzuncompress')){
2485  // $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
2486  // }
2487  // persistent connection
2488  if ($this->persistentConnection) {
2489  // I believe the following comment is now bogus, having applied to
2490  // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
2491  // The way we send data, we cannot use persistent connections, since
2492  // there will be some "junk" at the end of our request.
2493  //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
2494  $this->persistentConnection = false;
2495  $this->setHeader('Connection', 'close');
2496  }
2497  // set timeouts
2498  if ($connection_timeout != 0) {
2499  $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2500  }
2501  if ($response_timeout != 0) {
2502  $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
2503  }
2504 
2505  if ($this->scheme == 'https') {
2506  $this->debug('set cURL SSL verify options');
2507  // recent versions of cURL turn on peer/host checking by default,
2508  // while PHP binaries are not compiled with a default location for the
2509  // CA cert bundle, so disable peer/host checking.
2510  //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
2511  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
2512  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
2513 
2514  // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2515  if ($this->authtype == 'certificate') {
2516  $this->debug('set cURL certificate options');
2517  if (isset($this->certRequest['cainfofile'])) {
2518  $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2519  }
2520  if (isset($this->certRequest['verifypeer'])) {
2521  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2522  } else {
2523  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
2524  }
2525  if (isset($this->certRequest['verifyhost'])) {
2526  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2527  } else {
2528  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
2529  }
2530  if (isset($this->certRequest['sslcertfile'])) {
2531  $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2532  }
2533  if (isset($this->certRequest['sslkeyfile'])) {
2534  $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2535  }
2536  if (isset($this->certRequest['passphrase'])) {
2537  $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
2538  }
2539  if (isset($this->certRequest['certpassword'])) {
2540  $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
2541  }
2542  }
2543  }
2544  if ($this->authtype && ($this->authtype != 'certificate')) {
2545  if ($this->username) {
2546  $this->debug('set cURL username/password');
2547  $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
2548  }
2549  if ($this->authtype == 'basic') {
2550  $this->debug('set cURL for Basic authentication');
2551  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
2552  }
2553  if ($this->authtype == 'digest') {
2554  $this->debug('set cURL for digest authentication');
2555  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
2556  }
2557  if ($this->authtype == 'ntlm') {
2558  $this->debug('set cURL for NTLM authentication');
2559  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
2560  }
2561  }
2562  if (is_array($this->proxy)) {
2563  $this->debug('set cURL proxy options');
2564  if ($this->proxy['port'] != '') {
2565  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'] . ':' . $this->proxy['port']);
2566  } else {
2567  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
2568  }
2569  if ($this->proxy['username'] || $this->proxy['password']) {
2570  $this->debug('set cURL proxy authentication options');
2571  $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'] . ':' . $this->proxy['password']);
2572  if ($this->proxy['authtype'] == 'basic') {
2573  $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
2574  }
2575  if ($this->proxy['authtype'] == 'ntlm') {
2576  $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
2577  }
2578  }
2579  }
2580  $this->debug('cURL connection set up');
2581  return true;
2582  } else {
2583  $this->setError('Unknown scheme ' . $this->scheme);
2584  $this->debug('Unknown scheme ' . $this->scheme);
2585  return false;
2586  }
2587  }
2588 
2599  public function send($data, $timeout=0, $response_timeout=30, $cookies=null)
2600  {
2601  $this->debug('entered send() with data of length: ' . strlen($data));
2602 
2603  $this->tryagain = true;
2604  $tries = 0;
2605  while ($this->tryagain) {
2606  $this->tryagain = false;
2607  if ($tries++ < 2) {
2608  // make connnection
2609  if (!$this->connect($timeout, $response_timeout)) {
2610  return false;
2611  }
2612 
2613  // send request
2614  if (!$this->sendRequest($data, $cookies)) {
2615  return false;
2616  }
2617 
2618  // get response
2619  $respdata = $this->getResponse();
2620  } else {
2621  $this->setError("Too many tries to get an OK response ($this->response_status_line)");
2622  }
2623  }
2624  $this->debug('end of send()');
2625  return $respdata;
2626  }
2627 
2628 
2640  public function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies=null)
2641  {
2642  return $this->send($data, $timeout, $response_timeout, $cookies);
2643  }
2644 
2655  public function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array())
2656  {
2657  $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
2658  $this->appendDebug($this->varDump($digestRequest));
2659  $this->debug("certRequest=");
2660  $this->appendDebug($this->varDump($certRequest));
2661  // cf. RFC 2617
2662  if ($authtype == 'basic') {
2663  $this->setHeader('Authorization', 'Basic ' . base64_encode(str_replace(':', '', $username) . ':' . $password));
2664  } elseif ($authtype == 'digest') {
2665  if (isset($digestRequest['nonce'])) {
2666  $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2667 
2668  // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2669 
2670  // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2671  $A1 = $username . ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
2672 
2673  // H(A1) = MD5(A1)
2674  $HA1 = md5($A1);
2675 
2676  // A2 = Method ":" digest-uri-value
2677  $A2 = $this->request_method . ':' . $this->digest_uri;
2678 
2679  // H(A2)
2680  $HA2 = md5($A2);
2681 
2682  // KD(secret, data) = H(concat(secret, ":", data))
2683  // if qop == auth:
2684  // request-digest = <"> < KD ( H(A1), unq(nonce-value)
2685  // ":" nc-value
2686  // ":" unq(cnonce-value)
2687  // ":" unq(qop-value)
2688  // ":" H(A2)
2689  // ) <">
2690  // if qop is missing,
2691  // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2692 
2693  $unhashedDigest = '';
2694  $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
2695  $cnonce = $nonce;
2696  if ($digestRequest['qop'] != '') {
2697  $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2698  } else {
2699  $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2700  }
2701 
2702  $hashedDigest = md5($unhashedDigest);
2703 
2704  $opaque = '';
2705  if (isset($digestRequest['opaque'])) {
2706  $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
2707  }
2708 
2709  $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 . '"');
2710  }
2711  } elseif ($authtype == 'certificate') {
2712  $this->certRequest = $certRequest;
2713  $this->debug('Authorization header not set for certificate');
2714  } elseif ($authtype == 'ntlm') {
2715  // do nothing
2716  $this->debug('Authorization header not set for ntlm');
2717  }
2718  $this->username = $username;
2719  $this->password = $password;
2720  $this->authtype = $authtype;
2721  $this->digestRequest = $digestRequest;
2722  }
2723 
2730  public function setSOAPAction($soapaction)
2731  {
2732  $this->setHeader('SOAPAction', '"' . $soapaction . '"');
2733  }
2734 
2741  public function setEncoding($enc='gzip, deflate')
2742  {
2743  if (function_exists('gzdeflate')) {
2744  $this->protocol_version = '1.1';
2745  $this->setHeader('Accept-Encoding', $enc);
2746  if (!isset($this->outgoing_headers['Connection'])) {
2747  $this->setHeader('Connection', 'close');
2748  $this->persistentConnection = false;
2749  }
2750  #set_magic_quotes_runtime(0);
2751  // deprecated
2752  $this->encoding = $enc;
2753  }
2754  }
2755 
2766  public function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic')
2767  {
2768  if ($proxyhost) {
2769  $this->proxy = array(
2770  'host' => $proxyhost,
2771  'port' => $proxyport,
2772  'username' => $proxyusername,
2773  'password' => $proxypassword,
2774  'authtype' => $proxyauthtype
2775  );
2776  if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
2777  $this->setHeader('Proxy-Authorization', ' Basic ' . base64_encode($proxyusername . ':' . $proxypassword));
2778  }
2779  } else {
2780  $this->debug('remove proxy');
2781  $proxy = null;
2782  unsetHeader('Proxy-Authorization');
2783  }
2784  }
2785 
2786 
2795  public function isSkippableCurlHeader(&$data)
2796  {
2797  $skipHeaders = array( 'HTTP/1.1 100',
2798  'HTTP/1.0 301',
2799  'HTTP/1.1 301',
2800  'HTTP/1.0 302',
2801  'HTTP/1.1 302',
2802  'HTTP/1.0 401',
2803  'HTTP/1.1 401',
2804  'HTTP/1.0 200 Connection established');
2805  foreach ($skipHeaders as $hd) {
2806  $prefix = substr($data, 0, strlen($hd));
2807  if ($prefix == $hd) {
2808  return true;
2809  }
2810  }
2811 
2812  return false;
2813  }
2814 
2825  public function decodeChunked($buffer, $lb)
2826  {
2827  // length := 0
2828  $length = 0;
2829  $new = '';
2830 
2831  // read chunk-size, chunk-extension (if any) and CRLF
2832  // get the position of the linebreak
2833  $chunkend = strpos($buffer, $lb);
2834  if ($chunkend == false) {
2835  $this->debug('no linebreak found in decodeChunked');
2836  return $new;
2837  }
2838  $temp = substr($buffer, 0, $chunkend);
2839  $chunk_size = hexdec(trim($temp));
2840  $chunkstart = $chunkend + strlen($lb);
2841  // while (chunk-size > 0) {
2842  while ($chunk_size > 0) {
2843  $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
2844  $chunkend = strpos($buffer, $lb, $chunkstart + $chunk_size);
2845 
2846  // Just in case we got a broken connection
2847  if ($chunkend == false) {
2848  $chunk = substr($buffer, $chunkstart);
2849  // append chunk-data to entity-body
2850  $new .= $chunk;
2851  $length += strlen($chunk);
2852  break;
2853  }
2854 
2855  // read chunk-data and CRLF
2856  $chunk = substr($buffer, $chunkstart, $chunkend-$chunkstart);
2857  // append chunk-data to entity-body
2858  $new .= $chunk;
2859  // length := length + chunk-size
2860  $length += strlen($chunk);
2861  // read chunk-size and CRLF
2862  $chunkstart = $chunkend + strlen($lb);
2863 
2864  $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
2865  if ($chunkend == false) {
2866  break; //Just in case we got a broken connection
2867  }
2868  $temp = substr($buffer, $chunkstart, $chunkend-$chunkstart);
2869  $chunk_size = hexdec(trim($temp));
2870  $chunkstart = $chunkend;
2871  }
2872  return $new;
2873  }
2874 
2883  public function buildPayload($data, $cookie_str = '')
2884  {
2885  // Note: for cURL connections, $this->outgoing_payload is ignored,
2886  // as is the Content-Length header, but these are still created as
2887  // debugging guides.
2888 
2889  // add content-length header
2890  $this->setHeader('Content-Length', strlen($data));
2891 
2892  // start building outgoing payload:
2893  if ($this->proxy) {
2894  $uri = $this->url;
2895  } else {
2896  $uri = $this->uri;
2897  }
2898  $req = "$this->request_method $uri HTTP/$this->protocol_version";
2899  $this->debug("HTTP request: $req");
2900  $this->outgoing_payload = "$req\r\n";
2901 
2902  // loop thru headers, serializing
2903  foreach ($this->outgoing_headers as $k => $v) {
2904  $hdr = $k . ': ' . $v;
2905  $this->debug("HTTP header: $hdr");
2906  $this->outgoing_payload .= "$hdr\r\n";
2907  }
2908 
2909  // add any cookies
2910  if ($cookie_str != '') {
2911  $hdr = 'Cookie: ' . $cookie_str;
2912  $this->debug("HTTP header: $hdr");
2913  $this->outgoing_payload .= "$hdr\r\n";
2914  }
2915 
2916  // header/body separator
2917  $this->outgoing_payload .= "\r\n";
2918 
2919  // add data
2920  $this->outgoing_payload .= $data;
2921  }
2922 
2931  public function sendRequest($data, $cookies = null)
2932  {
2933  // build cookie string
2934  $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
2935 
2936  // build payload
2937  $this->buildPayload($data, $cookie_str);
2938 
2939  if ($this->io_method() == 'socket') {
2940  // send payload
2941  if (!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
2942  $this->setError('couldn\'t write message data to socket');
2943  $this->debug('couldn\'t write message data to socket');
2944  return false;
2945  }
2946  $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
2947  return true;
2948  } elseif ($this->io_method() == 'curl') {
2949  // set payload
2950  // cURL does say this should only be the verb, and in fact it
2951  // turns out that the URI and HTTP version are appended to this, which
2952  // some servers refuse to work with (so we no longer use this method!)
2953  //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
2954  $curl_headers = array();
2955  foreach ($this->outgoing_headers as $k => $v) {
2956  if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
2957  $this->debug("Skip cURL header $k: $v");
2958  } else {
2959  $curl_headers[] = "$k: $v";
2960  }
2961  }
2962  if ($cookie_str != '') {
2963  $curl_headers[] = 'Cookie: ' . $cookie_str;
2964  }
2965  $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
2966  $this->debug('set cURL HTTP headers');
2967  if ($this->request_method == "POST") {
2968  $this->setCurlOption(CURLOPT_POST, 1);
2969  $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
2970  $this->debug('set cURL POST data');
2971  } else {
2972  }
2973  // insert custom user-set cURL options
2974  foreach ($this->ch_options as $key => $val) {
2975  $this->setCurlOption($key, $val);
2976  }
2977 
2978  $this->debug('set cURL payload');
2979  return true;
2980  }
2981  }
2982 
2989  public function getResponse()
2990  {
2991  $this->incoming_payload = '';
2992 
2993  if ($this->io_method() == 'socket') {
2994  // loop until headers have been retrieved
2995  $data = '';
2996  while (!isset($lb)) {
2997  // We might EOF during header read.
2998  if (feof($this->fp)) {
2999  $this->incoming_payload = $data;
3000  $this->debug('found no headers before EOF after length ' . strlen($data));
3001  $this->debug("received before EOF:\n" . $data);
3002  $this->setError('server failed to send headers');
3003  return false;
3004  }
3005 
3006  $tmp = fgets($this->fp, 256);
3007  $tmplen = strlen($tmp);
3008  $this->debug("read line of $tmplen bytes: " . trim($tmp));
3009 
3010  if ($tmplen == 0) {
3011  $this->incoming_payload = $data;
3012  $this->debug('socket read of headers timed out after length ' . strlen($data));
3013  $this->debug("read before timeout: " . $data);
3014  $this->setError('socket read of headers timed out');
3015  return false;
3016  }
3017 
3018  $data .= $tmp;
3019  $pos = strpos($data, "\r\n\r\n");
3020  if ($pos > 1) {
3021  $lb = "\r\n";
3022  } else {
3023  $pos = strpos($data, "\n\n");
3024  if ($pos > 1) {
3025  $lb = "\n";
3026  }
3027  }
3028  // remove 100 headers
3029  if (isset($lb) && preg_match('/^HTTP\/1.1 100/', $data)) {
3030  unset($lb);
3031  $data = '';
3032  }//
3033  }
3034  // store header data
3035  $this->incoming_payload .= $data;
3036  $this->debug('found end of headers after length ' . strlen($data));
3037  // process headers
3038  $header_data = trim(substr($data, 0, $pos));
3039  $header_array = explode($lb, $header_data);
3040  $this->incoming_headers = array();
3041  $this->incoming_cookies = array();
3042  foreach ($header_array as $header_line) {
3043  $arr = explode(':', $header_line, 2);
3044  if (count($arr) > 1) {
3045  $header_name = strtolower(trim($arr[0]));
3046  $this->incoming_headers[$header_name] = trim($arr[1]);
3047  if ($header_name == 'set-cookie') {
3048  // TODO: allow multiple cookies from parseCookie
3049  $cookie = $this->parseCookie(trim($arr[1]));
3050  if ($cookie) {
3051  $this->incoming_cookies[] = $cookie;
3052  $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3053  } else {
3054  $this->debug('did not find cookie in ' . trim($arr[1]));
3055  }
3056  }
3057  } elseif (isset($header_name)) {
3058  // append continuation line to previous header
3059  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3060  }
3061  }
3062 
3063  // loop until msg has been received
3064  if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
3065  $content_length = 2147483647; // ignore any content-length header
3066  $chunked = true;
3067  $this->debug("want to read chunked content");
3068  } elseif (isset($this->incoming_headers['content-length'])) {
3069  $content_length = $this->incoming_headers['content-length'];
3070  $chunked = false;
3071  $this->debug("want to read content of length $content_length");
3072  } else {
3073  $content_length = 2147483647;
3074  $chunked = false;
3075  $this->debug("want to read content to EOF");
3076  }
3077  $data = '';
3078  do {
3079  if ($chunked) {
3080  $tmp = fgets($this->fp, 256);
3081  $tmplen = strlen($tmp);
3082  $this->debug("read chunk line of $tmplen bytes");
3083  if ($tmplen == 0) {
3084  $this->incoming_payload = $data;
3085  $this->debug('socket read of chunk length timed out after length ' . strlen($data));
3086  $this->debug("read before timeout:\n" . $data);
3087  $this->setError('socket read of chunk length timed out');
3088  return false;
3089  }
3090  $content_length = hexdec(trim($tmp));
3091  $this->debug("chunk length $content_length");
3092  }
3093  $strlen = 0;
3094  while (($strlen < $content_length) && (!feof($this->fp))) {
3095  $readlen = min(8192, $content_length - $strlen);
3096  $tmp = fread($this->fp, $readlen);
3097  $tmplen = strlen($tmp);
3098  $this->debug("read buffer of $tmplen bytes");
3099  if (($tmplen == 0) && (!feof($this->fp))) {
3100  $this->incoming_payload = $data;
3101  $this->debug('socket read of body timed out after length ' . strlen($data));
3102  $this->debug("read before timeout:\n" . $data);
3103  $this->setError('socket read of body timed out');
3104  return false;
3105  }
3106  $strlen += $tmplen;
3107  $data .= $tmp;
3108  }
3109  if ($chunked && ($content_length > 0)) {
3110  $tmp = fgets($this->fp, 256);
3111  $tmplen = strlen($tmp);
3112  $this->debug("read chunk terminator of $tmplen bytes");
3113  if ($tmplen == 0) {
3114  $this->incoming_payload = $data;
3115  $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
3116  $this->debug("read before timeout:\n" . $data);
3117  $this->setError('socket read of chunk terminator timed out');
3118  return false;
3119  }
3120  }
3121  } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
3122  if (feof($this->fp)) {
3123  $this->debug('read to EOF');
3124  }
3125  $this->debug('read body of length ' . strlen($data));
3126  $this->incoming_payload .= $data;
3127  $this->debug('received a total of ' . strlen($this->incoming_payload) . ' bytes of data from server');
3128 
3129  // close filepointer
3130  if (
3131  (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
3132  (! $this->persistentConnection) || feof($this->fp)) {
3133  fclose($this->fp);
3134  $this->fp = false;
3135  $this->debug('closed socket');
3136  }
3137 
3138  // connection was closed unexpectedly
3139  if ($this->incoming_payload == '') {
3140  $this->setError('no response from server');
3141  return false;
3142  }
3143 
3144  // decode transfer-encoding
3145  // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
3146  // if(!$data = $this->decodeChunked($data, $lb)){
3147  // $this->setError('Decoding of chunked data failed');
3148  // return false;
3149  // }
3150  //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
3151  // set decoded payload
3152  // $this->incoming_payload = $header_data.$lb.$lb.$data;
3153  // }
3154  } elseif ($this->io_method() == 'curl') {
3155  // send and receive
3156  $this->debug('send and receive with cURL');
3157  $this->incoming_payload = curl_exec($this->ch);
3158  $data = $this->incoming_payload;
3159 
3160  $cErr = curl_error($this->ch);
3161  if ($cErr != '') {
3162  $err = 'cURL ERROR: ' . curl_errno($this->ch) . ': ' . $cErr . '<br>';
3163  // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
3164  foreach (curl_getinfo($this->ch) as $k => $v) {
3165  $err .= "$k: $v<br>";
3166  }
3167  $this->debug($err);
3168  $this->setError($err);
3169  curl_close($this->ch);
3170  return false;
3171  } else {
3172  //echo '<pre>';
3173  //var_dump(curl_getinfo($this->ch));
3174  //echo '</pre>';
3175  }
3176  // close curl
3177  $this->debug('No cURL error, closing cURL');
3178  curl_close($this->ch);
3179 
3180  // try removing skippable headers
3181  $savedata = $data;
3182  while ($this->isSkippableCurlHeader($data)) {
3183  $this->debug("Found HTTP header to skip");
3184  if ($pos = strpos($data, "\r\n\r\n")) {
3185  $data = ltrim(substr($data, $pos));
3186  } elseif ($pos = strpos($data, "\n\n")) {
3187  $data = ltrim(substr($data, $pos));
3188  }
3189  }
3190 
3191  if ($data == '') {
3192  // have nothing left; just remove 100 header(s)
3193  $data = $savedata;
3194  while (preg_match('/^HTTP\/1.1 100/', $data)) {
3195  if ($pos = strpos($data, "\r\n\r\n")) {
3196  $data = ltrim(substr($data, $pos));
3197  } elseif ($pos = strpos($data, "\n\n")) {
3198  $data = ltrim(substr($data, $pos));
3199  }
3200  }
3201  }
3202 
3203  // separate content from HTTP headers
3204  if ($pos = strpos($data, "\r\n\r\n")) {
3205  $lb = "\r\n";
3206  } elseif ($pos = strpos($data, "\n\n")) {
3207  $lb = "\n";
3208  } else {
3209  $this->debug('no proper separation of headers and document');
3210  $this->setError('no proper separation of headers and document');
3211  return false;
3212  }
3213  $header_data = trim(substr($data, 0, $pos));
3214  $header_array = explode($lb, $header_data);
3215  $data = ltrim(substr($data, $pos));
3216  $this->debug('found proper separation of headers and document');
3217  $this->debug('cleaned data, stringlen: ' . strlen($data));
3218  // clean headers
3219  foreach ($header_array as $header_line) {
3220  $arr = explode(':', $header_line, 2);
3221  if (count($arr) > 1) {
3222  $header_name = strtolower(trim($arr[0]));
3223  $this->incoming_headers[$header_name] = trim($arr[1]);
3224  if ($header_name == 'set-cookie') {
3225  // TODO: allow multiple cookies from parseCookie
3226  $cookie = $this->parseCookie(trim($arr[1]));
3227  if ($cookie) {
3228  $this->incoming_cookies[] = $cookie;
3229  $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3230  } else {
3231  $this->debug('did not find cookie in ' . trim($arr[1]));
3232  }
3233  }
3234  } elseif (isset($header_name)) {
3235  // append continuation line to previous header
3236  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3237  }
3238  }
3239  }
3240 
3241  $this->response_status_line = $header_array[0];
3242  $arr = explode(' ', $this->response_status_line, 3);
3243  $http_version = $arr[0];
3244  $http_status = intval($arr[1]);
3245  $http_reason = count($arr) > 2 ? $arr[2] : '';
3246 
3247  // see if we need to resend the request with http digest authentication
3248  if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
3249  $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
3250  $this->setURL($this->incoming_headers['location']);
3251  $this->tryagain = true;
3252  return false;
3253  }
3254 
3255  // see if we need to resend the request with http digest authentication
3256  if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
3257  $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
3258  if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
3259  $this->debug('Server wants digest authentication');
3260  // remove "Digest " from our elements
3261  $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
3262 
3263  // parse elements into array
3264  $digestElements = explode(',', $digestString);
3265  foreach ($digestElements as $val) {
3266  $tempElement = explode('=', trim($val), 2);
3267  $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
3268  }
3269 
3270  // should have (at least) qop, realm, nonce
3271  if (isset($digestRequest['nonce'])) {
3272  $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
3273  $this->tryagain = true;
3274  return false;
3275  }
3276  }
3277  $this->debug('HTTP authentication failed');
3278  $this->setError('HTTP authentication failed');
3279  return false;
3280  }
3281 
3282  if (
3283  ($http_status >= 300 && $http_status <= 307) ||
3284  ($http_status >= 400 && $http_status <= 417) ||
3285  ($http_status >= 501 && $http_status <= 505)
3286  ) {
3287  $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
3288  return false;
3289  }
3290 
3291  // decode content-encoding
3292  if (isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != '') {
3293  if (strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip') {
3294  // if decoding works, use it. else assume data wasn't gzencoded
3295  if (function_exists('gzinflate')) {
3296  //$timer->setMarker('starting decoding of gzip/deflated content');
3297  // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
3298  // this means there are no Zlib headers, although there should be
3299  $this->debug('The gzinflate function exists');
3300  $datalen = strlen($data);
3301  if ($this->incoming_headers['content-encoding'] == 'deflate') {
3302  if ($degzdata = @gzinflate($data)) {
3303  $data = $degzdata;
3304  $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
3305  if (strlen($data) < $datalen) {
3306  // test for the case that the payload has been compressed twice
3307  $this->debug('The inflated payload is smaller than the gzipped one; try again');
3308  if ($degzdata = @gzinflate($data)) {
3309  $data = $degzdata;
3310  $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
3311  }
3312  }
3313  } else {
3314  $this->debug('Error using gzinflate to inflate the payload');
3315  $this->setError('Error using gzinflate to inflate the payload');
3316  }
3317  } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
3318  if ($degzdata = @gzinflate(substr($data, 10))) { // do our best
3319  $data = $degzdata;
3320  $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
3321  if (strlen($data) < $datalen) {
3322  // test for the case that the payload has been compressed twice
3323  $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
3324  if ($degzdata = @gzinflate(substr($data, 10))) {
3325  $data = $degzdata;
3326  $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
3327  }
3328  }
3329  } else {
3330  $this->debug('Error using gzinflate to un-gzip the payload');
3331  $this->setError('Error using gzinflate to un-gzip the payload');
3332  }
3333  }
3334  //$timer->setMarker('finished decoding of gzip/deflated content');
3335  //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
3336  // set decoded payload
3337  $this->incoming_payload = $header_data . $lb . $lb . $data;
3338  } else {
3339  $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3340  $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3341  }
3342  } else {
3343  $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3344  $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3345  }
3346  } else {
3347  $this->debug('No Content-Encoding header');
3348  }
3349 
3350  if (strlen($data) == 0) {
3351  $this->debug('no data after headers!');
3352  $this->setError('no data present after HTTP headers');
3353  return false;
3354  }
3355 
3356  return $data;
3357  }
3358 
3366  public function setContentType($type, $charset = false)
3367  {
3368  $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
3369  }
3370 
3377  public function usePersistentConnection()
3378  {
3379  if (isset($this->outgoing_headers['Accept-Encoding'])) {
3380  return false;
3381  }
3382  $this->protocol_version = '1.1';
3383  $this->persistentConnection = true;
3384  $this->setHeader('Connection', 'Keep-Alive');
3385  return true;
3386  }
3387 
3395  /*
3396  * TODO: allow a Set-Cookie string to be parsed into multiple cookies
3397  */
3398  public function parseCookie($cookie_str)
3399  {
3400  $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
3401  // begin-patch php8
3402  //$data = split(';', $cookie_str);
3403  $data = explode(';', $cookie_str);
3404  $value_str = $data[0];
3405 
3406  $cookie_param = 'domain=';
3407  $start = strpos($cookie_str, $cookie_param);
3408  if ($start > 0) {
3409  $domain = substr($cookie_str, $start + strlen($cookie_param));
3410  $domain = substr($domain, 0, strpos($domain, ';'));
3411  } else {
3412  $domain = '';
3413  }
3414 
3415  $cookie_param = 'expires=';
3416  $start = strpos($cookie_str, $cookie_param);
3417  if ($start > 0) {
3418  $expires = substr($cookie_str, $start + strlen($cookie_param));
3419  $expires = substr($expires, 0, strpos($expires, ';'));
3420  } else {
3421  $expires = '';
3422  }
3423 
3424  $cookie_param = 'path=';
3425  $start = strpos($cookie_str, $cookie_param);
3426  if ($start > 0) {
3427  $path = substr($cookie_str, $start + strlen($cookie_param));
3428  $path = substr($path, 0, strpos($path, ';'));
3429  } else {
3430  $path = '/';
3431  }
3432 
3433  $cookie_param = ';secure;';
3434  if (strpos($cookie_str, $cookie_param) !== false) {
3435  $secure = true;
3436  } else {
3437  $secure = false;
3438  }
3439 
3440  $sep_pos = strpos($value_str, '=');
3441 
3442  if ($sep_pos) {
3443  $name = substr($value_str, 0, $sep_pos);
3444  $value = substr($value_str, $sep_pos + 1);
3445  $cookie= array( 'name' => $name,
3446  'value' => $value,
3447  'domain' => $domain,
3448  'path' => $path,
3449  'expires' => $expires,
3450  'secure' => $secure
3451  );
3452  return $cookie;
3453  }
3454  return false;
3455  }
3456 
3465  public function getCookiesForRequest($cookies, $secure=false)
3466  {
3467  $cookie_str = '';
3468  if ((! is_null($cookies)) && (is_array($cookies))) {
3469  foreach ($cookies as $cookie) {
3470  if (! is_array($cookie)) {
3471  continue;
3472  }
3473  $this->debug("check cookie for validity: " . $cookie['name'] . '=' . $cookie['value']);
3474  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
3475  if (strtotime($cookie['expires']) <= time()) {
3476  $this->debug('cookie has expired');
3477  continue;
3478  }
3479  }
3480  if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
3481  $domain = preg_quote($cookie['domain']);
3482  if (! preg_match("'.*$domain$'i", $this->host)) {
3483  $this->debug('cookie has different domain');
3484  continue;
3485  }
3486  }
3487  if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
3488  $path = preg_quote($cookie['path']);
3489  if (! preg_match("'^$path.*'i", $this->path)) {
3490  $this->debug('cookie is for a different path');
3491  continue;
3492  }
3493  }
3494  if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
3495  $this->debug('cookie is secure, transport is not');
3496  continue;
3497  }
3498  $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3499  $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3500  }
3501  }
3502  return $cookie_str;
3503  }
3504 }
3505 
3506 ?><?php
3507 
3508 
3509 
3520 class nusoap_server extends nusoap_base
3521 {
3527  public $headers = array();
3533  public $request = '';
3539  public $requestHeaders = '';
3545  public $requestHeader = null;
3551  public $document = '';
3557  public $requestSOAP = '';
3563  public $methodURI = '';
3569  public $methodname = '';
3575  public $methodparams = array();
3581  public $SOAPAction = '';
3587  public $xml_encoding = '';
3593  public $decode_utf8 = true;
3594 
3600  public $outgoing_headers = array();
3606  public $response = '';
3612  public $responseHeaders = '';
3618  public $responseSOAP = '';
3624  public $methodreturn = false;
3630  public $methodreturnisliteralxml = false;
3636  public $fault = false;
3642  public $result = 'successful';
3643 
3650  public $operations = array();
3656  public $wsdl = false;
3662  public $externalWSDLURL = false;
3668  public $debug_flag = false;
3669 
3670 
3678  public function __construct($wsdl=false)
3679  {
3681  // turn on debugging?
3682  global $debug;
3683  global $HTTP_SERVER_VARS;
3684 
3685  if (isset($_SERVER)) {
3686  $this->debug("_SERVER is defined:");
3687  $this->appendDebug($this->varDump($_SERVER));
3688  } elseif (isset($HTTP_SERVER_VARS)) {
3689  $this->debug("HTTP_SERVER_VARS is defined:");
3690  $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
3691  } else {
3692  $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
3693  }
3694 
3695  if (isset($debug)) {
3696  $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
3697  $this->debug_flag = $debug;
3698  } elseif (isset($_SERVER['QUERY_STRING'])) {
3699  $qs = explode('&', $_SERVER['QUERY_STRING']);
3700  foreach ($qs as $v) {
3701  if (substr($v, 0, 6) == 'debug=') {
3702  $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
3703  $this->debug_flag = substr($v, 6);
3704  }
3705  }
3706  } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3707  $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
3708  foreach ($qs as $v) {
3709  if (substr($v, 0, 6) == 'debug=') {
3710  $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
3711  $this->debug_flag = substr($v, 6);
3712  }
3713  }
3714  }
3715 
3716  // wsdl
3717  if ($wsdl) {
3718  $this->debug("In nusoap_server, WSDL is specified");
3719  if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
3720  $this->wsdl = $wsdl;
3721  $this->externalWSDLURL = $this->wsdl->wsdl;
3722  $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3723  } else {
3724  $this->debug('Create wsdl from ' . $wsdl);
3725  $this->wsdl = new wsdl($wsdl);
3726  $this->externalWSDLURL = $wsdl;
3727  }
3728  $this->appendDebug($this->wsdl->getDebug());
3729  $this->wsdl->clearDebug();
3730  if ($err = $this->wsdl->getError()) {
3731  die('WSDL ERROR: ' . $err);
3732  }
3733  }
3734  }
3735 
3742  public function service($data)
3743  {
3744  global $HTTP_SERVER_VARS;
3745 
3746  if (isset($_SERVER['QUERY_STRING'])) {
3747  $qs = $_SERVER['QUERY_STRING'];
3748  } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3749  $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3750  } else {
3751  $qs = '';
3752  }
3753  $this->debug("In service, query string=$qs");
3754 
3755  if (preg_match('/wsdl/', $qs)) {
3756  $this->debug("In service, this is a request for WSDL");
3757  if ($this->externalWSDLURL) {
3758  if (strpos($this->externalWSDLURL, "://")!==false) { // assume URL
3759  header('Location: ' . $this->externalWSDLURL);
3760  } else { // assume file
3761  header("Content-Type: text/xml\r\n");
3762  $fp = fopen($this->externalWSDLURL, 'r');
3763  fpassthru($fp);
3764  }
3765  } elseif ($this->wsdl) {
3766  header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
3767  print $this->wsdl->serialize($this->debug_flag);
3768  if ($this->debug_flag) {
3769  $this->debug('wsdl:');
3770  $this->appendDebug($this->varDump($this->wsdl));
3771  print $this->getDebugAsXMLComment();
3772  }
3773  } else {
3774  header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3775  print "This service does not provide WSDL";
3776  }
3777  } elseif ($data == '' && $this->wsdl) {
3778  $this->debug("In service, there is no data, so return Web description");
3779  print $this->wsdl->webDescription();
3780  } else {
3781  $this->debug("In service, invoke the request");
3782  $this->parse_request($data);
3783  if (! $this->fault) {
3784  $this->invoke_method();
3785  }
3786  if (! $this->fault) {
3787  $this->serialize_return();
3788  }
3789  $this->send_response();
3790  }
3791  }
3792 
3805  public function parse_http_headers()
3806  {
3807  global $HTTP_SERVER_VARS;
3808 
3809  $this->request = '';
3810  $this->SOAPAction = '';
3811  if (function_exists('getallheaders')) {
3812  $this->debug("In parse_http_headers, use getallheaders");
3813  $headers = getallheaders();
3814  foreach ($headers as $k=>$v) {
3815  $k = strtolower($k);
3816  $this->headers[$k] = $v;
3817  $this->request .= "$k: $v\r\n";
3818  $this->debug("$k: $v");
3819  }
3820  // get SOAPAction header
3821  if (isset($this->headers['soapaction'])) {
3822  $this->SOAPAction = str_replace('"', '', $this->headers['soapaction']);
3823  }
3824  // get the character encoding of the incoming request
3825  if (isset($this->headers['content-type']) && strpos($this->headers['content-type'], '=')) {
3826  $enc = str_replace('"', '', substr(strstr($this->headers["content-type"], '='), 1));
3827  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3828  $this->xml_encoding = strtoupper($enc);
3829  } else {
3830  $this->xml_encoding = 'US-ASCII';
3831  }
3832  } else {
3833  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3834  $this->xml_encoding = 'ISO-8859-1';
3835  }
3836  } elseif (isset($_SERVER) && is_array($_SERVER)) {
3837  $this->debug("In parse_http_headers, use _SERVER");
3838  foreach ($_SERVER as $k => $v) {
3839  if (substr($k, 0, 5) == 'HTTP_') {
3840  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3841  } else {
3842  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3843  }
3844  if ($k == 'soapaction') {
3845  // get SOAPAction header
3846  $k = 'SOAPAction';
3847  $v = str_replace('"', '', $v);
3848  $v = str_replace('\\', '', $v);
3849  $this->SOAPAction = $v;
3850  } elseif ($k == 'content-type') {
3851  // get the character encoding of the incoming request
3852  if (strpos($v, '=')) {
3853  $enc = substr(strstr($v, '='), 1);
3854  $enc = str_replace('"', '', $enc);
3855  $enc = str_replace('\\', '', $enc);
3856  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3857  $this->xml_encoding = strtoupper($enc);
3858  } else {
3859  $this->xml_encoding = 'US-ASCII';
3860  }
3861  } else {
3862  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3863  $this->xml_encoding = 'ISO-8859-1';
3864  }
3865  }
3866  $this->headers[$k] = $v;
3867  $this->request .= "$k: $v\r\n";
3868  $this->debug("$k: $v");
3869  }
3870  } elseif (is_array($HTTP_SERVER_VARS)) {
3871  $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
3872  foreach ($HTTP_SERVER_VARS as $k => $v) {
3873  if (substr($k, 0, 5) == 'HTTP_') {
3874  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3875  $k = strtolower(substr($k, 5));
3876  } else {
3877  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3878  $k = strtolower($k);
3879  }
3880  if ($k == 'soapaction') {
3881  // get SOAPAction header
3882  $k = 'SOAPAction';
3883  $v = str_replace('"', '', $v);
3884  $v = str_replace('\\', '', $v);
3885  $this->SOAPAction = $v;
3886  } elseif ($k == 'content-type') {
3887  // get the character encoding of the incoming request
3888  if (strpos($v, '=')) {
3889  $enc = substr(strstr($v, '='), 1);
3890  $enc = str_replace('"', '', $enc);
3891  $enc = str_replace('\\', '', $enc);
3892  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3893  $this->xml_encoding = strtoupper($enc);
3894  } else {
3895  $this->xml_encoding = 'US-ASCII';
3896  }
3897  } else {
3898  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3899  $this->xml_encoding = 'ISO-8859-1';
3900  }
3901  }
3902  $this->headers[$k] = $v;
3903  $this->request .= "$k: $v\r\n";
3904  $this->debug("$k: $v");
3905  }
3906  } else {
3907  $this->debug("In parse_http_headers, HTTP headers not accessible");
3908  $this->setError("HTTP headers not accessible");
3909  }
3910  }
3911 
3934  public function parse_request($data='')
3935  {
3936  $this->debug('entering parse_request()');
3937  $this->parse_http_headers();
3938  $this->debug('got character encoding: ' . $this->xml_encoding);
3939  // uncompress if necessary
3940  if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
3941  $this->debug('got content encoding: ' . $this->headers['content-encoding']);
3942  if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
3943  // if decoding works, use it. else assume data wasn't gzencoded
3944  if (function_exists('gzuncompress')) {
3945  if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
3946  $data = $degzdata;
3947  } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
3948  $data = $degzdata;
3949  } else {
3950  $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
3951  return;
3952  }
3953  } else {
3954  $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
3955  return;
3956  }
3957  }
3958  }
3959  $this->request .= "\r\n" . $data;
3960  $data = $this->parseRequest($this->headers, $data);
3961  $this->requestSOAP = $data;
3962  $this->debug('leaving parse_request');
3963  }
3964 
3982  public function invoke_method()
3983  {
3984  $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
3985 
3986  if ($this->wsdl) {
3987  if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
3988  $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
3989  $this->appendDebug('opData=' . $this->varDump($this->opData));
3990  } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
3991  // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
3992  $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
3993  $this->appendDebug('opData=' . $this->varDump($this->opData));
3994  $this->methodname = $this->opData['name'];
3995  } else {
3996  $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
3997  $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
3998  return;
3999  }
4000  } else {
4001  $this->debug('in invoke_method, no WSDL to validate method');
4002  }
4003 
4004  // if a . is present in $this->methodname, we see if there is a class in scope,
4005  // which could be referred to. We will also distinguish between two deliminators,
4006  // to allow methods to be called a the class or an instance
4007  $class = '';
4008  $method = '';
4009  if (strpos($this->methodname, '..') > 0) {
4010  $delim = '..';
4011  } elseif (strpos($this->methodname, '.') > 0) {
4012  $delim = '.';
4013  } else {
4014  $delim = '';
4015  }
4016 
4017  if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 &&
4018  class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
4019  // get the class and method name
4020  $class = substr($this->methodname, 0, strpos($this->methodname, $delim));
4021  $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
4022  $this->debug("in invoke_method, class=$class method=$method delim=$delim");
4023  }
4024  // set class handler
4025  // added to support single operations
4026  if ($class == '' && $this->class !='') {
4027  $class = $this->class;
4028  $delim = "..";
4029  $method = $this->methodname;
4030  }
4031 
4032  // does method exist?
4033  if ($class == '') {
4034  if (!function_exists($this->methodname)) {
4035  $this->debug("in invoke_method, function '$this->methodname' not found!");
4036  $this->result = 'fault: method not found';
4037  $this->fault('SOAP-ENV:Client', "method '$this->methodname' not defined in service");
4038  return;
4039  }
4040  } else {
4041  $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
4042  if (!in_array($method_to_compare, get_class_methods($class))) {
4043  $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
4044  $this->result = 'fault: method not found';
4045  $this->fault('SOAP-ENV:Client', "method '$this->methodname' not defined in service");
4046  return;
4047  }
4048  }
4049 
4050  // evaluate message, getting back parameters
4051  // verify that request parameters match the method's signature
4052  if (! $this->verify_method($this->methodname, $this->methodparams)) {
4053  // debug
4054  $this->debug('ERROR: request not verified against method signature');
4055  $this->result = 'fault: request failed validation against method signature';
4056  // return fault
4057  $this->fault('SOAP-ENV:Client', "Operation '$this->methodname' not defined in service.");
4058  return;
4059  }
4060 
4061  // if there are parameters to pass
4062  $this->debug('in invoke_method, params:');
4063  $this->appendDebug($this->varDump($this->methodparams));
4064  $this->debug("in invoke_method, calling '$this->methodname'");
4065  if (!function_exists('call_user_func_array')) {
4066  if ($class == '') {
4067  $this->debug('in invoke_method, calling function using eval()');
4068  $funcCall = "\$this->methodreturn = $this->methodname(";
4069  } else {
4070  if ($delim == '..') {
4071  $this->debug('in invoke_method, calling class method using eval()');
4072  $funcCall = "\$this->methodreturn = " . $class . "::" . $method . "(";
4073  } else {
4074  $this->debug('in invoke_method, calling instance method using eval()');
4075  // generate unique instance name
4076  $instname = "\$inst_" . time();
4077  $funcCall = $instname . " = new " . $class . "(); ";
4078  $funcCall .= "\$this->methodreturn = " . $instname . "->" . $method . "(";
4079  }
4080  }
4081  if ($this->methodparams) {
4082  foreach ($this->methodparams as $param) {
4083  if (is_array($param) || is_object($param)) {
4084  $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
4085  return;
4086  }
4087  $funcCall .= "\"$param\",";
4088  }
4089  $funcCall = substr($funcCall, 0, -1);
4090  }
4091  $funcCall .= ');';
4092  $this->debug('in invoke_method, function call: ' . $funcCall);
4093  @eval($funcCall);
4094  } else {
4095  if ($class == '') {
4096  $this->debug('in invoke_method, calling function using call_user_func_array()');
4097  $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array()
4098  } elseif ($delim == '..') {
4099  $this->debug('in invoke_method, calling class method using call_user_func_array()');
4100  $call_arg = array($class, $method);
4101  } else {
4102  $this->debug('in invoke_method, calling instance method using call_user_func_array()');
4103  $instance = new $class();
4104  $call_arg = array(&$instance, $method);
4105  }
4106  if (is_array($this->methodparams)) {
4107  $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
4108  } else {
4109  $this->methodreturn = call_user_func_array($call_arg, array());
4110  }
4111  }
4112  $this->debug('in invoke_method, methodreturn:');
4113  $this->appendDebug($this->varDump($this->methodreturn));
4114  $this->debug("in invoke_method, called method $this->methodname, received data of type " . gettype($this->methodreturn));
4115  }
4116 
4128  public function serialize_return()
4129  {
4130  $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4131  // if fault
4132  if (isset($this->methodreturn) && ((get_class((object)$this->methodreturn) == 'soap_fault') || (get_class((object)$this->methodreturn) == 'nusoap_fault'))) {
4133  $this->debug('got a fault object from method');
4134  $this->fault = $this->methodreturn;
4135  return;
4136  } elseif ($this->methodreturnisliteralxml) {
4137  $return_val = $this->methodreturn;
4138  // returned value(s)
4139  } else {
4140  $this->debug('got a(n) ' . gettype($this->methodreturn) . ' from method');
4141  $this->debug('serializing return value');
4142  if ($this->wsdl) {
4143  if (sizeof($this->opData['output']['parts']) > 1) {
4144  $this->debug('more than one output part, so use the method return unchanged');
4145  $opParams = $this->methodreturn;
4146  } elseif (sizeof($this->opData['output']['parts']) == 1) {
4147  $this->debug('exactly one output part, so wrap the method return in a simple array');
4148  // TODO: verify that it is not already wrapped!
4149  //foreach ($this->opData['output']['parts'] as $name => $type) {
4150  // $this->debug('wrap in element named ' . $name);
4151  //}
4152  $opParams = array($this->methodreturn);
4153  }
4154  $return_val = $this->wsdl->serializeRPCParameters($this->methodname, 'output', $opParams);
4155  $this->appendDebug($this->wsdl->getDebug());
4156  $this->wsdl->clearDebug();
4157  if ($errstr = $this->wsdl->getError()) {
4158  $this->debug('got wsdl error: ' . $errstr);
4159  $this->fault('SOAP-ENV:Server', 'unable to serialize result');
4160  return;
4161  }
4162  } else {
4163  if (isset($this->methodreturn)) {
4164  $return_val = $this->serialize_val($this->methodreturn, 'return');
4165  } else {
4166  $return_val = '';
4167  $this->debug('in absence of WSDL, assume void return for backward compatibility');
4168  }
4169  }
4170  }
4171  $this->debug('return value:');
4172  $this->appendDebug($this->varDump($return_val));
4173 
4174  $this->debug('serializing response');
4175  if ($this->wsdl) {
4176  $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
4177  if ($this->opData['style'] == 'rpc') {
4178  $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
4179  if ($this->opData['output']['use'] == 'literal') {
4180  // 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
4181  $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4182  } else {
4183  $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4184  }
4185  } else {
4186  $this->debug('style is not rpc for serialization: assume document');
4187  $payload = $return_val;
4188  }
4189  } else {
4190  $this->debug('do not have WSDL for serialization: assume rpc/encoded');
4191  $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
4192  }
4193  $this->result = 'successful';
4194  if ($this->wsdl) {
4195  //if($this->debug_flag){
4196  $this->appendDebug($this->wsdl->getDebug());
4197  // }
4198  if (isset($opData['output']['encodingStyle'])) {
4199  $encodingStyle = $opData['output']['encodingStyle'];
4200  } else {
4201  $encodingStyle = '';
4202  }
4203  // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
4204  $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders, $this->wsdl->usedNamespaces, $this->opData['style'], $this->opData['output']['use'], $encodingStyle);
4205  } else {
4206  $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders);
4207  }
4208  $this->debug("Leaving serialize_return");
4209  }
4210 
4221  public function send_response()
4222  {
4223  $this->debug('Enter send_response');
4224  if ($this->fault) {
4225  $payload = $this->fault->serialize();
4226  $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
4227  $this->outgoing_headers[] = "Status: 500 Internal Server Error";
4228  } else {
4229  $payload = $this->responseSOAP;
4230  // Some combinations of PHP+Web server allow the Status
4231  // to come through as a header. Since OK is the default
4232  // just do nothing.
4233  // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
4234  // $this->outgoing_headers[] = "Status: 200 OK";
4235  }
4236  // add debug data if in debug mode
4237  if (isset($this->debug_flag) && $this->debug_flag) {
4238  $payload .= $this->getDebugAsXMLComment();
4239  }
4240  $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
4241  preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
4242  $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (" . $rev[1] . ")";
4243  // Let the Web server decide about this
4244  //$this->outgoing_headers[] = "Connection: Close\r\n";
4245  $payload = $this->getHTTPBody($payload);
4246  $type = $this->getHTTPContentType();
4247  $charset = $this->getHTTPContentTypeCharset();
4248  $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
4249  //begin code to compress payload - by John
4250  // NOTE: there is no way to know whether the Web server will also compress
4251  // this data.
4252  if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
4253  if (strstr($this->headers['accept-encoding'], 'gzip')) {
4254  if (function_exists('gzencode')) {
4255  if (isset($this->debug_flag) && $this->debug_flag) {
4256  $payload .= "<!-- Content being gzipped -->";
4257  }
4258  $this->outgoing_headers[] = "Content-Encoding: gzip";
4259  $payload = gzencode($payload);
4260  } else {
4261  if (isset($this->debug_flag) && $this->debug_flag) {
4262  $payload .= "<!-- Content will not be gzipped: no gzencode -->";
4263  }
4264  }
4265  } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
4266  // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
4267  // instead of gzcompress output,
4268  // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
4269  if (function_exists('gzdeflate')) {
4270  if (isset($this->debug_flag) && $this->debug_flag) {
4271  $payload .= "<!-- Content being deflated -->";
4272  }
4273  $this->outgoing_headers[] = "Content-Encoding: deflate";
4274  $payload = gzdeflate($payload);
4275  } else {
4276  if (isset($this->debug_flag) && $this->debug_flag) {
4277  $payload .= "<!-- Content will not be deflated: no gzcompress -->";
4278  }
4279  }
4280  }
4281  }
4282  //end code
4283  $this->outgoing_headers[] = "Content-Length: " . strlen($payload);
4284  reset($this->outgoing_headers);
4285  foreach ($this->outgoing_headers as $hdr) {
4286  header($hdr, false);
4287  }
4288  print $payload;
4289  $this->response = join("\r\n", $this->outgoing_headers) . "\r\n\r\n" . $payload;
4290  }
4291 
4301  public function verify_method($operation, $request)
4302  {
4303  if (isset($this->wsdl) && is_object($this->wsdl)) {
4304  if ($this->wsdl->getOperationData($operation)) {
4305  return true;
4306  }
4307  } elseif (isset($this->operations[$operation])) {
4308  return true;
4309  }
4310  return false;
4311  }
4312 
4321  public function parseRequest($headers, $data)
4322  {
4323  $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
4324  if (!strstr($headers['content-type'], 'text/xml')) {
4325  $this->setError('Request not of type text/xml');
4326  return false;
4327  }
4328  if (strpos($headers['content-type'], '=')) {
4329  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
4330  $this->debug('Got response encoding: ' . $enc);
4331  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4332  $this->xml_encoding = strtoupper($enc);
4333  } else {
4334  $this->xml_encoding = 'US-ASCII';
4335  }
4336  } else {
4337  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4338  $this->xml_encoding = 'ISO-8859-1';
4339  }
4340  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
4341  // parse response, get soap parser obj
4342  $parser = new nusoap_parser($data, $this->xml_encoding, '', $this->decode_utf8);
4343  // parser debug
4344  $this->debug("parser debug: \n" . $parser->getDebug());
4345  // if fault occurred during message parsing
4346  if ($err = $parser->getError()) {
4347  $this->result = 'fault: error in msg parsing: ' . $err;
4348  $this->fault('SOAP-ENV:Client', "error in msg parsing:\n" . $err);
4349  // else successfully parsed request into soapval object
4350  } else {
4351  // get/set methodname
4352  $this->methodURI = $parser->root_struct_namespace;
4353  $this->methodname = $parser->root_struct_name;
4354  $this->debug('methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4355  $this->debug('calling parser->get_soapbody()');
4356  $this->methodparams = $parser->get_soapbody();
4357  // get SOAP headers
4358  $this->requestHeaders = $parser->getHeaders();
4359  // get SOAP Header
4360  $this->requestHeader = $parser->get_soapheader();
4361  // add document for doclit support
4362  $this->document = $parser->document;
4363  }
4364  }
4365 
4373  public function getHTTPBody($soapmsg)
4374  {
4375  return $soapmsg;
4376  }
4377 
4386  public function getHTTPContentType()
4387  {
4388  return 'text/xml';
4389  }
4390 
4400  public function getHTTPContentTypeCharset()
4401  {
4402  return $this->soap_defencoding;
4403  }
4404 
4414  public function add_to_map($methodname, $in, $out)
4415  {
4416  $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
4417  }
4418 
4433  public function register($name, $in=array(), $out=array(), $namespace=false, $soapaction=false, $style=false, $use=false, $documentation='', $encodingStyle='')
4434  {
4435  global $HTTP_SERVER_VARS;
4436 
4437  if ($this->externalWSDLURL) {
4438  die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
4439  }
4440  if (! $name) {
4441  die('You must specify a name when you register an operation');
4442  }
4443  if (!is_array($in)) {
4444  die('You must provide an array for operation inputs');
4445  }
4446  if (!is_array($out)) {
4447  die('You must provide an array for operation outputs');
4448  }
4449  if (false == $namespace) {
4450  }
4451  if (false == $soapaction) {
4452  if (isset($_SERVER)) {
4453  $SERVER_NAME = $_SERVER['SERVER_NAME'];
4454  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4455  $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4456  } elseif (isset($HTTP_SERVER_VARS)) {
4457  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4458  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4459  $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4460  } else {
4461  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4462  }
4463  if ($HTTPS == '1' || $HTTPS == 'on') {
4464  $SCHEME = 'https';
4465  } else {
4466  $SCHEME = 'http';
4467  }
4468  $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
4469  }
4470  if (false == $style) {
4471  $style = "rpc";
4472  }
4473  if (false == $use) {
4474  $use = "encoded";
4475  }
4476  if ($use == 'encoded' && $encodingStyle = '') {
4477  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
4478  }
4479 
4480  $this->operations[$name] = array(
4481  'name' => $name,
4482  'in' => $in,
4483  'out' => $out,
4484  'namespace' => $namespace,
4485  'soapaction' => $soapaction,
4486  'style' => $style);
4487  if ($this->wsdl) {
4488  $this->wsdl->addOperation($name, $in, $out, $namespace, $soapaction, $style, $use, $documentation, $encodingStyle);
4489  }
4490  return true;
4491  }
4492 
4503  public function fault($faultcode, $faultstring, $faultactor='', $faultdetail='')
4504  {
4505  if ($faultdetail == '' && $this->debug_flag) {
4506  $faultdetail = $this->getDebug();
4507  }
4508  $this->fault = new nusoap_fault($faultcode, $faultactor, $faultstring, $faultdetail);
4509  $this->fault->soap_defencoding = $this->soap_defencoding;
4510  }
4511 
4523  public function configureWSDL($serviceName, $namespace = false, $endpoint = false, $style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
4524  {
4525  global $HTTP_SERVER_VARS;
4526 
4527  if (isset($_SERVER)) {
4528  $SERVER_NAME = $_SERVER['SERVER_NAME'];
4529  $SERVER_PORT = $_SERVER['SERVER_PORT'];
4530  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4531  $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4532  } elseif (isset($HTTP_SERVER_VARS)) {
4533  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4534  $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
4535  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4536  $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4537  } else {
4538  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4539  }
4540  // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
4541  $colon = strpos($SERVER_NAME, ":");
4542  if ($colon) {
4543  $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
4544  }
4545  if ($SERVER_PORT == 80) {
4546  $SERVER_PORT = '';
4547  } else {
4548  $SERVER_PORT = ':' . $SERVER_PORT;
4549  }
4550  if (false == $namespace) {
4551  $namespace = "http://$SERVER_NAME/soap/$serviceName";
4552  }
4553 
4554  if (false == $endpoint) {
4555  if ($HTTPS == '1' || $HTTPS == 'on') {
4556  $SCHEME = 'https';
4557  } else {
4558  $SCHEME = 'http';
4559  }
4560  $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
4561  }
4562 
4563  if (false == $schemaTargetNamespace) {
4564  $schemaTargetNamespace = $namespace;
4565  }
4566 
4567  $this->wsdl = new wsdl();
4568  $this->wsdl->serviceName = $serviceName;
4569  $this->wsdl->endpoint = $endpoint;
4570  $this->wsdl->namespaces['tns'] = $namespace;
4571  $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
4572  $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
4573  if ($schemaTargetNamespace != $namespace) {
4574  $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4575  }
4576  $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
4577  if ($style == 'document') {
4578  $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
4579  }
4580  $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
4581  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
4582  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
4583  $this->wsdl->bindings[$serviceName . 'Binding'] = array(
4584  'name'=>$serviceName . 'Binding',
4585  'style'=>$style,
4586  'transport'=>$transport,
4587  'portType'=>$serviceName . 'PortType');
4588  $this->wsdl->ports[$serviceName . 'Port'] = array(
4589  'binding'=>$serviceName . 'Binding',
4590  'location'=>$endpoint,
4591  'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
4592  }
4593 }
4594 
4598 class soap_server extends nusoap_server
4599 {
4600 }
4601 
4602 ?><?php
4603 
4604 
4605 
4615 class wsdl extends nusoap_base
4616 {
4617  // URL or filename of the root of this WSDL
4618  public $wsdl;
4619  // define internal arrays of bindings, ports, operations, messages, etc.
4620  public $schemas = array();
4621  public $currentSchema;
4622  public $message = array();
4623  public $complexTypes = array();
4624  public $messages = array();
4625  public $currentMessage;
4626  public $currentOperation;
4627  public $portTypes = array();
4628  public $currentPortType;
4629  public $bindings = array();
4630  public $currentBinding;
4631  public $ports = array();
4632  public $currentPort;
4633  public $opData = array();
4634  public $status = '';
4635  public $documentation = false;
4636  public $endpoint = '';
4637  // array of wsdl docs to import
4638  public $import = array();
4639  // parser vars
4640  public $parser;
4641  public $position = 0;
4642  public $depth = 0;
4643  public $depth_array = array();
4644  // for getting wsdl
4645  public $proxyhost = '';
4646  public $proxyport = '';
4647  public $proxyusername = '';
4648  public $proxypassword = '';
4649  public $timeout = 0;
4650  public $response_timeout = 30;
4651  public $curl_options = array(); // User-specified cURL options
4652  public $use_curl = false; // whether to always try to use cURL
4653  // for HTTP authentication
4654  public $username = ''; // Username for HTTP authentication
4655  public $password = ''; // Password for HTTP authentication
4656  public $authtype = ''; // Type of HTTP authentication
4657  public $certRequest = array(); // Certificate for HTTP SSL authentication
4658 
4673  public function __construct($wsdl = '', $proxyhost=false, $proxyport=false, $proxyusername=false, $proxypassword=false, $timeout=0, $response_timeout=30, $curl_options=null, $use_curl=false)
4674  {
4676  $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
4677  $this->proxyhost = $proxyhost;
4678  $this->proxyport = $proxyport;
4679  $this->proxyusername = $proxyusername;
4680  $this->proxypassword = $proxypassword;
4681  $this->timeout = $timeout;
4682  $this->response_timeout = $response_timeout;
4683  if (is_array($curl_options)) {
4684  $this->curl_options = $curl_options;
4685  }
4686  $this->use_curl = $use_curl;
4687  $this->fetchWSDL($wsdl);
4688  }
4689 
4695  public function fetchWSDL($wsdl)
4696  {
4697  $this->debug("parse and process WSDL path=$wsdl");
4698  $this->wsdl = $wsdl;
4699  // parse wsdl file
4700  if ($this->wsdl != "") {
4701  $this->parseWSDL($this->wsdl);
4702  }
4703  // imports
4704  // TODO: handle imports more properly, grabbing them in-line and nesting them
4705  $imported_urls = array();
4706  $imported = 1;
4707  while ($imported > 0) {
4708  $imported = 0;
4709  // Schema imports
4710  foreach ($this->schemas as $ns => $list) {
4711  foreach ($list as $xs) {
4712  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4713  foreach ($xs->imports as $ns2 => $list2) {
4714  for ($ii = 0; $ii < count($list2); $ii++) {
4715  if (! $list2[$ii]['loaded']) {
4716  $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
4717  $url = $list2[$ii]['location'];
4718  if ($url != '') {
4719  $urlparts = parse_url($url);
4720  if (!isset($urlparts['host'])) {
4721  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4722  substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
4723  }
4724  if (! in_array($url, $imported_urls)) {
4725  $this->parseWSDL($url);
4726  $imported++;
4727  $imported_urls[] = $url;
4728  }
4729  } else {
4730  $this->debug("Unexpected scenario: empty URL for unloaded import");
4731  }
4732  }
4733  }
4734  }
4735  }
4736  }
4737  // WSDL imports
4738  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4739  foreach ($this->import as $ns => $list) {
4740  for ($ii = 0; $ii < count($list); $ii++) {
4741  if (! $list[$ii]['loaded']) {
4742  $this->import[$ns][$ii]['loaded'] = true;
4743  $url = $list[$ii]['location'];
4744  if ($url != '') {
4745  $urlparts = parse_url($url);
4746  if (!isset($urlparts['host'])) {
4747  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4748  substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
4749  }
4750  if (! in_array($url, $imported_urls)) {
4751  $this->parseWSDL($url);
4752  $imported++;
4753  $imported_urls[] = $url;
4754  }
4755  } else {
4756  $this->debug("Unexpected scenario: empty URL for unloaded import");
4757  }
4758  }
4759  }
4760  }
4761  }
4762  // add new data to operation data
4763  foreach ($this->bindings as $binding => $bindingData) {
4764  if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
4765  foreach ($bindingData['operations'] as $operation => $data) {
4766  $this->debug('post-parse data gathering for ' . $operation);
4767  $this->bindings[$binding]['operations'][$operation]['input'] =
4768  isset($this->bindings[$binding]['operations'][$operation]['input']) ?
4769  array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
4770  $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
4771  $this->bindings[$binding]['operations'][$operation]['output'] =
4772  isset($this->bindings[$binding]['operations'][$operation]['output']) ?
4773  array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
4774  $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
4775  if (isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])) {
4776  $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
4777  }
4778  if (isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])) {
4779  $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
4780  }
4781  // Set operation style if necessary, but do not override one already provided
4782  if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
4783  $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
4784  }
4785  $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
4786  $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
4787  $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
4788  }
4789  }
4790  }
4791  }
4792 
4799  public function parseWSDL($wsdl = '')
4800  {
4801  $this->debug("parse WSDL at path=$wsdl");
4802 
4803  if ($wsdl == '') {
4804  $this->debug('no wsdl passed to parseWSDL()!!');
4805  $this->setError('no wsdl passed to parseWSDL()!!');
4806  return false;
4807  }
4808 
4809  // parse $wsdl for url format
4810  $wsdl_props = parse_url($wsdl);
4811 
4812  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
4813  $this->debug('getting WSDL http(s) URL ' . $wsdl);
4814  // get wsdl
4815  $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
4816  $tr->request_method = 'GET';
4817  $tr->useSOAPAction = false;
4818  if ($this->proxyhost && $this->proxyport) {
4819  $tr->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
4820  }
4821  if ($this->authtype != '') {
4822  $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
4823  }
4824  $tr->setEncoding('gzip, deflate');
4825  $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
4826  //$this->debug("WSDL request\n" . $tr->outgoing_payload);
4827  //$this->debug("WSDL response\n" . $tr->incoming_payload);
4828  $this->appendDebug($tr->getDebug());
4829  // catch errors
4830  if ($err = $tr->getError()) {
4831  $errstr = 'HTTP ERROR: ' . $err;
4832  $this->debug($errstr);
4833  $this->setError($errstr);
4834  unset($tr);
4835  return false;
4836  }
4837  unset($tr);
4838  $this->debug("got WSDL URL");
4839  } else {
4840  // $wsdl is not http(s), so treat it as a file URL or plain file path
4841  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
4842  $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
4843  } else {
4844  $path = $wsdl;
4845  }
4846  $this->debug('getting WSDL file ' . $path);
4847  if ($fp = @fopen($path, 'r')) {
4848  $wsdl_string = '';
4849  while ($data = fread($fp, 32768)) {
4850  $wsdl_string .= $data;
4851  }
4852  fclose($fp);
4853  } else {
4854  $errstr = "Bad path to WSDL file $path";
4855  $this->debug($errstr);
4856  $this->setError($errstr);
4857  return false;
4858  }
4859  }
4860  $this->debug('Parse WSDL');
4861  // end new code added
4862  // Create an XML parser.
4863  $this->parser = xml_parser_create();
4864  // Set the options for parsing the XML data.
4865  // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
4866  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
4867  // Set the object for the parser.
4868  xml_set_object($this->parser, $this);
4869  // Set the element handlers for the parser.
4870  xml_set_element_handler($this->parser, 'start_element', 'end_element');
4871  xml_set_character_data_handler($this->parser, 'character_data');
4872  // Parse the XML file.
4873  if (!xml_parse($this->parser, $wsdl_string, true)) {
4874  // Display an error message.
4875  $errstr = sprintf(
4876  'XML error parsing WSDL from %s on line %d: %s',
4877  $wsdl,
4878  xml_get_current_line_number($this->parser),
4879  xml_error_string(xml_get_error_code($this->parser))
4880  );
4881  $this->debug($errstr);
4882  $this->debug("XML payload:\n" . $wsdl_string);
4883  $this->setError($errstr);
4884  return false;
4885  }
4886  // free the parser
4887  xml_parser_free($this->parser);
4888  $this->debug('Parsing WSDL done');
4889  // catch wsdl parse errors
4890  if ($this->getError()) {
4891  return false;
4892  }
4893  return true;
4894  }
4895 
4904  public function start_element($parser, $name, $attrs)
4905  {
4906  if ($this->status == 'schema') {
4907  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4908  $this->appendDebug($this->currentSchema->getDebug());
4909  $this->currentSchema->clearDebug();
4910  } elseif (preg_match('/schema$/', $name)) {
4911  $this->debug('Parsing WSDL schema');
4912  // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
4913  $this->status = 'schema';
4914  $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
4915  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4916  $this->appendDebug($this->currentSchema->getDebug());
4917  $this->currentSchema->clearDebug();
4918  } else {
4919  // position in the total number of elements, starting from 0
4920  $pos = $this->position++;
4921  $depth = $this->depth++;
4922  // set self as current value for this depth
4923  $this->depth_array[$depth] = $pos;
4924  $this->message[$pos] = array('cdata' => '');
4925  // process attributes
4926  if (count($attrs) > 0) {
4927  // register namespace declarations
4928  foreach ($attrs as $k => $v) {
4929  if (preg_match('/^xmlns/', $k)) {
4930  if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
4931  $this->namespaces[$ns_prefix] = $v;
4932  } else {
4933  $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
4934  }
4935  if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
4936  $this->XMLSchemaVersion = $v;
4937  $this->namespaces['xsi'] = $v . '-instance';
4938  }
4939  }
4940  }
4941  // expand each attribute prefix to its namespace
4942  foreach ($attrs as $k => $v) {
4943  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
4944  if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
4945  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
4946  }
4947  $eAttrs[$k] = $v;
4948  }
4949  $attrs = $eAttrs;
4950  } else {
4951  $attrs = array();
4952  }
4953  // get element prefix, namespace and name
4954  if (preg_match('/:/', $name)) {
4955  // get ns prefix
4956  $prefix = substr($name, 0, strpos($name, ':'));
4957  // get ns
4958  $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
4959  // get unqualified name
4960  $name = substr(strstr($name, ':'), 1);
4961  }
4962  // process attributes, expanding any prefixes to namespaces
4963  // find status, register data
4964  switch ($this->status) {
4965  case 'message':
4966  if ($name == 'part') {
4967  if (isset($attrs['type'])) {
4968  $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
4969  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
4970  }
4971  if (isset($attrs['element'])) {
4972  $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
4973  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
4974  }
4975  }
4976  break;
4977  case 'portType':
4978  switch ($name) {
4979  case 'operation':
4980  $this->currentPortOperation = $attrs['name'];
4981  $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
4982  if (isset($attrs['parameterOrder'])) {
4983  $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
4984  }
4985  break;
4986  case 'documentation':
4987  $this->documentation = true;
4988  break;
4989  // merge input/output data
4990  default:
4991  $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
4992  $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
4993  break;
4994  }
4995  break;
4996  case 'binding':
4997  switch ($name) {
4998  case 'binding':
4999  // get ns prefix
5000  if (isset($attrs['style'])) {
5001  $this->bindings[$this->currentBinding]['prefix'] = $prefix;
5002  }
5003  $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
5004  break;
5005  case 'header':
5006  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
5007  break;
5008  case 'operation':
5009  if (isset($attrs['soapAction'])) {
5010  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
5011  }
5012  if (isset($attrs['style'])) {
5013  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
5014  }
5015  if (isset($attrs['name'])) {
5016  $this->currentOperation = $attrs['name'];
5017  $this->debug("current binding operation: $this->currentOperation");
5018  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
5019  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
5020  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
5021  }
5022  break;
5023  case 'input':
5024  $this->opStatus = 'input';
5025  break;
5026  case 'output':
5027  $this->opStatus = 'output';
5028  break;
5029  case 'body':
5030  if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
5031  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
5032  } else {
5033  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
5034  }
5035  break;
5036  }
5037  break;
5038  case 'service':
5039  switch ($name) {
5040  case 'port':
5041  $this->currentPort = $attrs['name'];
5042  $this->debug('current port: ' . $this->currentPort);
5043  $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
5044 
5045  break;
5046  case 'address':
5047  $this->ports[$this->currentPort]['location'] = $attrs['location'];
5048  $this->ports[$this->currentPort]['bindingType'] = $namespace;
5049  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
5050  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
5051  break;
5052  }
5053  break;
5054  }
5055  // set status
5056  switch ($name) {
5057  case 'import':
5058  if (isset($attrs['location'])) {
5059  $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
5060  $this->debug('parsing import ' . $attrs['namespace'] . ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]) . ')');
5061  } else {
5062  $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
5063  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
5064  $this->namespaces['ns' . (count($this->namespaces)+1)] = $attrs['namespace'];
5065  }
5066  $this->debug('parsing import ' . $attrs['namespace'] . ' - [no location] (' . count($this->import[$attrs['namespace']]) . ')');
5067  }
5068  break;
5069  //wait for schema
5070  //case 'types':
5071  // $this->status = 'schema';
5072  // break;
5073  case 'message':
5074  $this->status = 'message';
5075  $this->messages[$attrs['name']] = array();
5076  $this->currentMessage = $attrs['name'];
5077  break;
5078  case 'portType':
5079  $this->status = 'portType';
5080  $this->portTypes[$attrs['name']] = array();
5081  $this->currentPortType = $attrs['name'];
5082  break;
5083  case "binding":
5084  if (isset($attrs['name'])) {
5085  // get binding name
5086  if (strpos($attrs['name'], ':')) {
5087  $this->currentBinding = $this->getLocalPart($attrs['name']);
5088  } else {
5089  $this->currentBinding = $attrs['name'];
5090  }
5091  $this->status = 'binding';
5092  $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
5093  $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
5094  }
5095  break;
5096  case 'service':
5097  $this->serviceName = $attrs['name'];
5098  $this->status = 'service';
5099  $this->debug('current service: ' . $this->serviceName);
5100  break;
5101  case 'definitions':
5102  foreach ($attrs as $name => $value) {
5103  $this->wsdl_info[$name] = $value;
5104  }
5105  break;
5106  }
5107  }
5108  }
5109 
5117  public function end_element($parser, $name)
5118  {
5119  // unset schema status
5120  if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) {
5121  $this->status = "";
5122  $this->appendDebug($this->currentSchema->getDebug());
5123  $this->currentSchema->clearDebug();
5124  $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
5125  $this->debug('Parsing WSDL schema done');
5126  }
5127  if ($this->status == 'schema') {
5128  $this->currentSchema->schemaEndElement($parser, $name);
5129  } else {
5130  // bring depth down a notch
5131  $this->depth--;
5132  }
5133  // end documentation
5134  if ($this->documentation) {
5135  //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
5136  //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
5137  $this->documentation = false;
5138  }
5139  }
5140 
5148  public function character_data($parser, $data)
5149  {
5150  $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
5151  if (isset($this->message[$pos]['cdata'])) {
5152  $this->message[$pos]['cdata'] .= $data;
5153  }
5154  if ($this->documentation) {
5155  $this->documentation .= $data;
5156  }
5157  }
5158 
5168  public function setCredentials($username, $password, $authtype = 'basic', $certRequest = array())
5169  {
5170  $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
5171  $this->appendDebug($this->varDump($certRequest));
5172  $this->username = $username;
5173  $this->password = $password;
5174  $this->authtype = $authtype;
5175  $this->certRequest = $certRequest;
5176  }
5177 
5178  public function getBindingData($binding)
5179  {
5180  if (is_array($this->bindings[$binding])) {
5181  return $this->bindings[$binding];
5182  }
5183  }
5184 
5192  public function getOperations($bindingType = 'soap')
5193  {
5194  $ops = array();
5195  if ($bindingType == 'soap') {
5196  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5197  } elseif ($bindingType == 'soap12') {
5198  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5199  }
5200  // loop thru ports
5201  foreach ($this->ports as $port => $portData) {
5202  // binding type of port matches parameter
5203  if ($portData['bindingType'] == $bindingType) {
5204  //$this->debug("getOperations for port $port");
5205  //$this->debug("port data: " . $this->varDump($portData));
5206  //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
5207  // merge bindings
5208  if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
5209  $ops = array_merge($ops, $this->bindings[ $portData['binding'] ]['operations']);
5210  }
5211  }
5212  }
5213  return $ops;
5214  }
5215 
5224  public function getOperationData($operation, $bindingType = 'soap')
5225  {
5226  if ($bindingType == 'soap') {
5227  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5228  } elseif ($bindingType == 'soap12') {
5229  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5230  }
5231  // loop thru ports
5232  foreach ($this->ports as $port => $portData) {
5233  // binding type of port matches parameter
5234  if ($portData['bindingType'] == $bindingType) {
5235  // get binding
5236  //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5237  foreach (array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
5238  // note that we could/should also check the namespace here
5239  if ($operation == $bOperation) {
5240  $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
5241  return $opData;
5242  }
5243  }
5244  }
5245  }
5246  }
5247 
5256  public function getOperationDataForSoapAction($soapAction, $bindingType = 'soap')
5257  {
5258  if ($bindingType == 'soap') {
5259  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5260  } elseif ($bindingType == 'soap12') {
5261  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5262  }
5263  // loop thru ports
5264  foreach ($this->ports as $port => $portData) {
5265  // binding type of port matches parameter
5266  if ($portData['bindingType'] == $bindingType) {
5267  // loop through operations for the binding
5268  foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5269  if ($opData['soapAction'] == $soapAction) {
5270  return $opData;
5271  }
5272  }
5273  }
5274  }
5275  }
5276 
5295  public function getTypeDef($type, $ns)
5296  {
5297  $this->debug("in getTypeDef: type=$type, ns=$ns");
5298  if ((! $ns) && isset($this->namespaces['tns'])) {
5299  $ns = $this->namespaces['tns'];
5300  $this->debug("in getTypeDef: type namespace forced to $ns");
5301  }
5302  if (!isset($this->schemas[$ns])) {
5303  foreach ($this->schemas as $ns0 => $schema0) {
5304  if (strcasecmp($ns, $ns0) == 0) {
5305  $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
5306  $ns = $ns0;
5307  break;
5308  }
5309  }
5310  }
5311  if (isset($this->schemas[$ns])) {
5312  $this->debug("in getTypeDef: have schema for namespace $ns");
5313  for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
5314  $xs = &$this->schemas[$ns][$i];
5315  $t = $xs->getTypeDef($type);
5316  //$this->appendDebug($xs->getDebug());
5317  //$xs->clearDebug();
5318  if ($t) {
5319  if (!isset($t['phpType'])) {
5320  // get info for type to tack onto the element
5321  $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
5322  $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
5323  $etype = $this->getTypeDef($uqType, $ns);
5324  if ($etype) {
5325  $this->debug("found type for [element] $type:");
5326  $this->debug($this->varDump($etype));
5327  if (isset($etype['phpType'])) {
5328  $t['phpType'] = $etype['phpType'];
5329  }
5330  if (isset($etype['elements'])) {
5331  $t['elements'] = $etype['elements'];
5332  }
5333  if (isset($etype['attrs'])) {
5334  $t['attrs'] = $etype['attrs'];
5335  }
5336  }
5337  }
5338  return $t;
5339  }
5340  }
5341  } else {
5342  $this->debug("in getTypeDef: do not have schema for namespace $ns");
5343  }
5344  return false;
5345  }
5346 
5352  public function webDescription()
5353  {
5354  global $HTTP_SERVER_VARS;
5355 
5356  if (isset($_SERVER)) {
5357  $PHP_SELF = $_SERVER['PHP_SELF'];
5358  } elseif (isset($HTTP_SERVER_VARS)) {
5359  $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
5360  } else {
5361  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
5362  }
5363  // begin-patch: https://mantis.ilias.de/view.php?id=28866
5364  $PHP_SELF = filter_var($PHP_SELF, FILTER_SANITIZE_STRING);
5365  // end-patch
5366 
5367  $b = '
5368  <html><head><title>NuSOAP: ' . $this->serviceName . '</title>
5369  <style type="text/css">
5370  body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
5371  p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
5372  pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
5373  ul { margin-top: 10px; margin-left: 20px; }
5374  li { list-style-type: none; margin-top: 10px; color: #000000; }
5375  .content{
5376  margin-left: 0px; padding-bottom: 2em; }
5377  .nav {
5378  padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
5379  margin-top: 10px; margin-left: 0px; color: #000000;
5380  background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
5381  .title {
5382  font-family: arial; font-size: 26px; color: #ffffff;
5383  background-color: #999999; width: 105%; margin-left: 0px;
5384  padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
5385  .hidden {
5386  position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
5387  font-family: arial; overflow: hidden; width: 600;
5388  padding: 20px; font-size: 10px; background-color: #999999;
5389  layer-background-color:#FFFFFF; }
5390  a,a:active { color: charcoal; font-weight: bold; }
5391  a:visited { color: #666666; font-weight: bold; }
5392  a:hover { color: cc3300; font-weight: bold; }
5393  </style>
5394  <script language="JavaScript" type="text/javascript">
5395  <!--
5396  // POP-UP CAPTIONS...
5397  function lib_bwcheck(){ //Browsercheck (needed)
5398  this.ver=navigator.appVersion
5399  this.agent=navigator.userAgent
5400  this.dom=document.getElementById?1:0
5401  this.opera5=this.agent.indexOf("Opera 5")>-1
5402  this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
5403  this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
5404  this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
5405  this.ie=this.ie4||this.ie5||this.ie6
5406  this.mac=this.agent.indexOf("Mac")>-1
5407  this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
5408  this.ns4=(document.layers && !this.dom)?1:0;
5409  this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
5410  return this
5411  }
5412  var bw = new lib_bwcheck()
5413  //Makes crossbrowser object.
5414  function makeObj(obj){
5415  this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
5416  if(!this.evnt) return false
5417  this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
5418  this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
5419  this.writeIt=b_writeIt;
5420  return this
5421  }
5422  // A unit of measure that will be added when setting the position of a layer.
5423  //var px = bw.ns4||window.opera?"":"px";
5424  function b_writeIt(text){
5425  if (bw.ns4){this.wref.write(text);this.wref.close()}
5426  else this.wref.innerHTML = text
5427  }
5428  //Shows the messages
5429  var oDesc;
5430  function popup(divid){
5431  if(oDesc = new makeObj(divid)){
5432  oDesc.css.visibility = "visible"
5433  }
5434  }
5435  function popout(){ // Hides message
5436  if(oDesc) oDesc.css.visibility = "hidden"
5437  }
5438  //-->
5439  </script>
5440  </head>
5441  <body>
5442  <div class=content>
5443  <br><br>
5444  <div class=title>' . $this->serviceName . '</div>
5445  <div class=nav>
5446  <p>View the <a href="' . $PHP_SELF . '?wsdl">WSDL</a> for the service.
5447  Click on an operation name to view it&apos;s details.</p>
5448  <ul>';
5449  foreach ($this->getOperations() as $op => $data) {
5450  // begin-patch: https://mantis.ilias.de/view.php?id=28866
5451  if (isset($data['endpoint'])) {
5452  $data['endpoint'] = filter_var($data['endpoint'], FILTER_SANITIZE_STRING);
5453  }
5454  // end-patch
5455  $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
5456  // create hidden div
5457  $b .= "<div id='$op' class='hidden'>
5458  <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
5459  foreach ($data as $donnie => $marie) { // loop through opdata
5460  if ($donnie == 'input' || $donnie == 'output') { // show input/output data
5461  $b .= "<font color='white'>" . ucfirst($donnie) . ':</font><br>';
5462  foreach ($marie as $captain => $tenille) { // loop through data
5463  if ($captain == 'parts') { // loop thru parts
5464  $b .= "&nbsp;&nbsp;$captain:<br>";
5465  //if(is_array($tenille)){
5466  foreach ($tenille as $joanie => $chachi) {
5467  $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
5468  }
5469  //}
5470  } else {
5471  $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
5472  }
5473  }
5474  } else {
5475  $b .= "<font color='white'>" . ucfirst($donnie) . ":</font> $marie<br>";
5476  }
5477  }
5478  $b .= '</div>';
5479  }
5480  $b .= '
5481  <ul>
5482  </div>
5483  </div></body></html>';
5484  return $b;
5485  }
5486 
5494  public function serialize($debug = 0)
5495  {
5496  $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
5497  $xml .= "\n<definitions";
5498  foreach ($this->namespaces as $k => $v) {
5499  $xml .= " xmlns:$k=\"$v\"";
5500  }
5501  // 10.9.02 - add poulter fix for wsdl and tns declarations
5502  if (isset($this->namespaces['wsdl'])) {
5503  $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
5504  }
5505  if (isset($this->namespaces['tns'])) {
5506  $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
5507  }
5508  $xml .= '>';
5509  // imports
5510  if (sizeof($this->import) > 0) {
5511  foreach ($this->import as $ns => $list) {
5512  foreach ($list as $ii) {
5513  if ($ii['location'] != '') {
5514  $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
5515  } else {
5516  $xml .= '<import namespace="' . $ns . '" />';
5517  }
5518  }
5519  }
5520  }
5521  // types
5522  if (count($this->schemas)>=1) {
5523  $xml .= "\n<types>\n";
5524  foreach ($this->schemas as $ns => $list) {
5525  foreach ($list as $xs) {
5526  $xml .= $xs->serializeSchema();
5527  }
5528  }
5529  $xml .= '</types>';
5530  }
5531  // messages
5532  if (count($this->messages) >= 1) {
5533  foreach ($this->messages as $msgName => $msgParts) {
5534  $xml .= "\n<message name=\"" . $msgName . '">';
5535  if (is_array($msgParts)) {
5536  foreach ($msgParts as $partName => $partType) {
5537  // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
5538  if (strpos($partType, ':')) {
5539  $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
5540  } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
5541  // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
5542  $typePrefix = 'xsd';
5543  } else {
5544  foreach ($this->typemap as $ns => $types) {
5545  if (isset($types[$partType])) {
5546  $typePrefix = $this->getPrefixFromNamespace($ns);
5547  }
5548  }
5549  if (!isset($typePrefix)) {
5550  die("$partType has no namespace!");
5551  }
5552  }
5553  $ns = $this->getNamespaceFromPrefix($typePrefix);
5554  $localPart = $this->getLocalPart($partType);
5555  $typeDef = $this->getTypeDef($localPart, $ns);
5556  if (($typeDef['typeClass'] ?? '') == 'element') {
5557  $elementortype = 'element';
5558  if (substr($localPart, -1) == '^') {
5559  $localPart = substr($localPart, 0, -1);
5560  }
5561  } else {
5562  $elementortype = 'type';
5563  }
5564  $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
5565  }
5566  }
5567  $xml .= '</message>';
5568  }
5569  }
5570  // bindings & porttypes
5571  if (count($this->bindings) >= 1) {
5572  $binding_xml = '';
5573  $portType_xml = '';
5574  foreach ($this->bindings as $bindingName => $attrs) {
5575  $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
5576  $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
5577  $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
5578  foreach ($attrs['operations'] as $opName => $opParts) {
5579  $binding_xml .= "\n" . ' <operation name="' . $opName . '">';
5580  $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="' . $opParts['style'] . '"/>';
5581  if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
5582  $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
5583  } else {
5584  $enc_style = '';
5585  }
5586  $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
5587  if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
5588  $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
5589  } else {
5590  $enc_style = '';
5591  }
5592  $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
5593  $binding_xml .= "\n" . ' </operation>';
5594  $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"';
5595  if (isset($opParts['parameterOrder'])) {
5596  $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
5597  }
5598  $portType_xml .= '>';
5599  if (isset($opParts['documentation']) && $opParts['documentation'] != '') {
5600  $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
5601  }
5602  $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>';
5603  $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>';
5604  $portType_xml .= "\n" . ' </operation>';
5605  }
5606  $portType_xml .= "\n" . '</portType>';
5607  $binding_xml .= "\n" . '</binding>';
5608  }
5609  $xml .= $portType_xml . $binding_xml;
5610  }
5611  // services
5612  $xml .= "\n<service name=\"" . $this->serviceName . '">';
5613  $has_client = isset($_GET['client_id']);
5614  if (count($this->ports) >= 1) {
5615  foreach ($this->ports as $pName => $attrs) {
5616  $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5617  $address = $attrs['location'] . ($debug || $has_client ? "?" : "")
5618  . ($debug ? 'debug=1' : '') . ($debug && $has_client ? "&amp;" : "")
5619  . ($has_client ? 'client_id=' . $_GET['client_id'] : '');
5620  $xml .= "\n" . ' <soap:address location="' . $address . '"/>';
5621  $xml .= "\n" . ' </port>';
5622  }
5623  }
5624 
5625  $xml .= "\n" . '</service>';
5626  return $xml . "\n</definitions>";
5627  }
5628 
5638  public function parametersMatchWrapped($type, &$parameters)
5639  {
5640  $this->debug("in parametersMatchWrapped type=$type, parameters=");
5641  $this->appendDebug($this->varDump($parameters));
5642 
5643  // split type into namespace:unqualified-type
5644  if (strpos($type, ':')) {
5645  $uqType = substr($type, strrpos($type, ':') + 1);
5646  $ns = substr($type, 0, strrpos($type, ':'));
5647  $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
5648  if ($this->getNamespaceFromPrefix($ns)) {
5649  $ns = $this->getNamespaceFromPrefix($ns);
5650  $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
5651  }
5652  } else {
5653  // TODO: should the type be compared to types in XSD, and the namespace
5654  // set to XSD if the type matches?
5655  $this->debug("in parametersMatchWrapped: No namespace for type $type");
5656  $ns = '';
5657  $uqType = $type;
5658  }
5659 
5660  // get the type information
5661  if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
5662  $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
5663  return false;
5664  }
5665  $this->debug("in parametersMatchWrapped: found typeDef=");
5666  $this->appendDebug($this->varDump($typeDef));
5667  if (substr($uqType, -1) == '^') {
5668  $uqType = substr($uqType, 0, -1);
5669  }
5670  $phpType = $typeDef['phpType'];
5671  $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
5672  $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
5673 
5674  // we expect a complexType or element of complexType
5675  if ($phpType != 'struct') {
5676  $this->debug("in parametersMatchWrapped: not a struct");
5677  return false;
5678  }
5679 
5680  // see whether the parameter names match the elements
5681  if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
5682  $elements = 0;
5683  $matches = 0;
5684  $change = false;
5685  if ($this->isArraySimpleOrStruct($parameters) == 'arraySimple' && count($parameters) == count($typeDef['elements'])) {
5686  $this->debug("in parametersMatchWrapped: (wrapped return value kludge) correct number of elements in simple array, so change array and wrap");
5687  $change = true;
5688  }
5689  foreach ($typeDef['elements'] as $name => $attrs) {
5690  if ($change) {
5691  $this->debug("in parametersMatchWrapped: change parameter $element to name $name");
5692  $parameters[$name] = $parameters[$elements];
5693  unset($parameters[$elements]);
5694  $matches++;
5695  } elseif (isset($parameters[$name])) {
5696  $this->debug("in parametersMatchWrapped: have parameter named $name");
5697  $matches++;
5698  } else {
5699  $this->debug("in parametersMatchWrapped: do not have parameter named $name");
5700  }
5701  $elements++;
5702  }
5703 
5704  $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
5705  if ($matches == 0) {
5706  return false;
5707  }
5708  return true;
5709  }
5710 
5711  // since there are no elements for the type, if the user passed no
5712  // parameters, the parameters match wrapped.
5713  $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
5714  return count($parameters) == 0;
5715  }
5716 
5732  public function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap')
5733  {
5734  $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
5735  $this->appendDebug('parameters=' . $this->varDump($parameters));
5736 
5737  if ($direction != 'input' && $direction != 'output') {
5738  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5739  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5740  return false;
5741  }
5742  if (!$opData = $this->getOperationData($operation, $bindingType)) {
5743  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5744  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5745  return false;
5746  }
5747  $this->debug('in serializeRPCParameters: opData:');
5748  $this->appendDebug($this->varDump($opData));
5749 
5750  // Get encoding style for output and set to current
5751  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5752  if (($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5753  $encodingStyle = $opData['output']['encodingStyle'];
5754  $enc_style = $encodingStyle;
5755  }
5756 
5757  // set input params
5758  $xml = '';
5759  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5760  $parts = &$opData[$direction]['parts'];
5761  $part_count = sizeof($parts);
5762  $style = $opData['style'];
5763  $use = $opData[$direction]['use'];
5764  $this->debug("have $part_count part(s) to serialize using $style/$use");
5765  if (is_array($parameters)) {
5766  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5767  $parameter_count = count($parameters);
5768  $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
5769  // check for Microsoft-style wrapped parameters
5770  if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
5771  $this->debug('check whether the caller has wrapped the parameters');
5772  if ((($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) || ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1)) {
5773  $this->debug('check whether caller\'s parameters match the wrapped ones');
5774  if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
5775  $this->debug('wrap the parameters for the caller');
5776  $parameters = array('parameters' => $parameters);
5777  $parameter_count = 1;
5778  }
5779  }
5780  }
5781  foreach ($parts as $name => $type) {
5782  $this->debug("serializing part $name of type $type");
5783  // Track encoding style
5784  if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5785  $encodingStyle = $opData[$direction]['encodingStyle'];
5786  $enc_style = $encodingStyle;
5787  } else {
5788  $enc_style = false;
5789  }
5790  // NOTE: add error handling here
5791  // if serializeType returns false, then catch global error and fault
5792  if ($parametersArrayType == 'arraySimple') {
5793  $p = array_shift($parameters);
5794  $this->debug('calling serializeType w/indexed param');
5795  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5796  } elseif (isset($parameters[$name])) {
5797  $this->debug('calling serializeType w/named param');
5798  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5799  } else {
5800  // TODO: only send nillable
5801  $this->debug('calling serializeType w/null param');
5802  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5803  }
5804  }
5805  } else {
5806  $this->debug('no parameters passed.');
5807  }
5808  }
5809  $this->debug("serializeRPCParameters returning: $xml");
5810  return $xml;
5811  }
5812 
5827  public function serializeParameters($operation, $direction, $parameters)
5828  {
5829  $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
5830  $this->appendDebug('parameters=' . $this->varDump($parameters));
5831 
5832  if ($direction != 'input' && $direction != 'output') {
5833  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5834  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5835  return false;
5836  }
5837  if (!$opData = $this->getOperationData($operation)) {
5838  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
5839  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
5840  return false;
5841  }
5842  $this->debug('opData:');
5843  $this->appendDebug($this->varDump($opData));
5844 
5845  // Get encoding style for output and set to current
5846  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5847  if (($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5848  $encodingStyle = $opData['output']['encodingStyle'];
5849  $enc_style = $encodingStyle;
5850  }
5851 
5852  // set input params
5853  $xml = '';
5854  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5855  $use = $opData[$direction]['use'];
5856  $this->debug("use=$use");
5857  $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
5858  if (is_array($parameters)) {
5859  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5860  $this->debug('have ' . $parametersArrayType . ' parameters');
5861  foreach ($opData[$direction]['parts'] as $name => $type) {
5862  $this->debug('serializing part "' . $name . '" of type "' . $type . '"');
5863  // Track encoding style
5864  if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5865  $encodingStyle = $opData[$direction]['encodingStyle'];
5866  $enc_style = $encodingStyle;
5867  } else {
5868  $enc_style = false;
5869  }
5870  // NOTE: add error handling here
5871  // if serializeType returns false, then catch global error and fault
5872  if ($parametersArrayType == 'arraySimple') {
5873  $p = array_shift($parameters);
5874  $this->debug('calling serializeType w/indexed param');
5875  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5876  } elseif (isset($parameters[$name])) {
5877  $this->debug('calling serializeType w/named param');
5878  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5879  } else {
5880  // TODO: only send nillable
5881  $this->debug('calling serializeType w/null param');
5882  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5883  }
5884  }
5885  } else {
5886  $this->debug('no parameters passed.');
5887  }
5888  }
5889  $this->debug("serializeParameters returning: $xml");
5890  return $xml;
5891  }
5892 
5905  public function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
5906  {
5907  $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
5908  $this->appendDebug("value=" . $this->varDump($value));
5909  if ($use == 'encoded' && $encodingStyle) {
5910  $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
5911  }
5912 
5913  // if a soapval has been supplied, let its type override the WSDL
5914  if (is_object($value) && get_class($value) == 'soapval') {
5915  if ($value->type_ns) {
5916  $type = $value->type_ns . ':' . $value->type;
5917  $forceType = true;
5918  $this->debug("in serializeType: soapval overrides type to $type");
5919  } elseif ($value->type) {
5920  $type = $value->type;
5921  $forceType = true;
5922  $this->debug("in serializeType: soapval overrides type to $type");
5923  } else {
5924  $forceType = false;
5925  $this->debug("in serializeType: soapval does not override type");
5926  }
5927  $attrs = $value->attributes;
5928  $value = $value->value;
5929  $this->debug("in serializeType: soapval overrides value to $value");
5930  if ($attrs) {
5931  if (!is_array($value)) {
5932  $value['!'] = $value;
5933  }
5934  foreach ($attrs as $n => $v) {
5935  $value['!' . $n] = $v;
5936  }
5937  $this->debug("in serializeType: soapval provides attributes");
5938  }
5939  } else {
5940  $forceType = false;
5941  }
5942 
5943  $xml = '';
5944  if (strpos($type, ':')) {
5945  $uqType = substr($type, strrpos($type, ':') + 1);
5946  $ns = substr($type, 0, strrpos($type, ':'));
5947  $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
5948  if ($this->getNamespaceFromPrefix($ns)) {
5949  $ns = $this->getNamespaceFromPrefix($ns);
5950  $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
5951  }
5952 
5953  if ($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/') {
5954  $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
5955  if ($unqualified && $use == 'literal') {
5956  $elementNS = " xmlns=\"\"";
5957  } else {
5958  $elementNS = '';
5959  }
5960  if (is_null($value)) {
5961  if ($use == 'literal') {
5962  // TODO: depends on minOccurs
5963  $xml = "<$name$elementNS/>";
5964  } else {
5965  // TODO: depends on nillable, which should be checked before calling this method
5966  $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5967  }
5968  $this->debug("in serializeType: returning: $xml");
5969  return $xml;
5970  }
5971  if ($uqType == 'Array') {
5972  // JBoss/Axis does this sometimes
5973  return $this->serialize_val($value, $name, false, false, false, false, $use);
5974  }
5975  if ($uqType == 'boolean') {
5976  if ((is_string($value) && $value == 'false') || (! $value)) {
5977  $value = 'false';
5978  } else {
5979  $value = 'true';
5980  }
5981  }
5982  if ($uqType == 'string' && gettype($value) == 'string') {
5983  $value = $this->expandEntities($value);
5984  }
5985  if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
5986  $value = sprintf("%.0lf", $value);
5987  }
5988  // it's a scalar
5989  // TODO: what about null/nil values?
5990  // check type isn't a custom type extending xmlschema namespace
5991  if (!$this->getTypeDef($uqType, $ns)) {
5992  if ($use == 'literal') {
5993  if ($forceType) {
5994  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
5995  } else {
5996  $xml = "<$name$elementNS>$value</$name>";
5997  }
5998  } else {
5999  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6000  }
6001  $this->debug("in serializeType: returning: $xml");
6002  return $xml;
6003  }
6004  $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
6005  } elseif ($ns == 'http://xml.apache.org/xml-soap') {
6006  $this->debug('in serializeType: appears to be Apache SOAP type');
6007  if ($uqType == 'Map') {
6008  $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
6009  if (! $tt_prefix) {
6010  $this->debug('in serializeType: Add namespace for Apache SOAP type');
6011  $tt_prefix = 'ns' . rand(1000, 9999);
6012  $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
6013  // force this to be added to usedNamespaces
6014  $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
6015  }
6016  $contents = '';
6017  foreach ($value as $k => $v) {
6018  $this->debug("serializing map element: key $k, value $v");
6019  $contents .= '<item>';
6020  $contents .= $this->serialize_val($k, 'key', false, false, false, false, $use);
6021  $contents .= $this->serialize_val($v, 'value', false, false, false, false, $use);
6022  $contents .= '</item>';
6023  }
6024  if ($use == 'literal') {
6025  if ($forceType) {
6026  $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
6027  } else {
6028  $xml = "<$name>$contents</$name>";
6029  }
6030  } else {
6031  $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
6032  }
6033  $this->debug("in serializeType: returning: $xml");
6034  return $xml;
6035  }
6036  $this->debug('in serializeType: Apache SOAP type, but only support Map');
6037  }
6038  } else {
6039  // TODO: should the type be compared to types in XSD, and the namespace
6040  // set to XSD if the type matches?
6041  $this->debug("in serializeType: No namespace for type $type");
6042  $ns = '';
6043  $uqType = $type;
6044  }
6045  if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
6046  $this->setError("$type ($uqType) is not a supported type.");
6047  $this->debug("in serializeType: $type ($uqType) is not a supported type.");
6048  return false;
6049  } else {
6050  $this->debug("in serializeType: found typeDef");
6051  $this->appendDebug('typeDef=' . $this->varDump($typeDef));
6052  if (substr($uqType, -1) == '^') {
6053  $uqType = substr($uqType, 0, -1);
6054  }
6055  }
6056  $phpType = $typeDef['phpType'];
6057  $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''));
6058  // if php type == struct, map value to the <all> element names
6059  if ($phpType == 'struct') {
6060  if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
6061  $elementName = $uqType;
6062  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6063  $elementNS = " xmlns=\"$ns\"";
6064  } else {
6065  $elementNS = " xmlns=\"\"";
6066  }
6067  } else {
6068  $elementName = $name;
6069  if ($unqualified) {
6070  $elementNS = " xmlns=\"\"";
6071  } else {
6072  $elementNS = '';
6073  }
6074  }
6075  if (is_null($value)) {
6076  if ($use == 'literal') {
6077  // TODO: depends on minOccurs
6078  $xml = "<$elementName$elementNS/>";
6079  } else {
6080  $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
6081  }
6082  $this->debug("in serializeType: returning: $xml");
6083  return $xml;
6084  }
6085  if (is_object($value)) {
6086  $value = get_object_vars($value);
6087  }
6088  if (is_array($value)) {
6089  $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6090  if ($use == 'literal') {
6091  if ($forceType) {
6092  $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
6093  } else {
6094  $xml = "<$elementName$elementNS$elementAttrs>";
6095  }
6096  } else {
6097  $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
6098  }
6099 
6100  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6101  $xml .= "</$elementName>";
6102  } else {
6103  $this->debug("in serializeType: phpType is struct, but value is not an array");
6104  $this->setError("phpType is struct, but value is not an array: see debug output for details");
6105  $xml = '';
6106  }
6107  } elseif ($phpType == 'array') {
6108  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6109  $elementNS = " xmlns=\"$ns\"";
6110  } else {
6111  if ($unqualified) {
6112  $elementNS = " xmlns=\"\"";
6113  } else {
6114  $elementNS = '';
6115  }
6116  }
6117  if (is_null($value)) {
6118  if ($use == 'literal') {
6119  // TODO: depends on minOccurs
6120  $xml = "<$name$elementNS/>";
6121  } else {
6122  $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
6123  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
6124  ":Array\" " .
6125  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
6126  ':arrayType="' .
6127  $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
6128  ':' .
6129  $this->getLocalPart($typeDef['arrayType']) . "[0]\"/>";
6130  }
6131  $this->debug("in serializeType: returning: $xml");
6132  return $xml;
6133  }
6134  if (isset($typeDef['multidimensional'])) {
6135  $nv = array();
6136  foreach ($value as $v) {
6137  $cols = ',' . sizeof($v);
6138  $nv = array_merge($nv, $v);
6139  }
6140  $value = $nv;
6141  } else {
6142  $cols = '';
6143  }
6144  if (is_array($value) && sizeof($value) >= 1) {
6145  $rows = sizeof($value);
6146  $contents = '';
6147  foreach ($value as $k => $v) {
6148  $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
6149  //if (strpos($typeDef['arrayType'], ':') ) {
6150  if (!in_array($typeDef['arrayType'], $this->typemap['http://www.w3.org/2001/XMLSchema'])) {
6151  $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
6152  } else {
6153  $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
6154  }
6155  }
6156  } else {
6157  $rows = 0;
6158  $contents = null;
6159  }
6160  // TODO: for now, an empty value will be serialized as a zero element
6161  // array. Revisit this when coding the handling of null/nil values.
6162  if ($use == 'literal') {
6163  $xml = "<$name$elementNS>"
6164  . $contents
6165  . "</$name>";
6166  } else {
6167  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ':Array" ' .
6168  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6169  . ':arrayType="'
6170  . $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
6171  . ":" . $this->getLocalPart($typeDef['arrayType']) . "[$rows$cols]\">"
6172  . $contents
6173  . "</$name>";
6174  }
6175  } elseif ($phpType == 'scalar') {
6176  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6177  $elementNS = " xmlns=\"$ns\"";
6178  } else {
6179  if ($unqualified) {
6180  $elementNS = " xmlns=\"\"";
6181  } else {
6182  $elementNS = '';
6183  }
6184  }
6185  if ($use == 'literal') {
6186  if ($forceType) {
6187  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6188  } else {
6189  $xml = "<$name$elementNS>$value</$name>";
6190  }
6191  } else {
6192  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6193  }
6194  }
6195  $this->debug("in serializeType: returning: $xml");
6196  return $xml;
6197  }
6198 
6209  public function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType)
6210  {
6211  $xml = '';
6212  if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
6213  $this->debug("serialize attributes for XML Schema type $ns:$uqType");
6214  if (is_array($value)) {
6215  $xvalue = $value;
6216  } elseif (is_object($value)) {
6217  $xvalue = get_object_vars($value);
6218  } else {
6219  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6220  $xvalue = array();
6221  }
6222  foreach ($typeDef['attrs'] as $aName => $attrs) {
6223  if (isset($xvalue['!' . $aName])) {
6224  $xname = '!' . $aName;
6225  $this->debug("value provided for attribute $aName with key $xname");
6226  } elseif (isset($xvalue[$aName])) {
6227  $xname = $aName;
6228  $this->debug("value provided for attribute $aName with key $xname");
6229  } elseif (isset($attrs['default'])) {
6230  $xname = '!' . $aName;
6231  $xvalue[$xname] = $attrs['default'];
6232  $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
6233  } else {
6234  $xname = '';
6235  $this->debug("no value provided for attribute $aName");
6236  }
6237  if ($xname) {
6238  $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
6239  }
6240  }
6241  } else {
6242  $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
6243  }
6244  if (isset($typeDef['extensionBase'])) {
6245  $ns = $this->getPrefix($typeDef['extensionBase']);
6246  $uqType = $this->getLocalPart($typeDef['extensionBase']);
6247  if ($this->getNamespaceFromPrefix($ns)) {
6248  $ns = $this->getNamespaceFromPrefix($ns);
6249  }
6250  if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6251  $this->debug("serialize attributes for extension base $ns:$uqType");
6252  $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6253  } else {
6254  $this->debug("extension base $ns:$uqType is not a supported type");
6255  }
6256  }
6257  return $xml;
6258  }
6259 
6272  public function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false)
6273  {
6274  $xml = '';
6275  if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6276  $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
6277  if (is_array($value)) {
6278  $xvalue = $value;
6279  } elseif (is_object($value)) {
6280  $xvalue = get_object_vars($value);
6281  } else {
6282  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6283  $xvalue = array();
6284  }
6285  // toggle whether all elements are present - ideally should validate against schema
6286  if (count($typeDef['elements']) != count($xvalue)) {
6287  $optionals = true;
6288  }
6289  foreach ($typeDef['elements'] as $eName => $attrs) {
6290  if (!isset($xvalue[$eName])) {
6291  if (isset($attrs['default'])) {
6292  $xvalue[$eName] = $attrs['default'];
6293  $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
6294  }
6295  }
6296  // if user took advantage of a minOccurs=0, then only serialize named parameters
6297  if (isset($optionals)
6298  && (!isset($xvalue[$eName]))
6299  && ((!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
6300  ) {
6301  if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
6302  $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
6303  }
6304  // do nothing
6305  $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
6306  } else {
6307  // get value
6308  if (isset($xvalue[$eName])) {
6309  $v = $xvalue[$eName];
6310  } else {
6311  $v = null;
6312  }
6313  if (isset($attrs['form'])) {
6314  $unqualified = ($attrs['form'] == 'unqualified');
6315  } else {
6316  $unqualified = false;
6317  }
6318  if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
6319  $vv = $v;
6320  foreach ($vv as $k => $v) {
6321  if (isset($attrs['type']) || isset($attrs['ref'])) {
6322  // serialize schema-defined type
6323  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6324  } else {
6325  // serialize generic type (can this ever really happen?)
6326  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6327  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6328  }
6329  }
6330  } else {
6331  if (isset($attrs['type']) || isset($attrs['ref'])) {
6332  // serialize schema-defined type
6333  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6334  } else {
6335  // serialize generic type (can this ever really happen?)
6336  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6337  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6338  }
6339  }
6340  }
6341  }
6342  } else {
6343  $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
6344  }
6345  if (isset($typeDef['extensionBase'])) {
6346  $ns = $this->getPrefix($typeDef['extensionBase']);
6347  $uqType = $this->getLocalPart($typeDef['extensionBase']);
6348  if ($this->getNamespaceFromPrefix($ns)) {
6349  $ns = $this->getNamespaceFromPrefix($ns);
6350  }
6351  if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6352  $this->debug("serialize elements for extension base $ns:$uqType");
6353  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6354  } else {
6355  $this->debug("extension base $ns:$uqType is not a supported type");
6356  }
6357  }
6358  return $xml;
6359  }
6360 
6375  public function addComplexType($name, $typeClass='complexType', $phpType='array', $compositor='', $restrictionBase='', $elements=array(), $attrs=array(), $arrayType='')
6376  {
6377  if (count($elements) > 0) {
6378  $eElements = array();
6379  foreach ($elements as $n => $e) {
6380  // expand each element
6381  $ee = array();
6382  foreach ($e as $k => $v) {
6383  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
6384  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
6385  $ee[$k] = $v;
6386  }
6387  $eElements[$n] = $ee;
6388  }
6389  $elements = $eElements;
6390  }
6391 
6392  if (count($attrs) > 0) {
6393  foreach ($attrs as $n => $a) {
6394  // expand each attribute
6395  foreach ($a as $k => $v) {
6396  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
6397  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
6398  $aa[$k] = $v;
6399  }
6400  $eAttrs[$n] = $aa;
6401  }
6402  $attrs = $eAttrs;
6403  }
6404 
6405  $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6406  $arrayType = strpos($arrayType, ':') ? $this->expandQname($arrayType) : $arrayType;
6407 
6408  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6409  $this->schemas[$typens][0]->addComplexType($name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType);
6410  }
6411 
6423  public function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array())
6424  {
6425  $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6426 
6427  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6428  $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
6429  }
6430 
6438  public function addElement($attrs)
6439  {
6440  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6441  $this->schemas[$typens][0]->addElement($attrs);
6442  }
6443 
6458  public function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = '')
6459  {
6460  if ($use == 'encoded' && $encodingStyle == '') {
6461  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6462  }
6463 
6464  if ($style == 'document') {
6465  $elements = array();
6466  foreach ($in as $n => $t) {
6467  $elements[$n] = array('name' => $n, 'type' => $t);
6468  }
6469  $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
6470  $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
6471  $in = array('parameters' => 'tns:' . $name . '^');
6472 
6473  $elements = array();
6474  foreach ($out as $n => $t) {
6475  $elements[$n] = array('name' => $n, 'type' => $t);
6476  }
6477  $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
6478  $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
6479  $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
6480  }
6481 
6482  // get binding
6483  $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
6484  array(
6485  'name' => $name,
6486  'binding' => $this->serviceName . 'Binding',
6487  'endpoint' => $this->endpoint,
6488  'soapAction' => $soapaction,
6489  'style' => $style,
6490  'input' => array(
6491  'use' => $use,
6492  'namespace' => $namespace,
6493  'encodingStyle' => $encodingStyle,
6494  'message' => $name . 'Request',
6495  'parts' => $in),
6496  'output' => array(
6497  'use' => $use,
6498  'namespace' => $namespace,
6499  'encodingStyle' => $encodingStyle,
6500  'message' => $name . 'Response',
6501  'parts' => $out),
6502  'namespace' => $namespace,
6503  'transport' => 'http://schemas.xmlsoap.org/soap/http',
6504  'documentation' => $documentation);
6505  // add portTypes
6506  // add messages
6507  if ($in) {
6508  foreach ($in as $pName => $pType) {
6509  if (strpos($pType, ':')) {
6510  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ":" . $this->getLocalPart($pType);
6511  }
6512  $this->messages[$name . 'Request'][$pName] = $pType;
6513  }
6514  } else {
6515  $this->messages[$name . 'Request']= '0';
6516  }
6517  if ($out) {
6518  foreach ($out as $pName => $pType) {
6519  if (strpos($pType, ':')) {
6520  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ":" . $this->getLocalPart($pType);
6521  }
6522  $this->messages[$name . 'Response'][$pName] = $pType;
6523  }
6524  } else {
6525  $this->messages[$name . 'Response']= '0';
6526  }
6527  return true;
6528  }
6529 }
6530 ?><?php
6531 
6532 
6533 
6543 class nusoap_parser extends nusoap_base
6544 {
6545  public $xml = '';
6546  public $xml_encoding = '';
6547  public $method = '';
6548  public $root_struct = '';
6549  public $root_struct_name = '';
6550  public $root_struct_namespace = '';
6551  public $root_header = '';
6552  public $document = ''; // incoming SOAP body (text)
6553  // determines where in the message we are (envelope,header,body,method)
6554  public $status = '';
6555  public $position = 0;
6556  public $depth = 0;
6557  public $default_namespace = '';
6558  public $namespaces = array();
6559  public $message = array();
6560  public $parent = '';
6561  public $fault = false;
6562  public $fault_code = '';
6563  public $fault_str = '';
6564  public $fault_detail = '';
6565  public $depth_array = array();
6566  public $debug_flag = true;
6567  public $soapresponse = null; // parsed SOAP Body
6568  public $soapheader = null; // parsed SOAP Header
6569  public $responseHeaders = ''; // incoming SOAP headers (text)
6570  public $body_position = 0;
6571  // for multiref parsing:
6572  // array of id => pos
6573  public $ids = array();
6574  // array of id => hrefs => pos
6575  public $multirefs = array();
6576  // toggle for auto-decoding element content
6577  public $decode_utf8 = true;
6578 
6588  public function __construct($xml, $encoding='UTF-8', $method='', $decode_utf8=true)
6589  {
6591  $this->xml = $xml;
6592  $this->xml_encoding = $encoding;
6593  $this->method = $method;
6594  $this->decode_utf8 = $decode_utf8;
6595 
6596  // Check whether content has been read.
6597  if (!empty($xml)) {
6598  // Check XML encoding
6599  $pos_xml = strpos($xml, '<?xml');
6600  if ($pos_xml !== false) {
6601  $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
6602  if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
6603  $xml_encoding = $res[1];
6604  if (strtoupper($xml_encoding) != $encoding) {
6605  $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
6606  $this->debug($err);
6607  if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
6608  $this->setError($err);
6609  return;
6610  }
6611  // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
6612  } else {
6613  $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
6614  }
6615  } else {
6616  $this->debug('No encoding specified in XML declaration');
6617  }
6618  } else {
6619  $this->debug('No XML declaration');
6620  }
6621  $this->debug('Entering nusoap_parser(), length=' . strlen($xml) . ', encoding=' . $encoding);
6622  // Create an XML parser - why not xml_parser_create_ns?
6623  $this->parser = xml_parser_create($this->xml_encoding);
6624  // Set the options for parsing the XML data.
6625  //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
6626  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
6627  xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
6628  // Set the object for the parser.
6629  xml_set_object($this->parser, $this);
6630  // Set the element handlers for the parser.
6631  xml_set_element_handler($this->parser, 'start_element', 'end_element');
6632  xml_set_character_data_handler($this->parser, 'character_data');
6633 
6634  // Parse the XML file.
6635  if (!xml_parse($this->parser, $xml, true)) {
6636  // Display an error message.
6637  $err = sprintf(
6638  'XML error parsing SOAP payload on line %d: %s',
6639  xml_get_current_line_number($this->parser),
6640  xml_error_string(xml_get_error_code($this->parser))
6641  );
6642  $this->debug($err);
6643  $this->debug("XML payload:\n" . $xml);
6644  $this->setError($err);
6645  } else {
6646  $this->debug('parsed successfully, found root struct: ' . $this->root_struct . ' of name ' . $this->root_struct_name);
6647  // get final value
6648  $this->soapresponse = $this->message[$this->root_struct]['result'];
6649  // get header value
6650  if ($this->root_header != '' && isset($this->message[$this->root_header]['result'])) {
6651  $this->soapheader = $this->message[$this->root_header]['result'];
6652  }
6653  // resolve hrefs/ids
6654  if (sizeof($this->multirefs) > 0) {
6655  foreach ($this->multirefs as $id => $hrefs) {
6656  $this->debug('resolving multirefs for id: ' . $id);
6657  $idVal = $this->buildVal($this->ids[$id]);
6658  if (is_array($idVal) && isset($idVal['!id'])) {
6659  unset($idVal['!id']);
6660  }
6661  foreach ($hrefs as $refPos => $ref) {
6662  $this->debug('resolving href at pos ' . $refPos);
6663  $this->multirefs[$id][$refPos] = $idVal;
6664  }
6665  }
6666  }
6667  }
6668  xml_parser_free($this->parser);
6669  } else {
6670  $this->debug('xml was empty, didn\'t parse!');
6671  $this->setError('xml was empty, didn\'t parse!');
6672  }
6673  }
6674 
6683  public function start_element($parser, $name, $attrs)
6684  {
6685  // position in a total number of elements, starting from 0
6686  // update class level pos
6687  $pos = $this->position++;
6688  // and set mine
6689  $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
6690  // depth = how many levels removed from root?
6691  // set mine as current global depth and increment global depth value
6692  $this->message[$pos]['depth'] = $this->depth++;
6693 
6694  // else add self as child to whoever the current parent is
6695  if ($pos != 0) {
6696  $this->message[$this->parent]['children'] .= '|' . $pos;
6697  }
6698  // set my parent
6699  $this->message[$pos]['parent'] = $this->parent;
6700  // set self as current parent
6701  $this->parent = $pos;
6702  // set self as current value for this depth
6703  $this->depth_array[$this->depth] = $pos;
6704  // get element prefix
6705  if (strpos($name, ':')) {
6706  // get ns prefix
6707  $prefix = substr($name, 0, strpos($name, ':'));
6708  // get unqualified name
6709  $name = substr(strstr($name, ':'), 1);
6710  }
6711  // set status
6712  if ($name == 'Envelope') {
6713  $this->status = 'envelope';
6714  } elseif ($name == 'Header' && $this->status = 'envelope') {
6715  $this->root_header = $pos;
6716  $this->status = 'header';
6717  } elseif ($name == 'Body' && $this->status = 'envelope') {
6718  $this->status = 'body';
6719  $this->body_position = $pos;
6720  // set method
6721  } elseif ($this->status == 'body' && $pos == ($this->body_position+1)) {
6722  $this->status = 'method';
6723  $this->root_struct_name = $name;
6724  $this->root_struct = $pos;
6725  $this->message[$pos]['type'] = 'struct';
6726  $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
6727  }
6728  // set my status
6729  $this->message[$pos]['status'] = $this->status;
6730  // set name
6731  $this->message[$pos]['name'] = htmlspecialchars($name);
6732  // set attrs
6733  $this->message[$pos]['attrs'] = $attrs;
6734 
6735  // loop through atts, logging ns and type declarations
6736  $attstr = '';
6737  foreach ($attrs as $key => $value) {
6738  $key_prefix = $this->getPrefix($key);
6739  $key_localpart = $this->getLocalPart($key);
6740  // if ns declarations, add to class level array of valid namespaces
6741  if ($key_prefix == 'xmlns') {
6742  if (preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/', $value)) {
6743  $this->XMLSchemaVersion = $value;
6744  $this->namespaces['xsd'] = $this->XMLSchemaVersion;
6745  $this->namespaces['xsi'] = $this->XMLSchemaVersion . '-instance';
6746  }
6747  $this->namespaces[$key_localpart] = $value;
6748  // set method namespace
6749  if ($name == $this->root_struct_name) {
6750  $this->methodNamespace = $value;
6751  }
6752  // if it's a type declaration, set type
6753  } elseif ($key_localpart == 'type') {
6754  if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
6755  // do nothing: already processed arrayType
6756  } else {
6757  $value_prefix = $this->getPrefix($value);
6758  $value_localpart = $this->getLocalPart($value);
6759  $this->message[$pos]['type'] = $value_localpart;
6760  $this->message[$pos]['typePrefix'] = $value_prefix;
6761  if (isset($this->namespaces[$value_prefix])) {
6762  $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
6763  } elseif (isset($attrs['xmlns:' . $value_prefix])) {
6764  $this->message[$pos]['type_namespace'] = $attrs['xmlns:' . $value_prefix];
6765  }
6766  // should do something here with the namespace of specified type?
6767  }
6768  } elseif ($key_localpart == 'arrayType') {
6769  $this->message[$pos]['type'] = 'array';
6770  /* do arrayType ereg here
6771  [1] arrayTypeValue ::= atype asize
6772  [2] atype ::= QName rank*
6773  [3] rank ::= '[' (',')* ']'
6774  [4] asize ::= '[' length~ ']'
6775  [5] length ::= nextDimension* Digit+
6776  [6] nextDimension ::= Digit+ ','
6777  */
6778  $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
6779  if (preg_match($expr, $value, $regs)) {
6780  $this->message[$pos]['typePrefix'] = $regs[1];
6781  $this->message[$pos]['arrayTypePrefix'] = $regs[1];
6782  if (isset($this->namespaces[$regs[1]])) {
6783  $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
6784  } elseif (isset($attrs['xmlns:' . $regs[1]])) {
6785  $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:' . $regs[1]];
6786  }
6787  $this->message[$pos]['arrayType'] = $regs[2];
6788  $this->message[$pos]['arraySize'] = $regs[3];
6789  $this->message[$pos]['arrayCols'] = $regs[4];
6790  }
6791  // specifies nil value (or not)
6792  } elseif ($key_localpart == 'nil') {
6793  $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
6794  // some other attribute
6795  } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
6796  $this->message[$pos]['xattrs']['!' . $key] = $value;
6797  }
6798 
6799  if ($key == 'xmlns') {
6800  $this->default_namespace = $value;
6801  }
6802  // log id
6803  if ($key == 'id') {
6804  $this->ids[$value] = $pos;
6805  }
6806  // root
6807  if ($key_localpart == 'root' && $value == 1) {
6808  $this->status = 'method';
6809  $this->root_struct_name = $name;
6810  $this->root_struct = $pos;
6811  $this->debug("found root struct $this->root_struct_name, pos $pos");
6812  }
6813  // for doclit
6814  $attstr .= " $key=\"$value\"";
6815  }
6816  // get namespace - must be done after namespace atts are processed
6817  if (isset($prefix)) {
6818  $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
6819  $this->default_namespace = $this->namespaces[$prefix];
6820  } else {
6821  $this->message[$pos]['namespace'] = $this->default_namespace;
6822  }
6823  if ($this->status == 'header') {
6824  if ($this->root_header != $pos) {
6825  $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6826  }
6827  } elseif ($this->root_struct_name != '') {
6828  $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6829  }
6830  }
6831 
6839  public function end_element($parser, $name)
6840  {
6841  // position of current element is equal to the last value left in depth_array for my depth
6842  $pos = $this->depth_array[$this->depth--];
6843 
6844  // get element prefix
6845  if (strpos($name, ':')) {
6846  // get ns prefix
6847  $prefix = substr($name, 0, strpos($name, ':'));
6848  // get unqualified name
6849  $name = substr(strstr($name, ':'), 1);
6850  }
6851 
6852  // build to native type
6853  if (isset($this->body_position) && $pos > $this->body_position) {
6854  // deal w/ multirefs
6855  if (isset($this->message[$pos]['attrs']['href'])) {
6856  // get id
6857  $id = substr($this->message[$pos]['attrs']['href'], 1);
6858  // add placeholder to href array
6859  $this->multirefs[$id][$pos] = 'placeholder';
6860  // add set a reference to it as the result value
6861  $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
6862  // build complexType values
6863  } elseif ($this->message[$pos]['children'] != '') {
6864  // if result has already been generated (struct/array)
6865  if (!isset($this->message[$pos]['result'])) {
6866  $this->message[$pos]['result'] = $this->buildVal($pos);
6867  }
6868  // build complexType values of attributes and possibly simpleContent
6869  } elseif (isset($this->message[$pos]['xattrs'])) {
6870  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6871  $this->message[$pos]['xattrs']['!'] = null;
6872  } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
6873  if (isset($this->message[$pos]['type'])) {
6874  $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'] : '');
6875  } else {
6876  $parent = $this->message[$pos]['parent'];
6877  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6878  $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6879  } else {
6880  $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
6881  }
6882  }
6883  }
6884  $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
6885  // set value of simpleType (or nil complexType)
6886  } else {
6887  //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
6888  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6889  $this->message[$pos]['xattrs']['!'] = null;
6890  } elseif (isset($this->message[$pos]['type'])) {
6891  $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'] : '');
6892  } else {
6893  $parent = $this->message[$pos]['parent'];
6894  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6895  $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6896  } else {
6897  $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
6898  }
6899  }
6900 
6901  /* add value to parent's result, if parent is struct/array
6902  $parent = $this->message[$pos]['parent'];
6903  if($this->message[$parent]['type'] != 'map'){
6904  if(strtolower($this->message[$parent]['type']) == 'array'){
6905  $this->message[$parent]['result'][] = $this->message[$pos]['result'];
6906  } else {
6907  $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
6908  }
6909  }
6910  */
6911  }
6912  }
6913 
6914  // for doclit
6915  if ($this->status == 'header') {
6916  if ($this->root_header != $pos) {
6917  $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6918  }
6919  } elseif ($pos >= $this->root_struct) {
6920  $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6921  }
6922  // switch status
6923  if ($pos == $this->root_struct) {
6924  $this->status = 'body';
6925  $this->root_struct_namespace = $this->message[$pos]['namespace'];
6926  } elseif ($name == 'Body') {
6927  $this->status = 'envelope';
6928  } elseif ($name == 'Header') {
6929  $this->status = 'envelope';
6930  } elseif ($name == 'Envelope') {
6931  //
6932  }
6933  // set parent back to my parent
6934  $this->parent = $this->message[$pos]['parent'];
6935  }
6936 
6944  public function character_data($parser, $data)
6945  {
6946  $pos = $this->depth_array[$this->depth];
6947  if ($this->xml_encoding=='UTF-8') {
6948  // TODO: add an option to disable this for folks who want
6949  // raw UTF-8 that, e.g., might not map to iso-8859-1
6950  // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
6951  if ($this->decode_utf8) {
6952  $data = utf8_decode($data);
6953  }
6954  }
6955  $this->message[$pos]['cdata'] .= $data;
6956  // for doclit
6957  if ($this->status == 'header') {
6958  $this->responseHeaders .= $data;
6959  } else {
6960  $this->document .= $data;
6961  }
6962  }
6963 
6971  public function get_response()
6972  {
6973  return $this->soapresponse;
6974  }
6975 
6982  public function get_soapbody()
6983  {
6984  return $this->soapresponse;
6985  }
6986 
6993  public function get_soapheader()
6994  {
6995  return $this->soapheader;
6996  }
6997 
7004  public function getHeaders()
7005  {
7006  return $this->responseHeaders;
7007  }
7008 
7018  public function decodeSimple($value, $type, $typens)
7019  {
7020  // TODO: use the namespace!
7021  if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
7022  return (string) $value;
7023  }
7024  if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
7025  return (int) $value;
7026  }
7027  if ($type == 'float' || $type == 'double' || $type == 'decimal') {
7028  return (float) $value;
7029  }
7030  if ($type == 'boolean') {
7031  if (strtolower($value) == 'false' || strtolower($value) == 'f') {
7032  return false;
7033  }
7034  return (bool) $value;
7035  }
7036  if ($type == 'base64' || $type == 'base64Binary') {
7037  $this->debug('Decode base64 value');
7038  return base64_decode($value);
7039  }
7040  // obscure numeric types
7041  if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
7042  || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
7043  || $type == 'unsignedInt'
7044  || $type == 'unsignedShort' || $type == 'unsignedByte') {
7045  return (int) $value;
7046  }
7047  // bogus: parser treats array with no elements as a simple type
7048  if ($type == 'array') {
7049  return array();
7050  }
7051  // everything else
7052  return (string) $value;
7053  }
7054 
7063  public function buildVal($pos)
7064  {
7065  if (!isset($this->message[$pos]['type'])) {
7066  $this->message[$pos]['type'] = '';
7067  }
7068  $this->debug('in buildVal() for ' . $this->message[$pos]['name'] . "(pos $pos) of type " . $this->message[$pos]['type']);
7069  // if there are children...
7070  if ($this->message[$pos]['children'] != '') {
7071  $this->debug('in buildVal, there are children');
7072  $children = explode('|', $this->message[$pos]['children']);
7073  array_shift($children); // knock off empty
7074  // md array
7075  if (isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != '') {
7076  $r=0; // rowcount
7077  $c=0; // colcount
7078  foreach ($children as $child_pos) {
7079  $this->debug("in buildVal, got an MD array element: $r, $c");
7080  $params[$r][] = $this->message[$child_pos]['result'];
7081  $c++;
7082  if ($c == $this->message[$pos]['arrayCols']) {
7083  $c = 0;
7084  $r++;
7085  }
7086  }
7087  // array
7088  } elseif ($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array') {
7089  $this->debug('in buildVal, adding array ' . $this->message[$pos]['name']);
7090  foreach ($children as $child_pos) {
7091  $params[] = &$this->message[$child_pos]['result'];
7092  }
7093  // apache Map type: java hashtable
7094  } elseif ($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
7095  $this->debug('in buildVal, Java Map ' . $this->message[$pos]['name']);
7096  foreach ($children as $child_pos) {
7097  $kv = explode("|", $this->message[$child_pos]['children']);
7098  $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
7099  }
7100  // generic compound type
7101  //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
7102  } else {
7103  // Apache Vector type: treat as an array
7104  $this->debug('in buildVal, adding Java Vector or generic compound type ' . $this->message[$pos]['name']);
7105  if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
7106  $notstruct = 1;
7107  } else {
7108  $notstruct = 0;
7109  }
7110  //
7111  foreach ($children as $child_pos) {
7112  if ($notstruct) {
7113  $params[] = &$this->message[$child_pos]['result'];
7114  } else {
7115  if (isset($params[$this->message[$child_pos]['name']])) {
7116  // de-serialize repeated element name into an array
7117  if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
7118  $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
7119  }
7120  $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
7121  } else {
7122  $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
7123  }
7124  }
7125  }
7126  }
7127  if (isset($this->message[$pos]['xattrs'])) {
7128  $this->debug('in buildVal, handling attributes');
7129  foreach ($this->message[$pos]['xattrs'] as $n => $v) {
7130  $params[$n] = $v;
7131  }
7132  }
7133  // handle simpleContent
7134  if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
7135  $this->debug('in buildVal, handling simpleContent');
7136  if (isset($this->message[$pos]['type'])) {
7137  $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7138  } else {
7139  $parent = $this->message[$pos]['parent'];
7140  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
7141  $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7142  } else {
7143  $params['!'] = $this->message[$pos]['cdata'];
7144  }
7145  }
7146  }
7147  $ret = is_array($params) ? $params : array();
7148  $this->debug('in buildVal, return:');
7149  $this->appendDebug($this->varDump($ret));
7150  return $ret;
7151  } else {
7152  $this->debug('in buildVal, no children, building scalar');
7153  $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
7154  if (isset($this->message[$pos]['type'])) {
7155  $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7156  $this->debug("in buildVal, return: $ret");
7157  return $ret;
7158  }
7159  $parent = $this->message[$pos]['parent'];
7160  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
7161  $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7162  $this->debug("in buildVal, return: $ret");
7163  return $ret;
7164  }
7165  $ret = $this->message[$pos]['cdata'];
7166  $this->debug("in buildVal, return: $ret");
7167  return $ret;
7168  }
7169  }
7170 }
7171 
7175 class soap_parser extends nusoap_parser
7176 {
7177 }
7178 
7179 ?><?php
7180 
7181 
7182 
7203 class nusoap_client extends nusoap_base
7204 {
7205  public $username = ''; // Username for HTTP authentication
7206  public $password = ''; // Password for HTTP authentication
7207  public $authtype = ''; // Type of HTTP authentication
7208  public $certRequest = array(); // Certificate for HTTP SSL authentication
7209  public $requestHeaders = false; // SOAP headers in request (text)
7210  public $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
7211  public $responseHeader = null; // SOAP Header from response (parsed)
7212  public $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
7213  public $endpoint;
7214  public $forceEndpoint = ''; // overrides WSDL endpoint
7215  public $proxyhost = '';
7216  public $proxyport = '';
7217  public $proxyusername = '';
7218  public $proxypassword = '';
7219  public $xml_encoding = ''; // character set encoding of incoming (response) messages
7220  public $http_encoding = false;
7221  public $timeout = 0; // HTTP connection timeout
7222  public $response_timeout = 30; // HTTP response timeout
7223  public $endpointType = ''; // soap|wsdl, empty for WSDL initialization error
7224  public $persistentConnection = false;
7225  public $defaultRpcParams = false; // This is no longer used
7226  public $request = ''; // HTTP request
7227  public $response = ''; // HTTP response
7228  public $responseData = ''; // SOAP payload of response
7229  public $cookies = array(); // Cookies from response or for request
7230  public $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
7231  public $operations = array(); // WSDL operations, empty for WSDL initialization error
7232  public $curl_options = array(); // User-specified cURL options
7233  public $bindingType = ''; // WSDL operation binding type
7234  public $use_curl = false; // whether to always try to use cURL
7235 
7236  /*
7237  * fault related variables
7238  */
7243  public $fault;
7248  public $faultcode;
7253  public $faultstring;
7258  public $faultdetail;
7259 
7274  public function __construct($endpoint, $wsdl = false, $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30)
7275  {
7277  $this->endpoint = $endpoint;
7278  $this->proxyhost = $proxyhost;
7279  $this->proxyport = $proxyport;
7280  $this->proxyusername = $proxyusername;
7281  $this->proxypassword = $proxypassword;
7282  $this->timeout = $timeout;
7283  $this->response_timeout = $response_timeout;
7284 
7285  $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
7286  $this->appendDebug('endpoint=' . $this->varDump($endpoint));
7287 
7288  // make values
7289  if ($wsdl) {
7290  if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
7291  $this->wsdl = $endpoint;
7292  $this->endpoint = $this->wsdl->wsdl;
7293  $this->wsdlFile = $this->endpoint;
7294  $this->debug('existing wsdl instance created from ' . $this->endpoint);
7295  $this->checkWSDL();
7296  } else {
7297  $this->wsdlFile = $this->endpoint;
7298  $this->wsdl = null;
7299  $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
7300  }
7301  $this->endpointType = 'wsdl';
7302  } else {
7303  $this->debug("instantiate SOAP with endpoint at $endpoint");
7304  $this->endpointType = 'soap';
7305  }
7306  }
7307 
7333  public function call($operation, $params=array(), $namespace='http://tempuri.org', $soapAction='', $headers=false, $rpcParams=null, $style='rpc', $use='encoded')
7334  {
7335  $this->operation = $operation;
7336  $this->fault = false;
7337  $this->setError('');
7338  $this->request = '';
7339  $this->response = '';
7340  $this->responseData = '';
7341  $this->faultstring = '';
7342  $this->faultcode = '';
7343  $this->opData = array();
7344 
7345  $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
7346  $this->appendDebug('params=' . $this->varDump($params));
7347  $this->appendDebug('headers=' . $this->varDump($headers));
7348  if ($headers) {
7349  $this->requestHeaders = $headers;
7350  }
7351  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7352  $this->loadWSDL();
7353  if ($this->getError()) {
7354  return false;
7355  }
7356  }
7357  // serialize parameters
7358  if ($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)) {
7359  // use WSDL for operation
7360  $this->opData = $opData;
7361  $this->debug("found operation");
7362  $this->appendDebug('opData=' . $this->varDump($opData));
7363  if (isset($opData['soapAction'])) {
7364  $soapAction = $opData['soapAction'];
7365  }
7366  if (! $this->forceEndpoint) {
7367  $this->endpoint = $opData['endpoint'];
7368  } else {
7369  $this->endpoint = $this->forceEndpoint;
7370  }
7371  $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace;
7372  $style = $opData['style'];
7373  $use = $opData['input']['use'];
7374  // add ns to ns array
7375  if ($namespace != '' && !isset($this->wsdl->namespaces[$namespace])) {
7376  $nsPrefix = 'ns' . rand(1000, 9999);
7377  $this->wsdl->namespaces[$nsPrefix] = $namespace;
7378  }
7379  $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
7380  // serialize payload
7381  if (is_string($params)) {
7382  $this->debug("serializing param string for WSDL operation $operation");
7383  $payload = $params;
7384  } elseif (is_array($params)) {
7385  $this->debug("serializing param array for WSDL operation $operation");
7386  $payload = $this->wsdl->serializeRPCParameters($operation, 'input', $params, $this->bindingType);
7387  } else {
7388  $this->debug('params must be array or string');
7389  $this->setError('params must be array or string');
7390  return false;
7391  }
7392  $usedNamespaces = $this->wsdl->usedNamespaces;
7393  if (isset($opData['input']['encodingStyle'])) {
7394  $encodingStyle = $opData['input']['encodingStyle'];
7395  } else {
7396  $encodingStyle = '';
7397  }
7398  $this->appendDebug($this->wsdl->getDebug());
7399  $this->wsdl->clearDebug();
7400  if ($errstr = $this->wsdl->getError()) {
7401  $this->debug('got wsdl error: ' . $errstr);
7402  $this->setError('wsdl error: ' . $errstr);
7403  return false;
7404  }
7405  } elseif ($this->endpointType == 'wsdl') {
7406  // operation not in WSDL
7407  $this->appendDebug($this->wsdl->getDebug());
7408  $this->wsdl->clearDebug();
7409  $this->setError('operation ' . $operation . ' not present.');
7410  $this->debug("operation '$operation' not present.");
7411  return false;
7412  } else {
7413  // no WSDL
7414  //$this->namespaces['ns1'] = $namespace;
7415  $nsPrefix = 'ns' . rand(1000, 9999);
7416  // serialize
7417  $payload = '';
7418  if (is_string($params)) {
7419  $this->debug("serializing param string for operation $operation");
7420  $payload = $params;
7421  } elseif (is_array($params)) {
7422  $this->debug("serializing param array for operation $operation");
7423  foreach ($params as $k => $v) {
7424  $payload .= $this->serialize_val($v, $k, false, false, false, false, $use);
7425  }
7426  } else {
7427  $this->debug('params must be array or string');
7428  $this->setError('params must be array or string');
7429  return false;
7430  }
7431  $usedNamespaces = array();
7432  if ($use == 'encoded') {
7433  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7434  } else {
7435  $encodingStyle = '';
7436  }
7437  }
7438  // wrap RPC calls with method element
7439  if ($style == 'rpc') {
7440  if ($use == 'literal') {
7441  $this->debug("wrapping RPC request with literal method element");
7442  if ($namespace) {
7443  // 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
7444  $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7445  $payload .
7446  "</$nsPrefix:$operation>";
7447  } else {
7448  $payload = "<$operation>" . $payload . "</$operation>";
7449  }
7450  } else {
7451  $this->debug("wrapping RPC request with encoded method element");
7452  if ($namespace) {
7453  $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7454  $payload .
7455  "</$nsPrefix:$operation>";
7456  } else {
7457  $payload = "<$operation>" .
7458  $payload .
7459  "</$operation>";
7460  }
7461  }
7462  }
7463  // serialize envelope
7464  $soapmsg = $this->serializeEnvelope($payload, $this->requestHeaders, $usedNamespaces, $style, $use, $encodingStyle);
7465  $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
7466  $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
7467  // send
7468  $return = $this->send($this->getHTTPBody($soapmsg), $soapAction, $this->timeout, $this->response_timeout);
7469  if ($errstr = $this->getError()) {
7470  $this->debug('Error: ' . $errstr);
7471  return false;
7472  } else {
7473  $this->return = $return;
7474  $this->debug('sent message successfully and got a(n) ' . gettype($return));
7475  $this->appendDebug('return=' . $this->varDump($return));
7476 
7477  // fault?
7478  if (is_array($return) && isset($return['faultcode'])) {
7479  $this->debug('got fault');
7480  $this->setError($return['faultcode'] . ': ' . $return['faultstring']);
7481  $this->fault = true;
7482  foreach ($return as $k => $v) {
7483  $this->$k = $v;
7484  $this->debug("$k = $v<br>");
7485  }
7486  return $return;
7487  } elseif ($style == 'document') {
7488  // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
7489  // we are only going to return the first part here...sorry about that
7490  return $return;
7491  } else {
7492  // array of return values
7493  if (is_array($return)) {
7494  // multiple 'out' parameters, which we return wrapped up
7495  // in the array
7496  if (sizeof($return) > 1) {
7497  return $return;
7498  }
7499  // single 'out' parameter (normally the return value)
7500  $return = array_shift($return);
7501  $this->debug('return shifted value: ');
7502  $this->appendDebug($this->varDump($return));
7503  return $return;
7504  // nothing returned (ie, echoVoid)
7505  } else {
7506  return "";
7507  }
7508  }
7509  }
7510  }
7511 
7517  public function checkWSDL()
7518  {
7519  $this->appendDebug($this->wsdl->getDebug());
7520  $this->wsdl->clearDebug();
7521  $this->debug('checkWSDL');
7522  // catch errors
7523  if ($errstr = $this->wsdl->getError()) {
7524  $this->debug('got wsdl error: ' . $errstr);
7525  $this->setError('wsdl error: ' . $errstr);
7526  } elseif ($this->operations = $this->wsdl->getOperations('soap')) {
7527  $this->bindingType = 'soap';
7528  $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType);
7529  } elseif ($this->operations = $this->wsdl->getOperations('soap12')) {
7530  $this->bindingType = 'soap12';
7531  $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType);
7532  $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
7533  } else {
7534  $this->debug('getOperations returned false');
7535  $this->setError('no operations defined in the WSDL document!');
7536  }
7537  }
7538 
7544  public function loadWSDL()
7545  {
7546  $this->debug('instantiating wsdl class with doc: ' . $this->wsdlFile);
7547  $this->wsdl = new wsdl('', $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword, $this->timeout, $this->response_timeout, $this->curl_options, $this->use_curl);
7548  $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
7549  $this->wsdl->fetchWSDL($this->wsdlFile);
7550  $this->checkWSDL();
7551  }
7552 
7560  public function getOperationData($operation)
7561  {
7562  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7563  $this->loadWSDL();
7564  if ($this->getError()) {
7565  return false;
7566  }
7567  }
7568  if (isset($this->operations[$operation])) {
7569  return $this->operations[$operation];
7570  }
7571  $this->debug("No data for operation: $operation");
7572  }
7573 
7588  public function send($msg, $soapaction = '', $timeout=0, $response_timeout=30)
7589  {
7590  $this->checkCookies();
7591  // detect transport
7592  switch (true) {
7593  // http(s)
7594  case preg_match('/^http/', $this->endpoint):
7595  $this->debug('transporting via HTTP');
7596  if ($this->persistentConnection == true && is_object($this->persistentConnection)) {
7597  $http =& $this->persistentConnection;
7598  } else {
7599  $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
7600  if ($this->persistentConnection) {
7601  $http->usePersistentConnection();
7602  }
7603  }
7604  $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
7605  $http->setSOAPAction($soapaction);
7606  if ($this->proxyhost && $this->proxyport) {
7607  $http->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
7608  }
7609  if ($this->authtype != '') {
7610  $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
7611  }
7612  if ($this->http_encoding != '') {
7613  $http->setEncoding($this->http_encoding);
7614  }
7615  $this->debug('sending message, length=' . strlen($msg));
7616  if (preg_match('/^http:/', $this->endpoint)) {
7617  //if(strpos($this->endpoint,'http:')){
7618  $this->responseData = $http->send($msg, $timeout, $response_timeout, $this->cookies);
7619  } elseif (preg_match('/^https/', $this->endpoint)) {
7620  //} elseif(strpos($this->endpoint,'https:')){
7621  //if(phpversion() == '4.3.0-dev'){
7622  //$response = $http->send($msg,$timeout,$response_timeout);
7623  //$this->request = $http->outgoing_payload;
7624  //$this->response = $http->incoming_payload;
7625  //} else
7626  $this->responseData = $http->sendHTTPS($msg, $timeout, $response_timeout, $this->cookies);
7627  } else {
7628  $this->setError('no http/s in endpoint url');
7629  }
7630  $this->request = $http->outgoing_payload;
7631  $this->response = $http->incoming_payload;
7632  $this->appendDebug($http->getDebug());
7633  $this->UpdateCookies($http->incoming_cookies);
7634 
7635  // save transport object if using persistent connections
7636  if ($this->persistentConnection) {
7637  $http->clearDebug();
7638  if (!is_object($this->persistentConnection)) {
7639  $this->persistentConnection = $http;
7640  }
7641  }
7642 
7643  if ($err = $http->getError()) {
7644  $this->setError('HTTP Error: ' . $err);
7645  return false;
7646  } elseif ($this->getError()) {
7647  return false;
7648  } else {
7649  $this->debug('got response, length=' . strlen($this->responseData) . ' type=' . $http->incoming_headers['content-type']);
7650  return $this->parseResponse($http->incoming_headers, $this->responseData);
7651  }
7652  break;
7653  default:
7654  $this->setError('no transport found, or selected transport is not yet supported!');
7655  return false;
7656  break;
7657  }
7658  }
7659 
7668  public function parseResponse($headers, $data)
7669  {
7670  $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
7671  $this->appendDebug($this->varDump($headers));
7672  if (!strstr($headers['content-type'], 'text/xml')) {
7673  $this->setError('Response not of type text/xml: ' . $headers['content-type']);
7674  return false;
7675  }
7676  if (strpos($headers['content-type'], '=')) {
7677  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
7678  $this->debug('Got response encoding: ' . $enc);
7679  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
7680  $this->xml_encoding = strtoupper($enc);
7681  } else {
7682  $this->xml_encoding = 'US-ASCII';
7683  }
7684  } else {
7685  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
7686  $this->xml_encoding = 'ISO-8859-1';
7687  }
7688  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
7689  $parser = new nusoap_parser($data, $this->xml_encoding, $this->operation, $this->decode_utf8);
7690  // add parser debug data to our debug
7691  $this->appendDebug($parser->getDebug());
7692  // if parse errors
7693  if ($errstr = $parser->getError()) {
7694  $this->setError($errstr);
7695  // destroy the parser object
7696  unset($parser);
7697  return false;
7698  } else {
7699  // get SOAP headers
7700  $this->responseHeaders = $parser->getHeaders();
7701  // get SOAP headers
7702  $this->responseHeader = $parser->get_soapheader();
7703  // get decoded message
7704  $return = $parser->get_soapbody();
7705  // add document for doclit support
7706  $this->document = $parser->document;
7707  // destroy the parser object
7708  unset($parser);
7709  // return decode message
7710  return $return;
7711  }
7712  }
7713 
7721  public function setCurlOption($option, $value)
7722  {
7723  $this->debug("setCurlOption option=$option, value=");
7724  $this->appendDebug($this->varDump($value));
7725  $this->curl_options[$option] = $value;
7726  }
7727 
7734  public function setEndpoint($endpoint)
7735  {
7736  $this->debug("setEndpoint(\"$endpoint\")");
7737  $this->forceEndpoint = $endpoint;
7738  }
7739 
7746  public function setHeaders($headers)
7747  {
7748  $this->debug("setHeaders headers=");
7749  $this->appendDebug($this->varDump($headers));
7750  $this->requestHeaders = $headers;
7751  }
7752 
7759  public function getHeaders()
7760  {
7761  return $this->responseHeaders;
7762  }
7763 
7770  public function getHeader()
7771  {
7772  return $this->responseHeader;
7773  }
7774 
7784  public function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '')
7785  {
7786  $this->proxyhost = $proxyhost;
7787  $this->proxyport = $proxyport;
7788  $this->proxyusername = $proxyusername;
7789  $this->proxypassword = $proxypassword;
7790  }
7791 
7801  public function setCredentials($username, $password, $authtype = 'basic', $certRequest = array())
7802  {
7803  $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
7804  $this->appendDebug($this->varDump($certRequest));
7805  $this->username = $username;
7806  $this->password = $password;
7807  $this->authtype = $authtype;
7808  $this->certRequest = $certRequest;
7809  }
7810 
7817  public function setHTTPEncoding($enc='gzip, deflate')
7818  {
7819  $this->debug("setHTTPEncoding(\"$enc\")");
7820  $this->http_encoding = $enc;
7821  }
7822 
7829  public function setUseCURL($use)
7830  {
7831  $this->debug("setUseCURL($use)");
7832  $this->use_curl = $use;
7833  }
7834 
7840  public function useHTTPPersistentConnection()
7841  {
7842  $this->debug("useHTTPPersistentConnection");
7843  $this->persistentConnection = true;
7844  }
7845 
7857  public function getDefaultRpcParams()
7858  {
7859  return $this->defaultRpcParams;
7860  }
7861 
7873  public function setDefaultRpcParams($rpcParams)
7874  {
7875  $this->defaultRpcParams = $rpcParams;
7876  }
7877 
7885  public function getProxy()
7886  {
7887  $r = rand();
7888  $evalStr = $this->_getProxyClassCode($r);
7889  //$this->debug("proxy class: $evalStr");
7890  if ($this->getError()) {
7891  $this->debug("Error from _getProxyClassCode, so return NULL");
7892  return null;
7893  }
7894  // eval the class
7895  eval($evalStr);
7896  // instantiate proxy object
7897  eval("\$proxy = new nusoap_proxy_$r('');");
7898  // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
7899  $proxy->endpointType = 'wsdl';
7900  $proxy->wsdlFile = $this->wsdlFile;
7901  $proxy->wsdl = $this->wsdl;
7902  $proxy->operations = $this->operations;
7903  $proxy->defaultRpcParams = $this->defaultRpcParams;
7904  // transfer other state
7905  $proxy->soap_defencoding = $this->soap_defencoding;
7906  $proxy->username = $this->username;
7907  $proxy->password = $this->password;
7908  $proxy->authtype = $this->authtype;
7909  $proxy->certRequest = $this->certRequest;
7910  $proxy->requestHeaders = $this->requestHeaders;
7911  $proxy->endpoint = $this->endpoint;
7912  $proxy->forceEndpoint = $this->forceEndpoint;
7913  $proxy->proxyhost = $this->proxyhost;
7914  $proxy->proxyport = $this->proxyport;
7915  $proxy->proxyusername = $this->proxyusername;
7916  $proxy->proxypassword = $this->proxypassword;
7917  $proxy->http_encoding = $this->http_encoding;
7918  $proxy->timeout = $this->timeout;
7919  $proxy->response_timeout = $this->response_timeout;
7920  $proxy->persistentConnection = &$this->persistentConnection;
7921  $proxy->decode_utf8 = $this->decode_utf8;
7922  $proxy->curl_options = $this->curl_options;
7923  $proxy->bindingType = $this->bindingType;
7924  $proxy->use_curl = $this->use_curl;
7925  return $proxy;
7926  }
7927 
7934  public function _getProxyClassCode($r)
7935  {
7936  $this->debug("in getProxy endpointType=$this->endpointType");
7937  $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
7938  if ($this->endpointType != 'wsdl') {
7939  $evalStr = 'A proxy can only be created for a WSDL client';
7940  $this->setError($evalStr);
7941  $evalStr = "echo \"$evalStr\";";
7942  return $evalStr;
7943  }
7944  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7945  $this->loadWSDL();
7946  if ($this->getError()) {
7947  return "echo \"" . $this->getError() . "\";";
7948  }
7949  }
7950  $evalStr = '';
7951  foreach ($this->operations as $operation => $opData) {
7952  if ($operation != '') {
7953  // create param string and param comment string
7954  if (sizeof($opData['input']['parts']) > 0) {
7955  $paramStr = '';
7956  $paramArrayStr = '';
7957  $paramCommentStr = '';
7958  foreach ($opData['input']['parts'] as $name => $type) {
7959  $paramStr .= "\$$name, ";
7960  $paramArrayStr .= "'$name' => \$$name, ";
7961  $paramCommentStr .= "$type \$$name, ";
7962  }
7963  $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
7964  $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
7965  $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
7966  } else {
7967  $paramStr = '';
7968  $paramArrayStr = '';
7969  $paramCommentStr = 'void';
7970  }
7971  $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
7972  $evalStr .= "// $paramCommentStr
7973  function " . str_replace('.', '__', $operation) . "($paramStr) {
7974  \$params = array($paramArrayStr);
7975  return \$this->call('$operation', \$params, '" . $opData['namespace'] . "', '" . (isset($opData['soapAction']) ? $opData['soapAction'] : '') . "');
7976  }
7977  ";
7978  unset($paramStr);
7979  unset($paramCommentStr);
7980  }
7981  }
7982  $evalStr = 'class nusoap_proxy_' . $r . ' extends nusoap_client {
7983  ' . $evalStr . '
7984 }';
7985  return $evalStr;
7986  }
7987 
7994  public function getProxyClassCode()
7995  {
7996  $r = rand();
7997  return $this->_getProxyClassCode($r);
7998  }
7999 
8007  public function getHTTPBody($soapmsg)
8008  {
8009  return $soapmsg;
8010  }
8011 
8020  public function getHTTPContentType()
8021  {
8022  return 'text/xml';
8023  }
8024 
8034  public function getHTTPContentTypeCharset()
8035  {
8036  return $this->soap_defencoding;
8037  }
8038 
8039  /*
8040  * whether or not parser should decode utf8 element content
8041  *
8042  * @return always returns true
8043  * @access public
8044  */
8045  public function decodeUTF8($bool)
8046  {
8047  $this->decode_utf8 = $bool;
8048  return true;
8049  }
8050 
8059  public function setCookie($name, $value)
8060  {
8061  if (strlen($name) == 0) {
8062  return false;
8063  }
8064  $this->cookies[] = array('name' => $name, 'value' => $value);
8065  return true;
8066  }
8067 
8074  public function getCookies()
8075  {
8076  return $this->cookies;
8077  }
8078 
8085  public function checkCookies()
8086  {
8087  if (sizeof($this->cookies) == 0) {
8088  return true;
8089  }
8090  $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
8091  $curr_cookies = $this->cookies;
8092  $this->cookies = array();
8093  foreach ($curr_cookies as $cookie) {
8094  if (! is_array($cookie)) {
8095  $this->debug('Remove cookie that is not an array');
8096  continue;
8097  }
8098  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
8099  if (strtotime($cookie['expires']) > time()) {
8100  $this->cookies[] = $cookie;
8101  } else {
8102  $this->debug('Remove expired cookie ' . $cookie['name']);
8103  }
8104  } else {
8105  $this->cookies[] = $cookie;
8106  }
8107  }
8108  $this->debug('checkCookie: ' . sizeof($this->cookies) . ' cookies left in array');
8109  return true;
8110  }
8111 
8119  public function UpdateCookies($cookies)
8120  {
8121  if (sizeof($this->cookies) == 0) {
8122  // no existing cookies: take whatever is new
8123  if (sizeof($cookies) > 0) {
8124  $this->debug('Setting new cookie(s)');
8125  $this->cookies = $cookies;
8126  }
8127  return true;
8128  }
8129  if (sizeof($cookies) == 0) {
8130  // no new cookies: keep what we've got
8131  return true;
8132  }
8133  // merge
8134  foreach ($cookies as $newCookie) {
8135  if (!is_array($newCookie)) {
8136  continue;
8137  }
8138  if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
8139  continue;
8140  }
8141  $newName = $newCookie['name'];
8142 
8143  $found = false;
8144  for ($i = 0; $i < count($this->cookies); $i++) {
8145  $cookie = $this->cookies[$i];
8146  if (!is_array($cookie)) {
8147  continue;
8148  }
8149  if (!isset($cookie['name'])) {
8150  continue;
8151  }
8152  if ($newName != $cookie['name']) {
8153  continue;
8154  }
8155  $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
8156  $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
8157  if ($newDomain != $domain) {
8158  continue;
8159  }
8160  $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
8161  $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
8162  if ($newPath != $path) {
8163  continue;
8164  }
8165  $this->cookies[$i] = $newCookie;
8166  $found = true;
8167  $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
8168  break;
8169  }
8170  if (! $found) {
8171  $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
8172  $this->cookies[] = $newCookie;
8173  }
8174  }
8175  return true;
8176  }
8177 }
8178 
8179 if (!extension_loaded('soap')) {
8183  class soapclient extends nusoap_client
8184  {
8185  }
8186 }
if($err=$client->getError()) $namespace
appendDebug($string)
adds debug data to the instance debug string without formatting
Definition: nusoap.php:305
Backward compatibility.
Definition: nusoap.php:4598
$res
Definition: ltiservices.php:69
& getDebugAsXMLComment()
gets the current debug data for this instance as an XML comment this may change the contents of the d...
Definition: nusoap.php:346
setError($str)
sets error string
Definition: nusoap.php:395
$_GET["client_id"]
Definition: webdav.php:30
Contains information for a SOAP fault.
Definition: nusoap.php:1035
$scope
Definition: ltiregstart.php:53
transport class for sending/receiving data via HTTP and HTTPS NOTE: PHP must be compiled with the CUR...
Definition: nusoap.php:2185
& getDebug()
gets the current debug data for this instance
Definition: nusoap.php:332
if(empty($path)) $serviceName
Definition: ltiservices.php:38
isArraySimpleOrStruct($val)
detect if array is a simple array or a struct (associative array)
Definition: nusoap.php:407
parses a WSDL file, allows access to it&#39;s data, other utility methods.
Definition: nusoap.php:4615
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:64
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:33
getOperationDataForSoapAction($soapAction, $bindingType='soap')
returns an associative array of data necessary for calling an operation
Definition: nusoap.php:5256
if(count($parts) !=3) $payload
Definition: ltitoken.php:70
$XMLSchemaVersion
Definition: nusoap.php:155
Backward compatibility.
Definition: nusoap.php:1110
nusoap_server allows the user to create a SOAP server that is capable of receiving messages and retur...
Definition: nusoap.php:3520
$response
Definition: xapitoken.php:93
getLocalPart($str)
returns the local part of a prefixed string returns the original string, if not prefixed ...
Definition: nusoap.php:821
$responseData
serialize($debug=0)
serialize the parsed wsdl
Definition: nusoap.php:5494
__construct()
constructor
Definition: nusoap.php:237
Backward compatibility.
Definition: nusoap.php:2060
$path
Definition: ltiservices.php:32
For creating serializable abstractions of native PHP types.
Definition: nusoap.php:2079
catch(\Exception $e) $req
Definition: xapiproxy.php:93
getError()
returns error string if present
Definition: nusoap.php:381
debug($string)
adds debug data to the instance debug string with formatting
Definition: nusoap.php:292
Backward compatibility.
Definition: nusoap.php:7175
$messages
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Definition: xapiexit.php:22
__construct(VocabulariesInterface $vocabularies)
serializeRPCParameters($operation, $direction, $parameters, $bindingType='soap')
serialize PHP values according to a WSDL message definition contrary to the method name...
Definition: nusoap.php:5732
getPrefixFromNamespace($ns)
returns the prefix for a given namespace (or prefix) or false if no prefixes registered for the given...
Definition: nusoap.php:872
expandQname($qname)
expands (changes prefix to namespace) a qualified name
Definition: nusoap.php:795
parses an XML Schema, allows access to it&#39;s data, other utility methods.
Definition: nusoap.php:1127
setCredentials($username, $password, $authtype='basic', $certRequest=array())
if authenticating, set user credentials here
Definition: nusoap.php:5168
nusoap_base
Definition: nusoap.php:96
$_SERVER['HTTP_HOST']
Definition: raiseError.php:10
webDescription()
prints html description of services
Definition: nusoap.php:5352
$param
Definition: xapitoken.php:46
$out
Definition: buildRTE.php:24
string $key
Consumer key/client ID value.
Definition: System.php:193
[nu]soapclient higher level class for easy usage.
Definition: nusoap.php:7203
$url
Definition: ltiregstart.php:35
serializeEnvelope($body, $headers=false, $namespaces=array(), $style='rpc', $use='encoded', $encodingStyle='http://schemas.xmlsoap.org/soap/encoding/')
serializes a message
Definition: nusoap.php:700
$http
Definition: raiseError.php:7
varDump($data)
Returns a string with the output of var_dump.
Definition: nusoap.php:909
getPrefix($str)
returns the prefix part of a prefixed string returns false, if not prefixed
Definition: nusoap.php:839
getOperations($bindingType='soap')
returns an assoc array of operation names => operation data
Definition: nusoap.php:5192
serialize()
serialize a fault
Definition: nusoap.php:1085
$soap_defencoding
Definition: nusoap.php:164
expandEntities($val)
expands entities, e.g.
Definition: nusoap.php:363
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$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:855
nusoap_parser class parses SOAP XML messages into native PHP values
Definition: nusoap.php:6543
$message
Definition: xapiexit.php:32
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:6458
getOperationData($operation, $bindingType='soap')
returns an associative array of data necessary for calling an operation
Definition: nusoap.php:5224
clearDebug()
clears the current debug data for this instance
Definition: nusoap.php:319
fetchWSDL($wsdl)
fetches the WSDL document and parses it
Definition: nusoap.php:4695
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:433
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

Definition at line 85 of file nusoap.php.