Sabre Web Services in PHP

oecdworld200I’ve been on contract for the past couple of months at a lovely company up in Newmarket, called Solutions360. I’m part of a team working on a system for the travel industry. So we’re deep into API’s for hotels, flights, cruises and such. Listing, booking, cancelling have been our constant concerns for weeks now.

My bailiwick is a module called a Service Manager, which translates requests from our system to an outside web service. Then captures the responses and again translates them into a standard format for the system to display.

The first Service Manager I wrote used the cURL library to communicate with the external service. So when it came time to interface with the Sabre services I tried using the same mechanism; but for some reason it was a non-starter. I tweaked it as much as I could; as much as it made sense to. But the only response I got was an error that the service “couldn’t internalize the request.” *sigh*

And while Sabre’s support team has proven to be enormously helpful and responsive, on the phone and via email, if it isn’t Java or .Net, you’re pretty much on your own.

Then I turned to the Interwebs for help, and that’s where I found Moazzam Khan’s blog post PHP and Sabre. In it Moazzam gives us a class which eschews cURL in favour of a low-level approach using fsockopen(), and the ssl:// scheme. Brilliant. And more importantly, it works.

I’ve tweaked the routine a bit, and present it here complete with an invocation for SessionCreateRQ. All you need to add are your credentials.

<?php
	$serverProperties = array (
		 'SERVER'  		=> 'sws-crt.cert.sabre.com' 
		,'USERNAME' 	=> '*USERNAME*'
		,'PASSWORD' 	=> '*PASSWORD*'
		,'PCC'			=> '*PCC*'
	);

	// == Process Request
	$oDate = new DateTime();
	$timestamp = $oDate->format('Y-m-d\Th:i:sP');
	$timetolive = $oDate->add(new DateInterval('PT1H'))->format('Y-m-d\Th:i:sP');
	$xml = <<<SESSIONCREATEXML
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="https://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Header>
      <MessageHeader xmlns="https://www.ebxml.org/namespaces/messageHeader">
         <From>
            <PartyId type="urn:x12.org:IO5:01">Sabre WS Example</PartyId>
         </From>
         <To>
            <PartyId type="urn:x12.org:IO5:01">Sabre</PartyId>
         </To>
         <CPAId>{$serverProperties['PCC']}</CPAId>
         <ConversationId>MyConversationID</ConversationId>
         <Service type="string">Cruise</Service>
         <Action>SessionCreateRQ</Action>
         <MessageData>
            <MessageId>1000</MessageId>
            <Timestamp>{$timestamp}</Timestamp>
            <TimeToLive>{$timetolive}</TimeToLive>
         </MessageData>
      </MessageHeader>
      <Security xmlns="https://schemas.xmlsoap.org/ws/2002/12/secext">
         <UsernameToken>
            <Username>{$serverProperties['USERNAME']}</Username>
            <Password>{$serverProperties['PASSWORD']}</Password>
            <Organization>{$serverProperties['PCC']}</Organization>
            <Domain>DEFAULT</Domain>
         </UsernameToken>
      </Security>
   </soapenv:Header>
   <soapenv:Body>
      <SessionCreateRQ xmlns="https://www.opentravel.org/OTA/2002/11">
         <POS>
            <Source PseudoCityCode="{$serverProperties['PCC']}" />
         </POS>
      </SessionCreateRQ>
   </soapenv:Body>
</soapenv:Envelope>
SESSIONCREATEXML;

	// == Submit Request
	$xmlResponse = callSabre($xml);
	echo '<pre>';
	echo $xmlResponse;
	echo '</pre>';

	function callSabre($xml) {

		$oSabre = new Sabre();
		$oSabre->host = $serverProperties['SERVER'];
		$content = $oSabre->makeRequest($xml);

		return $content;
	}


/**
 * Sabre class (for connecting to Sabre web services)
 * @author Moazzam Khan <moazzam at moazzam-khan dot com>
 * @version $Id$
 * @source https://moazzam-khan.com/blog/?p=495
 */
class Sabre {
	public $host;
	public $port = 443;
	public $timeout = 30;
 
