├── CREDITS ├── EXPERIMENTAL ├── LICENSE ├── README.md ├── config.m4 ├── config.w32 ├── handlersocketi class ├── handlersocketi.c ├── handlersocketi_class.c ├── handlersocketi_class.h ├── handlersocketi_exception.c ├── handlersocketi_exception.h ├── handlersocketi_index.c ├── handlersocketi_index.h ├── php_handlersocketi.h ├── php_verdep.h └── util ├── common.h ├── request.c ├── request.h ├── response.c └── response.h /CREDITS: -------------------------------------------------------------------------------- 1 | handlersocketi 2 | -------------------------------------------------------------------------------- /EXPERIMENTAL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjdev/php-ext-handlersocketi/ff47ad829bd152ab4c2c37b4e48982bb975cffcb/EXPERIMENTAL -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------- 2 | The PHP License, version 3.01 3 | Copyright (c) 1999 - 2012 The PHP Group. All rights reserved. 4 | -------------------------------------------------------------------- 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, is permitted provided that the following conditions 8 | are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | 18 | 3. The name "PHP" must not be used to endorse or promote products 19 | derived from this software without prior written permission. For 20 | written permission, please contact group@php.net. 21 | 22 | 4. Products derived from this software may not be called "PHP", nor 23 | may "PHP" appear in their name, without prior written permission 24 | from group@php.net. You may indicate that your software works in 25 | conjunction with PHP by saying "Foo for PHP" instead of calling 26 | it "PHP Foo" or "phpfoo" 27 | 28 | 5. The PHP Group may publish revised and/or new versions of the 29 | license from time to time. Each version will be given a 30 | distinguishing version number. 31 | Once covered code has been published under a particular version 32 | of the license, you may always continue to use it under the terms 33 | of that version. You may also choose to use such covered code 34 | under the terms of any subsequent version of the license 35 | published by the PHP Group. No one other than the PHP Group has 36 | the right to modify the terms applicable to covered code created 37 | under this License. 38 | 39 | 6. Redistributions of any form whatsoever must retain the following 40 | acknowledgment: 41 | "This product includes PHP software, freely available from 42 | ". 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND 45 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 46 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP 48 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 49 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 51 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 53 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 55 | OF THE POSSIBILITY OF SUCH DAMAGE. 56 | 57 | -------------------------------------------------------------------- 58 | 59 | This software consists of voluntary contributions made by many 60 | individuals on behalf of the PHP Group. 61 | 62 | The PHP Group can be contacted via Email at group@php.net. 63 | 64 | For more information on the PHP Group and the PHP project, 65 | please see . 66 | 67 | PHP includes the Zend Engine, freely available at 68 | . 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HandlerSocket plugin for MySQL Improved Extension # 2 | 3 | The handlersocketi extension allows you to access the functionality 4 | provided by HandlerSocket plugin for MySQL. 5 | 6 | More information about the HandlerSocket plugin for MySQL can be found at 7 | [» http://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL](http://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL) 8 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl config.m4 for extension handlersocketi 2 | 3 | dnl Check PHP version: 4 | AC_MSG_CHECKING(PHP version) 5 | if test ! -z "$phpincludedir"; then 6 | PHP_VERSION=`grep 'PHP_VERSION ' $phpincludedir/main/php_version.h | sed -e 's/.*"\([[0-9\.]]*\)".*/\1/g' 2>/dev/null` 7 | elif test ! -z "$PHP_CONFIG"; then 8 | PHP_VERSION=`$PHP_CONFIG --version 2>/dev/null` 9 | fi 10 | 11 | if test x"$PHP_VERSION" = "x"; then 12 | AC_MSG_WARN([none]) 13 | else 14 | PHP_MAJOR_VERSION=`echo $PHP_VERSION | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/g' 2>/dev/null` 15 | PHP_MINOR_VERSION=`echo $PHP_VERSION | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/g' 2>/dev/null` 16 | PHP_RELEASE_VERSION=`echo $PHP_VERSION | sed -e 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/g' 2>/dev/null` 17 | AC_MSG_RESULT([$PHP_VERSION]) 18 | fi 19 | 20 | if test $PHP_MAJOR_VERSION -lt 5; then 21 | AC_MSG_ERROR([need at least PHP 5 or newer]) 22 | fi 23 | 24 | PHP_ARG_ENABLE(handlersocketi, whether to enable handlersocketi support, 25 | [ --enable-handlersocketi Enable handlersocketi support]) 26 | 27 | if test "$PHP_HANDLERSOCKETI" != "no"; then 28 | 29 | PHP_NEW_EXTENSION(handlersocketi, handlersocketi.c handlersocketi_exception.c handlersocketi_class.c handlersocketi_index.c util/request.c util/response.c, $ext_shared) 30 | 31 | ifdef([PHP_INSTALL_HEADERS], 32 | [ 33 | PHP_INSTALL_HEADERS([ext/handlersocketi/], [php_handlersocketi.h handlersocketi_exception.h handlersocketi_class.h handlersocketi_index.h]) 34 | ], [ 35 | PHP_ADD_MAKEFILE_FRAGMENT 36 | ]) 37 | fi 38 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | ARG_ENABLE("handlersocketi", "enable handlersocketi support", "no"); 2 | 3 | if (PHP_HANDLERSOCKETI != "no") { 4 | handlersocketi_source = 5 | "handlersocketi.c " + 6 | "handlersocketi_exception.c " + 7 | "handlersocketi_class.c " + 8 | "handlersocketi_index.c " + 9 | "util/request.c " + 10 | "util/response.c"; 11 | EXTENSION("handlersocketi", handlersocketi_source); 12 | PHP_INSTALL_HEADERS("ext/handlersocketi/", "php_handlersocketi.h handlersocketi_exception.h handlersocketi_class.h handlersocketi_index.h"); 13 | } 14 | -------------------------------------------------------------------------------- /handlersocketi class: -------------------------------------------------------------------------------- 1 | (string) What host to connect to, defaults to localhost 68 | * port => (int) The port of the database read 69 | * port_wr => (string) What host to connect to, defaults to localhost => (int) The port of the database write, update, delete 70 | * database => (string) The name of the database to user 71 | * table => (string) The table of the database table 72 | * options => (array) set timeout, default 5s 73 | * 74 | * @param array $config 75 | */ 76 | 77 | /** 78 | * Constructor 79 | * 80 | * @param array $config 81 | */ 82 | public function __construct(array $config = array()) 83 | { 84 | $this->_config = $config + array('host' => '127.0.0.1', 'port' => 9998, 'port_wr' => 9999, 'options' => array('timeout' => 5)); 85 | 86 | $this->_port = $this->_config['port']; 87 | $this->_portWr = $this->_config['port_wr']; 88 | 89 | if (isset($this->_config['database'])) { 90 | $this->_db = $this->_config['database']; 91 | } 92 | 93 | if (isset($this->_config['table'])) { 94 | $this->_table = $this->_config['table']; 95 | } 96 | 97 | return $this->connection(); 98 | } 99 | 100 | /** 101 | * Get HandlerSocketi connection 102 | * 103 | * @return HandlerSocketi 104 | */ 105 | public function connection() 106 | { 107 | if (NULL === $this->_connection) { 108 | $this->_connection = new HandlerSocketi($this->_config['host'], $this->_port, $this->_config['options']); 109 | } 110 | if (isset($this->_config['auth'])) { 111 | $this->_connection->auth($this->_config['auth']['user'], $this->_config['auth']['password']); 112 | } 113 | return $this->_connection; 114 | } 115 | 116 | /** 117 | * Get HandlerSocketi write connection 118 | * 119 | * @return HandlerSocketi 120 | */ 121 | public function writeConnection() 122 | { 123 | if (NULL === $this->_writeConnection) { 124 | $this->_writeConnection = new HandlerSocketi($this->_config['host'], $this->_portWr, $this->_config['options']); 125 | } 126 | if (isset($this->_config['auth'])) { 127 | $this->_writeConnection->auth($this->_config['auth']['user'], $this->_config['auth']['password']); 128 | } 129 | 130 | return $this->_writeConnection; 131 | } 132 | 133 | /** 134 | * Select Database 135 | * 136 | * @param string $db 137 | * @return database name 138 | */ 139 | public function db($db = null) 140 | { 141 | if ($db) { 142 | return $this->_db->$db; 143 | } 144 | 145 | return $this->_db; 146 | } 147 | 148 | /** 149 | * Select table 150 | * 151 | * @param string $table 152 | * @return table name 153 | */ 154 | public function talbe($table = NULL) 155 | { 156 | if ($table) { 157 | return $this->_table->$table; 158 | } 159 | 160 | return $this->_table; 161 | } 162 | 163 | /** 164 | * select and return query result array. 165 | * 166 | * Pass the query and options as array objects (this is more convenient than the standard HandlerSocketi API especially when caching) 167 | * 168 | * $query may contain: 169 | * op - string comparison operator, supported '=', '<', '<=', '>', '>=' 170 | * criteria - string | array comparison values 171 | * limit - int limit number 172 | * skip - int skip number 173 | * 174 | * $options may contain: 175 | * dbname - string database name 176 | * table - string select table name 177 | * fields - string | array the fields to retrieve 178 | * index - string index name. 179 | * 180 | * @param array $query 181 | * @param array $options 182 | * @return false|array 183 | * */ 184 | public function select(array $query = array(), array $options = array()) 185 | { 186 | $query += array('op' => '=', 'criteria' => array(), 'limit' => 1, 'skip' => 0,); 187 | $options += array('dbname' => '', 'table' => '', 'fields' => '', 'index' => ''); 188 | 189 | $dbname = $options['dbname'] ? : $this->_db; 190 | $table = $options['table'] ? : $this->_table; 191 | $index = $options['index'] ? : 'PRIMARY'; 192 | $hsi = $this->connection()->open_index($dbname, $table, $options['fields'], ['index' => $index]); 193 | $result = $hsi->find([$query['op'] => $query['criteria']], ['limit' => $query['limit'], 'offset' => $query['skip']]); 194 | if (!$result) { 195 | $this->_errorLog = $hsi->getError(); 196 | } 197 | return $result; 198 | } 199 | 200 | /** 201 | * selectMulti and return query result array. 202 | * 203 | * Pass the query and options as array objects (this is more convenient than the standard HandlerSocketi API especially when caching) 204 | * 205 | * $query may multi select parameter 206 | * 207 | * $options may contain: 208 | * dbname - string database name 209 | * table - string select table name 210 | * fields - string | array the fields to retrieve 211 | * index - string index name. 212 | * 213 | * @param array $querys 214 | * @param array $options 215 | * @return false|array 216 | * */ 217 | public function selectMulti($querys = array(), $options = array()) 218 | { 219 | $options += array('dbname' => '', 'table' => '', 'fields' => '', 'index' => ''); 220 | 221 | $dbname = $options['dbname'] ? : $this->_db; 222 | $table = $options['table'] ? : $this->_table; 223 | $index = $options['index'] ? : 'PRIMARY'; 224 | $hsi = $this->connection()->open_index($dbname, $table, $options['fields'], ['index' => $index]); 225 | 226 | foreach ($querys as $key => $value) { 227 | $query[$key] = ['find', [$value['op'] => $value['criteria']], ['limit' => $value['limit'], 'offset' => $value['skip']]]; 228 | } 229 | $result = $hsi->multi($query); 230 | if (!$result) { 231 | $this->_errorLog = $hsi->getError(); 232 | } 233 | return $result; 234 | } 235 | 236 | /** 237 | * Insert data 238 | * 239 | * $data is insert fields array values 240 | * 241 | * $options may contain: 242 | * dbname - database name 243 | * table - select table name 244 | * 245 | * @param array $data 246 | * @param array $options 247 | * @return false|int 248 | * */ 249 | public function insert($data, $options = array()) 250 | { 251 | $options += array('dbname' => '', 'table' => ''); 252 | $dbname = $options['dbname'] ? : $this->_db; 253 | $table = $options['table'] ? : $this->_table; 254 | $hsi = $this->writeConnection()->open_index($dbname, $table, implode(',', array_keys($data))); 255 | $resutl = $hsi->insert($data); 256 | if (!$resutl) { 257 | $this->_errorLog = $hsi->getError(); 258 | } 259 | return $resutl; 260 | } 261 | 262 | /** 263 | * Update data 264 | * 265 | * $query may contain: 266 | * op - string comparison operator, supported '=', '<', '<=', '>', '>=' 267 | * criteria - string | array comparison values 268 | * limit - int limit number 269 | * skip - int skip number 270 | * 271 | * $options may contain: 272 | * dbname - string database name 273 | * table - string select table name 274 | * index - string index name. 275 | * 276 | * @param array $query 277 | * @param array $data 278 | * @param array $options 279 | * @return false|int 280 | */ 281 | public function update($query, $data, $options = array()) 282 | { 283 | $query += array('op' => '=', 'criteria' => array(), 'limit' => 1, 'skip' => 0); 284 | $options += array('dbname' => '', 'table' => '', 'index' => ''); 285 | 286 | $dbname = $options['dbname'] ? : $this->_db; 287 | $table = $options['table'] ? : $this->_table; 288 | $index = $options['index'] ? : 'PRIMARY'; 289 | 290 | $hsi = $this->writeConnection()->open_index($dbname, $table, implode(',', array_keys($data)), ['index' => $index]); 291 | $result = $hsi->update([$query['op'] => $query['criteria']], array_values($data), ['limit' => $query['limit'], 'offset' => $query['skip']]); 292 | if (!$result) { 293 | $this->_errorLog = $hsi->getError(); 294 | } 295 | return $result; 296 | } 297 | 298 | /** 299 | * delete data 300 | * $query may contain: 301 | * op - string comparison operator, supported '=', '<', '<=', '>', '>=' 302 | * criteria - string | array comparison values 303 | * limit - int limit number 304 | * skip - int skip number 305 | * 306 | * $options may contain: 307 | * dbname - string database name 308 | * table - string select table name 309 | * fields - string | array the fields to retrieve 310 | * index - string index name. 311 | * 312 | * @param array $query 313 | * @param array $options 314 | * @return false|int 315 | */ 316 | public function delete($query, $options = array()) 317 | { 318 | $query += array('op' => '=', 'criteria' => array(), 'limit' => 1, 'skip' => 0,); 319 | $options += array('dbname' => '', 'table' => '', 'fields' => '', 'index' => ''); 320 | 321 | $dbname = $options['dbname'] ? : $this->_db; 322 | $table = $options['table'] ? : $this->_table; 323 | $index = $options['index'] ? : 'PRIMARY'; 324 | 325 | $hsi = $this->writeConnection()->open_index($dbname, $table, $options['fields'], ['index' => $index]); 326 | $result = $hsi->remove([$query['op'] => $query['criteria']], ['limit' => $query['limit'], 'offset' => $query['skip']]); 327 | if (!$result) { 328 | $this->_errorLog = $hsi->getError(); 329 | } 330 | return $result; 331 | } 332 | 333 | /** 334 | * Last error 335 | * 336 | * @return array 337 | */ 338 | public function error($log = NULL) 339 | { 340 | if (NULL == $log) { 341 | return $this->_errorLog; 342 | } 343 | $this->_errorLog = $log; 344 | } 345 | 346 | } 347 | -------------------------------------------------------------------------------- /handlersocketi.c: -------------------------------------------------------------------------------- 1 | 2 | #ifdef HAVE_CONFIG_H 3 | #include "config.h" 4 | #endif 5 | 6 | #include "php.h" 7 | #include "php_ini.h" 8 | #include "ext/standard/info.h" 9 | 10 | #include "php_verdep.h" 11 | #include "php_handlersocketi.h" 12 | #include "handlersocketi_exception.h" 13 | #include "handlersocketi_class.h" 14 | #include "handlersocketi_index.h" 15 | 16 | ZEND_DECLARE_MODULE_GLOBALS(handlersocketi) 17 | 18 | static void 19 | hs_init_globals(zend_handlersocketi_globals *hs_globals) 20 | { 21 | hs_globals->id = 1; 22 | } 23 | 24 | ZEND_MINIT_FUNCTION(handlersocketi) 25 | { 26 | ZEND_INIT_MODULE_GLOBALS(handlersocketi, hs_init_globals, NULL); 27 | /* 28 | REGISTER_INI_ENTRIES(); 29 | */ 30 | 31 | handlersocketi_register_exception(TSRMLS_C); 32 | handlersocketi_register_class(TSRMLS_C); 33 | handlersocketi_register_index(TSRMLS_C); 34 | 35 | /* 36 | REGISTER_LONG_CONSTANT("MSGPACKI_MODE_ORIGIN", PHP_MSGPACKI_MODE_ORIGIN, 37 | CONST_CS | CONST_PERSISTENT); 38 | 39 | REGISTER_STRING_CONSTANT("MSGPACKI_FILTER_REGISTER", 40 | PHP_MSGPACKI_FILTER_REGISTER, 41 | CONST_CS | CONST_PERSISTENT); 42 | */ 43 | 44 | 45 | /* constant 46 | #if ZEND_MODULE_API_NO < 20050922 47 | REGISTER_STRING_CONSTANT( 48 | "HANDLERSOCKETI_PRIMARY", HS_PRIMARY, CONST_CS | CONST_PERSISTENT); 49 | REGISTER_STRING_CONSTANT( 50 | "HANDLERSOCKETI_UPDATE", HS_MODIFY_UPDATE, CONST_CS | CONST_PERSISTENT); 51 | REGISTER_STRING_CONSTANT( 52 | "HANDLERSOCKETI_DELETE", HS_MODIFY_REMOVE, CONST_CS | CONST_PERSISTENT); 53 | #else 54 | zend_declare_class_constant_string( 55 | hs_ce, "PRIMARY", strlen("PRIMARY"), HS_PRIMARY TSRMLS_CC); 56 | zend_declare_class_constant_string( 57 | hs_ce, "UPDATE", strlen("UPDATE"), HS_MODIFY_UPDATE TSRMLS_CC); 58 | zend_declare_class_constant_string( 59 | hs_ce, "DELETE", strlen("DELETE"), HS_MODIFY_REMOVE TSRMLS_CC); 60 | #endif 61 | */ 62 | 63 | return SUCCESS; 64 | } 65 | 66 | ZEND_MSHUTDOWN_FUNCTION(handlersocketi) 67 | { 68 | /* 69 | UNREGISTER_INI_ENTRIES(); 70 | */ 71 | 72 | return SUCCESS; 73 | } 74 | 75 | /* 76 | ZEND_RINIT_FUNCTION(handlersocketi) 77 | { 78 | return SUCCESS; 79 | } 80 | 81 | ZEND_RSHUTDOWN_FUNCTION(handlersocketi) 82 | { 83 | return SUCCESS; 84 | } 85 | */ 86 | 87 | ZEND_MINFO_FUNCTION(handlersocketi) 88 | { 89 | php_info_print_table_start(); 90 | php_info_print_table_header(2, "handlersocketi support", "enabled"); 91 | php_info_print_table_header(2, "extension version", 92 | HANDLERSOCKETI_EXT_VERSION); 93 | php_info_print_table_end(); 94 | 95 | DISPLAY_INI_ENTRIES(); 96 | } 97 | 98 | const zend_function_entry handlersocketi_functions[] = { 99 | ZEND_FE_END 100 | }; 101 | 102 | zend_module_entry handlersocketi_module_entry = { 103 | #if ZEND_MODULE_API_NO >= 20010901 104 | STANDARD_MODULE_HEADER, 105 | #endif 106 | "handlersocketi", 107 | NULL, 108 | ZEND_MINIT(handlersocketi), 109 | ZEND_MSHUTDOWN(handlersocketi), 110 | NULL, /* ZEND_RINIT(handlersocketi), */ 111 | NULL, /* ZEND_RSHUTDOWN(handlersocketi), */ 112 | ZEND_MINFO(handlersocketi), 113 | #if ZEND_MODULE_API_NO >= 20010901 114 | HANDLERSOCKETI_EXT_VERSION, 115 | #endif 116 | STANDARD_MODULE_PROPERTIES 117 | }; 118 | 119 | #ifdef COMPILE_DL_HANDLERSOCKETI 120 | ZEND_GET_MODULE(handlersocketi) 121 | #endif 122 | -------------------------------------------------------------------------------- /handlersocketi_class.c: -------------------------------------------------------------------------------- 1 | 2 | #include "php.h" 3 | #include "php_ini.h" 4 | #include "php_streams.h" 5 | #include "ext/standard/php_smart_str.h" 6 | 7 | #include "php_verdep.h" 8 | #include "php_handlersocketi.h" 9 | #include "handlersocketi_exception.h" 10 | #include "handlersocketi_class.h" 11 | #include "util/common.h" 12 | #include "util/request.h" 13 | #include "util/response.h" 14 | 15 | ZEND_EXTERN_MODULE_GLOBALS(handlersocketi); 16 | 17 | #define HS_STREAM_DEFAULT_TIMEOUT 5 18 | 19 | static zend_class_entry *hs_ce; 20 | static zend_object_handlers hs_object_handlers; 21 | 22 | typedef struct hs_obj { 23 | zend_object std; 24 | php_stream *stream; 25 | long timeout; 26 | zval *server; 27 | zval *auth; 28 | zval *error; 29 | zval *persistent; 30 | zend_bool is_persistent; 31 | } hs_obj_t; 32 | 33 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_method__construct, 0, 0, 2) 34 | ZEND_ARG_INFO(0, host) 35 | ZEND_ARG_INFO(0, port) 36 | ZEND_ARG_INFO(0, options) 37 | ZEND_END_ARG_INFO() 38 | 39 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_method_auth, 0, 0, 1) 40 | ZEND_ARG_INFO(0, key) 41 | ZEND_ARG_INFO(0, type) 42 | ZEND_END_ARG_INFO() 43 | 44 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_method_open_index, 0, 0, 3) 45 | ZEND_ARG_INFO(0, db) 46 | ZEND_ARG_INFO(0, table) 47 | ZEND_ARG_INFO(0, fields) 48 | ZEND_ARG_INFO(0, options) 49 | ZEND_END_ARG_INFO() 50 | 51 | ZEND_METHOD(HandlerSocketi, __construct); 52 | ZEND_METHOD(HandlerSocketi, auth); 53 | ZEND_METHOD(HandlerSocketi, open_index); 54 | 55 | const zend_function_entry hs_methods[] = { 56 | ZEND_ME(HandlerSocketi, __construct, 57 | arginfo_hs_method__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) 58 | ZEND_ME(HandlerSocketi, auth, 59 | arginfo_hs_method_open_index, ZEND_ACC_PUBLIC) 60 | ZEND_ME(HandlerSocketi, open_index, 61 | arginfo_hs_method_open_index, ZEND_ACC_PUBLIC) 62 | ZEND_MALIAS(HandlerSocketi, openIndex, open_index, 63 | arginfo_hs_method_open_index, ZEND_ACC_PUBLIC) 64 | ZEND_FE_END 65 | }; 66 | 67 | static void 68 | hs_object_free_storage(void *object TSRMLS_DC) 69 | { 70 | hs_obj_t *intern = (hs_obj_t *)object; 71 | zend_object_std_dtor(&intern->std TSRMLS_CC); 72 | 73 | if (intern->stream) { 74 | if (!intern->persistent) { 75 | php_stream_close(intern->stream); 76 | } 77 | } 78 | 79 | if (intern->server) { 80 | zval_ptr_dtor(&intern->server); 81 | } 82 | 83 | if (intern->auth) { 84 | zval_ptr_dtor(&intern->auth); 85 | } 86 | 87 | if (intern->error) { 88 | zval_ptr_dtor(&intern->error); 89 | } 90 | 91 | if (intern->persistent) { 92 | zval_ptr_dtor(&intern->persistent); 93 | } 94 | 95 | efree(object); 96 | } 97 | 98 | #define HS_EXCEPTION(...) \ 99 | zend_throw_exception_ex(handlersocketi_get_ce_exception(), \ 100 | 0 TSRMLS_CC, \ 101 | "HandlerSocketi::" __VA_ARGS__) 102 | 103 | #define HS_CHECK_OBJECT(object, classname) \ 104 | if (!(object)) { \ 105 | HS_EXCEPTION("The " #classname " object has not been " \ 106 | "correctly initialized by its constructor"); \ 107 | RETURN_FALSE; \ 108 | } 109 | 110 | static inline zend_object_value 111 | hs_object_new_ex(zend_class_entry *ce, hs_obj_t **ptr TSRMLS_DC) 112 | { 113 | hs_obj_t *intern; 114 | zend_object_value retval; 115 | #if ZEND_MODULE_API_NO < 20100525 116 | zval *tmp; 117 | #endif 118 | 119 | intern = emalloc(sizeof(hs_obj_t)); 120 | memset(intern, 0, sizeof(hs_obj_t)); 121 | if (ptr) { 122 | *ptr = intern; 123 | } 124 | 125 | zend_object_std_init(&intern->std, ce TSRMLS_CC); 126 | 127 | #if ZEND_MODULE_API_NO >= 20100525 128 | object_properties_init(&intern->std, ce); 129 | #else 130 | zend_hash_copy(intern->std.properties, &ce->default_properties, 131 | (copy_ctor_func_t)zval_add_ref, (void *)&tmp, sizeof(zval *)); 132 | #endif 133 | 134 | retval.handle = zend_objects_store_put( 135 | intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, 136 | (zend_objects_free_object_storage_t)hs_object_free_storage, 137 | NULL TSRMLS_CC); 138 | retval.handlers = &hs_object_handlers; 139 | 140 | intern->timeout = 0; 141 | intern->stream = NULL; 142 | intern->server = NULL; 143 | intern->auth = NULL; 144 | intern->error = NULL; 145 | intern->persistent = NULL; 146 | 147 | return retval; 148 | } 149 | 150 | static inline int 151 | hs_object_connection(hs_obj_t *obj) 152 | { 153 | char *hashkey = NULL; 154 | char *errstr = NULL; 155 | int err; 156 | struct timeval tv; 157 | TSRMLS_FETCH(); 158 | 159 | if (obj->timeout > 0) { 160 | tv.tv_sec = obj->timeout; 161 | tv.tv_usec = 0; 162 | } 163 | 164 | if (obj->persistent) { 165 | hashkey = Z_STRVAL_P(obj->persistent); 166 | } 167 | 168 | obj->stream = php_stream_xport_create(Z_STRVAL_P(obj->server), 169 | Z_STRLEN_P(obj->server), 170 | ENFORCE_SAFE_MODE|REPORT_ERRORS, 171 | STREAM_XPORT_CLIENT| 172 | STREAM_XPORT_CONNECT, 173 | hashkey, &tv, NULL, &errstr, &err); 174 | 175 | if (!obj->stream) { 176 | if (errstr) { 177 | efree(errstr); 178 | } 179 | return FAILURE; 180 | } 181 | 182 | if (errstr) { 183 | efree(errstr); 184 | } 185 | 186 | /* non-blocking */ 187 | if (php_stream_set_option(obj->stream, PHP_STREAM_OPTION_BLOCKING, 188 | 0, NULL) == -1) { 189 | zend_error(E_WARNING, 190 | "HandlerSocketi: Un set non-blocking mode on a stream"); 191 | } 192 | 193 | return SUCCESS; 194 | } 195 | 196 | static inline zend_object_value 197 | hs_object_new(zend_class_entry *ce TSRMLS_DC) 198 | { 199 | return hs_object_new_ex(ce, NULL TSRMLS_CC); 200 | } 201 | 202 | static inline zend_object_value 203 | hs_object_clone(zval *this_ptr TSRMLS_DC) 204 | { 205 | hs_obj_t *new_obj = NULL; 206 | hs_obj_t *old_obj = 207 | (hs_obj_t *)zend_object_store_get_object(this_ptr TSRMLS_CC); 208 | zend_object_value new_ov = hs_object_new_ex(old_obj->std.ce, 209 | &new_obj TSRMLS_CC); 210 | 211 | zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, 212 | Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC); 213 | 214 | new_obj->timeout = old_obj->timeout; 215 | 216 | MAKE_STD_ZVAL(new_obj->server); 217 | *new_obj->server = *old_obj->server; 218 | zval_copy_ctor(new_obj->server); 219 | 220 | if (old_obj->auth) { 221 | MAKE_STD_ZVAL(new_obj->auth); 222 | *new_obj->auth = *old_obj->auth; 223 | zval_copy_ctor(new_obj->auth); 224 | } else { 225 | new_obj->auth = NULL; 226 | } 227 | 228 | new_obj->error = NULL; 229 | 230 | if (old_obj->persistent) { 231 | MAKE_STD_ZVAL(new_obj->persistent); 232 | *new_obj->persistent = *old_obj->persistent; 233 | zval_copy_ctor(new_obj->persistent); 234 | } else { 235 | new_obj->persistent = NULL; 236 | } 237 | 238 | hs_object_connection(new_obj); 239 | 240 | return new_ov; 241 | } 242 | 243 | PHP_HANDLERSOCKETI_API int 244 | handlersocketi_register_class(TSRMLS_D) 245 | { 246 | zend_class_entry ce; 247 | 248 | INIT_CLASS_ENTRY(ce, "HandlerSocketi", hs_methods); 249 | 250 | ce.create_object = hs_object_new; 251 | 252 | hs_ce = zend_register_internal_class(&ce TSRMLS_CC); 253 | if (hs_ce == NULL) { 254 | return FAILURE; 255 | } 256 | 257 | memcpy(&hs_object_handlers, zend_get_std_object_handlers(), 258 | sizeof(zend_object_handlers)); 259 | 260 | hs_object_handlers.clone_obj = hs_object_clone; 261 | 262 | return SUCCESS; 263 | } 264 | 265 | PHP_HANDLERSOCKETI_API zend_class_entry 266 | *handlersocketi_get_ce(void) 267 | { 268 | return hs_ce; 269 | } 270 | 271 | PHP_HANDLERSOCKETI_API php_stream 272 | *handlersocketi_object_store_get_stream(zval *link) 273 | { 274 | hs_obj_t *hs; 275 | TSRMLS_FETCH(); 276 | 277 | hs = (hs_obj_t *)zend_object_store_get_object(link TSRMLS_CC); 278 | if (hs) { 279 | return hs->stream; 280 | } else { 281 | return NULL; 282 | } 283 | } 284 | 285 | PHP_HANDLERSOCKETI_API long 286 | handlersocketi_object_store_get_timeout(zval *link) 287 | { 288 | hs_obj_t *hs; 289 | TSRMLS_FETCH(); 290 | 291 | hs = (hs_obj_t *)zend_object_store_get_object(link TSRMLS_CC); 292 | if (hs) { 293 | return hs->timeout; 294 | } else { 295 | return 0; 296 | } 297 | } 298 | 299 | ZEND_METHOD(HandlerSocketi, __construct) 300 | { 301 | char *server, *host = NULL; 302 | int server_len, host_len = 0; 303 | long port = -1; 304 | zval *options = NULL; 305 | hs_obj_t *hs; 306 | 307 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|z", 308 | &host, &host_len, &port, &options) == FAILURE) { 309 | zval *object = getThis(); 310 | ZVAL_NULL(object); 311 | return; 312 | } 313 | 314 | if (!host || host_len <= 0) { 315 | HS_EXCEPTION("__construct(): no host name"); 316 | zval *object = getThis(); 317 | ZVAL_NULL(object); 318 | return; 319 | } 320 | 321 | if (port > 0) { 322 | server_len = spprintf(&server, 0, "%s:%ld", host, port); 323 | } else { 324 | server_len = spprintf(&server, 0, "%s", host); 325 | } 326 | 327 | hs = (hs_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 328 | HS_CHECK_OBJECT(hs, HandlerSocketi); 329 | 330 | MAKE_STD_ZVAL(hs->server); 331 | ZVAL_STRINGL(hs->server, server, server_len, 1); 332 | efree(server); 333 | 334 | hs->timeout = HS_STREAM_DEFAULT_TIMEOUT; 335 | 336 | if (options && Z_TYPE_P(options) == IS_ARRAY) { 337 | zval **tmp; 338 | if (zend_hash_find(Z_ARRVAL_P(options), "timeout", 339 | sizeof("timeout"), (void **)&tmp) == SUCCESS) { 340 | convert_to_long_ex(tmp); 341 | hs->timeout = Z_LVAL_PP(tmp); 342 | } 343 | 344 | if (zend_hash_find(Z_ARRVAL_P(options), "persistent", 345 | sizeof("persistent"), (void **)&tmp) == SUCCESS) { 346 | convert_to_string_ex(tmp); 347 | MAKE_STD_ZVAL(hs->persistent); 348 | ZVAL_STRINGL(hs->persistent, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1); 349 | } 350 | } 351 | 352 | if (hs_object_connection(hs) != SUCCESS) { 353 | HS_EXCEPTION("__construct(): unable to connect %s", 354 | Z_STRVAL_P(hs->server)); 355 | RETURN_FALSE; 356 | } 357 | } 358 | 359 | ZEND_METHOD(HandlerSocketi, auth) 360 | { 361 | char *key, *type = NULL; 362 | long key_len, type_len = 0; 363 | hs_obj_t *hs; 364 | smart_str request = {0}; 365 | 366 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", 367 | &key, &key_len, &type, &type_len) == FAILURE) { 368 | RETURN_FALSE; 369 | } 370 | 371 | if (key_len <= 0) { 372 | RETURN_FALSE; 373 | } 374 | 375 | /* handerlsocket: object */ 376 | hs = (hs_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 377 | HS_CHECK_OBJECT(hs, HandlerSocketi); 378 | 379 | MAKE_STD_ZVAL(hs->auth); 380 | ZVAL_STRINGL(hs->auth, key, key_len, 1); 381 | 382 | /* auth */ 383 | hs_request_string(&request, HS_PROTOCOL_AUTH, 1); 384 | hs_request_delim(&request); 385 | hs_request_string(&request, "1", 1); 386 | hs_request_delim(&request); 387 | hs_request_string(&request, Z_STRVAL_P(hs->auth), Z_STRLEN_P(hs->auth)); 388 | hs_request_next(&request); 389 | 390 | /* request: send */ 391 | if (hs_request_send(hs->stream, &request TSRMLS_CC) < 0) { 392 | ZVAL_BOOL(return_value, 0); 393 | } else { 394 | zval *retval; 395 | MAKE_STD_ZVAL(retval); 396 | 397 | /* response */ 398 | hs_response_value(hs->stream, hs->timeout, retval, NULL, 0 TSRMLS_CC); 399 | if (Z_TYPE_P(retval) == IS_BOOL && Z_LVAL_P(retval) == 1) { 400 | ZVAL_BOOL(return_value, 1); 401 | } else { 402 | ZVAL_BOOL(return_value, 0); 403 | } 404 | 405 | zval_ptr_dtor(&retval); 406 | } 407 | 408 | smart_str_free(&request); 409 | } 410 | 411 | ZEND_METHOD(HandlerSocketi, open_index) 412 | { 413 | char *db, *table; 414 | int db_len, table_len; 415 | zval *fields, *options = NULL; 416 | 417 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssz|z", 418 | &db, &db_len, &table, &table_len, 419 | &fields, &options) == FAILURE) { 420 | return; 421 | } 422 | 423 | handlersocketi_create_index(return_value, getThis(), db, db_len, 424 | table, table_len, fields, options TSRMLS_CC); 425 | } 426 | -------------------------------------------------------------------------------- /handlersocketi_class.h: -------------------------------------------------------------------------------- 1 | #ifndef HANDLERSOCKETI_CLASS_H 2 | #define HANDLERSOCKETI_CLASS_H 3 | 4 | PHP_HANDLERSOCKETI_API int handlersocketi_register_class(TSRMLS_D); 5 | PHP_HANDLERSOCKETI_API zend_class_entry *handlersocketi_get_ce(void); 6 | 7 | PHP_HANDLERSOCKETI_API php_stream *handlersocketi_object_store_get_stream(zval *link); 8 | PHP_HANDLERSOCKETI_API long handlersocketi_object_store_get_timeout(zval *link); 9 | 10 | #endif /* HANDLERSOCKETI_CLASS_H */ 11 | -------------------------------------------------------------------------------- /handlersocketi_exception.c: -------------------------------------------------------------------------------- 1 | 2 | #include "php.h" 3 | #include "php_ini.h" 4 | #include "Zend/zend_exceptions.h" 5 | 6 | #include "php_handlersocketi.h" 7 | #include "handlersocketi_exception.h" 8 | 9 | ZEND_EXTERN_MODULE_GLOBALS(handlersocketi); 10 | 11 | static zend_class_entry *hs_ce_exception; 12 | 13 | PHP_HANDLERSOCKETI_API int 14 | handlersocketi_register_exception(TSRMLS_D) 15 | { 16 | zend_class_entry ce; 17 | 18 | INIT_CLASS_ENTRY(ce, "HandlerSocketi_Exception", NULL); 19 | 20 | hs_ce_exception = zend_register_internal_class_ex( 21 | &ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC); 22 | if (hs_ce_exception == NULL) { 23 | return FAILURE; 24 | } 25 | 26 | return SUCCESS; 27 | } 28 | 29 | PHP_HANDLERSOCKETI_API zend_class_entry 30 | *handlersocketi_get_ce_exception(void) { 31 | return hs_ce_exception; 32 | } 33 | -------------------------------------------------------------------------------- /handlersocketi_exception.h: -------------------------------------------------------------------------------- 1 | #ifndef HANDLERSOCKETI_EXCEPTION_H 2 | #define HANDLERSOCKETI_EXCEPTION_H 3 | 4 | PHP_HANDLERSOCKETI_API int handlersocketi_register_exception(TSRMLS_D); 5 | PHP_HANDLERSOCKETI_API zend_class_entry *handlersocketi_get_ce_exception(void); 6 | 7 | #endif /* HANDLERSOCKETI_EXCEPTION_H */ 8 | -------------------------------------------------------------------------------- /handlersocketi_index.c: -------------------------------------------------------------------------------- 1 | 2 | #include "php.h" 3 | #include "php_ini.h" 4 | #include "ext/standard/php_smart_str.h" 5 | #include "ext/standard/php_string.h" 6 | 7 | #include "php_verdep.h" 8 | #include "php_handlersocketi.h" 9 | #include "handlersocketi_exception.h" 10 | #include "handlersocketi_class.h" 11 | #include "handlersocketi_index.h" 12 | #include "util/common.h" 13 | #include "util/request.h" 14 | #include "util/response.h" 15 | 16 | ZEND_EXTERN_MODULE_GLOBALS(handlersocketi); 17 | 18 | #define HS_DEFAULT_LIMIT 1 19 | #define HS_DEFAULT_OFFSET 0 20 | 21 | static zend_class_entry *hs_ce_index; 22 | static zend_object_handlers hs_index_object_handlers; 23 | 24 | typedef struct hs_index_obj { 25 | zend_object std; 26 | long id; 27 | zval *name; 28 | zval *db; 29 | zval *table; 30 | zval *field; 31 | long field_num; 32 | zval *filter; 33 | zval *link; 34 | zval *error; 35 | } hs_index_obj_t; 36 | 37 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method__construct, 0, 0, 4) 38 | ZEND_ARG_INFO(0, hs) 39 | ZEND_ARG_INFO(0, db) 40 | ZEND_ARG_INFO(0, table) 41 | ZEND_ARG_INFO(0, fields) 42 | ZEND_ARG_INFO(0, options) 43 | ZEND_END_ARG_INFO() 44 | 45 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_find, 0, 0, 1) 46 | ZEND_ARG_INFO(0, query) 47 | ZEND_ARG_INFO(0, options) 48 | ZEND_END_ARG_INFO() 49 | 50 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_insert, 0, 0, 0) 51 | ZEND_END_ARG_INFO() 52 | 53 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_update, 0, 0, 2) 54 | ZEND_ARG_INFO(0, query) 55 | ZEND_ARG_INFO(0, update) 56 | ZEND_ARG_INFO(0, options) 57 | ZEND_END_ARG_INFO() 58 | 59 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_remove, 0, 0, 1) 60 | ZEND_ARG_INFO(0, query) 61 | ZEND_ARG_INFO(0, options) 62 | ZEND_END_ARG_INFO() 63 | 64 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_multi, 0, 0, 1) 65 | ZEND_ARG_INFO(0, args) 66 | ZEND_END_ARG_INFO() 67 | 68 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_get_error, 0, 0, 0) 69 | ZEND_END_ARG_INFO() 70 | 71 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_get_id, 0, 0, 0) 72 | ZEND_END_ARG_INFO() 73 | 74 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_get_name, 0, 0, 0) 75 | ZEND_END_ARG_INFO() 76 | 77 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_get_db, 0, 0, 0) 78 | ZEND_END_ARG_INFO() 79 | 80 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_get_table, 0, 0, 0) 81 | ZEND_END_ARG_INFO() 82 | 83 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_get_field, 0, 0, 0) 84 | ZEND_END_ARG_INFO() 85 | 86 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_get_filter, 0, 0, 0) 87 | ZEND_END_ARG_INFO() 88 | 89 | ZEND_BEGIN_ARG_INFO_EX(arginfo_hs_index_method_get_operator, 0, 0, 0) 90 | ZEND_END_ARG_INFO() 91 | 92 | ZEND_METHOD(HandlerSocketi_Index, __construct); 93 | ZEND_METHOD(HandlerSocketi_Index, find); 94 | ZEND_METHOD(HandlerSocketi_Index, insert); 95 | ZEND_METHOD(HandlerSocketi_Index, update); 96 | ZEND_METHOD(HandlerSocketi_Index, remove); 97 | ZEND_METHOD(HandlerSocketi_Index, multi); 98 | ZEND_METHOD(HandlerSocketi_Index, get_error); 99 | ZEND_METHOD(HandlerSocketi_Index, get_id); 100 | ZEND_METHOD(HandlerSocketi_Index, get_name); 101 | ZEND_METHOD(HandlerSocketi_Index, get_db); 102 | ZEND_METHOD(HandlerSocketi_Index, get_table); 103 | ZEND_METHOD(HandlerSocketi_Index, get_field); 104 | ZEND_METHOD(HandlerSocketi_Index, get_filter); 105 | ZEND_METHOD(HandlerSocketi_Index, get_operator); 106 | 107 | const zend_function_entry hs_index_methods[] = { 108 | ZEND_ME(HandlerSocketi_Index, __construct, 109 | arginfo_hs_index_method__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) 110 | ZEND_ME(HandlerSocketi_Index, find, 111 | arginfo_hs_index_method_find, ZEND_ACC_PUBLIC) 112 | ZEND_ME(HandlerSocketi_Index, insert, 113 | arginfo_hs_index_method_insert, ZEND_ACC_PUBLIC) 114 | ZEND_ME(HandlerSocketi_Index, update, 115 | arginfo_hs_index_method_update, ZEND_ACC_PUBLIC) 116 | ZEND_ME(HandlerSocketi_Index, remove, 117 | arginfo_hs_index_method_remove, ZEND_ACC_PUBLIC) 118 | ZEND_ME(HandlerSocketi_Index, multi, 119 | arginfo_hs_index_method_multi, ZEND_ACC_PUBLIC) 120 | ZEND_ME(HandlerSocketi_Index, get_error, 121 | arginfo_hs_index_method_get_error, ZEND_ACC_PUBLIC) 122 | ZEND_ME(HandlerSocketi_Index, get_id, 123 | arginfo_hs_index_method_get_id, ZEND_ACC_PUBLIC) 124 | ZEND_ME(HandlerSocketi_Index, get_name, 125 | arginfo_hs_index_method_get_name, ZEND_ACC_PUBLIC) 126 | ZEND_ME(HandlerSocketi_Index, get_db, 127 | arginfo_hs_index_method_get_db, ZEND_ACC_PUBLIC) 128 | ZEND_ME(HandlerSocketi_Index, get_table, 129 | arginfo_hs_index_method_get_table, ZEND_ACC_PUBLIC) 130 | ZEND_ME(HandlerSocketi_Index, get_field, 131 | arginfo_hs_index_method_get_field, ZEND_ACC_PUBLIC) 132 | ZEND_ME(HandlerSocketi_Index, get_filter, 133 | arginfo_hs_index_method_get_filter, ZEND_ACC_PUBLIC) 134 | ZEND_ME(HandlerSocketi_Index, get_operator, 135 | arginfo_hs_index_method_get_operator, ZEND_ACC_PUBLIC) 136 | ZEND_MALIAS(HandlerSocketi_Index, getError, get_error, 137 | arginfo_hs_index_method_get_error, ZEND_ACC_PUBLIC) 138 | ZEND_MALIAS(HandlerSocketi_Index, getId, get_id, 139 | arginfo_hs_index_method_get_id, ZEND_ACC_PUBLIC) 140 | ZEND_MALIAS(HandlerSocketi_Index, getName, get_name, 141 | arginfo_hs_index_method_get_name, ZEND_ACC_PUBLIC) 142 | ZEND_MALIAS(HandlerSocketi_Index, getDb, get_db, 143 | arginfo_hs_index_method_get_db, ZEND_ACC_PUBLIC) 144 | ZEND_MALIAS(HandlerSocketi_Index, getTable, get_table, 145 | arginfo_hs_index_method_get_table, ZEND_ACC_PUBLIC) 146 | ZEND_MALIAS(HandlerSocketi_Index, getField, get_field, 147 | arginfo_hs_index_method_get_field, ZEND_ACC_PUBLIC) 148 | ZEND_MALIAS(HandlerSocketi_Index, getFilter, get_filter, 149 | arginfo_hs_index_method_get_filter, ZEND_ACC_PUBLIC) 150 | ZEND_MALIAS(HandlerSocketi_Index, getOperator, get_operator, 151 | arginfo_hs_index_method_get_operator, ZEND_ACC_PUBLIC) 152 | ZEND_FE_END 153 | }; 154 | 155 | #define HS_EXCEPTION(...) \ 156 | zend_throw_exception_ex(handlersocketi_get_ce_exception(), \ 157 | 0 TSRMLS_CC, \ 158 | "HandlerSocketi_Index::" __VA_ARGS__) 159 | 160 | #define HS_CHECK_OBJECT(object, classname) \ 161 | if (!(object)) { \ 162 | HS_EXCEPTION("The " #classname " object has not been " \ 163 | "correctly initialized by its constructor"); \ 164 | RETURN_FALSE; \ 165 | } 166 | 167 | #define HS_ERROR_RESET(error) \ 168 | if (error) { \ 169 | zval_ptr_dtor(&error); \ 170 | } \ 171 | MAKE_STD_ZVAL(error); \ 172 | ZVAL_NULL(error) 173 | 174 | static inline void 175 | hs_index_object_free_storage(void *object TSRMLS_DC) 176 | { 177 | hs_index_obj_t *intern = (hs_index_obj_t *)object; 178 | zend_object_std_dtor(&intern->std TSRMLS_CC); 179 | 180 | if (intern->link) { 181 | zval_ptr_dtor(&intern->link); 182 | } 183 | 184 | if (intern->name) { 185 | zval_ptr_dtor(&intern->name); 186 | } 187 | 188 | if (intern->db) { 189 | zval_ptr_dtor(&intern->db); 190 | } 191 | 192 | if (intern->table) { 193 | zval_ptr_dtor(&intern->table); 194 | } 195 | 196 | if (intern->field) { 197 | zval_ptr_dtor(&intern->field); 198 | } 199 | 200 | if (intern->filter) { 201 | zval_ptr_dtor(&intern->filter); 202 | } 203 | 204 | if (intern->error) { 205 | zval_ptr_dtor(&intern->error); 206 | } 207 | 208 | efree(object); 209 | } 210 | 211 | static inline zend_object_value 212 | hs_index_object_new_ex(zend_class_entry *ce, hs_index_obj_t **ptr TSRMLS_DC) 213 | { 214 | hs_index_obj_t *intern; 215 | zend_object_value retval; 216 | #if ZEND_MODULE_API_NO < 20100525 217 | zval *tmp; 218 | #endif 219 | 220 | intern = emalloc(sizeof(hs_index_obj_t)); 221 | memset(intern, 0, sizeof(hs_index_obj_t)); 222 | if (ptr) { 223 | *ptr = intern; 224 | } 225 | 226 | zend_object_std_init(&intern->std, ce TSRMLS_CC); 227 | 228 | #if ZEND_MODULE_API_NO >= 20100525 229 | object_properties_init(&intern->std, ce); 230 | #else 231 | zend_hash_copy(intern->std.properties, &ce->default_properties, 232 | (copy_ctor_func_t)zval_add_ref, (void *)&tmp, sizeof(zval *)); 233 | #endif 234 | 235 | retval.handle = zend_objects_store_put( 236 | intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, 237 | (zend_objects_free_object_storage_t)hs_index_object_free_storage, 238 | NULL TSRMLS_CC); 239 | retval.handlers = &hs_index_object_handlers; 240 | 241 | intern->id = 0; 242 | intern->name = NULL; 243 | intern->db = NULL; 244 | intern->table = NULL; 245 | intern->field = NULL; 246 | intern->field_num = 0; 247 | intern->filter = NULL; 248 | intern->link = NULL; 249 | intern->error = NULL; 250 | 251 | return retval; 252 | } 253 | 254 | 255 | static inline zend_object_value 256 | hs_index_object_new(zend_class_entry *ce TSRMLS_DC) 257 | { 258 | return hs_index_object_new_ex(ce, NULL TSRMLS_CC); 259 | } 260 | 261 | static inline zend_object_value 262 | hs_index_object_clone(zval *this_ptr TSRMLS_DC) 263 | { 264 | hs_index_obj_t *new_obj = NULL; 265 | hs_index_obj_t *old_obj = 266 | (hs_index_obj_t *)zend_object_store_get_object(this_ptr TSRMLS_CC); 267 | zend_object_value new_ov = hs_index_object_new_ex(old_obj->std.ce, 268 | &new_obj TSRMLS_CC); 269 | 270 | zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, 271 | Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC); 272 | 273 | new_obj->id = old_obj->id; 274 | 275 | MAKE_STD_ZVAL(new_obj->name); 276 | *new_obj->name = *old_obj->name; 277 | zval_copy_ctor(new_obj->name); 278 | 279 | MAKE_STD_ZVAL(new_obj->db); 280 | *new_obj->db = *old_obj->db; 281 | zval_copy_ctor(new_obj->db); 282 | 283 | MAKE_STD_ZVAL(new_obj->table); 284 | *new_obj->table = *old_obj->table; 285 | zval_copy_ctor(new_obj->table); 286 | 287 | MAKE_STD_ZVAL(new_obj->field); 288 | *new_obj->field = *old_obj->field; 289 | zval_copy_ctor(new_obj->field); 290 | 291 | new_obj->field_num = old_obj->field_num; 292 | 293 | if (old_obj->filter) { 294 | MAKE_STD_ZVAL(new_obj->filter); 295 | *new_obj->filter = *old_obj->filter; 296 | zval_copy_ctor(new_obj->filter); 297 | } else { 298 | new_obj->filter = NULL; 299 | } 300 | 301 | MAKE_STD_ZVAL(new_obj->link); 302 | *new_obj->link = *old_obj->link; 303 | zval_copy_ctor(new_obj->link); 304 | 305 | new_obj->error = NULL; 306 | 307 | return new_ov; 308 | } 309 | 310 | static inline zval 311 | *hs_zval_to_comma_string(zval *val) 312 | { 313 | smart_str comma = {0}; 314 | zval *retval; 315 | TSRMLS_FETCH(); 316 | 317 | if (Z_TYPE_P(val) == IS_ARRAY) { 318 | zval **tmp; 319 | HashTable *ht; 320 | HashPosition pos; 321 | 322 | ht = HASH_OF(val); 323 | if (zend_hash_num_elements(ht) >= 0) { 324 | zend_hash_internal_pointer_reset_ex(ht, &pos); 325 | while (zend_hash_get_current_data_ex(ht, (void **)&tmp, 326 | &pos) == SUCCESS) { 327 | switch ((*tmp)->type) { 328 | case IS_STRING: 329 | if (Z_STRLEN_PP(tmp) > 0) { 330 | smart_str_appendl(&comma, Z_STRVAL_PP(tmp), 331 | Z_STRLEN_PP(tmp)); 332 | smart_str_appendl(&comma, ",", strlen(",")); 333 | } 334 | break; 335 | default: 336 | convert_to_string(*tmp); 337 | if (Z_STRLEN_PP(tmp) > 0) { 338 | smart_str_appendl(&comma, Z_STRVAL_PP(tmp), 339 | Z_STRLEN_PP(tmp)); 340 | smart_str_appendl(&comma, ",", strlen(",")); 341 | } 342 | break; 343 | } 344 | zend_hash_move_forward_ex(ht, &pos); 345 | } 346 | if (comma.len > 0) { 347 | comma.len--; 348 | comma.a--; 349 | } 350 | } 351 | } else if (Z_TYPE_P(val) == IS_STRING) { 352 | if (Z_STRLEN_P(val) > 0) { 353 | smart_str_appendl(&comma, Z_STRVAL_P(val), Z_STRLEN_P(val)); 354 | } 355 | } else { 356 | convert_to_string(val); 357 | if (Z_STRLEN_P(val) > 0) { 358 | smart_str_appendl(&comma, Z_STRVAL_P(val), Z_STRLEN_P(val)); 359 | } 360 | } 361 | 362 | smart_str_0(&comma); 363 | 364 | MAKE_STD_ZVAL(retval); 365 | ZVAL_STRINGL(retval, comma.c, comma.len, 1); 366 | smart_str_free(&comma); 367 | 368 | return retval; 369 | } 370 | 371 | static inline zval 372 | *hs_zval_to_comma_array(zval *val) 373 | { 374 | zval *retval; 375 | 376 | MAKE_STD_ZVAL(retval); 377 | 378 | if (Z_TYPE_P(val) == IS_ARRAY) { 379 | long n, i; 380 | /* 381 | array_init(retval); 382 | n = zend_hash_num_elements(HASH_OF(*tmp)); 383 | for (i = 0; i < n; i++) { 384 | zval **val; 385 | if (zend_hash_index_find(HASH_OF(*tmp), i, 386 | (void **)&val) == SUCCESS) { 387 | convert_to_string(*val); 388 | add_next_index_stringl(retval, Z_STRVAL_PP(val), 389 | Z_STRLEN_PP(val), 1); 390 | } 391 | } 392 | */ 393 | *retval = *val; 394 | zval_copy_ctor(retval); 395 | } else if (Z_TYPE_P(val) == IS_STRING) { 396 | zval delim; 397 | ZVAL_STRINGL(&delim, ",", strlen(","), 0); 398 | 399 | array_init(retval); 400 | php_explode(&delim, val, retval, LONG_MAX); 401 | } else { 402 | ZVAL_NULL(retval); 403 | } 404 | 405 | return retval; 406 | } 407 | 408 | static inline int 409 | hs_get_options_long(HashTable *options, char *item, long def TSRMLS_DC) 410 | { 411 | zval **tmp; 412 | 413 | if (zend_hash_find(options, item, strlen(item)+1, 414 | (void**)&tmp) == SUCCESS && 415 | Z_TYPE_PP(tmp) == IS_LONG) { 416 | return Z_LVAL_PP(tmp); 417 | } 418 | return def; 419 | } 420 | 421 | static inline int 422 | hs_is_options_safe(HashTable *options TSRMLS_DC) 423 | { 424 | zval **tmp; 425 | 426 | if (zend_hash_find(options, "safe", sizeof("safe"), 427 | (void**)&tmp) == SUCCESS) { 428 | if (Z_TYPE_PP(tmp) == IS_STRING || 429 | ((Z_TYPE_PP(tmp) == IS_LONG || Z_TYPE_PP(tmp) == IS_BOOL) && 430 | Z_LVAL_PP(tmp) >= 1)) { 431 | return 1; 432 | } 433 | } 434 | return 0; 435 | } 436 | 437 | static inline int 438 | hs_zval_to_operate_criteria(zval *query, zval *operate, 439 | zval **criteria, char *defaults TSRMLS_DC) 440 | { 441 | if (query == NULL) { 442 | return FAILURE; 443 | } 444 | 445 | if (Z_TYPE_P(query) == IS_ARRAY) { 446 | char *key; 447 | uint key_len; 448 | ulong index; 449 | HashTable *ht; 450 | zval **tmp; 451 | 452 | ht = HASH_OF(query); 453 | if (zend_hash_get_current_data_ex(ht, (void **)&tmp, NULL) != SUCCESS) { 454 | return FAILURE; 455 | } 456 | 457 | if (zend_hash_get_current_key_ex(ht, &key, &key_len, &index, 458 | 0, NULL) == HASH_KEY_IS_STRING) { 459 | ZVAL_STRINGL(operate, key, key_len-1, 1); 460 | *criteria = *tmp; 461 | } else { 462 | ZVAL_STRINGL(operate, defaults, strlen(defaults), 1); 463 | *criteria = query; 464 | } 465 | } else { 466 | ZVAL_STRINGL(operate, defaults, strlen(defaults), 1); 467 | *criteria = query; 468 | } 469 | 470 | return SUCCESS; 471 | } 472 | 473 | static inline zval 474 | *hs_zval_search_key(zval *value, zval *array TSRMLS_DC) 475 | { 476 | zval *return_value, **entry, res; 477 | HashPosition pos; 478 | HashTable *ht; 479 | ulong index; 480 | uint key_len; 481 | char *key; 482 | int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function; 483 | 484 | MAKE_STD_ZVAL(return_value); 485 | 486 | ht = HASH_OF(array); 487 | zend_hash_internal_pointer_reset_ex(ht, &pos); 488 | while (zend_hash_get_current_data_ex(ht, (void **)&entry, 489 | &pos) == SUCCESS) { 490 | is_equal_func(&res, value, *entry TSRMLS_CC); 491 | if (Z_LVAL(res)) { 492 | switch (zend_hash_get_current_key_ex(ht, &key, &key_len, 493 | &index, 0, &pos)) { 494 | case HASH_KEY_IS_STRING: 495 | ZVAL_STRINGL(return_value, key, key_len - 1, 1); 496 | break; 497 | case HASH_KEY_IS_LONG: 498 | ZVAL_LONG(return_value, index); 499 | break; 500 | default: 501 | ZVAL_NULL(return_value); 502 | break; 503 | } 504 | return return_value; 505 | } 506 | zend_hash_move_forward_ex(ht, &pos); 507 | } 508 | ZVAL_NULL(return_value); 509 | return return_value; 510 | } 511 | 512 | static inline void 513 | hs_zval_to_filter(zval **return_value, zval *filter, 514 | zval *value, char *type TSRMLS_DC) 515 | { 516 | HashTable *ht; 517 | HashPosition pos; 518 | zval **tmp, **ftmp, **vtmp, *index, *item; 519 | long n; 520 | 521 | if (value == NULL || Z_TYPE_P(value) != IS_ARRAY) { 522 | return; 523 | } 524 | 525 | ht = HASH_OF(value); 526 | n = zend_hash_num_elements(ht); 527 | 528 | if (n <= 0 || zend_hash_index_find(ht, 0, (void **)&ftmp) != SUCCESS) { 529 | return; 530 | } 531 | 532 | zend_hash_internal_pointer_reset_ex(ht, &pos); 533 | 534 | if (Z_TYPE_PP(ftmp) == IS_ARRAY) { 535 | do { 536 | if (zend_hash_move_forward_ex(ht, &pos) < 0) { 537 | break; 538 | } 539 | hs_zval_to_filter(return_value, filter, *ftmp, type TSRMLS_CC); 540 | } while (zend_hash_get_current_data_ex( 541 | ht, (void **)&ftmp, &pos) == SUCCESS); 542 | return; 543 | } else if (n < 3) { 544 | return; 545 | } 546 | 547 | if (zend_hash_index_find(ht, 1, (void **)&tmp) != SUCCESS) { 548 | return; 549 | } 550 | 551 | index = hs_zval_search_key(*ftmp, filter TSRMLS_CC); 552 | if (Z_TYPE_P(index) != IS_LONG) { 553 | zval_ptr_dtor(&index); 554 | return; 555 | } 556 | 557 | if (zend_hash_index_find(ht, 2, (void **)&vtmp) != SUCCESS) { 558 | zval_ptr_dtor(&index); 559 | return; 560 | } 561 | 562 | MAKE_STD_ZVAL(item); 563 | array_init(item); 564 | 565 | add_next_index_stringl(item, type, strlen(type), 1); 566 | 567 | convert_to_string(*tmp); 568 | add_next_index_stringl(item, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1); 569 | 570 | add_next_index_long(item, Z_LVAL_P(index)); 571 | 572 | if (Z_TYPE_PP(vtmp) == IS_NULL) { 573 | add_next_index_null(item); 574 | } else if (Z_TYPE_PP(vtmp) == IS_LONG) { 575 | add_next_index_long(item, Z_LVAL_PP(vtmp)); 576 | } else if (Z_TYPE_PP(vtmp) == IS_DOUBLE) { 577 | add_next_index_double(item, Z_DVAL_PP(vtmp)); 578 | } else { 579 | convert_to_string(*tmp); 580 | add_next_index_stringl(item, Z_STRVAL_PP(vtmp), Z_STRLEN_PP(vtmp), 1); 581 | } 582 | 583 | if (!(*return_value)) { 584 | MAKE_STD_ZVAL(*return_value); 585 | array_init(*return_value); 586 | } 587 | 588 | add_next_index_zval(*return_value, item); 589 | 590 | zval_ptr_dtor(&index); 591 | } 592 | 593 | static inline void 594 | hs_array_to_in_filter(HashTable *ht, zval *filter, zval **filters, 595 | long *in_key, zval **in_values TSRMLS_DC) 596 | { 597 | HashPosition pos; 598 | zval **val; 599 | char *key; 600 | ulong key_index; 601 | uint key_len; 602 | 603 | if (!filter) { 604 | return; 605 | } 606 | 607 | zend_hash_internal_pointer_reset_ex(ht, &pos); 608 | while (zend_hash_get_current_data_ex(ht, (void **)&val, &pos) == SUCCESS) { 609 | if (zend_hash_get_current_key_ex(ht, &key, &key_len, 610 | &key_index, 0, &pos) 611 | != HASH_KEY_IS_STRING) { 612 | zend_hash_move_forward_ex(ht, &pos); 613 | continue; 614 | } 615 | 616 | if (strcmp(key, "in") == 0) { 617 | /* in */ 618 | if (Z_TYPE_PP(val) == IS_ARRAY) { 619 | HashTable *in_ht; 620 | HashPosition in_pos; 621 | zval **tmp; 622 | char *in_key_name; 623 | ulong in_key_index; 624 | uint in_key_len; 625 | 626 | in_ht = HASH_OF(*val); 627 | 628 | zend_hash_internal_pointer_reset_ex(in_ht, &in_pos); 629 | if (zend_hash_get_current_data_ex(in_ht, (void **)&tmp, 630 | &in_pos) == SUCCESS) { 631 | if (Z_TYPE_PP(tmp) == IS_ARRAY) { 632 | switch (zend_hash_get_current_key_ex( 633 | in_ht, &in_key_name, &in_key_len, 634 | &in_key_index, 0, &in_pos)) { 635 | case HASH_KEY_NON_EXISTANT: 636 | *in_key = 0; 637 | break; 638 | case HASH_KEY_IS_LONG: 639 | *in_key = in_key_index; 640 | break; 641 | default: 642 | { 643 | zval *key; 644 | MAKE_STD_ZVAL(key); 645 | ZVAL_STRINGL(key, in_key_name, in_key_len, 1); 646 | convert_to_long(key); 647 | *in_key = Z_LVAL_P(key); 648 | zval_ptr_dtor(&key); 649 | break; 650 | 651 | } 652 | } 653 | *in_values = *tmp; 654 | } else { 655 | *in_key = 0; 656 | *in_values = *val; 657 | } 658 | } 659 | } else { 660 | *in_key = 0; 661 | *in_values = *val; 662 | } 663 | } else if (strcmp(key, "filter") == 0 && filter != NULL) { 664 | /* filter */ 665 | hs_zval_to_filter(filters, filter, *val, 666 | HS_PROTOCOL_FILTER TSRMLS_CC); 667 | } else if (strcmp(key, "while") == 0 && filter != NULL) { 668 | /* while */ 669 | hs_zval_to_filter(filters, filter, *val, 670 | HS_PROTOCOL_WHILE TSRMLS_CC); 671 | } 672 | 673 | zend_hash_move_forward_ex(ht, &pos); 674 | } 675 | } 676 | 677 | static inline void 678 | hs_index_object_init(hs_index_obj_t *hsi, 679 | zval *link, char *db, long db_len, 680 | char *table, long table_len, 681 | zval *fields, zval *options TSRMLS_DC) 682 | { 683 | int id = 0; 684 | zval *index = NULL, *fields_str = NULL, *filter = NULL, *retval; 685 | php_stream *stream; 686 | long timeout; 687 | smart_str request = {0}; 688 | 689 | if (db_len == 0) { 690 | HS_EXCEPTION("__construct(): invalid database %s", db); 691 | return; 692 | } 693 | 694 | if (table_len == 0) { 695 | HS_EXCEPTION("__construct(): invalid table %s", table); 696 | return; 697 | } 698 | 699 | fields_str = hs_zval_to_comma_string(fields); 700 | if (!fields_str) { 701 | HS_EXCEPTION("__construct(): invalid fields"); 702 | return; 703 | } 704 | 705 | if (options && Z_TYPE_P(options) == IS_ARRAY) { 706 | zval **tmp; 707 | if (zend_hash_find(Z_ARRVAL_P(options), "id", 708 | sizeof("id"), (void **)&tmp) == SUCCESS) { 709 | convert_to_long_ex(tmp); 710 | id = Z_LVAL_PP(tmp); 711 | } 712 | 713 | if (zend_hash_find(Z_ARRVAL_P(options), "index", 714 | sizeof("index"), (void **)&tmp) == SUCCESS) { 715 | convert_to_string_ex(tmp); 716 | MAKE_STD_ZVAL(index); 717 | ZVAL_STRINGL(index, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1); 718 | } 719 | 720 | if (zend_hash_find(Z_ARRVAL_P(options), "filter", 721 | sizeof("filter"), (void **)&tmp) == SUCCESS) { 722 | filter = hs_zval_to_comma_array(*tmp); 723 | } 724 | } 725 | 726 | if (!index) { 727 | MAKE_STD_ZVAL(index); 728 | ZVAL_STRINGL(index, "PRIMARY", sizeof("PRIMARY")-1, 1); 729 | } else if (Z_STRLEN_P(index) <= 0) { 730 | if (index) { 731 | zval_ptr_dtor(&index); 732 | } 733 | if (fields_str) { 734 | zval_ptr_dtor(&fields_str); 735 | } 736 | if (filter) { 737 | zval_ptr_dtor(&filter); 738 | } 739 | HS_EXCEPTION("__construct(): invalid index"); 740 | return; 741 | } 742 | 743 | if (id <= 0) { 744 | id = HANDLERSOCKETI_G(id)++; 745 | } 746 | 747 | /* handerlsocket: object */ 748 | //hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 749 | //HS_CHECK_OBJECT(hsi, HandlersocketiIndex); 750 | if (!hsi) { 751 | HS_EXCEPTION("The HandlerSocketi_Index object has not been " 752 | "correctly initialized by its constructor"); 753 | return; 754 | } 755 | 756 | hsi->link = link; 757 | zval_add_ref(&hsi->link); 758 | 759 | /* id */ 760 | hsi->id = id; 761 | 762 | /* name */ 763 | MAKE_STD_ZVAL(hsi->name); 764 | *hsi->name = *index; 765 | zval_copy_ctor(hsi->name); 766 | 767 | /* db */ 768 | MAKE_STD_ZVAL(hsi->db); 769 | ZVAL_STRINGL(hsi->db, db, db_len, 1); 770 | 771 | /* table */ 772 | MAKE_STD_ZVAL(hsi->table); 773 | ZVAL_STRINGL(hsi->table, table, db_len, 1); 774 | 775 | /* field */ 776 | MAKE_STD_ZVAL(hsi->field); 777 | if (Z_TYPE_P(fields) == IS_STRING) { 778 | zval delim, *arr; 779 | MAKE_STD_ZVAL(arr); 780 | array_init(arr); 781 | 782 | ZVAL_STRINGL(&delim, ",", strlen(","), 0); 783 | php_explode(&delim, fields, arr, LONG_MAX); 784 | 785 | hsi->field_num = zend_hash_num_elements(HASH_OF(arr)); 786 | 787 | *hsi->field = *arr; 788 | zval_copy_ctor(hsi->field); 789 | zval_ptr_dtor(&arr); 790 | } else { 791 | hsi->field_num = zend_hash_num_elements(HASH_OF(fields)); 792 | *hsi->field = *fields; 793 | zval_copy_ctor(hsi->field); 794 | } 795 | 796 | if (filter) { 797 | MAKE_STD_ZVAL(hsi->filter); 798 | *hsi->filter = *filter; 799 | zval_copy_ctor(hsi->filter); 800 | } 801 | 802 | /* stream */ 803 | stream = handlersocketi_object_store_get_stream(hsi->link); 804 | timeout = handlersocketi_object_store_get_timeout(hsi->link); 805 | 806 | hs_request_string(&request, HS_PROTOCOL_OPEN, 1); 807 | hs_request_delim(&request); 808 | 809 | /* id */ 810 | hs_request_long(&request, hsi->id); 811 | hs_request_delim(&request); 812 | 813 | /* db */ 814 | hs_request_string(&request, db, db_len); 815 | hs_request_delim(&request); 816 | 817 | /* table */ 818 | hs_request_string(&request, table, table_len); 819 | hs_request_delim(&request); 820 | 821 | /* index */ 822 | hs_request_string(&request, Z_STRVAL_P(index), Z_STRLEN_P(index)); 823 | hs_request_delim(&request); 824 | 825 | /* fields */ 826 | hs_request_string(&request, Z_STRVAL_P(fields_str), Z_STRLEN_P(fields_str)); 827 | 828 | /* filters */ 829 | if (hsi->filter) { 830 | hs_request_filter(&request, HASH_OF(hsi->filter) TSRMLS_CC); 831 | } 832 | 833 | /* eol */ 834 | hs_request_next(&request); 835 | 836 | /* request: send */ 837 | if (hs_request_send(stream, &request TSRMLS_CC) < 0) { 838 | smart_str_free(&request); 839 | zval_ptr_dtor(&index); 840 | if (fields_str) { 841 | zval_ptr_dtor(&fields_str); 842 | } 843 | HS_EXCEPTION("__construct(): invalid request send"); 844 | return; 845 | } 846 | 847 | smart_str_free(&request); 848 | 849 | /* response */ 850 | MAKE_STD_ZVAL(retval); 851 | hs_response_value(stream, timeout, retval, hsi->error, 0 TSRMLS_CC); 852 | if (Z_TYPE_P(retval) == IS_BOOL && Z_LVAL_P(retval) == 0) { 853 | HS_EXCEPTION("__construct(): unable to open index: %ld: %s", 854 | id, 855 | hsi->error == NULL ? 856 | "Unknwon error" : Z_STRVAL_P(hsi->error)); 857 | return; 858 | } 859 | 860 | /* cleanup */ 861 | zval_ptr_dtor(&retval); 862 | zval_ptr_dtor(&index); 863 | if (fields_str) { 864 | zval_ptr_dtor(&fields_str); 865 | } 866 | } 867 | 868 | PHP_HANDLERSOCKETI_API int 869 | handlersocketi_register_index(TSRMLS_D) 870 | { 871 | zend_class_entry ce; 872 | 873 | INIT_CLASS_ENTRY(ce, "HandlerSocketi_Index", hs_index_methods); 874 | 875 | ce.create_object = hs_index_object_new; 876 | 877 | hs_ce_index = zend_register_internal_class(&ce TSRMLS_CC); 878 | if (hs_ce_index == NULL) { 879 | return FAILURE; 880 | } 881 | 882 | memcpy(&hs_index_object_handlers, zend_get_std_object_handlers(), 883 | sizeof(zend_object_handlers)); 884 | 885 | hs_index_object_handlers.clone_obj = hs_index_object_clone; 886 | 887 | return SUCCESS; 888 | } 889 | 890 | PHP_HANDLERSOCKETI_API zend_class_entry 891 | *handlersocketi_get_ce_index(void) { 892 | return hs_ce_index; 893 | } 894 | 895 | PHP_HANDLERSOCKETI_API void 896 | handlersocketi_create_index(zval *return_value, 897 | zval *link, char *db, long db_len, 898 | char *table, long table_len, 899 | zval *fields, zval *options TSRMLS_DC) 900 | { 901 | object_init_ex(return_value, hs_ce_index); 902 | 903 | hs_index_object_init(zend_object_store_get_object(return_value TSRMLS_CC), 904 | link, db, db_len, table, table_len, 905 | fields, options TSRMLS_CC); 906 | } 907 | 908 | ZEND_METHOD(HandlerSocketi_Index, __construct) 909 | { 910 | zval *link; 911 | char *db, *table; 912 | int db_len, table_len, id = 0; 913 | zval *fields, *options = NULL; 914 | zval *index = NULL, *fields_str = NULL, *filter = NULL; 915 | hs_index_obj_t *hsi; 916 | php_stream *stream; 917 | long timeout; 918 | smart_str request = {0}; 919 | 920 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ossz|z", 921 | &link, handlersocketi_get_ce(), 922 | &db, &db_len, &table, &table_len, 923 | &fields, &options) == FAILURE) { 924 | HS_EXCEPTION("__construct(): expects parameters"); 925 | zval *object = getThis(); 926 | ZVAL_NULL(object); 927 | return; 928 | } 929 | 930 | if (db_len == 0) { 931 | HS_EXCEPTION("__construct(): invalid database %s", db); 932 | return; 933 | } 934 | 935 | if (table_len == 0) { 936 | HS_EXCEPTION("__construct(): invalid table %s", table); 937 | return; 938 | } 939 | 940 | fields_str = hs_zval_to_comma_string(fields); 941 | if (!fields_str) { 942 | HS_EXCEPTION("__construct(): invalid fields"); 943 | return; 944 | } 945 | 946 | if (options && Z_TYPE_P(options) == IS_ARRAY) { 947 | zval **tmp; 948 | if (zend_hash_find(Z_ARRVAL_P(options), "id", 949 | sizeof("id"), (void **)&tmp) == SUCCESS) { 950 | convert_to_long_ex(tmp); 951 | id = Z_LVAL_PP(tmp); 952 | } 953 | 954 | if (zend_hash_find(Z_ARRVAL_P(options), "index", 955 | sizeof("index"), (void **)&tmp) == SUCCESS) { 956 | convert_to_string_ex(tmp); 957 | MAKE_STD_ZVAL(index); 958 | ZVAL_STRINGL(index, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1); 959 | } 960 | 961 | if (zend_hash_find(Z_ARRVAL_P(options), "filter", 962 | sizeof("filter"), (void **)&tmp) == SUCCESS) { 963 | filter = hs_zval_to_comma_array(*tmp); 964 | } 965 | } 966 | 967 | if (!index) { 968 | MAKE_STD_ZVAL(index); 969 | ZVAL_STRINGL(index, "PRIMARY", sizeof("PRIMARY")-1, 1); 970 | } else if (Z_STRLEN_P(index) <= 0) { 971 | if (index) { 972 | zval_ptr_dtor(&index); 973 | } 974 | if (fields_str) { 975 | zval_ptr_dtor(&fields_str); 976 | } 977 | if (filter) { 978 | zval_ptr_dtor(&filter); 979 | } 980 | HS_EXCEPTION("__construct(): invalid index"); 981 | return; 982 | } 983 | 984 | if (id <= 0) { 985 | id = HANDLERSOCKETI_G(id)++; 986 | } 987 | 988 | /* handerlsocket: object */ 989 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 990 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 991 | 992 | hsi->link = link; 993 | zval_add_ref(&hsi->link); 994 | 995 | /* id */ 996 | hsi->id = id; 997 | 998 | /* name */ 999 | MAKE_STD_ZVAL(hsi->name); 1000 | *hsi->name = *index; 1001 | zval_copy_ctor(hsi->name); 1002 | 1003 | /* db */ 1004 | MAKE_STD_ZVAL(hsi->db); 1005 | ZVAL_STRINGL(hsi->db, db, db_len, 1); 1006 | 1007 | /* table */ 1008 | MAKE_STD_ZVAL(hsi->table); 1009 | ZVAL_STRINGL(hsi->table, table, db_len, 1); 1010 | 1011 | /* field */ 1012 | MAKE_STD_ZVAL(hsi->field); 1013 | if (Z_TYPE_P(fields) == IS_STRING) { 1014 | zval delim, *arr; 1015 | MAKE_STD_ZVAL(arr); 1016 | array_init(arr); 1017 | 1018 | ZVAL_STRINGL(&delim, ",", strlen(","), 0); 1019 | php_explode(&delim, fields, arr, LONG_MAX); 1020 | 1021 | hsi->field_num = zend_hash_num_elements(HASH_OF(arr)); 1022 | 1023 | *hsi->field = *arr; 1024 | zval_copy_ctor(hsi->field); 1025 | zval_ptr_dtor(&arr); 1026 | } else { 1027 | hsi->field_num = zend_hash_num_elements(HASH_OF(fields)); 1028 | *hsi->field = *fields; 1029 | zval_copy_ctor(hsi->field); 1030 | } 1031 | 1032 | if (filter) { 1033 | MAKE_STD_ZVAL(hsi->filter); 1034 | *hsi->filter = *filter; 1035 | zval_copy_ctor(hsi->filter); 1036 | } 1037 | 1038 | /* stream */ 1039 | stream = handlersocketi_object_store_get_stream(hsi->link); 1040 | timeout = handlersocketi_object_store_get_timeout(hsi->link); 1041 | 1042 | hs_request_string(&request, HS_PROTOCOL_OPEN, 1); 1043 | hs_request_delim(&request); 1044 | 1045 | /* id */ 1046 | hs_request_long(&request, hsi->id); 1047 | hs_request_delim(&request); 1048 | 1049 | /* db */ 1050 | hs_request_string(&request, db, db_len); 1051 | hs_request_delim(&request); 1052 | 1053 | /* table */ 1054 | hs_request_string(&request, table, table_len); 1055 | hs_request_delim(&request); 1056 | 1057 | /* index */ 1058 | hs_request_string(&request, Z_STRVAL_P(index), Z_STRLEN_P(index)); 1059 | hs_request_delim(&request); 1060 | 1061 | /* fields */ 1062 | hs_request_string(&request, Z_STRVAL_P(fields_str), Z_STRLEN_P(fields_str)); 1063 | 1064 | /* filters */ 1065 | if (hsi->filter) { 1066 | hs_request_filter(&request, HASH_OF(hsi->filter) TSRMLS_CC); 1067 | } 1068 | 1069 | /* eol */ 1070 | hs_request_next(&request); 1071 | 1072 | /* request: send */ 1073 | if (hs_request_send(stream, &request TSRMLS_CC) < 0) { 1074 | smart_str_free(&request); 1075 | zval_ptr_dtor(&index); 1076 | if (fields_str) { 1077 | zval_ptr_dtor(&fields_str); 1078 | } 1079 | HS_EXCEPTION("__construct(): invalid request send"); 1080 | return; 1081 | } 1082 | 1083 | smart_str_free(&request); 1084 | 1085 | /* response */ 1086 | hs_response_value(stream, timeout, return_value, hsi->error, 0 TSRMLS_CC); 1087 | 1088 | if (Z_TYPE_P(return_value) == IS_BOOL && Z_LVAL_P(return_value) == 0) { 1089 | HS_EXCEPTION("__construct(): unable to open index: %ld: %s", 1090 | id, 1091 | hsi->error == NULL ? 1092 | "Unknwon error" : Z_STRVAL_P(hsi->error)); 1093 | return; 1094 | } 1095 | 1096 | /* cleanup */ 1097 | zval_ptr_dtor(&index); 1098 | if (fields_str) { 1099 | zval_ptr_dtor(&fields_str); 1100 | } 1101 | } 1102 | 1103 | ZEND_METHOD(HandlerSocketi_Index, find) 1104 | { 1105 | zval *query, *operate, *criteria; 1106 | zval *options = NULL; 1107 | long safe = -1, limit = HS_DEFAULT_LIMIT, offset = HS_DEFAULT_OFFSET; 1108 | zval *filters = NULL, *in_values = NULL; 1109 | long in_key = -1; 1110 | hs_index_obj_t *hsi; 1111 | php_stream *stream; 1112 | long timeout; 1113 | smart_str request = {0}; 1114 | 1115 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", 1116 | &query, &options) == FAILURE) { 1117 | RETURN_FALSE; 1118 | } 1119 | 1120 | /* handerlsocket: object */ 1121 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1122 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1123 | HS_ERROR_RESET(hsi->error); 1124 | 1125 | /* options */ 1126 | if (options != NULL && Z_TYPE_P(options) == IS_ARRAY) { 1127 | /* limit */ 1128 | limit = hs_get_options_long(HASH_OF(options), "limit", 1129 | limit TSRMLS_CC); 1130 | /* offset */ 1131 | offset = hs_get_options_long(HASH_OF(options), "offset", 1132 | offset TSRMLS_CC); 1133 | /* safe */ 1134 | safe = hs_is_options_safe(HASH_OF(options) TSRMLS_CC); 1135 | /* in, fiter, while */ 1136 | hs_array_to_in_filter(HASH_OF(options), hsi->filter, 1137 | &filters, &in_key, &in_values TSRMLS_CC); 1138 | } 1139 | 1140 | /* stream */ 1141 | stream = handlersocketi_object_store_get_stream(hsi->link); 1142 | timeout = handlersocketi_object_store_get_timeout(hsi->link); 1143 | 1144 | /* operate : criteria */ 1145 | MAKE_STD_ZVAL(operate); 1146 | if (hs_zval_to_operate_criteria(query, operate, &criteria, 1147 | HS_FIND_EQUAL TSRMLS_CC) != SUCCESS) { 1148 | zval_ptr_dtor(&operate); 1149 | RETURN_FALSE; 1150 | } 1151 | 1152 | /* command */ 1153 | hs_request_command(&request, hsi->id, operate, criteria, 1154 | limit, offset, filters, in_key, in_values TSRMLS_CC); 1155 | 1156 | /* eol */ 1157 | hs_request_next(&request); 1158 | 1159 | /* request: send */ 1160 | if (hs_request_send(stream, &request TSRMLS_CC) < 0) { 1161 | ZVAL_BOOL(return_value, 0); 1162 | } else { 1163 | /* response */ 1164 | hs_response_value(stream, timeout, return_value, 1165 | hsi->error, 0 TSRMLS_CC); 1166 | } 1167 | 1168 | zval_ptr_dtor(&operate); 1169 | if (filters) { 1170 | zval_ptr_dtor(&filters); 1171 | } 1172 | smart_str_free(&request); 1173 | 1174 | /* exception */ 1175 | if (safe > 0 && 1176 | Z_TYPE_P(return_value) == IS_BOOL && Z_LVAL_P(return_value) == 0) { 1177 | HS_EXCEPTION("find(): response error: %s", 1178 | hsi->error == NULL ? 1179 | "Unknown error" : Z_STRVAL_P(hsi->error)); 1180 | RETURN_FALSE; 1181 | } 1182 | } 1183 | 1184 | ZEND_METHOD(HandlerSocketi_Index, insert) 1185 | { 1186 | zval ***args; 1187 | zval *operate, *fields; 1188 | long i, argc = ZEND_NUM_ARGS(); 1189 | hs_index_obj_t *hsi; 1190 | php_stream *stream; 1191 | long timeout; 1192 | smart_str request = {0}; 1193 | long fnum = 0; 1194 | 1195 | if (argc < 1) { 1196 | zend_wrong_param_count(TSRMLS_C); 1197 | RETURN_FALSE; 1198 | } 1199 | 1200 | args = safe_emalloc(argc, sizeof(zval **), 0); 1201 | if (zend_get_parameters_array_ex(argc, args) == FAILURE) { 1202 | efree(args); 1203 | zend_wrong_param_count(TSRMLS_C); 1204 | RETURN_FALSE; 1205 | } 1206 | 1207 | if (Z_TYPE_PP(args[0]) == IS_ARRAY) { 1208 | fields = *args[0]; 1209 | } else { 1210 | MAKE_STD_ZVAL(fields); 1211 | array_init(fields); 1212 | 1213 | for (i = 0; i < argc; i++) { 1214 | switch (Z_TYPE_P(*args[i])) { 1215 | case IS_NULL: 1216 | add_next_index_null(fields); 1217 | break; 1218 | case IS_LONG: 1219 | add_next_index_long(fields, Z_LVAL_P(*args[i])); 1220 | break; 1221 | case IS_DOUBLE: 1222 | add_next_index_double(fields, Z_DVAL_P(*args[i])); 1223 | break; 1224 | default: 1225 | convert_to_string(*args[i]); 1226 | add_next_index_stringl(fields, Z_STRVAL_P(*args[i]), 1227 | Z_STRLEN_P(*args[i]), 1); 1228 | break; 1229 | } 1230 | } 1231 | } 1232 | 1233 | /* handerlsocket: object */ 1234 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1235 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1236 | HS_ERROR_RESET(hsi->error); 1237 | 1238 | /* fiedls check */ 1239 | fnum = zend_hash_num_elements(HASH_OF(fields)); 1240 | if (fnum < hsi->field_num) { 1241 | for (i = 0; i < fnum; i++) { 1242 | add_next_index_null(fields); 1243 | } 1244 | } else if (fnum > hsi->field_num) { 1245 | /* 1246 | efree(args); 1247 | ZVAL_STRINGL(hsi->error, "invalid field count", 1248 | strlen("invalid field count"), 1); 1249 | RETURN_FALSE; 1250 | */ 1251 | zend_error(E_WARNING, 1252 | "HandlerSocketi_Index::insert(): invalid field count"); 1253 | } 1254 | 1255 | stream = handlersocketi_object_store_get_stream(hsi->link); 1256 | timeout = handlersocketi_object_store_get_timeout(hsi->link); 1257 | 1258 | /* operate */ 1259 | MAKE_STD_ZVAL(operate); 1260 | ZVAL_STRINGL(operate, HS_PROTOCOL_INSERT, 1, 1); 1261 | 1262 | /* command */ 1263 | hs_request_command(&request, hsi->id, operate, fields, 1264 | 0, 0, NULL, -1, NULL TSRMLS_CC); 1265 | 1266 | /* eol */ 1267 | hs_request_next(&request); 1268 | 1269 | /* request: send */ 1270 | if (hs_request_send(stream, &request TSRMLS_CC) < 0) { 1271 | ZVAL_BOOL(return_value, 0); 1272 | } else { 1273 | /* response */ 1274 | hs_response_value(stream, timeout, return_value, 1275 | hsi->error, 1 TSRMLS_CC); 1276 | } 1277 | 1278 | zval_ptr_dtor(&operate); 1279 | //zval_ptr_dtor(&fields); 1280 | smart_str_free(&request); 1281 | efree(args); 1282 | } 1283 | 1284 | ZEND_METHOD(HandlerSocketi_Index, update) 1285 | { 1286 | zval *query, *update, *options = NULL; 1287 | long safe = -1, modify = 1; 1288 | long limit = HS_DEFAULT_LIMIT, offset = HS_DEFAULT_OFFSET; 1289 | zval *operate, *criteria, *modify_operate, *modify_criteria; 1290 | zval *filters = NULL, *in_values = NULL; 1291 | long in_key = -1; 1292 | hs_index_obj_t *hsi; 1293 | php_stream *stream; 1294 | long timeout; 1295 | smart_str request = {0}; 1296 | long fnum = 0; 1297 | 1298 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|z", 1299 | &query, &update, &options) == FAILURE) { 1300 | RETURN_FALSE; 1301 | } 1302 | 1303 | /* handerlsocket: object */ 1304 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1305 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1306 | HS_ERROR_RESET(hsi->error); 1307 | 1308 | if (options != NULL && Z_TYPE_P(options) == IS_ARRAY) { 1309 | /* limit */ 1310 | limit = hs_get_options_long(HASH_OF(options), "limit", 1311 | limit TSRMLS_CC); 1312 | /* offset */ 1313 | offset = hs_get_options_long(HASH_OF(options), "offset", 1314 | offset TSRMLS_CC); 1315 | /* safe */ 1316 | safe = hs_is_options_safe(HASH_OF(options) TSRMLS_CC); 1317 | /* in, fiter, while */ 1318 | hs_array_to_in_filter(HASH_OF(options), hsi->filter, 1319 | &filters, &in_key, &in_values TSRMLS_CC); 1320 | } 1321 | 1322 | /* stream */ 1323 | stream = handlersocketi_object_store_get_stream(hsi->link); 1324 | timeout = handlersocketi_object_store_get_timeout(hsi->link); 1325 | 1326 | /* operate : criteria */ 1327 | MAKE_STD_ZVAL(operate); 1328 | if (hs_zval_to_operate_criteria(query, operate, &criteria, 1329 | HS_FIND_EQUAL TSRMLS_CC) != SUCCESS) { 1330 | zval_ptr_dtor(&operate); 1331 | RETURN_FALSE; 1332 | } 1333 | 1334 | /* modify_operete : modify_criteria */ 1335 | MAKE_STD_ZVAL(modify_operate); 1336 | if (hs_zval_to_operate_criteria(update, modify_operate, &modify_criteria, 1337 | HS_MODIFY_UPDATE TSRMLS_CC) != SUCCESS) { 1338 | zval_ptr_dtor(&operate); 1339 | zval_ptr_dtor(&modify_operate); 1340 | RETURN_FALSE; 1341 | } 1342 | 1343 | /* fiedls check */ 1344 | if (Z_TYPE_P(modify_criteria) == IS_ARRAY) { 1345 | fnum = zend_hash_num_elements(HASH_OF(modify_criteria)); 1346 | } else { 1347 | fnum = 1; 1348 | } 1349 | 1350 | if (fnum > hsi->field_num) { 1351 | /* 1352 | ZVAL_STRINGL(hsi->error, "invalid field count", 1353 | strlen("invalid field count"), 1); 1354 | RETURN_FALSE; 1355 | */ 1356 | zend_error(E_WARNING, 1357 | "HandlerSocketi_Index::update(): invalid field count"); 1358 | } 1359 | 1360 | /* command */ 1361 | hs_request_command(&request, hsi->id, operate, criteria, 1362 | limit, offset, filters, in_key, in_values TSRMLS_CC); 1363 | 1364 | /* command: modify */ 1365 | modify = hs_request_command_modify(&request, modify_operate, 1366 | modify_criteria, -1 TSRMLS_CC); 1367 | if (modify >= 0) { 1368 | /* eol */ 1369 | hs_request_next(&request); 1370 | 1371 | /* request: send */ 1372 | if (hs_request_send(stream, &request TSRMLS_CC) < 0) { 1373 | ZVAL_BOOL(return_value, 0); 1374 | } else { 1375 | /* response */ 1376 | hs_response_value(stream, timeout, return_value, 1377 | hsi->error, modify TSRMLS_CC); 1378 | } 1379 | } else { 1380 | ZVAL_BOOL(return_value, 0); 1381 | ZVAL_STRINGL(hsi->error, "unable to update parameter", 1382 | strlen("unable to update parameter"), 1); 1383 | } 1384 | 1385 | zval_ptr_dtor(&operate); 1386 | zval_ptr_dtor(&modify_operate); 1387 | if (filters) { 1388 | zval_ptr_dtor(&filters); 1389 | } 1390 | smart_str_free(&request); 1391 | 1392 | /* exception */ 1393 | if (safe > 0 && 1394 | Z_TYPE_P(return_value) == IS_BOOL && Z_LVAL_P(return_value) == 0) { 1395 | HS_EXCEPTION("update(): response error: %s", 1396 | hsi->error == NULL ? 1397 | "Unknown error" : Z_STRVAL_P(hsi->error)); 1398 | } 1399 | } 1400 | 1401 | ZEND_METHOD(HandlerSocketi_Index, remove) 1402 | { 1403 | zval *query, *options = NULL; 1404 | zval *operate, *criteria; 1405 | long safe = -1, limit = HS_DEFAULT_LIMIT, offset = HS_DEFAULT_OFFSET; 1406 | zval *filters = NULL, *in_values = NULL; 1407 | long in_key = -1; 1408 | hs_index_obj_t *hsi; 1409 | php_stream *stream; 1410 | long timeout; 1411 | smart_str request = {0}; 1412 | 1413 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", 1414 | &query, &options) == FAILURE) { 1415 | RETURN_FALSE; 1416 | } 1417 | 1418 | /* handelrsocket : object */ 1419 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1420 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1421 | HS_ERROR_RESET(hsi->error); 1422 | 1423 | if (options != NULL && Z_TYPE_P(options) == IS_ARRAY) { 1424 | /* limit */ 1425 | limit = hs_get_options_long(HASH_OF(options), "limit", 1426 | limit TSRMLS_CC); 1427 | /* offset */ 1428 | offset = hs_get_options_long(HASH_OF(options), "offset", 1429 | offset TSRMLS_CC); 1430 | /* safe */ 1431 | safe = hs_is_options_safe(HASH_OF(options) TSRMLS_CC); 1432 | /* in, fiter, while */ 1433 | hs_array_to_in_filter(HASH_OF(options), hsi->filter, 1434 | &filters, &in_key, &in_values TSRMLS_CC); 1435 | } 1436 | 1437 | /* stream */ 1438 | stream = handlersocketi_object_store_get_stream(hsi->link); 1439 | timeout = handlersocketi_object_store_get_timeout(hsi->link); 1440 | 1441 | /* operate : criteria */ 1442 | MAKE_STD_ZVAL(operate); 1443 | if (hs_zval_to_operate_criteria(query, operate, &criteria, 1444 | HS_FIND_EQUAL TSRMLS_CC) != SUCCESS) { 1445 | zval_ptr_dtor(&operate); 1446 | RETURN_FALSE; 1447 | } 1448 | 1449 | /* command */ 1450 | hs_request_command(&request, hsi->id, operate, criteria, 1451 | limit, offset, filters, in_key, in_values TSRMLS_CC); 1452 | 1453 | /* find: modify: D */ 1454 | hs_request_delim(&request); 1455 | hs_request_string(&request, HS_MODIFY_REMOVE, 1); 1456 | 1457 | /* eol */ 1458 | hs_request_next(&request); 1459 | 1460 | /* request: send */ 1461 | if (hs_request_send(stream, &request TSRMLS_CC) < 0) { 1462 | ZVAL_BOOL(return_value, 0); 1463 | } else { 1464 | /* response */ 1465 | hs_response_value(stream, timeout, return_value, 1466 | hsi->error, 1 TSRMLS_CC); 1467 | } 1468 | 1469 | zval_ptr_dtor(&operate); 1470 | if (filters) { 1471 | zval_ptr_dtor(&filters); 1472 | } 1473 | smart_str_free(&request); 1474 | 1475 | /* exception */ 1476 | if (safe > 0 && 1477 | Z_TYPE_P(return_value) == IS_BOOL && Z_LVAL_P(return_value) == 0) { 1478 | HS_EXCEPTION("remove(): response error: %s", 1479 | hsi->error == NULL ? 1480 | "Unknown error" : Z_STRVAL_P(hsi->error)); 1481 | } 1482 | } 1483 | 1484 | ZEND_METHOD(HandlerSocketi_Index, multi) 1485 | { 1486 | zval *args = NULL; 1487 | 1488 | zval *mreq; 1489 | HashPosition pos; 1490 | zval **val; 1491 | int err = -1; 1492 | 1493 | hs_index_obj_t *hsi; 1494 | php_stream *stream; 1495 | long timeout; 1496 | smart_str request = {0}; 1497 | 1498 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", 1499 | &args) == FAILURE) { 1500 | RETURN_FALSE; 1501 | } 1502 | 1503 | /* handlersocket: object */ 1504 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1505 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1506 | HS_ERROR_RESET(hsi->error); 1507 | 1508 | MAKE_STD_ZVAL(mreq); 1509 | array_init(mreq); 1510 | 1511 | zend_hash_internal_pointer_reset_ex(HASH_OF(args), &pos); 1512 | while (zend_hash_get_current_data_ex(HASH_OF(args), 1513 | (void **)&val, &pos) == SUCCESS) { 1514 | zval **method; 1515 | HashTable *ht; 1516 | 1517 | if (Z_TYPE_PP(val) != IS_ARRAY) { 1518 | err = -1; 1519 | break; 1520 | } 1521 | 1522 | ht = HASH_OF(*val); 1523 | 1524 | /* 0: method */ 1525 | if (zend_hash_index_find(ht, 0, (void **)&method) != SUCCESS) { 1526 | err = -1; 1527 | break; 1528 | } 1529 | 1530 | convert_to_string(*method); 1531 | 1532 | if (strncmp(Z_STRVAL_PP(method), "find", strlen("find")) == 0) { 1533 | /* method: find */ 1534 | zval **query, **options, *operate, *criteria; 1535 | zval *filters = NULL, *in_values = NULL; 1536 | long in_key = -1; 1537 | long limit = HS_DEFAULT_LIMIT, offset = HS_DEFAULT_OFFSET; 1538 | 1539 | if (zend_hash_num_elements(ht) <= 1) { 1540 | err = -1; 1541 | break; 1542 | } 1543 | 1544 | /* 1: query */ 1545 | if (zend_hash_index_find(ht, 1, (void **)&query) != SUCCESS) { 1546 | err = -1; 1547 | break; 1548 | } 1549 | 1550 | /* 2: options */ 1551 | if (zend_hash_index_find(ht, 2, (void **)&options) == SUCCESS && 1552 | options != NULL && Z_TYPE_PP(options) == IS_ARRAY) { 1553 | limit = hs_get_options_long(HASH_OF(*options), 1554 | "limit", limit TSRMLS_CC); 1555 | offset = hs_get_options_long(HASH_OF(*options), 1556 | "offset", offset TSRMLS_CC); 1557 | hs_array_to_in_filter(HASH_OF(*options), hsi->filter, 1558 | &filters, &in_key, &in_values TSRMLS_CC); 1559 | } 1560 | 1561 | /* operete : criteria */ 1562 | MAKE_STD_ZVAL(operate); 1563 | if (hs_zval_to_operate_criteria(*query, operate, &criteria, 1564 | HS_FIND_EQUAL TSRMLS_CC) 1565 | != SUCCESS) { 1566 | err = -1; 1567 | zval_ptr_dtor(&operate); 1568 | break; 1569 | } 1570 | 1571 | if (*query == NULL) { 1572 | err = -1; 1573 | zval_ptr_dtor(&operate); 1574 | break; 1575 | } 1576 | 1577 | /* command */ 1578 | hs_request_command(&request, hsi->id, operate, criteria, 1579 | limit, offset, filters, in_key, 1580 | in_values TSRMLS_CC); 1581 | 1582 | /* eol */ 1583 | hs_request_next(&request); 1584 | 1585 | add_next_index_long(mreq, 0); 1586 | err = 0; 1587 | 1588 | zval_ptr_dtor(&operate); 1589 | if (filters) { 1590 | zval_ptr_dtor(&filters); 1591 | } 1592 | } else if (strncmp(Z_STRVAL_PP(method), 1593 | "insert", strlen("insert")) == 0) { 1594 | /* method: insert */ 1595 | zval *operate, *fields; 1596 | zval **tmp; 1597 | long i, n, fnum = 0; 1598 | 1599 | if (zend_hash_num_elements(ht) <= 1) { 1600 | err = -1; 1601 | break; 1602 | } 1603 | 1604 | if (zend_hash_index_find(ht, 1, (void **)&tmp) != SUCCESS) { 1605 | err = -1; 1606 | break; 1607 | } 1608 | 1609 | MAKE_STD_ZVAL(fields); 1610 | array_init(fields); 1611 | 1612 | if (Z_TYPE_PP(tmp) == IS_ARRAY) { 1613 | n = zend_hash_num_elements(HASH_OF(*tmp)); 1614 | for (i = 0; i < n; i++) { 1615 | zval **val; 1616 | if (zend_hash_index_find(HASH_OF(*tmp), 1617 | i, (void **)&val) == SUCCESS) { 1618 | if (Z_TYPE_PP(val) == IS_NULL) { 1619 | add_next_index_null(fields); 1620 | } else { 1621 | convert_to_string(*val); 1622 | add_next_index_stringl(fields, Z_STRVAL_PP(val), 1623 | Z_STRLEN_PP(val), 1); 1624 | } 1625 | } 1626 | } 1627 | } else { 1628 | i = 1; 1629 | do { 1630 | if (Z_TYPE_PP(tmp) == IS_NULL) { 1631 | add_next_index_null(fields); 1632 | } else { 1633 | convert_to_string(*tmp); 1634 | add_next_index_stringl(fields, Z_STRVAL_PP(tmp), 1635 | Z_STRLEN_PP(tmp), 1); 1636 | } 1637 | 1638 | i++; 1639 | 1640 | if (zend_hash_index_find(ht, i, (void **)&tmp) != SUCCESS) { 1641 | break; 1642 | } 1643 | } while (i < n); 1644 | } 1645 | 1646 | /* fields check */ 1647 | fnum = zend_hash_num_elements(HASH_OF(fields)); 1648 | if (fnum < hsi->field_num) { 1649 | for (i = 0; i < fnum; i++) { 1650 | add_next_index_null(fields); 1651 | } 1652 | } 1653 | 1654 | MAKE_STD_ZVAL(operate); 1655 | ZVAL_STRINGL(operate, HS_PROTOCOL_INSERT, 1, 1); 1656 | 1657 | /* command */ 1658 | hs_request_command(&request, hsi->id, operate, fields, 0, 0, 1659 | NULL, -1, NULL TSRMLS_CC); 1660 | 1661 | /* eol */ 1662 | hs_request_next(&request); 1663 | 1664 | add_next_index_long(mreq, 1); 1665 | err = 0; 1666 | 1667 | zval_ptr_dtor(&operate); 1668 | zval_ptr_dtor(&fields); 1669 | } else if (strncmp(Z_STRVAL_PP(method), 1670 | "remove", strlen("remove")) == 0) { 1671 | /* method: remove */ 1672 | zval **query, **options, *operate, *criteria; 1673 | zval *filters = NULL, *in_values = NULL; 1674 | long in_key = -1; 1675 | long limit = HS_DEFAULT_LIMIT, offset = HS_DEFAULT_OFFSET; 1676 | 1677 | if (zend_hash_num_elements(ht) <= 1) { 1678 | err = -1; 1679 | break; 1680 | } 1681 | 1682 | /* 1: query */ 1683 | if (zend_hash_index_find(ht, 1, (void **)&query) != SUCCESS) { 1684 | if (operate) { 1685 | zval_ptr_dtor(&operate); 1686 | } 1687 | err = -1; 1688 | break; 1689 | } 1690 | 1691 | /* 2: options */ 1692 | if (zend_hash_index_find(ht, 2, (void **)&options) == SUCCESS && 1693 | options != NULL && Z_TYPE_PP(options) == IS_ARRAY) { 1694 | limit = hs_get_options_long(HASH_OF(*options), 1695 | "limit", limit TSRMLS_CC); 1696 | offset = hs_get_options_long(HASH_OF(*options), 1697 | "offset", offset TSRMLS_CC); 1698 | hs_array_to_in_filter(HASH_OF(*options), hsi->filter, 1699 | &filters, &in_key, &in_values TSRMLS_CC); 1700 | } 1701 | 1702 | /* operete : criteria */ 1703 | MAKE_STD_ZVAL(operate); 1704 | if (hs_zval_to_operate_criteria(*query, operate, &criteria, 1705 | HS_FIND_EQUAL TSRMLS_CC) 1706 | != SUCCESS) { 1707 | zval_ptr_dtor(&operate); 1708 | err = -1; 1709 | break; 1710 | } 1711 | 1712 | /* command */ 1713 | hs_request_command(&request, hsi->id, operate, criteria, 1714 | limit, offset, filters, in_key, 1715 | in_values TSRMLS_CC); 1716 | 1717 | /* find: modify: D */ 1718 | hs_request_delim(&request); 1719 | 1720 | hs_request_string(&request, HS_MODIFY_REMOVE, 1); 1721 | 1722 | /* eol */ 1723 | hs_request_next(&request); 1724 | 1725 | add_next_index_long(mreq, 1); 1726 | err = 0; 1727 | 1728 | zval_ptr_dtor(&operate); 1729 | if (filters) { 1730 | zval_ptr_dtor(&filters); 1731 | } 1732 | } else if (strncmp(Z_STRVAL_PP(method), 1733 | "update", strlen("update")) == 0) { 1734 | /* method: update */ 1735 | zval **query, **update, **options; 1736 | zval *operate, *criteria, *modify_operate, *modify_criteria; 1737 | zval *filters = NULL, *in_values = NULL; 1738 | long in_key = -1; 1739 | long limit = HS_DEFAULT_LIMIT, offset = HS_DEFAULT_OFFSET; 1740 | int modify; 1741 | 1742 | if (zend_hash_num_elements(ht) <= 2) { 1743 | err = -1; 1744 | break; 1745 | } 1746 | 1747 | /* 1: query */ 1748 | if (zend_hash_index_find(ht, 1, (void **)&query) != SUCCESS) { 1749 | err = -1; 1750 | break; 1751 | } 1752 | 1753 | /* 2: update */ 1754 | if (zend_hash_index_find(ht, 2, (void **)&update) != SUCCESS) { 1755 | err = -1; 1756 | break; 1757 | } 1758 | 1759 | /* 3: options */ 1760 | if (zend_hash_index_find(ht, 3, (void **)&options) == SUCCESS && 1761 | options != NULL && Z_TYPE_PP(options) == IS_ARRAY) { 1762 | limit = hs_get_options_long(HASH_OF(*options), 1763 | "limit", limit TSRMLS_CC); 1764 | offset = hs_get_options_long(HASH_OF(*options), 1765 | "offset", offset TSRMLS_CC); 1766 | hs_array_to_in_filter(HASH_OF(*options), hsi->filter, 1767 | &filters, &in_key, &in_values TSRMLS_CC); 1768 | } 1769 | 1770 | /* operete : criteria */ 1771 | MAKE_STD_ZVAL(operate); 1772 | if (hs_zval_to_operate_criteria(*query, operate, &criteria, 1773 | HS_FIND_EQUAL TSRMLS_CC) 1774 | != SUCCESS) { 1775 | zval_ptr_dtor(&operate); 1776 | err = -1; 1777 | break; 1778 | } 1779 | 1780 | /* modify_operete : modify_criteria */ 1781 | MAKE_STD_ZVAL(modify_operate); 1782 | if (hs_zval_to_operate_criteria(*update, modify_operate, 1783 | &modify_criteria, 1784 | HS_MODIFY_UPDATE TSRMLS_CC) 1785 | != SUCCESS) { 1786 | zval_ptr_dtor(&operate); 1787 | zval_ptr_dtor(&modify_operate); 1788 | err = -1; 1789 | break; 1790 | } 1791 | 1792 | /* command */ 1793 | hs_request_command(&request, hsi->id, operate, criteria, 1794 | limit, offset, filters, in_key, 1795 | in_values TSRMLS_CC); 1796 | 1797 | /* command: modify */ 1798 | modify = hs_request_command_modify(&request, modify_operate, 1799 | modify_criteria, -1 TSRMLS_CC); 1800 | if (modify < 0) { 1801 | err = -1; 1802 | break; 1803 | } 1804 | 1805 | /* eol */ 1806 | hs_request_next(&request); 1807 | 1808 | add_next_index_long(mreq, modify); 1809 | err = 0; 1810 | 1811 | zval_ptr_dtor(&operate); 1812 | zval_ptr_dtor(&modify_operate); 1813 | if (filters) { 1814 | zval_ptr_dtor(&filters); 1815 | } 1816 | } else { 1817 | err = -1; 1818 | break; 1819 | } 1820 | 1821 | zend_hash_move_forward_ex(HASH_OF(args), &pos); 1822 | } 1823 | 1824 | /* stream */ 1825 | stream = handlersocketi_object_store_get_stream(hsi->link); 1826 | timeout = handlersocketi_object_store_get_timeout(hsi->link); 1827 | 1828 | /* request: send */ 1829 | if (err < 0 || hs_request_send(stream, &request TSRMLS_CC) < 0) { 1830 | smart_str_free(&request); 1831 | zval_ptr_dtor(&mreq); 1832 | RETURN_FALSE; 1833 | } 1834 | smart_str_free(&request); 1835 | 1836 | /* response */ 1837 | hs_response_multi(stream, timeout, return_value, hsi->error, mreq TSRMLS_CC); 1838 | 1839 | zval_ptr_dtor(&mreq); 1840 | } 1841 | 1842 | ZEND_METHOD(HandlerSocketi_Index, get_error) 1843 | { 1844 | hs_index_obj_t *hsi; 1845 | 1846 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1847 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1848 | 1849 | if (hsi->error == NULL) { 1850 | RETURN_NULL(); 1851 | } else { 1852 | RETVAL_ZVAL(hsi->error, 1, 0); 1853 | } 1854 | } 1855 | 1856 | ZEND_METHOD(HandlerSocketi_Index, get_id) 1857 | { 1858 | hs_index_obj_t *hsi; 1859 | 1860 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1861 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1862 | 1863 | RETVAL_LONG(hsi->id); 1864 | } 1865 | 1866 | ZEND_METHOD(HandlerSocketi_Index, get_name) 1867 | { 1868 | hs_index_obj_t *hsi; 1869 | 1870 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1871 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1872 | 1873 | RETVAL_ZVAL(hsi->name, 1, 0); 1874 | } 1875 | 1876 | ZEND_METHOD(HandlerSocketi_Index, get_db) 1877 | { 1878 | hs_index_obj_t *hsi; 1879 | 1880 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1881 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1882 | 1883 | RETVAL_ZVAL(hsi->db, 1, 0); 1884 | } 1885 | 1886 | ZEND_METHOD(HandlerSocketi_Index, get_table) 1887 | { 1888 | hs_index_obj_t *hsi; 1889 | 1890 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1891 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1892 | 1893 | RETVAL_ZVAL(hsi->table, 1, 0); 1894 | } 1895 | 1896 | ZEND_METHOD(HandlerSocketi_Index, get_field) 1897 | { 1898 | hs_index_obj_t *hsi; 1899 | 1900 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1901 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1902 | 1903 | RETVAL_ZVAL(hsi->field, 1, 0); 1904 | } 1905 | 1906 | ZEND_METHOD(HandlerSocketi_Index, get_filter) 1907 | { 1908 | hs_index_obj_t *hsi; 1909 | 1910 | hsi = (hs_index_obj_t *)zend_object_store_get_object(getThis() TSRMLS_CC); 1911 | HS_CHECK_OBJECT(hsi, HandlerSocketi_Index); 1912 | 1913 | if (hsi->filter) { 1914 | RETVAL_ZVAL(hsi->filter, 1, 0); 1915 | } else { 1916 | RETVAL_NULL(); 1917 | } 1918 | } 1919 | 1920 | ZEND_METHOD(HandlerSocketi_Index, get_operator) 1921 | { 1922 | zval *query, *modify; 1923 | 1924 | MAKE_STD_ZVAL(query); 1925 | array_init(query); 1926 | 1927 | add_next_index_stringl(query, HS_FIND_EQUAL, strlen(HS_FIND_EQUAL), 1); 1928 | add_next_index_stringl(query, HS_FIND_LESS, strlen(HS_FIND_LESS), 1); 1929 | add_next_index_stringl(query, HS_FIND_LESS_EQUAL, 1930 | strlen(HS_FIND_LESS_EQUAL), 1); 1931 | add_next_index_stringl(query, HS_FIND_GREATER, strlen(HS_FIND_GREATER), 1); 1932 | add_next_index_stringl(query, HS_FIND_GREATER_EQUAL, 1933 | strlen(HS_FIND_GREATER_EQUAL), 1); 1934 | 1935 | MAKE_STD_ZVAL(modify); 1936 | array_init(modify); 1937 | 1938 | add_next_index_stringl(modify, HS_MODIFY_UPDATE, 1939 | strlen(HS_MODIFY_UPDATE), 1); 1940 | add_next_index_stringl(modify, HS_MODIFY_INCREMENT, 1941 | strlen(HS_MODIFY_INCREMENT), 1); 1942 | add_next_index_stringl(modify, HS_MODIFY_DECREMENT, 1943 | strlen(HS_MODIFY_DECREMENT), 1); 1944 | add_next_index_stringl(modify, HS_MODIFY_REMOVE, 1945 | strlen(HS_MODIFY_REMOVE), 1); 1946 | add_next_index_stringl(modify, HS_MODIFY_GET_UPDATE, 1947 | strlen(HS_MODIFY_GET_UPDATE), 1); 1948 | add_next_index_stringl(modify, HS_MODIFY_GET_INCREMENT, 1949 | strlen(HS_MODIFY_GET_INCREMENT), 1); 1950 | add_next_index_stringl(modify, HS_MODIFY_GET_DECREMENT, 1951 | strlen(HS_MODIFY_GET_DECREMENT), 1); 1952 | add_next_index_stringl(modify, HS_MODIFY_GET_REMOVE, 1953 | strlen(HS_MODIFY_GET_REMOVE), 1); 1954 | 1955 | array_init(return_value); 1956 | add_assoc_zval(return_value, "query", query); 1957 | add_assoc_zval(return_value, "modify", modify); 1958 | } 1959 | -------------------------------------------------------------------------------- /handlersocketi_index.h: -------------------------------------------------------------------------------- 1 | #ifndef HANDLERSOCKETI_INDEX_H 2 | #define HANDLERSOCKETI_INDEX_H 3 | 4 | PHP_HANDLERSOCKETI_API int handlersocketi_register_index(TSRMLS_D); 5 | PHP_HANDLERSOCKETI_API zend_class_entry *handlersocketi_get_ce_index(void); 6 | PHP_HANDLERSOCKETI_API void handlersocketi_create_index( 7 | zval *return_value, zval *link, char *db, long db_len, 8 | char *table, long table_len, zval *fields, zval *options TSRMLS_DC); 9 | 10 | #endif /* HANDLERSOCKETI_INDEX_H */ 11 | -------------------------------------------------------------------------------- /php_handlersocketi.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef PHP_HANDLERSOCKETI_H 3 | #define PHP_HANDLERSOCKETI_H 4 | 5 | #define HANDLERSOCKETI_EXT_VERSION "0.0.1" 6 | 7 | extern zend_module_entry handlersocketi_module_entry; 8 | #define phpext_handlersocketi_ptr &handlersocketi_module_entry 9 | 10 | #ifdef PHP_WIN32 11 | # define PHP_HANDLERSOCKETI_API __declspec(dllexport) 12 | #elif defined(__GNUC__) && __GNUC__ >= 4 13 | # define PHP_HANDLERSOCKETI_API __attribute__ ((visibility("default"))) 14 | #else 15 | # define PHP_HANDLERSOCKETI_API 16 | #endif 17 | 18 | #ifdef ZTS 19 | #include "TSRM.h" 20 | #endif 21 | 22 | ZEND_BEGIN_MODULE_GLOBALS(handlersocketi) 23 | long id; 24 | ZEND_END_MODULE_GLOBALS(handlersocketi) 25 | 26 | #ifdef ZTS 27 | #define HANDLERSOCKETI_G(v) TSRMG(handlersocketi_globals_id, zend_handlersocketi_globals *, v) 28 | #else 29 | #define HANDLERSOCKETI_G(v) (handlersocketi_globals.v) 30 | #endif 31 | 32 | #endif /* PHP_HANDLERSOCKETI_H */ 33 | -------------------------------------------------------------------------------- /php_verdep.h: -------------------------------------------------------------------------------- 1 | #ifndef PHP_VERDEP_H 2 | #define PHP_VERDEP_H 3 | 4 | #ifndef ZED_FE_END 5 | #define ZEND_FE_END { NULL, NULL, NULL, 0, 0 } 6 | #endif 7 | 8 | #ifndef Z_SET_REFCOUNT_P 9 | #define Z_SET_REFCOUNT_P(pz, rc) ((pz)->refcount = rc) 10 | #endif 11 | 12 | #ifndef Z_UNSET_ISREF_PP 13 | #define Z_UNSET_ISREF_PP(ppz) Z_UNSET_ISREF_P(*(ppz)) 14 | #endif 15 | 16 | #ifndef Z_UNSET_ISREF_P 17 | #define Z_UNSET_ISREF_P(pz) ((pz)->is_ref = 0) 18 | #endif 19 | 20 | #ifndef Z_ISREF_PP 21 | #define Z_ISREF_PP(ppz) Z_ISREF_P(*(ppz)) 22 | #endif 23 | 24 | #ifndef Z_ISREF_P 25 | #if ZEND_MODULE_API_NO >= 20090626 26 | #define Z_ISREF_P(pz) zval_isref_p(pz) 27 | #else 28 | #define Z_ISREF_P(pz) ((pz)->is_ref) 29 | #endif 30 | #endif 31 | 32 | #ifndef Z_ADDREF_PP 33 | #define Z_ADDREF_PP(ppz) Z_ADDREF_P(*(ppz)) 34 | #endif 35 | 36 | #ifndef Z_ADDREF_P 37 | #if ZEND_MODULE_API_NO >= 20090626 38 | #define Z_ADDREF_P(pz) zval_addref_p(pz) 39 | #else 40 | #define Z_ADDREF_P(pz) (++(pz)->refcount) 41 | #endif 42 | #endif 43 | 44 | #ifndef Z_SET_ISREF_PP 45 | #define Z_SET_ISREF_PP(ppz) Z_SET_ISREF_P(*(ppz)) 46 | #endif 47 | 48 | #ifndef Z_SET_ISREF_P 49 | #if ZEND_MODULE_API_NO >= 20090626 50 | #define Z_SET_ISREF_P(pz) zval_set_isref_p(pz) 51 | #else 52 | #define Z_SET_ISREF_P(pz) ((pz)->is_ref = 1) 53 | #endif 54 | #endif 55 | 56 | #ifndef array_init_size 57 | #define array_init_size(arg, size) _array_init((arg) ZEND_FILE_LINE_CC) 58 | #endif 59 | 60 | #ifndef zend_parse_parameters_none 61 | #define zend_parse_parameters_none() \ 62 | zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") 63 | #endif 64 | 65 | #endif /* PHP_VERDEP_H */ 66 | -------------------------------------------------------------------------------- /util/common.h: -------------------------------------------------------------------------------- 1 | #ifndef HANDLERSOCKET_COMMON_H 2 | #define HANDLERSOCKET_COMMON_H 3 | 4 | #define HS_PROTOCOL_OPEN "P" 5 | #define HS_PROTOCOL_AUTH "A" 6 | #define HS_PROTOCOL_INSERT "+" 7 | #define HS_PROTOCOL_FILTER "F" 8 | #define HS_PROTOCOL_WHILE "W" 9 | #define HS_PROTOCOL_IN "@" 10 | 11 | #define HS_FIND_EQUAL "=" 12 | #define HS_FIND_LESS "<" 13 | #define HS_FIND_LESS_EQUAL "<=" 14 | #define HS_FIND_GREATER ">" 15 | #define HS_FIND_GREATER_EQUAL ">=" 16 | 17 | #define HS_MODIFY_UPDATE "U" 18 | #define HS_MODIFY_INCREMENT "+" 19 | #define HS_MODIFY_DECREMENT "-" 20 | #define HS_MODIFY_REMOVE "D" 21 | #define HS_MODIFY_GET_UPDATE "U?" 22 | #define HS_MODIFY_GET_INCREMENT "+?" 23 | #define HS_MODIFY_GET_DECREMENT "-?" 24 | #define HS_MODIFY_GET_REMOVE "D?" 25 | 26 | #define HS_CODE_NULL 0x00 27 | #define HS_CODE_DELIMITER 0x09 28 | #define HS_CODE_EOL 0x0a 29 | #define HS_CODE_ESCAPE 0x10 30 | #define HS_CODE_ESCAPE_PREFIX 0x01 31 | #define HS_CODE_ESCAPE_ADD 0x40 32 | 33 | #endif /* HANDLERSOCKET_COMMON_H */ 34 | -------------------------------------------------------------------------------- /util/request.c: -------------------------------------------------------------------------------- 1 | 2 | #include "php.h" 3 | #include "php_network.h" 4 | 5 | #include "common.h" 6 | #include "request.h" 7 | 8 | static inline void 9 | hs_request_zval_scalar(smart_str *buf, zval *val, int delim) 10 | { 11 | switch (Z_TYPE_P(val)) { 12 | case IS_LONG: 13 | hs_request_long(buf, Z_LVAL_P(val)); 14 | break; 15 | case IS_STRING: 16 | hs_request_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val)); 17 | break; 18 | case IS_DOUBLE: 19 | convert_to_string(val); 20 | hs_request_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val)); 21 | break; 22 | case IS_BOOL: 23 | convert_to_long(val); 24 | hs_request_long(buf, Z_LVAL_P(val)); 25 | break; 26 | case IS_NULL: 27 | hs_request_null(buf); 28 | break; 29 | default: 30 | //IS_ARRAY 31 | //IS_OBJECT 32 | //IS_RESOURCE 33 | hs_request_long(buf, 0); 34 | break; 35 | } 36 | 37 | if (delim > 0) { 38 | hs_request_delim(buf); 39 | } 40 | } 41 | 42 | void 43 | hs_request_string(smart_str *buf, char *str, long str_len) 44 | { 45 | long i; 46 | 47 | if (str_len <= 0) { 48 | return; 49 | } else { 50 | for (i = 0; i < str_len; i++) { 51 | if ((unsigned char)str[i] > HS_CODE_ESCAPE) { 52 | smart_str_appendc(buf, str[i]); 53 | } else { 54 | smart_str_appendc(buf, HS_CODE_ESCAPE_PREFIX); 55 | smart_str_appendc(buf, (unsigned char)str[i]+HS_CODE_ESCAPE_ADD); 56 | } 57 | } 58 | } 59 | } 60 | 61 | void 62 | hs_request_array(smart_str *buf, HashTable *ht, int num, int i TSRMLS_DC) 63 | { 64 | long n; 65 | HashPosition pos; 66 | zval **data; 67 | 68 | n = zend_hash_num_elements(ht); 69 | if (i > 0 && i < n) { 70 | n = i; 71 | } 72 | 73 | if (n == 0) { 74 | if (num == 1) { 75 | hs_request_long(buf, 1); 76 | hs_request_delim(buf); 77 | } 78 | hs_request_null(buf); 79 | return; 80 | } 81 | 82 | if (num == 1) { 83 | hs_request_long(buf, n); 84 | hs_request_delim(buf); 85 | } 86 | 87 | zend_hash_internal_pointer_reset_ex(ht, &pos); 88 | while (zend_hash_get_current_data_ex(ht, (void **)&data, &pos) == SUCCESS) { 89 | if (n <= 0) { 90 | break; 91 | } 92 | n--; 93 | hs_request_zval_scalar(buf, *data, n); 94 | zend_hash_move_forward_ex(ht, &pos); 95 | } 96 | } 97 | 98 | void 99 | hs_request_filter(smart_str *request, HashTable *ht TSRMLS_DC) 100 | { 101 | zval **tmp; 102 | HashPosition pos; 103 | long n, i = 0; 104 | 105 | n = zend_hash_num_elements(ht); 106 | if (n >= 0) { 107 | hs_request_delim(request); 108 | 109 | zend_hash_internal_pointer_reset_ex(ht, &pos); 110 | while (zend_hash_get_current_data_ex(ht, 111 | (void **)&tmp, &pos) == SUCCESS) { 112 | switch ((*tmp)->type) { 113 | case IS_STRING: 114 | hs_request_string(request, Z_STRVAL_PP(tmp), 115 | Z_STRLEN_PP(tmp)); 116 | break; 117 | case IS_LONG: 118 | hs_request_long(request, Z_LVAL_PP(tmp)); 119 | break; 120 | default: 121 | convert_to_string(*tmp); 122 | hs_request_string(request, Z_STRVAL_PP(tmp), 123 | Z_STRLEN_PP(tmp)); 124 | break; 125 | } 126 | 127 | if (++i != n) { 128 | hs_request_string(request, ",", strlen(",")); 129 | } 130 | 131 | zend_hash_move_forward_ex(ht, &pos); 132 | } 133 | } 134 | } 135 | 136 | void 137 | hs_request_command(smart_str *buf, long id, zval * operate, zval *criteria, 138 | long limit, long offset, zval *filters, long in_key, 139 | zval *in_values TSRMLS_DC) 140 | { 141 | hs_request_long(buf, id); 142 | hs_request_delim(buf); 143 | 144 | convert_to_string(operate); 145 | hs_request_string(buf, Z_STRVAL_P(operate), Z_STRLEN_P(operate)); 146 | hs_request_delim(buf); 147 | 148 | if (Z_TYPE_P(criteria) == IS_ARRAY) { 149 | hs_request_array(buf, HASH_OF(criteria), 1, -1 TSRMLS_CC); 150 | } else { 151 | hs_request_long(buf, 1); 152 | hs_request_delim(buf); 153 | hs_request_zval_scalar(buf, criteria, 0); 154 | } 155 | 156 | hs_request_delim(buf); 157 | hs_request_long(buf, limit); 158 | 159 | hs_request_delim(buf); 160 | hs_request_long(buf, offset); 161 | 162 | if (in_key >= 0 && in_values != NULL) { 163 | hs_request_delim(buf); 164 | 165 | hs_request_string(buf, HS_PROTOCOL_IN, 1); 166 | hs_request_delim(buf); 167 | 168 | hs_request_long(buf, in_key); 169 | hs_request_delim(buf); 170 | 171 | if (Z_TYPE_P(in_values) == IS_ARRAY) { 172 | hs_request_array(buf, HASH_OF(in_values), 1, -1 TSRMLS_CC); 173 | } else { 174 | hs_request_zval_scalar(buf, in_values, 0); 175 | } 176 | } 177 | 178 | if (filters != NULL && Z_TYPE_P(filters) == IS_ARRAY) { 179 | HashTable *ht; 180 | HashPosition pos; 181 | zval **tmp; 182 | 183 | ht = HASH_OF(filters); 184 | 185 | zend_hash_internal_pointer_reset_ex(ht, &pos); 186 | while (zend_hash_get_current_data_ex(ht, (void **)&tmp, 187 | &pos) == SUCCESS) { 188 | if (Z_TYPE_PP(tmp) != IS_ARRAY || 189 | zend_hash_num_elements(HASH_OF(*tmp)) < 4) { 190 | zend_hash_move_forward_ex(ht, &pos); 191 | continue; 192 | } 193 | 194 | hs_request_delim(buf); 195 | 196 | hs_request_array(buf, HASH_OF(*tmp), -1, 4 TSRMLS_CC); 197 | 198 | zend_hash_move_forward_ex(ht, &pos); 199 | } 200 | } 201 | } 202 | 203 | int 204 | hs_request_command_modify(smart_str *buf, zval *update, 205 | zval *values, long field TSRMLS_DC) 206 | { 207 | int ret = -1; 208 | long len; 209 | 210 | if (update == NULL || Z_TYPE_P(update) != IS_STRING) { 211 | return -1; 212 | } 213 | 214 | len = Z_STRLEN_P(update); 215 | if (len == 1) { 216 | ret = 1; 217 | } else if (len == 2) { 218 | ret = 0; 219 | } else { 220 | return -1; 221 | } 222 | 223 | if (values == NULL) { 224 | hs_request_delim(buf); 225 | hs_request_string(buf, Z_STRVAL_P(update), Z_STRLEN_P(update)); 226 | 227 | hs_request_delim(buf); 228 | hs_request_null(buf); 229 | } else if (Z_TYPE_P(values) == IS_ARRAY) { 230 | if (field > 0 && 231 | zend_hash_num_elements(HASH_OF(values)) < field) { 232 | return -1; 233 | } 234 | 235 | hs_request_delim(buf); 236 | hs_request_string(buf, Z_STRVAL_P(update), Z_STRLEN_P(update)); 237 | 238 | hs_request_delim(buf); 239 | hs_request_array(buf, HASH_OF(values), 0, -1 TSRMLS_CC); 240 | } else { 241 | if (field > 0 && field != 1) { 242 | return -1; 243 | } 244 | 245 | hs_request_delim(buf); 246 | hs_request_string(buf, Z_STRVAL_P(update), Z_STRLEN_P(update)); 247 | 248 | hs_request_delim(buf); 249 | hs_request_zval_scalar(buf, values, 0); 250 | } 251 | 252 | return ret; 253 | } 254 | 255 | long 256 | hs_request_send(php_stream *stream, smart_str *request TSRMLS_DC) 257 | { 258 | #ifdef HS_DEBUG 259 | long i; 260 | smart_str debug = {0}; 261 | if (request->len <= 0) { 262 | return -1; 263 | } 264 | for (i = 0; i < request->len; i++) { 265 | if ((unsigned char)request->c[i] == HS_CODE_NULL) { 266 | smart_str_appendl_ex(&debug, "\\0", strlen("\\0"), 1); 267 | } else { 268 | smart_str_appendc(&debug, request->c[i]); 269 | } 270 | } 271 | smart_str_0(&debug); 272 | php_printf("[handlersocket] (request) %ld : \"%s\"\n", 273 | request->len, debug.c); 274 | smart_str_free(&debug); 275 | #endif 276 | 277 | if (!stream) { 278 | return -1; 279 | } 280 | 281 | return php_stream_write(stream, request->c, request->len); 282 | } 283 | -------------------------------------------------------------------------------- /util/request.h: -------------------------------------------------------------------------------- 1 | #ifndef HANDLERSOCKET_REQUEST_H 2 | #define HANDLERSOCKET_REQUEST_H 3 | 4 | #include "ext/standard/php_smart_str.h" 5 | #include "php_streams.h" 6 | 7 | #define hs_request_long(buf, num) smart_str_append_long(buf, num) 8 | #define hs_request_null(buf) smart_str_appendc(buf, HS_CODE_NULL) 9 | #define hs_request_delim(buf) smart_str_appendc(buf, HS_CODE_DELIMITER) 10 | #define hs_request_next(buf) smart_str_appendc(buf, HS_CODE_EOL) 11 | 12 | void hs_request_string(smart_str *buf, char *str, long str_len); 13 | 14 | void hs_request_array(smart_str *buf, HashTable *ht, int num, int i TSRMLS_DC); 15 | void hs_request_filter(smart_str *request, HashTable *ht TSRMLS_DC); 16 | 17 | void hs_request_command(smart_str *buf, long id, zval * operate, zval *criteria, 18 | long limit, long offset, zval *filters, long in_key, 19 | zval *in_values TSRMLS_DC); 20 | int hs_request_command_modify(smart_str *buf, zval *update, 21 | zval *values, long field TSRMLS_DC); 22 | 23 | long hs_request_send(php_stream *stream, smart_str *request TSRMLS_DC); 24 | 25 | #endif /* HANDLERSOCKET_REQUEST_H */ 26 | -------------------------------------------------------------------------------- /util/response.c: -------------------------------------------------------------------------------- 1 | 2 | #include "php.h" 3 | #include "php_network.h" 4 | #include "ext/standard/php_smart_str.h" 5 | 6 | #include "common.h" 7 | #include "response.h" 8 | 9 | #define HS_SOCKET_BLOCK_SIZE 4096 10 | 11 | #ifndef PHP_WIN32 12 | #define php_select(m, r, w, e, t) select(m, r, w, e, t) 13 | #else 14 | #include "win32/select.h" 15 | #endif 16 | 17 | static inline long 18 | hs_response_select(php_stream *stream, long timeout TSRMLS_DC) 19 | { 20 | php_socket_t max_fd = 0; 21 | int retval, max_set_count = 0; 22 | struct timeval tv; 23 | struct timeval *tv_p = NULL; 24 | fd_set fds; 25 | 26 | FD_ZERO(&fds); 27 | 28 | if (php_stream_cast(stream, 29 | PHP_STREAM_AS_FD_FOR_SELECT|PHP_STREAM_CAST_INTERNAL, 30 | (void*)&max_fd, 1) == SUCCESS && max_fd != -1) { 31 | PHP_SAFE_FD_SET(max_fd, &fds); 32 | max_set_count++; 33 | } 34 | 35 | PHP_SAFE_MAX_FD(max_fd, max_set_count); 36 | 37 | if (timeout > 0) { 38 | tv.tv_sec = timeout; 39 | tv.tv_usec = 0; 40 | tv_p = &tv; 41 | } 42 | 43 | retval = php_select(max_fd+1, &fds, NULL, NULL, tv_p); 44 | if (retval == -1) { 45 | zend_error(E_WARNING, "[HandlerSocket] unable to select"); 46 | return -1; 47 | } 48 | 49 | if (!PHP_SAFE_FD_ISSET(max_fd, &fds)) { 50 | return -1; 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | static inline long 57 | hs_response_recv(php_stream *stream, char *recv, size_t size TSRMLS_DC) 58 | { 59 | long ret; 60 | #ifdef HS_DEBUG 61 | long i; 62 | smart_str debug = {0}; 63 | #endif 64 | 65 | ret = php_stream_read(stream, recv, size); 66 | if (ret <= 0) { 67 | return -1; 68 | } 69 | recv[size] = '\0'; 70 | 71 | #ifdef HS_DEBUG 72 | for (i = 0; i < ret; i++) { 73 | if ((unsigned char)recv[i] == HS_CODE_NULL) { 74 | smart_str_appendl_ex(&debug, "\\0", strlen("\\0"), 1); 75 | } else { 76 | smart_str_appendc(&debug, recv[i]); 77 | } 78 | } 79 | smart_str_0(&debug); 80 | php_printf("[handlersocket] (recv) %ld : \"%s\"", ret, debug.c); 81 | smart_str_free(&debug); 82 | #endif 83 | 84 | return ret; 85 | } 86 | 87 | static inline zval 88 | *hs_response_add(zval *return_value TSRMLS_DC) 89 | { 90 | zval *value; 91 | MAKE_STD_ZVAL(value); 92 | array_init(value); 93 | add_next_index_zval(return_value, value); 94 | return value; 95 | } 96 | 97 | static inline zval 98 | *hs_response_zval(smart_str *buf TSRMLS_DC) 99 | { 100 | zval *val; 101 | MAKE_STD_ZVAL(val); 102 | ZVAL_STRINGL(val, buf->c, buf->len, 1); 103 | return val; 104 | } 105 | 106 | void 107 | hs_response_value(php_stream *stream, long timeout, zval *return_value, 108 | zval *error, int modify TSRMLS_DC) 109 | { 110 | char *recv; 111 | long i, j, len; 112 | zval *val, *item; 113 | 114 | smart_str response = {0}; 115 | long n = 0, block_size = HS_SOCKET_BLOCK_SIZE; 116 | int escape = 0, flag = 0, null = 0; 117 | long ret[2] = {-1, -1}; 118 | 119 | if (hs_response_select(stream, timeout TSRMLS_CC) < 0) { 120 | ZVAL_BOOL(return_value, 0); 121 | } 122 | 123 | recv = emalloc(block_size+1); 124 | len = hs_response_recv(stream, recv, block_size TSRMLS_CC); 125 | if (len <= 0) { 126 | efree(recv); 127 | ZVAL_BOOL(return_value, 0); 128 | return; 129 | } 130 | 131 | do { 132 | for (i = 0; i < len; i++) { 133 | if (recv[i] == HS_CODE_DELIMITER || recv[i] == HS_CODE_EOL) { 134 | val = hs_response_zval(&response TSRMLS_CC); 135 | convert_to_long(val); 136 | ret[flag] = Z_LVAL_P(val); 137 | flag++; 138 | zval_ptr_dtor(&val); 139 | smart_str_free(&response); 140 | } else { 141 | smart_str_appendc(&response, recv[i]); 142 | } 143 | 144 | if (flag > 1) { 145 | break; 146 | } 147 | } 148 | 149 | if (flag > 1) { 150 | break; 151 | } else { 152 | i = 0; 153 | len = hs_response_recv(stream, recv, block_size TSRMLS_CC); 154 | if (len <= 0) { 155 | break; 156 | } 157 | } 158 | } while (1); 159 | 160 | if (ret[0] != 0) { 161 | if (recv[i] != HS_CODE_EOL) { 162 | smart_str err = {0}; 163 | 164 | i++; 165 | 166 | if (i > len) { 167 | i = 0; 168 | len = -1; 169 | } 170 | 171 | do { 172 | for (j = i; j < len; j++) { 173 | if (recv[j] == HS_CODE_EOL) { 174 | break; 175 | } 176 | 177 | if (recv[j] == HS_CODE_ESCAPE_PREFIX) { 178 | escape = 1; 179 | } else if (escape) { 180 | escape = 0; 181 | smart_str_appendc( 182 | &err, (unsigned char)recv[j]-HS_CODE_ESCAPE_ADD); 183 | } else { 184 | smart_str_appendc(&err, recv[j]); 185 | } 186 | } 187 | 188 | if (recv[j] == HS_CODE_EOL) { 189 | break; 190 | } 191 | 192 | i = 0; 193 | } while ((len = hs_response_recv( 194 | stream, recv, block_size TSRMLS_CC)) > 0); 195 | 196 | if (error) { 197 | ZVAL_STRINGL(error, err.c, err.len, 1); 198 | } 199 | 200 | smart_str_free(&err); 201 | } else if (error) { 202 | ZVAL_NULL(error); 203 | } 204 | 205 | efree(recv); 206 | ZVAL_BOOL(return_value, 0); 207 | 208 | return; 209 | } 210 | 211 | if (ret[1] == 1 && recv[i] == HS_CODE_EOL) { 212 | efree(recv); 213 | ZVAL_BOOL(return_value, 1); 214 | return; 215 | } 216 | 217 | i++; 218 | 219 | if (i > len) { 220 | i = 0; 221 | len = -1; 222 | } 223 | 224 | if (modify) { 225 | if (i > 0 && recv[i-1] == HS_CODE_EOL) { 226 | efree(recv); 227 | ZVAL_LONG(return_value, 0); 228 | return; 229 | } 230 | 231 | do { 232 | for (j = i; j < len; j++) { 233 | if (recv[j] == HS_CODE_EOL) { 234 | ZVAL_STRINGL(return_value, response.c, response.len, 1); 235 | break; 236 | } 237 | 238 | if (recv[j] == HS_CODE_ESCAPE_PREFIX) { 239 | escape = 1; 240 | } else if (escape) { 241 | escape = 0; 242 | smart_str_appendc( 243 | &response, (unsigned char)recv[j]-HS_CODE_ESCAPE_ADD); 244 | } else { 245 | smart_str_appendc(&response, recv[j]); 246 | } 247 | } 248 | 249 | if (recv[j] == HS_CODE_EOL) { 250 | break; 251 | } 252 | i = 0; 253 | } while ((len = hs_response_recv( 254 | stream, recv, block_size TSRMLS_CC)) > 0); 255 | 256 | convert_to_long(return_value); 257 | } else { 258 | array_init(return_value); 259 | 260 | if (i > 0 && recv[i-1] == HS_CODE_EOL) { 261 | efree(recv); 262 | return; 263 | } 264 | 265 | item = hs_response_add(return_value TSRMLS_CC); 266 | 267 | do { 268 | for (j = i; j < len; j++) { 269 | if (recv[j] == HS_CODE_DELIMITER) { 270 | if (response.len == 0 && null == 1) { 271 | add_next_index_null(item); 272 | } else { 273 | add_next_index_stringl(item, response.c, 274 | response.len, 1); 275 | } 276 | 277 | n++; 278 | null = 0; 279 | if (n == ret[1]) { 280 | item = hs_response_add(return_value TSRMLS_CC); 281 | n = 0; 282 | } 283 | 284 | smart_str_free(&response); 285 | 286 | continue; 287 | } else if (recv[j] == HS_CODE_EOL) { 288 | if (response.len == 0 && null == 1) { 289 | add_next_index_null(item); 290 | } else { 291 | add_next_index_stringl(item, response.c, 292 | response.len, 1); 293 | } 294 | null = 0; 295 | break; 296 | } 297 | 298 | if (recv[j] == HS_CODE_ESCAPE_PREFIX) { 299 | escape = 1; 300 | } else if (escape) { 301 | escape = 0; 302 | smart_str_appendc( 303 | &response, (unsigned char)recv[j]-HS_CODE_ESCAPE_ADD); 304 | } else if (recv[j] == HS_CODE_NULL) { 305 | null = 1; 306 | } else { 307 | smart_str_appendc(&response, recv[j]); 308 | } 309 | } 310 | 311 | if (recv[j] == HS_CODE_EOL) { 312 | break; 313 | } 314 | i = 0; 315 | } while ((len = hs_response_recv( 316 | stream, recv, block_size TSRMLS_CC)) > 0); 317 | } 318 | 319 | efree(recv); 320 | 321 | smart_str_free(&response); 322 | } 323 | 324 | void 325 | hs_response_multi(php_stream *stream, long timeout, zval *return_value, 326 | zval *error, zval *mreq TSRMLS_DC) 327 | { 328 | char *recv; 329 | long i, len, count; 330 | long current = 0; 331 | smart_str response = {0}; 332 | long block_size = HS_SOCKET_BLOCK_SIZE; 333 | 334 | if (hs_response_select(stream, timeout TSRMLS_CC) < 0) { 335 | ZVAL_BOOL(return_value, 0); 336 | } 337 | 338 | recv = emalloc(block_size+1); 339 | len = hs_response_recv(stream, recv, block_size TSRMLS_CC); 340 | if (len <= 0) { 341 | efree(recv); 342 | RETVAL_BOOL(0); 343 | } 344 | 345 | count = zend_hash_num_elements(HASH_OF(mreq)); 346 | 347 | array_init(return_value); 348 | 349 | array_init(error); 350 | 351 | for(i = 0; i < count; i++) { 352 | long j, k; 353 | zval *rval, *item, *val, **tmp; 354 | 355 | int flag = 0, escape = 0, null = 0; 356 | long n = 0, modify = 0; 357 | long ret[2] = {-1, -1}; 358 | 359 | if (zend_hash_index_find(HASH_OF(mreq), i, (void **)&tmp) == SUCCESS) { 360 | modify = Z_LVAL_PP(tmp); 361 | } 362 | 363 | smart_str_free(&response); 364 | 365 | do { 366 | for (j = current; j < len; j++) { 367 | if (recv[j] == HS_CODE_DELIMITER || recv[j] == HS_CODE_EOL) { 368 | rval = hs_response_zval(&response TSRMLS_CC); 369 | convert_to_long(rval); 370 | ret[flag] = Z_LVAL_P(rval); 371 | flag++; 372 | zval_ptr_dtor(&rval); 373 | smart_str_free(&response); 374 | } else { 375 | smart_str_appendc(&response, recv[j]); 376 | } 377 | 378 | if (flag > 1) { 379 | break; 380 | } 381 | } 382 | 383 | if (flag > 1) { 384 | break; 385 | } else { 386 | j = 0; 387 | current = 0; 388 | len = hs_response_recv(stream, recv, block_size TSRMLS_CC); 389 | if (len <= 0) { 390 | break; 391 | } 392 | } 393 | } while (1); 394 | 395 | if (ret[0] != 0) { 396 | if (recv[j] != HS_CODE_EOL) { 397 | smart_str err = {0}; 398 | 399 | j++; 400 | 401 | if (j > len) { 402 | j = 0; 403 | current = 0; 404 | len = -1; 405 | } 406 | 407 | do { 408 | for (k = j; k < len; k++) { 409 | if (recv[k] == HS_CODE_EOL) { 410 | break; 411 | } 412 | 413 | if (recv[k] == HS_CODE_ESCAPE_PREFIX) { 414 | escape = 1; 415 | } else if (escape) { 416 | escape = 0; 417 | smart_str_appendc( 418 | &err, 419 | (unsigned char)recv[k] - HS_CODE_ESCAPE_ADD); 420 | } else { 421 | smart_str_appendc(&err, recv[k]); 422 | } 423 | } 424 | 425 | if (recv[k] == HS_CODE_EOL) { 426 | current = k; 427 | break; 428 | } 429 | 430 | j = 0; 431 | current = 0; 432 | 433 | } while ((len = hs_response_recv( 434 | stream, recv, block_size TSRMLS_CC)) > 0); 435 | 436 | add_next_index_stringl(error, err.c, err.len, 1); 437 | 438 | smart_str_free(&err); 439 | } else { 440 | add_next_index_null(error); 441 | } 442 | 443 | add_next_index_bool(return_value, 0); 444 | 445 | current++; 446 | 447 | continue; 448 | } 449 | 450 | add_next_index_null(error); 451 | 452 | if (ret[1] == 1 && recv[j] == HS_CODE_EOL) { 453 | add_next_index_bool(return_value, 1); 454 | 455 | current = j + 1; 456 | 457 | continue; 458 | } 459 | 460 | j++; 461 | 462 | if (j > len) { 463 | j = 0; 464 | current = 0; 465 | len = -1; 466 | } 467 | 468 | if (modify) { 469 | zval *num_z; 470 | 471 | if (j > 0 && recv[j-1] == HS_CODE_EOL) { 472 | current = j; 473 | 474 | add_next_index_long(return_value, 0); 475 | 476 | continue; 477 | } 478 | 479 | MAKE_STD_ZVAL(num_z); 480 | 481 | do { 482 | for (k = j; k < len; k++) { 483 | if (recv[k] == HS_CODE_EOL) { 484 | ZVAL_STRINGL(num_z, response.c, response.len, 1); 485 | break; 486 | } 487 | 488 | if (recv[k] == HS_CODE_ESCAPE_PREFIX) { 489 | escape = 1; 490 | } else if (escape) { 491 | escape = 0; 492 | smart_str_appendc( 493 | &response, 494 | (unsigned char)recv[k] - HS_CODE_ESCAPE_ADD); 495 | } else { 496 | smart_str_appendc(&response, recv[k]); 497 | } 498 | } 499 | 500 | if (recv[k] == HS_CODE_EOL) { 501 | current = k; 502 | break; 503 | } 504 | 505 | j = 0; 506 | current = 0; 507 | 508 | } while ((len = hs_response_recv( 509 | stream, recv, block_size TSRMLS_CC)) > 0); 510 | 511 | convert_to_long(num_z); 512 | 513 | add_next_index_long(return_value, Z_LVAL_P(num_z)); 514 | 515 | zval_ptr_dtor(&num_z); 516 | } else { 517 | item = hs_response_add(return_value TSRMLS_CC); 518 | 519 | if (j > 0 && recv[j-1] == HS_CODE_EOL) { 520 | current = j; 521 | continue; 522 | } 523 | 524 | val = hs_response_add(item TSRMLS_CC); 525 | 526 | do { 527 | for (k = j; k < len; k++) { 528 | if (recv[k] == HS_CODE_DELIMITER) { 529 | if (response.len == 0 && null == 1) { 530 | add_next_index_null(val); 531 | } else { 532 | add_next_index_stringl(val, response.c, 533 | response.len, 1); 534 | } 535 | 536 | null = 0; 537 | n++; 538 | if (n == ret[1]) { 539 | val = hs_response_add(item TSRMLS_CC); 540 | n = 0; 541 | } 542 | 543 | smart_str_free(&response); 544 | 545 | continue; 546 | } else if (recv[k] == HS_CODE_EOL) { 547 | if (response.len == 0 && null == 1) { 548 | add_next_index_null(val); 549 | } else { 550 | add_next_index_stringl(val, response.c, 551 | response.len, 1); 552 | } 553 | null = 0; 554 | break; 555 | } 556 | 557 | if (recv[k] == HS_CODE_ESCAPE_PREFIX) { 558 | escape = 1; 559 | } else if (escape) { 560 | escape = 0; 561 | smart_str_appendc( 562 | &response, 563 | (unsigned char)recv[k] - HS_CODE_ESCAPE_ADD); 564 | } else if (recv[k] == HS_CODE_NULL) { 565 | null = 1; 566 | } else { 567 | smart_str_appendc(&response, recv[k]); 568 | } 569 | } 570 | 571 | if (recv[k] == HS_CODE_EOL) { 572 | current = k; 573 | break; 574 | } 575 | 576 | j = 0; 577 | current = 0; 578 | 579 | } while ((len = hs_response_recv( 580 | stream, recv, block_size TSRMLS_CC)) > 0); 581 | } 582 | 583 | current++; 584 | } 585 | 586 | efree(recv); 587 | 588 | smart_str_free(&response); 589 | } 590 | -------------------------------------------------------------------------------- /util/response.h: -------------------------------------------------------------------------------- 1 | #ifndef HANDLERSOCKET_RESPONSE_H 2 | #define HANDLERSOCKET_RESPONSE_H 3 | 4 | #include "php_streams.h" 5 | 6 | #define HS_CODE_NULL 0x00 7 | #define HS_CODE_DELIMITER 0x09 8 | #define HS_CODE_EOL 0x0a 9 | #define HS_CODE_ESCAPE 0x10 10 | #define HS_CODE_ESCAPE_PREFIX 0x01 11 | #define HS_CODE_ESCAPE_ADD 0x40 12 | 13 | void hs_response_value(php_stream *stream, long timeout, zval *return_value, 14 | zval *error, int modify TSRMLS_DC); 15 | void hs_response_multi(php_stream *stream, long timeout, zval *return_value, 16 | zval *error, zval *mreq TSRMLS_DC); 17 | 18 | #endif /* HANDLERSOCKET_RESPONSE_H */ 19 | --------------------------------------------------------------------------------