source: handler-socket-client-php/handler_socket.php

Last change on this file was 91, checked in by apokalyptik, 15 years ago

Some things only work against InnoDB, they only corrupt other table types

File size: 9.6 KB
Line 
1<?php
2
3/* Example code
4 *
5 *              // Tested with source compiled MySQL 5.1.54 and ahiguti-HandlerSocket-Plugin-for-MySQL-c865c53
6 *              $hs = new handler_socket( '127.0.0.1', 9998, 9999 );
7 *              // Works with InnoDB and MyISAM
8 *              $hs->index( 'test_db', 'test_table', 'PRIMARY', array('id','name','code') );
9 *              // Works with InnoDB
10 *              $hs->insert( 'PRIMARY', array( 1, 'FOO', 'F@' ) );
11 *              // Works with InnoDB and MyISAM
12 *              $results = $hs->select('PRIMARY', '=', 1 );
13 *              // Works with InnoDB
14 *              $hs->update( 'PRIMARY', '=', 1, array( '1', 'FOO UPDATED AT '.time() ) );
15 *              // Works with InnoDB and MyISAM
16 *              $hs->delete( 'PRIMARY', '=', 1 );
17 *
18 * Written against https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL/blob/master/docs-en/protocol.en.txt
19 */
20
21class handler_socket {
22
23        var $debug   = false;
24        var $read        = null;
25        var $write       = null;
26        var $indexes = array();
27        var $lookup      = array();
28
29        /* Initialize a handlersocket client.
30         *
31         * @param $host string the hostname of ip address of the server
32         * @param $read_port integer the port number to connect to for read connections
33         * @param $write_post integer the port number to connect to for write connections
34         */
35        function handler_socket( $host, $read_port, $write_port ) {
36                $this->read = (object)array( 'fp' => null, 'host' => $host, 'port' => $read_port, 'errno' => null, 'error' => null );
37                $this->write = (object)array( 'fp' => null, 'host' => $host, 'port' => $write_port, 'errno' => null, 'error' => null );
38        }
39
40        /* Define an index, and the columns you want to interract with when using it
41         *
42         * @param $db string the name, in MySQL, of the database in which the table exists
43         * @param $table string the name, in MySQL, of the table on which the index exists
44         * @param $key string the name, in MySQL, of the index you wish to use on the table
45         * @param $columns array the columns you wish to interract with.  This includes querying against, returning, inserting, and updating
46         */
47        function index( $db, $table, $key, $columns ) {
48                if ( isset( $this->lookup[$key] ) )
49                        return true;
50                $this->lookup[$key] = count( $this->indexes );
51                $this->indexes[] = (object)array(
52                        'd' => $db,
53                        't' => $table,
54                        'k' => $key,
55                        'c' => $columns,
56                        'read' => false, 
57                        'write' => false,
58                );
59        }
60
61        /*
62         * Select against a defined index
63         *
64         * @param $key string the defined index you wish to use, use "PRIMARY" fpr the primary key
65         * @param $op string the operation you want to use, one of '=', '>', '>=', '<', or '<='
66         * @param $values array a list of strings to compare to the index columns using the $op to test
67         * @param $limit integer
68         * @param $offset integer
69         */
70        function select( $key, $op, $values, $limit=1, $offset=0 ) {
71                if ( !$this->open( $key ) )
72                        return false;
73                if ( !$values )
74                        return false;
75                if ( !is_array($values) )
76                        $values = array( $values );
77                $id = $this->lookup[$key];
78                $request = array( $id, $op, (string)count($values) );
79                foreach( $values as $val ) 
80                        $request[] = (string)$val;
81                $request[] = $limit;
82                $request[] = $offset;
83                $request = $this->create_request( $request );
84                return $this->parse_response( $this->query( 'read', $request ), $key );
85        }
86
87        /*
88         * Delete via comparison against a defined index
89         *
90         * @param $key string the defined index you wish to use, use "PRIMARY" fpr the primary key
91         * @param $op string the operation you want to use, one of '=', '>', '>=', '<', or '<='
92         * @param $compare array a list of strings to compare to the index columns using the $op to test
93         * @param $limit integer
94         * @param $offset integer
95         */ 
96        function delete( $key, $op, $compare, $limit=1, $offset=0 ) {
97                if ( !$this->open( $key, 'write' ) )
98                        return false;
99                if ( !is_array( $compare ) )
100                        $compare = array( $compare );
101                $id = $this->lookup[$key];
102                $request = array( $id, $op, (string)count($compare) );
103                foreach( $compare as $val )
104                        $request[] = (string)$val;
105                $request[] = $limit;
106                $request[] = $offset;
107                $request[] = 'D';
108                $request = $this->create_request( $request );
109                return $this->parse_response( $this->query( 'write', $request ), false );
110        }
111
112        /*
113         * Update via comparison against a defined index
114         *
115         * @param $key string the defined index you wish to use, use "PRIMARY" fpr the primary key
116         * @param $op string the operation you want to use, one of '=', '>', '>=', '<', or '<='
117         * @param $compare array a list of strings to compare to the index columns using the $op to test
118         * @param $update array a list of strings to use, mapping to the columns in the defined index
119         * @param $limit integer
120         * @param $offset integer
121         */
122        function update( $key, $op, $compare, $update, $limit=1, $offset=0 ) {
123                if ( !$this->open( $key, 'write' ) )
124                        return false;
125                if ( !$update )
126                        return false;
127                if ( !is_array( $compare ) )
128                        $compare = array( $compare );
129                if ( !is_array( $update ) )
130                        $update = array( $update );
131                $id = $this->lookup[$key];
132                $request = array( $id, $op, (string)count($compare) );
133                foreach( $compare as $val )
134                        $request[] = (string)$val;
135                $request[] = $limit;
136                $request[] = $offset;
137                $request[] = 'U';
138                foreach( $update as $val )
139                        $request[] = (string)$val;
140                $request = $this->create_request( $request );
141                return $this->parse_response( $this->query( 'write', $request ), true );
142        }
143
144        /*
145         * Insert into a given table, using the key as a reference
146         *
147         * @param $key string the defined index you wish to use, use "PRIMARY" fpr the primary key
148         * @param $values array a list of strings to use for the insert, mapping to the columns in the defined index
149         */
150        function insert( $key, $values ) {
151                if ( !$this->open( $key, 'write' ) )
152                        return false;
153                if ( !is_array( $values ) )
154                        $values = array( $valuse );
155                $id = $this->lookup[$key];
156                $request = array( $id, '+', (string)count($values) );
157                foreach( $values as $val )
158                        $request[] = (string)$val;
159                $request = $this->create_request( $request );
160                return $this->parse_response( $this->query( 'write', $request ), false );
161        }
162
163        private function open( $key, $type="read" ) {
164                if ( !isset( $this->lookup[$key] ) )
165                        return false;
166                $id = $this->lookup[$key];
167                if ( $this->indexes[$id]->$type )
168                        return true;
169                $request = $this->create_request( array(
170                        'P', 
171                        (string)$id,
172                        $this->indexes[$id]->d,
173                        $this->indexes[$id]->t,
174                        $this->indexes[$id]->k,
175                        implode( ',', $this->indexes[$id]->c )
176                ));
177                if ( !$this->parse_response( $this->query( $type, $request ), true ) )
178                        return false;
179                $this->indexes[$id]->$type = 1;
180                return true;
181        }
182
183        private function query( $type='read', $request ) {
184                if ( !$this->connect( $type ) )
185                        return false;
186                if ( $this->debug )
187                        echo "> $type > $request";
188                if ( false === fwrite( $this->$type->fp, $request ) )
189                        return false;
190                return $this->read( $type );
191        }
192
193        private function connect( $type='read' ) {
194                if ( !isset( $this->$type ) ) {
195                        if ( $this->debug )
196                                echo "connect: $type, no such thing\n";
197                        return false;
198                }
199                if ( $this->$type->fp ) {
200                        if ( $this->debug )
201                                echo "connect: $type, already connected\n";
202                        return true;
203                }
204                $this->$type->fp = fsockopen( 
205                        $this->$type->host,
206                        $this->$type->port,
207                        $this->$type->errno,
208                        $this->$type->error
209                );
210                if ( $this->$type->fp ) {
211                        if ( $this->debug )
212                                echo "connect: $type, connected\n";
213                        return true;
214                }
215                $this->$type->fp = null;
216                if ( $this->debug )
217                        echo "connect: $type, failed to connect\n";
218                return false;
219        }
220
221        private function read( $type='read' ) {
222                if ( !isset( $this->$type ) )
223                        return false;
224                if ( !$this->$type->fp )
225                        return false;
226                $line = '';
227                $chars = 0;
228                if ( $this->debug )
229                        echo "< $type < ";
230                while ( !feof( $this->$type->fp ) ) {
231                        $chars++;
232                        $c = fread( $this->$type->fp, 1 );
233                        if ( $this->debug )
234                                echo $c;
235                        if ( $c === "\x0a" )
236                                break;
237                        if ( $chars < 2 )
238                                continue;
239                        $line .= $c;
240                }
241                return $line;
242        }
243
244        private function create_request( $tokens ) {
245                foreach( $tokens as $idx => $token )
246                        $tokens[$idx] = $this->encode_token( $token );
247                return implode( "\x09", $tokens ) . "\x0a";
248        }
249
250        private function parse_response( $line, $key=null ) {
251                $tokens = explode( "\x09", $line );
252                foreach( $tokens as $idx => $token )
253                        $tokens[$idx] == $this->unencode_token( $token );
254                $error = array_shift( $tokens );
255                if ( $error )
256                        return false;
257                // open, insert
258                if ( $key === true )
259                        return true;
260                // find_modify
261                if ( $key === false )
262                        return array_shift( $tokens );
263                // find
264                $cols = array_shift( $tokens );
265                $i = 0;
266                $rval = array();
267                foreach( $tokens as $v ) {
268                        $pos = ++$i%$cols;
269                        if ( $pos == 1 )
270                                $entry = array();
271                        $n = $pos - 1;
272                        if ( $n == -1 )
273                                $n = ( $cols - 1 );
274                        if ( $key )
275                                $n = $this->indexes[$this->lookup[$key]]->c[$n];
276                        $entry[$n] = $v;
277                        if ( $pos == 0 )
278                                $rval[] = (object)$entry;
279                }
280                return $rval;
281        }
282
283        private function unencode_token( $token ) {
284                if ( $token === "\x00" )
285                        return null;
286                return str_replace(
287                        array(
288                                        "\x01\x40", "\x01\x41", "\x01\x42", "\x01\x43", "\x01\x44", "\x01\x45",
289                                        "\x01\x46", "\x01\x47", "\x01\x48", "\x01\x49", "\x01\x4a", "\x01\x4b",
290                                        "\x01\x4c", "\x01\x4d", "\x01\x4e", "\x01\x4f",
291                        ),
292                        array(
293                                        "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", 
294                                        "\x06", "\x07", "\x08", "\x09", "\x0a", "\x0b", 
295                                        "\x0c", "\x0d", "\x0e", "\x0f",
296                        ),
297                        $token
298                );
299        }
300
301        private function encode_token( $token ) {
302                if ( $token === null )
303                        return "\x00";
304                return str_replace(
305                        array(
306                                "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", 
307                                "\x06", "\x07", "\x08", "\x09", "\x0a", "\x0b", 
308                                "\x0c", "\x0d", "\x0e", "\x0f",
309                        ),
310                        array(
311                                "\x01\x40", "\x01\x41", "\x01\x42", "\x01\x43", "\x01\x44", "\x01\x45",
312                                "\x01\x46", "\x01\x47", "\x01\x48", "\x01\x49", "\x01\x4a", "\x01\x4b",
313                                "\x01\x4c", "\x01\x4d", "\x01\x4e", "\x01\x4f",
314                        ),
315                        $token
316                );
317        }
318
319}
Note: See TracBrowser for help on using the repository browser.