PHP and Sabre
What is Sabre?
Sabre is a company that has data of all flight schedules, etc. And, using their system, you can book flights, hotels, rent cars, etc.
Getting PHP to talk with Sabre
I tried PHP Soap and nuSoap. They both didn't work for me because of their limitations. So I ended up writing a small script of my own that talks with Sabre for me after I realized that the headers being sent by all the SOAP libraries I tried, were not compatible with Sabre's web services.
Sabre checks the "Content-Type" header in your request. If that is not "text/xml", you will always get an error, even if your xml is correct.
Here's a little piece of code that should help with the transport part. I will leave the generation of XML to you.
/** * Sabre class (for connecting to Sabre web services) * @author Moazzam Khan <moazzam at moazzam-khan dot com> * @version $Id$ */ class Sabre { public $host; public $port; public $timeout; public function Sabre() { $this->timeout = 30; } public function makeRequest($body) { $header = "POST /websvc HTTP/1.1\r\n" . "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){ print "SOCKET ERROR $errstr ($errno)\n"; } else { //send the request fputs($fp, $header."\r\n\r\n".$body, strlen($header."\r\n\r\n".$body)); stream_set_timeout($fp, 30); stream_set_blocking ($fp, 1); while (!feof($fp)) { $line = fread($fp, 2048); if (trim(strlen($line)) < 10) continue; $output .= $line; } fclose($fp); } $ret = explode("\r\n\r\n", $output); $ret = explode("\r\n", $ret[1]); for ($i=0; $i<count($ret); ++$i) if (strlen($ret[$i]) < 5) $ret[$i] = ''; return implode('', $ret); } }
Design Patterns – Singletons in PHP 5.x
Design Patterns (and anti-patterns) are techniques of programming. There are a lot of design patterns. It is upto the programmer to pick and choose which patterns to use based on their needs. Singleton is also a design pattern. A singleton is a type of class which can have only 1 object of its kind through the lifecycle of an application. It is very suitable for database, caching, etc. I will use a database class as an example as it is probably the most-widely used class in web development.
Why use a singleton you ask? A popular practice among PHP4's developers is to make a database object global then use that variable anything a query needs to be run. It works in small applications and even in not-so-big applications. In enterprise applications where you use hundreds (if not thousands) of variables, there is a very good chance that you database object will get mutated or overridden. You also don't want to have multiple instance of a database class (unless you are running a multi-threaded application).
A database class should be able to connect to a database, run queries, return results and close the connection to the database when it's done. Keeping that in mind, let's start writing our database class.
/** * Database wrapper */ class Database { private $_host; private $_user; private $_pass; private $_name; private $_conn; private $_err; /** * Setting the constructor as private will make sure * that the class cannot be instantiated using the * "new" keyword. You can to instantiate it like this : * $db = Database::getInstance(); * getInstance() is implemented right after the constructor */ private function __construct($host, $user, $pass, $name) { $this->_host = $host; $this->_user = $user; $this->_pass = $pass; $this->_name = $name; } /** * This function is what makes this whole class a singleton. * It will make sure only one instance of this class is available */ function getInstance($host='', $user='', $pass='', $name='') { static $obj; if (null == $obj) { $obj = new Database($host, $user, $pass, $name); $obj->connect(); } return obj; } /** * Connects to the database */ function connect() { $this->_err = null; if (!mysql_connect($this->_host, $this->_user, $this->_pass)) { $this->_err = mysql_error(); return false; } if (!mysql_select_db($this->_name)) { $this->_err = mysql_error(); return false; } return true; } function error() { return $this->_err; } function user($val=null) { if (null == $val) return $this->_user; $this->_user = $val; } function host($val=null) { if (null == $val) return $this->_host; $this->_host = $val; } function pass($val=null) { if (null == $val) return $this->_pass; $this->_pass = $val; } function name($val=null) { if (null == $val) return $this->_name; $this->_name = $val; } }
So, we wrote a class called database and made its constructor private so you can't instantiate it using the "new" keyword. We also wrote a method/function for this class called getInstance() which will return a database object. getInstance() has a local static variable called $obj. It checks if this variable is null. If it's null then that means there is no object of the type "Database". So, it creates an object and assigns it to $obj. It also returns the object to the code that called it. Setting permissions of private, protected and public could not have been done in PHP 4, which frustrated a lot of OOP enthusiasts. PHP 5, however, has the capability of doing it and thus fulfilling one of OOP's main goals - encapsulation.
The first time an object of the class Database is instantiated, it will have to pass all the variables required to make a database connection. Its subsequent calls need not do that.
// First call $db = Database::getInstance('localhost', 'root', '', 'myDB'); function hello() { // Second call $database = Database::getInstance(); }
Both $db and $database point to the same object. Any changes made to $database will be reflected in $db also. This eliminates the use of global variables for quite a few things (especially our database class).