A QCodo powered CMS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

412 lines
13 KiB

<?php
if(!defined('QUINTACMS') ) die('No Quinta.');
if (!defined("WEBSERVICEREQUEST.CLASS.PHP")){
define("WEBSERVICEREQUEST.CLASS.PHP",1);
/**
* Class WebRequestType - enumerator class for types of shipping requests
*@package Quinta
* @subpackage Classes
*/
class WebRequestType
{
///@var const - a POST request
const POST = 1;
///@var const - a GET request
const GET = 2;
///@var const - a SOAP request
const SOAP = 3;
}
/**
* Class WebServiceRequest - base class for classes that perform request actions with a web service
*
* This class provides the basic request actions and properties for all of the Shipping and Payment Action classes.
* This includes making the connection to the payment service provider, sending the request in either GET or
* POST (usually in XML ..) and accepting the response from the server.
* The request to send is stored in strRequest and the response is stored in strResponse regardless
* of format or request type. Subclasses are responsible for initilizing these priory to calling createRequest(),
* formatting the request and for handling the response. The required properties (eg. RemoteDomainName,
* RemotePassword, etc ..) must be initilized by users of this or subclasses.
*
* Subclasses must implement these methods:
* - createPostRequest: initializes strRequest with a formatted POST query (may return null if unused)
* - createGetRequest: initializes strRequest with a formatted GET query (may return null if unused)
* - handleResponse: parse strResponse for relevant data ..
*
* See the documentation for the Shipping and Payment Action subclasses
* for more details.
*
*@todo
* - Support SOAP connections
* - Support using CURL
*
*@author Erik Winn <sidewalksoftware@gmail.com>
*
*@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 = '</' . $strTag . '>';
$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
?>