	public function makeRequest($body) {

		$header = "POST /websvc HTTP/1.1
Host: {$this->host}:{$this->port}
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Content-Type: text/xml
Content-Length: ".strlen($body)."
Pragma: no-cache
Cache-Control: no-cache";

		$fp = fsockopen("ssl://".$this->host, $this->port, $errno, $errstr, $this->timeout);
		if(!$fp){
			throw new Exception("SOCKET ERROR ({$errno}): {$errstr}\n");
		} else {
				//send the request
				$req = $header."\r\n\r\n".$body;
				fputs($fp, $req, strlen($req));
				stream_set_timeout($fp, $this->timeout);
				stream_set_blocking($fp, 1);
				while (!feof($fp)) {
					$line = fread($fp, 2048);
					// if (trim(strlen($line)) < 10) continue;
					$output .= $line;
				}
				fclose($fp);
		}

		// remove the HTTP response header
		$ret = explode("\r\n\r\n", $output);
		$ret = $ret[1];

		// format XML so we can read it.
		$dom = new DOMDocument;
		$dom->preserveWhiteSpace = FALSE;
		$dom->loadXML($ret);
		$dom->formatOutput = TRUE;
		$ret = $dom->saveXml();
			
		return $ret;
	}
}

I hope you find this helpful.

23 thoughts on “Sabre Web Services in PHP

  1. Hi Alfred,

    This looks nice. I am glad my blog post was helpful. What I also did (but did not publish) is create a session manager along with “Sabre” class. Session manager, checks for the right parameters, etc and instantiates a connection object (an instance of Sabre class).

    I have fallen in love with dependency injection so I have been refactoring everything to use that. You should check it out too!

    • Yes, I’ve looked at Dependency Injection, but I haven’t yet seen the light on that one. From a testing perspective I see it makes it easier. When I jump into testing with both feet I expect it’ll make more sense to me.

      Thanks for taking the time to look at my post.

      • Hi Alfred,

        is it still working?
        I’ve copied the same code and I’ve changed my credentials. And get some error.

        As well:
        unable to connect to ssl://:443 (No connection could be made because the target machine actively refused it. )

        On the call Sabre->makeRequest( )

        Can you help me?

  2. Peter, I disagree.

    Just because a system has a convoluted history does not mean that it should be scrapped. Using that logic, banks would be redoing their Point of Sale and ATM systems every couple of years. There is no way any non IT company can afford to replace a systenm simply because it is old….

  3. Good afternoon, thank you for your example, everything turned out. Many examples of how to find flights, book, etc. Ready to take part in the development examples, only direct.

  4. Hi Moazzam Khan,
    please help me,

    i have create the PNR, nt now i want to issue the ticket on sabre webconnect, i try a lot but i still unsuccessfully, please mention me which payload send to sabre server, i using these webservice for issue ticket
    DesignatePrinterLLS
    PhaseIVAddInfoLLS for PQ
    TravelItineraryReadLLS
    AirTicketLLS

    without payment

    please help me some body.

    • Sorry KabirSafi, it’s been almost 2 years since I’ve played with this API. I don’t even think I have credentials to access it anymore. But perhaps someone else, more current with it, can. Also, have you looked at Sabre’s own site for developers? What about StackOverflow?

      Best of luck.

    • Ask to the developers mail of Sabre. They are also very help full.

      @Alfred
      I’m just started using sabre api. As a reference I’m using this codes of Alfred. Though sabre api is totally different now.
      Thanks Alfred for this helpfull post.

      • are you create the session or not, if you not create the session then you first create the session, when create the session the close the session.
        when you close the session then you get the security token which is most important in sabre api. then call RQ payload, through security token it’s get response to you.

        1: createSession payload.
        2: closeSession payload
        3: you target payload (RQ)

        xpert of sabre web service

        kabir safi

        • Kabir , i think first we need to create session then in response it returns token and we have to store that token because for another request you need that token , at the end you close session.

  5. can anybody tell me how can i create session and check flights availability using sabre web-service in java, please help me, i need urgent help related to use sabre web-services consumption and usage in java

Leave a Reply to Alfred Ayache Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.