* *@version 0.3 * *@package Quinta * @subpackage Classes */ abstract class WebServiceRequest{ //////////// HTTP members: /** *@var string Username, login or account id for the service */ protected $strRemoteAccountId; /** *@var string password for the service */ protected $strRemotePassword; /** *@var string the FQD for the payment service provider API server */ protected $strRemoteDomainName; /** * Note: This must contain the separater character that follows the script name, eg. '?' or '&' * if the request is of type GET *@var string the URL portion after the domain name leading to API script */ protected $strRemoteCgiUrl; /** * This is appended to the CGI URL: www.foo.com/$CgiUrl . ApiName .. etc. *@var string the name of the API call to use */ protected $strApiName; /** *@var string storage for response from service */ protected $strResponse; /** *@var string storage for the request to service */ protected $strRequest; /** *@var string The type of request to be made (GET | POST | SOAP ) */ protected $intRequestType; /** *@var integer Port number to use for the connection (80, 443) */ protected $intPort; /** *@var integer Connection time out in seconds */ protected $intTimeOut = 90; //////////// SOAP members: /** * This is an array handed to the SOAP client - the values should match those * found in the WSDL *@var array storage for the SOAP request to service */ protected $arySoapRequest; /** * This is an array handed to the SOAP client - the values should match those * found in the WSDL *@var mixed storage for the SOAP response */ protected $mixSoapResponse; /** *@var string name of the SOAP function to call */ protected $strSoapFunction; /** *@var string location of the WSDL to use */ protected $strWsdlUri; //////////// Common members: /** *@var string Errors */ protected $strErrors; /** *@var boolean True if there were errors or if the transaction/connection failed for any reason */ protected $blnHasErrors; /** *@var boolean True if we should use SSL to connect to the provider */ protected $blnUseSsl = true; /** * NOTE: You must explicitly set this to disable testing mode .. *@var boolean True for testing (and by default) */ protected $blnTestMode = true; /** * Parses the response from the web services provider */ abstract protected function handleResponse(); /** * Creates GET query string for the transaction appropriate to the provider API, storing * the result in strRequest. */ abstract protected function createGETRequest(); /** * Creates POST query string for the transaction appropriate to the provider API, storing * the result in strRequest. */ abstract protected function createPOSTRequest(); /** * Connects to web SOAP service and submits the request. * This function merely passes the arySoapRequest to the SOAP client * and stores the result in mixSoapResponse. * Note: strWsdlUri, strSoapFunction, and arySoapRequest_must_ _all_ * be set before calling this. *@return boolean true on success */ protected function submitSoapRequest(){ //Fedex Example code does this - not sure why or if it is really needed .. ini_set("soap.wsdl_cache_enabled", "0"); $objClient = new SoapClient($this->strWsdlUri, array('trace' => 1)); //typical php - this does not work, __soapCall breaks the parameter array: // $this->mixSoapResponse = $objClient->__soapCall($this->strSoapFunction, $this->arySoapRequest); // so we have to do this: $strFunctionName = $this->strSoapFunction; $this->mixSoapResponse = $objClient->$strFunctionName($this->arySoapRequest); } /** * Connects to web service and submits the request. Note that * this function merely constructs a request URL from internal variables * that are set in createRequest, it may therefor contain a GET query * string or a POST depending on the subclass requirements. *@return boolean true on success */ protected function submitRequest(){ if( WebRequestType::SOAP === $this->intRequestType) return $this->submitSoapRequest(); $strProtocol = ''; if($this->UseSsl){ $strProtocol = 'ssl://'; $this->intPort = 443; }else{ // $strProtocol = 'http://'; $this->intPort = 80; } $strTarget = $strProtocol . $this->strRemoteDomainName; //attempt to connect .. @$fp = fsockopen($strTarget, $this->intPort, $intError, $strError, $this->intTimeOut ); //did we connect? if (!$fp){ if($this->TestMode) throw new Exception("Web Service request failed: $strError ($intError) "); else return false; }else{ // optionally add an API extension: if($this->strApiName) $strUrl = $this->strRemoteCgiUrl . $this->strApiName; else $strUrl = $this->strRemoteCgiUrl; //construct the request .. switch( $this->intRequestType ){ case WebRequestType::GET: $out = "GET " . $strUrl . $this->strRequest . " HTTP/1.1\r\n"; $out .= "Host:" . $this->strRemoteDomainName . "\r\n"; $out .= "User-Agent: QuintaCMS " . QUINTA_VERSION . "\r\n"; $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; $out .= "Connection: Close\r\n\r\n"; break; case WebRequestType::POST: $out = "POST " . $strUrl . " HTTP/1.1\r\n"; $out .= "Host:" . $this->strRemoteDomainName . "\r\n"; $out .= "User-Agent: QuintaCMS " . QUINTA_VERSION . "\r\n"; // $out .= "MIME-Version: 1.0\r\n"; $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; // $out .= "Accept: text/xml\r\n"; $out .= "Content-length: " . strlen($this->strRequest) . "\r\n"; $out .= "Cache-Control: no-cache\r\n"; $out .= "Connection: Close\r\n\r\n"; $out .= $this->strRequest . "\r\n\r\n"; break; default: throw new Exception('WebService RequestType unsupported: ' . $this->intRequestType); } //send the request fwrite($fp, $out ); $this->strResponse = ''; //store the response while ( !feof($fp) ) $this->strResponse .= fgets($fp, 128); $this->strResponse .= $out; fclose($fp); return true; } } /** * This function directs the call to the appropriate creation function and returns * a string containing either a query string for a GET or a content string for a POST. * * A WebRequestType may be provided to override a default as an alternative to setting * it explicitly. Note that this will set the RequestType for the object. * *@param string intRequestType - you may provide the RequestType */ protected function createRequest($intWebRequestType=null){ if(null !== $intWebRequestType) $this->intRequestType = $intWebRequestType; switch($this->intRequestType){ case WebRequestType::GET: $this->createGETRequest(); return $this->strRequest; break; case WebRequestType::POST: $this->createPOSTRequest(); return $this->strRequest; break; case WebRequestType::SOAP: default: throw new Exception('WebService RequestType unsupported: ' . $this->RequestType); } } /** * Utility function to extract a root XML node string by tag * *@param string text of the node name *@return null | DOMDocument - a DOMDocument containing the node or null on failure */ protected function getDomDocument($strTag){ $strStartTag = '<' . $strTag . '>'; $strEndTag = ''; $intStartPos = strpos( $this->strResponse, $strStartTag ); //no start? try leaving the start tag open ended to allow definitions .. if(false === $intStartPos){ $strStartTag = '<' . $strTag . ' '; $intStartPos = strpos( $this->strResponse, $strStartTag ); } $intEndPos = strpos($this->strResponse, $strEndTag); $intLength = ($intEndPos + strlen($strEndTag)) - $intStartPos; if(false !== $intStartPos && false !== $intEndPos){ $objDomDoc = new DOMDocument(); //don't let Domdoc complain about incorrect Endicia XML .. if( @$objDomDoc->loadXML(substr( $this->strResponse, $intStartPos, $intLength)) ); return $objDomDoc; } return null; } public function __get($strName){ switch ($strName){ case 'RemotePassword': return $this->strRemotePassword ; case 'RemoteAccountId': return $this->strRemoteAccountId ; case 'RemoteCgiUrl': return $this->strRemoteCgiUrl ; case 'RemoteDomainName': return $this->strRemoteDomainName ; case 'Errors': return $this->strErrors ; case 'HasErrors': return $this->blnHasErrors ; case 'UseSsl': return $this->blnUseSsl ; case 'TestMode': return $this->blnTestMode ; case 'TimeOut': return $this->intTimeOut ; case 'Port': return $this->intPort ; default: throw new Exception('WebService Request - Unknown __get property: ' . $strName); } } public function __set($strName, $mixValue){ switch ($strName){ case 'RemoteDomainName': try { return ($this->strRemoteDomainName = QType::Cast($mixValue, QType::String )); } catch (QInvalidCastException $objExc) { $objExc->IncrementOffset(); throw $objExc; } case 'RemoteCgiUrl': try { return ($this->strRemoteCgiUrl = QType::Cast($mixValue, QType::String )); } catch (QInvalidCastException $objExc) { $objExc->IncrementOffset(); throw $objExc; } case 'RemoteAccountId': try { return ($this->strRemoteAccountId = QType::Cast($mixValue, QType::String )); } catch (QInvalidCastException $objExc) { $objExc->IncrementOffset(); throw $objExc; } case 'RemotePassword': try { return ($this->strRemotePassword = QType::Cast($mixValue, QType::String )); } catch (QInvalidCastException $objExc) { $objExc->IncrementOffset(); throw $objExc; } case 'Errors': try { return ($this->strErrors = QType::Cast($mixValue, QType::String )); } catch (QInvalidCastException $objExc) { $objExc->IncrementOffset(); throw $objExc; } case 'HasErrors': try { return ($this->blnHasErrors = QType::Cast($mixValue, QType::Boolean )); } catch (QInvalidCastException $objExc) { $objExc->IncrementOffset(); throw $objExc; } case 'UseSsl': try { return ($this->blnUseSsl = QType::Cast($mixValue, QType::Boolean )); } catch (QInvalidCastException $objExc) { $objExc->IncrementOffset(); throw $objExc; } case 'TestMode': try { return ($this->blnTestMode = QType::Cast($mixValue, QType::Boolean )); } catch (QInvalidCastException $objExc) { $objExc->IncrementOffset(); throw $objExc; } case 'Port': try { return ($this->intPort = QType::Cast($mixValue, QType::Integer )); } catch (QInvalidCastException $objExc) { $objExc->IncrementOffset(); throw $objExc; } case 'TimeOut': try { return ($this->intTimeOut = QType::Cast($mixValue, QType::Integer )); } catch (QInvalidCastException $objExc) { $objExc->IncrementOffset(); throw $objExc; } default: throw new Exception('WebService Request - Unknown __set property: ' . $strName); } } }//end class }//end define ?>