diff --git a/main/exercise/hotspot_answers.as.php b/main/exercise/hotspot_answers.as.php index c9efc95b72..91b6b92162 100755 --- a/main/exercise/hotspot_answers.as.php +++ b/main/exercise/hotspot_answers.as.php @@ -102,14 +102,16 @@ if (in_array( ) { $showOnlyScore = true; $showResults = true; + $lpId = isset($trackExerciseInfo['orig_lp_id']) ? $trackExerciseInfo['orig_lp_id'] : 0; + $lpItemId = isset($trackExerciseInfo['orig_lp_item_id']) ? $trackExerciseInfo['orig_lp_item_id'] : 0; if ($objExercise->attempts > 0) { $attempts = Event::getExerciseResultsByUser( api_get_user_id(), $objExercise->id, $courseId, api_get_session_id(), - $trackExerciseInfo['orig_lp_id'], - $trackExerciseInfo['orig_lp_item_id'], + $lpId, + $lpItemId, 'desc' ); $numberAttempts = count($attempts); diff --git a/main/inc/ajax/extra_field.ajax.php b/main/inc/ajax/extra_field.ajax.php index eaba87543c..e215c25fa1 100755 --- a/main/inc/ajax/extra_field.ajax.php +++ b/main/inc/ajax/extra_field.ajax.php @@ -65,6 +65,117 @@ switch ($action) { echo json_encode(['items' => $result]); break; + case 'search_options_from_tags': + $type = isset($_REQUEST['type']) ? $_REQUEST['type'] : null; + $fieldId = isset($_REQUEST['field_id']) ? $_REQUEST['field_id'] : null; + $tag = isset($_REQUEST['tag']) ? $_REQUEST['tag'] : null; + $extraFieldOption = new ExtraFieldOption($type); + + $from = isset($_REQUEST['from']) ? $_REQUEST['from'] : ''; + $search = isset($_REQUEST['search']) ? $_REQUEST['search'] : ''; + $options = isset($_REQUEST['options']) ? json_decode($_REQUEST['options']) : ''; + + $extraField = new ExtraField('session'); + $result = $extraField->searchOptionsFromTags($from, $search, $options); + $options = []; + $groups = []; + + foreach ($result as $data) { + // Try to get the translation + $displayText = $data['display_text']; + $valueToTranslate = str_replace('-', '', $data['value']); + $valueTranslated = str_replace(['[=', '=]'], '', get_lang($valueToTranslate)); + if ($valueToTranslate != $valueTranslated) { + $displayText = $valueTranslated; + } + $groups[$displayText][] = [ + 'id' => $data['id'], + 'text' => $data['tag'], + ]; + } + + foreach ($groups as $key => $data) { + $options[] = [ + 'text' => $key, + 'children' => $groups[$key], + ]; + } + echo json_encode($options); + break; + case 'order': + $variable = isset($_REQUEST['field_variable']) ? $_REQUEST['field_variable'] : ''; + $save = isset($_REQUEST['save']) ? $_REQUEST['save'] : ''; + $values = isset($_REQUEST['values']) ? json_decode($_REQUEST['values']) : ''; + $extraField = new ExtraField('session'); + $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable(str_replace('extra_', '', $variable)); + + $em = Database::getManager(); + + $search = [ + 'user' => api_get_user_id(), + 'field' => $extraFieldInfo['id'], + ]; + + $extraFieldSavedSearch = $em->getRepository('ChamiloCoreBundle:ExtraFieldSavedSearch')->findOneBy($search); + + if ($save) { + $extraField = new \Chamilo\CoreBundle\Entity\ExtraFieldSavedSearch('session'); + if ($extraFieldSavedSearch) { + $extraFieldSavedSearch->setValue($values); + $em->merge($extraFieldSavedSearch); + $em->flush(); + } + } + + if ($extraFieldInfo) { + /** @var \Chamilo\CoreBundle\Entity\ExtraFieldSavedSearch $options */ + $extraFieldSavedSearch = $em->getRepository('ChamiloCoreBundle:ExtraFieldSavedSearch')->findOneBy($search); + $values = $extraFieldSavedSearch->getValue(); + $url = api_get_self().'?a=order&save=1&field_variable='.$variable; + + $html = ' + '; + + $html .= ''; + $html .= Display::url(get_lang('Save'), '#', ['id' => 'link_'.$variable, 'class' => 'btn btn-primary']); + echo $html; + } + break; default: exit; break; diff --git a/main/inc/ajax/model.ajax.php b/main/inc/ajax/model.ajax.php index a282b62c86..87d4c537cf 100755 --- a/main/inc/ajax/model.ajax.php +++ b/main/inc/ajax/model.ajax.php @@ -73,6 +73,8 @@ if (!in_array( api_protect_teacher_script(true); } +$toRemove = ['extra_access_start_date', 'extra_access_end_date']; + // Search features //@todo move this in the display_class or somewhere else @@ -130,6 +132,8 @@ $searchString = isset($_REQUEST['searchString']) ? $_REQUEST['searchString'] : f $search = isset($_REQUEST['_search']) ? $_REQUEST['_search'] : false; $forceSearch = isset($_REQUEST['_force_search']) ? $_REQUEST['_force_search'] : false; $extra_fields = []; +$accessStartDate = ''; +$accessEndDate = ''; $overwriteColumnHeaderExport = []; if (!empty($searchString)) { @@ -150,6 +154,10 @@ if (($search || $forceSearch) && ($search !== 'false')) { } $filters = isset($_REQUEST['filters']) && !is_array($_REQUEST['filters']) ? json_decode($_REQUEST['filters']) : false; + if (isset($_REQUEST['filters2'])) { + $filters = json_decode($_REQUEST['filters2']); + } + if (!empty($filters)) { if (in_array($action, ['get_questions', 'get_sessions'])) { switch ($action) { @@ -164,7 +172,25 @@ if (($search || $forceSearch) && ($search !== 'false')) { if (!empty($type)) { // Extra field. $extraField = new ExtraField($type); + + foreach ($filters->rules as $key => $data) { + if (empty($data)) { + continue; + } + if ($data->field == 'extra_access_start_date') { + $accessStartDate = $data->data; + } + + if ($data->field == 'extra_access_end_date') { + $accessEndDate = $data->data; + } + + if (in_array($data->field, $toRemove)) { + unset($filters->rules[$key]); + } + } $result = $extraField->getExtraFieldRules($filters, 'extra_'); + $extra_fields = $result['extra_fields']; $condition_array = $result['condition_array']; @@ -184,6 +210,7 @@ if (($search || $forceSearch) && ($search !== 'false')) { $questionFields = $resultQuestion['extra_fields']; $condition_array = $resultQuestion['condition_array']; + $extraQuestionCondition = ''; if (!empty($condition_array)) { $extraQuestionCondition = $filters->groupOp.' ( '; $extraQuestionCondition .= implode($filters->groupOp, $condition_array); @@ -197,6 +224,10 @@ if (($search || $forceSearch) && ($search !== 'false')) { } $whereCondition .= $extraQuestionCondition; + + if (isset($filters->custom_dates)) { + $whereCondition .= $filters->custom_dates; + } } } elseif (!empty($filters->rules)) { $whereCondition .= ' AND ( '; diff --git a/main/inc/ajax/social.ajax.php b/main/inc/ajax/social.ajax.php index a602f35999..f77d2ac1e4 100755 --- a/main/inc/ajax/social.ajax.php +++ b/main/inc/ajax/social.ajax.php @@ -273,7 +273,7 @@ switch ($action) { $start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0; $length = isset($_REQUEST['length']) ? (int) $_REQUEST['length'] : 10; $userId = isset($_REQUEST['u']) ? (int) $_REQUEST['u'] : api_get_user_id(); - $html = ''; + $html = ''; if ($userId == api_get_user_id()) { $threadList = SocialManager::getThreadList(); $threadIdList = []; diff --git a/main/inc/lib/CoursesAndSessionsCatalog.class.php b/main/inc/lib/CoursesAndSessionsCatalog.class.php index 4641bc54f3..7c97b7deb1 100644 --- a/main/inc/lib/CoursesAndSessionsCatalog.class.php +++ b/main/inc/lib/CoursesAndSessionsCatalog.class.php @@ -332,7 +332,6 @@ class CoursesAndSessionsCatalog $visibilityCondition ORDER BY RAND() LIMIT 0, $random_value"; - echo $sql; } else { $sql = "SELECT id, id as real_id FROM $tbl_course course WHERE diff --git a/main/inc/lib/nusoap/class.soap_server.php b/main/inc/lib/nusoap/class.soap_server.php index e53ae10cae..4b7efddea4 100755 --- a/main/inc/lib/nusoap/class.soap_server.php +++ b/main/inc/lib/nusoap/class.soap_server.php @@ -1,1128 +1,1129 @@ - -* @author Scott Nichol -* @version $Id: class.soap_server.php,v 1.63 2010/04/26 20:15:08 snichol Exp $ -* @access public -*/ -class nusoap_server extends nusoap_base -{ - /** - * HTTP headers of request - * @var array - * @access private - */ - var $headers = array(); - /** - * HTTP request - * @var string - * @access private - */ - var $request = ''; - /** - * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) - * @var string - * @access public - */ - var $requestHeaders = ''; - /** - * SOAP Headers from request (parsed) - * @var mixed - * @access public - */ - var $requestHeader = NULL; - /** - * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) - * @var string - * @access public - */ - var $document = ''; - /** - * SOAP payload for request (text) - * @var string - * @access public - */ - var $requestSOAP = ''; - /** - * requested method namespace URI - * @var string - * @access private - */ - var $methodURI = ''; - /** - * name of method requested - * @var string - * @access private - */ - var $methodname = ''; - /** - * method parameters from request - * @var array - * @access private - */ - var $methodparams = array(); - /** - * SOAP Action from request - * @var string - * @access private - */ - var $SOAPAction = ''; - /** - * character set encoding of incoming (request) messages - * @var string - * @access public - */ - var $xml_encoding = ''; - /** - * toggles whether the parser decodes element content w/ utf8_decode() - * @var boolean - * @access public - */ - var $decode_utf8 = true; - - /** - * HTTP headers of response - * @var array - * @access public - */ - var $outgoing_headers = array(); - /** - * HTTP response - * @var string - * @access private - */ - var $response = ''; - /** - * SOAP headers for response (text or array of soapval or associative array) - * @var mixed - * @access public - */ - var $responseHeaders = ''; - /** - * SOAP payload for response (text) - * @var string - * @access private - */ - var $responseSOAP = ''; - /** - * method return value to place in response - * @var mixed - * @access private - */ - var $methodreturn = false; - /** - * whether $methodreturn is a string of literal XML - * @var boolean - * @access public - */ - var $methodreturnisliteralxml = false; - /** - * SOAP fault for response (or false) - * @var mixed - * @access private - */ - var $fault = false; - /** - * text indication of result (for debugging) - * @var string - * @access private - */ - var $result = 'successful'; - - /** - * assoc array of operations => opData; operations are added by the register() - * method or by parsing an external WSDL definition - * @var array - * @access private - */ - var $operations = array(); - /** - * wsdl instance (if one) - * @var mixed - * @access private - */ - var $wsdl = false; - /** - * URL for WSDL (if one) - * @var mixed - * @access private - */ - var $externalWSDLURL = false; - /** - * whether to append debug to response as XML comment - * @var boolean - * @access public - */ - var $debug_flag = false; - - - /** - * constructor - * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. - * - * @param mixed $wsdl file path or URL (string), or wsdl instance (object) - * @access public - */ - function __construct($wsdl=false) - { - parent::__construct(); - // turn on debugging? - global $debug; - global $HTTP_SERVER_VARS; - - if (isset($_SERVER)) { - $this->debug("_SERVER is defined:"); - $this->appendDebug($this->varDump($_SERVER)); - } elseif (isset($HTTP_SERVER_VARS)) { - $this->debug("HTTP_SERVER_VARS is defined:"); - $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); - } else { - $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); - } - - if (isset($debug)) { - $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); - $this->debug_flag = $debug; - } elseif (isset($_SERVER['QUERY_STRING'])) { - $qs = explode('&', $_SERVER['QUERY_STRING']); - foreach ($qs as $v) { - if (substr($v, 0, 6) == 'debug=') { - $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); - $this->debug_flag = substr($v, 6); - } - } - } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { - $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); - foreach ($qs as $v) { - if (substr($v, 0, 6) == 'debug=') { - $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); - $this->debug_flag = substr($v, 6); - } - } - } - - // wsdl - if($wsdl){ - $this->debug("In nusoap_server, WSDL is specified"); - if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { - $this->wsdl = $wsdl; - $this->wsdl->soap_defencoding = $this->soap_defencoding; - $this->externalWSDLURL = $this->wsdl->wsdl; - $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); - } else { - $this->debug('Create wsdl from ' . $wsdl); - $this->wsdl = new wsdl($wsdl); - $this->wsdl->soap_defencoding = $this->soap_defencoding; - $this->externalWSDLURL = $wsdl; - } - $this->appendDebug($this->wsdl->getDebug()); - $this->wsdl->clearDebug(); - if($err = $this->wsdl->getError()){ - die('WSDL ERROR: '.$err); - } - } - } - - /** - * processes request and returns response - * - * @param string $data usually is the value of $HTTP_RAW_POST_DATA - * @access public - */ - function service($data){ - global $HTTP_SERVER_VARS; - - if (isset($_SERVER['REQUEST_METHOD'])) { - $rm = $_SERVER['REQUEST_METHOD']; - } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) { - $rm = $HTTP_SERVER_VARS['REQUEST_METHOD']; - } else { - $rm = ''; - } - - if (isset($_SERVER['QUERY_STRING'])) { - $qs = $_SERVER['QUERY_STRING']; - } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { - $qs = $HTTP_SERVER_VARS['QUERY_STRING']; - } else { - $qs = ''; - } - $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data)); - - if ($rm == 'POST') { - $this->debug("In service, invoke the request"); - $this->parse_request($data); - if (! $this->fault) { - $this->invoke_method(); - } - if (! $this->fault) { - $this->serialize_return(); - } - $this->send_response(); - } elseif (preg_match('/wsdl/', $qs) ){ - $this->debug("In service, this is a request for WSDL"); - if ($this->externalWSDLURL){ - if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL - $this->debug("In service, re-direct for WSDL"); - header('Location: '.$this->externalWSDLURL); - } else { // assume file - $this->debug("In service, use file passthru for WSDL"); - header("Content-Type: text/xml\r\n"); - $pos = strpos($this->externalWSDLURL, "file://"); - if ($pos === false) { - $filename = $this->externalWSDLURL; - } else { - $filename = substr($this->externalWSDLURL, $pos + 7); - } - $fp = fopen($this->externalWSDLURL, 'r'); - fpassthru($fp); - } - } elseif ($this->wsdl) { - $this->debug("In service, serialize WSDL"); - header("Content-Type: text/xml; charset=".$this->soap_defencoding."\r\n"); - print $this->wsdl->serialize($this->debug_flag); - if ($this->debug_flag) { - $this->debug('wsdl:'); - $this->appendDebug($this->varDump($this->wsdl)); - print $this->getDebugAsXMLComment(); - } - } else { - $this->debug("In service, there is no WSDL"); - header("Content-Type: text/html; charset=".$this->soap_defencoding."\r\n"); - print "This service does not provide WSDL"; - } - } elseif ($this->wsdl) { - $this->debug("In service, return Web description"); - print $this->wsdl->webDescription(); - } else { - $this->debug("In service, no Web description"); - header("Content-Type: text/html; charset=ISO-8859-1\r\n"); - print "This service does not provide a Web description"; - } - } - - /** - * parses HTTP request headers. - * - * The following fields are set by this function (when successful) - * - * headers - * request - * xml_encoding - * SOAPAction - * - * @access private - */ - function parse_http_headers() { - global $HTTP_SERVER_VARS; - - $this->request = ''; - $this->SOAPAction = ''; - if(function_exists('getallheaders')){ - $this->debug("In parse_http_headers, use getallheaders"); - $headers = getallheaders(); - foreach($headers as $k=>$v){ - $k = strtolower($k); - $this->headers[$k] = $v; - $this->request .= "$k: $v\r\n"; - $this->debug("$k: $v"); - } - // get SOAPAction header - if(isset($this->headers['soapaction'])){ - $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); - } - // get the character encoding of the incoming request - if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ - $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); - if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ - $this->xml_encoding = strtoupper($enc); - } else { - $this->xml_encoding = 'US-ASCII'; - } - } else { - // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 - $this->xml_encoding = 'ISO-8859-1'; - } - } elseif(isset($_SERVER) && is_array($_SERVER)){ - $this->debug("In parse_http_headers, use _SERVER"); - foreach ($_SERVER as $k => $v) { - if (substr($k, 0, 5) == 'HTTP_') { - $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); - } else { - $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); - } - if ($k == 'soapaction') { - // get SOAPAction header - $k = 'SOAPAction'; - $v = str_replace('"', '', $v); - $v = str_replace('\\', '', $v); - $this->SOAPAction = $v; - } else if ($k == 'content-type') { - // get the character encoding of the incoming request - if (strpos($v, '=')) { - $enc = substr(strstr($v, '='), 1); - $enc = str_replace('"', '', $enc); - $enc = str_replace('\\', '', $enc); - if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { - $this->xml_encoding = strtoupper($enc); - } else { - $this->xml_encoding = 'US-ASCII'; - } - } else { - // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 - $this->xml_encoding = 'ISO-8859-1'; - } - } - $this->headers[$k] = $v; - $this->request .= "$k: $v\r\n"; - $this->debug("$k: $v"); - } - } elseif (is_array($HTTP_SERVER_VARS)) { - $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); - foreach ($HTTP_SERVER_VARS as $k => $v) { - if (substr($k, 0, 5) == 'HTTP_') { - $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); - } else { - $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); - } - if ($k == 'soapaction') { - // get SOAPAction header - $k = 'SOAPAction'; - $v = str_replace('"', '', $v); - $v = str_replace('\\', '', $v); - $this->SOAPAction = $v; - } else if ($k == 'content-type') { - // get the character encoding of the incoming request - if (strpos($v, '=')) { - $enc = substr(strstr($v, '='), 1); - $enc = str_replace('"', '', $enc); - $enc = str_replace('\\', '', $enc); - if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { - $this->xml_encoding = strtoupper($enc); - } else { - $this->xml_encoding = 'US-ASCII'; - } - } else { - // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 - $this->xml_encoding = 'ISO-8859-1'; - } - } - $this->headers[$k] = $v; - $this->request .= "$k: $v\r\n"; - $this->debug("$k: $v"); - } - } else { - $this->debug("In parse_http_headers, HTTP headers not accessible"); - $this->setError("HTTP headers not accessible"); - } - } - - /** - * parses a request - * - * The following fields are set by this function (when successful) - * - * headers - * request - * xml_encoding - * SOAPAction - * request - * requestSOAP - * methodURI - * methodname - * methodparams - * requestHeaders - * document - * - * This sets the fault field on error - * - * @param string $data XML string - * @access private - */ - function parse_request($data='') { - $this->debug('entering parse_request()'); - $this->parse_http_headers(); - $this->debug('got character encoding: '.$this->xml_encoding); - // uncompress if necessary - if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { - $this->debug('got content encoding: ' . $this->headers['content-encoding']); - if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { - // if decoding works, use it. else assume data wasn't gzencoded - if (function_exists('gzuncompress')) { - if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { - $data = $degzdata; - } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { - $data = $degzdata; - } else { - $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); - return; - } - } else { - $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); - return; - } - } - } - $this->request .= "\r\n".$data; - $data = $this->parseRequest($this->headers, $data); - $this->requestSOAP = $data; - $this->debug('leaving parse_request'); - } - - /** - * invokes a PHP function for the requested SOAP method - * - * The following fields are set by this function (when successful) - * - * methodreturn - * - * Note that the PHP function that is called may also set the following - * fields to affect the response sent to the client - * - * responseHeaders - * outgoing_headers - * - * This sets the fault field on error - * - * @access private - */ - function invoke_method() { - $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); - - // - // if you are debugging in this area of the code, your service uses a class to implement methods, - // you use SOAP RPC, and the client is .NET, please be aware of the following... - // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the - // method name. that is fine for naming the .NET methods. it is not fine for properly constructing - // the XML request and reading the XML response. you need to add the RequestElementName and - // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe - // generates for the method. these parameters are used to specify the correct XML element names - // for .NET to use, i.e. the names with the '.' in them. - // - $orig_methodname = $this->methodname; - if ($this->wsdl) { - if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { - $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); - $this->appendDebug('opData=' . $this->varDump($this->opData)); - } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { - // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element - $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); - $this->appendDebug('opData=' . $this->varDump($this->opData)); - $this->methodname = $this->opData['name']; - } else { - $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); - $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); - return; - } - } else { - $this->debug('in invoke_method, no WSDL to validate method'); - } - - // if a . is present in $this->methodname, we see if there is a class in scope, - // which could be referred to. We will also distinguish between two deliminators, - // to allow methods to be called a the class or an instance - if (strpos($this->methodname, '..') > 0) { - $delim = '..'; - } else if (strpos($this->methodname, '.') > 0) { - $delim = '.'; - } else { - $delim = ''; - } - $this->debug("in invoke_method, delim=$delim"); - - $class = ''; - $method = ''; - if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) { - $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim)); - if (class_exists($try_class)) { - // get the class and method name - $class = $try_class; - $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); - $this->debug("in invoke_method, class=$class method=$method delim=$delim"); - } else { - $this->debug("in invoke_method, class=$try_class not found"); - } - } else { - $try_class = ''; - $this->debug("in invoke_method, no class to try"); - } - - // does method exist? - if ($class == '') { - if (!function_exists($this->methodname)) { - $this->debug("in invoke_method, function '$this->methodname' not found!"); - $this->result = 'fault: method not found'; - $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')"); - return; - } - } else { - $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; - if (!in_array($method_to_compare, get_class_methods($class))) { - $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); - $this->result = 'fault: method not found'; - $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')"); - return; - } - } - - // evaluate message, getting back parameters - // verify that request parameters match the method's signature - if(! $this->verify_method($this->methodname,$this->methodparams)){ - // debug - $this->debug('ERROR: request not verified against method signature'); - $this->result = 'fault: request failed validation against method signature'; - // return fault - $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); - return; - } - - // if there are parameters to pass - $this->debug('in invoke_method, params:'); - $this->appendDebug($this->varDump($this->methodparams)); - $this->debug("in invoke_method, calling '$this->methodname'"); - if (!function_exists('call_user_func_array')) { - if ($class == '') { - $this->debug('in invoke_method, calling function using eval()'); - $funcCall = "\$this->methodreturn = $this->methodname("; - } else { - if ($delim == '..') { - $this->debug('in invoke_method, calling class method using eval()'); - $funcCall = "\$this->methodreturn = ".$class."::".$method."("; - } else { - $this->debug('in invoke_method, calling instance method using eval()'); - // generate unique instance name - $instname = "\$inst_".time(); - $funcCall = $instname." = new ".$class."(); "; - $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; - } - } - if ($this->methodparams) { - foreach ($this->methodparams as $param) { - if (is_array($param) || is_object($param)) { - $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); - return; - } - $funcCall .= "\"$param\","; - } - $funcCall = substr($funcCall, 0, -1); - } - $funcCall .= ');'; - $this->debug('in invoke_method, function call: '.$funcCall); - @eval($funcCall); - } else { - if ($class == '') { - $this->debug('in invoke_method, calling function using call_user_func_array()'); - $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() - } elseif ($delim == '..') { - $this->debug('in invoke_method, calling class method using call_user_func_array()'); - $call_arg = array ($class, $method); - } else { - $this->debug('in invoke_method, calling instance method using call_user_func_array()'); - $instance = new $class (); - $call_arg = array(&$instance, $method); - } - if (is_array($this->methodparams)) { - $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); - } else { - $this->methodreturn = call_user_func_array($call_arg, array()); - } - } - $this->debug('in invoke_method, methodreturn:'); - $this->appendDebug($this->varDump($this->methodreturn)); - $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); - } - - /** - * serializes the return value from a PHP function into a full SOAP Envelope - * - * The following fields are set by this function (when successful) - * - * responseSOAP - * - * This sets the fault field on error - * - * @access private - */ - function serialize_return() { - $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); - // if fault - if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { - $this->debug('got a fault object from method'); - $this->fault = $this->methodreturn; - return; - } elseif ($this->methodreturnisliteralxml) { - $return_val = $this->methodreturn; - // returned value(s) - } else { - $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); - $this->debug('serializing return value'); - if($this->wsdl){ - $opParams = ""; - if (sizeof($this->opData['output']['parts']) > 1) { - $this->debug('more than one output part, so use the method return unchanged'); - $opParams = $this->methodreturn; - } elseif (sizeof($this->opData['output']['parts']) == 1) { - $this->debug('exactly one output part, so wrap the method return in a simple array'); - // TODO: verify that it is not already wrapped! - //foreach ($this->opData['output']['parts'] as $name => $type) { - // $this->debug('wrap in element named ' . $name); - //} - $opParams = array($this->methodreturn); - } - $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); - $this->appendDebug($this->wsdl->getDebug()); - $this->wsdl->clearDebug(); - if($errstr = $this->wsdl->getError()){ - $this->debug('got wsdl error: '.$errstr); - $this->fault('SOAP-ENV:Server', 'unable to serialize result'); - return; - } - } else { - if (isset($this->methodreturn)) { - $return_val = $this->serialize_val($this->methodreturn, 'return'); - } else { - $return_val = ''; - $this->debug('in absence of WSDL, assume void return for backward compatibility'); - } - } - } - $this->debug('return value:'); - $this->appendDebug($this->varDump($return_val)); - - $this->debug('serializing response'); - if ($this->wsdl) { - $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); - if ($this->opData['style'] == 'rpc') { - $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); - if ($this->opData['output']['use'] == 'literal') { - // 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 - if ($this->methodURI) { - $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; - } else { - $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; - } - } else { - if ($this->methodURI) { - $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; - } else { - $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; - } - } - } else { - $this->debug('style is not rpc for serialization: assume document'); - $payload = $return_val; - } - } else { - $this->debug('do not have WSDL for serialization: assume rpc/encoded'); - $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; - } - $this->result = 'successful'; - if($this->wsdl){ - //if($this->debug_flag){ - $this->appendDebug($this->wsdl->getDebug()); - // } - if (isset($this->opData['output']['encodingStyle'])) { - $encodingStyle = $this->opData['output']['encodingStyle']; - } else { - $encodingStyle = ''; - } - // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. - $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); - } else { - $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); - } - $this->debug("Leaving serialize_return"); - } - - /** - * sends an HTTP response - * - * The following fields are set by this function (when successful) - * - * outgoing_headers - * response - * - * @access private - */ - function send_response() { - $this->debug('Enter send_response'); - if ($this->fault) { - $payload = $this->fault->serialize(); - $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; - $this->outgoing_headers[] = "Status: 500 Internal Server Error"; - } else { - $payload = $this->responseSOAP; - // Some combinations of PHP+Web server allow the Status - // to come through as a header. Since OK is the default - // just do nothing. - // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; - // $this->outgoing_headers[] = "Status: 200 OK"; - } - // add debug data if in debug mode - if(isset($this->debug_flag) && $this->debug_flag){ - $payload .= $this->getDebugAsXMLComment(); - } - $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; - preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); - $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; - // Let the Web server decide about this - //$this->outgoing_headers[] = "Connection: Close\r\n"; - $payload = $this->getHTTPBody($payload); - $type = $this->getHTTPContentType(); - $charset = $this->getHTTPContentTypeCharset(); - $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); - //begin code to compress payload - by John - // NOTE: there is no way to know whether the Web server will also compress - // this data. - if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { - if (strstr($this->headers['accept-encoding'], 'gzip')) { - if (function_exists('gzencode')) { - if (isset($this->debug_flag) && $this->debug_flag) { - $payload .= ""; - } - $this->outgoing_headers[] = "Content-Encoding: gzip"; - $payload = gzencode($payload); - } else { - if (isset($this->debug_flag) && $this->debug_flag) { - $payload .= ""; - } - } - } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { - // Note: MSIE requires gzdeflate output (no Zlib header and checksum), - // instead of gzcompress output, - // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) - if (function_exists('gzdeflate')) { - if (isset($this->debug_flag) && $this->debug_flag) { - $payload .= ""; - } - $this->outgoing_headers[] = "Content-Encoding: deflate"; - $payload = gzdeflate($payload); - } else { - if (isset($this->debug_flag) && $this->debug_flag) { - $payload .= ""; - } - } - } - } - //end code - $this->outgoing_headers[] = "Content-Length: ".strlen($payload); - reset($this->outgoing_headers); - foreach($this->outgoing_headers as $hdr){ - header($hdr, false); - } - print $payload; - $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; - } - - /** - * takes the value that was created by parsing the request - * and compares to the method's signature, if available. - * - * @param string $operation The operation to be invoked - * @param array $request The array of parameter values - * @return boolean Whether the operation was found - * @access private - */ - function verify_method($operation,$request){ - if(isset($this->wsdl) && is_object($this->wsdl)){ - if($this->wsdl->getOperationData($operation)){ - return true; - } - } elseif(isset($this->operations[$operation])){ - return true; - } - return false; - } - - /** - * processes SOAP message received from client - * - * @param array $headers The HTTP headers - * @param string $data unprocessed request data from client - * @return mixed value of the message, decoded into a PHP type - * @access private - */ - function parseRequest($headers, $data) { - $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:'); - $this->appendDebug($this->varDump($headers)); - if (!isset($headers['content-type'])) { - $this->setError('Request not of type text/xml (no content-type header)'); - return false; - } - if (!strstr($headers['content-type'], 'text/xml')) { - $this->setError('Request not of type text/xml'); - return false; - } - if (strpos($headers['content-type'], '=')) { - $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); - $this->debug('Got response encoding: ' . $enc); - if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ - $this->xml_encoding = strtoupper($enc); - } else { - $this->xml_encoding = 'US-ASCII'; - } - } else { - // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 - $this->xml_encoding = 'ISO-8859-1'; - } - $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); - // parse response, get soap parser obj - $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); - - // parser debug - $this->debug("parser debug: \n".$parser->getDebug()); - // if fault occurred during message parsing - if($err = $parser->getError()){ - $this->result = 'fault: error in msg parsing: '.$err; - $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); - // else successfully parsed request into soapval object - } else { - // get/set methodname - $this->methodURI = $parser->root_struct_namespace; - $this->methodname = $parser->root_struct_name; - $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); - $this->debug('calling parser->get_soapbody()'); - $this->methodparams = $parser->get_soapbody(); - // get SOAP headers - $this->requestHeaders = $parser->getHeaders(); - // get SOAP Header - $this->requestHeader = $parser->get_soapheader(); - // add document for doclit support - $this->document = $parser->document; - } - } - - /** - * gets the HTTP body for the current response. - * - * @param string $soapmsg The SOAP payload - * @return string The HTTP body, which includes the SOAP payload - * @access private - */ - function getHTTPBody($soapmsg) { - return $soapmsg; - } - - /** - * gets the HTTP content type for the current response. - * - * Note: getHTTPBody must be called before this. - * - * @return string the HTTP content type for the current response. - * @access private - */ - function getHTTPContentType() { - return 'text/xml'; - } - - /** - * gets the HTTP content type charset for the current response. - * returns false for non-text content types. - * - * Note: getHTTPBody must be called before this. - * - * @return string the HTTP content type charset for the current response. - * @access private - */ - function getHTTPContentTypeCharset() { - return $this->soap_defencoding; - } - - /** - * add a method to the dispatch map (this has been replaced by the register method) - * - * @param string $methodname - * @param string $in array of input values - * @param string $out array of output values - * @access public - * @deprecated - */ - function add_to_map($methodname,$in,$out){ - $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); - } - - /** - * register a service function with the server - * - * @param string $name the name of the PHP function, class.method or class..method - * @param array $in assoc array of input values: key = param name, value = param type - * @param array $out assoc array of output values: key = param name, value = param type - * @param mixed $namespace the element namespace for the method or false - * @param mixed $soapaction the soapaction for the method or false - * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically - * @param mixed $use optional (encoded|literal) or false - * @param string $documentation optional Description to include in WSDL - * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) - * @access public - */ - function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ - global $HTTP_SERVER_VARS; - - if($this->externalWSDLURL){ - die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); - } - if (! $name) { - die('You must specify a name when you register an operation'); - } - if (!is_array($in)) { - die('You must provide an array for operation inputs'); - } - if (!is_array($out)) { - die('You must provide an array for operation outputs'); - } - if(false == $namespace) { - } - if(false == $soapaction) { - if (isset($_SERVER)) { - $SERVER_NAME = $_SERVER['SERVER_NAME']; - $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; - $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); - } elseif (isset($HTTP_SERVER_VARS)) { - $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; - $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; - $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; - } else { - $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); - } - if ($HTTPS == '1' || $HTTPS == 'on') { - $SCHEME = 'https'; - } else { - $SCHEME = 'http'; - } - $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; - } - if(false == $style) { - $style = "rpc"; - } - if(false == $use) { - $use = "encoded"; - } - if ($use == 'encoded' && $encodingStyle == '') { - $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; - } - - $this->operations[$name] = array( - 'name' => $name, - 'in' => $in, - 'out' => $out, - 'namespace' => $namespace, - 'soapaction' => $soapaction, - 'style' => $style); - if($this->wsdl){ - $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); - } - return true; - } - - /** - * Specify a fault to be returned to the client. - * This also acts as a flag to the server that a fault has occured. - * - * @param string $faultcode - * @param string $faultstring - * @param string $faultactor - * @param string $faultdetail - * @access public - */ - function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ - if ($faultdetail == '' && $this->debug_flag) { - $faultdetail = $this->getDebug(); - } - $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); - $this->fault->soap_defencoding = $this->soap_defencoding; - } - - /** - * Sets up wsdl object. - * Acts as a flag to enable internal WSDL generation - * - * @param string $serviceName, name of the service - * @param mixed $namespace optional 'tns' service namespace or false - * @param mixed $endpoint optional URL of service endpoint or false - * @param string $style optional (rpc|document) WSDL style (also specified by operation) - * @param string $transport optional SOAP transport - * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false - */ - function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) - { - global $HTTP_SERVER_VARS; - - if (isset($_SERVER)) { - $SERVER_NAME = $_SERVER['SERVER_NAME']; - $SERVER_PORT = $_SERVER['SERVER_PORT']; - $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; - $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); - } elseif (isset($HTTP_SERVER_VARS)) { - $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; - $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; - $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; - $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; - } else { - $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); - } - // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) - $colon = strpos($SERVER_NAME,":"); - if ($colon) { - $SERVER_NAME = substr($SERVER_NAME, 0, $colon); - } - if ($SERVER_PORT == 80) { - $SERVER_PORT = ''; - } else { - $SERVER_PORT = ':' . $SERVER_PORT; - } - if(false == $namespace) { - $namespace = "http://$SERVER_NAME/soap/$serviceName"; - } - - if(false == $endpoint) { - if ($HTTPS == '1' || $HTTPS == 'on') { - $SCHEME = 'https'; - } else { - $SCHEME = 'http'; - } - $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; - } - - if(false == $schemaTargetNamespace) { - $schemaTargetNamespace = $namespace; - } - - $this->wsdl = new wsdl(); - $this->wsdl->soap_defencoding = $this->soap_defencoding; - $this->wsdl->serviceName = $serviceName; - $this->wsdl->endpoint = $endpoint; - $this->wsdl->namespaces['tns'] = $namespace; - $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; - $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; - if ($schemaTargetNamespace != $namespace) { - $this->wsdl->namespaces['types'] = $schemaTargetNamespace; - } - $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); - if ($style == 'document') { - $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; - } - $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; - $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); - $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); - $this->wsdl->bindings[$serviceName.'Binding'] = array( - 'name'=>$serviceName.'Binding', - 'style'=>$style, - 'transport'=>$transport, - 'portType'=>$serviceName.'PortType'); - $this->wsdl->ports[$serviceName.'Port'] = array( - 'binding'=>$serviceName.'Binding', - 'location'=>$endpoint, - 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); - } -} - -/** - * Backward compatibility - */ -class soap_server extends nusoap_server { -} + +* @author Scott Nichol +* @version $Id: class.soap_server.php,v 1.63 2010/04/26 20:15:08 snichol Exp $ +* @access public +*/ +class nusoap_server extends nusoap_base +{ + /** + * HTTP headers of request + * @var array + * @access private + */ + var $headers = array(); + /** + * HTTP request + * @var string + * @access private + */ + var $request = ''; + /** + * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $requestHeaders = ''; + /** + * SOAP Headers from request (parsed) + * @var mixed + * @access public + */ + var $requestHeader = NULL; + /** + * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $document = ''; + /** + * SOAP payload for request (text) + * @var string + * @access public + */ + var $requestSOAP = ''; + /** + * requested method namespace URI + * @var string + * @access private + */ + var $methodURI = ''; + /** + * name of method requested + * @var string + * @access private + */ + var $methodname = ''; + /** + * method parameters from request + * @var array + * @access private + */ + var $methodparams = array(); + /** + * SOAP Action from request + * @var string + * @access private + */ + var $SOAPAction = ''; + /** + * character set encoding of incoming (request) messages + * @var string + * @access public + */ + var $xml_encoding = ''; + /** + * toggles whether the parser decodes element content w/ utf8_decode() + * @var boolean + * @access public + */ + var $decode_utf8 = true; + + /** + * HTTP headers of response + * @var array + * @access public + */ + var $outgoing_headers = array(); + /** + * HTTP response + * @var string + * @access private + */ + var $response = ''; + /** + * SOAP headers for response (text or array of soapval or associative array) + * @var mixed + * @access public + */ + var $responseHeaders = ''; + /** + * SOAP payload for response (text) + * @var string + * @access private + */ + var $responseSOAP = ''; + /** + * method return value to place in response + * @var mixed + * @access private + */ + var $methodreturn = false; + /** + * whether $methodreturn is a string of literal XML + * @var boolean + * @access public + */ + var $methodreturnisliteralxml = false; + /** + * SOAP fault for response (or false) + * @var mixed + * @access private + */ + var $fault = false; + /** + * text indication of result (for debugging) + * @var string + * @access private + */ + var $result = 'successful'; + + /** + * assoc array of operations => opData; operations are added by the register() + * method or by parsing an external WSDL definition + * @var array + * @access private + */ + var $operations = array(); + /** + * wsdl instance (if one) + * @var mixed + * @access private + */ + var $wsdl = false; + /** + * URL for WSDL (if one) + * @var mixed + * @access private + */ + var $externalWSDLURL = false; + /** + * whether to append debug to response as XML comment + * @var boolean + * @access public + */ + var $debug_flag = false; + + + /** + * constructor + * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. + * + * @param mixed $wsdl file path or URL (string), or wsdl instance (object) + * @access public + */ + function __construct($wsdl=false) + { + parent::__construct(); + // turn on debugging? + global $debug; + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $this->debug("_SERVER is defined:"); + $this->appendDebug($this->varDump($_SERVER)); + } elseif (isset($HTTP_SERVER_VARS)) { + $this->debug("HTTP_SERVER_VARS is defined:"); + $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); + } else { + $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); + } + + if (isset($debug)) { + $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); + $this->debug_flag = $debug; + } elseif (isset($_SERVER['QUERY_STRING'])) { + $qs = explode('&', $_SERVER['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); + $this->debug_flag = substr($v, 6); + } + } + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); + $this->debug_flag = substr($v, 6); + } + } + } + + // wsdl + if ($wsdl){ + $this->debug("In nusoap_server, WSDL is specified"); + if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { + $this->wsdl = $wsdl; + $this->wsdl->soap_defencoding = $this->soap_defencoding; + $this->externalWSDLURL = $this->wsdl->wsdl; + $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); + } else { + $this->debug('Create wsdl from ' . $wsdl); + $this->wsdl = new wsdl($wsdl); + $this->wsdl->soap_defencoding = $this->soap_defencoding; + $this->externalWSDLURL = $wsdl; + } + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if($err = $this->wsdl->getError()){ + die('WSDL ERROR: '.$err); + } + } + } + + /** + * processes request and returns response + * + * @param string $data usually is the value of $HTTP_RAW_POST_DATA + * @access public + */ + function service($data){ + global $HTTP_SERVER_VARS; + + if (isset($_SERVER['REQUEST_METHOD'])) { + $rm = $_SERVER['REQUEST_METHOD']; + } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) { + $rm = $HTTP_SERVER_VARS['REQUEST_METHOD']; + } else { + $rm = ''; + } + + if (isset($_SERVER['QUERY_STRING'])) { + $qs = $_SERVER['QUERY_STRING']; + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = $HTTP_SERVER_VARS['QUERY_STRING']; + } else { + $qs = ''; + } + $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data)); + + if ($rm == 'POST') { + $this->debug("In service, invoke the request"); + $this->parse_request($data); + if (! $this->fault) { + $this->invoke_method(); + } + if (! $this->fault) { + $this->serialize_return(); + } + $this->send_response(); + } elseif (preg_match('/wsdl/', $qs) ){ + $this->debug("In service, this is a request for WSDL"); + if ($this->externalWSDLURL){ + if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL + $this->debug("In service, re-direct for WSDL"); + header('Location: '.$this->externalWSDLURL); + } else { // assume file + $this->debug("In service, use file passthru for WSDL"); + header("Content-Type: text/xml\r\n"); + $pos = strpos($this->externalWSDLURL, "file://"); + if ($pos === false) { + $filename = $this->externalWSDLURL; + } else { + $filename = substr($this->externalWSDLURL, $pos + 7); + } + $fp = fopen($this->externalWSDLURL, 'r'); + fpassthru($fp); + } + } elseif ($this->wsdl) { + $this->debug("In service, serialize WSDL"); + header("Content-Type: text/xml; charset=".$this->soap_defencoding."\r\n"); + print $this->wsdl->serialize($this->debug_flag); + if ($this->debug_flag) { + $this->debug('wsdl:'); + $this->appendDebug($this->varDump($this->wsdl)); + print $this->getDebugAsXMLComment(); + } + } else { + $this->debug("In service, there is no WSDL"); + header("Content-Type: text/html; charset=".$this->soap_defencoding."\r\n"); + print "This service does not provide WSDL"; + } + } elseif ($this->wsdl) { + $this->debug("In service, return Web description"); + print $this->wsdl->webDescription(); + } else { + $this->debug("In service, no Web description"); + header("Content-Type: text/html; charset=ISO-8859-1\r\n"); + print "This service does not provide a Web description"; + } + } + + /** + * parses HTTP request headers. + * + * The following fields are set by this function (when successful) + * + * headers + * request + * xml_encoding + * SOAPAction + * + * @access private + */ + function parse_http_headers() { + global $HTTP_SERVER_VARS; + + $this->request = ''; + $this->SOAPAction = ''; + if(function_exists('getallheaders')){ + $this->debug("In parse_http_headers, use getallheaders"); + $headers = getallheaders(); + foreach($headers as $k=>$v){ + $k = strtolower($k); + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + // get SOAPAction header + if(isset($this->headers['soapaction'])){ + $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); + } + // get the character encoding of the incoming request + if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ + $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); + if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } elseif(isset($_SERVER) && is_array($_SERVER)){ + $this->debug("In parse_http_headers, use _SERVER"); + foreach ($_SERVER as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); + } + if ($k == 'soapaction') { + // get SOAPAction header + $k = 'SOAPAction'; + $v = str_replace('"', '', $v); + $v = str_replace('\\', '', $v); + $this->SOAPAction = $v; + } else if ($k == 'content-type') { + // get the character encoding of the incoming request + if (strpos($v, '=')) { + $enc = substr(strstr($v, '='), 1); + $enc = str_replace('"', '', $enc); + $enc = str_replace('\\', '', $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } elseif (is_array($HTTP_SERVER_VARS)) { + $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); + foreach ($HTTP_SERVER_VARS as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); + } + if ($k == 'soapaction') { + // get SOAPAction header + $k = 'SOAPAction'; + $v = str_replace('"', '', $v); + $v = str_replace('\\', '', $v); + $this->SOAPAction = $v; + } else if ($k == 'content-type') { + // get the character encoding of the incoming request + if (strpos($v, '=')) { + $enc = substr(strstr($v, '='), 1); + $enc = str_replace('"', '', $enc); + $enc = str_replace('\\', '', $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } else { + $this->debug("In parse_http_headers, HTTP headers not accessible"); + $this->setError("HTTP headers not accessible"); + } + } + + /** + * parses a request + * + * The following fields are set by this function (when successful) + * + * headers + * request + * xml_encoding + * SOAPAction + * request + * requestSOAP + * methodURI + * methodname + * methodparams + * requestHeaders + * document + * + * This sets the fault field on error + * + * @param string $data XML string + * @access private + */ + function parse_request($data='') { + $this->debug('entering parse_request()'); + $this->parse_http_headers(); + $this->debug('got character encoding: '.$this->xml_encoding); + // uncompress if necessary + if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { + $this->debug('got content encoding: ' . $this->headers['content-encoding']); + if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { + // if decoding works, use it. else assume data wasn't gzencoded + if (function_exists('gzuncompress')) { + if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { + $data = $degzdata; + } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { + $data = $degzdata; + } else { + $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); + return; + } + } else { + $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); + return; + } + } + } + $this->request .= "\r\n".$data; + $data = $this->parseRequest($this->headers, $data); + $this->requestSOAP = $data; + $this->debug('leaving parse_request'); + } + + /** + * invokes a PHP function for the requested SOAP method + * + * The following fields are set by this function (when successful) + * + * methodreturn + * + * Note that the PHP function that is called may also set the following + * fields to affect the response sent to the client + * + * responseHeaders + * outgoing_headers + * + * This sets the fault field on error + * + * @access private + */ + function invoke_method() { + $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); + + // + // if you are debugging in this area of the code, your service uses a class to implement methods, + // you use SOAP RPC, and the client is .NET, please be aware of the following... + // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the + // method name. that is fine for naming the .NET methods. it is not fine for properly constructing + // the XML request and reading the XML response. you need to add the RequestElementName and + // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe + // generates for the method. these parameters are used to specify the correct XML element names + // for .NET to use, i.e. the names with the '.' in them. + // + $orig_methodname = $this->methodname; + if ($this->wsdl) { + if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { + $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { + // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element + $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + $this->methodname = $this->opData['name']; + } else { + $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); + $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); + return; + } + } else { + $this->debug('in invoke_method, no WSDL to validate method'); + } + + // if a . is present in $this->methodname, we see if there is a class in scope, + // which could be referred to. We will also distinguish between two deliminators, + // to allow methods to be called a the class or an instance + if (strpos($this->methodname, '..') > 0) { + $delim = '..'; + } else if (strpos($this->methodname, '.') > 0) { + $delim = '.'; + } else { + $delim = ''; + } + $this->debug("in invoke_method, delim=$delim"); + + $class = ''; + $method = ''; + if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) { + $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim)); + if (class_exists($try_class)) { + // get the class and method name + $class = $try_class; + $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); + $this->debug("in invoke_method, class=$class method=$method delim=$delim"); + } else { + $this->debug("in invoke_method, class=$try_class not found"); + } + } else { + $try_class = ''; + $this->debug("in invoke_method, no class to try"); + } + + // does method exist? + if ($class == '') { + if (!function_exists($this->methodname)) { + $this->debug("in invoke_method, function '$this->methodname' not found!"); + $this->result = 'fault: method not found'; + $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')"); + return; + } + } else { + $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; + if (!in_array($method_to_compare, get_class_methods($class))) { + $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); + $this->result = 'fault: method not found'; + $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')"); + return; + } + } + + // evaluate message, getting back parameters + // verify that request parameters match the method's signature + if(! $this->verify_method($this->methodname,$this->methodparams)){ + // debug + $this->debug('ERROR: request not verified against method signature'); + $this->result = 'fault: request failed validation against method signature'; + // return fault + $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); + return; + } + + // if there are parameters to pass + $this->debug('in invoke_method, params:'); + $this->appendDebug($this->varDump($this->methodparams)); + $this->debug("in invoke_method, calling '$this->methodname'"); + if (!function_exists('call_user_func_array')) { + if ($class == '') { + $this->debug('in invoke_method, calling function using eval()'); + $funcCall = "\$this->methodreturn = $this->methodname("; + } else { + if ($delim == '..') { + $this->debug('in invoke_method, calling class method using eval()'); + $funcCall = "\$this->methodreturn = ".$class."::".$method."("; + } else { + $this->debug('in invoke_method, calling instance method using eval()'); + // generate unique instance name + $instname = "\$inst_".time(); + $funcCall = $instname." = new ".$class."(); "; + $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; + } + } + if ($this->methodparams) { + foreach ($this->methodparams as $param) { + if (is_array($param) || is_object($param)) { + $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); + return; + } + $funcCall .= "\"$param\","; + } + $funcCall = substr($funcCall, 0, -1); + } + $funcCall .= ');'; + $this->debug('in invoke_method, function call: '.$funcCall); + @eval($funcCall); + } else { + if ($class == '') { + $this->debug('in invoke_method, calling function using call_user_func_array()'); + $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() + } elseif ($delim == '..') { + $this->debug('in invoke_method, calling class method using call_user_func_array()'); + $call_arg = array ($class, $method); + } else { + $this->debug('in invoke_method, calling instance method using call_user_func_array()'); + $instance = new $class (); + $call_arg = array(&$instance, $method); + } + if (is_array($this->methodparams)) { + $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); + } else { + $this->methodreturn = call_user_func_array($call_arg, array()); + } + } + $this->debug('in invoke_method, methodreturn:'); + $this->appendDebug($this->varDump($this->methodreturn)); + $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); + } + + /** + * serializes the return value from a PHP function into a full SOAP Envelope + * + * The following fields are set by this function (when successful) + * + * responseSOAP + * + * This sets the fault field on error + * + * @access private + */ + function serialize_return() { + $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); + // if fault + if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { + $this->debug('got a fault object from method'); + $this->fault = $this->methodreturn; + return; + } elseif ($this->methodreturnisliteralxml) { + $return_val = $this->methodreturn; + // returned value(s) + } else { + $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); + $this->debug('serializing return value'); + if($this->wsdl){ + $opParams = ""; + if (sizeof($this->opData['output']['parts']) > 1) { + $this->debug('more than one output part, so use the method return unchanged'); + $opParams = $this->methodreturn; + } elseif (sizeof($this->opData['output']['parts']) == 1) { + $this->debug('exactly one output part, so wrap the method return in a simple array'); + // TODO: verify that it is not already wrapped! + //foreach ($this->opData['output']['parts'] as $name => $type) { + // $this->debug('wrap in element named ' . $name); + //} + $opParams = array($this->methodreturn); + } + $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if($errstr = $this->wsdl->getError()){ + $this->debug('got wsdl error: '.$errstr); + $this->fault('SOAP-ENV:Server', 'unable to serialize result'); + return; + } + } else { + if (isset($this->methodreturn)) { + $return_val = $this->serialize_val($this->methodreturn, 'return'); + } else { + $return_val = ''; + $this->debug('in absence of WSDL, assume void return for backward compatibility'); + } + } + } + $this->debug('return value:'); + $this->appendDebug($this->varDump($return_val)); + + $this->debug('serializing response'); + if ($this->wsdl) { + $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); + if ($this->opData['style'] == 'rpc') { + $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); + if ($this->opData['output']['use'] == 'literal') { + // 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 + if ($this->methodURI) { + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } else { + $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; + } + } else { + if ($this->methodURI) { + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } else { + $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; + } + } + } else { + $this->debug('style is not rpc for serialization: assume document'); + $payload = $return_val; + } + } else { + $this->debug('do not have WSDL for serialization: assume rpc/encoded'); + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } + $this->result = 'successful'; + if($this->wsdl){ + //if($this->debug_flag){ + $this->appendDebug($this->wsdl->getDebug()); + // } + if (isset($this->opData['output']['encodingStyle'])) { + $encodingStyle = $this->opData['output']['encodingStyle']; + } else { + $encodingStyle = ''; + } + // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. + $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); + } else { + $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); + } + $this->debug("Leaving serialize_return"); + } + + /** + * sends an HTTP response + * + * The following fields are set by this function (when successful) + * + * outgoing_headers + * response + * + * @access private + */ + function send_response() { + $this->debug('Enter send_response'); + if ($this->fault) { + $payload = $this->fault->serialize(); + $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; + $this->outgoing_headers[] = "Status: 500 Internal Server Error"; + } else { + $payload = $this->responseSOAP; + // Some combinations of PHP+Web server allow the Status + // to come through as a header. Since OK is the default + // just do nothing. + // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; + // $this->outgoing_headers[] = "Status: 200 OK"; + } + // add debug data if in debug mode + if(isset($this->debug_flag) && $this->debug_flag){ + $payload .= $this->getDebugAsXMLComment(); + } + $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; + preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); + $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; + // Let the Web server decide about this + //$this->outgoing_headers[] = "Connection: Close\r\n"; + $payload = $this->getHTTPBody($payload); + $type = $this->getHTTPContentType(); + $charset = $this->getHTTPContentTypeCharset(); + $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); + //begin code to compress payload - by John + // NOTE: there is no way to know whether the Web server will also compress + // this data. + if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { + if (strstr($this->headers['accept-encoding'], 'gzip')) { + if (function_exists('gzencode')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + $this->outgoing_headers[] = "Content-Encoding: gzip"; + $payload = gzencode($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + } + } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { + // Note: MSIE requires gzdeflate output (no Zlib header and checksum), + // instead of gzcompress output, + // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) + if (function_exists('gzdeflate')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + $this->outgoing_headers[] = "Content-Encoding: deflate"; + $payload = gzdeflate($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + } + } + } + //end code + $this->outgoing_headers[] = "Content-Length: ".strlen($payload); + reset($this->outgoing_headers); + foreach($this->outgoing_headers as $hdr){ + header($hdr, false); + } + print $payload; + $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; + } + + /** + * takes the value that was created by parsing the request + * and compares to the method's signature, if available. + * + * @param string $operation The operation to be invoked + * @param array $request The array of parameter values + * @return boolean Whether the operation was found + * @access private + */ + function verify_method($operation,$request){ + if(isset($this->wsdl) && is_object($this->wsdl)){ + if($this->wsdl->getOperationData($operation)){ + return true; + } + } elseif(isset($this->operations[$operation])){ + return true; + } + return false; + } + + /** + * processes SOAP message received from client + * + * @param array $headers The HTTP headers + * @param string $data unprocessed request data from client + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseRequest($headers, $data) { + $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:'); + $this->appendDebug($this->varDump($headers)); + if (!isset($headers['content-type'])) { + $this->setError('Request not of type text/xml (no content-type header)'); + return false; + } + if (!strstr($headers['content-type'], 'text/xml')) { + $this->setError('Request not of type text/xml'); + return false; + } + if (strpos($headers['content-type'], '=')) { + $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); + $this->debug('Got response encoding: ' . $enc); + if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); + // parse response, get soap parser obj + $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); + + // parser debug + $this->debug("parser debug: \n".$parser->getDebug()); + // if fault occurred during message parsing + if($err = $parser->getError()){ + $this->result = 'fault: error in msg parsing: '.$err; + $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); + // else successfully parsed request into soapval object + } else { + // get/set methodname + $this->methodURI = $parser->root_struct_namespace; + $this->methodname = $parser->root_struct_name; + $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); + $this->debug('calling parser->get_soapbody()'); + $this->methodparams = $parser->get_soapbody(); + // get SOAP headers + $this->requestHeaders = $parser->getHeaders(); + // get SOAP Header + $this->requestHeader = $parser->get_soapheader(); + // add document for doclit support + $this->document = $parser->document; + } + } + + /** + * gets the HTTP body for the current response. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + return $soapmsg; + } + + /** + * gets the HTTP content type for the current response. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current response. + * @access private + */ + function getHTTPContentType() { + return 'text/xml'; + } + + /** + * gets the HTTP content type charset for the current response. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current response. + * @access private + */ + function getHTTPContentTypeCharset() { + return $this->soap_defencoding; + } + + /** + * add a method to the dispatch map (this has been replaced by the register method) + * + * @param string $methodname + * @param string $in array of input values + * @param string $out array of output values + * @access public + * @deprecated + */ + function add_to_map($methodname,$in,$out){ + $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); + } + + /** + * register a service function with the server + * + * @param string $name the name of the PHP function, class.method or class..method + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $out assoc array of output values: key = param name, value = param type + * @param mixed $namespace the element namespace for the method or false + * @param mixed $soapaction the soapaction for the method or false + * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @param mixed $use optional (encoded|literal) or false + * @param string $documentation optional Description to include in WSDL + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ + global $HTTP_SERVER_VARS; + + if($this->externalWSDLURL){ + die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); + } + if (! $name) { + die('You must specify a name when you register an operation'); + } + if (!is_array($in)) { + die('You must provide an array for operation inputs'); + } + if (!is_array($out)) { + die('You must provide an array for operation outputs'); + } + if(false == $namespace) { + } + if(false == $soapaction) { + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + if ($HTTPS == '1' || $HTTPS == 'on') { + $SCHEME = 'https'; + } else { + $SCHEME = 'http'; + } + $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; + } + if(false == $style) { + $style = "rpc"; + } + if(false == $use) { + $use = "encoded"; + } + if ($use == 'encoded' && $encodingStyle == '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + $this->operations[$name] = array( + 'name' => $name, + 'in' => $in, + 'out' => $out, + 'namespace' => $namespace, + 'soapaction' => $soapaction, + 'style' => $style); + if($this->wsdl){ + $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); + } + return true; + } + + /** + * Specify a fault to be returned to the client. + * This also acts as a flag to the server that a fault has occured. + * + * @param string $faultcode + * @param string $faultstring + * @param string $faultactor + * @param string $faultdetail + * @access public + */ + function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ + if ($faultdetail == '' && $this->debug_flag) { + $faultdetail = $this->getDebug(); + } + $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); + $this->fault->soap_defencoding = $this->soap_defencoding; + } + + /** + * Sets up wsdl object. + * Acts as a flag to enable internal WSDL generation + * + * @param string $serviceName, name of the service + * @param mixed $namespace optional 'tns' service namespace or false + * @param mixed $endpoint optional URL of service endpoint or false + * @param string $style optional (rpc|document) WSDL style (also specified by operation) + * @param string $transport optional SOAP transport + * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false + */ + function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) + { + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SERVER_PORT = $_SERVER['SERVER_PORT']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) + $colon = strpos($SERVER_NAME,":"); + if ($colon) { + $SERVER_NAME = substr($SERVER_NAME, 0, $colon); + } + if ($SERVER_PORT == 80) { + $SERVER_PORT = ''; + } else { + $SERVER_PORT = ':' . $SERVER_PORT; + } + if(false == $namespace) { + $namespace = "http://$SERVER_NAME/soap/$serviceName"; + } + + if(false == $endpoint) { + if ($HTTPS == '1' || $HTTPS == 'on') { + $SCHEME = 'https'; + } else { + $SCHEME = 'http'; + } + $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; + } + + if(false == $schemaTargetNamespace) { + $schemaTargetNamespace = $namespace; + } + + $this->wsdl = new wsdl(); + $this->wsdl->soap_defencoding = $this->soap_defencoding; + $this->wsdl->serviceName = $serviceName; + $this->wsdl->endpoint = $endpoint; + $this->wsdl->namespaces['tns'] = $namespace; + $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; + $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; + if ($schemaTargetNamespace != $namespace) { + $this->wsdl->namespaces['types'] = $schemaTargetNamespace; + } + $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); + if ($style == 'document') { + $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; + } + $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; + $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); + $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); + $this->wsdl->bindings[$serviceName.'Binding'] = array( + 'name'=>$serviceName.'Binding', + 'style'=>$style, + 'transport'=>$transport, + 'portType'=>$serviceName.'PortType'); + $this->wsdl->ports[$serviceName.'Port'] = array( + 'binding'=>$serviceName.'Binding', + 'location'=>$endpoint, + 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); + } +} + +/** + * Backward compatibility + */ +class soap_server extends nusoap_server +{ +} diff --git a/main/inc/lib/pear/HTML/QuickForm/file.php b/main/inc/lib/pear/HTML/QuickForm/file.php index 42b0272c59..c7e3c3a0f7 100755 --- a/main/inc/lib/pear/HTML/QuickForm/file.php +++ b/main/inc/lib/pear/HTML/QuickForm/file.php @@ -372,9 +372,9 @@ class HTML_QuickForm_file extends HTML_QuickForm_input $class = 'input-file'; } - return $js.$this->_getTabs(). + return $js.$this->_getTabs(). '_getAttrString($this->_attributes).' />'; - } + } } /**