Instantly share code, notes, and snippets.

Embed
What would you like to do?
PHP7 nusoap library
<?php
/*
$Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
NuSOAP - Web Services Toolkit for PHP
Copyright (c) 2002 NuSphere Corporation
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
The NuSOAP project home is:
http://sourceforge.net/projects/nusoap/
The primary support for NuSOAP is the Help forum on the project home page.
If you have any questions or comments, please email:
Dietrich Ayala
dietrich@ganx4.com
http://dietrich.ganx4.com/nusoap
NuSphere Corporation
http://www.nusphere.com
*/
/*
* Some of the standards implmented in whole or part by NuSOAP:
*
* SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
* WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
* SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
* XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
* Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
* XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
* RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
* RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
* RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
*/
/* load classes
// necessary classes
require_once('class.soapclient.php');
require_once('class.soap_val.php');
require_once('class.soap_parser.php');
require_once('class.soap_fault.php');
// transport classes
require_once('class.soap_transport_http.php');
// optional add-on classes
require_once('class.xmlschema.php');
require_once('class.wsdl.php');
// server class
require_once('class.soap_server.php');*/
// class variable emulation
// cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9;
/**
*
* nusoap_base
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @author Scott Nichol <snichol@users.sourceforge.net>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class nusoap_base
{
/**
* Identification for HTTP headers.
*
* @var string
* @access private
*/
var $title = 'NuSOAP';
/**
* Version for HTTP headers.
*
* @var string
* @access private
*/
var $version = '0.9.5';
/**
* CVS revision for HTTP headers.
*
* @var string
* @access private
*/
var $revision = '$Revision: 1.123 $';
/**
* Current error string (manipulated by getError/setError)
*
* @var string
* @access private
*/
var $error_str = '';
/**
* Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
*
* @var string
* @access private
*/
var $debug_str = '';
/**
* toggles automatic encoding of special characters as entities
* (should always be true, I think)
*
* @var boolean
* @access private
*/
var $charencoding = true;
/**
* the debug level for this instance
*
* @var integer
* @access private
*/
var $debugLevel;
/**
* set schema version
*
* @var string
* @access public
*/
var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
/**
* charset encoding for outgoing messages
*
* @var string
* @access public
*/
var $soap_defencoding = 'ISO-8859-1';
//var $soap_defencoding = 'UTF-8';
/**
* namespaces in an array of prefix => uri
*
* this is "seeded" by a set of constants, but it may be altered by code
*
* @var array
* @access public
*/
var $namespaces = array(
'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
'xsd' => 'http://www.w3.org/2001/XMLSchema',
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
);
/**
* namespaces used in the current context, e.g. during serialization
*
* @var array
* @access private
*/
var $usedNamespaces = array();
/**
* XML Schema types in an array of uri => (array of xml type => php type)
* is this legacy yet?
* no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
*
* @var array
* @access public
*/
var $typemap = array(
'http://www.w3.org/2001/XMLSchema' => array(
'string' => 'string', 'boolean' => 'boolean', 'float' => 'double', 'double' => 'double', 'decimal' => 'double',
'duration' => '', 'dateTime' => 'string', 'time' => 'string', 'date' => 'string', 'gYearMonth' => '',
'gYear' => '', 'gMonthDay' => '', 'gDay' => '', 'gMonth' => '', 'hexBinary' => 'string', 'base64Binary' => 'string',
// abstract "any" types
'anyType' => 'string', 'anySimpleType' => 'string',
// derived datatypes
'normalizedString' => 'string', 'token' => 'string', 'language' => '', 'NMTOKEN' => '', 'NMTOKENS' => '', 'Name' => '', 'NCName' => '', 'ID' => '',
'IDREF' => '', 'IDREFS' => '', 'ENTITY' => '', 'ENTITIES' => '', 'integer' => 'integer', 'nonPositiveInteger' => 'integer',
'negativeInteger' => 'integer', 'long' => 'integer', 'int' => 'integer', 'short' => 'integer', 'byte' => 'integer', 'nonNegativeInteger' => 'integer',
'unsignedLong' => '', 'unsignedInt' => '', 'unsignedShort' => '', 'unsignedByte' => '', 'positiveInteger' => ''),
'http://www.w3.org/2000/10/XMLSchema' => array(
'i4' => '', 'int' => 'integer', 'boolean' => 'boolean', 'string' => 'string', 'double' => 'double',
'float' => 'double', 'dateTime' => 'string',
'timeInstant' => 'string', 'base64Binary' => 'string', 'base64' => 'string', 'ur-type' => 'array'),
'http://www.w3.org/1999/XMLSchema' => array(
'i4' => '', 'int' => 'integer', 'boolean' => 'boolean', 'string' => 'string', 'double' => 'double',
'float' => 'double', 'dateTime' => 'string',
'timeInstant' => 'string', 'base64Binary' => 'string', 'base64' => 'string', 'ur-type' => 'array'),
'http://soapinterop.org/xsd' => array('SOAPStruct' => 'struct'),
'http://schemas.xmlsoap.org/soap/encoding/' => array('base64' => 'string', 'array' => 'array', 'Array' => 'array'),
'http://xml.apache.org/xml-soap' => array('Map')
);
/**
* XML entities to convert
*
* @var array
* @access public
* @deprecated
* @see expandEntities
*/
var $xmlEntities = array('quot' => '"', 'amp' => '&',
'lt' => '<', 'gt' => '>', 'apos' => "'");
/**
* constructor
*
* @access public
*/
function __construct()
{
$this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
}
/**
* gets the global debug level, which applies to future instances
*
* @return integer Debug level 0-9, where 0 turns off
* @access public
*/
function getGlobalDebugLevel()
{
return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
}
/**
* sets the global debug level, which applies to future instances
*
* @param int $level Debug level 0-9, where 0 turns off
* @access public
*/
function setGlobalDebugLevel($level)
{
$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
}
/**
* gets the debug level for this instance
*
* @return int Debug level 0-9, where 0 turns off
* @access public
*/
function getDebugLevel()
{
return $this->debugLevel;
}
/**
* sets the debug level for this instance
*
* @param int $level Debug level 0-9, where 0 turns off
* @access public
*/
function setDebugLevel($level)
{
$this->debugLevel = $level;
}
/**
* adds debug data to the instance debug string with formatting
*
* @param string $string debug data
* @access private
*/
function debug($string)
{
if ($this->debugLevel > 0) {
$this->appendDebug($this->getmicrotime() . ' ' . get_class($this) . ": $string\n");
}
}
/**
* adds debug data to the instance debug string without formatting
*
* @param string $string debug data
* @access public
*/
function appendDebug($string)
{
if ($this->debugLevel > 0) {
// it would be nice to use a memory stream here to use
// memory more efficiently
$this->debug_str .= $string;
}
}
/**
* clears the current debug data for this instance
*
* @access public
*/
function clearDebug()
{
// it would be nice to use a memory stream here to use
// memory more efficiently
$this->debug_str = '';
}
/**
* gets the current debug data for this instance
*
* @return debug data
* @access public
*/
function &getDebug()
{
// it would be nice to use a memory stream here to use
// memory more efficiently
return $this->debug_str;
}
/**
* gets the current debug data for this instance as an XML comment
* this may change the contents of the debug data
*
* @return debug data as an XML comment
* @access public
*/
function &getDebugAsXMLComment()
{
// it would be nice to use a memory stream here to use
// memory more efficiently
while (strpos($this->debug_str, '--')) {
$this->debug_str = str_replace('--', '- -', $this->debug_str);
}
$ret = "<!--\n" . $this->debug_str . "\n-->";
return $ret;
}
/**
* expands entities, e.g. changes '<' to '&lt;'.
*
* @param string $val The string in which to expand entities.
* @access private
*/
function expandEntities($val)
{
if ($this->charencoding) {
$val = str_replace('&', '&amp;', $val);
$val = str_replace("'", '&apos;', $val);
$val = str_replace('"', '&quot;', $val);
$val = str_replace('<', '&lt;', $val);
$val = str_replace('>', '&gt;', $val);
}
return $val;
}
/**
* returns error string if present
*
* @return mixed error string or false
* @access public
*/
function getError()
{
if ($this->error_str != '') {
return $this->error_str;
}
return false;
}
/**
* sets error string
*
* @return boolean $string error string
* @access private
*/
function setError($str)
{
$this->error_str = $str;
}
/**
* detect if array is a simple array or a struct (associative array)
*
* @param mixed $val The PHP array
* @return string (arraySimple|arrayStruct)
* @access private
*/
function isArraySimpleOrStruct($val)
{
$keyList = array_keys($val);
foreach ($keyList as $keyListValue) {
if (!is_int($keyListValue)) {
return 'arrayStruct';
}
}
return 'arraySimple';
}
/**
* serializes PHP values in accordance w/ section 5. Type information is
* not serialized if $use == 'literal'.
*
* @param mixed $val The value to serialize
* @param string $name The name (local part) of the XML element
* @param string $type The XML schema type (local part) for the element
* @param string $name_ns The namespace for the name of the XML element
* @param string $type_ns The namespace for the type of the element
* @param array $attributes The attributes to serialize as name=>value pairs
* @param string $use The WSDL "use" (encoded|literal)
* @param boolean $soapval Whether this is called from soapval.
* @return string The serialized element, possibly with child elements
* @access public
*/
function serialize_val($val, $name = false, $type = false, $name_ns = false, $type_ns = false, $attributes = false, $use = 'encoded', $soapval = false)
{
$this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
$this->appendDebug('value=' . $this->varDump($val));
$this->appendDebug('attributes=' . $this->varDump($attributes));
if (is_object($val) && get_class($val) == 'soapval' && (!$soapval)) {
$this->debug("serialize_val: serialize soapval");
$xml = $val->serialize($use);
$this->appendDebug($val->getDebug());
$val->clearDebug();
$this->debug("serialize_val of soapval returning $xml");
return $xml;
}
// force valid name if necessary
if (is_numeric($name)) {
$name = '__numeric_' . $name;
} elseif (!$name) {
$name = 'noname';
}
// if name has ns, add ns prefix to name
$xmlns = '';
if ($name_ns) {
$prefix = 'nu' . rand(1000, 9999);
$name = $prefix . ':' . $name;
$xmlns .= " xmlns:$prefix=\"$name_ns\"";
}
// if type is prefixed, create type prefix
if ($type_ns != '' && $type_ns == $this->namespaces['xsd']) {
// need to fix this. shouldn't default to xsd if no ns specified
// w/o checking against typemap
$type_prefix = 'xsd';
} elseif ($type_ns) {
$type_prefix = 'ns' . rand(1000, 9999);
$xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
}
// serialize attributes if present
$atts = '';
if ($attributes) {
foreach ($attributes as $k => $v) {
$atts .= " $k=\"" . $this->expandEntities($v) . '"';
}
}
// serialize null value
if (is_null($val)) {
$this->debug("serialize_val: serialize null");
if ($use == 'literal') {
// TODO: depends on minOccurs
$xml = "<$name$xmlns$atts/>";
$this->debug("serialize_val returning $xml");
return $xml;
} else {
if (isset($type) && isset($type_prefix)) {
$type_str = " xsi:type=\"$type_prefix:$type\"";
} else {
$type_str = '';
}
$xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
$this->debug("serialize_val returning $xml");
return $xml;
}
}
// serialize if an xsd built-in primitive type
if ($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])) {
$this->debug("serialize_val: serialize xsd built-in primitive type");
if (is_bool($val)) {
if ($type == 'boolean') {
$val = $val ? 'true' : 'false';
} elseif (!$val) {
$val = 0;
}
} elseif (is_string($val)) {
$val = $this->expandEntities($val);
}
if ($use == 'literal') {
$xml = "<$name$xmlns$atts>$val</$name>";
$this->debug("serialize_val returning $xml");
return $xml;
} else {
$xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
$this->debug("serialize_val returning $xml");
return $xml;
}
}
// detect type and serialize
$xml = '';
switch (true) {
case (is_bool($val) || $type == 'boolean'):
$this->debug("serialize_val: serialize boolean");
if ($type == 'boolean') {
$val = $val ? 'true' : 'false';
} elseif (!$val) {
$val = 0;
}
if ($use == 'literal') {
$xml .= "<$name$xmlns$atts>$val</$name>";
} else {
$xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
}
break;
case (is_int($val) || is_long($val) || $type == 'int'):
$this->debug("serialize_val: serialize int");
if ($use == 'literal') {
$xml .= "<$name$xmlns$atts>$val</$name>";
} else {
$xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
}
break;
case (is_float($val) || is_double($val) || $type == 'float'):
$this->debug("serialize_val: serialize float");
if ($use == 'literal') {
$xml .= "<$name$xmlns$atts>$val</$name>";
} else {
$xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
}
break;
case (is_string($val) || $type == 'string'):
$this->debug("serialize_val: serialize string");
$val = $this->expandEntities($val);
if ($use == 'literal') {
$xml .= "<$name$xmlns$atts>$val</$name>";
} else {
$xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
}
break;
case is_object($val):
$this->debug("serialize_val: serialize object");
if (get_class($val) == 'soapval') {
$this->debug("serialize_val: serialize soapval object");
$pXml = $val->serialize($use);
$this->appendDebug($val->getDebug());
$val->clearDebug();
} else {
if (!$name) {
$name = get_class($val);
$this->debug("In serialize_val, used class name $name as element name");
} else {
$this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
}
foreach (get_object_vars($val) as $k => $v) {
$pXml = isset($pXml) ? $pXml . $this->serialize_val($v, $k, false, false, false, false, $use) : $this->serialize_val($v, $k, false, false, false, false, $use);
}
}
if (isset($type) && isset($type_prefix)) {
$type_str = " xsi:type=\"$type_prefix:$type\"";
} else {
$type_str = '';
}
if ($use == 'literal') {
$xml .= "<$name$xmlns$atts>$pXml</$name>";
} else {
$xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
}
break;
break;
case (is_array($val) || $type):
// detect if struct or array
$valueType = $this->isArraySimpleOrStruct($val);
if ($valueType == 'arraySimple' || preg_match('/^ArrayOf/', $type)) {
$this->debug("serialize_val: serialize array");
$i = 0;
if (is_array($val) && count($val) > 0) {
foreach ($val as $v) {
if (is_object($v) && get_class($v) == 'soapval') {
$tt_ns = $v->type_ns;
$tt = $v->type;
} elseif (is_array($v)) {
$tt = $this->isArraySimpleOrStruct($v);
} else {
$tt = gettype($v);
}
$array_types[$tt] = 1;
// TODO: for literal, the name should be $name
$xml .= $this->serialize_val($v, 'item', false, false, false, false, $use);
++$i;
}
if (count($array_types) > 1) {
$array_typename = 'xsd:anyType';
} elseif (isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
if ($tt == 'integer') {
$tt = 'int';
}
$array_typename = 'xsd:' . $tt;
} elseif (isset($tt) && $tt == 'arraySimple') {
$array_typename = 'SOAP-ENC:Array';
} elseif (isset($tt) && $tt == 'arrayStruct') {
$array_typename = 'unnamed_struct_use_soapval';
} else {
// if type is prefixed, create type prefix
if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']) {
$array_typename = 'xsd:' . $tt;
} elseif ($tt_ns) {
$tt_prefix = 'ns' . rand(1000, 9999);
$array_typename = "$tt_prefix:$tt";
$xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
} else {
$array_typename = $tt;
}
}
$array_type = $i;
if ($use == 'literal') {
$type_str = '';
} elseif (isset($type) && isset($type_prefix)) {
$type_str = " xsi:type=\"$type_prefix:$type\"";
} else {
$type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"" . $array_typename . "[$array_type]\"";
}
// empty array
} else {
if ($use == 'literal') {
$type_str = '';
} elseif (isset($type) && isset($type_prefix)) {
$type_str = " xsi:type=\"$type_prefix:$type\"";
} else {
$type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
}
}
// TODO: for array in literal, there is no wrapper here
$xml = "<$name$xmlns$type_str$atts>" . $xml . "</$name>";
} else {
// got a struct
$this->debug("serialize_val: serialize struct");
if (isset($type) && isset($type_prefix)) {
$type_str = " xsi:type=\"$type_prefix:$type\"";
} else {
$type_str = '';
}
if ($use == 'literal') {
$xml .= "<$name$xmlns$atts>";
} else {
$xml .= "<$name$xmlns$type_str$atts>";
}
foreach ($val as $k => $v) {
// Apache Map
if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
$xml .= '<item>';
$xml .= $this->serialize_val($k, 'key', false, false, false, false, $use);
$xml .= $this->serialize_val($v, 'value', false, false, false, false, $use);
$xml .= '</item>';
} else {
$xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
}
}
$xml .= "</$name>";
}
break;
default:
$this->debug("serialize_val: serialize unknown");
$xml .= 'not detected, got ' . gettype($val) . ' for ' . $val;
break;
}
$this->debug("serialize_val returning $xml");
return $xml;
}
/**
* serializes a message
*
* @param string $body the XML of the SOAP body
* @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
* @param array $namespaces optional the namespaces used in generating the body and headers
* @param string $style optional (rpc|document)
* @param string $use optional (encoded|literal)
* @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
* @return string the message
* @access public
*/
function serializeEnvelope($body, $headers = false, $namespaces = array(), $style = 'rpc', $use = 'encoded', $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/')
{
// TODO: add an option to automatically run utf8_encode on $body and $headers
// if $this->soap_defencoding is UTF-8. Not doing this automatically allows
// one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
$this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
$this->debug("headers:");
$this->appendDebug($this->varDump($headers));
$this->debug("namespaces:");
$this->appendDebug($this->varDump($namespaces));
// serialize namespaces
$ns_string = '';
foreach (array_merge($this->namespaces, $namespaces) as $k => $v) {
$ns_string .= " xmlns:$k=\"$v\"";
}
if ($encodingStyle) {
$ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
}
// serialize headers
if ($headers) {
if (is_array($headers)) {
$xml = '';
foreach ($headers as $k => $v) {
if (is_object($v) && get_class($v) == 'soapval') {
$xml .= $this->serialize_val($v, false, false, false, false, false, $use);
} else {
$xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
}
}
$headers = $xml;
$this->debug("In serializeEnvelope, serialized array of headers to $headers");
}
$headers = "<SOAP-ENV:Header>" . $headers . "</SOAP-ENV:Header>";
}
// serialize envelope
return
'<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?' . ">" .
'<SOAP-ENV:Envelope' . $ns_string . ">" .
$headers .
"<SOAP-ENV:Body>" .
$body .
"</SOAP-ENV:Body>" .
"</SOAP-ENV:Envelope>";
}
/**
* formats a string to be inserted into an HTML stream
*
* @param string $str The string to format
* @return string The formatted string
* @access public
* @deprecated
*/
function formatDump($str)
{
$str = htmlspecialchars($str);
return nl2br($str);
}
/**
* contracts (changes namespace to prefix) a qualified name
*
* @param string $qname qname
* @return string contracted qname
* @access private
*/
function contractQname($qname)
{
// get element namespace
//$this->xdebug("Contract $qname");
if (strrpos($qname, ':')) {
// get unqualified name
$name = substr($qname, strrpos($qname, ':') + 1);
// get ns
$ns = substr($qname, 0, strrpos($qname, ':'));
$p = $this->getPrefixFromNamespace($ns);
if ($p) {
return $p . ':' . $name;
}
return $qname;
} else {
return $qname;
}
}
/**
* expands (changes prefix to namespace) a qualified name
*
* @param string $qname qname
* @return string expanded qname
* @access private
*/
function expandQname($qname)
{
// get element prefix
if (strpos($qname, ':') && !preg_match('/^http:\/\//', $qname)) {
// get unqualified name
$name = substr(strstr($qname, ':'), 1);
// get ns prefix
$prefix = substr($qname, 0, strpos($qname, ':'));
if (isset($this->namespaces[$prefix])) {
return $this->namespaces[$prefix] . ':' . $name;
} else {
return $qname;
}
} else {
return $qname;
}
}
/**
* returns the local part of a prefixed string
* returns the original string, if not prefixed
*
* @param string $str The prefixed string
* @return string The local part
* @access public
*/
function getLocalPart($str)
{
if ($sstr = strrchr($str, ':')) {
// get unqualified name
return substr($sstr, 1);
} else {
return $str;
}
}
/**
* returns the prefix part of a prefixed string
* returns false, if not prefixed
*
* @param string $str The prefixed string
* @return mixed The prefix or false if there is no prefix
* @access public
*/
function getPrefix($str)
{
if ($pos = strrpos($str, ':')) {
// get prefix
return substr($str, 0, $pos);
}
return false;
}
/**
* pass it a prefix, it returns a namespace
*
* @param string $prefix The prefix
* @return mixed The namespace, false if no namespace has the specified prefix
* @access public
*/
function getNamespaceFromPrefix($prefix)
{
if (isset($this->namespaces[$prefix])) {
return $this->namespaces[$prefix];
}
//$this->setError("No namespace registered for prefix '$prefix'");
return false;
}
/**
* returns the prefix for a given namespace (or prefix)
* or false if no prefixes registered for the given namespace
*
* @param string $ns The namespace
* @return mixed The prefix, false if the namespace has no prefixes
* @access public
*/
function getPrefixFromNamespace($ns)
{
foreach ($this->namespaces as $p => $n) {
if ($ns == $n || $ns == $p) {
$this->usedNamespaces[$p] = $n;
return $p;
}
}
return false;
}
/**
* returns the time in ODBC canonical form with microseconds
*
* @return string The time in ODBC canonical form with microseconds
* @access public
*/
function getmicrotime()
{
if (function_exists('gettimeofday')) {
$tod = gettimeofday();
$sec = $tod['sec'];
$usec = $tod['usec'];
} else {
$sec = time();
$usec = 0;
}
return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
}
/**
* Returns a string with the output of var_dump
*
* @param mixed $data The variable to var_dump
* @return string The output of var_dump
* @access public
*/
function varDump($data)
{
ob_start();
var_dump($data);
$ret_val = ob_get_contents();
ob_end_clean();
return $ret_val;
}
/**
* represents the object as a string
*
* @return string
* @access public
*/
function __toString()
{
return $this->varDump($this);
}
}
// XML Schema Datatype Helper Functions
//xsd:dateTime helpers
/**
* convert unix timestamp to ISO 8601 compliant date string
*
* @param int $timestamp Unix time stamp
* @param boolean $utc Whether the time stamp is UTC or local
* @return mixed ISO 8601 date string or false
* @access public
*/
function timestamp_to_iso8601($timestamp, $utc = true)
{
$datestr = date('Y-m-d\TH:i:sO', $timestamp);
$pos = strrpos($datestr, "+");
if ($pos === false) {
$pos = strrpos($datestr, "-");
}
if ($pos !== false) {
if (strlen($datestr) == $pos + 5) {
$datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2);
}
}
if ($utc) {
$pattern = '/' .
'([0-9]{4})-' . // centuries & years CCYY-
'([0-9]{2})-' . // months MM-
'([0-9]{2})' . // days DD
'T' . // separator T
'([0-9]{2}):' . // hours hh:
'([0-9]{2}):' . // minutes mm:
'([0-9]{2})(\.[0-9]*)?' . // seconds ss.ss...
'(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
'/';
if (preg_match($pattern, $datestr, $regs)) {
return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ', $regs[1], $regs[2], $regs[3], $regs[4], $regs[5], $regs[6]);
}
return false;
} else {
return $datestr;
}
}
/**
* convert ISO 8601 compliant date string to unix timestamp
*
* @param string $datestr ISO 8601 compliant date string
* @return mixed Unix timestamp (int) or false
* @access public
*/
function iso8601_to_timestamp($datestr)
{
$pattern = '/' .
'([0-9]{4})-' . // centuries & years CCYY-
'([0-9]{2})-' . // months MM-
'([0-9]{2})' . // days DD
'T' . // separator T
'([0-9]{2}):' . // hours hh:
'([0-9]{2}):' . // minutes mm:
'([0-9]{2})(\.[0-9]+)?' . // seconds ss.ss...
'(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
'/';
if (preg_match($pattern, $datestr, $regs)) {
// not utc
if ($regs[8] != 'Z') {
$op = substr($regs[8], 0, 1);
$h = substr($regs[8], 1, 2);
$m = substr($regs[8], strlen($regs[8]) - 2, 2);
if ($op == '-') {
$regs[4] = $regs[4] + $h;
$regs[5] = $regs[5] + $m;
} elseif ($op == '+') {
$regs[4] = $regs[4] - $h;
$regs[5] = $regs[5] - $m;
}
}
return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
// return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
} else {
return false;
}
}
/**
* sleeps some number of microseconds
*
* @param string $usec the number of microseconds to sleep
* @access public
* @deprecated
*/
function usleepWindows($usec)
{
$start = gettimeofday();
do {
$stop = gettimeofday();
$timePassed = 1000000 * ($stop['sec'] - $start['sec'])
+ $stop['usec'] - $start['usec'];
} while ($timePassed < $usec);
}
/**
* Contains information for a SOAP fault.
* Mainly used for returning faults from deployed functions
* in a server instance.
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class nusoap_fault extends nusoap_base
{
/**
* The fault code (client|server)
*
* @var string
* @access private
*/
var $faultcode;
/**
* The fault actor
*
* @var string
* @access private
*/
var $faultactor;
/**
* The fault string, a description of the fault
*
* @var string
* @access private
*/
var $faultstring;
/**
* The fault detail, typically a string or array of string
*
* @var mixed
* @access private
*/
var $faultdetail;
/**
* constructor
*
* @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server)
* @param string $faultactor only used when msg routed between multiple actors
* @param string $faultstring human readable error message
* @param mixed $faultdetail detail, typically a string or array of string
*/
function __construct($faultcode, $faultactor = '', $faultstring = '', $faultdetail = '')
{
parent::__construct();
$this->faultcode = $faultcode;
$this->faultactor = $faultactor;
$this->faultstring = $faultstring;
$this->faultdetail = $faultdetail;
}
/**
* serialize a fault
*
* @return string The serialization of the fault instance.
* @access public
*/
function serialize()
{
$ns_string = '';
foreach ($this->namespaces as $k => $v) {
$ns_string .= "\n xmlns:$k=\"$v\"";
}
$return_msg =
'<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?>' .
'<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string . ">\n" .
'<SOAP-ENV:Body>' .
'<SOAP-ENV:Fault>' .
$this->serialize_val($this->faultcode, 'faultcode') .
$this->serialize_val($this->faultactor, 'faultactor') .
$this->serialize_val($this->faultstring, 'faultstring') .
$this->serialize_val($this->faultdetail, 'detail') .
'</SOAP-ENV:Fault>' .
'</SOAP-ENV:Body>' .
'</SOAP-ENV:Envelope>';
return $return_msg;
}
}
/**
* Backward compatibility
*/
class soap_fault extends nusoap_fault
{
}
/**
* parses an XML Schema, allows access to it's data, other utility methods.
* imperfect, no validation... yet, but quite functional.
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @author Scott Nichol <snichol@users.sourceforge.net>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class nusoap_xmlschema extends nusoap_base
{
// files
var $schema = '';
var $xml = '';
// namespaces
var $enclosingNamespaces;
// schema info
var $schemaInfo = array();
var $schemaTargetNamespace = '';
// types, elements, attributes defined by the schema
var $attributes = array();
var $complexTypes = array();
var $complexTypeStack = array();
var $currentComplexType = null;
var $elements = array();
var $elementStack = array();
var $currentElement = null;
var $simpleTypes = array();
var $simpleTypeStack = array();
var $currentSimpleType = null;
// imports
var $imports = array();
// parser vars
var $parser;
var $position = 0;
var $depth = 0;
var $depth_array = array();
var $message = array();
var $defaultNamespace = array();
/**
* constructor
*
* @param string $schema schema document URI
* @param string $xml xml document URI
* @param string $namespaces namespaces defined in enclosing XML
* @access public
*/
function __construct($schema = '', $xml = '', $namespaces = array())
{
parent::__construct();
$this->debug('nusoap_xmlschema class instantiated, inside constructor');
// files
$this->schema = $schema;
$this->xml = $xml;
// namespaces
$this->enclosingNamespaces = $namespaces;
$this->namespaces = array_merge($this->namespaces, $namespaces);
// parse schema file
if ($schema != '') {
$this->debug('initial schema file: ' . $schema);
$this->parseFile($schema, 'schema');
}
// parse xml file
if ($xml != '') {
$this->debug('initial xml file: ' . $xml);
$this->parseFile($xml, 'xml');
}
}
/**
* parse an XML file
*
* @param string $xml path/URL to XML file
* @param string $type (schema | xml)
* @return boolean
* @access public
*/
function parseFile($xml, $type)
{
// parse xml file
if ($xml != "") {
$xmlStr = @join("", @file($xml));
if ($xmlStr == "") {
$msg = 'Error reading XML from ' . $xml;
$this->setError($msg);
$this->debug($msg);
return false;
} else {
$this->debug("parsing $xml");
$this->parseString($xmlStr, $type);
$this->debug("done parsing $xml");
return true;
}
}
return false;
}
/**
* parse an XML string
*
* @param string $xml path or URL
* @param string $type (schema|xml)
* @access private
*/
function parseString($xml, $type)
{
// parse xml string
if ($xml != "") {
// Create an XML parser.
$this->parser = xml_parser_create();
// Set the options for parsing the XML data.
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
// Set the object for the parser.
xml_set_object($this->parser, $this);
// Set the element handlers for the parser.
if ($type == "schema") {
xml_set_element_handler($this->parser, 'schemaStartElement', 'schemaEndElement');
xml_set_character_data_handler($this->parser, 'schemaCharacterData');
} elseif ($type == "xml") {
xml_set_element_handler($this->parser, 'xmlStartElement', 'xmlEndElement');
xml_set_character_data_handler($this->parser, 'xmlCharacterData');
}
// Parse the XML file.
if (!xml_parse($this->parser, $xml, true)) {
// Display an error message.
$errstr = sprintf('XML error parsing XML schema on line %d: %s',
xml_get_current_line_number($this->parser),
xml_error_string(xml_get_error_code($this->parser))
);
$this->debug($errstr);
$this->debug("XML payload:\n" . $xml);
$this->setError($errstr);
}
xml_parser_free($this->parser);
unset($this->parser);
} else {
$this->debug('no xml passed to parseString()!!');
$this->setError('no xml passed to parseString()!!');
}
}
/**
* gets a type name for an unnamed type
*
* @param string Element name
* @return string A type name for an unnamed type
* @access private
*/
function CreateTypeName($ename)
{
$scope = '';
for ($i = 0; $i < count($this->complexTypeStack); $i++) {
$scope .= $this->complexTypeStack[$i] . '_';
}
return $scope . $ename . '_ContainedType';
}
/**
* start-element handler
*
* @param string $parser XML parser object
* @param string $name element name
* @param string $attrs associative array of attributes
* @access private
*/
function schemaStartElement($parser, $name, $attrs)
{
// position in the total number of elements, starting from 0
$pos = $this->position++;
$depth = $this->depth++;
// set self as current value for this depth
$this->depth_array[$depth] = $pos;
$this->message[$pos] = array('cdata' => '');
if ($depth > 0) {
$this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
} else {
$this->defaultNamespace[$pos] = false;
}
// get element prefix
if ($prefix = $this->getPrefix($name)) {
// get unqualified name
$name = $this->getLocalPart($name);
} else {
$prefix = '';
}
// loop thru attributes, expanding, and registering namespace declarations
if (count($attrs) > 0) {
foreach ($attrs as $k => $v) {
// if ns declarations, add to class level array of valid namespaces
if (preg_match('/^xmlns/', $k)) {
//$this->xdebug("$k: $v");
//$this->xdebug('ns_prefix: '.$this->getPrefix($k));
if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
//$this->xdebug("Add namespace[$ns_prefix] = $v");
$this->namespaces[$ns_prefix] = $v;
} else {
$this->defaultNamespace[$pos] = $v;
if (!$this->getPrefixFromNamespace($v)) {
$this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
}
}
if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
$this->XMLSchemaVersion = $v;
$this->namespaces['xsi'] = $v . '-instance';
}
}
}
foreach ($attrs as $k => $v) {
// expand each attribute
$k = strpos($k, ':') ? $this->expandQname($k) : $k;
$v = strpos($v, ':') ? $this->expandQname($v) : $v;
$eAttrs[$k] = $v;
}
$attrs = $eAttrs;
} else {
$attrs = array();
}
// find status, register data
switch ($name) {
case 'all': // (optional) compositor content for a complexType
case 'choice':
case 'group':
case 'sequence':
//$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
$this->complexTypes[$this->currentComplexType]['compositor'] = $name;
//if($name == 'all' || $name == 'sequence'){
// $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
//}
break;
case 'attribute': // complexType attribute
//$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
$this->xdebug("parsing attribute:");
$this->appendDebug($this->varDump($attrs));
if (!isset($attrs['form'])) {
// TODO: handle globals
$attrs['form'] = $this->schemaInfo['attributeFormDefault'];
}
if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
$v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
if (!strpos($v, ':')) {
// no namespace in arrayType attribute value...
if ($this->defaultNamespace[$pos]) {
// ...so use the default
$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
}
}
}
if (isset($attrs['name'])) {
$this->attributes[$attrs['name']] = $attrs;
$aname = $attrs['name'];
} elseif (isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType') {
if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
$aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
} else {
$aname = '';
}
} elseif (isset($attrs['ref'])) {
$aname = $attrs['ref'];
$this->attributes[$attrs['ref']] = $attrs;
}
if ($this->currentComplexType) { // This should *always* be
$this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
}
// arrayType attribute
if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType') {
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
$prefix = $this->getPrefix($aname);
if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
$v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
} else {
$v = '';
}
if (strpos($v, '[,]')) {
$this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
}
$v = substr($v, 0, strpos($v, '[')); // clip the []
if (!strpos($v, ':') && isset($this->typemap[$this->XMLSchemaVersion][$v])) {
$v = $this->XMLSchemaVersion . ':' . $v;
}
$this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
}
break;
case 'complexContent': // (optional) content for a complexType
$this->xdebug("do nothing for element $name");
break;
case 'complexType':
array_push($this->complexTypeStack, $this->currentComplexType);
if (isset($attrs['name'])) {
// TODO: what is the scope of named complexTypes that appear
// nested within other c complexTypes?
$this->xdebug('processing named complexType ' . $attrs['name']);
//$this->currentElement = false;
$this->currentComplexType = $attrs['name'];
$this->complexTypes[$this->currentComplexType] = $attrs;
$this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
// This is for constructs like
// <complexType name="ListOfString" base="soap:Array">
// <sequence>
// <element name="string" type="xsd:string"
// minOccurs="0" maxOccurs="unbounded" />
// </sequence>
// </complexType>
if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
$this->xdebug('complexType is unusual array');
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
} else {
$this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
}
} else {
$name = $this->CreateTypeName($this->currentElement);
$this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
$this->currentComplexType = $name;
//$this->currentElement = false;
$this->complexTypes[$this->currentComplexType] = $attrs;
$this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
// This is for constructs like
// <complexType name="ListOfString" base="soap:Array">
// <sequence>
// <element name="string" type="xsd:string"
// minOccurs="0" maxOccurs="unbounded" />
// </sequence>
// </complexType>
if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
$this->xdebug('complexType is unusual array');
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
} else {
$this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
}
}
$this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false';
break;
case 'element':
array_push($this->elementStack, $this->currentElement);
if (!isset($attrs['form'])) {
if ($this->currentComplexType) {
$attrs['form'] = $this->schemaInfo['elementFormDefault'];
} else {
// global
$attrs['form'] = 'qualified';
}
}
if (isset($attrs['type'])) {
$this->xdebug("processing typed element " . $attrs['name'] . " of type " . $attrs['type']);
if (!$this->getPrefix($attrs['type'])) {
if ($this->defaultNamespace[$pos]) {
$attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
$this->xdebug('used default namespace to make type ' . $attrs['type']);
}
}
// This is for constructs like
// <complexType name="ListOfString" base="soap:Array">
// <sequence>
// <element name="string" type="xsd:string"
// minOccurs="0" maxOccurs="unbounded" />
// </sequence>
// </complexType>
if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
$this->xdebug('arrayType for unusual array is ' . $attrs['type']);
$this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
}
$this->currentElement = $attrs['name'];
$ename = $attrs['name'];
} elseif (isset($attrs['ref'])) {
$this->xdebug("processing element as ref to " . $attrs['ref']);
$this->currentElement = "ref to " . $attrs['ref'];
$ename = $this->getLocalPart($attrs['ref']);
} else {
$type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
$this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
$this->currentElement = $attrs['name'];
$attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
$ename = $attrs['name'];
}
if (isset($ename) && $this->currentComplexType) {
$this->xdebug("add element $ename to complexType $this->currentComplexType");
$this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
} elseif (!isset($attrs['ref'])) {
$this->xdebug("add element $ename to elements array");
$this->elements[$attrs['name']] = $attrs;
$this->elements[$attrs['name']]['typeClass'] = 'element';
}
break;
case 'enumeration': // restriction value list member
$this->xdebug('enumeration ' . $attrs['value']);
if ($this->currentSimpleType) {
$this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
} elseif ($this->currentComplexType) {
$this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
}
break;
case 'extension': // simpleContent or complexContent type extension
$this->xdebug('extension ' . $attrs['base']);
if ($this->currentComplexType) {
$ns = $this->getPrefix($attrs['base']);
if ($ns == '') {
$this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
} else {
$this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
}
} else {
$this->xdebug('no current complexType to set extensionBase');
}
break;
case 'import':
if (isset($attrs['schemaLocation'])) {
$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
$this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
} else {
$this->xdebug('import namespace ' . $attrs['namespace']);
$this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
if (!$this->getPrefixFromNamespace($attrs['namespace'])) {
$this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace'];
}
}
break;
case 'include':
if (isset($attrs['schemaLocation'])) {
$this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']);
$this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
} else {
$this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute');
}
break;
case 'list': // simpleType value list
$this->xdebug("do nothing for element $name");
break;
case 'restriction': // simpleType, simpleContent or complexContent value restriction
$this->xdebug('restriction ' . $attrs['base']);
if ($this->currentSimpleType) {
$this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
} elseif ($this->currentComplexType) {
$this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
if (strstr($attrs['base'], ':') == ':Array') {
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
}
}
break;
case 'schema':
$this->schemaInfo = $attrs;
$this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
if (isset($attrs['targetNamespace'])) {
$this->schemaTargetNamespace = $attrs['targetNamespace'];
}
if (!isset($attrs['elementFormDefault'])) {
$this->schemaInfo['elementFormDefault'] = 'unqualified';
}
if (!isset($attrs['attributeFormDefault'])) {
$this->schemaInfo['attributeFormDefault'] = 'unqualified';
}
break;
case 'simpleContent': // (optional) content for a complexType
if ($this->currentComplexType) { // This should *always* be
$this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true';
} else {
$this->xdebug("do nothing for element $name because there is no current complexType");
}
break;
case 'simpleType':
array_push($this->simpleTypeStack, $this->currentSimpleType);
if (isset($attrs['name'])) {
$this->xdebug("processing simpleType for name " . $attrs['name']);
$this->currentSimpleType = $attrs['name'];
$this->simpleTypes[$attrs['name']] = $attrs;
$this->simpleTypes[$attrs['name']]['typeClass'] = 'simpleType';
$this->simpleTypes[$attrs['name']]['phpType'] = 'scalar';
} else {
$name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
$this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
$this->currentSimpleType = $name;
//$this->currentElement = false;
$this->simpleTypes[$this->currentSimpleType] = $attrs;
$this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
}
break;
case 'union': // simpleType type list
$this->xdebug("do nothing for element $name");
break;
default:
$this->xdebug("do not have any logic to process element $name");
}
}
/**
* end-element handler
*
* @param string $parser XML parser object
* @param string $name element name
* @access private
*/
function schemaEndElement($parser, $name)
{
// bring depth down a notch
$this->depth--;
// position of current element is equal to the last value left in depth_array for my depth
if (isset($this->depth_array[$this->depth])) {
$pos = $this->depth_array[$this->depth];
}
// get element prefix
if ($prefix = $this->getPrefix($name)) {
// get unqualified name
$name = $this->getLocalPart($name);
} else {
$prefix = '';
}
// move on...
if ($name == 'complexType') {
$this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
$this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType]));
$this->currentComplexType = array_pop($this->complexTypeStack);
//$this->currentElement = false;
}
if ($name == 'element') {
$this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
$this->currentElement = array_pop($this->elementStack);
}
if ($name == 'simpleType') {
$this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
$this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType]));
$this->currentSimpleType = array_pop($this->simpleTypeStack);
}
}
/**
* element content handler
*
* @param string $parser XML parser object
* @param string $data element content
* @access private
*/
function schemaCharacterData($parser, $data)
{
$pos = $this->depth_array[$this->depth - 1];
$this->message[$pos]['cdata'] .= $data;
}
/**
* serialize the schema
*
* @access public
*/
function serializeSchema()
{
$schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
$xml = '';
// imports
if (sizeof($this->imports) > 0) {
foreach ($this->imports as $ns => $list) {
foreach ($list as $ii) {
if ($ii['location'] != '') {
$xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
} else {
$xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
}
}
}
}
// complex types
foreach ($this->complexTypes as $typeName => $attrs) {
$contentStr = '';
// serialize child elements
if (isset($attrs['elements']) && (count($attrs['elements']) > 0)) {
foreach ($attrs['elements'] as $element => $eParts) {
if (isset($eParts['ref'])) {
$contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
} else {
$contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
foreach ($eParts as $aName => $aValue) {
// handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
if ($aName != 'name' && $aName != 'type') {
$contentStr .= " $aName=\"$aValue\"";
}
}
$contentStr .= "/>\n";
}
}
// compositor wraps elements
if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
$contentStr = " <$schemaPrefix:$attrs[compositor]>\n" . $contentStr . " </$schemaPrefix:$attrs[compositor]>\n";
}
}
// attributes
if (isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)) {
foreach ($attrs['attrs'] as $attr => $aParts) {
$contentStr .= " <$schemaPrefix:attribute";
foreach ($aParts as $a => $v) {
if ($a == 'ref' || $a == 'type') {
$contentStr .= " $a=\"" . $this->contractQName($v) . '"';
} elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
$this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
$contentStr .= ' wsdl:arrayType="' . $this->contractQName($v) . '"';
} else {
$contentStr .= " $a=\"$v\"";
}
}
$contentStr .= "/>\n";
}
}
// if restriction
if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != '') {
$contentStr = " <$schemaPrefix:restriction base=\"" . $this->contractQName($attrs['restrictionBase']) . "\">\n" . $contentStr . " </$schemaPrefix:restriction>\n";
// complex or simple content
if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)) {
$contentStr = " <$schemaPrefix:complexContent>\n" . $contentStr . " </$schemaPrefix:complexContent>\n";
}
}
// finalize complex type
if ($contentStr != '') {
$contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n" . $contentStr . " </$schemaPrefix:complexType>\n";
} else {
$contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
}
$xml .= $contentStr;
}
// simple types
if (isset($this->simpleTypes) && count($this->simpleTypes) > 0) {
foreach ($this->simpleTypes as $typeName => $eParts) {
$xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"" . $this->contractQName($eParts['type']) . "\">\n";
if (isset($eParts['enumeration'])) {
foreach ($eParts['enumeration'] as $e) {
$xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
}
}
$xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
}
}
// elements
if (isset($this->elements) && count($this->elements) > 0) {
foreach ($this->elements as $element => $eParts) {
$xml .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"/>\n";
}
}
// attributes
if (isset($this->attributes) && count($this->attributes) > 0) {
foreach ($this->attributes as $attr => $aParts) {
$xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"" . $this->contractQName($aParts['type']) . "\"\n/>";
}
}
// finish 'er up
$attr = '';
foreach ($this->schemaInfo as $k => $v) {
if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
$attr .= " $k=\"$v\"";
}
}
$el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
$el .= " xmlns:$nsp=\"$ns\"";
}
$xml = $el . ">\n" . $xml . "</$schemaPrefix:schema>\n";
return $xml;
}
/**
* adds debug data to the clas level debug string
*
* @param string $string debug data
* @access private
*/
function xdebug($string)
{
$this->debug('<' . $this->schemaTargetNamespace . '> ' . $string);
}
/**
* get the PHP type of a user defined type in the schema
* PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
* returns false if no type exists, or not w/ the given namespace
* else returns a string that is either a native php type, or 'struct'
*
* @param string $type name of defined type
* @param string $ns namespace of type
* @return mixed
* @access public
* @deprecated
*/
function getPHPType($type, $ns)
{
if (isset($this->typemap[$ns][$type])) {
//print "found type '$type' and ns $ns in typemap<br>";
return $this->typemap[$ns][$type];
} elseif (isset($this->complexTypes[$type])) {
//print "getting type '$type' and ns $ns from complexTypes array<br>";
return $this->complexTypes[$type]['phpType'];
}
return false;
}
/**
* returns an associative array of information about a given type
* returns false if no type exists by the given name
*
* For a complexType typeDef = array(
* 'restrictionBase' => '',
* 'phpType' => '',
* 'compositor' => '(sequence|all)',
* 'elements' => array(), // refs to elements array
* 'attrs' => array() // refs to attributes array
* ... and so on (see addComplexType)
* )
*
* For simpleType or element, the array has different keys.
*
* @param string $type
* @return mixed
* @access public
* @see addComplexType
* @see addSimpleType
* @see addElement
*/
function getTypeDef($type)
{
//$this->debug("in getTypeDef for type $type");
if (substr($type, -1) == '^') {
$is_element = 1;
$type = substr($type, 0, -1);
} else {
$is_element = 0;
}
if ((!$is_element) && isset($this->complexTypes[$type])) {
$this->xdebug("in getTypeDef, found complexType $type");
return $this->complexTypes[$type];
} elseif ((!$is_element) && isset($this->simpleTypes[$type])) {
$this->xdebug("in getTypeDef, found simpleType $type");
if (!isset($this->simpleTypes[$type]['phpType'])) {
// get info for type to tack onto the simple type
// TODO: can this ever really apply (i.e. what is a simpleType really?)
$uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
$ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
$etype = $this->getTypeDef($uqType);
if ($etype) {
$this->xdebug("in getTypeDef, found type for simpleType $type:");
$this->xdebug($this->varDump($etype));
if (isset($etype['phpType'])) {
$this->simpleTypes[$type]['phpType'] = $etype['phpType'];
}
if (isset($etype['elements'])) {
$this->simpleTypes[$type]['elements'] = $etype['elements'];
}
}
}
return $this->simpleTypes[$type];
} elseif (isset($this->elements[$type])) {
$this->xdebug("in getTypeDef, found element $type");
if (!isset($this->elements[$type]['phpType'])) {
// get info for type to tack onto the element
$uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
$ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
$etype = $this->getTypeDef($uqType);
if ($etype) {
$this->xdebug("in getTypeDef, found type for element $type:");
$this->xdebug($this->varDump($etype));
if (isset($etype['phpType'])) {
$this->elements[$type]['phpType'] = $etype['phpType'];
}
if (isset($etype['elements'])) {
$this->elements[$type]['elements'] = $etype['elements'];
}
if (isset($etype['extensionBase'])) {
$this->elements[$type]['extensionBase'] = $etype['extensionBase'];
}
} elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
$this->xdebug("in getTypeDef, element $type is an XSD type");
$this->elements[$type]['phpType'] = 'scalar';
}
}
return $this->elements[$type];
} elseif (isset($this->attributes[$type])) {
$this->xdebug("in getTypeDef, found attribute $type");
return $this->attributes[$type];
} elseif (preg_match('/_ContainedType$/', $type)) {
$this->xdebug("in getTypeDef, have an untyped element $type");
$typeDef['typeClass'] = 'simpleType';
$typeDef['phpType'] = 'scalar';
$typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
return $typeDef;
}
$this->xdebug("in getTypeDef, did not find $type");
return false;
}
/**
* returns a sample serialization of a given type, or false if no type by the given name
*
* @param string $type name of type
* @return mixed
* @access public
* @deprecated
*/
function serializeTypeDef($type)
{
//print "in sTD() for type $type<br>";
if ($typeDef = $this->getTypeDef($type)) {
$str .= '<' . $type;
if (is_array($typeDef['attrs'])) {
foreach ($typeDef['attrs'] as $attName => $data) {
$str .= " $attName=\"{type = " . $data['type'] . "}\"";
}
}
$str .= " xmlns=\"" . $this->schema['targetNamespace'] . "\"";
if (count($typeDef['elements']) > 0) {
$str .= ">";
foreach ($typeDef['elements'] as $element => $eData) {
$str .= $this->serializeTypeDef($element);
}
$str .= "</$type>";
} elseif ($typeDef['typeClass'] == 'element') {
$str .= "></$type>";
} else {
$str .= "/>";
}
return $str;
}
return false;
}
/**
* returns HTML form elements that allow a user
* to enter values for creating an instance of the given type.
*
* @param string $name name for type instance
* @param string $type name of type
* @return string
* @access public
* @deprecated
*/
function typeToForm($name, $type)
{
// get typedef
if ($typeDef = $this->getTypeDef($type)) {
// if struct
if ($typeDef['phpType'] == 'struct') {
$buffer .= '<table>';
foreach ($typeDef['elements'] as $child => $childDef) {
$buffer .= "
<tr><td align='right'>$childDef[name] (type: " . $this->getLocalPart($childDef['type']) . "):</td>
<td><input type='text' name='parameters[" . $name . "][$childDef[name]]'></td></tr>";
}
$buffer .= '</table>';
// if array
} elseif ($typeDef['phpType'] == 'array') {
$buffer .= '<table>';
for ($i = 0; $i < 3; $i++) {
$buffer .= "
<tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
<td><input type='text' name='parameters[" . $name . "][]'></td></tr>";
}
$buffer .= '</table>';
// if scalar
} else {
$buffer .= "<input type='text' name='parameters[$name]'>";
}
} else {
$buffer .= "<input type='text' name='parameters[$name]'>";
}
return $buffer;
}
/**
* adds a complex type to the schema
*
* example: array
*
* addType(
* 'ArrayOfstring',
* 'complexType',
* 'array',
* '',
* 'SOAP-ENC:Array',
* array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
* 'xsd:string'
* );
*
* example: PHP associative array ( SOAP Struct )
*
* addType(
* 'SOAPStruct',
* 'complexType',
* 'struct',
* 'all',
* array('myVar'=> array('name'=>'myVar','type'=>'string')
* );
*
* @param name
* @param typeClass (complexType|simpleType|attribute)
* @param phpType : currently supported are array and struct (php assoc array)
* @param compositor (all|sequence|choice)
* @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
* @param elements = array ( name = array(name=>'',type=>'') )
* @param attrs = array(
* array(
* 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
* "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
* )
* )
* @param arrayType : namespace:name (http://www.w3.org/2001/XMLSchema:string)
* @access public
* @see getTypeDef
*/
function addComplexType($name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '')
{
$this->complexTypes[$name] = array(
'name' => $name,
'typeClass' => $typeClass,
'phpType' => $phpType,
'compositor' => $compositor,
'restrictionBase' => $restrictionBase,
'elements' => $elements,
'attrs' => $attrs,
'arrayType' => $arrayType
);
$this->xdebug("addComplexType $name:");
$this->appendDebug($this->varDump($this->complexTypes[$name]));
}
/**
* adds a simple type to the schema
*
* @param string $name
* @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
* @param string $typeClass (should always be simpleType)
* @param string $phpType (should always be scalar)
* @param array $enumeration array of values
* @access public
* @see nusoap_xmlschema
* @see getTypeDef
*/
function addSimpleType($name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array())
{
$this->simpleTypes[$name] = array(
'name' => $name,
'typeClass' => $typeClass,
'phpType' => $phpType,
'type' => $restrictionBase,
'enumeration' => $enumeration
);
$this->xdebug("addSimpleType $name:");
$this->appendDebug($this->varDump($this->simpleTypes[$name]));
}
/**
* adds an element to the schema
*
* @param array $attrs attributes that must include name and type
* @see nusoap_xmlschema
* @access public
*/
function addElement($attrs)
{
if (!$this->getPrefix($attrs['type'])) {
$attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
}
$this->elements[$attrs['name']] = $attrs;
$this->elements[$attrs['name']]['typeClass'] = 'element';
$this->xdebug("addElement " . $attrs['name']);
$this->appendDebug($this->varDump($this->elements[$attrs['name']]));
}
}
/**
* Backward compatibility
*/
class XMLSchema extends nusoap_xmlschema
{
}
/**
* For creating serializable abstractions of native PHP types. This class
* allows element name/namespace, XSD type, and XML attributes to be
* associated with a value. This is extremely useful when WSDL is not
* used, but is also useful when WSDL is used with polymorphic types, including
* xsd:anyType and user-defined types.
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class soapval extends nusoap_base
{
/**
* The XML element name
*
* @var string
* @access private
*/
var $name;
/**
* The XML type name (string or false)
*
* @var mixed
* @access private
*/
var $type;
/**
* The PHP value
*
* @var mixed
* @access private
*/
var $value;
/**
* The XML element namespace (string or false)
*
* @var mixed
* @access private
*/
var $element_ns;
/**
* The XML type namespace (string or false)
*
* @var mixed
* @access private
*/
var $type_ns;
/**
* The XML element attributes (array or false)
*
* @var mixed
* @access private
*/
var $attributes;
/**
* constructor
*
* @param string $name optional name
* @param mixed $type optional type name
* @param mixed $value optional value
* @param mixed $element_ns optional namespace of value
* @param mixed $type_ns optional namespace of type
* @param mixed $attributes associative array of attributes to add to element serialization
* @access public
*/
function __construct($name = 'soapval', $type = false, $value = -1, $element_ns = false, $type_ns = false, $attributes = false)
{
parent::__construct();
$this->name = $name;
$this->type = $type;
$this->value = $value;
$this->element_ns = $element_ns;
$this->type_ns = $type_ns;
$this->attributes = $attributes;
}
/**
* return serialized value
*
* @param string $use The WSDL use value (encoded|literal)
* @return string XML data
* @access public
*/
function serialize($use = 'encoded')
{
return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
}
/**
* decodes a soapval object into a PHP native type
*
* @return mixed
* @access public
*/
function decode()
{
return $this->value;
}
}
/**
* transport class for sending/receiving data via HTTP and HTTPS
* NOTE: PHP must be compiled with the CURL extension for HTTPS support
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @author Scott Nichol <snichol@users.sourceforge.net>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class soap_transport_http extends nusoap_base
{
var $url = '';
var $uri = '';
var $digest_uri = '';
var $scheme = '';
var $host = '';
var $port = '';
var $path = '';
var $request_method = 'POST';
var $protocol_version = '1.0';
var $encoding = '';
var $outgoing_headers = array();
var $incoming_headers = array();
var $incoming_cookies = array();
var $outgoing_payload = '';
var $incoming_payload = '';
var $response_status_line; // HTTP response status line
var $useSOAPAction = true;
var $persistentConnection = false;
var $ch = false; // cURL handle
var $ch_options = array(); // cURL custom options
var $use_curl = false; // force cURL use
var $proxy = null; // proxy information (associative array)
var $username = '';
var $password = '';
var $authtype = '';
var $digestRequest = array();
var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
// cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
// sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
// sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
// passphrase: SSL key password/passphrase
// certpassword: SSL certificate password
// verifypeer: default is 1
// verifyhost: default is 1
/**
* constructor
*
* @param string $url The URL to which to connect
* @param array $curl_options User-specified cURL options
* @param boolean $use_curl Whether to try to force cURL use
* @access public
*/
function __construct($url, $curl_options = null, $use_curl = false)
{
parent::__construct();
$this->debug("ctor url=$url use_curl=$use_curl curl_options:");
$this->appendDebug($this->varDump($curl_options));
$this->setURL($url);
if (is_array($curl_options)) {
$this->ch_options = $curl_options;
}
$this->use_curl = $use_curl;
preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
$this->setHeader('User-Agent', $this->title . '/' . $this->version . ' (' . $rev[1] . ')');
}
/**
* sets a cURL option
*
* @param mixed $option The cURL option (always integer?)
* @param mixed $value The cURL option value
* @access private
*/
function setCurlOption($option, $value)
{
$this->debug("setCurlOption option=$option, value=");
$this->appendDebug($this->varDump($value));
curl_setopt($this->ch, $option, $value);
}
/**
* sets an HTTP header
*
* @param string $name The name of the header
* @param string $value The value of the header
* @access private
*/
function setHeader($name, $value)
{
$this->outgoing_headers[$name] = $value;
$this->debug("set header $name: $value");
}
/**
* unsets an HTTP header
*
* @param string $name The name of the header
* @access private
*/
function unsetHeader($name)
{
if (isset($this->outgoing_headers[$name])) {
$this->debug("unset header $name");
unset($this->outgoing_headers[$name]);
}
}
/**
* sets the URL to which to connect
*
* @param string $url The URL to which to connect
* @access private
*/
function setURL($url)
{
$this->url = $url;
$u = parse_url($url);
foreach ($u as $k => $v) {
$this->debug("parsed URL $k = $v");
$this->$k = $v;
}
// add any GET params to path
if (isset($u['query']) && $u['query'] != '') {
$this->path .= '?' . $u['query'];
}
// set default port
if (!isset($u['port'])) {
if ($u['scheme'] == 'https') {
$this->port = 443;
} else {
$this->port = 80;
}
}
$this->uri = $this->path;
$this->digest_uri = $this->uri;
// build headers
if (!isset($u['port'])) {
$this->setHeader('Host', $this->host);
} else {
$this->setHeader('Host', $this->host . ':' . $this->port);
}
if (isset($u['user']) && $u['user'] != '') {
$this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
}
}
/**
* gets the I/O method to use
*
* @return string I/O method to use (socket|curl|unknown)
* @access private
*/
function io_method()
{
if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) {
return 'curl';
}
if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) {
return 'socket';
}
return 'unknown';
}
/**
* establish an HTTP connection
*
* @param integer $timeout set connection timeout in seconds
* @param integer $response_timeout set response timeout in seconds
* @return boolean true if connected, false if not
* @access private
*/
function connect($connection_timeout = 0, $response_timeout = 30)
{
// For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
// "regular" socket.
// TODO: disabled for now because OpenSSL must be *compiled* in (not just
// loaded), and until PHP5 stream_get_wrappers is not available.
// if ($this->scheme == 'https') {
// if (version_compare(phpversion(), '4.3.0') >= 0) {
// if (extension_loaded('openssl')) {
// $this->scheme = 'ssl';
// $this->debug('Using SSL over OpenSSL');
// }
// }
// }
$this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
if ($this->io_method() == 'socket') {
if (!is_array($this->proxy)) {
$host = $this->host;
$port = $this->port;
} else {
$host = $this->proxy['host'];
$port = $this->proxy['port'];
}
// use persistent connection
if ($this->persistentConnection && isset($this->fp) && is_resource($this->fp)) {
if (!feof($this->fp)) {
$this->debug('Re-use persistent connection');
return true;
}
fclose($this->fp);
$this->debug('Closed persistent connection at EOF');
}
// munge host if using OpenSSL
if ($this->scheme == 'ssl') {
$host = 'ssl://' . $host;
}
$this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
// open socket
if ($connection_timeout > 0) {
$this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str, $connection_timeout);
} else {
$this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str);
}
// test pointer
if (!$this->fp) {
$msg = 'Couldn\'t open socket connection to server ' . $this->url;
if ($this->errno) {
$msg .= ', Error (' . $this->errno . '): ' . $this->error_str;
} else {
$msg .= ' prior to connect(). This is often a problem looking up the host name.';
}
$this->debug($msg);
$this->setError($msg);
return false;
}
// set response timeout
$this->debug('set response timeout to ' . $response_timeout);
socket_set_timeout($this->fp, $response_timeout);
$this->debug('socket connected');
return true;
} elseif ($this->io_method() == 'curl') {
if (!extension_loaded('curl')) {
// $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
$this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.');
return false;
}
// Avoid warnings when PHP does not have these options
if (defined('CURLOPT_CONNECTIONTIMEOUT')) {
$CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
} else {
$CURLOPT_CONNECTIONTIMEOUT = 78;
}
if (defined('CURLOPT_HTTPAUTH')) {
$CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
} else {
$CURLOPT_HTTPAUTH = 107;
}
if (defined('CURLOPT_PROXYAUTH')) {
$CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
} else {
$CURLOPT_PROXYAUTH = 111;
}
if (defined('CURLAUTH_BASIC')) {
$CURLAUTH_BASIC = CURLAUTH_BASIC;
} else {
$CURLAUTH_BASIC = 1;
}
if (defined('CURLAUTH_DIGEST')) {
$CURLAUTH_DIGEST = CURLAUTH_DIGEST;
} else {
$CURLAUTH_DIGEST = 2;
}
if (defined('CURLAUTH_NTLM')) {
$CURLAUTH_NTLM = CURLAUTH_NTLM;
} else {
$CURLAUTH_NTLM = 8;
}
$this->debug('connect using cURL');
// init CURL
$this->ch = curl_init();
// set url
$hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
// add path
$hostURL .= $this->path;
$this->setCurlOption(CURLOPT_URL, $hostURL);
// follow location headers (re-directs)
if (ini_get('safe_mode') || ini_get('open_basedir')) {
$this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
$this->debug('safe_mode = ');
$this->appendDebug($this->varDump(ini_get('safe_mode')));
$this->debug('open_basedir = ');
$this->appendDebug($this->varDump(ini_get('open_basedir')));
} else {
$this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
}
// ask for headers in the response output
$this->setCurlOption(CURLOPT_HEADER, 1);
// ask for the response output as the return value
$this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
// encode
// We manage this ourselves through headers and encoding
// if(function_exists('gzuncompress')){
// $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
// }
// persistent connection
if ($this->persistentConnection) {
// I believe the following comment is now bogus, having applied to
// the code when it used CURLOPT_CUSTOMREQUEST to send the request.
// The way we send data, we cannot use persistent connections, since
// there will be some "junk" at the end of our request.
//$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
$this->persistentConnection = false;
$this->setHeader('Connection', 'close');
}
// set timeouts
if ($connection_timeout != 0) {
$this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
}
if ($response_timeout != 0) {
$this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
}
if ($this->scheme == 'https') {
$this->debug('set cURL SSL verify options');
// recent versions of cURL turn on peer/host checking by default,
// while PHP binaries are not compiled with a default location for the
// CA cert bundle, so disable peer/host checking.
//$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
$this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
$this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
// support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
if ($this->authtype == 'certificate') {
$this->debug('set cURL certificate options');
if (isset($this->certRequest['cainfofile'])) {
$this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
}
if (isset($this->certRequest['verifypeer'])) {
$this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
} else {
$this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
}
if (isset($this->certRequest['verifyhost'])) {
$this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
} else {
$this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
}
if (isset($this->certRequest['sslcertfile'])) {
$this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
}
if (isset($this->certRequest['sslkeyfile'])) {
$this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
}
if (isset($this->certRequest['passphrase'])) {
$this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
}
if (isset($this->certRequest['certpassword'])) {
$this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
}
}
}