Showing posts with label https. Show all posts
Showing posts with label https. Show all posts

Friday, June 12, 2009

Using CURL as HTTP Client for XmlRPC in PHP

From my previous post, about modification of IXR XmlRPC client to add HTTPS capability, I used function fopen as a HTTP/S client. This technique can only be applied for PHP ver 5.0 or above. So, in this post, I will try to use CURL as a more attractive alternative for all PHP version that support CURL extention. CURL itself is known as stable and powerful multi protocol (including HTTP/S) client for command line in linux world. Thanks to the extension capability of PHP, we can utilize the power of CURL inside PHP directly. So here is the code for SendHttpPost method using CURL:

function SendHttpPost($url,$content){

$ch = curl_init(); // initialize curl handle

curl_setopt($ch, CURLOPT_VERBOSE, 0); // set url to post to
curl_setopt($ch, CURLOPT_URL, $url); // set url to post to
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // return into a variable
curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type: text/xml"));
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_TIMEOUT, 40); // times out after 4s
curl_setopt($ch, CURLOPT_POSTFIELDS, $content); // add POST fields
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST ,0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

$result = curl_exec($ch); // run the whole process

if (empty($result)) {
// some kind of an error happened
//die(curl_error($ch));
//curl_close($ch); // close cURL handler

} else {
$info = curl_getinfo($ch);
//curl_close($ch); // close cURL handler

if (empty($info['http_code'])) {
//die("No HTTP code was returned");
} else {
// load the HTTP codes
// $http_codes = parse_ini_file("response.inc");
// echo results
//echo "The server responded: \n";
//echo $info['http_code'] . " " . $http_codes[$info['http_code']];
}
}

curl_close($ch);
return $result; //contains response from server

}



Thursday, June 11, 2009

Secure HTTP/HTTPS capable XmlRpc library for PHP

IXR - The Inutio XML-RPC Library is one of my favorite Xmlrpc library for PHP. I found it very straight forward,simple and powerful xmlrpc client. Unfortunately, it doesn't have capability to connect using secure HTTP protocol / HTTPS. So, I decided to give more "security" juice to it. The trick is to use fopen instead of fsockopen function to send HTTP POST method to the server. For your notice, this trick is for PHP ver 5 or above only. Replace the function query() in file IXR_Library.inc, with this modification:

/*
* Sends a form-encoded HTTP(S) POST to a given URL.
* Returns a string containing the response.
*
* If response code is not 200, throws an error msg.
*/
function SendHttpPost($url,$content)
{


$context_options = array(
'http'=>array(
'method'=>"POST",
'header'=> "User-Agent: {$this->useragent}\r\n".
"Content-type: text/xml\r\n".
"Content-length: " . strlen($content) . "\r\n"
,
'content'=> $content
)
);
// Make sure the HTTPS options are the same as HTTP
$context_options['https'] = $context_options['http'];
$context = stream_context_create($context_options);
echo 'context:'.var_export($context_options,true);
$fp = fopen($url, 'r', false, $context);
// Get the response...
$response = '';
/* For HTTPS, IIS closes the SSL socket improperly hence
* generating a warning. We want to suppress this, as some
* servers will be doing this.
*
* see http://uk.php.net/manual/en/wrappers.http.php
*/
$old_error_reporting = error_reporting();
error_reporting($old_error_reporting & ~E_WARNING);
// Get the headers
$metadata = stream_get_meta_data($fp);
foreach($metadata['wrapper_data'] as $responseheader) {
// Look for the status header...
if (substr($responseheader,0,5) == 'HTTP/') {
$bits = split(' ', $responseheader);
$httpstatus = (int) $bits[1];
$httpstatusmessage = $responseheader;
}
}
// There is no need to check the HTTP status, as fopen wrapper
// that for us anyway.
// Read the the response data
while (!feof($fp)) {
$response .= fread($fp, 8192);
}
fclose($fp);
error_reporting($old_error_reporting);
return $response;
}


function query() {
$args = func_get_args();
$method = array_shift($args);
$request = new IXR_Request($method, $args);
$length = $request->getLength();
$xml = $request->getXml();
// Modification from Original ------------------
// $r = "\r\n";
// $request = "POST {$this->path} HTTP/1.0$r";
// $request .= "Host: {$this->server}$r";
// $request .= "Content-Type: text/xml$r";
// $request .= "User-Agent: {$this->useragent}$r";
// $request .= "Content-length: {$length}$r$r";
// $request .= $xml;
// // Now send the request
// if ($this->debug) {
// echo '
'.htmlspecialchars($request)."\n
\n\n";
// }
// $fp = @fsockopen($this->server, $this->port);
// if (!$fp) {
// $this->error = new IXR_Error(-32300, 'transport error - could not open socket');
// return false;
// }
// fputs($fp, $request);
// $contents = '';
// $gotFirstLine = false;
// $gettingHeaders = true;
// while (!feof($fp)) {
// $line = fgets($fp, 4096);
// if (!$gotFirstLine) {
// // Check line for '200'
// if (strstr($line, '200') === false) {
// $this->error = new IXR_Error(-32300, 'transport error - HTTP status code was not 200');
// return false;
// }
// $gotFirstLine = true;
// }
// if (trim($line) == '') {
// $gettingHeaders = false;
// }
// if (!$gettingHeaders) {
// $contents .= trim($line)."\n";
// }
// }


// end of Modification from Original ------------------

if ($this->debug) {
echo 'server:'.$this->server.'
'.htmlspecialchars( $xml)."\n
\n\n";
}
// Add new function to send HTTP Post
$contents=$this->SendHttpPost($this->server,$xml);
if ($this->debug) {
echo '
'.htmlspecialchars($contents)."\n
\n\n";
}
// Now parse what we've got back
$this->message = new IXR_Message($contents);
if (!$this->message->parse()) {
// XML error
$this->error = new IXR_Error(-32700, 'parse error. not well formed');
return false;
}
// Is the message a fault?
if ($this->message->messageType == 'fault') {
$this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
return false;
}
// Message must be OK
return true;
}