PHP Tyrant

Sign in or create your account | Project List | Help

PHP Tyrant Git Source Tree

Root/Tyrant.php

1<?php
2/**
3* Tokyo Tyrant network API for PHP
4*
5* Copyright (c) 2009 Bertrand Mansion <bmansion@mamasam.com>
6*
7* Permission is hereby granted, free of charge, to any person obtaining a copy
8* of this software and associated documentation files (the "Software"), to deal
9* in the Software without restriction, including without limitation the rights
10* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11* copies of the Software, and to permit persons to whom the Software is
12* furnished to do so, subject to the following conditions:
13*
14* The above copyright notice and this permission notice shall be included in
15* all copies or substantial portions of the Software.
16*
17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23* THE SOFTWARE.
24*
25* @package Tyrant
26* @author Bertrand Mansion <bmansion@mamasam.com>
27* @license http://www.opensource.org/licenses/mit-license.php MIT License
28* @link http://mamasam.indefero.net/p/tyrant/
29*/
30
31require_once dirname(__FILE__).'/Tyrant/Exception.php';
32
33/**
34* Factory for Tokyo Tyrant connections
35*
36* @package Tyrant
37* @author Bertrand Mansion <bmansion@mamasam.com>
38*/
39class Tyrant
40{
41    /**
42    * Scripting extension option for record locking
43    */
44    const XOLCKREC = 1;
45
46    /**
47    * scripting extension option for global locking
48    */
49    const XOLCKGLB = 2;
50
51    /**
52    * Misc function option for omission of the update log
53    */
54    const MONOULOG = 1;
55
56    /**
57    * Restore function option for consistency checking
58    */
59    const ROCHKCON = 1;
60
61    /**
62    * Keeps track of the connection objects
63    * Makes it possible to easily reuse a connection.
64    * @var array
65    */
66    protected static $connections = array();
67
68    /**
69    * Current connection object
70    * @var object
71    */
72    protected static $connection;
73
74    /**
75    * Opens a connection to a Tokyo Tyrant server
76    * <code>
77    * try {
78    * $tt = Tyrant::connect('localhost', 1978);
79    * } catch (Tyrant_Exception $e) {
80    * echo $e->getMessage();
81    * }
82    * </code>
83    *
84    * @param string Server hostname or IP address
85    * @param string Server port
86    * @param string Optional existing connection id
87    * @return object Database connection
88    */
89    public static function connect($host = 'localhost', $port = '1978', $id = 0)
90    {
91        $id = implode(':', array($host, $port, $id));
92        
93        // Check if connection already exists
94        
95        if (isset(self::$connections[$id])) {
96            $connection =& self::$connections[$id];
97            return $connection;
98        }
99
100        // Start a new connection
101
102        $ip = gethostbyname($host);
103        $addr = ip2long($ip);
104        if (empty($addr)) {
105            throw new Tyrant_Exception("Host not found");
106        }
107        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
108        if (!is_resource($socket)){
109            throw new Tyrant_Exception("Connection refused");
110        }
111        if (!socket_connect($socket, $addr, $port)) {
112            throw new Tyrant_Exception("Connection refused");
113        }
114        if (defined('TCP_NODELAY')) {
115            socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1);
116        } else {
117            // See http://bugs.php.net/bug.php?id=46360
118            socket_set_option($socket, SOL_TCP, 1, 1);
119        }
120
121        // Determine the database type
122
123        if (socket_write($socket, pack('CC', 0xC8, 0x88)) === false) {
124            throw new Tyrant_Exception("Unable to get database type");
125        }
126        $str = '';
127        if (socket_recv($socket, $str, 1, 0) === false) {
128            throw new Tyrant_Exception("Unable to get database type");
129        }
130        $c = unpack("C", $str);
131        if (!isset($c[1]) || $c[1] !== 0) {
132            throw new Tyrant_Exception("Unable to get database type");
133        }
134        $str = '';
135        if (socket_recv($socket, $str, 4, 0) === false) {
136            throw new Tyrant_Exception("Unable to get database type");
137        }
138        $num = unpack("N", $str);
139        if (!isset($num[1])) {
140            throw new Tyrant_Exception("Unable to get database type");
141        }
142        $size = unpack("l", pack("l", $num[1]));
143        $len = $size[1];
144        $str = '';
145        if (socket_recv($socket, $str, $len, 0) === false) {
146            throw new Tyrant_Exception("Unable to get database type");
147        }
148        $value = explode("\n", trim($str));
149        $stats = array();
150        foreach ($value as $v) {
151            $v = explode("\t", $v);
152            $stats[$v[0]] = $v[1];
153        }
154        if (!isset($stats['type'])) {
155            throw new Tyrant_Exception("Unable to get database type");
156        }
157        
158        // Get the right interface for the database type
159        
160        if ($stats['type'] == 'table') {
161            include_once dirname(__FILE__).'/Tyrant/RDBTable.php';
162            $conn = new Tyrant_RDBTable($socket);
163        } else {
164            include_once dirname(__FILE__).'/Tyrant/RDB.php';
165            $conn = new Tyrant_RDB($socket);
166        }
167        self::$connections[$id] =& $conn;
168        self::$connection = $conn;
169        return $conn;
170    }
171
172    /**
173    * Return the current connection
174    * The current connection is set using Tyrant::setConnection() and
175    * defaults to the last connection made
176    *
177    * @return object|null First connection in the stack
178    */
179    public function getConnection()
180    {
181        return self::$connection;
182    }
183
184    /**
185    * Changes the current connection
186    * @param string Server hostname or IP address
187    * @param string Server port
188    * @param string Optional existing connection id
189    * @return object|null First connection in the stack
190    */
191    public function setConnection($host = 'localhost', $port = '1978', $id = 0)
192    {
193        $id = implode(':', array($host, $port, $id));
194        self::$connection =& self::$connections[$id];
195    }
196
197    /**
198    * Disconnects and removes a connection
199    * @param string Server hostname or IP address
200    * @param string Server port
201    * @param string Optional existing connection id
202    */
203    public function disconnect($host = 'localhost', $port = '1978', $id = 0)
204    {
205        $id = implode(':', array($host, $port, $id));
206        if (isset(self::$connections[$id])) {
207            $connection =& self::$connections[$id];
208            $connection->disconnect();
209            unset(self::$connections[$id]);
210            return true;
211        }
212        return false;
213    }
214}
215

Archive Download this file

Branches:
master