From 5f2d3003d0c52601623a0f1b812a085c128095d7 Mon Sep 17 00:00:00 2001 From: Konstantin Shulgin <konstantin.shulgin@gmail.com> Date: Fri, 16 Dec 2011 15:08:38 +0400 Subject: [PATCH] feature-php-driver-improve: initial implementarion of new php driver. --- connector/php/exampleCall.php | 37 - connector/php/exampleInsert.php | 66 - connector/php/exampleSelect.php | 100 - connector/php/exampleUpdate.php | 98 - connector/php/tarantool.c | 3232 ++++++++--------- connector/php/tarantool.h | 199 +- connector/php/test/admin.phpt | 112 + connector/php/test/bin/run-test.bash | 204 ++ connector/php/test/call.phpt | 93 + connector/php/test/delete.phpt | 125 + connector/php/test/errors.phpt | 26 + connector/php/test/etc/php.ini | 1851 ++++++++++ connector/php/test/etc/tarantool_box.cfg | 55 + connector/php/test/insert.phpt | 173 + connector/php/test/lib/lua/test.lua | 25 + .../php/test/lib/php/tarantool_utest.php | 183 + connector/php/test/run-test | 1 + connector/php/test/select.phpt | 346 ++ connector/php/test/update_fields.phpt | 96 + 19 files changed, 4986 insertions(+), 2036 deletions(-) delete mode 100644 connector/php/exampleCall.php delete mode 100644 connector/php/exampleInsert.php delete mode 100644 connector/php/exampleSelect.php delete mode 100644 connector/php/exampleUpdate.php create mode 100644 connector/php/test/admin.phpt create mode 100755 connector/php/test/bin/run-test.bash create mode 100644 connector/php/test/call.phpt create mode 100644 connector/php/test/delete.phpt create mode 100644 connector/php/test/errors.phpt create mode 100644 connector/php/test/etc/php.ini create mode 100644 connector/php/test/etc/tarantool_box.cfg create mode 100644 connector/php/test/insert.phpt create mode 100644 connector/php/test/lib/lua/test.lua create mode 100644 connector/php/test/lib/php/tarantool_utest.php create mode 120000 connector/php/test/run-test create mode 100644 connector/php/test/select.phpt create mode 100644 connector/php/test/update_fields.phpt diff --git a/connector/php/exampleCall.php b/connector/php/exampleCall.php deleted file mode 100644 index d02a7dda72..0000000000 --- a/connector/php/exampleCall.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php - -define("NMSPACE", 0); - -if(!extension_loaded('tarantool')) { - dl('tarantool.so'); -} - -/** - * Tarantool::constructor - * - * @param optional string host default 127.0.0.1 - * @param optional number port default 33013 - */ -$tnt = new Tarantool('localhost'); - -/** - * Tarantool::call - * - * @param procname procedure namei - * @param array procedure argumetns - * - * @return count of tuples - */ -$tuple = array('test', 'x', 'abd', 1023); - -$res = $tnt->insert(NMSPACE, $tuple); - -$tuple = array(NMSPACE, 0, 'test'); - -$res = $tnt->call("box.select", $tuple); - -var_dump($res); - -while(($res = $tnt->getTuple()) != false) { - var_dump($res); -} diff --git a/connector/php/exampleInsert.php b/connector/php/exampleInsert.php deleted file mode 100644 index 2766fd65ed..0000000000 --- a/connector/php/exampleInsert.php +++ /dev/null @@ -1,66 +0,0 @@ -<?php -if(!extension_loaded('tarantool')) { - dl('tarantool.so'); -} - -define("NMSPACE", 0); - -$tnt = new Tarantool('tfn24'); -$res=0; - -/** - * Tarantool::insert - * - * @param namespace - * @param array of tuple - * - * @return result - */ - - -$tuple = array(1, 'x','abd', 1023 ); -$res += $tnt->insert(NMSPACE, $tuple); - -$tuple = array(2, 'z','abd', 1023 ); -$res += $tnt->insert(NMSPACE,$tuple); - -$tuple = array(3, 'z','abc', 1025 ); -$res += $tnt->insert(NMSPACE,$tuple); - -$tuple = array(4, 'y','abd', 1025 ); -$res += $tnt->insert(NMSPACE,$tuple); - -$tuple = array(5, 'y','abc', 1025 ); -$res += $tnt->insert(NMSPACE,$tuple); - -$tuple = array(6, 'x','abd', 1025 ); -$res += $tnt->insert(NMSPACE,$tuple); - -$tuple = array(7, 'x','abc', 1025 ); -$res += $tnt->insert(NMSPACE,$tuple); - -$tuple = array(8, 'x','abd', 1025 ); -$res += $tnt->insert(NMSPACE,$tuple); - -$tuple = array(9, 'x','abc', 1024 ); -$res += $tnt->insert(NMSPACE,$tuple); - -$tuple = array(9, 'x','abc', 1024 ); -$res += $tnt->insert(NMSPACE,$tuple); -echo "inserted $res tuples\n"; - -$tuple = array('9', 66,65, 1024 ); -$res = $tnt->insert(NMSPACE,$tuple); -if (!$res) - echo $tnt->getError(); -else - echo "inserted $res tuples\n"; - -$tuple = array(10, 66,65, 'xdf' ); -$res = $tnt->insert(NMSPACE,$tuple); - -if (!$res) - echo $tnt->getError(); -else - echo "inserted $res tuples\n"; - \ No newline at end of file diff --git a/connector/php/exampleSelect.php b/connector/php/exampleSelect.php deleted file mode 100644 index f3b3c1c58f..0000000000 --- a/connector/php/exampleSelect.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php - -define("NMSPACE", 0); -define("PRIMARYINDEX", 0); -define("INDEX_1", 1); -define("INDEX_2", 2); -define("INDEX_3", 3); - - -if(!extension_loaded('tarantool')) { - dl('tarantool.so'); -} - -$res = true; - -/** - * Tarantool::constructor - * - * @param optional string host default 127.0.0.1 - * @param optional number port default 33013 - */ -$tnt = new Tarantool('tfn24'); - -echo 'single tuple select by primary key (key=1)', PHP_EOL; - -/** - * Tarantool::select - * - * @param number namespace - * @param number index No - * @param mixed key - * @param optional limit default all - * @param optional offset default 0 - * - * @return count of tuples - */ -$res = $tnt->select(NMSPACE,PRIMARYINDEX,1); // namespace,index, key -var_dump($res); -$res = $tnt->getTuple(); -var_dump($res); - - -echo "some tuple select by fielNo[1] = 'x'\n"; -$res = $tnt->select(NMSPACE,INDEX_1,'x'); // namespace,index, key -var_dump($res); - -while( ($res = $tnt->getTuple()) != false){ - var_dump($res); -} - -echo "some tuple select by index = 2 (fielNo[1] = 'x' and fielNo[2] = 'abc')\n"; -$res = $tnt->select(NMSPACE,INDEX_2,array('x', 'abc')); // namespace,index, key -var_dump($res); - -while( ($res = $tnt->getTuple()) != false){ - var_dump($res); -} - -echo "some tuple select by index = 3 (fielNo[3] = 1025)\n"; -$res = $tnt->select(NMSPACE,INDEX_3,1025); // namespace,index, key -var_dump($res); - -while( ($res = $tnt->getTuple()) != false){ - var_dump($res); -} - -echo "some tuple select by index = 3 (fielNo[3] = 1025) LIMIT=3\n"; -$res = $tnt->select(NMSPACE,INDEX_3,1025,3); // namespace,index, key, limit -var_dump($res); - -while( ($res = $tnt->getTuple()) != false){ - var_dump($res); -} - -echo "some tuple select by index = 3 (fielNo[3] = 1025) NEXT 3 (offset=3, limit=3)\n"; -$res = $tnt->select(NMSPACE,INDEX_3,1025,3,3); // namespace,index, key, limit, offset -var_dump($res); - -while( ($res = $tnt->getTuple()) != false){ - var_dump($res); -} - -// multi select -/// SELECT * FROM t0 WHERE k0 IN (1,2) -$count = $tnt->mselect(NMSPACE,PRIMARYINDEX, array(1,2)); // ns, idx , keys, [limit, offset] -print "count=$count\n"; -while ( false != ($res = $tnt->getTuple())) { - var_dump($res); -} - -/// SELECT * FROM t0 WHERE k1 IN ('x','z') -$count = $tnt->mselect(NMSPACE,INDEX_1, array('x','z')); // ns, idx , keys, [limit, offset] -print "count=$count\n"; -while ( false != ($res = $tnt->getTuple())) { - var_dump($res); -} - - - - diff --git a/connector/php/exampleUpdate.php b/connector/php/exampleUpdate.php deleted file mode 100644 index 0d07f62091..0000000000 --- a/connector/php/exampleUpdate.php +++ /dev/null @@ -1,98 +0,0 @@ -<?php - -define("NMSPACE", 0); -define("PRIMARYINDEX", 0); - -define("FIELD_1", 1); -define("FIELD_2", 2); -define("FIELD_3", 3); - -if(!extension_loaded('tarantool')) { - dl('tarantool.so'); -} - -$res = true; - -// constructor(host,port); -$tnt = new Tarantool('tfn24'); - -$tnt->select(NMSPACE,PRIMARYINDEX,1); -$tuple = $tnt->getTuple(); -var_dump($tuple); - -/** - * Tarantool::inc - * - * @param namespace - * @param primary key - * @param field No for increment - * @param optional incremental data default +1 - * - * @return bool result - */ -// increment -$tnt->inc(NMSPACE,1,FIELD_3); - -$tnt->select(NMSPACE,PRIMARYINDEX,1); -$tuple = $tnt->getTuple(); -var_dump($tuple); - - -// duble increment (+2) -$tnt->inc(NMSPACE,1,FIELD_3,2); - -$tnt->select(NMSPACE,PRIMARYINDEX,1); -$tuple = $tnt->getTuple(); -var_dump($tuple); - - -// decrement -$res = $tnt->inc(NMSPACE,1,FIELD_3,-1); -echo "increment tuple res=$res\n"; - -$tnt->select(NMSPACE,PRIMARYINDEX,1); -$tuple = $tnt->getTuple(); -var_dump($tuple); - -// error, type inxex must be NUM -$res = $tnt->inc(NMSPACE,1,FIELD_2); -echo "increment tuple res=$res\n"; -if (!$res) - echo $tnt->getError(); -$tnt->select(NMSPACE,PRIMARYINDEX,1); -$tuple = $tnt->getTuple(); -var_dump($tuple); - -/** - * Tarantool::update - * - * @param namespace - * @param primary key - * @param array of new data: - * array( fieldNo => newValue, ... ) - * - * @return bool result - */ -$res = $tnt->update(NMSPACE,1,array(2=>'y')); -echo "update tuple res=$res\n"; - -$tnt->select(NMSPACE,0,1); -$tuple = $tnt->getTuple(); -var_dump($tuple); - - -$res = $tnt->update(NMSPACE,1,array(1 => 'z', 2=>'abc')); -echo "update tuple res=$res\n"; - -$tnt->select(NMSPACE,0,1); -$tuple = $tnt->getTuple(); -var_dump($tuple); - - -// Error type inxex 0 must be NUM -$res = $tnt->update(NMSPACE,1,array(0 => 'z', 2=>'abc')); -echo "update tuple res=$res\n"; -if (!$res) - echo $tnt->getError(); - - diff --git a/connector/php/tarantool.c b/connector/php/tarantool.c index b9b917c959..fc1a825dcb 100644 --- a/connector/php/tarantool.c +++ b/connector/php/tarantool.c @@ -16,197 +16,152 @@ | Copyright (c) 2011 | +----------------------------------------------------------------------+ */ - -/* $Id: header 252479 2008-02-07 19:39:50Z iliaa $ */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include <stdint.h> +#include <stdbool.h> #include <netinet/in.h> #include <netdb.h> +#include <inttypes.h> -#include "php.h" -#include "php_ini.h" -#include "ext/standard/info.h" -#include "zend_exceptions.h" +#include <php.h> +#include <php_ini.h> +#include <ext/standard/info.h> +#include <zend_exceptions.h> #include "tarantool.h" -/* If you declare any globals in php_tarantool.h uncomment this: -ZEND_DECLARE_MODULE_GLOBALS(tarantool) -*/ - -/* True global resources - no need for thread safety here */ -static int le_tarantool; - -zend_class_entry *tarantool_class_entry; - -typedef struct { - uint32_t type; - uint32_t len; - uint32_t request_id; -} Header; - -typedef struct _tarantool_object { - zend_object zo; - char * host; // tarantool host - int port; // tarantool port - int admin_port; // tarantool admin port - int bodyLen; // body len from tuples header - int countTuples; // count tuples - int readedTuples; // - int readed; // readed byte - uint32_t errorcode; // error code - php_stream * stream; - php_stream * admin_stream; -} tarantool_object; - -#define HEADER_SIZE sizeof(Header) - -typedef union { - u_char b; - uint32_t i; -} b2i; - -typedef struct { - uint32_t count; - u_char data[]; -} Tuple; - -typedef struct { - uint32_t fieldNo; - int8_t code; - u_char arg[]; -} Operation; - - -// sizeof(spaceNo) + sizeof(flag) + sizeof(tuple.count) -#define INSERT_REQUEST_SIZE 12 -typedef struct { - uint32_t spaceNo; - uint32_t flag; - Tuple tuple; -} InsertRequest; - -typedef struct { - uint32_t spaceNo; - Tuple tuple; -} DeleteRequest; - - -// sizeof(count) + sizeof(operation.fieldNo) + sizeof(operation.code) +1 // 10 -#define UPDATE_REQUEST_SIZE 10 -typedef struct { - uint32_t count; - Operation operation; -} UpdateRequest; - - -#define SELECT_REQUEST_SIZE 20 -typedef struct { - uint32_t spaceNo; - uint32_t indexNo; - uint32_t offset; - uint32_t limit; - uint32_t count; - char tuples[]; -} SelectRequest; - -typedef struct { - uint32_t len; - Tuple tuple; -} FTuple; - - -typedef struct { - uint32_t code; // request error code - uint32_t tuples_count; // count of tuples -} SelectResponseBody; - - -#define SELECT_RESPONSE_SIZE sizeof(SelectResponseTuple) -typedef struct { - uint32_t size; // tuple size in bytes - uint32_t count; // count elements in tuple -} SelectResponseTuple; - -typedef struct { - uint32_t code; - uint32_t count; - char data[]; -} Response; - -//typedef struct { -// uint32_t code; -// uint32_t count; -// char data[]; -//} UpdateResponse; - - -static void printLine( u_char *p ); -static void printLine3( u_char *p ); - -static void -leb128_write(char * buf, unsigned long value); - -static int -leb128_size(unsigned long value); - -static int -leb128_read(char * buf, int size, unsigned long * value); - -/* {{{ tarantool_functions[] - * - * Every user visible function must have an entry in tarantool_functions[]. - */ -const zend_function_entry tarantool_functions[] = { - PHP_ME(tarantool_class, __construct, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} +/*============================================================================* + * Tarantool extension structures defintion + *============================================================================*/ + +/* I/O buffer */ +struct io_buf { + /* buffer's size */ + size_t size; + /* buffer's capacity */ + size_t capacity; + /* read position in the I/O buffer */ + size_t readed; + /* buffer value */ + uint8_t *value; }; -zend_function_entry tarantool_class_functions[] = { - PHP_ME(tarantool_class, __construct, NULL, ZEND_ACC_PUBLIC) - - PHP_ME(tarantool_class, insert, NULL, ZEND_ACC_PUBLIC) - PHP_ME(tarantool_class, select, NULL, ZEND_ACC_PUBLIC) - PHP_ME(tarantool_class, mselect, NULL, ZEND_ACC_PUBLIC) - PHP_ME(tarantool_class, call, NULL, ZEND_ACC_PUBLIC) - PHP_ME(tarantool_class, getTuple, NULL, ZEND_ACC_PUBLIC) - PHP_ME(tarantool_class, delete, NULL, ZEND_ACC_PUBLIC) - PHP_ME(tarantool_class, update, NULL, ZEND_ACC_PUBLIC) - PHP_ME(tarantool_class, inc, NULL, ZEND_ACC_PUBLIC) - PHP_ME(tarantool_class, getError, NULL, ZEND_ACC_PUBLIC) - PHP_ME(tarantool_class, getInfo, NULL, ZEND_ACC_PUBLIC) - PHP_ME(tarantool_class, getStat, NULL, ZEND_ACC_PUBLIC) - PHP_ME(tarantool_class, getConf, NULL, ZEND_ACC_PUBLIC) +/* tarantool object */ +typedef struct tarantool_object { + zend_object zo; + /* host name */ + char *host; + /* tarantool primary port */ + int port; + /* tarantool admin port */ + int admin_port; + /* tarantool primary connection */ + php_stream *stream; + /* tarantool admin connecion */ + php_stream *admin_stream; + /* I/O buffer */ + struct io_buf *io_buf; + /* additional buffer for splice args */ + struct io_buf *splice_field; +} tarantool_object; + +/* iproto header */ +struct iproto_header { + /* command code */ + uint32_t type; + /* command length */ + uint32_t length; + /* request id */ + uint32_t request_id; +} __attribute__((packed)); + +/* tarantool select command request */ +struct tnt_select_request { + /* space number */ + int32_t space_no; + /* index number */ + int32_t index_no; + /* select offset from begining */ + int32_t offset; + /* maximail number tuples in responce */ + int32_t limit; +} __attribute__((packed)); + +/* tarantool insert command request */ +struct tnt_insert_request { + /* space number */ + int32_t space_no; + /* flags */ + int32_t flags; +} __attribute__((packed)); + +/* tarantool update fields command request */ +struct tnt_update_fields_request { + /* space number */ + int32_t space_no; + /* flags */ + int32_t flags; +} __attribute__((packed)); + +/* tarantool delete command request */ +struct tnt_delete_request { + /* space number */ + int32_t space_no; + /* flags */ + int32_t flags; +} __attribute__((packed)); + +/* tarantool call command request */ +struct tnt_call_request { + /* flags */ + int32_t flags; +} __attribute__((packed)); + +/* tarantool command response */ +struct tnt_response { + /* return code */ + int32_t return_code; + /* count */ + int32_t count; +} __attribute__((packed)); + + +/*============================================================================* + * Global variables definition + *============================================================================*/ + + +/*----------------------------------------------------------------------------* + * Tarantool module variables + *----------------------------------------------------------------------------*/ + +/* module functions list */ +zend_function_entry tarantool_module_functions[] = { + PHP_ME(tarantool_class, __construct, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; - -/* }}} */ - -/* {{{ tarantool_module_entry - */ +/* tarantool module struct */ zend_module_entry tarantool_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif "tarantool", - tarantool_functions, + tarantool_module_functions, PHP_MINIT(tarantool), PHP_MSHUTDOWN(tarantool), NULL, NULL, PHP_MINFO(tarantool), #if ZEND_MODULE_API_NO >= 20010901 - "0.1", /* Replace with version number for your extension */ + "1.0", #endif STANDARD_MODULE_PROPERTIES }; -/* }}} */ - #ifdef COMPILE_DL_TARANTOOL @@ -214,1875 +169,1798 @@ ZEND_GET_MODULE(tarantool) #endif -static int php_tnt_connect( tarantool_object *ctx TSRMLS_DC) { - // open stream - struct timeval tv; - tv.tv_sec = TARANTOOL_TIMEOUT; - tv.tv_usec = 0; +/*----------------------------------------------------------------------------* + * Tarantool class variables + *----------------------------------------------------------------------------*/ - char * errstr = NULL, *hostname = NULL; - int err = 0, hostname_len; +/* tarantool class methods */ +const zend_function_entry tarantool_class_methods[] = { + PHP_ME(tarantool_class, __construct, NULL, ZEND_ACC_PUBLIC) + PHP_ME(tarantool_class, select, NULL, ZEND_ACC_PUBLIC) + PHP_ME(tarantool_class, insert, NULL, ZEND_ACC_PUBLIC) + PHP_ME(tarantool_class, update_fields, NULL, ZEND_ACC_PUBLIC) + PHP_ME(tarantool_class, delete, NULL, ZEND_ACC_PUBLIC) + PHP_ME(tarantool_class, call, NULL, ZEND_ACC_PUBLIC) + PHP_ME(tarantool_class, admin, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; - if (ctx->port) { - hostname_len = spprintf(&hostname, 0, "tcp://%s:%d", ctx->host, ctx->port); - } else { - php_printf("port undefined\n"); - } +/* tarantool class */ +zend_class_entry *tarantool_class_ptr; - ctx->stream = php_stream_xport_create( hostname, hostname_len, - ENFORCE_SAFE_MODE | REPORT_ERRORS, - STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, - NULL, &tv, NULL, &errstr, &err); +/*============================================================================* + * local functions declaration + *============================================================================*/ - efree(hostname); - if (err && errstr) { - php_printf("stream error: %s\n", errstr); - ctx->stream = NULL; - efree(errstr); - } +/*----------------------------------------------------------------------------* + * I/O buffer interface + *----------------------------------------------------------------------------*/ - if (!ctx->stream) { - return 1; - } +/* create I/O buffer instance */ +static struct io_buf * +io_buf_create(); - return 0; -} +/* destroy I/O buffer */ +static void +io_buf_destroy(struct io_buf *buf); -static int php_tnt_admin_connect( tarantool_object *ctx TSRMLS_DC) { - // open stream - struct timeval tv; - tv.tv_sec = TARANTOOL_TIMEOUT; - tv.tv_usec = 0; +/* reserv I/O buffer space */ +inline static bool +io_buf_reserve(struct io_buf *buf, size_t n); - char * errstr = NULL, *hostname = NULL; - int err = 0, hostname_len; +/* resize I/O buffer */ +inline static bool +io_buf_resize(struct io_buf *buf, size_t n); - if (ctx->admin_port) { - hostname_len = spprintf(&hostname, 0, "tcp://%s:%d", ctx->host, ctx->admin_port); - } else { - php_printf("admin port undefined\n"); - } +/* calculate next capacity for I/O buffer */ +inline static size_t +io_buf_next_capacity(size_t n); - ctx->admin_stream = php_stream_xport_create( hostname, hostname_len, - ENFORCE_SAFE_MODE | REPORT_ERRORS, - STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, - NULL, &tv, NULL, &errstr, &err); +/* clean I/O buffer */ +static void +io_buf_clean(struct io_buf *buf); - efree(hostname); +/* read struct from buffer */ +static bool +read_struct_io_buf(struct io_buf *buf, void **ptr, size_t n); - if (err && errstr) { - php_printf("stream error: %s\n", errstr); - ctx->admin_stream = NULL; - efree(errstr); - } +/* read integer from buffer */ +static bool +read_int_io_buf(struct io_buf *buf, int32_t *val); - if (!ctx->admin_stream) { - return 1; - } +/* read var integer from buffer */ +static bool +read_varint_io_buf(struct io_buf *buf, int32_t *val); - return 0; -} +/* read string from buffer */ +static bool +read_str_io_buf(struct io_buf *buf, char **str, size_t len); -/* {{{ proto tarantool::__construct( string string host=localhost, int port=PORT, int admin_port=ADMIN_PORT) - tarantool constructor */ -PHP_METHOD(tarantool_class, __construct) -{ - zval *id; - tarantool_object *ctx; +/* read fied from buffer */ +static bool +read_field_io_buf(struct io_buf *buf, zval *tuple); +/* read tuple from buffer */ +static bool +read_tuple_io_buf(struct io_buf *buf, zval **tuple); - zval** zdata; //?????? +/* + * Write to I/O buffer functions + */ - char * host = NULL; - int host_len = 0; - long port=0, admin_port=0; +/* write struct to I/O buffer */ +static void * +io_buf_write_struct(struct io_buf *buf, size_t n); - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|sll", - &id, tarantool_class_entry, &host, &host_len, &port, &admin_port) == FAILURE) { - return; - } +/* write byte to I/O buffer */ +static bool +io_buf_write_byte(struct io_buf *buf, int8_t value); - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - ctx->host = NULL; - ctx->port = 0; - ctx->admin_port = 0; - ctx->stream = NULL; - ctx->bodyLen = 0; - ctx->errorcode = 0; +/* write int32 to I/O buffer */ +static bool +io_buf_write_int32(struct io_buf *buf, int32_t value); - if (host_len > 0) - ctx->host = estrdup(host); - else - ctx->host = estrdup(TARANTOOL_DEF_HOST); +/* write varint to I/O buffer */ +static bool +io_buf_write_varint(struct io_buf *buf, int32_t value); - if (port) - ctx->port = port; - else - ctx->port = TARANTOOL_DEF_PORT; +/* write string to I/O buffer */ +static bool +io_buf_write_str(struct io_buf *buf, uint8_t *str, size_t len); - if (admin_port) - ctx->admin_port = admin_port; - else - ctx->admin_port = TARANTOOL_ADMIN_PORT; +/* write tuple to I/O buffer */ +static bool +io_buf_write_tuple_int(struct io_buf *buf, zval *tuple); -} -/* }}} */ +/* write tuple's field to I/O buffer */ +static bool +io_buf_write_field(struct io_buf *buf, uint8_t *val, size_t len); +/* write tuple (string) to I/O buffer */ +static bool +io_buf_write_tuple_str(struct io_buf *buf, zval *tuple); +/* write tuple (array) to I/O buffer */ +static bool +io_buf_write_tuple_array(struct io_buf *buf, zval *tuple); -/* {{{ proto int tarantool::insert(int space, int index, zval tuple); -insert tuple -*/ -PHP_METHOD(tarantool_class, insert ) -{ - zval *id; - tarantool_object *ctx; - long space; - zval * tuple; - HashTable *pht; - HashPosition pos; - zval **curr; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ola", &id, - tarantool_class_entry, &space, &tuple) == FAILURE) { - return; - } +/* write tuple to I/O buffer */ +static bool +io_buf_write_tuple(struct io_buf *buf, zval *tuple); - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); +/* write array of tuples to I/O buffer */ +static bool +io_buf_write_tuples_list_array(struct io_buf *buf, zval *tuples_list); - if (!ctx->stream) { - if (php_tnt_connect(ctx TSRMLS_CC)) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the can't open remote host " ,0 TSRMLS_DC); - return; - } - } +/* write tuples list to I/O buffer */ +static bool +io_buf_write_tuples_list(struct io_buf *buf, zval *tuples_list); - pht = Z_ARRVAL_P(tuple); - int num = zend_hash_num_elements(pht); - char * out_buf = emalloc(TARANTOOL_BUFSIZE); - bzero(out_buf, TARANTOOL_BUFSIZE); +/*----------------------------------------------------------------------------* + * alloc/free classes functions + *----------------------------------------------------------------------------*/ - Header * header = (Header *) out_buf; - InsertRequest * insert = (InsertRequest *) (out_buf + HEADER_SIZE); +/* tarantool class instance allocator */ +static zend_object_value +alloc_tarantool_object(zend_class_entry *entry TSRMLS_DC); - header->type = TARANTOOL_INSERT; - header->request_id = TARANTOOL_REQUEST_ID; +/* free tarantool class instance */ +static void +free_tarantool_object(tarantool_object *tnt TSRMLS_DC); - insert->spaceNo = space; - insert->tuple.count = num; // count Tuples - u_char * p = (u_char *) insert->tuple.data; +/*----------------------------------------------------------------------------* + * raise exceation functions + *----------------------------------------------------------------------------*/ - for(zend_hash_internal_pointer_reset_ex(pht, &pos); - zend_hash_get_current_data_ex(pht, (void **) &curr, &pos) == SUCCESS; - zend_hash_move_forward_ex(pht, &pos)) { +/* raise exception */ +static void +raise_exception(const char *format, ...); - if (Z_TYPE_PP(curr) == IS_STRING) { - char * strval = Z_STRVAL_PP(curr); - int str_len = Z_STRLEN_PP(curr); - u_char str_shortlen = (u_char)str_len; +/*----------------------------------------------------------------------------* + * php stream functions + *----------------------------------------------------------------------------*/ - *(p++) = str_shortlen; - memcpy(p, strval, str_len); - p += str_len; - } - if (Z_TYPE_PP(curr) == IS_LONG) { - unsigned long val = Z_LVAL_PP(curr); - -// u_char leb_size = (u_char)leb128_size( val); -// *(p++) = leb_size; -// leb128_write( (char *)p, val); -// p += leb_size; - u_char leb_size = 4; - *(p++) = leb_size; - b2i * pval = (b2i*) p; - pval->i = (int) val; - p += leb_size; - } - } +/* establic connection */ +static php_stream * +establish_connection(char *host, int port); - header->len = INSERT_REQUEST_SIZE + (p-insert->tuple.data); // 12 = 3 * sizeof(int32) :ns, flag & cardinality +/* send administation command request */ +static bool +send_admin_request(php_stream *stream, struct io_buf *buf); - // write header - int len = php_stream_write(ctx->stream, out_buf , sizeof(Header)); // 12 +/* receive administration command response */ +static bool +recv_admin_response(php_stream *stream, struct io_buf *buf); - // write tuple - p = (u_char*)insert; - len = php_stream_write(ctx->stream, (char*)p , header->len ); +/* send request by iproto */ +static bool +send_iproto_request(php_stream *stream, int32_t type, int32_t request_id, struct io_buf *buf); - bzero(out_buf, header->len + INSERT_REQUEST_SIZE); +/* receive response by iproto */ +static bool +recv_iproto_response(php_stream *stream, struct io_buf *buf); - len = php_stream_read(ctx->stream, out_buf, TARANTOOL_BUFSIZE); - if ( *(out_buf+HEADER_SIZE) == '\0') { - efree(out_buf); - RETURN_TRUE; - } +/*----------------------------------------------------------------------------* + * php hash functions + *----------------------------------------------------------------------------*/ +/* find long by key in the hash table */ +static bool +hash_fing_long(HashTable *hash, char *key, long *value); + +/* find string by key in the hash table */ +static bool +hash_fing_str(HashTable *hash, char *key, char **value, int *value_length); + +/* find scalar by key in the hash table */ +static bool +hash_fing_scalar(HashTable *hash, char *key, zval ***value); + + +/*============================================================================* + * Interface definition + *============================================================================*/ + + +/*----------------------------------------------------------------------------* + * Tarantool main module interface + *----------------------------------------------------------------------------*/ + +/* initialize module function */ +PHP_MINIT_FUNCTION(tarantool) +{ + /* register constants */ + + /* register tarantool flags */ + REGISTER_LONG_CONSTANT("TARANTOOL_FLAGS_RETURN_TUPLE", + TARANTOOL_FLAGS_RETURN_TUPLE, + CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("TARANTOOL_FLAGS_ADD", + TARANTOOL_FLAGS_ADD, + CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("TARANTOOL_FLAGS_REPLACE", + TARANTOOL_FLAGS_REPLACE, + CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("TARANTOOL_FLAGS_NOT_STORE", + TARANTOOL_FLAGS_NOT_STORE, + CONST_CS | CONST_PERSISTENT); + + /* register tarantool update fields operations */ + REGISTER_LONG_CONSTANT("TARANTOOL_OP_ASSIGN", + TARANTOOL_OP_ASSIGN, + CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("TARANTOOL_OP_ADD", + TARANTOOL_OP_ADD, + CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("TARANTOOL_OP_AND", + TARANTOOL_OP_AND, + CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("TARANTOOL_OP_XOR", + TARANTOOL_OP_XOR, + CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("TARANTOOL_OP_OR", + TARANTOOL_OP_OR, + CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("TARANTOOL_OP_SPLICE", + TARANTOOL_OP_SPLICE, + CONST_CS | CONST_PERSISTENT); + + /* register classes */ + + /* register tarantool class */ + zend_class_entry tarantool_class; + INIT_CLASS_ENTRY(tarantool_class, "Tarantool", tarantool_class_methods); + tarantool_class.create_object = alloc_tarantool_object; + tarantool_class_ptr = zend_register_internal_class(&tarantool_class TSRMLS_CC); - b2i* bb = (b2i*)(out_buf+HEADER_SIZE); - ctx->errorcode = bb->i; + return SUCCESS; +} - efree(out_buf); +/* shutdown module function */ +PHP_MSHUTDOWN_FUNCTION(tarantool) +{ + return SUCCESS; +} - RETURN_FALSE; +/* show information about this module */ +PHP_MINFO_FUNCTION(tarantool) +{ + php_info_print_table_start(); + php_info_print_table_header(2, "Tarantool/Box support", "enabled"); + php_info_print_table_row(2, "default host", TARANTOOL_DEFAULT_HOST); + php_info_print_table_row(2, "default primary port", TARANTOOL_DEFAULT_PORT); + php_info_print_table_row(2, "default read-only port", TARANTOOL_DEFAULT_RO_PORT); + php_info_print_table_row(2, "default admin port", TARANTOOL_DEFAULT_ADMIN_PORT); + php_info_print_table_end(); } -/* }}} */ +/*----------------------------------------------------------------------------* + * Tarantool class interface + *----------------------------------------------------------------------------*/ -/* {{{ proto int tarantool::select(space, index, tuple [, limit=all, offset=0]); - select tuple use php_streams -*/ -PHP_METHOD(tarantool_class, select ) +PHP_METHOD(tarantool_class, __construct) { - zval *id, * tuple; - tarantool_object *ctx; - long ns = 0; - long idx = 0; - long limit = 0xffffffff; - long offset = 0; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ollz|ll", &id, - tarantool_class_entry, &ns, &idx, &tuple, &limit, &offset) == FAILURE) { + /* + * parse method's parameters + */ + zval *id; + char *host = NULL; + int host_len = 0; + long port = 0; + long admin_port = 0; + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "Osl|l", + &id, + tarantool_class_ptr, + &host, + &host_len, + &port, + &admin_port) == FAILURE) { return; } + + /* + * validate parameters + */ + + /* check host name */ + if (host == NULL || host_len == 0) + raise_exception("invalid tarantool's hostname"); - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - if (!ctx) - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the context is null" ,0 TSRMLS_CC); + /* validate port value */ + if (port <= 0 || port >= 65536) { + raise_exception("invalid primary port value: %li", port); + return; + } - if (!ctx->stream) { - if (php_tnt_connect(ctx TSRMLS_CC)) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the can't open remote host " ,0 TSRMLS_DC); + /* check admin port */ + if (admin_port) { + /* validate port value */ + if (admin_port < 0 || admin_port >= 65536) { + raise_exception("invalid admin port value: %li", admin_port); return; } - } - ctx->bodyLen = 0; - ctx->countTuples = 0; - ctx->readedTuples = 0; - ctx->readed = 0; - ctx->errorcode = 0; - - char * out_buf = emalloc(TARANTOOL_BUFSIZE); - bzero(out_buf, TARANTOOL_BUFSIZE); + /* initialzie object structure */ + tarantool_object *object = (tarantool_object *) zend_object_store_get_object( + id TSRMLS_CC); + object->host = estrdup(host); + object->port = port; + object->admin_port = admin_port; + object->stream = NULL; + object->admin_stream = NULL; + object->io_buf = io_buf_create(); + if (!object->io_buf) { + return; + } + object->splice_field = io_buf_create(); + if (!object->splice_field) { + return; + } - Header * header = (Header *) out_buf; - SelectRequest * select = (SelectRequest *) out_buf + HEADER_SIZE; + return; +} - header->type = TARANTOOL_SELECT; - header->request_id = TARANTOOL_REQUEST_ID; +PHP_METHOD(tarantool_class, select) +{ + /* + * parse methods parameters + */ + zval *id; + long space_no = 0; + long index_no = 0; + zval *keys_list = NULL; + long limit = -1; + long offset = 0; + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "Ollz|ll", + &id, + tarantool_class_ptr, + &space_no, + &index_no, + &keys_list, + &limit, + &offset) == FAILURE) { + return; + } - select->spaceNo = ns; - select->indexNo = idx; - select->limit = limit; - select->offset = offset; - select->count = 1; // âðåìåííî îòëàæèâàåì - îäèí êîðòåæ + tarantool_object *tnt = (tarantool_object *) zend_object_store_get_object( + id TSRMLS_CC); - u_char * p = (u_char *)select->tuples ; + /* check connection */ + if (!tnt->stream) { + /* establis connection */ + tnt->stream = establish_connection(tnt->host, tnt->port); + if (!tnt->stream) + return; + } - int * count_elements = (int *)p; + /* + * send request + */ - switch (Z_TYPE_P(tuple)) { - case IS_STRING: { - *count_elements = 1; //!!!! <------- êîë-âî ýëåìåíòîâ â êîðòåæå - p += sizeof(uint32_t); + /* clean-up buffer */ + io_buf_clean(tnt->io_buf); - char * strval = Z_STRVAL_P(tuple); - int str_len = Z_STRLEN_P(tuple); - u_char str_shortlen = (u_char)str_len; + /* fill select command */ + /* fill command header */ + struct tnt_select_request *request = (struct tnt_select_request *) io_buf_write_struct( + tnt->io_buf, sizeof(struct tnt_select_request)); + if (request == NULL) + return; + request->space_no = space_no; + request->index_no = index_no; + request->offset = offset; + request->limit = limit; + /* fill keys */ + if (!io_buf_write_tuples_list(tnt->io_buf, keys_list)) + return; - *(p++) = str_shortlen; - memcpy(p, strval, str_len); - p += str_len; + /* send iproto request */ + if (!send_iproto_request(tnt->stream, TARANTOOL_COMMAND_SELECT, 0, tnt->io_buf)) + return; -// printf("tuple: len=%d [%s]\n", str_len, strval ); - } - break; + /* + * receive response + */ - case IS_LONG: { - *count_elements = 1; //!!!! <------- êîë-âî ýëåìåíòîâ â êîðòåæå - p += sizeof(uint32_t); + /* clean-up buffer */ + io_buf_clean(tnt->io_buf); - unsigned long val = Z_LVAL_P(tuple); -// u_char leb_size = (u_char)leb128_size( val); -// *(p++) = leb_size; -// leb128_write( (char *)p, val); + /* receive */ + if (!recv_iproto_response(tnt->stream, tnt->io_buf)) + return; - u_char leb_size = 4; - *(p++) = leb_size; - b2i * pval = (b2i*) p; - pval->i = (int) val; - p += leb_size; + /* read response */ + struct tnt_response *response; + if (!read_struct_io_buf(tnt->io_buf, + (void **) &response, + sizeof(struct tnt_response))) { + raise_exception("select failed: invalid response was received"); + return; + } -// printf("tuple: int %d\n", val ); - } - break; + /* check return code */ + if (response->return_code) { + /* error happen, throw exceprion */ + raise_exception("select failed: %"PRIi32, response->return_code); + return; + } + if (array_init(return_value) != SUCCESS) { + raise_exception("select failed: create array failed"); + return; + } - case IS_ARRAY: { - HashTable *pht; - HashPosition pos; - zval **curr; - - *count_elements = zend_hash_num_elements(Z_ARRVAL_P(tuple)); - p += sizeof(uint32_t); - - pht = Z_ARRVAL_P(tuple); - for(zend_hash_internal_pointer_reset_ex(pht, &pos); - zend_hash_get_current_data_ex(pht, (void **)&curr, &pos) == SUCCESS; - zend_hash_move_forward_ex(pht, &pos)) { - - if (Z_TYPE_PP(curr) == IS_STRING) { - char * strval = Z_STRVAL_PP(curr); - int str_len = Z_STRLEN_PP(curr); - // printf("tuple: len=%d [%s]", str_len, strval ); - u_char str_shortlen = (u_char)str_len; - - *(p++) = str_shortlen; - memcpy(p, strval, str_len); - p += str_len; - } - if (Z_TYPE_PP(curr) == IS_LONG) { - unsigned long val = Z_LVAL_PP(curr); - -// u_char leb_size = (u_char)leb128_size( val); -// *(p++) = leb_size; -// leb128_write( (char *)p, val); - u_char leb_size = 4; - *(p++) = leb_size; - b2i * pval = (b2i*) p; - pval->i = (int) val; - - p += leb_size; - } - } + /* put count to result array */ + add_assoc_long(return_value, "count", response->count); - } - break; - default : - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "tuple: unsuport tuple type" ,0 TSRMLS_CC); - return; + /* put tuple list to result array */ + zval *tuples_list; + MAKE_STD_ZVAL(tuples_list); + if (array_init(tuples_list) == FAILURE) { + raise_exception("select failed: create array failed"); + return; } - u_char * p_end = (u_char *)select->tuples ; - header->len = (p - p_end) + SELECT_REQUEST_SIZE; //+ HEADER_SIZE ; // 12 = 3 * sizeof(int32) :ns, flag & cardinality - - // write header - int len = php_stream_write(ctx->stream, out_buf, HEADER_SIZE); // 12 - if (len != HEADER_SIZE) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "write header error" ,0 TSRMLS_CC); - efree(out_buf); + /* read tuples for responce */ + int i; + for (i = 0; i < response->count; ++i) { + zval *tuple; + if (!read_tuple_io_buf(tnt->io_buf, &tuple)) { + raise_exception("select failed: invalid response was received"); return; + } + add_next_index_zval(tuples_list, tuple); } - len = php_stream_write(ctx->stream, (void*)select , header->len ); - if (len != header->len) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "write request error" ,0 TSRMLS_CC); - efree(out_buf); - return; + add_assoc_zval(return_value, "tuples_list", tuples_list); +} + +PHP_METHOD(tarantool_class, insert) +{ + /* + * parse methods parameters + */ + zval *id; + long space_no = 0; + long flags = 0; + zval *tuple = NULL; + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "Ola|l", + &id, + tarantool_class_ptr, + &space_no, + &tuple, + &flags) == FAILURE) { + return; } - Header responseHeader; - bzero(&responseHeader, HEADER_SIZE); + tarantool_object *tnt = (tarantool_object *) zend_object_store_get_object( + id TSRMLS_CC); - len = php_stream_read(ctx->stream, (void *)&responseHeader, HEADER_SIZE); - if (len != HEADER_SIZE) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "read header error" ,0 TSRMLS_CC); - efree(out_buf); + /* check connection */ + if (!tnt->stream) { + /* establis connection */ + tnt->stream = establish_connection(tnt->host, tnt->port); + if (!tnt->stream) return; } - ctx->bodyLen = responseHeader.len; + /* + * send request + */ - uint32_t code; + /* clean-up buffer */ + io_buf_clean(tnt->io_buf); - len = php_stream_read(ctx->stream, (void *) &code,sizeof(uint32_t)); - ctx->readed += len; - if (code > 0 || len != sizeof(uint32_t)) { - ctx->errorcode = code; /// need test - efree(out_buf); - RETURN_FALSE; - } -// - uint32_t tuples_count=0; - len = php_stream_read(ctx->stream, (void *) &tuples_count,sizeof(uint32_t)); - ctx->readed += len; - if (len != sizeof(uint32_t)) { - zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), - 0 TSRMLS_CC,"read body error"); - efree(out_buf); + /* fill insert command */ + struct tnt_insert_request *request = (struct tnt_insert_request *) io_buf_write_struct( + tnt->io_buf, sizeof(struct tnt_insert_request)); + if (request == NULL) return; - } - - ctx->errorcode = code; - ctx->countTuples = tuples_count; - efree(out_buf); - RETURN_LONG(ctx->countTuples); + /* space number */ + request->space_no = space_no; + /* flags */ + request->flags = flags; + /* tuple */ + if (!io_buf_write_tuple(tnt->io_buf, tuple)) + return; -} -/* }}} */ + /* send iproto request */ + if (!send_iproto_request(tnt->stream, TARANTOOL_COMMAND_INSERT, 0, tnt->io_buf)) + return; -/* {{{ proto int tarantool::mselect(space, index, tuples [, limit=all, offset=0]); - select some tuples tuples = array(key1,key2,key3); - use only simple key -*/ -PHP_METHOD(tarantool_class, mselect ) -{ - zval *id, * tuple; - tarantool_object *ctx; - long ns = 0; - long idx = 0; - long limit = 0xffffffff; - long offset = 0; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olla|ll", &id, - tarantool_class_entry, &ns, &idx, &tuple, &limit, &offset) == FAILURE) { - return; - } + /* + * receive response + */ - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - if (!ctx) - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the context is null" ,0 TSRMLS_CC); + /* clean-up buffer */ + io_buf_clean(tnt->io_buf); - if (!ctx->stream) { - if (php_tnt_connect(ctx TSRMLS_CC)) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the can't open remote host " ,0 TSRMLS_DC); - return; - } + /* receive */ + if (!recv_iproto_response(tnt->stream, tnt->io_buf)) + return; + /* read response */ + struct tnt_response *response; + if (!read_struct_io_buf(tnt->io_buf, + (void **) &response, + sizeof(struct tnt_response))) { + raise_exception("insert failed: invalid response was received"); + return; } - ctx->bodyLen = 0; - ctx->countTuples = 0; - ctx->readedTuples = 0; - ctx->readed = 0; - ctx->errorcode = 0; - - char * out_buf = emalloc(TARANTOOL_BUFSIZE); - bzero(out_buf, TARANTOOL_BUFSIZE); + /* check return code */ + if (response->return_code) { + /* error happen, throw exceprion */ + raise_exception("insert failed: %"PRIi32, response->return_code); + return; + } + + /* + * fill return value + */ - Header * header = (Header *) out_buf; - SelectRequest * select = (SelectRequest *) out_buf + HEADER_SIZE; + if (array_init(return_value) != SUCCESS) { + raise_exception("insert failed: create array failed"); + return; + } - header->type = TARANTOOL_SELECT; - header->request_id = TARANTOOL_REQUEST_ID; + /* put count to result array */ + add_assoc_long(return_value, "count", response->count); - select->spaceNo = ns; - select->indexNo = idx; - select->limit = limit; - select->offset = offset; + /* check "return tuple" flag */ + if (flags & TARANTOOL_FLAGS_RETURN_TUPLE) { + /* ok, the responce should contain inserted tuple */ + if (!read_tuple_io_buf(tnt->io_buf, &tuple)) { + raise_exception("insert failed: invalid response was received"); + return; + } + /* put returned tuple to result array */ + add_assoc_zval(return_value, "tuple", tuple); + } +} - u_char * p = (u_char *)select->tuples ; - select->count = zend_hash_num_elements(Z_ARRVAL_P(tuple)); +PHP_METHOD(tarantool_class, update_fields) +{ + /* + * parse methods parameters + */ + zval *id; + long space_no = 0; + long flags = 0; + zval *tuple = NULL; + zval *op_list = NULL; + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "Olza|l", + &id, + tarantool_class_ptr, + &space_no, + &tuple, + &op_list, + &flags) == FAILURE) { + return; + } - // ôîðìèðóåì òàê êàê íàäî! + tarantool_object *tnt = (tarantool_object *) zend_object_store_get_object( + id TSRMLS_CC); - HashTable *pht; - HashPosition pos; - zval **curr; + /* check connection */ + if (!tnt->stream) { + /* establis connection */ + tnt->stream = establish_connection(tnt->host, tnt->port); + if (!tnt->stream) + return; + } + /* + * send request + */ - pht = Z_ARRVAL_P(tuple); - for(zend_hash_internal_pointer_reset_ex(pht, &pos); - zend_hash_get_current_data_ex(pht, (void **)&curr, &pos) == SUCCESS; - zend_hash_move_forward_ex(pht, &pos)) { + /* clean-up buffer */ + io_buf_clean(tnt->io_buf); - int32_t * count = (int32_t *)p; - *count = 1; - p += sizeof(int32_t); + /* fill insert command */ + struct tnt_update_fields_request *request = (struct tnt_update_fields_request *) io_buf_write_struct( + tnt->io_buf, sizeof(struct tnt_update_fields_request)); + if (request == NULL) + return; + /* space number */ + request->space_no = space_no; + /* flags */ + request->flags = flags; + /* tuple */ + if (!io_buf_write_tuple(tnt->io_buf, tuple)) + return; - if (Z_TYPE_PP(curr) == IS_STRING) { - char * strval = Z_STRVAL_PP(curr); - int str_len = Z_STRLEN_PP(curr); -// printf("tuple: len=%d [%s]", str_len, strval ); - u_char str_shortlen = (u_char)str_len; + HashTable *op_list_array = Z_ARRVAL_P(op_list); + int op_count = zend_hash_num_elements(op_list_array); - *(p++) = str_shortlen; - memcpy(p, strval, str_len); - p += str_len; + /* write number of update fields operaion */ + if (!io_buf_write_int32(tnt->io_buf, op_count)) + return; + php_printf("ops count = %i\n", op_count); + + HashPosition itr; + zval **op; + for (zend_hash_internal_pointer_reset_ex(op_list_array, &itr); + zend_hash_get_current_data_ex(op_list_array, (void **) &op, &itr) == SUCCESS; + zend_hash_move_forward_ex(op_list_array, &itr)) { + /* check operation type */ + if (Z_TYPE_PP(op) != IS_ARRAY) { + raise_exception("invalid operations list"); + return; } - if (Z_TYPE_PP(curr) == IS_LONG) { - unsigned long val = Z_LVAL_PP(curr); - u_char leb_size = 4; - *(p++) = leb_size; - b2i * pval = (b2i*) p; - pval->i = (int) val; + HashTable *op_array = Z_ARRVAL_PP(op); + long field_no; + long opcode; - p += leb_size; + if (!hash_fing_long(op_array, "field", &field_no)) { + raise_exception("can't find 'field' in the update field operation"); + return; } - } // end array + if (!hash_fing_long(op_array, "op", &opcode)) { + raise_exception("can't find 'op' in the update field operation"); + return; + } + /* write field number */ + if (!io_buf_write_int32(tnt->io_buf, field_no)) + return; - u_char * p_end = (u_char *)select->tuples ; - header->len = (p - p_end) + SELECT_REQUEST_SIZE; //+ HEADER_SIZE ; // 12 = 3 * sizeof(int32) :ns, flag & cardinality + /* write operation code */ + if (!io_buf_write_byte(tnt->io_buf, opcode)) + return; + zval **assing_arg = NULL; + long arith_arg; + long splice_offset; + long splice_length; + char *splice_list; + int splice_list_len; + switch (opcode) { + case TARANTOOL_OP_ASSIGN: + if (!hash_fing_scalar(op_array, "arg", &assing_arg)) { + raise_exception("can't find 'arg' in the update field operation"); + return; + } + if (Z_TYPE_PP(assing_arg) == IS_LONG) { + /* write as interger */ + if (!io_buf_write_field(tnt->io_buf, (uint8_t *) &Z_LVAL_PP(assing_arg), sizeof(int32_t))) + return; + } else { + /* write as string */ + if (!io_buf_write_field(tnt->io_buf, (uint8_t *) Z_STRVAL_PP(assing_arg), Z_STRLEN_PP(assing_arg))) + return; + } + break; + case TARANTOOL_OP_ADD: + case TARANTOOL_OP_AND: + case TARANTOOL_OP_XOR: + case TARANTOOL_OP_OR: + if (!hash_fing_long(op_array, "arg", &arith_arg)) { + raise_exception("can't find 'arg' in the update field operation"); + return; + } + /* write arith arg */ + if (!io_buf_write_field(tnt->io_buf, (uint8_t *) &arith_arg, sizeof(int32_t))) + return; + break; + case TARANTOOL_OP_SPLICE: + /* + * read splice args + */ + + /* read offset */ + if (!hash_fing_long(op_array, "offset", &splice_offset)) { + raise_exception("can't find 'offset' in the update field operation"); + return; + } + /* read length */ + if (!hash_fing_long(op_array, "length", &splice_length)) { + raise_exception("can't find 'length' in the update field operation"); + return; + } + /* read list */ + if (!hash_fing_str(op_array, "list", &splice_list, &splice_list_len)) { + raise_exception("can't find 'list' in the update field operation"); + return; + } -// printf("body len %d\n", header->len); -// -// p = (u_char *)select; -// printLine3(p); -// printLine3(p+12); -// printLine3(p+24); -// printLine3(p+36); -// -// efree(out_buf); -// RETURN_FALSE; + /* + * write splice args + */ + io_buf_clean(tnt->splice_field); + + /* write offset to separate buffer */ + if (!io_buf_write_field(tnt->splice_field, (uint8_t *) &splice_offset, sizeof(int32_t))) + return; + /* write length to separate buffer */ + if (!io_buf_write_field(tnt->splice_field, (uint8_t *) &splice_length, sizeof(int32_t))) + return; + /* write list to separate buffer */ + if (!io_buf_write_field(tnt->splice_field, (uint8_t *) splice_list, splice_list_len)) + return; + + /* write splice args as alone field */ + if (!io_buf_write_field(tnt->io_buf, tnt->splice_field->value, tnt->splice_field->size)) + return; - // write header - int len = php_stream_write(ctx->stream, out_buf, HEADER_SIZE); // 12 - if (len != HEADER_SIZE) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "write header error" ,0 TSRMLS_CC); - efree(out_buf); + break; + default: + raise_exception("invalid operaion code %i", opcode); return; + } } - len = php_stream_write(ctx->stream, (void*)select , header->len ); - if (len != header->len) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "write request error" ,0 TSRMLS_CC); - efree(out_buf); - return; - } + /* send iproto request */ + if (!send_iproto_request(tnt->stream, TARANTOOL_COMMAND_UPDATE, 0, tnt->io_buf)) + return; - Header responseHeader; - bzero(&responseHeader, HEADER_SIZE); + /* + * receive response + */ - len = php_stream_read(ctx->stream, (void *)&responseHeader, HEADER_SIZE); - if (len != HEADER_SIZE) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "read header error" ,0 TSRMLS_CC); - efree(out_buf); - return; - } + /* clean-up buffer */ + io_buf_clean(tnt->io_buf); - ctx->bodyLen = responseHeader.len; + /* receive */ + if (!recv_iproto_response(tnt->stream, tnt->io_buf)) + return; - uint32_t code; + /* read response */ + struct tnt_response *response; + if (!read_struct_io_buf(tnt->io_buf, + (void **) &response, + sizeof(struct tnt_response))) { + raise_exception("update fields failed: invalid response was received"); + return; + } - len = php_stream_read(ctx->stream, (void *) &code,sizeof(uint32_t)); - ctx->readed += len; - if (code > 0 || len != sizeof(uint32_t)) { - ctx->errorcode = code; /// need test - efree(out_buf); - RETURN_FALSE; + /* check return code */ + if (response->return_code) { + /* error happen, throw exceprion */ + raise_exception("update fields failed: %"PRIi32, response->return_code); + return; } -// - uint32_t tuples_count=0; - len = php_stream_read(ctx->stream, (void *) &tuples_count,sizeof(uint32_t)); - ctx->readed += len; - if (len != sizeof(uint32_t)) { - zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), - 0 TSRMLS_CC,"read body error"); - efree(out_buf); + + /* + * fill return value + */ + + if (array_init(return_value) != SUCCESS) { + raise_exception("update fields failed: create array failed"); return; } - ctx->errorcode = code; - ctx->countTuples = tuples_count; - efree(out_buf); + /* put count to result array */ + add_assoc_long(return_value, "count", response->count); - RETURN_LONG(ctx->countTuples); + /* check "return tuple" flag */ + if (flags & TARANTOOL_FLAGS_RETURN_TUPLE) { + /* ok, the responce should contain inserted tuple */ + if (!read_tuple_io_buf(tnt->io_buf, &tuple)) { + raise_exception("update fields failed: invalid response was received"); + return; + } + /* put returned tuple to result array */ + add_assoc_zval(return_value, "tuple", tuple); + } } -/* }}} */ -/* {{{ proto int tarantool::call(procname, tuple); - call a stored procedure by name -*/ -PHP_METHOD(tarantool_class, call) +PHP_METHOD(tarantool_class, delete) { - zval *id, * tuple; - tarantool_object *ctx; - const char *procname = NULL; - long procname_len = 0; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osz", &id, - tarantool_class_entry, &procname, &procname_len, &tuple) == FAILURE) { + /* + * parse methods parameters + */ + zval *id; + long space_no = 0; + long flags = 0; + zval *tuple = NULL; + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "Olz|l", + &id, + tarantool_class_ptr, + &space_no, + &tuple, + &flags) == FAILURE) { return; } - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - if (!ctx) - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the context is null" ,0 TSRMLS_CC); + tarantool_object *tnt = (tarantool_object *) zend_object_store_get_object( + id TSRMLS_CC); - if (!ctx->stream) { - if (php_tnt_connect(ctx TSRMLS_CC)) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "can't connect to remote host " ,0 TSRMLS_DC); + /* check connection */ + if (!tnt->stream) { + /* establis connection */ + tnt->stream = establish_connection(tnt->host, tnt->port); + if (!tnt->stream) return; - } } - ctx->bodyLen = 0; - ctx->countTuples = 0; - ctx->readedTuples = 0; - ctx->readed = 0; - ctx->errorcode = 0; - - char *out_buf = emalloc(TARANTOOL_BUFSIZE); - bzero(out_buf, TARANTOOL_BUFSIZE); - - Header *header = (Header *) out_buf; - - header->type = TARANTOOL_CALL; - header->request_id = TARANTOOL_REQUEST_ID; - - u_char *call = (char *) out_buf + HEADER_SIZE; - u_char *p = call; + /* + * send request + */ - p+= 4; /* flags */ - *p++ = (u_char) procname_len; + /* clean-up buffer */ + io_buf_clean(tnt->io_buf); - memcpy(p, procname, procname_len); - p += procname_len; - - int * count_elements = (int *)p; - - switch (Z_TYPE_P(tuple)) { - case IS_STRING: { - *count_elements = 1; - p += sizeof(uint32_t); - - char * strval = Z_STRVAL_P(tuple); - int str_len = Z_STRLEN_P(tuple); - u_char str_shortlen = (u_char)str_len; + /* fill delete command */ + struct tnt_delete_request *request = (struct tnt_delete_request *) io_buf_write_struct( + tnt->io_buf, sizeof(struct tnt_delete_request)); + if (request == NULL) + return; - *(p++) = str_shortlen; - memcpy(p, strval, str_len); - p += str_len; - } - break; + /* space number */ + request->space_no = space_no; + /* flags */ + request->flags = flags; + /* tuple */ + if (!io_buf_write_tuple(tnt->io_buf, tuple)) + return; - case IS_LONG: { - *count_elements = 1; - p += sizeof(uint32_t); + /* send iproto request */ + if (!send_iproto_request(tnt->stream, TARANTOOL_COMMAND_DELETE, 0, tnt->io_buf)) + return; - unsigned long val = Z_LVAL_P(tuple); + /* + * receive response + */ - u_char leb_size = 4; - *(p++) = leb_size; - b2i * pval = (b2i*) p; - pval->i = (int) val; - p += leb_size; + /* clean-up buffer */ + io_buf_clean(tnt->io_buf); - } - break; + /* receive */ + if (!recv_iproto_response(tnt->stream, tnt->io_buf)) + return; + /* read response */ + struct tnt_response *response; + if (!read_struct_io_buf(tnt->io_buf, + (void **) &response, + sizeof(struct tnt_response))) { + raise_exception("delete failed: invalid response was received"); + return; + } - case IS_ARRAY: { - HashTable *pht; - HashPosition pos; - zval **curr; - - *count_elements = zend_hash_num_elements(Z_ARRVAL_P(tuple)); - p += sizeof(uint32_t); - - pht = Z_ARRVAL_P(tuple); - for(zend_hash_internal_pointer_reset_ex(pht, &pos); - zend_hash_get_current_data_ex(pht, (void **)&curr, &pos) == SUCCESS; - zend_hash_move_forward_ex(pht, &pos)) { - - if (Z_TYPE_PP(curr) == IS_STRING) { - char * strval = Z_STRVAL_PP(curr); - int str_len = Z_STRLEN_PP(curr); - // printf("tuple: len=%d [%s]", str_len, strval ); - u_char str_shortlen = (u_char)str_len; - - *(p++) = str_shortlen; - memcpy(p, strval, str_len); - p += str_len; - } - if (Z_TYPE_PP(curr) == IS_LONG) { - unsigned long val = Z_LVAL_PP(curr); - -// u_char leb_size = (u_char)leb128_size( val); -// *(p++) = leb_size; -// leb128_write( (char *)p, val); - u_char leb_size = 4; - *(p++) = leb_size; - b2i * pval = (b2i*) p; - pval->i = (int) val; - - p += leb_size; - } - } + /* check return code */ + if (response->return_code) { + /* error happen, throw exceprion */ + raise_exception("delete failed: %"PRIi32, response->return_code); + return; + } + + /* + * fill return value + */ - } - break; - default : - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "tuple: unsuport tuple type" ,0 TSRMLS_CC); - return; + if (array_init(return_value) != SUCCESS) { + raise_exception("delete failed: create array failed"); + return; } - header->len = p - call; + /* put count to result array */ + add_assoc_long(return_value, "count", response->count); - // write header - int len = php_stream_write(ctx->stream, out_buf, HEADER_SIZE); // 12 - if (len != HEADER_SIZE) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "write header error" ,0 TSRMLS_CC); - efree(out_buf); + /* check "return tuple" flag */ + if (flags & TARANTOOL_FLAGS_RETURN_TUPLE) { + /* ok, the responce should contain inserted tuple */ + if (!read_tuple_io_buf(tnt->io_buf, &tuple)) { + raise_exception("delete failed: invalid response was received"); return; + } + + /* put returned tuple to result array */ + add_assoc_zval(return_value, "tuple", tuple); } +} - len = php_stream_write(ctx->stream, call, header->len ); - if (len != header->len) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "write request error" ,0 TSRMLS_CC); - efree(out_buf); - return; +PHP_METHOD(tarantool_class, call) +{ + /* + * parse methods parameters + */ + zval *id; + char *proc_name = NULL; + int proc_name_len = 0; + zval *tuple = NULL; + long flags = 0; + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "Osz|l", + &id, + tarantool_class_ptr, + &proc_name, &proc_name_len, + &tuple, + &flags) == FAILURE) { + return; } - Header responseHeader; - bzero(&responseHeader, HEADER_SIZE); + tarantool_object *tnt = (tarantool_object *) zend_object_store_get_object( + id TSRMLS_CC); - len = php_stream_read(ctx->stream, (void *)&responseHeader, HEADER_SIZE); - if (len != HEADER_SIZE) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "read header error" ,0 TSRMLS_CC); - efree(out_buf); + /* check connection */ + if (!tnt->stream) { + /* establis connection */ + tnt->stream = establish_connection(tnt->host, tnt->port); + if (!tnt->stream) return; } - ctx->bodyLen = responseHeader.len; + /* + * send request + */ - uint32_t code; + /* clean-up buffer */ + io_buf_clean(tnt->io_buf); - len = php_stream_read(ctx->stream, (void *) &code,sizeof(uint32_t)); - ctx->readed += len; - if (code > 0 || len != sizeof(uint32_t)) { - ctx->errorcode = code; /// need test - efree(out_buf); - RETURN_FALSE; - } -// - uint32_t tuples_count=0; - len = php_stream_read(ctx->stream, (void *) &tuples_count,sizeof(uint32_t)); - ctx->readed += len; - if (len != sizeof(uint32_t)) { - zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), - 0 TSRMLS_CC,"read body error"); - efree(out_buf); + /* fill insert command */ + struct tnt_call_request *request = (struct tnt_call_request *) io_buf_write_struct( + tnt->io_buf, sizeof(struct tnt_call_request)); + if (request == NULL) return; - } - ctx->errorcode = code; - ctx->countTuples = tuples_count; - efree(out_buf); + /* flags */ + request->flags = flags; + /* proc name */ + if (!io_buf_write_field(tnt->io_buf, proc_name, proc_name_len)) + return; + /* tuple */ + if (!io_buf_write_tuple(tnt->io_buf, tuple)) + return; - RETURN_LONG(ctx->countTuples); + /* send iproto request */ + if (!send_iproto_request(tnt->stream, TARANTOOL_COMMAND_CALL, 0, tnt->io_buf)) + return; -} -/* }}} */ + /* + * receive response + */ -/* {{{ proto array tarantool::getTuple() - return one tuple */ -PHP_METHOD(tarantool_class, getTuple ) -{ - zval *id; - tarantool_object *ctx; + /* clean-up buffer */ + io_buf_clean(tnt->io_buf); - int len; + /* receive */ + if (!recv_iproto_response(tnt->stream, tnt->io_buf)) + return; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, - tarantool_class_entry) == FAILURE) { + /* read response */ + struct tnt_response *response; + if (!read_struct_io_buf(tnt->io_buf, + (void **) &response, + sizeof(struct tnt_response))) { + raise_exception("call failed: invalid response was received"); return; } - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - if (!ctx) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the context is null" ,0 TSRMLS_CC); + /* check return code */ + if (response->return_code) { + /* error happen, throw exceprion */ + raise_exception("call failed: %"PRIi32, response->return_code); return; } - if (!ctx->bodyLen) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the response body is null" ,0 TSRMLS_CC); + if (array_init(return_value) != SUCCESS) { + raise_exception("call failed: create array failed"); return; } - if (++ctx->readedTuples > ctx->countTuples) { - RETURN_FALSE; - } + /* put count to result array */ + add_assoc_long(return_value, "count", response->count); - if (ctx->readed >= ctx->bodyLen) { - RETURN_FALSE; + /* put tuple list to result array */ + zval *tuples_list; + MAKE_STD_ZVAL(tuples_list); + if (array_init(tuples_list) == FAILURE) { + raise_exception("call failed: create array failed"); + return; } + /* read tuples for responce */ + int i; + for (i = 0; i < response->count; ++i) { + zval *tuple; + if (!read_tuple_io_buf(tnt->io_buf, &tuple)) { + raise_exception("call failed: invalid response was received"); + return; + } + add_next_index_zval(tuples_list, tuple); + } - SelectResponseTuple responseBody; + add_assoc_zval(return_value, "tuples_list", tuples_list); +} - if (php_stream_read(ctx->stream, (void*)&responseBody, sizeof(SelectResponseTuple)) !=sizeof(SelectResponseTuple)) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the read body error" ,0 TSRMLS_CC); +PHP_METHOD(tarantool_class, admin) +{ + /* parse methods parameters */ + zval *id; + char *cmd = NULL; + int cmd_len = 0; + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, + getThis(), + "Os", + &id, + tarantool_class_ptr, + &cmd, &cmd_len) == FAILURE) { return; } - ctx->readed += sizeof(SelectResponseTuple); + tarantool_object *tnt = (tarantool_object *) zend_object_store_get_object( + id TSRMLS_CC); - u_char * buf = emalloc(responseBody.size); - - if (php_stream_read(ctx->stream, (char*) buf, responseBody.size) != responseBody.size) { - efree(buf); - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the read tuple error" ,0 TSRMLS_CC); + /* check admin port */ + if (!tnt->admin_port) { + raise_exception("admin command not allowed for this commection"); return; } - ctx->readed += responseBody.size; - - array_init(return_value); - - char bb2[16]; - int i; - unsigned long value; - b2i b; - b2i * pb; - u_char* p = buf; - int is_string = 0; - - for(i=0; i < responseBody.count; i++) { // - b.i=0; - b.b = *p; - bzero(bb2,16); - len = b.i; - memcpy(bb2, p+1, len); - - switch (len) { - case 1 : { - if ( isprint(*bb2) ) { -// printf("tuple element '%s' len=%d\n",bb2, len); - is_string = 1; - } else { - is_string = 0; - leb128_read(bb2, len, &value); -// printf("tuple element(int) %d len=%d\n",value, len); - } - break; - } - case 2 : { - if ( isprint(*bb2) && isprint(*(bb2+1))) { -// printf("tuple element '%s' len=%d\n",bb2, len); - is_string = 1; - } else { - is_string = 0; - leb128_read(bb2, len, &value); -// printf("tuple element(int) %d len=%d\n",value, len); - } - break; - } - - case 3 : { - if ( isprint(*bb2) && isprint(*(bb2+1)) && isprint(*(bb2+2)) ) { -// printf("tuple element '%s' len=%d\n",bb2, len); - is_string = 1; - } else { - is_string = 0; - leb128_read(bb2, len, &value); -// printf("tuple element(int) %d len=%d\n",value, len); - } - break; - } - - case 4 : { - if ( isprint(*bb2) && isprint(*(bb2+1)) && isprint(*(bb2+2)) && isprint(*(bb2+3)) ) { - is_string = 1; - } else { - - pb = (b2i*) bb2; - value = (unsigned long) pb->i; -// php_printf("tuple element(int) %d len=%d\n",value, len); - is_string = 0; - } - break; - } - default : { - is_string = 0; -// printf("tuple element %s len=%d\n",bb2, len); - } - } // end switch - - - if (is_string) { -// php_printf("tuple element '%s' len=%d\n",bb2, len); - add_next_index_stringl( return_value, bb2 , len , 1); - } else -// php_printf("tuple element %d\n",bb2, value); - add_next_index_long( return_value, value); + /* check connection */ + if (!tnt->admin_stream) { + /* establis connection */ + tnt->admin_stream = establish_connection(tnt->host, tnt->admin_port); + if (!tnt->admin_stream) + return; - p += len+1; + /* set string eol */ + php_stream_locate_eol(tnt->admin_stream, + ADMIN_SEPARATOR, + strlen(ADMIN_SEPARATOR) TSRMLS_DC); } - efree(buf); -} -/* }}} */ - -/* {{{ proto int tarantool::delete(key) - tarantool delete tuple */ -PHP_METHOD(tarantool_class, delete) -{ - zval *id; - tarantool_object *ctx; - long space; - - zval* data; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olz", - &id, tarantool_class_entry, &space, &data) == FAILURE) { + /* send request */ + io_buf_clean(tnt->io_buf); + if (!io_buf_write_str(tnt->io_buf, cmd, cmd_len)) return; - } - - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - if (!ctx) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the context is null" ,0 TSRMLS_CC); + if (!io_buf_write_str(tnt->io_buf, ADMIN_SEPARATOR, strlen(ADMIN_SEPARATOR))) + return; + if (!send_admin_request(tnt->admin_stream, tnt->io_buf)) return; - } - - ctx->bodyLen = 0; - ctx->countTuples = 0; - ctx->readedTuples = 0; - ctx->readed = 0; - - if (!ctx->stream) { - if (php_tnt_connect(ctx TSRMLS_CC)) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the can't open remote host " ,0 TSRMLS_DC); - return; - } - } - - char * buf = emalloc(TARANTOOL_BUFSIZE); - bzero(buf, TARANTOOL_BUFSIZE); - - Header * header = (Header *) buf; - DeleteRequest * delRequest = (DeleteRequest *) buf + HEADER_SIZE; - - header->type = TARANTOOL_DELETE; - header->request_id = TARANTOOL_REQUEST_ID; - - delRequest->spaceNo = space; - delRequest->tuple.count = 1; // count in the Tuples - - u_char * p = (u_char *) delRequest->tuple.data; - - int * count_elements = (int *)p; - - switch (Z_TYPE_P(data)) { - case IS_STRING: { - char * strval = Z_STRVAL_P(data); - int str_len = Z_STRLEN_P(data); - u_char str_shortlen = (u_char)str_len; + /* recv response */ + io_buf_clean(tnt->io_buf); + if (!recv_admin_response(tnt->admin_stream, tnt->io_buf)) + return; - *(p++) = str_shortlen; - memcpy(p, strval, str_len); - p += str_len; - } - break; + char *response = estrndup(tnt->io_buf->value, tnt->io_buf->size); + RETURN_STRING(response, 0); +} - case IS_LONG: { - unsigned long val = Z_LVAL_P(data); - u_char leb_size = (u_char)leb128_size( val); - *(p++) = leb_size; - leb128_write( (char *)p, val); - p += leb_size; +/*============================================================================* + * local functions definition + *============================================================================*/ -// printf("tuple: int %d\n", val ); - } - break; - case IS_ARRAY: { - HashTable *pht; - HashPosition pos; - zval **curr; - - delRequest->tuple.count = zend_hash_num_elements(Z_ARRVAL_P(data)); - pht = Z_ARRVAL_P(data); - for(zend_hash_internal_pointer_reset_ex(pht, &pos); - zend_hash_get_current_data_ex(pht, (void **)&curr, &pos) == SUCCESS; - zend_hash_move_forward_ex(pht, &pos)) { - - if (Z_TYPE_PP(curr) == IS_STRING) { - char * strval = Z_STRVAL_PP(curr); - int str_len = Z_STRLEN_PP(curr); - u_char str_shortlen = (u_char)str_len; - - *(p++) = str_shortlen; - memcpy(p, strval, str_len); - p += str_len; - } - if (Z_TYPE_PP(curr) == IS_LONG) { - unsigned long val = Z_LVAL_PP(curr); - - u_char leb_size = (u_char)leb128_size( val); - *(p++) = leb_size; - leb128_write( (char *)p, val); - p += leb_size; - } - } +/*----------------------------------------------------------------------------* + * Buffer interface + *----------------------------------------------------------------------------*/ - } - break; - default : - efree(buf); - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "tuple: unsuport tuple type" ,0 TSRMLS_CC); - return; +static struct io_buf * +io_buf_create() +{ + struct io_buf *buf = (struct io_buf *) emalloc(sizeof(struct io_buf)); + if (!buf) { + raise_exception("allocation memory fail: %s (%i)", strerror(errno), errno); + goto failure; } - header->len = (p-delRequest->tuple.data) + sizeof(uint32_t) *2 ; // sizeof(int) + sizeof(int) - - // write header - int len = php_stream_write(ctx->stream, buf , HEADER_SIZE); // 12 - - // write tuple - p = (u_char*)delRequest; - len = php_stream_write(ctx->stream, (char*)p , header->len ); - - if (header->len + HEADER_SIZE > TARANTOOL_BUFSIZE) { - efree(buf); - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "out of memory: the tuple is very big" ,0 TSRMLS_CC); - return; + buf->size = 0; + buf->capacity = io_buf_next_capacity(buf->size); + buf->readed = 0; + buf->value = (uint8_t *) emalloc(buf->capacity); + if (!buf->value) { + raise_exception("allocation memory fail: %s (%i)", strerror(errno), errno); + goto failure; } - bzero(buf, header->len + HEADER_SIZE); + return buf; - len = php_stream_read(ctx->stream, buf, TARANTOOL_BUFSIZE); +failure: + if (buf) { + if (buf->value) + efree(buf->value); - if ( *(buf+HEADER_SIZE) == '\0') { - int deleted = *(buf+HEADER_SIZE + sizeof(uint32_t)); efree(buf); - RETURN_LONG(deleted); } - - b2i* bb =(b2i*)(buf+HEADER_SIZE); - ctx->errorcode = bb->i; - - efree(buf); - RETURN_FALSE; - + return NULL; } -/* }}} */ -/* {{{ proto int tarantool::update(int space, mixed key, array data); - tarantool update tuple */ -PHP_METHOD(tarantool_class, update) +static void +io_buf_destroy(struct io_buf *buf) { - zval *id; - tarantool_object *ctx; - long space; - - zval* key; - zval* data; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olza", - &id, tarantool_class_entry, &space, &key, &data) == FAILURE) { - return; - } - - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - if (!ctx) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the context is null" ,0 TSRMLS_CC); - return; - } - - ctx->bodyLen = 0; - ctx->countTuples = 0; - ctx->readedTuples = 0; - ctx->readed = 0; - ctx->errorcode = 0; - - if (!ctx->stream) { - if (php_tnt_connect(ctx TSRMLS_CC)) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the can't open remote host " ,0 TSRMLS_DC); - return; - } - } - -// <insert_request_body> ::= <space_no><flags><tuple> -// <update_request_body> ::= <space_no><flags><tuple><count><operation>+ -// <operation> ::= <field_no><op_code><op_arg> - - char * out_buf = emalloc(TARANTOOL_BUFSIZE); - bzero(out_buf, TARANTOOL_BUFSIZE); - - Header * header = (Header *) out_buf; - - header->type = TARANTOOL_UPDATE; - header->request_id = TARANTOOL_REQUEST_ID; - - InsertRequest * insert = (InsertRequest *) (out_buf + HEADER_SIZE); - - insert->spaceNo = space; - insert->tuple.count = 1; - - u_char * p = (u_char *) insert->tuple.data; - - switch (Z_TYPE_P(key)) { - case IS_STRING: { -// *count_elements = 1; //!!!! <------- êîë-âî ýëåìåíòîâ â êîðòåæå -// p += sizeof(uint32_t); - - char * strval = Z_STRVAL_P(key); - int str_len = Z_STRLEN_P(key); - u_char str_shortlen = (u_char)str_len; - - *(p++) = str_shortlen; - memcpy(p, strval, str_len); - p += str_len; - -// printf("tuple: len=%d [%s]\n", str_len, strval ); - } - break; - - case IS_LONG: { -// *count_elements = 1; //!!!! <------- êîë-âî ýëåìåíòîâ â êîðòåæå -// p += sizeof(uint32_t); - - unsigned long val = Z_LVAL_P(key); - - u_char leb_size = 4; //(u_char)leb128_size( val); - *(p++) = leb_size; - - b2i * pb = (b2i*) p; - pb->i = (uint32_t) val; -// leb128_write( (char *)p, val); - p += leb_size; - -// printf("tuple: int %d\n", val ); - } - break; - - default : - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "unsupport key type" ,0 TSRMLS_CC); - return; - } - - const int insertLen = p-insert->tuple.data; - - - HashTable *pht = Z_ARRVAL_P(data); - - UpdateRequest * updateRequest = (UpdateRequest*) p; - updateRequest->count = zend_hash_num_elements(pht);; - - HashPosition pos; - zval** curr; - - char *ht_key; - ulong index; - uint ht_key_len; - - Operation * operation = &(updateRequest->operation); - - for(zend_hash_internal_pointer_reset_ex(pht, &pos); - zend_hash_get_current_data_ex(pht, (void **) &curr, &pos) == SUCCESS; - zend_hash_move_forward_ex(pht,&pos)) { - - if (HASH_KEY_IS_LONG != zend_hash_get_current_key_ex(pht, &ht_key, &ht_key_len, &index, 0, &pos)) { - efree(out_buf); - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "key type error" ,0 TSRMLS_CC); - return; - } - - operation->code = TARANTOOL_OP_ASSIGN; - operation->fieldNo = index; - p = operation->arg; - - if (Z_TYPE_PP(curr) == IS_STRING) { - char * strval = Z_STRVAL_PP(curr); - int str_len = Z_STRLEN_PP(curr); - - u_char str_shortlen = (u_char)str_len; - - *(p++) = str_shortlen; - memcpy(p, strval, str_len); - p += str_len; - } - if (Z_TYPE_PP(curr) == IS_LONG) { - unsigned long val = Z_LVAL_PP(curr); - - u_char leb_size = 4; - *(p++) = leb_size; - b2i * pb = (b2i*) p; - pb->i = (uint32_t) val; - p += leb_size; - } - - operation = (Operation*)p; - } - - u_char * p2 = (u_char *) insert; - header->len = (uint32_t) (p-p2); - - // write header - int len = php_stream_write(ctx->stream, out_buf , HEADER_SIZE); // 12 - if (len!=HEADER_SIZE) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "error write header" ,0 TSRMLS_CC); + if (!buf) return; - } -// write tuple - p = (u_char*) out_buf+HEADER_SIZE; - len = php_stream_write(ctx->stream, (char*)p , header->len ); // - if (len != header->len) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "error write body" ,0 TSRMLS_CC); - return; - } - - bzero(out_buf, header->len + HEADER_SIZE); -// - len = php_stream_read(ctx->stream, out_buf, TARANTOOL_BUFSIZE); - - if ( *(out_buf+HEADER_SIZE) == '\0') { - efree(out_buf); - RETURN_TRUE; - } - - b2i* bb = (b2i*) out_buf+HEADER_SIZE; - ctx->errorcode = bb->i; - - efree(out_buf); - RETURN_FALSE; + if (buf->value) + efree(buf->value); + efree(buf); } -/* }}} */ - -/* {{{ proto int tarantool::inc(int space, mixed key, int fieldNo, [data = 1, flag=0]); - $tnt->inc($NS,$key, $fieldNo , $inc=1; ); - tarantool incremental tuple */ -PHP_METHOD(tarantool_class, inc) +inline static bool +io_buf_reserve(struct io_buf *buf, size_t n) { - zval *id; - tarantool_object *ctx; - long space, fieldNo ; - zval* key; - long data = 1; - long flag = 0; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olzl|lb", - &id, tarantool_class_entry, &space, &key, &fieldNo, &data, &flag) == FAILURE) { - return; - } + if (buf->capacity > n) + return true; - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - if (!ctx) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the context is null" ,0 TSRMLS_CC); - return; - } - - ctx->bodyLen = 0; - ctx->countTuples = 0; - ctx->readedTuples = 0; - ctx->readed = 0; - ctx->errorcode = 0; - - if (!ctx->stream) { - if (php_tnt_connect(ctx TSRMLS_CC)) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the can't open remote host " ,0 TSRMLS_DC); - return; - } + size_t new_capacity = io_buf_next_capacity(n); + uint8_t *new_value = (uint8_t *) erealloc(buf->value, new_capacity); + if (!new_value) { + raise_exception("allocation memory fail: %s (%i)", strerror(errno), errno); + return false; } -// <insert_request_body> ::= <space_no><flags><tuple> -// <update_request_body> ::= <space_no><flags><tuple><count><operation>+ - -// <operation> ::= <field_no><op_code><op_arg> - - char * out_buf = emalloc(TARANTOOL_BUFSIZE); - bzero(out_buf, TARANTOOL_BUFSIZE); - - - Header * header = (Header *) out_buf; - - - header->type = TARANTOOL_UPDATE; - header->request_id = TARANTOOL_REQUEST_ID; - - InsertRequest * insert = (InsertRequest *) (out_buf + HEADER_SIZE); - - insert->spaceNo = space; - insert->tuple.count = 1; - insert->flag = flag; - - u_char * p = (u_char *) insert->tuple.data; - - switch (Z_TYPE_P(key)) { - case IS_STRING: { -// *count_elements = 1; //!!!! <------- êîë-âî ýëåìåíòîâ â êîðòåæå -// p += sizeof(uint32_t); - - char * strval = Z_STRVAL_P(key); - int str_len = Z_STRLEN_P(key); - u_char str_shortlen = (u_char)str_len; + buf->capacity = new_capacity; + buf->value = new_value; + return true; +} - *(p++) = str_shortlen; - memcpy(p, strval, str_len); - p += str_len; +inline static bool +io_buf_resize(struct io_buf *buf, size_t n) +{ + io_buf_reserve(buf, n); + buf->size = n; + return true; +} -// printf("tuple: len=%d [%s]\n", str_len, strval ); - } - break; +inline static size_t +io_buf_next_capacity(size_t n) +{ + size_t capacity = IO_BUF_CAPACITY_MIN; + while (capacity < n) + capacity *= IO_BUF_CAPACITY_FACTOR; + return capacity; +} - case IS_LONG: { -// *count_elements = 1; //!!!! <------- êîë-âî ýëåìåíòîâ â êîðòåæå -// p += sizeof(uint32_t); +static void +io_buf_clean(struct io_buf *buf) +{ + buf->size = 0; + buf->readed = 0; +} - unsigned long val = Z_LVAL_P(key); +static bool +read_struct_io_buf(struct io_buf *buf, void **ptr, size_t n) +{ + size_t last = buf->size - buf->readed; + if (last < n) + return false; + *ptr = buf->value + buf->readed; + buf->readed += n; + return true; +} - u_char leb_size = 4; //(u_char)leb128_size( val); - *(p++) = leb_size; +static bool +read_int_io_buf(struct io_buf *buf, int32_t *val) +{ + size_t last = buf->size - buf->readed; + if (last < sizeof(int32_t)) + return false; + *val = *(int32_t *)(buf->value + buf->readed); + buf->readed += sizeof(int32_t); + return true; +} - b2i * pb = (b2i*) p; - pb->i = (uint32_t) val; -// leb128_write( (char *)p, val); - p += leb_size; +static bool +read_varint_io_buf(struct io_buf *buf, int32_t *val) +{ + uint8_t *b = buf->value + buf->readed; + size_t size = buf->size - buf->readed; -// printf("tuple: int %d\n", val ); - } - break; + if (size < 1) + return false; - default : - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "unsupport key type" ,0 TSRMLS_CC); - return; + if (!(b[0] & 0x80)) { + buf->readed += 1; + *val = (b[0] & 0x7f); + return true; } - const int insertLen = p-insert->tuple.data; - - UpdateRequest * incRequest = (UpdateRequest*) p; - incRequest->count = 1; - incRequest->operation.code = TARANTOOL_OP_ADD; - incRequest->operation.fieldNo = fieldNo; - - u_char leb_size = '\4'; - if (data == 1) { - incRequest->operation.arg[0] = leb_size; - incRequest->operation.arg[1] = '\1'; - incRequest->operation.arg[2] = '\0'; - incRequest->operation.arg[3] = '\0'; - incRequest->operation.arg[4] = '\0'; + if (size < 2) + return false; - } else { - p = incRequest->operation.arg; - *(p++) = leb_size; - b2i * pb = (b2i*) p; - pb->i = (int) data; - p += leb_size; + if (!(b[1] & 0x80)) { + buf->readed += 2; + *val = (b[0] & 0x7f) << 7 | (b[1] & 0x7f); + return true; } - header->len = INSERT_REQUEST_SIZE + insertLen + UPDATE_REQUEST_SIZE + (int)leb_size; - - // write header - int len = php_stream_write(ctx->stream, out_buf , HEADER_SIZE); // 12 - if (len!=HEADER_SIZE) { - efree(out_buf); - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "error write header" ,0 TSRMLS_CC); - return; - } + if (size < 3) + return false; -// write tuple - p = (u_char*) out_buf+HEADER_SIZE; - len = php_stream_write(ctx->stream, (char*)p , header->len ); // - if (len != header->len) { - efree(out_buf); - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "error write body" ,0 TSRMLS_CC); - return; + if (!(b[2] & 0x80)) { + buf->readed += 3; + *val = (b[0] & 0x7f) << 14 | (b[1] & 0x7f) << 7 | (b[2] & 0x7f); + return true; } + if (size < 4) + return false; - bzero(out_buf, header->len + HEADER_SIZE); -// - len = php_stream_read(ctx->stream, out_buf, TARANTOOL_BUFSIZE); - - if ( *(out_buf+HEADER_SIZE) != '\0') { - b2i* bb = (b2i*)(out_buf+HEADER_SIZE); - ctx->errorcode = bb->i; - efree(out_buf); - RETURN_FALSE; + if (!(b[3] & 0x80)) { + buf->readed += 4; + *val = (b[0] & 0x7f) << 21 | (b[1] & 0x7f) << 14 | + (b[2] & 0x7f) << 7 | (b[3] & 0x7f); + return true; } - if( !flag) - RETURN_TRUE; - - Response * responseBody = (Response*) (out_buf+HEADER_SIZE); - SelectResponseTuple * responseTuple = (SelectResponseTuple*) responseBody->data; - - p = responseBody->data + SELECT_RESPONSE_SIZE; + if (size < 5) + return false; - int i=0; - int8_t * size; - while (i < fieldNo) { - size = (int8_t*) p; - p += *size+1; - i++; + if (!(b[4] & 0x80)) { + buf->readed += 5; + *val = (b[0] & 0x7f) << 28 | (b[1] & 0x7f) << 21 | + (b[2] & 0x7f) << 14 | (b[3] & 0x7f) << 7 | (b[4] & 0x7f); + return true; } - b2i* bb = (b2i*)(p+1); - - efree(out_buf); - RETURN_LONG(bb->i); - - + return false; } -/* }}} */ - -/* {{{ proto string tarantool::getError(); - returb tarantool error string */ - -PHP_METHOD(tarantool_class, getError) +static bool +read_str_io_buf(struct io_buf *buf, char **str, size_t len) { - zval *id; - tarantool_object *ctx; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, - tarantool_class_entry) == FAILURE) { - return; - } - - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - if (!ctx) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the context is null" ,0 TSRMLS_CC); - return; - } - - switch(ctx->errorcode) { - case 0: { RETURN_STRING("Result Ok",1); break; } - case 258: {RETURN_STRING("Non master connection, but it should be",1); break; } - case 514: {RETURN_STRING("Illegal parametrs",1); break; } - case 770: {RETURN_STRING("Uid not from this storage range",1); break; } - case 1025: {RETURN_STRING("Node is marked as read-only",1); break; } - case 1281: {RETURN_STRING("Node isn't locked",1); break; } - case 1537: {RETURN_STRING("Node is locked",1); break; } - case 1793: {RETURN_STRING("Some memory issues",1); break; } - case 0x00000802: {RETURN_STRING("Bad graph integrity",1); break; } - case 0x00000a02: {RETURN_STRING("Unsupported command",1); break; } - case 0x00001801: {RETURN_STRING("Can't register new user",1); break; } - case 0x00001a01: {RETURN_STRING("Can't generate alert id",1); break; } - case 0x00001b02: {RETURN_STRING("Can't del node",1); break; } - case 0x00001c02: {RETURN_STRING("User isn't registered",1); break; } - case 0x00001d02: {RETURN_STRING("Syntax error in query",1); break; } - case 0x00001e02: {RETURN_STRING("Unknown field",1); break; } - case 0x00001f02: {RETURN_STRING("Number value is out of range",1); break; } - case 0x00002002: {RETURN_STRING("Insert already existing object",1); break; } - case 0x00002202: {RETURN_STRING("Can not order result",1); break; } - case 0x00002302: {RETURN_STRING("Multiple to update/delete",1); break; } - case 0x00002400: {RETURN_STRING("nothing to do (not an error)",1); break; } - case 0x00002502: {RETURN_STRING("id's update",1); break; } - case 0x00002602: {RETURN_STRING("unsupported version of protocol",1); break; } - - case 0x00002702: {RETURN_STRING("Unknow error",1); break; } - case 0x00003102: {RETURN_STRING("Node not found",1); break; } - - case 0x00003702: {RETURN_STRING("Node found",1); break; } - case 0x00003802: {RETURN_STRING("INDEX violation",1); break; } - case 0x00003902: {RETURN_STRING("No such space",1); break; } - - default : { - char * err_string; - int len = spprintf(&err_string, 0, "Unknow error code : %X\n", ctx->errorcode); - RETVAL_STRINGL(err_string, len,1); - efree(err_string); - } - } - + size_t last = buf->size - buf->readed; + if (last < len) + return false; + *str = (char *)(buf->value + buf->readed); + buf->readed += len; + return true; } -/* }}}*/ - -/* {{{ proto string tarantool::getInfo(); - return tarantool info string */ -PHP_METHOD(tarantool_class, getInfo) +static bool +read_field_io_buf(struct io_buf *buf, zval *tuple) { - zval *id; - tarantool_object *ctx; - size_t response_len=0; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, - tarantool_class_entry) == FAILURE) { - return; - } - - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - if (!ctx) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the context is null" ,0 TSRMLS_CC); - return; - } - - if (!ctx->admin_stream) { - if (php_tnt_admin_connect(ctx TSRMLS_CC)) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the can't open remote host " ,0 TSRMLS_DC); - return; - } - } - - if (php_stream_write(ctx->admin_stream, TARANTOOL_SHOW_INFO, TARANTOOL_SHOW_INFO_SIZE) != TARANTOOL_SHOW_INFO_SIZE) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "Failed sending command" ,0 TSRMLS_DC); - return; - } - - char * buf=emalloc(TARANTOOL_SMALL_BUFSIZE); - bzero(buf,TARANTOOL_SMALL_BUFSIZE); - - response_len = php_stream_read(ctx->admin_stream, buf, TARANTOOL_SMALL_BUFSIZE); - - if (response_len) { - RETVAL_STRINGL(buf,response_len,1); - efree(buf); - return; + int32_t field_length; + + if (!read_varint_io_buf(buf, &field_length)) + return false; + + int32_t i32_val; + char *str_val; + switch (field_length) { + case sizeof(int32_t): + if (!read_int_io_buf(buf, &i32_val)) + return false; + add_next_index_long(tuple, i32_val); + break; + default: + if (!read_str_io_buf(buf, &str_val, field_length)) + return false; + add_next_index_stringl(tuple, str_val, field_length, true); } - efree(buf); - RETURN_FALSE; - + return true; } -/* }}}*/ -/* {{{ proto string tarantool::getConf(); - returb tarantool info string */ -PHP_METHOD(tarantool_class, getConf) +static bool +read_tuple_io_buf(struct io_buf *buf, zval **tuple) { - zval *id; - tarantool_object *ctx; - size_t response_len=0; - - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, - tarantool_class_entry) == FAILURE) { - return; + MAKE_STD_ZVAL(*tuple); + if (array_init(*tuple) == FAILURE) { + return false; } - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - if (!ctx) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the context is null" ,0 TSRMLS_CC); - return; - } + int32_t size; + if (!read_int_io_buf(buf, &size)) + return false; - if (!ctx->admin_stream) { - if (php_tnt_admin_connect(ctx TSRMLS_CC)) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the can't open remote host " ,0 TSRMLS_DC); - return; - } - } - - if (php_stream_write(ctx->admin_stream, TARANTOOL_SHOW_CONF, TARANTOOL_SHOW_CONF_SIZE) != TARANTOOL_SHOW_CONF_SIZE) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "Failed sending command" ,0 TSRMLS_DC); - return; - } - - char * buf = emalloc(TARANTOOL_BUFSIZE); - response_len = php_stream_read(ctx->admin_stream, buf, TARANTOOL_BUFSIZE); + int32_t cardinality; + if (!read_int_io_buf(buf, &cardinality)) + return false; - if (response_len) { - RETVAL_STRINGL(buf,response_len,1); - efree(buf); - return; + while (cardinality > 0) { + if (!read_field_io_buf(buf, *tuple)) + return false; + cardinality -= 1; } - efree(buf); - RETURN_FALSE; + return true; +} +static void * +io_buf_write_struct(struct io_buf *buf, size_t n) +{ + if (!io_buf_reserve(buf, buf->size + n)) + return NULL; + void *ptr = buf->value + buf->size; + buf->size += n; + return ptr; } -/* }}}*/ -/* {{{ proto string tarantool::getStat(); - returb tarantool statistic string */ -PHP_METHOD(tarantool_class, getStat) +static bool +io_buf_write_byte(struct io_buf *buf, int8_t value) { - zval *id; - tarantool_object *ctx; - size_t response_len=0; + if (!io_buf_reserve(buf, buf->size + sizeof(int8_t))) + return false; + *(int8_t *)(buf->value + buf->size) = value; + buf->size += sizeof(uint8_t); + return true; +} - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, - tarantool_class_entry) == FAILURE) { - return; - } +static bool +io_buf_write_int32(struct io_buf *buf, int32_t value) +{ + if (!io_buf_reserve(buf, buf->size + sizeof(int32_t))) + return false; + *(int32_t *)(buf->value + buf->size) = value; + buf->size += sizeof(int32_t); + return true; +} - ctx = (tarantool_object *)zend_object_store_get_object(id TSRMLS_CC); - if (!ctx) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the context is null" ,0 TSRMLS_CC); - return; - } +static bool +io_buf_write_varint(struct io_buf *buf, int32_t value) +{ + if (!io_buf_reserve(buf, buf->size + 5)) + /* reseve maximal varint size (5 bytes) */ + return false; - if (!ctx->admin_stream) { - if (php_tnt_admin_connect(ctx TSRMLS_CC)) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "the can't open remote host " ,0 TSRMLS_DC); - return; + if (value >= (1 << 7)) { + if (value >= (1 << 14)) { + if (value >= (1 << 21)) { + if (value >= (1 << 28)) + io_buf_write_byte(buf, (int8_t)(value >> 28) | 0x80); + io_buf_write_byte(buf, (int8_t)(value >> 21) | 0x80); + } + io_buf_write_byte(buf, (int8_t)((value >> 14) | 0x80)); } + io_buf_write_byte(buf, (int8_t)((value >> 7) | 0x80)); } + io_buf_write_byte(buf, (int8_t)((value) & 0x7F)); - if (php_stream_write(ctx->admin_stream, TARANTOOL_SHOW_STAT, TARANTOOL_SHOW_STAT_SIZE) != TARANTOOL_SHOW_STAT_SIZE) { - zend_throw_exception(zend_exception_get_default(TSRMLS_C), - "Failed sending command" ,0 TSRMLS_DC); - return; - } - - char * buf = emalloc(TARANTOOL_SMALL_BUFSIZE); - bzero(buf,TARANTOOL_SMALL_BUFSIZE); - - response_len = php_stream_read(ctx->admin_stream, buf, TARANTOOL_SMALL_BUFSIZE); - - if (response_len) { - RETVAL_STRINGL(buf,response_len,1); - efree(buf); - return; - } + return true; +} - efree(buf); - RETURN_FALSE; +static bool +io_buf_write_str(struct io_buf *buf, uint8_t *str, size_t len) +{ + if (!io_buf_reserve(buf, buf->size + len)) + return false; + memcpy(buf->value + buf->size, str, len); + buf->size += len; + return true; } -/* }}}*/ -static void printLine( u_char *p ) { - u_char b[4]; - memcpy(b, p, 4); - php_printf("%x %x %x %x\t\t", b[0], b[1], b[2], b[3]); +static bool +io_buf_write_field(struct io_buf *buf, uint8_t *field_value, size_t field_length) +{ + if (!io_buf_write_varint(buf, (int32_t)field_length)) + return false; + if (!io_buf_write_str(buf, field_value, field_length)) + return false; + return true; } -static void printLine3( u_char *p ) { - u_char b[12]; - memcpy(b, p, 12); - php_printf("%x %x %x %x\t\t", b[0], b[1], b[2], b[3]); - php_printf("%x %x %x %x\t\t", b[4], b[5], b[6], b[7]); - php_printf("%x %x %x %x\n", b[8], b[9], b[10], b[11]); +static bool +io_buf_write_tuple_int(struct io_buf *buf, zval *tuple) +{ + /* single field tuple: (int) */ + long long_value = Z_LVAL_P(tuple); + /* write tuple cardinality */ + if (!io_buf_write_int32(buf, 1)) + return false; + /* write field */ + if (!io_buf_write_field(buf, (uint8_t *)&long_value, sizeof(int32_t))) + return false; + + return true; } +static bool +io_buf_write_tuple_str(struct io_buf *buf, zval *tuple) +{ + /* single field tuple: (string) */ + char *str_value = Z_STRVAL_P(tuple); + size_t str_length = Z_STRLEN_P(tuple); + /* write tuple cardinality */ + if (!io_buf_write_int32(buf, 1)) + return false; + /* write field */ + if (!io_buf_write_field(buf, str_value, str_length)) + return false; + + return true; +} -static void -leb128_write(char * buf, unsigned long value) +static bool +io_buf_write_tuple_array(struct io_buf *buf, zval *tuple) { - if (value >= (1 << 7)) { - if (value >= (1 << 14)) { - if (value >= (1 << 21)) { - if (value >= (1 << 28)) - *(buf++) = (value >> 28) | 0x80; - *(buf++) = (value >> 21) | 0x80; - } - *(buf++) = ((value >> 14) | 0x80); + /* multyply tuple array */ + HashTable *hash = Z_ARRVAL_P(tuple); + HashPosition itr; + zval **field; + /* put tuple cardinality */ + io_buf_write_int32(buf, zend_hash_num_elements(hash)); + for (zend_hash_internal_pointer_reset_ex(hash, &itr); + zend_hash_get_current_data_ex(hash, (void **) &field, &itr) == SUCCESS; + zend_hash_move_forward_ex(hash, &itr)) { + char *str_value; + size_t str_length; + long long_value; + + switch (Z_TYPE_PP(field)) { + case IS_STRING: + /* string field */ + str_value = Z_STRVAL_PP(field); + str_length = Z_STRLEN_PP(field); + io_buf_write_field(buf, str_value, str_length); + break; + case IS_LONG: + /* integer field */ + long_value = Z_LVAL_PP(field); + io_buf_write_field(buf, (uint8_t *)&long_value, sizeof(int32_t)); + break; + default: + raise_exception("unsupported field type"); + return false; } - *(buf++) = ((value >> 7) | 0x80); } - *(buf++) = ((value) & 0x7F); + return true; } -static int -leb128_read(char * buf, int size, unsigned long * value) +static bool +io_buf_write_tuple(struct io_buf *buf, zval *tuple) { - *value = 0; - - if (size < 1) - return -1; + switch (Z_TYPE_P(tuple)) { + case IS_LONG: + return io_buf_write_tuple_int(buf, tuple); + case IS_STRING: + return io_buf_write_tuple_str(buf, tuple); + case IS_ARRAY: + return io_buf_write_tuple_array(buf, tuple); + default: + raise_exception("unsupported tuple type"); + return false; + } + + return true; +} - if (!(buf[0] & 0x80)) { +static bool +io_buf_write_tuples_list_array(struct io_buf *buf, zval *tuples_list) +{ + HashTable *hash = Z_ARRVAL_P(tuples_list); + HashPosition itr; + zval **tuple; + + /* write number of tuples */ + if (!io_buf_write_int32(buf, zend_hash_num_elements(hash))) + return false; + + /* write tuples */ + for (zend_hash_internal_pointer_reset_ex(hash, &itr); + zend_hash_get_current_data_ex(hash, (void **) &tuple, &itr) == SUCCESS; + zend_hash_move_forward_ex(hash, &itr)) { + if (Z_TYPE_PP(tuple) != IS_ARRAY) { + raise_exception("invalid tuples list: expected array of array"); + return false; + } - *value = buf[0] & 0x7f; - return 1; + if (!io_buf_write_tuple_array(buf, *tuple)) + return false; } - if (size < 2) - return -1; - - if (!(buf[1] & 0x80)) { + return true; +} - *value = (buf[0] & 0x7f) << 7 | - (buf[1] & 0x7f); - return 2; - } - if (size < 3) - return -1; +static bool +io_buf_write_tuples_list(struct io_buf *buf, zval *tuples_list) +{ + HashTable *hash; + HashPosition itr; + zval **tuple; + + switch (Z_TYPE_P(tuples_list)) { + case IS_LONG: + /* single tuple: long */ + /* write number of tuples */ + if (!io_buf_write_int32(buf, 1)) + return false; + /* write tuple */ + if (!io_buf_write_tuple_int(buf, tuples_list)) + return false; + break; + case IS_STRING: + /* single tuple: string */ + /* write number of tuples */ + if (!io_buf_write_int32(buf, 1)) + return false; + /* write tuple */ + if (!io_buf_write_tuple_str(buf, tuples_list)) + return false; + break; + case IS_ARRAY: + /* array: migth be single or multi tuples array */ + hash = Z_ARRVAL_P(tuples_list); + zend_hash_internal_pointer_reset_ex(hash, &itr); + if (zend_hash_get_current_data_ex(hash, (void **) &tuple, &itr) != SUCCESS) { + raise_exception("invalid tuples list: empty array"); + return false; + } - if (!(buf[2] & 0x80)) { + /* check type of the first element */ + switch (Z_TYPE_PP(tuple)) { + case IS_STRING: + case IS_LONG: + /* single tuple: array */ + /* write tuples count */ + if (!io_buf_write_int32(buf, 1)) + return false; + /* write tuple */ + if (!io_buf_write_tuple_array(buf, tuples_list)) + return false; + break; + case IS_ARRAY: + /* multi tuples list */ + if (!io_buf_write_tuples_list_array(buf, tuples_list)) + return false; + break; + default: + /* invalid element type */ + raise_exception("unsupported tuple type"); + return false; + } - *value = (buf[0] & 0x7f) << 14 | - (buf[1] & 0x7f) << 7 | - (buf[2] & 0x7f); - return 3; + break; + default: + raise_exception("unsupported tuple type"); + return false; } - if (size < 4) - return -1; + return true; +} - if (!(buf[3] & 0x80)) { - *value = (buf[0] & 0x7f) << 21 | - (buf[1] & 0x7f) << 14 | - (buf[2] & 0x7f) << 7 | - (buf[3] & 0x7f); - return 4; - } +/*----------------------------------------------------------------------------* + * Tarantool class functions + *----------------------------------------------------------------------------*/ - if (size < 5) - return -1; - if (!(buf[4] & 0x80)) { +/*----------------------------------------------------------------------------* + * alloc/free classes functions + *----------------------------------------------------------------------------*/ - *value = (buf[0] & 0x7f) << 28 | - (buf[1] & 0x7f) << 21 | - (buf[2] & 0x7f) << 14 | - (buf[3] & 0x7f) << 7 | - (buf[4] & 0x7f); - return 5; - } +static zend_object_value +alloc_tarantool_object(zend_class_entry *entry TSRMLS_DC) +{ + zend_object_value new_value; - return -1; + /* allocate and clean-up instance */ + tarantool_object *tnt = (tarantool_object *) emalloc(sizeof(tarantool_object)); + /* TODO: emalloc result must be checked */ + memset(tnt, 0, sizeof(tarantool_object)); + + /* initialize class instance */ + zend_object_std_init(&tnt->zo, entry TSRMLS_CC); + new_value.handle = zend_objects_store_put( + tnt, + (zend_objects_store_dtor_t) zend_objects_destroy_object, + (zend_objects_free_object_storage_t) free_tarantool_object, + NULL TSRMLS_CC); + new_value.handlers = zend_get_std_object_handlers(); + return new_value; } - -static int -leb128_size(unsigned long value) +static void +free_tarantool_object(tarantool_object *tnt TSRMLS_DC) { - if (value < (1 << 7)) - return 1; - - if (value < (1 << 14)) - return 2; + if (tnt == NULL) + return; - if (value < (1 << 21)) - return 3; + if (tnt->stream) + php_stream_close(tnt->stream); - if (value < (1 << 28)) - return 4; + if (tnt->admin_stream) + php_stream_close(tnt->admin_stream); - return 5; + io_buf_destroy(tnt->io_buf); + io_buf_destroy(tnt->splice_field); + efree(tnt); } + +/*----------------------------------------------------------------------------* + * raise exceation functions + *----------------------------------------------------------------------------*/ + static void -tarantool_dtor(void *object TSRMLS_DC) +raise_exception(const char *format, ...) { - tarantool_object *ctx = (tarantool_object*)object; + /* format exception message */ + va_list ap; + va_start(ap, format); + char *message = NULL; + vspprintf(&message, 0, format, ap); + va_end(ap); + /* check formated message */ + if (message == NULL) + message = "error: can't format error message"; + + /* throw exception */ + zend_throw_exception(zend_exception_get_default(TSRMLS_C), + message, + 0 TSRMLS_DC); +} - if (ctx) { - if (ctx->stream) { - php_stream_close(ctx->stream); - } - if (ctx->admin_stream) { - php_stream_close(ctx->admin_stream); - } +/*----------------------------------------------------------------------------* + * php stream functions + *----------------------------------------------------------------------------*/ - if (ctx->host) { - efree(ctx->host); - } +static php_stream * +establish_connection(char *host, int port) +{ + char *msg = NULL; + /* initialize connection parameters */ + char *dest_addr = NULL; + size_t dest_addr_len = spprintf(&dest_addr, 0, "tcp://%s:%d", host, port); + int options = ENFORCE_SAFE_MODE | REPORT_ERRORS; + int flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT; + struct timeval timeout = { + .tv_sec = TARANTOOL_TIMEOUT_SEC, + .tv_usec = TARANTOOL_TIMEOUT_USEC, + }; + char *error_msg = NULL; + int error_code = 0; + + /* establish connection */ + php_stream *stream = php_stream_xport_create(dest_addr, dest_addr_len, + options, flags, + NULL, &timeout, NULL, + &error_msg, &error_code); + efree(dest_addr); + + /* check result */ + if (error_code && error_msg) { + raise_exception("establist connection fail: %s", error_msg); + efree(error_msg); + return NULL; + } + + return stream; +} +static bool +send_admin_request(php_stream *stream, struct io_buf *buf) +{ + if (php_stream_write(stream, + buf->value, + buf->size) != buf->size) { + raise_exception("send message fail"); + return false; } - zend_object_std_dtor(&ctx->zo TSRMLS_CC); + return true; +} + +static bool +recv_admin_response(php_stream *stream, struct io_buf *buf) +{ + char *line = php_stream_get_line(stream, NULL, 0, NULL); + while (strcmp(line, ADMIN_TOKEN_BEGIN) != 0) { + line = php_stream_get_line(stream, NULL, 0, NULL); + } - efree(object); + line = php_stream_get_line(stream, NULL, 0, NULL); + while (strcmp(line, ADMIN_TOKEN_END) != 0) { + io_buf_write_str(buf, line, strlen(line)); + line = php_stream_get_line(stream, NULL, 0, NULL); + } + return true; } -static zend_object_value tarantool_ctor(zend_class_entry *ce TSRMLS_DC) +static bool +send_iproto_request(php_stream *stream, int32_t type, int32_t request_id, struct io_buf *buf) { - zend_object_value new_value; - tarantool_object* obj = (tarantool_object*)emalloc(sizeof(tarantool_object)); - memset(obj, 0, sizeof(tarantool_object)); + /* send iproto header */ + struct iproto_header header; + header.type = type; + header.length = buf->size; + header.request_id = request_id; - zend_object_std_init(&obj->zo, ce TSRMLS_CC); + size_t length = sizeof(struct iproto_header); + if (php_stream_write(stream, (char *) &header, length) != length) { + raise_exception("send requset failed"); + return false; + } - new_value.handle = zend_objects_store_put(obj, (zend_objects_store_dtor_t)zend_objects_destroy_object, - (zend_objects_free_object_storage_t)tarantool_dtor, NULL TSRMLS_CC); - new_value.handlers = zend_get_std_object_handlers(); + /* send requets */ + if (php_stream_write(stream, buf->value, buf->size) != buf->size) { + raise_exception("send requset failed"); + return false; + } - return new_value; + return true; } -/* {{{ PHP_MINIT_FUNCTION - */ -PHP_MINIT_FUNCTION(tarantool) +static bool +recv_iproto_response(php_stream *stream, struct io_buf *buf) { - zend_class_entry ce; + /* receiving header */ + struct iproto_header header; + size_t length = sizeof(struct iproto_header); + if (php_stream_read(stream, (char *) &header, length) != length) { + raise_exception("receive response failed"); + return false; + } - INIT_CLASS_ENTRY(ce, "Tarantool", tarantool_class_functions); - ce.create_object = tarantool_ctor; - tarantool_class_entry = zend_register_internal_class(&ce TSRMLS_CC); + /* receiving body */ + if (!io_buf_resize(buf, header.length)) + return false; + if (php_stream_read(stream, buf->value, buf->size) != buf->size) { + raise_exception("receive response failed"); + return false; + } - return SUCCESS; + return true; } -/* }}} */ -/* {{{ PHP_MSHUTDOWN_FUNCTION - */ -PHP_MSHUTDOWN_FUNCTION(tarantool) + +/*----------------------------------------------------------------------------* + * php hash functions + *----------------------------------------------------------------------------*/ + +static bool +hash_fing_long(HashTable *hash, char *key, long *value) { - /* uncomment this line if you have INI entries - UNREGISTER_INI_ENTRIES(); - */ - return SUCCESS; + zval **zvalue = NULL; + if (zend_hash_find(hash, key, strlen(key) + 1, (void **)&zvalue) != SUCCESS) + return false; + if (Z_TYPE_PP(zvalue) != IS_LONG) + return false; + *value = Z_LVAL_PP(zvalue); + return true; } -/* }}} */ - -/* {{{ PHP_MINFO_FUNCTION - */ -PHP_MINFO_FUNCTION(tarantool) +static bool +hash_fing_str(HashTable *hash, char *key, char **value, int *value_length) { - php_info_print_table_start(); - php_info_print_table_header(2, "tarantool_box support", "enabled"); - php_info_print_table_row(2, "default host", TARANTOOL_DEF_HOST); - php_info_print_table_row(2, "default port", TARANTOOL_DEF_PORT); - php_info_print_table_row(2, "admin port", TARANTOOL_ADMIN_PORT); - php_info_print_table_row(2, "timeout in sec",TARANTOOL_TIMEOUT); - php_info_print_table_end(); + zval **zvalue = NULL; + if (zend_hash_find(hash, key, strlen(key) + 1, (void **)&zvalue) != SUCCESS) + return false; + if (Z_TYPE_PP(zvalue) != IS_STRING) + return false; + *value = Z_STRVAL_PP(zvalue); + *value_length = Z_STRLEN_PP(zvalue); + return true; +} - /* Remove comments if you have entries in php.ini - DISPLAY_INI_ENTRIES(); - */ +static bool +hash_fing_scalar(HashTable *hash, char *key, zval ***value) +{ + if (zend_hash_find(hash, key, strlen(key) + 1, (void **)value) != SUCCESS) + return false; + if (Z_TYPE_PP(*value) != IS_STRING && Z_TYPE_PP(*value) != IS_LONG) + return false; + return true; } -/* }}} */ + /* * Local variables: diff --git a/connector/php/tarantool.h b/connector/php/tarantool.h index a05dfeacfd..6c52876f5e 100644 --- a/connector/php/tarantool.h +++ b/connector/php/tarantool.h @@ -16,79 +16,163 @@ | Copyright (c) 2011 | +----------------------------------------------------------------------+ */ - -/* $Id: header 252479 2008-02-07 19:39:50Z iliaa $ */ - #ifndef PHP_TARANTOOL_H #define PHP_TARANTOOL_H -extern zend_module_entry tarantool_module_entry; -#define phpext_tarantool_ptr &tarantool_module_entry - -#ifdef PHP_WIN32 -# define PHP_TARANTOOL_API __declspec(dllexport) -#elif defined(__GNUC__) && __GNUC__ >= 4 -# define PHP_TARANTOOL_API __attribute__ ((visibility("default"))) -#else -# define PHP_TARANTOOL_API +#ifdef ZTS +#include "TSRM.h" #endif -#define TARANTOOL_TIMEOUT 5 // sec -#define TARANTOOL_DEF_PORT 33013 -#define TARANTOOL_ADMIN_PORT 33015 -#define TARANTOOL_DEF_HOST "localhost" -#define TARANTOOL_BUFSIZE 2048 -#define TARANTOOL_SMALL_BUFSIZE 256 +/*============================================================================* + * Constants + *============================================================================*/ + + +/*----------------------------------------------------------------------------* + * tbuf constants + *----------------------------------------------------------------------------*/ + +enum { + /* tbuf minimal capacity */ + IO_BUF_CAPACITY_MIN = 128, + /* tbuf factor */ + IO_BUF_CAPACITY_FACTOR = 2, +}; + + +/*----------------------------------------------------------------------------* + * Connections constants + *----------------------------------------------------------------------------*/ + +enum { + /* timeout: seconds */ + TARANTOOL_TIMEOUT_SEC = 5, + /* timeout: microseconds */ + TARANTOOL_TIMEOUT_USEC = 0, + /* tarantool default primary port */ + TARANTOOL_DEFAULT_PORT = 33013, + /* tarantool default readonly port */ + TARANTOOL_DEFAULT_RO_PORT = 33014, + /* tarantool default adnim port */ + TARANTOOL_DEFAULT_ADMIN_PORT = 33015, +}; + +#define TARANTOOL_DEFAULT_HOST "localhost" + + +/*----------------------------------------------------------------------------* + * Commands constants + *----------------------------------------------------------------------------*/ + +/* tarantool/box flags */ +enum { + /* return resulting tuples */ + TARANTOOL_FLAGS_RETURN_TUPLE = 0x01, + /* insert is add operation: errro will be raised if tuple exists */ + TARANTOOL_FLAGS_ADD = 0x02, + /* insert is replace operation: errro will be raised if tuple doesn't exist */ + TARANTOOL_FLAGS_REPLACE = 0x04, + /* doesn't write command to WAL */ + TARANTOOL_FLAGS_NOT_STORE = 0x10, +}; + +/* tarantool command codes */ +enum { + /* insert/replace command code */ + TARANTOOL_COMMAND_INSERT = 13, + /* select command code */ + TARANTOOL_COMMAND_SELECT = 17, + /* update fields command code */ + TARANTOOL_COMMAND_UPDATE = 19, + /* delete command code */ + TARANTOOL_COMMAND_DELETE = 21, + /* call lua function command code */ + TARANTOOL_COMMAND_CALL = 22, + /* pid command code */ + TARANTOOL_COMMAND_PING = 65280, +}; + +/* update fields operation codes */ +enum { + /* update fields: assing field value operation code */ + TARANTOOL_OP_ASSIGN = 0, + /* update fields: add operation code */ + TARANTOOL_OP_ADD = 1, + /* update fields: and operation code */ + TARANTOOL_OP_AND = 2, + /* update fields: xor operation code */ + TARANTOOL_OP_XOR = 3, + /* update fields: or operation code */ + TARANTOOL_OP_OR = 4, + /* update fields: splice operation code */ + TARANTOOL_OP_SPLICE = 5, +}; + + +/*----------------------------------------------------------------------------* + * Amdin commands + *----------------------------------------------------------------------------*/ + +/* admin protocol separator */ +#define ADMIN_SEPARATOR "\r\n" +/* admin command begin token */ +#define ADMIN_TOKEN_BEGIN "---"ADMIN_SEPARATOR +/* admin command end token */ +#define ADMIN_TOKEN_END "..."ADMIN_SEPARATOR + +/* show information admin command */ +#define ADMIN_COMMAND_SHOW_INFO "show info" +/* show statistic admin command */ +#define ADMIN_COMMAND_SHOW_STAT "show stat" +/* show configuration admin command */ +#define ADMIN_COMMAND_SHOW_CONF "show configuration" + + +/*============================================================================* + * Interaface decalaration + *============================================================================*/ + + +/*----------------------------------------------------------------------------* + * Tarantool module interface + *----------------------------------------------------------------------------*/ + +/* initialize module function */ +PHP_MINIT_FUNCTION(tarantool); + +/* shutdown module function */ +PHP_MSHUTDOWN_FUNCTION(tarantool); -#define TARANTOOL_INSERT 13 -#define TARANTOOL_SELECT 17 -#define TARANTOOL_UPDATE 19 -#define TARANTOOL_DELETE 20 -#define TARANTOOL_CALL 22 -#define TARANTOOL_PING 65280 +/* show information about this module */ +PHP_MINFO_FUNCTION(tarantool); -#define TARANTOOL_REQUEST_ID 8 -#define TARANTOOL_OP_ASSIGN 0 -#define TARANTOOL_OP_ADD 1 -#define TARANTOOL_OP_AND 2 -#define TARANTOOL_OP_XOR 3 -#define TARANTOOL_OP_OR 4 +/*----------------------------------------------------------------------------* + * Tarantool class interface + *----------------------------------------------------------------------------*/ -#define TARANTOOL_SHOW_INFO "show info\r\n" -#define TARANTOOL_SHOW_INFO_SIZE sizeof(TARANTOOL_SHOW_INFO) +/* class constructor */ +PHP_METHOD(tarantool_class, __construct); -#define TARANTOOL_SHOW_STAT "show stat\r\n" -#define TARANTOOL_SHOW_STAT_SIZE sizeof(TARANTOOL_SHOW_STAT) +/* do select operation */ +PHP_METHOD(tarantool_class, select); -#define TARANTOOL_SHOW_CONF "show configuration\n" -#define TARANTOOL_SHOW_CONF_SIZE sizeof(TARANTOOL_SHOW_CONF) +/* do insert operation */ +PHP_METHOD(tarantool_class, insert); +/* do update fields operation */ +PHP_METHOD(tarantool_class, update_fields); -#ifdef ZTS -#include "TSRM.h" -#endif +/* do delete operation */ +PHP_METHOD(tarantool_class, delete); -PHP_MINIT_FUNCTION(tarantool); -PHP_MSHUTDOWN_FUNCTION(tarantool); +/* call lua funtion operation */ +PHP_METHOD(tarantool_class, call); -PHP_MINFO_FUNCTION(tarantool); +/* do admin command */ +PHP_METHOD(tarantool_class, admin); -PHP_METHOD( tarantool_class, __construct); - -PHP_METHOD( tarantool_class, insert); -PHP_METHOD( tarantool_class, select); -PHP_METHOD( tarantool_class, mselect); -PHP_METHOD( tarantool_class, call); -PHP_METHOD( tarantool_class, getTuple); -PHP_METHOD( tarantool_class, delete); -PHP_METHOD( tarantool_class, update); -PHP_METHOD( tarantool_class, inc); -PHP_METHOD( tarantool_class, getError); -PHP_METHOD( tarantool_class, getInfo); -PHP_METHOD( tarantool_class, getStat); -PHP_METHOD( tarantool_class, getConf); #ifdef ZTS #define TARANTOOL_G(v) TSRMG(tarantool_globals_id, zend_tarantool_globals *, v) @@ -96,8 +180,7 @@ PHP_METHOD( tarantool_class, getConf); #define TARANTOOL_G(v) (tarantool_globals.v) #endif -#endif -/* PHP_TARANTOOL_H */ +#endif /* PHP_TARANTOOL_H */ /* * Local variables: diff --git a/connector/php/test/admin.phpt b/connector/php/test/admin.phpt new file mode 100644 index 0000000000..e13120ddce --- /dev/null +++ b/connector/php/test/admin.phpt @@ -0,0 +1,112 @@ +--TEST-- +Tarantool/box administation commands test +--FILE-- +<?php +include "lib/php/tarantool_utest.php"; + +$tarantool = new Tarantool("localhost", 33013, 33015); + +echo "---------- test begin ----------\n"; +echo "help\n"; +echo $tarantool->admin("help"); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "insert\n"; +for ($i = 0; $i < 10; ++$i) + echo $tarantool->admin("lua box.insert(0, $i, 'test_id1', 'test field #$i')"); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "select\n"; +echo $tarantool->admin("lua box.select(0, 1, 'test_id1')"); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "myselect\n"; +echo $tarantool->admin("lua myselect(0, 1, 'test_id1')"); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "delete\n"; +for ($i = 0; $i < 10; ++$i) + echo $tarantool->admin("lua box.delete(0, $i)"); +echo "----------- test end -----------\n\n"; +?> +===DONE=== +--EXPECT-- +---------- test begin ---------- +help +available commands: + - help + - exit + - show info + - show fiber + - show configuration + - show slab + - show palloc + - show stat + - save coredump + - save snapshot + - lua command + - reload configuration +----------- test end ----------- + +---------- test begin ---------- +insert + - 0: {'test_id1', 'test field #0'} + - 1: {'test_id1', 'test field #1'} + - 2: {'test_id1', 'test field #2'} + - 3: {'test_id1', 'test field #3'} + - 4: {'test_id1', 'test field #4'} + - 5: {'test_id1', 'test field #5'} + - 6: {'test_id1', 'test field #6'} + - 7: {'test_id1', 'test field #7'} + - 8: {'test_id1', 'test field #8'} + - 9: {'test_id1', 'test field #9'} +----------- test end ----------- + +---------- test begin ---------- +select + - 0: {'test_id1', 'test field #0'} + - 1: {'test_id1', 'test field #1'} + - 2: {'test_id1', 'test field #2'} + - 3: {'test_id1', 'test field #3'} + - 4: {'test_id1', 'test field #4'} + - 5: {'test_id1', 'test field #5'} + - 6: {'test_id1', 'test field #6'} + - 7: {'test_id1', 'test field #7'} + - 8: {'test_id1', 'test field #8'} + - 9: {'test_id1', 'test field #9'} +----------- test end ----------- + +---------- test begin ---------- +myselect +select in space: 0 index: 1 by key test_id1 + - 0: {'test_id1', 'test field #0'} + - 1: {'test_id1', 'test field #1'} + - 2: {'test_id1', 'test field #2'} + - 3: {'test_id1', 'test field #3'} + - 4: {'test_id1', 'test field #4'} + - 5: {'test_id1', 'test field #5'} + - 6: {'test_id1', 'test field #6'} + - 7: {'test_id1', 'test field #7'} + - 8: {'test_id1', 'test field #8'} + - 9: {'test_id1', 'test field #9'} +----------- test end ----------- + +---------- test begin ---------- +delete + - 0: {'test_id1', 'test field #0'} + - 1: {'test_id1', 'test field #1'} + - 2: {'test_id1', 'test field #2'} + - 3: {'test_id1', 'test field #3'} + - 4: {'test_id1', 'test field #4'} + - 5: {'test_id1', 'test field #5'} + - 6: {'test_id1', 'test field #6'} + - 7: {'test_id1', 'test field #7'} + - 8: {'test_id1', 'test field #8'} + - 9: {'test_id1', 'test field #9'} +----------- test end ----------- + +===DONE=== \ No newline at end of file diff --git a/connector/php/test/bin/run-test.bash b/connector/php/test/bin/run-test.bash new file mode 100755 index 0000000000..b7df9a01c1 --- /dev/null +++ b/connector/php/test/bin/run-test.bash @@ -0,0 +1,204 @@ +#!/bin/bash +#==============================================================================# +# PHP tarantool test suite runner +#==============================================================================# + +#------------------------------------------------------------------------------# +# Constants +#------------------------------------------------------------------------------# + +# Success constant +SUCCESS=0 +# Failure constant +FAILURE=1 + +# test runner etc directory +TEST_RUNNER_ETC_DIR="etc" +# test runner var directory +TEST_RUNNER_VAR_DIR="var" +# test runner var directory +TEST_RUNNER_LIB_DIR="lib" + +# php.ini file +PHP_INI="$TEST_RUNNER_ETC_DIR/php.ini" + +# Tarantool/box binary file name +TARANTOOL_BOX_BIN="tarantool_box" +# Tarantool/box configuration file +TARANTOOL_BOX_CFG="$TEST_RUNNER_ETC_DIR/tarantool_box.cfg" +# Tarantool/box pid file +TARANTOOL_BOX_PID="$TEST_RUNNER_VAR_DIR/tarantool_box.pid" + + +#------------------------------------------------------------------------------# +# Suite runner functions +#------------------------------------------------------------------------------# + +# initialize suite +function init_suite() +{ + # check TARANTOOL_HOME variable + if [ ! -z $TARANTOOL_HOME ]; then + # Use user-defined path + tarantool_bin="$TARANTOOL_HOME/$TARANTOOL_BOX_BIN" + else + # try to find by standard paths + tarantool_bin="$TARANTOOL_BOX_BIN" + fi + + # check binary + if ! which $tarantool_bin > /dev/null 2>&1; then + echo "can't found Tarantool/Box binary file" + exit $FAILURE + fi + + # check pear + if ! which pear > /dev/null 2>&1; then + echo "can't found pear" + exit $FAILURE + fi + + # check tarantool module library + if [ ! -f ../modules/tarantool.so ]; then + echo "can't found tarantool module library" + exit $FAILURE + fi + if [ -f $TEST_RUNNER_LIB_DIR/tarantool.so ]; then + rm $TEST_RUNNER_LIB_DIR/tarantool.so + fi + ln -s ../../modules/tarantool.so $TEST_RUNNER_LIB_DIR + + if [ -f ../$TEST_RUNNER_VAR_DIR/init.lua ]; then + rm ../$TEST_RUNNER_VAR_DIR/init.lua + fi + ln -s ../$TEST_RUNNER_LIB_DIR/lua/test.lua $TEST_RUNNER_VAR_DIR/init.lua + + return $SUCCESS +} + +# initialize tarantool's storage +function tarantool_init_storage() +{ + $tarantool_bin --init-storage -c $TARANTOOL_BOX_CFG 1> /dev/null 2>&1 + return $SUCCESS +} + +# start tarantool +function tarantool_start() +{ + if [ -f $TARANTOOL_BOX_PID ]; then + tarantool_stop + tarantool_cleanup + fi + + # run tarantool to background + $tarantool_bin -c $TARANTOOL_BOX_CFG & + # wait pid file + for i in {1..500}; do + if [ -f $TARANTOOL_BOX_PID ]; then + break + fi + sleep 0.01 + done + + if [ ! -f $TARANTOOL_BOX_PID ]; then + echo "error: can't start tarantool" + tarantool_cleanup + exit $FAILURE + fi + + return $SUCCESS +} + +# stop tarantool +function tarantool_stop() +{ + if [ ! -f $TARANTOOL_BOX_PID ]; then + return $SUCCESS + fi + + # get tarantool pid form pid file + pid=`cat $TARANTOOL_BOX_PID` + # kill process via SIGTERM + kill -TERM $pid 1> /dev/null 2>&1 + + for i in {1..500}; do + if [ ! -f $TARANTOOL_BOX_PID ]; then + # tarantool successfully stopped + return $SUCCESS + fi + sleep 0.01 + done + + if [ -f $TARANTOOL_BOX_PID ]; then + kill -KILL $pid 1> /dev/null 2>&1 + fi + + return $SUCCESS +} + +# clean-up tarantool +function tarantool_cleanup() +{ + # delete pid + rm -f $TEST_RUNNER_VAR_DIR/*.pid + # delete xlogs + rm -f $TEST_RUNNER_VAR_DIR/*.xlog + # delete snaps + rm -f $TEST_RUNNER_VAR_DIR/*.snap +} + + +#------------------------------------------------------------------------------# +# run test scrip body +#------------------------------------------------------------------------------# + +# +# initialize +# + +printf "initialize tarantool ... " +# initializing suite +init_suite +# initializing storage +tarantool_init_storage +printf "done\n" + +printf "starting tarantool ... " +# start tarantool +tarantool_start +printf "done\n" + + +# +# run +# + +printf "\n" +printf "================================= PHP test ===============================\n" + +# running pear's regression test scrips +PHPRC=$PHP_INI pear run-tests $1 + +printf "==========================================================================\n" +printf "\n" + +# +# stop & clean-up +# + +printf "stopping tarantool ... " +# stop tarantool +tarantool_stop +# clean-up tarantool +tarantool_cleanup +printf "done\n" + +# +# Local variables: +# tab-width: 4 +# c-basic-offset: 4 +# End: +# vim600: noet sw=4 ts=4 fdm=marker +# vim<600: noet sw=4 ts=4 +# diff --git a/connector/php/test/call.phpt b/connector/php/test/call.phpt new file mode 100644 index 0000000000..fe85b595f8 --- /dev/null +++ b/connector/php/test/call.phpt @@ -0,0 +1,93 @@ +--TEST-- +Tarantool/box call commands test +--FILE-- +<?php +include "lib/php/tarantool_utest.php"; + +$tarantool = new Tarantool("localhost", 33013, 33015); +test_init($tarantool, 0); + +echo "---------- test begin ----------\n"; +echo "test call: myselect by primary index\n"; +test_call($tarantool, "box.select", array(0, 0, 2), 0); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test call: function w/o params\n"; +test_call($tarantool, "myfoo", array(), 0); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test call: call undefined function (expected error exception)\n"; +test_call($tarantool, "fafagaga", array("fafa-gaga", "foo", "bar"), 0); +echo "----------- test end -----------\n\n"; + +test_clean($tarantool, 0); +?> +===DONE=== +--EXPECT-- +---------- test begin ---------- +test call: myselect by primary index +result: +count = 1 +tuple[0]: + id = 2 + series = Star Wars + year = 1983 + name = Return of the Jedi... + crawl = Luke Skywalker has returned +to his home planet of +Tatooine in an attempt +to rescue his friend +Han Solo from the +clutches of the vile +gangster Jabba the Hutt. + +Little does Luke know +that the GALACTIC EMPIRE +has secretly begun construction +on a new armored space station +even more powerful than the +first dreaded Death Star. + +When completed, this ultimate +weapon will spell certain +doom for the small band of +rebels struggling to restore +freedom to the galaxy... +----------- test end ----------- + +---------- test begin ---------- +test call: function w/o params +result: +count = 1 +tuple[0]: + id = 0 + series = Star Wars + year = 1977 year + name = A New Hope... + crawl = A long time ago, in a galaxy far, far away... +It is a period of civil war. Rebel +spaceships, striking from a hidden +base, have won their first victory +against the evil Galactic Empire. + +During the battle, Rebel spies managed +to steal secret plans to the Empire's +ultimate weapon, the Death Star, an +armored space station with enough +power to destroy an entire planet. + +Pursued by the Empire's sinister agents, +Princess Leia races home aboard her +starship, custodian of the stolen plans +that can save her people and restore +freedom to the galaxy.... +----------- test end ----------- + +---------- test begin ---------- +test call: call undefined function (expected error exception) +catched exception: call failed: 12802 +----------- test end ----------- + +===DONE=== \ No newline at end of file diff --git a/connector/php/test/delete.phpt b/connector/php/test/delete.phpt new file mode 100644 index 0000000000..d19a0aaaef --- /dev/null +++ b/connector/php/test/delete.phpt @@ -0,0 +1,125 @@ +--TEST-- +Tarantool/box delete commands test +--FILE-- +<?php +include "lib/php/tarantool_utest.php"; + +$tarantool = new Tarantool("localhost", 33013, 33015); + +test_init($tarantool, 0); + +echo "---------- test begin ----------\n"; +echo "test delete: invalid key (expected error exception)\n"; +test_delete($tarantool, 0, $tarantool, 0); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test delete: invalid key (expected error exception)\n"; +test_delete($tarantool, 0, array($tarantool), 0); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test delete: invalid key (expected error exception)\n"; +test_delete($tarantool, 0, array(1, 2), 0); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test delete: delete key as interger\n"; +test_delete($tarantool, 0, 0, TARANTOOL_FLAGS_RETURN_TUPLE); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test delete: delete key as array\n"; +test_delete($tarantool, 0, array(1), TARANTOOL_FLAGS_RETURN_TUPLE); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test delete: delete key (tuple doesn't return)\n"; +test_delete($tarantool, 0, 2, 0); +echo "----------- test end -----------\n\n"; + +test_clean($tarantool, 0); +?> +===DONE=== +--EXPECT-- +---------- test begin ---------- +test delete: invalid key (expected error exception) +catched exception: unsupported tuple type +----------- test end ----------- + +---------- test begin ---------- +test delete: invalid key (expected error exception) +catched exception: unsupported field type +----------- test end ----------- + +---------- test begin ---------- +test delete: invalid key (expected error exception) +catched exception: delete failed: 514 +----------- test end ----------- + +---------- test begin ---------- +test delete: delete key as interger +result: +count = 1 +tuple: + id = 0 + series = Star Wars + year = 1977 + name = A New Hope... + crawl = A long time ago, in a galaxy far, far away... +It is a period of civil war. Rebel +spaceships, striking from a hidden +base, have won their first victory +against the evil Galactic Empire. + +During the battle, Rebel spies managed +to steal secret plans to the Empire's +ultimate weapon, the Death Star, an +armored space station with enough +power to destroy an entire planet. + +Pursued by the Empire's sinister agents, +Princess Leia races home aboard her +starship, custodian of the stolen plans +that can save her people and restore +freedom to the galaxy.... +----------- test end ----------- + +---------- test begin ---------- +test delete: delete key as array +result: +count = 1 +tuple: + id = 1 + series = Star Wars + year = 1980 + name = The Empire Strikes Back... + crawl = It is a dark time for the +Rebellion. Although the Death +Star has been destroyed. +Imperial troops have driven the +Rebel forces from their hidden +base and pursued them across +the galaxy. + +Evading the dreaded Imperial +Starfleet, a group of freedom +fighters led by Luke Skywalker +have established a new secret base +on the remote ice world +of Hoth. + +The evil lord Darth Vader, +obsessed with finding young +Skywalker, has dispatched +thousands of remote probes +into the far reaches of space.... +----------- test end ----------- + +---------- test begin ---------- +test delete: delete key (tuple doesn't return) +result: +count = 1 +----------- test end ----------- + +===DONE=== \ No newline at end of file diff --git a/connector/php/test/errors.phpt b/connector/php/test/errors.phpt new file mode 100644 index 0000000000..2450b3efb6 --- /dev/null +++ b/connector/php/test/errors.phpt @@ -0,0 +1,26 @@ +--TEST-- +Tarantool/box error commands test +--FILE-- +<?php + +try +{ + $tarantool = new Tarantool("localhost", -33013, 0); + echo "error: the exception didn't raise\n"; +} catch (Exception $e) { + echo "catched exception: ", $e->getMessage(), "\n"; +} + +try { + $tarantool = new Tarantool("localhost", 33013, 65537); + echo "error: the exception didn't raise\n"; +} catch (Exception $e) { + echo "catched exception: ", $e->getMessage(), "\n"; +} + +?> +===DONE=== +--EXPECT-- +catched exception: invalid primary port value: -33013 +catched exception: invalid admin port value: 65537 +===DONE=== diff --git a/connector/php/test/etc/php.ini b/connector/php/test/etc/php.ini new file mode 100644 index 0000000000..ae7b2ee849 --- /dev/null +++ b/connector/php/test/etc/php.ini @@ -0,0 +1,1851 @@ +[PHP] + +;;;;;;;;;;;;;;;;;;; +; About php.ini ; +;;;;;;;;;;;;;;;;;;; +; PHP's initialization file, generally called php.ini, is responsible for +; configuring many of the aspects of PHP's behavior. + +; PHP attempts to find and load this configuration from a number of locations. +; The following is a summary of its search order: +; 1. SAPI module specific location. +; 2. The PHPRC environment variable. (As of PHP 5.2.0) +; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0) +; 4. Current working directory (except CLI) +; 5. The web server's directory (for SAPI modules), or directory of PHP +; (otherwise in Windows) +; 6. The directory from the --with-config-file-path compile time option, or the +; Windows directory (C:\windows or C:\winnt) +; See the PHP docs for more specific information. +; http://php.net/configuration.file + +; The syntax of the file is extremely simple. Whitespace and Lines +; beginning with a semicolon are silently ignored (as you probably guessed). +; Section headers (e.g. [Foo]) are also silently ignored, even though +; they might mean something in the future. + +; Directives following the section heading [PATH=/www/mysite] only +; apply to PHP files in the /www/mysite directory. Directives +; following the section heading [HOST=www.example.com] only apply to +; PHP files served from www.example.com. Directives set in these +; special sections cannot be overridden by user-defined INI files or +; at runtime. Currently, [PATH=] and [HOST=] sections only work under +; CGI/FastCGI. +; http://php.net/ini.sections + +; Directives are specified using the following syntax: +; directive = value +; Directive names are *case sensitive* - foo=bar is different from FOO=bar. +; Directives are variables used to configure PHP or PHP extensions. +; There is no name validation. If PHP can't find an expected +; directive because it is not set or is mistyped, a default value will be used. + +; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one +; of the INI constants (On, Off, True, False, Yes, No and None) or an expression +; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a +; previously set variable or directive (e.g. ${foo}) + +; Expressions in the INI file are limited to bitwise operators and parentheses: +; | bitwise OR +; ^ bitwise XOR +; & bitwise AND +; ~ bitwise NOT +; ! boolean NOT + +; Boolean flags can be turned on using the values 1, On, True or Yes. +; They can be turned off using the values 0, Off, False or No. + +; An empty string can be denoted by simply not writing anything after the equal +; sign, or by using the None keyword: + +; foo = ; sets foo to an empty string +; foo = None ; sets foo to an empty string +; foo = "None" ; sets foo to the string 'None' + +; If you use constants in your value, and these constants belong to a +; dynamically loaded extension (either a PHP extension or a Zend extension), +; you may only use these constants *after* the line that loads the extension. + +;;;;;;;;;;;;;;;;;;; +; About this file ; +;;;;;;;;;;;;;;;;;;; +; PHP comes packaged with two INI files. One that is recommended to be used +; in production environments and one that is recommended to be used in +; development environments. + +; php.ini-production contains settings which hold security, performance and +; best practices at its core. But please be aware, these settings may break +; compatibility with older or less security conscience applications. We +; recommending using the production ini in production and testing environments. + +; php.ini-development is very similar to its production variant, except it's +; much more verbose when it comes to errors. We recommending using the +; development version only in development environments as errors shown to +; application users can inadvertently leak otherwise secure information. + +;;;;;;;;;;;;;;;;;;; +; Quick Reference ; +;;;;;;;;;;;;;;;;;;; +; The following are all the settings which are different in either the production +; or development versions of the INIs with respect to PHP's default behavior. +; Please see the actual settings later in the document for more details as to why +; we recommend these changes in PHP's behavior. + +; allow_call_time_pass_reference +; Default Value: On +; Development Value: Off +; Production Value: Off + +; display_errors +; Default Value: On +; Development Value: On +; Production Value: Off + +; display_startup_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; error_reporting +; Default Value: E_ALL & ~E_NOTICE +; Development Value: E_ALL | E_STRICT +; Production Value: E_ALL & ~E_DEPRECATED + +; html_errors +; Default Value: On +; Development Value: On +; Production value: Off + +; log_errors +; Default Value: Off +; Development Value: On +; Production Value: On + +; magic_quotes_gpc +; Default Value: On +; Development Value: Off +; Production Value: Off + +; max_input_time +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) + +; output_buffering +; Default Value: Off +; Development Value: 4096 +; Production Value: 4096 + +; register_argc_argv +; Default Value: On +; Development Value: Off +; Production Value: Off + +; register_long_arrays +; Default Value: On +; Development Value: Off +; Production Value: Off + +; request_order +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" + +; session.bug_compat_42 +; Default Value: On +; Development Value: On +; Production Value: Off + +; session.bug_compat_warn +; Default Value: On +; Development Value: On +; Production Value: Off + +; session.gc_divisor +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 + +; session.hash_bits_per_character +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 + +; short_open_tag +; Default Value: On +; Development Value: Off +; Production Value: Off + +; track_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; url_rewriter.tags +; Default Value: "a=href,area=href,frame=src,form=,fieldset=" +; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" + +; variables_order +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS" + +;;;;;;;;;;;;;;;;;;;; +; php.ini Options ; +;;;;;;;;;;;;;;;;;;;; +; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" +;user_ini.filename = ".user.ini" + +; To disable this feature set this option to empty value +;user_ini.filename = + +; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) +;user_ini.cache_ttl = 300 + +;;;;;;;;;;;;;;;;;;;; +; Language Options ; +;;;;;;;;;;;;;;;;;;;; + +; Enable the PHP scripting language engine under Apache. +; http://php.net/engine +engine = On + +; This directive determines whether or not PHP will recognize code between +; <? and ?> tags as PHP source which should be processed as such. It's been +; recommended for several years that you not use the short tag "short cut" and +; instead to use the full <?php and ?> tag combination. With the wide spread use +; of XML and use of these tags by other languages, the server can become easily +; confused and end up parsing the wrong code in the wrong context. But because +; this short cut has been a feature for such a long time, it's currently still +; supported for backwards compatibility, but we recommend you don't use them. +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/short-open-tag +short_open_tag = On + +; Allow ASP-style <% %> tags. +; http://php.net/asp-tags +asp_tags = Off + +; The number of significant digits displayed in floating point numbers. +; http://php.net/precision +precision = 14 + +; Enforce year 2000 compliance (will cause problems with non-compliant browsers) +; http://php.net/y2k-compliance +y2k_compliance = On + +; Output buffering is a mechanism for controlling how much output data +; (excluding headers and cookies) PHP should keep internally before pushing that +; data to the client. If your application's output exceeds this setting, PHP +; will send that data in chunks of roughly the size you specify. +; Turning on this setting and managing its maximum buffer size can yield some +; interesting side-effects depending on your application and web server. +; You may be able to send headers and cookies after you've already sent output +; through print or echo. You also may see performance benefits if your server is +; emitting less packets due to buffered output versus PHP streaming the output +; as it gets it. On production servers, 4096 bytes is a good setting for performance +; reasons. +; Note: Output buffering can also be controlled via Output Buffering Control +; functions. +; Possible Values: +; On = Enabled and buffer is unlimited. (Use with caution) +; Off = Disabled +; Integer = Enables the buffer and sets its maximum size in bytes. +; Note: This directive is hardcoded to Off for the CLI SAPI +; Default Value: Off +; Development Value: 4096 +; Production Value: 4096 +; http://php.net/output-buffering +output_buffering = 4096 + +; You can redirect all of the output of your scripts to a function. For +; example, if you set output_handler to "mb_output_handler", character +; encoding will be transparently converted to the specified encoding. +; Setting any output handler automatically turns on output buffering. +; Note: People who wrote portable scripts should not depend on this ini +; directive. Instead, explicitly set the output handler using ob_start(). +; Using this ini directive may cause problems unless you know what script +; is doing. +; Note: You cannot use both "mb_output_handler" with "ob_iconv_handler" +; and you cannot use both "ob_gzhandler" and "zlib.output_compression". +; Note: output_handler must be empty if this is set 'On' !!!! +; Instead you must use zlib.output_handler. +; http://php.net/output-handler +;output_handler = + +; Transparent output compression using the zlib library +; Valid values for this option are 'off', 'on', or a specific buffer size +; to be used for compression (default is 4KB) +; Note: Resulting chunk size may vary due to nature of compression. PHP +; outputs chunks that are few hundreds bytes each as a result of +; compression. If you prefer a larger chunk size for better +; performance, enable output_buffering in addition. +; Note: You need to use zlib.output_handler instead of the standard +; output_handler, or otherwise the output will be corrupted. +; http://php.net/zlib.output-compression +zlib.output_compression = Off + +; http://php.net/zlib.output-compression-level +;zlib.output_compression_level = -1 + +; You cannot specify additional output handlers if zlib.output_compression +; is activated here. This setting does the same as output_handler but in +; a different order. +; http://php.net/zlib.output-handler +;zlib.output_handler = + +; Implicit flush tells PHP to tell the output layer to flush itself +; automatically after every output block. This is equivalent to calling the +; PHP function flush() after each and every call to print() or echo() and each +; and every HTML block. Turning this option on has serious performance +; implications and is generally recommended for debugging purposes only. +; http://php.net/implicit-flush +; Note: This directive is hardcoded to On for the CLI SAPI +implicit_flush = Off + +; The unserialize callback function will be called (with the undefined class' +; name as parameter), if the unserializer finds an undefined class +; which should be instantiated. A warning appears if the specified function is +; not defined, or if the function doesn't include/implement the missing class. +; So only set this entry, if you really want to implement such a +; callback-function. +unserialize_callback_func = + +; When floats & doubles are serialized store serialize_precision significant +; digits after the floating point. The default value ensures that when floats +; are decoded with unserialize, the data will remain the same. +serialize_precision = 17 + +; This directive allows you to enable and disable warnings which PHP will issue +; if you pass a value by reference at function call time. Passing values by +; reference at function call time is a deprecated feature which will be removed +; from PHP at some point in the near future. The acceptable method for passing a +; value by reference to a function is by declaring the reference in the functions +; definition, not at call time. This directive does not disable this feature, it +; only determines whether PHP will warn you about it or not. These warnings +; should enabled in development environments only. +; Default Value: On (Suppress warnings) +; Development Value: Off (Issue warnings) +; Production Value: Off (Issue warnings) +; http://php.net/allow-call-time-pass-reference +allow_call_time_pass_reference = Off + +; Safe Mode +; http://php.net/safe-mode +safe_mode = Off + +; By default, Safe Mode does a UID compare check when +; opening files. If you want to relax this to a GID compare, +; then turn on safe_mode_gid. +; http://php.net/safe-mode-gid +safe_mode_gid = Off + +; When safe_mode is on, UID/GID checks are bypassed when +; including files from this directory and its subdirectories. +; (directory must also be in include_path or full path must +; be used when including) +; http://php.net/safe-mode-include-dir +safe_mode_include_dir = + +; When safe_mode is on, only executables located in the safe_mode_exec_dir +; will be allowed to be executed via the exec family of functions. +; http://php.net/safe-mode-exec-dir +safe_mode_exec_dir = + +; Setting certain environment variables may be a potential security breach. +; This directive contains a comma-delimited list of prefixes. In Safe Mode, +; the user may only alter environment variables whose names begin with the +; prefixes supplied here. By default, users will only be able to set +; environment variables that begin with PHP_ (e.g. PHP_FOO=BAR). +; Note: If this directive is empty, PHP will let the user modify ANY +; environment variable! +; http://php.net/safe-mode-allowed-env-vars +safe_mode_allowed_env_vars = PHP_ + +; This directive contains a comma-delimited list of environment variables that +; the end user won't be able to change using putenv(). These variables will be +; protected even if safe_mode_allowed_env_vars is set to allow to change them. +; http://php.net/safe-mode-protected-env-vars +safe_mode_protected_env_vars = LD_LIBRARY_PATH + +; open_basedir, if set, limits all file operations to the defined directory +; and below. This directive makes most sense if used in a per-directory +; or per-virtualhost web server configuration file. This directive is +; *NOT* affected by whether Safe Mode is turned On or Off. +; http://php.net/open-basedir +;open_basedir = + +; This directive allows you to disable certain functions for security reasons. +; It receives a comma-delimited list of function names. This directive is +; *NOT* affected by whether Safe Mode is turned On or Off. +; http://php.net/disable-functions +disable_functions = + +; This directive allows you to disable certain classes for security reasons. +; It receives a comma-delimited list of class names. This directive is +; *NOT* affected by whether Safe Mode is turned On or Off. +; http://php.net/disable-classes +disable_classes = + +; Colors for Syntax Highlighting mode. Anything that's acceptable in +; <span style="color: ???????"> would work. +; http://php.net/syntax-highlighting +;highlight.string = #DD0000 +;highlight.comment = #FF9900 +;highlight.keyword = #007700 +;highlight.bg = #FFFFFF +;highlight.default = #0000BB +;highlight.html = #000000 + +; If enabled, the request will be allowed to complete even if the user aborts +; the request. Consider enabling it if executing long requests, which may end up +; being interrupted by the user or a browser timing out. PHP's default behavior +; is to disable this feature. +; http://php.net/ignore-user-abort +;ignore_user_abort = On + +; Determines the size of the realpath cache to be used by PHP. This value should +; be increased on systems where PHP opens many files to reflect the quantity of +; the file operations performed. +; http://php.net/realpath-cache-size +;realpath_cache_size = 16k + +; Duration of time, in seconds for which to cache realpath information for a given +; file or directory. For systems with rarely changing files, consider increasing this +; value. +; http://php.net/realpath-cache-ttl +;realpath_cache_ttl = 120 + +;;;;;;;;;;;;;;;;; +; Miscellaneous ; +;;;;;;;;;;;;;;;;; + +; Decides whether PHP may expose the fact that it is installed on the server +; (e.g. by adding its signature to the Web server header). It is no security +; threat in any way, but it makes it possible to determine whether you use PHP +; on your server or not. +; http://php.net/expose-php +expose_php = On + +;;;;;;;;;;;;;;;;;;; +; Resource Limits ; +;;;;;;;;;;;;;;;;;;; + +; Maximum execution time of each script, in seconds +; http://php.net/max-execution-time +; Note: This directive is hardcoded to 0 for the CLI SAPI +max_execution_time = 30 + +; Maximum amount of time each script may spend parsing request data. It's a good +; idea to limit this time on productions servers in order to eliminate unexpectedly +; long running scripts. +; Note: This directive is hardcoded to -1 for the CLI SAPI +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) +; http://php.net/max-input-time +max_input_time = 60 + +; Maximum input variable nesting level +; http://php.net/max-input-nesting-level +;max_input_nesting_level = 64 + +; Maximum amount of memory a script may consume (128MB) +; http://php.net/memory-limit +memory_limit = -1 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Error handling and logging ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; This directive informs PHP of which errors, warnings and notices you would like +; it to take action for. The recommended way of setting values for this +; directive is through the use of the error level constants and bitwise +; operators. The error level constants are below here for convenience as well as +; some common settings and their meanings. +; By default, PHP is set to take action on all errors, notices and warnings EXCEPT +; those related to E_NOTICE and E_STRICT, which together cover best practices and +; recommended coding standards in PHP. For performance reasons, this is the +; recommend error reporting setting. Your production server shouldn't be wasting +; resources complaining about best practices and coding standards. That's what +; development servers and development settings are for. +; Note: The php.ini-development file has this setting as E_ALL | E_STRICT. This +; means it pretty much reports everything which is exactly what you want during +; development and early testing. +; +; Error Level Constants: +; E_ALL - All errors and warnings (includes E_STRICT as of PHP 6.0.0) +; E_ERROR - fatal run-time errors +; E_RECOVERABLE_ERROR - almost fatal run-time errors +; E_WARNING - run-time warnings (non-fatal errors) +; E_PARSE - compile-time parse errors +; E_NOTICE - run-time notices (these are warnings which often result +; from a bug in your code, but it's possible that it was +; intentional (e.g., using an uninitialized variable and +; relying on the fact it's automatically initialized to an +; empty string) +; E_STRICT - run-time notices, enable to have PHP suggest changes +; to your code which will ensure the best interoperability +; and forward compatibility of your code +; E_CORE_ERROR - fatal errors that occur during PHP's initial startup +; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's +; initial startup +; E_COMPILE_ERROR - fatal compile-time errors +; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) +; E_USER_ERROR - user-generated error message +; E_USER_WARNING - user-generated warning message +; E_USER_NOTICE - user-generated notice message +; E_DEPRECATED - warn about code that will not work in future versions +; of PHP +; E_USER_DEPRECATED - user-generated deprecation warnings +; +; Common Values: +; E_ALL & ~E_NOTICE (Show all errors, except for notices and coding standards warnings.) +; E_ALL & ~E_NOTICE | E_STRICT (Show all errors, except for notices) +; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) +; E_ALL | E_STRICT (Show all errors, warnings and notices including coding standards.) +; Default Value: E_ALL & ~E_NOTICE +; Development Value: E_ALL | E_STRICT +; Production Value: E_ALL & ~E_DEPRECATED +; http://php.net/error-reporting +error_reporting = E_ALL & ~E_DEPRECATED + +; This directive controls whether or not and where PHP will output errors, +; notices and warnings too. Error output is very useful during development, but +; it could be very dangerous in production environments. Depending on the code +; which is triggering the error, sensitive information could potentially leak +; out of your application such as database usernames and passwords or worse. +; It's recommended that errors be logged on production servers rather than +; having the errors sent to STDOUT. +; Possible Values: +; Off = Do not display any errors +; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) +; On or stdout = Display errors to STDOUT +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/display-errors +display_errors = Off + +; The display of errors which occur during PHP's startup sequence are handled +; separately from display_errors. PHP's default behavior is to suppress those +; errors from clients. Turning the display of startup errors on can be useful in +; debugging configuration problems. But, it's strongly recommended that you +; leave this setting off on production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/display-startup-errors +display_startup_errors = Off + +; Besides displaying errors, PHP can also log errors to locations such as a +; server-specific log, STDERR, or a location specified by the error_log +; directive found below. While errors should not be displayed on productions +; servers they should still be monitored and logging is a great way to do that. +; Default Value: Off +; Development Value: On +; Production Value: On +; http://php.net/log-errors +log_errors = On + +; Set maximum length of log_errors. In error_log information about the source is +; added. The default is 1024 and 0 allows to not apply any maximum length at all. +; http://php.net/log-errors-max-len +log_errors_max_len = 1024 + +; Do not log repeated messages. Repeated errors must occur in same file on same +; line unless ignore_repeated_source is set true. +; http://php.net/ignore-repeated-errors +ignore_repeated_errors = Off + +; Ignore source of message when ignoring repeated messages. When this setting +; is On you will not log errors with repeated messages from different files or +; source lines. +; http://php.net/ignore-repeated-source +ignore_repeated_source = Off + +; If this parameter is set to Off, then memory leaks will not be shown (on +; stdout or in the log). This has only effect in a debug compile, and if +; error reporting includes E_WARNING in the allowed list +; http://php.net/report-memleaks +report_memleaks = On + +; This setting is on by default. +;report_zend_debug = 0 + +; Store the last error/warning message in $php_errormsg (boolean). Setting this value +; to On can assist in debugging and is appropriate for development servers. It should +; however be disabled on production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/track-errors +track_errors = Off + +; Turn off normal error reporting and emit XML-RPC error XML +; http://php.net/xmlrpc-errors +;xmlrpc_errors = 0 + +; An XML-RPC faultCode +;xmlrpc_error_number = 0 + +; When PHP displays or logs an error, it has the capability of inserting html +; links to documentation related to that error. This directive controls whether +; those HTML links appear in error messages or not. For performance and security +; reasons, it's recommended you disable this on production servers. +; Note: This directive is hardcoded to Off for the CLI SAPI +; Default Value: On +; Development Value: On +; Production value: Off +; http://php.net/html-errors +html_errors = Off + +; If html_errors is set On PHP produces clickable error messages that direct +; to a page describing the error or function causing the error in detail. +; You can download a copy of the PHP manual from http://php.net/docs +; and change docref_root to the base URL of your local copy including the +; leading '/'. You must also specify the file extension being used including +; the dot. PHP's default behavior is to leave these settings empty. +; Note: Never use this feature for production boxes. +; http://php.net/docref-root +; Examples +;docref_root = "/phpmanual/" + +; http://php.net/docref-ext +;docref_ext = .html + +; String to output before an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-prepend-string +; Example: +;error_prepend_string = "<span style='color: #ff0000'>" + +; String to output after an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-append-string +; Example: +;error_append_string = "</span>" + +; Log errors to specified file. PHP's default behavior is to leave this value +; empty. +; http://php.net/error-log +; Example: +;error_log = php_errors.log +; Log errors to syslog (Event Log on NT, not valid in Windows 95). +;error_log = syslog + +;;;;;;;;;;;;;;;;; +; Data Handling ; +;;;;;;;;;;;;;;;;; + +; The separator used in PHP generated URLs to separate arguments. +; PHP's default setting is "&". +; http://php.net/arg-separator.output +; Example: +;arg_separator.output = "&" + +; List of separator(s) used by PHP to parse input URLs into variables. +; PHP's default setting is "&". +; NOTE: Every character in this directive is considered as separator! +; http://php.net/arg-separator.input +; Example: +;arg_separator.input = ";&" + +; This directive determines which super global arrays are registered when PHP +; starts up. If the register_globals directive is enabled, it also determines +; what order variables are populated into the global space. G,P,C,E & S are +; abbreviations for the following respective super globals: GET, POST, COOKIE, +; ENV and SERVER. There is a performance penalty paid for the registration of +; these arrays and because ENV is not as commonly used as the others, ENV is +; is not recommended on productions servers. You can still get access to +; the environment variables through getenv() should you need to. +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS"; +; http://php.net/variables-order +variables_order = "GPCS" + +; This directive determines which super global data (G,P,C,E & S) should +; be registered into the super global array REQUEST. If so, it also determines +; the order in which that data is registered. The values for this directive are +; specified in the same manner as the variables_order directive, EXCEPT one. +; Leaving this value empty will cause PHP to use the value set in the +; variables_order directive. It does not mean it will leave the super globals +; array REQUEST empty. +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" +; http://php.net/request-order +request_order = "GP" + +; Whether or not to register the EGPCS variables as global variables. You may +; want to turn this off if you don't want to clutter your scripts' global scope +; with user data. +; You should do your best to write your scripts so that they do not require +; register_globals to be on; Using form variables as globals can easily lead +; to possible security problems, if the code is not very well thought of. +; http://php.net/register-globals +register_globals = Off + +; Determines whether the deprecated long $HTTP_*_VARS type predefined variables +; are registered by PHP or not. As they are deprecated, we obviously don't +; recommend you use them. They are on by default for compatibility reasons but +; they are not recommended on production servers. +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/register-long-arrays +register_long_arrays = Off + +; This directive determines whether PHP registers $argv & $argc each time it +; runs. $argv contains an array of all the arguments passed to PHP when a script +; is invoked. $argc contains an integer representing the number of arguments +; that were passed when the script was invoked. These arrays are extremely +; useful when running scripts from the command line. When this directive is +; enabled, registering these variables consumes CPU cycles and memory each time +; a script is executed. For performance reasons, this feature should be disabled +; on production servers. +; Note: This directive is hardcoded to On for the CLI SAPI +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/register-argc-argv +register_argc_argv = Off + +; When enabled, the SERVER and ENV variables are created when they're first +; used (Just In Time) instead of when the script starts. If these variables +; are not used within a script, having this directive on will result in a +; performance gain. The PHP directives register_globals, register_long_arrays, +; and register_argc_argv must be disabled for this directive to have any affect. +; http://php.net/auto-globals-jit +auto_globals_jit = On + +; Maximum size of POST data that PHP will accept. +; http://php.net/post-max-size +post_max_size = 8M + +; Magic quotes are a preprocessing feature of PHP where PHP will attempt to +; escape any character sequences in GET, POST, COOKIE and ENV data which might +; otherwise corrupt data being placed in resources such as databases before +; making that data available to you. Because of character encoding issues and +; non-standard SQL implementations across many databases, it's not currently +; possible for this feature to be 100% accurate. PHP's default behavior is to +; enable the feature. We strongly recommend you use the escaping mechanisms +; designed specifically for the database your using instead of relying on this +; feature. Also note, this feature has been deprecated as of PHP 5.3.0 and is +; scheduled for removal in PHP 6. +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/magic-quotes-gpc +magic_quotes_gpc = Off + +; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc. +; http://php.net/magic-quotes-runtime +magic_quotes_runtime = Off + +; Use Sybase-style magic quotes (escape ' with '' instead of \'). +; http://php.net/magic-quotes-sybase +magic_quotes_sybase = Off + +; Automatically add files before PHP document. +; http://php.net/auto-prepend-file +auto_prepend_file = + +; Automatically add files after PHP document. +; http://php.net/auto-append-file +auto_append_file = + +; By default, PHP will output a character encoding using +; the Content-type: header. To disable sending of the charset, simply +; set it to be empty. +; +; PHP's built-in default is text/html +; http://php.net/default-mimetype +default_mimetype = "text/html" + +; PHP's default character set is set to empty. +; http://php.net/default-charset +;default_charset = "iso-8859-1" + +; Always populate the $HTTP_RAW_POST_DATA variable. PHP's default behavior is +; to disable this feature. +; http://php.net/always-populate-raw-post-data +;always_populate_raw_post_data = On + +;;;;;;;;;;;;;;;;;;;;;;;;; +; Paths and Directories ; +;;;;;;;;;;;;;;;;;;;;;;;;; + +; UNIX: "/path1:/path2" +;include_path = ".:/usr/share/php" +; +; Windows: "\path1;\path2" +;include_path = ".;c:\php\includes" +; +; PHP's default setting for include_path is ".;/path/to/php/pear" +; http://php.net/include-path + +; The root of the PHP pages, used only if nonempty. +; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root +; if you are running php as a CGI under any web server (other than IIS) +; see documentation for security issues. The alternate is to use the +; cgi.force_redirect configuration below +; http://php.net/doc-root +doc_root = + +; The directory under which PHP opens the script using /~username used only +; if nonempty. +; http://php.net/user-dir +user_dir = + +; Directory in which the loadable extensions (modules) reside. +; http://php.net/extension-dir +; extension_dir = "lib/" + +; Whether or not to enable the dl() function. The dl() function does NOT work +; properly in multithreaded servers, such as IIS or Zeus, and is automatically +; disabled on them. +; http://php.net/enable-dl +enable_dl = Off + +; cgi.force_redirect is necessary to provide security running PHP as a CGI under +; most web servers. Left undefined, PHP turns this on by default. You can +; turn it off here AT YOUR OWN RISK +; **You CAN safely turn this off for IIS, in fact, you MUST.** +; http://php.net/cgi.force-redirect +;cgi.force_redirect = 1 + +; if cgi.nph is enabled it will force cgi to always sent Status: 200 with +; every request. PHP's default behavior is to disable this feature. +;cgi.nph = 1 + +; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape +; (iPlanet) web servers, you MAY need to set an environment variable name that PHP +; will look for to know it is OK to continue execution. Setting this variable MAY +; cause security issues, KNOW WHAT YOU ARE DOING FIRST. +; http://php.net/cgi.redirect-status-env +;cgi.redirect_status_env = ; + +; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's +; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok +; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting +; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting +; of zero causes PHP to behave as before. Default is 1. You should fix your scripts +; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. +; http://php.net/cgi.fix-pathinfo +;cgi.fix_pathinfo=1 + +; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate +; security tokens of the calling client. This allows IIS to define the +; security context that the request runs under. mod_fastcgi under Apache +; does not currently support this feature (03/17/2002) +; Set to 1 if running under IIS. Default is zero. +; http://php.net/fastcgi.impersonate +;fastcgi.impersonate = 1; + +; Disable logging through FastCGI connection. PHP's default behavior is to enable +; this feature. +;fastcgi.logging = 0 + +; cgi.rfc2616_headers configuration option tells PHP what type of headers to +; use when sending HTTP response code. If it's set 0 PHP sends Status: header that +; is supported by Apache. When this option is set to 1 PHP will send +; RFC2616 compliant header. +; Default is zero. +; http://php.net/cgi.rfc2616-headers +;cgi.rfc2616_headers = 0 + +;;;;;;;;;;;;;;;; +; File Uploads ; +;;;;;;;;;;;;;;;; + +; Whether to allow HTTP file uploads. +; http://php.net/file-uploads +file_uploads = On + +; Temporary directory for HTTP uploaded files (will use system default if not +; specified). +; http://php.net/upload-tmp-dir +;upload_tmp_dir = + +; Maximum allowed size for uploaded files. +; http://php.net/upload-max-filesize +upload_max_filesize = 2M + +; Maximum number of files that can be uploaded via a single request +max_file_uploads = 20 + +;;;;;;;;;;;;;;;;;; +; Fopen wrappers ; +;;;;;;;;;;;;;;;;;; + +; Whether to allow the treatment of URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-fopen +allow_url_fopen = On + +; Whether to allow include/require to open URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-include +allow_url_include = Off + +; Define the anonymous ftp password (your email address). PHP's default setting +; for this is empty. +; http://php.net/from +;from="john@doe.com" + +; Define the User-Agent string. PHP's default setting for this is empty. +; http://php.net/user-agent +;user_agent="PHP" + +; Default timeout for socket based streams (seconds) +; http://php.net/default-socket-timeout +default_socket_timeout = 60 + +; If your scripts have to deal with files from Macintosh systems, +; or you are running on a Mac and need to deal with files from +; unix or win32 systems, setting this flag will cause PHP to +; automatically detect the EOL character in those files so that +; fgets() and file() will work regardless of the source of the file. +; http://php.net/auto-detect-line-endings +;auto_detect_line_endings = Off + +;;;;;;;;;;;;;;;;;;;;;; +; Dynamic Extensions ; +;;;;;;;;;;;;;;;;;;;;;; + +extension=./lib/tarantool.so +; If you wish to have an extension loaded automatically, use the following +; syntax: +; +; extension=modulename.extension +; +; For example, on Windows: +; +; extension=msql.dll +; +; ... or under UNIX: +; +; extension=msql.so +; +; ... or with a path: +; +; extension=/path/to/extension/msql.so +; +; If you only provide the name of the extension, PHP will look for it in its +; default extension directory. + +;;;;;;;;;;;;;;;;;;; +; Module Settings ; +;;;;;;;;;;;;;;;;;;; + +[Date] +; Defines the default timezone used by the date functions +; http://php.net/date.timezone +;date.timezone = + +; http://php.net/date.default-latitude +;date.default_latitude = 31.7667 + +; http://php.net/date.default-longitude +;date.default_longitude = 35.2333 + +; http://php.net/date.sunrise-zenith +;date.sunrise_zenith = 90.583333 + +; http://php.net/date.sunset-zenith +;date.sunset_zenith = 90.583333 + +[filter] +; http://php.net/filter.default +;filter.default = unsafe_raw + +; http://php.net/filter.default-flags +;filter.default_flags = + +[iconv] +;iconv.input_encoding = ISO-8859-1 +;iconv.internal_encoding = ISO-8859-1 +;iconv.output_encoding = ISO-8859-1 + +[intl] +;intl.default_locale = +; This directive allows you to produce PHP errors when some error +; happens within intl functions. The value is the level of the error produced. +; Default is 0, which does not produce any errors. +;intl.error_level = E_WARNING + +[sqlite] +; http://php.net/sqlite.assoc-case +;sqlite.assoc_case = 0 + +[sqlite3] +;sqlite3.extension_dir = + +[Pcre] +;PCRE library backtracking limit. +; http://php.net/pcre.backtrack-limit +;pcre.backtrack_limit=100000 + +;PCRE library recursion limit. +;Please note that if you set this value to a high number you may consume all +;the available process stack and eventually crash PHP (due to reaching the +;stack size limit imposed by the Operating System). +; http://php.net/pcre.recursion-limit +;pcre.recursion_limit=100000 + +[Pdo] +; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" +; http://php.net/pdo-odbc.connection-pooling +;pdo_odbc.connection_pooling=strict + +;pdo_odbc.db2_instance_name + +[Pdo_mysql] +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/pdo_mysql.cache_size +pdo_mysql.cache_size = 2000 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/pdo_mysql.default-socket +pdo_mysql.default_socket= + +[Phar] +; http://php.net/phar.readonly +;phar.readonly = On + +; http://php.net/phar.require-hash +;phar.require_hash = On + +;phar.cache_list = + +[Syslog] +; Whether or not to define the various syslog variables (e.g. $LOG_PID, +; $LOG_CRON, etc.). Turning it off is a good idea performance-wise. In +; runtime, you can define these variables by calling define_syslog_variables(). +; http://php.net/define-syslog-variables +define_syslog_variables = Off + +[mail function] +; For Win32 only. +; http://php.net/smtp +SMTP = localhost +; http://php.net/smtp-port +smtp_port = 25 + +; For Win32 only. +; http://php.net/sendmail-from +;sendmail_from = me@example.com + +; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). +; http://php.net/sendmail-path +;sendmail_path = + +; Force the addition of the specified parameters to be passed as extra parameters +; to the sendmail binary. These parameters will always replace the value of +; the 5th parameter to mail(), even in safe mode. +;mail.force_extra_parameters = + +; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename +mail.add_x_header = On + +; The path to a log file that will log all mail() calls. Log entries include +; the full path of the script, line number, To address and headers. +;mail.log = + +[SQL] +; http://php.net/sql.safe-mode +sql.safe_mode = Off + +[ODBC] +; http://php.net/odbc.default-db +;odbc.default_db = Not yet implemented + +; http://php.net/odbc.default-user +;odbc.default_user = Not yet implemented + +; http://php.net/odbc.default-pw +;odbc.default_pw = Not yet implemented + +; Controls the ODBC cursor model. +; Default: SQL_CURSOR_STATIC (default). +;odbc.default_cursortype + +; Allow or prevent persistent links. +; http://php.net/odbc.allow-persistent +odbc.allow_persistent = On + +; Check that a connection is still valid before reuse. +; http://php.net/odbc.check-persistent +odbc.check_persistent = On + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/odbc.max-persistent +odbc.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/odbc.max-links +odbc.max_links = -1 + +; Handling of LONG fields. Returns number of bytes to variables. 0 means +; passthru. +; http://php.net/odbc.defaultlrl +odbc.defaultlrl = 4096 + +; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. +; See the documentation on odbc_binmode and odbc_longreadlen for an explanation +; of odbc.defaultlrl and odbc.defaultbinmode +; http://php.net/odbc.defaultbinmode +odbc.defaultbinmode = 1 + +;birdstep.max_links = -1 + +[Interbase] +; Allow or prevent persistent links. +ibase.allow_persistent = 1 + +; Maximum number of persistent links. -1 means no limit. +ibase.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +ibase.max_links = -1 + +; Default database name for ibase_connect(). +;ibase.default_db = + +; Default username for ibase_connect(). +;ibase.default_user = + +; Default password for ibase_connect(). +;ibase.default_password = + +; Default charset for ibase_connect(). +;ibase.default_charset = + +; Default timestamp format. +ibase.timestampformat = "%Y-%m-%d %H:%M:%S" + +; Default date format. +ibase.dateformat = "%Y-%m-%d" + +; Default time format. +ibase.timeformat = "%H:%M:%S" + +[MySQL] +; Allow accessing, from PHP's perspective, local files with LOAD DATA statements +; http://php.net/mysql.allow_local_infile +mysql.allow_local_infile = On + +; Allow or prevent persistent links. +; http://php.net/mysql.allow-persistent +mysql.allow_persistent = On + +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/mysql.cache_size +mysql.cache_size = 2000 + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/mysql.max-persistent +mysql.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/mysql.max-links +mysql.max_links = -1 + +; Default port number for mysql_connect(). If unset, mysql_connect() will use +; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the +; compile-time value defined MYSQL_PORT (in that order). Win32 will only look +; at MYSQL_PORT. +; http://php.net/mysql.default-port +mysql.default_port = + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/mysql.default-socket +mysql.default_socket = + +; Default host for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysql.default-host +mysql.default_host = + +; Default user for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysql.default-user +mysql.default_user = + +; Default password for mysql_connect() (doesn't apply in safe mode). +; Note that this is generally a *bad* idea to store passwords in this file. +; *Any* user with PHP access can run 'echo get_cfg_var("mysql.default_password") +; and reveal this password! And of course, any users with read access to this +; file will be able to reveal the password as well. +; http://php.net/mysql.default-password +mysql.default_password = + +; Maximum time (in seconds) for connect timeout. -1 means no limit +; http://php.net/mysql.connect-timeout +mysql.connect_timeout = 60 + +; Trace mode. When trace_mode is active (=On), warnings for table/index scans and +; SQL-Errors will be displayed. +; http://php.net/mysql.trace-mode +mysql.trace_mode = Off + +[MySQLi] + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/mysqli.max-persistent +mysqli.max_persistent = -1 + +; Allow accessing, from PHP's perspective, local files with LOAD DATA statements +; http://php.net/mysqli.allow_local_infile +;mysqli.allow_local_infile = On + +; Allow or prevent persistent links. +; http://php.net/mysqli.allow-persistent +mysqli.allow_persistent = On + +; Maximum number of links. -1 means no limit. +; http://php.net/mysqli.max-links +mysqli.max_links = -1 + +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/mysqli.cache_size +mysqli.cache_size = 2000 + +; Default port number for mysqli_connect(). If unset, mysqli_connect() will use +; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the +; compile-time value defined MYSQL_PORT (in that order). Win32 will only look +; at MYSQL_PORT. +; http://php.net/mysqli.default-port +mysqli.default_port = 3306 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/mysqli.default-socket +mysqli.default_socket = + +; Default host for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-host +mysqli.default_host = + +; Default user for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-user +mysqli.default_user = + +; Default password for mysqli_connect() (doesn't apply in safe mode). +; Note that this is generally a *bad* idea to store passwords in this file. +; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") +; and reveal this password! And of course, any users with read access to this +; file will be able to reveal the password as well. +; http://php.net/mysqli.default-pw +mysqli.default_pw = + +; Allow or prevent reconnect +mysqli.reconnect = Off + +[mysqlnd] +; Enable / Disable collection of general statstics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_statistics +mysqlnd.collect_statistics = On + +; Enable / Disable collection of memory usage statstics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_memory_statistics +mysqlnd.collect_memory_statistics = Off + +; Size of a pre-allocated buffer used when sending commands to MySQL in bytes. +; http://php.net/mysqlnd.net_cmd_buffer_size +;mysqlnd.net_cmd_buffer_size = 2048 + +; Size of a pre-allocated buffer used for reading data sent by the server in +; bytes. +; http://php.net/mysqlnd.net_read_buffer_size +;mysqlnd.net_read_buffer_size = 32768 + +[OCI8] + +; Connection: Enables privileged connections using external +; credentials (OCI_SYSOPER, OCI_SYSDBA) +; http://php.net/oci8.privileged-connect +;oci8.privileged_connect = Off + +; Connection: The maximum number of persistent OCI8 connections per +; process. Using -1 means no limit. +; http://php.net/oci8.max-persistent +;oci8.max_persistent = -1 + +; Connection: The maximum number of seconds a process is allowed to +; maintain an idle persistent connection. Using -1 means idle +; persistent connections will be maintained forever. +; http://php.net/oci8.persistent-timeout +;oci8.persistent_timeout = -1 + +; Connection: The number of seconds that must pass before issuing a +; ping during oci_pconnect() to check the connection validity. When +; set to 0, each oci_pconnect() will cause a ping. Using -1 disables +; pings completely. +; http://php.net/oci8.ping-interval +;oci8.ping_interval = 60 + +; Connection: Set this to a user chosen connection class to be used +; for all pooled server requests with Oracle 11g Database Resident +; Connection Pooling (DRCP). To use DRCP, this value should be set to +; the same string for all web servers running the same application, +; the database pool must be configured, and the connection string must +; specify to use a pooled server. +;oci8.connection_class = + +; High Availability: Using On lets PHP receive Fast Application +; Notification (FAN) events generated when a database node fails. The +; database must also be configured to post FAN events. +;oci8.events = Off + +; Tuning: This option enables statement caching, and specifies how +; many statements to cache. Using 0 disables statement caching. +; http://php.net/oci8.statement-cache-size +;oci8.statement_cache_size = 20 + +; Tuning: Enables statement prefetching and sets the default number of +; rows that will be fetched automatically after statement execution. +; http://php.net/oci8.default-prefetch +;oci8.default_prefetch = 100 + +; Compatibility. Using On means oci_close() will not close +; oci_connect() and oci_new_connect() connections. +; http://php.net/oci8.old-oci-close-semantics +;oci8.old_oci_close_semantics = Off + +[PostgresSQL] +; Allow or prevent persistent links. +; http://php.net/pgsql.allow-persistent +pgsql.allow_persistent = On + +; Detect broken persistent links always with pg_pconnect(). +; Auto reset feature requires a little overheads. +; http://php.net/pgsql.auto-reset-persistent +pgsql.auto_reset_persistent = Off + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/pgsql.max-persistent +pgsql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +; http://php.net/pgsql.max-links +pgsql.max_links = -1 + +; Ignore PostgreSQL backends Notice message or not. +; Notice message logging require a little overheads. +; http://php.net/pgsql.ignore-notice +pgsql.ignore_notice = 0 + +; Log PostgreSQL backends Notice message or not. +; Unless pgsql.ignore_notice=0, module cannot log notice message. +; http://php.net/pgsql.log-notice +pgsql.log_notice = 0 + +[Sybase-CT] +; Allow or prevent persistent links. +; http://php.net/sybct.allow-persistent +sybct.allow_persistent = On + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/sybct.max-persistent +sybct.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/sybct.max-links +sybct.max_links = -1 + +; Minimum server message severity to display. +; http://php.net/sybct.min-server-severity +sybct.min_server_severity = 10 + +; Minimum client message severity to display. +; http://php.net/sybct.min-client-severity +sybct.min_client_severity = 10 + +; Set per-context timeout +; http://php.net/sybct.timeout +;sybct.timeout= + +;sybct.packet_size + +; The maximum time in seconds to wait for a connection attempt to succeed before returning failure. +; Default: one minute +;sybct.login_timeout= + +; The name of the host you claim to be connecting from, for display by sp_who. +; Default: none +;sybct.hostname= + +; Allows you to define how often deadlocks are to be retried. -1 means "forever". +; Default: 0 +;sybct.deadlock_retry_count= + +[bcmath] +; Number of decimal digits for all bcmath functions. +; http://php.net/bcmath.scale +bcmath.scale = 0 + +[browscap] +; http://php.net/browscap +;browscap = extra/browscap.ini + +[Session] +; Handler used to store/retrieve data. +; http://php.net/session.save-handler +session.save_handler = files + +; Argument passed to save_handler. In the case of files, this is the path +; where data files are stored. Note: Windows users have to change this +; variable in order to use PHP's session functions. +; +; The path can be defined as: +; +; session.save_path = "N;/path" +; +; where N is an integer. Instead of storing all the session files in +; /path, what this will do is use subdirectories N-levels deep, and +; store the session data in those directories. This is useful if you +; or your OS have problems with lots of files in one directory, and is +; a more efficient layout for servers that handle lots of sessions. +; +; NOTE 1: PHP will not create this directory structure automatically. +; You can use the script in the ext/session dir for that purpose. +; NOTE 2: See the section on garbage collection below if you choose to +; use subdirectories for session storage +; +; The file storage module creates files using mode 600 by default. +; You can change that by using +; +; session.save_path = "N;MODE;/path" +; +; where MODE is the octal representation of the mode. Note that this +; does not overwrite the process's umask. +; http://php.net/session.save-path +;session.save_path = "/tmp" + +; Whether to use cookies. +; http://php.net/session.use-cookies +session.use_cookies = 1 + +; http://php.net/session.cookie-secure +;session.cookie_secure = + +; This option forces PHP to fetch and use a cookie for storing and maintaining +; the session id. We encourage this operation as it's very helpful in combatting +; session hijacking when not specifying and managing your own session id. It is +; not the end all be all of session hijacking defense, but it's a good start. +; http://php.net/session.use-only-cookies +session.use_only_cookies = 1 + +; Name of the session (used as cookie name). +; http://php.net/session.name +session.name = PHPSESSID + +; Initialize session on request startup. +; http://php.net/session.auto-start +session.auto_start = 0 + +; Lifetime in seconds of cookie or, if 0, until browser is restarted. +; http://php.net/session.cookie-lifetime +session.cookie_lifetime = 0 + +; The path for which the cookie is valid. +; http://php.net/session.cookie-path +session.cookie_path = / + +; The domain for which the cookie is valid. +; http://php.net/session.cookie-domain +session.cookie_domain = + +; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. +; http://php.net/session.cookie-httponly +session.cookie_httponly = + +; Handler used to serialize data. php is the standard serializer of PHP. +; http://php.net/session.serialize-handler +session.serialize_handler = php + +; Defines the probability that the 'garbage collection' process is started +; on every session initialization. The probability is calculated by using +; gc_probability/gc_divisor. Where session.gc_probability is the numerator +; and gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.gc-probability +session.gc_probability = 0 + +; Defines the probability that the 'garbage collection' process is started on every +; session initialization. The probability is calculated by using the following equation: +; gc_probability/gc_divisor. Where session.gc_probability is the numerator and +; session.gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. Increasing this value to 1000 will give you +; a 0.1% chance the gc will run on any give request. For high volume production servers, +; this is a more efficient approach. +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 +; http://php.net/session.gc-divisor +session.gc_divisor = 1000 + +; After this number of seconds, stored data will be seen as 'garbage' and +; cleaned up by the garbage collection process. +; http://php.net/session.gc-maxlifetime +session.gc_maxlifetime = 1440 + +; NOTE: If you are using the subdirectory option for storing session files +; (see session.save_path above), then garbage collection does *not* +; happen automatically. You will need to do your own garbage +; collection through a shell script, cron entry, or some other method. +; For example, the following script would is the equivalent of +; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): +; find /path/to/sessions -cmin +24 | xargs rm + +; PHP 4.2 and less have an undocumented feature/bug that allows you to +; to initialize a session variable in the global scope, even when register_globals +; is disabled. PHP 4.3 and later will warn you, if this feature is used. +; You can disable the feature and the warning separately. At this time, +; the warning is only displayed, if bug_compat_42 is enabled. This feature +; introduces some serious security problems if not handled correctly. It's +; recommended that you do not use this feature on production servers. But you +; should enable this on development servers and enable the warning as well. If you +; do not enable the feature on development servers, you won't be warned when it's +; used and debugging errors caused by this can be difficult to track down. +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/session.bug-compat-42 +session.bug_compat_42 = Off + +; This setting controls whether or not you are warned by PHP when initializing a +; session value into the global space. session.bug_compat_42 must be enabled before +; these warnings can be issued by PHP. See the directive above for more information. +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/session.bug-compat-warn +session.bug_compat_warn = Off + +; Check HTTP Referer to invalidate externally stored URLs containing ids. +; HTTP_REFERER has to contain this substring for the session to be +; considered as valid. +; http://php.net/session.referer-check +session.referer_check = + +; How many bytes to read from the file. +; http://php.net/session.entropy-length +session.entropy_length = 0 + +; Specified here to create the session id. +; http://php.net/session.entropy-file +; On systems that don't have /dev/urandom /dev/arandom can be used +; On windows, setting the entropy_length setting will activate the +; Windows random source (using the CryptoAPI) +;session.entropy_file = /dev/urandom + +; Set to {nocache,private,public,} to determine HTTP caching aspects +; or leave this empty to avoid sending anti-caching headers. +; http://php.net/session.cache-limiter +session.cache_limiter = nocache + +; Document expires after n minutes. +; http://php.net/session.cache-expire +session.cache_expire = 180 + +; trans sid support is disabled by default. +; Use of trans sid may risk your users security. +; Use this option with caution. +; - User may send URL contains active session ID +; to other person via. email/irc/etc. +; - URL that contains active session ID may be stored +; in publically accessible computer. +; - User may access your site with the same session ID +; always using URL stored in browser's history or bookmarks. +; http://php.net/session.use-trans-sid +session.use_trans_sid = 0 + +; Select a hash function for use in generating session ids. +; Possible Values +; 0 (MD5 128 bits) +; 1 (SHA-1 160 bits) +; This option may also be set to the name of any hash function supported by +; the hash extension. A list of available hashes is returned by the hash_algos() +; function. +; http://php.net/session.hash-function +session.hash_function = 0 + +; Define how many bits are stored in each character when converting +; the binary hash data to something readable. +; Possible values: +; 4 (4 bits: 0-9, a-f) +; 5 (5 bits: 0-9, a-v) +; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 +; http://php.net/session.hash-bits-per-character +session.hash_bits_per_character = 5 + +; The URL rewriter will look for URLs in a defined set of HTML tags. +; form/fieldset are special; if you include them here, the rewriter will +; add a hidden <input> field with the info which is otherwise appended +; to URLs. If you want XHTML conformity, remove the form entry. +; Note that all valid entries require a "=", even if no value follows. +; Default Value: "a=href,area=href,frame=src,form=,fieldset=" +; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry" +; http://php.net/url-rewriter.tags +url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry" + +[MSSQL] +; Allow or prevent persistent links. +mssql.allow_persistent = On + +; Maximum number of persistent links. -1 means no limit. +mssql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +mssql.max_links = -1 + +; Minimum error severity to display. +mssql.min_error_severity = 10 + +; Minimum message severity to display. +mssql.min_message_severity = 10 + +; Compatibility mode with old versions of PHP 3.0. +mssql.compatability_mode = Off + +; Connect timeout +;mssql.connect_timeout = 5 + +; Query timeout +;mssql.timeout = 60 + +; Valid range 0 - 2147483647. Default = 4096. +;mssql.textlimit = 4096 + +; Valid range 0 - 2147483647. Default = 4096. +;mssql.textsize = 4096 + +; Limits the number of records in each batch. 0 = all records in one batch. +;mssql.batchsize = 0 + +; Specify how datetime and datetim4 columns are returned +; On => Returns data converted to SQL server settings +; Off => Returns values as YYYY-MM-DD hh:mm:ss +;mssql.datetimeconvert = On + +; Use NT authentication when connecting to the server +mssql.secure_connection = Off + +; Specify max number of processes. -1 = library default +; msdlib defaults to 25 +; FreeTDS defaults to 4096 +;mssql.max_procs = -1 + +; Specify client character set. +; If empty or not set the client charset from freetds.comf is used +; This is only used when compiled with FreeTDS +;mssql.charset = "ISO-8859-1" + +[Assertion] +; Assert(expr); active by default. +; http://php.net/assert.active +;assert.active = On + +; Issue a PHP warning for each failed assertion. +; http://php.net/assert.warning +;assert.warning = On + +; Don't bail out by default. +; http://php.net/assert.bail +;assert.bail = Off + +; User-function to be called if an assertion fails. +; http://php.net/assert.callback +;assert.callback = 0 + +; Eval the expression with current error_reporting(). Set to true if you want +; error_reporting(0) around the eval(). +; http://php.net/assert.quiet-eval +;assert.quiet_eval = 0 + +[COM] +; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs +; http://php.net/com.typelib-file +;com.typelib_file = + +; allow Distributed-COM calls +; http://php.net/com.allow-dcom +;com.allow_dcom = true + +; autoregister constants of a components typlib on com_load() +; http://php.net/com.autoregister-typelib +;com.autoregister_typelib = true + +; register constants casesensitive +; http://php.net/com.autoregister-casesensitive +;com.autoregister_casesensitive = false + +; show warnings on duplicate constant registrations +; http://php.net/com.autoregister-verbose +;com.autoregister_verbose = true + +; The default character set code-page to use when passing strings to and from COM objects. +; Default: system ANSI code page +;com.code_page= + +[mbstring] +; language for internal character representation. +; http://php.net/mbstring.language +;mbstring.language = Japanese + +; internal/script encoding. +; Some encoding cannot work as internal encoding. +; (e.g. SJIS, BIG5, ISO-2022-*) +; http://php.net/mbstring.internal-encoding +;mbstring.internal_encoding = EUC-JP + +; http input encoding. +; http://php.net/mbstring.http-input +;mbstring.http_input = auto + +; http output encoding. mb_output_handler must be +; registered as output buffer to function +; http://php.net/mbstring.http-output +;mbstring.http_output = SJIS + +; enable automatic encoding translation according to +; mbstring.internal_encoding setting. Input chars are +; converted to internal encoding by setting this to On. +; Note: Do _not_ use automatic encoding translation for +; portable libs/applications. +; http://php.net/mbstring.encoding-translation +;mbstring.encoding_translation = Off + +; automatic encoding detection order. +; auto means +; http://php.net/mbstring.detect-order +;mbstring.detect_order = auto + +; substitute_character used when character cannot be converted +; one from another +; http://php.net/mbstring.substitute-character +;mbstring.substitute_character = none; + +; overload(replace) single byte functions by mbstring functions. +; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), +; etc. Possible values are 0,1,2,4 or combination of them. +; For example, 7 for overload everything. +; 0: No overload +; 1: Overload mail() function +; 2: Overload str*() functions +; 4: Overload ereg*() functions +; http://php.net/mbstring.func-overload +;mbstring.func_overload = 0 + +; enable strict encoding detection. +;mbstring.strict_detection = Off + +; This directive specifies the regex pattern of content types for which mb_output_handler() +; is activated. +; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) +;mbstring.http_output_conv_mimetype= + +; Allows to set script encoding. Only affects if PHP is compiled with --enable-zend-multibyte +; Default: "" +;mbstring.script_encoding= + +[gd] +; Tell the jpeg decode to ignore warnings and try to create +; a gd image. The warning will then be displayed as notices +; disabled by default +; http://php.net/gd.jpeg-ignore-warning +;gd.jpeg_ignore_warning = 0 + +[exif] +; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. +; With mbstring support this will automatically be converted into the encoding +; given by corresponding encode setting. When empty mbstring.internal_encoding +; is used. For the decode settings you can distinguish between motorola and +; intel byte order. A decode setting cannot be empty. +; http://php.net/exif.encode-unicode +;exif.encode_unicode = ISO-8859-15 + +; http://php.net/exif.decode-unicode-motorola +;exif.decode_unicode_motorola = UCS-2BE + +; http://php.net/exif.decode-unicode-intel +;exif.decode_unicode_intel = UCS-2LE + +; http://php.net/exif.encode-jis +;exif.encode_jis = + +; http://php.net/exif.decode-jis-motorola +;exif.decode_jis_motorola = JIS + +; http://php.net/exif.decode-jis-intel +;exif.decode_jis_intel = JIS + +[Tidy] +; The path to a default tidy configuration file to use when using tidy +; http://php.net/tidy.default-config +;tidy.default_config = /usr/local/lib/php/default.tcfg + +; Should tidy clean and repair output automatically? +; WARNING: Do not use this option if you are generating non-html content +; such as dynamic images +; http://php.net/tidy.clean-output +tidy.clean_output = Off + +[soap] +; Enables or disables WSDL caching feature. +; http://php.net/soap.wsdl-cache-enabled +soap.wsdl_cache_enabled=1 + +; Sets the directory name where SOAP extension will put cache files. +; http://php.net/soap.wsdl-cache-dir +soap.wsdl_cache_dir="/tmp" + +; (time to live) Sets the number of second while cached file will be used +; instead of original one. +; http://php.net/soap.wsdl-cache-ttl +soap.wsdl_cache_ttl=86400 + +; Sets the size of the cache limit. (Max. number of WSDL files to cache) +soap.wsdl_cache_limit = 5 + +[sysvshm] +; A default size of the shared memory segment +;sysvshm.init_mem = 10000 + +[ldap] +; Sets the maximum number of open links or -1 for unlimited. +ldap.max_links = -1 + +[mcrypt] +; For more information about mcrypt settings see http://php.net/mcrypt-module-open + +; Directory where to load mcrypt algorithms +; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) +;mcrypt.algorithms_dir= + +; Directory where to load mcrypt modes +; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt) +;mcrypt.modes_dir= + +[dba] +;dba.default_handler= + +; Local Variables: +; tab-width: 4 +; End: diff --git a/connector/php/test/etc/tarantool_box.cfg b/connector/php/test/etc/tarantool_box.cfg new file mode 100644 index 0000000000..9ccb6910a3 --- /dev/null +++ b/connector/php/test/etc/tarantool_box.cfg @@ -0,0 +1,55 @@ +# Limit of memory used to store tuples to 100MB +# (0.1 GB) +# This effectively limits the memory, used by +# Tarantool. However, index and connection memory +# is stored outside the slab allocator, hence +# the effective memory usage can be higher (sometimes +# twice as high). +slab_alloc_arena = 0.1 + +# Tarantool executable directory +work_dir = "var" + +# Store the pid in this file. Relative to startup dir. +pid_file = "tarantool_box.pid" + +# Snapshot directory (where snapshots get saved/read) +snap_dir="." + +# WAL directory (where WALs get saved/read) +wal_dir="." + +# Pipe the logs into the following process. +logger="cat - >> tarantool_box.log" + +# Read only and read-write port. +primary_port = 33013 + +# Read-only port. +secondary_port = 33014 + +# The port for administrative commands. +admin_port = 33015 + +# Log level +log_level = 4 + +# Each write ahead log contains this many rows. +# When the limit is reached, Tarantool closes +# the WAL and starts a new one. +rows_per_wal = 5000000 + +wal_fsync_delay = 0.1 +wal_writer_inbox_size=1024 + +# Define a simple space with 1 HASH-based +# primary key. +space[0].enabled = 1 +space[0].index[0].type = "HASH" +space[0].index[0].unique = 1 +space[0].index[0].key_field[0].fieldno = 0 +space[0].index[0].key_field[0].type = "NUM" +space[0].index[1].type = "TREE" +space[0].index[1].unique = 0 +space[0].index[1].key_field[0].fieldno = 1 +space[0].index[1].key_field[0].type = "STR" diff --git a/connector/php/test/insert.phpt b/connector/php/test/insert.phpt new file mode 100644 index 0000000000..047db2a297 --- /dev/null +++ b/connector/php/test/insert.phpt @@ -0,0 +1,173 @@ +--TEST-- +Tarantool/box insert command test +--FILE-- +<?php +include "lib/php/tarantool_utest.php"; + +$tarantool = new Tarantool("localhost", 33013, 33015); + +echo "---------- test begin ----------\n"; +echo "test insert: invalid tuple (expected error exception)\n"; +test_insert($tarantool, 0, array(0, array(1, 2, 3), "str"), 0); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test insert: invalid tuple (expected error exception)\n"; +test_insert($tarantool, 0, array(0, $tarantool), 0); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test insert: assign tuple"; +test_insert($tarantool, 0, $sw4, + TARANTOOL_FLAGS_RETURN_TUPLE); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test insert: assign tuple (tuple doesn't return)\n"; +test_insert($tarantool, 0, $sw6, 0); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test insert: add existed tuple (expected error exception)\n"; +test_insert($tarantool, 0, $sw4, + TARANTOOL_FLAGS_RETURN_TUPLE | TARANTOOL_FLAGS_ADD); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test insert: replace not existed tuple (expected error exception)\n"; +test_insert($tarantool, 0, $sw5, + TARANTOOL_FLAGS_RETURN_TUPLE | TARANTOOL_FLAGS_REPLACE); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test insert: add not existed tuple\n"; +test_insert($tarantool, 0, $sw5, + TARANTOOL_FLAGS_RETURN_TUPLE | TARANTOOL_FLAGS_ADD); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test insert: replace existed tuple\n"; +test_insert($tarantool, 0, $sw5, + TARANTOOL_FLAGS_RETURN_TUPLE | TARANTOOL_FLAGS_REPLACE); +echo "----------- test end -----------\n\n"; + +test_clean($tarantool, 0); +?> +===DONE=== +--EXPECT-- +---------- test begin ---------- +test insert: invalid tuple (expected error exception) +catched exception: unsupported field type +----------- test end ----------- + +---------- test begin ---------- +test insert: invalid tuple (expected error exception) +catched exception: unsupported field type +----------- test end ----------- + +---------- test begin ---------- +test insert: assign tupleresult: +count = 1 +tuple: + id = 0 + series = Star Wars + year = 1977 + name = A New Hope + crawl = A long time ago, in a galaxy far, far away... +It is a period of civil war. Rebel +spaceships, striking from a hidden +base, have won their first victory +against the evil Galactic Empire. + +During the battle, Rebel spies managed +to steal secret plans to the Empire's +ultimate weapon, the Death Star, an +armored space station with enough +power to destroy an entire planet. + +Pursued by the Empire's sinister agents, +Princess Leia races home aboard her +starship, custodian of the stolen plans +that can save her people and restore +freedom to the galaxy.... +----------- test end ----------- + +---------- test begin ---------- +test insert: assign tuple (tuple doesn't return) +result: +count = 1 +----------- test end ----------- + +---------- test begin ---------- +test insert: add existed tuple (expected error exception) +catched exception: insert failed: 14082 +----------- test end ----------- + +---------- test begin ---------- +test insert: replace not existed tuple (expected error exception) +catched exception: insert failed: 12546 +----------- test end ----------- + +---------- test begin ---------- +test insert: add not existed tuple +result: +count = 1 +tuple: + id = 1 + series = Star Wars + year = 1980 + name = The Empire Strikes Back + crawl = It is a dark time for the +Rebellion. Although the Death +Star has been destroyed. +Imperial troops have driven the +Rebel forces from their hidden +base and pursued them across +the galaxy. + +Evading the dreaded Imperial +Starfleet, a group of freedom +fighters led by Luke Skywalker +have established a new secret base +on the remote ice world +of Hoth. + +The evil lord Darth Vader, +obsessed with finding young +Skywalker, has dispatched +thousands of remote probes +into the far reaches of space.... +----------- test end ----------- + +---------- test begin ---------- +test insert: replace existed tuple +result: +count = 1 +tuple: + id = 1 + series = Star Wars + year = 1980 + name = The Empire Strikes Back + crawl = It is a dark time for the +Rebellion. Although the Death +Star has been destroyed. +Imperial troops have driven the +Rebel forces from their hidden +base and pursued them across +the galaxy. + +Evading the dreaded Imperial +Starfleet, a group of freedom +fighters led by Luke Skywalker +have established a new secret base +on the remote ice world +of Hoth. + +The evil lord Darth Vader, +obsessed with finding young +Skywalker, has dispatched +thousands of remote probes +into the far reaches of space.... +----------- test end ----------- + +===DONE=== \ No newline at end of file diff --git a/connector/php/test/lib/lua/test.lua b/connector/php/test/lib/lua/test.lua new file mode 100644 index 0000000000..2dcc8f1df6 --- /dev/null +++ b/connector/php/test/lib/lua/test.lua @@ -0,0 +1,25 @@ +function myselect(space, index, key) + print("select in space: ", space, " index: ", index, " by key ", key) + return box.select(space, index, key) +end + +function myfoo() + return { 0, "Star Wars", "1977 year", "A New Hope", + "A long time ago, in a galaxy far, far away...\n" .. + "It is a period of civil war. Rebel\n" .. + "spaceships, striking from a hidden\n" .. + "base, have won their first victory\n" .. + "against the evil Galactic Empire.\n" .. + "\n" .. + "During the battle, Rebel spies managed\n" .. + "to steal secret plans to the Empire's\n" .. + "ultimate weapon, the Death Star, an\n" .. + "armored space station with enough\n".. + "power to destroy an entire planet.\n" .. + "\n" .. + "Pursued by the Empire's sinister agents,\n" .. + "Princess Leia races home aboard her\n" .. + "starship, custodian of the stolen plans\n" .. + "that can save her people and restore\n" .. + "freedom to the galaxy...." } +end \ No newline at end of file diff --git a/connector/php/test/lib/php/tarantool_utest.php b/connector/php/test/lib/php/tarantool_utest.php new file mode 100644 index 0000000000..27ac276d7b --- /dev/null +++ b/connector/php/test/lib/php/tarantool_utest.php @@ -0,0 +1,183 @@ +<?php + +$sw4 = array(0, "Star Wars", 1977, "A New Hope", + "A long time ago, in a galaxy far, far away...\n" . + "It is a period of civil war. Rebel\n" . + "spaceships, striking from a hidden\n" . + "base, have won their first victory\n" . + "against the evil Galactic Empire.\n" . + "\n" . + "During the battle, Rebel spies managed\n" . + "to steal secret plans to the Empire's\n" . + "ultimate weapon, the Death Star, an\n" . + "armored space station with enough\n". + "power to destroy an entire planet.\n" . + "\n" . + "Pursued by the Empire's sinister agents,\n" . + "Princess Leia races home aboard her\n" . + "starship, custodian of the stolen plans\n" . + "that can save her people and restore\n" . + "freedom to the galaxy...."); + +$sw5 = array(1, "Star Wars", 1980, "The Empire Strikes Back", + "It is a dark time for the\n" . + "Rebellion. Although the Death\n" . + "Star has been destroyed.\n" . + "Imperial troops have driven the\n" . + "Rebel forces from their hidden\n" . + "base and pursued them across\n" . + "the galaxy.\n" . + "\n" . + "Evading the dreaded Imperial\n" . + "Starfleet, a group of freedom\n" . + "fighters led by Luke Skywalker\n" . + "have established a new secret base\n" . + "on the remote ice world\n" . + "of Hoth.\n" . + "\n" . + "The evil lord Darth Vader,\n" . + "obsessed with finding young\n" . + "Skywalker, has dispatched\n" . + "thousands of remote probes\n" . + "into the far reaches of space...."); + +$sw6 = array(2, "Star Wars", 1983, "Return of the Jedi", + "Luke Skywalker has returned\n" . + "to his home planet of\n" . + "Tatooine in an attempt\n" . + "to rescue his friend\n" . + "Han Solo from the\n" . + "clutches of the vile\n" . + "gangster Jabba the Hutt.\n" . + "\n" . + "Little does Luke know\n" . + "that the GALACTIC EMPIRE\n" . + "has secretly begun construction\n" . + "on a new armored space station\n" . + "even more powerful than the\n" . + "first dreaded Death Star.\n" . + "\n" . + "When completed, this ultimate\n" . + "weapon will spell certain\n" . + "doom for the small band of\n" . + "rebels struggling to restore\n" . + "freedom to the galaxy..."); + +function test_init($tarantool, $space_no) { + try { + global $sw4, $sw5, $sw6; + $tarantool->insert($space_no, $sw4); + $tarantool->insert($space_no, $sw5); + $tarantool->insert($space_no, $sw6); + } catch (Exception $e) { + echo "init failed: ", $e->getMessage(), "\n"; + throw $e; + } +} + +function test_clean($tarantool, $space_no) { + try { + $tarantool->delete($space_no, 0); + $tarantool->delete($space_no, 1); + $tarantool->delete($space_no, 2); + } catch (Exception $e) { + echo "clean-up failed: ", $e->getMessage(), "\n"; + throw $e; + } +} + +function test_select($tarantool, $space_no, $index_no, $key) { + try { + $result = $tarantool->select($space_no, $index_no, $key); + echo "result:\n"; + echo "count = ", $result["count"], "\n"; + $tuples_list = $result["tuples_list"]; + sort($tuples_list); + for ($i = 0; $i < $result["count"]; $i++) { + echo "tuple[", $i, "]:", "\n"; + echo " id = ", $tuples_list[$i][0], "\n"; + echo " series = ", $tuples_list[$i][1], "\n"; + echo " year = ", $tuples_list[$i][2], "\n"; + echo " name = ", $tuples_list[$i][3], "\n"; + echo " crawl = ", $tuples_list[$i][4], "\n"; + } + } catch (Exception $e) { + echo "catched exception: ", $e->getMessage(), "\n"; + } +} + +function test_insert($tarantool, $space_no, $tuple, $flags) { + try { + $result = $tarantool->insert($space_no, $tuple, $flags); + echo "result:\n"; + echo "count = ", $result["count"], "\n"; + if ($flags & TARANTOOL_FLAGS_RETURN_TUPLE) { + echo "tuple:", "\n"; + echo " id = ", $result["tuple"][0], "\n"; + echo " series = ", $result["tuple"][1], "\n"; + echo " year = ", $result["tuple"][2], "\n"; + echo " name = ", $result["tuple"][3], "\n"; + echo " crawl = ", $result["tuple"][4], "\n"; + } + } catch (Exception $e) { + echo "catched exception: ", $e->getMessage(), "\n"; + } +} + +function test_update_fields($tarantool, $space_no, $tuple, $ops, $flags) { + try { + $result = $tarantool->update_fields($space_no, $tuple, $ops, $flags); + echo "result:\n"; + echo "count = ", $result["count"], "\n"; + if ($flags & TARANTOOL_FLAGS_RETURN_TUPLE) { + echo "tuple:", "\n"; + echo " id = ", $result["tuple"][0], "\n"; + echo " series = ", $result["tuple"][1], "\n"; + echo " year = ", $result["tuple"][2], "\n"; + echo " name = ", $result["tuple"][3], "\n"; + echo " crawl = ", $result["tuple"][4], "\n"; + } + } catch (Exception $e) { + echo "catched exception: ", $e->getMessage(), "\n"; + } +} + +function test_delete($tarantool, $space_no, $tuple, $flags) { + try { + $result = $tarantool->delete($space_no, $tuple, $flags); + echo "result:\n"; + echo "count = ", $result["count"], "\n"; + if ($flags & TARANTOOL_FLAGS_RETURN_TUPLE) { + echo "tuple:", "\n"; + echo " id = ", $result["tuple"][0], "\n"; + echo " series = ", $result["tuple"][1], "\n"; + echo " year = ", $result["tuple"][2], "\n"; + echo " name = ", $result["tuple"][3], "...\n"; + echo " crawl = ", $result["tuple"][4], "\n"; + } + } catch (Exception $e) { + echo "catched exception: ", $e->getMessage(), "\n"; + } +} + +function test_call($tarantool, $proc, $tuple, $flags) { + try { + $result = $tarantool->call($proc, $tuple, $flags); + echo "result:\n"; + echo "count = ", $result["count"], "\n"; + $tuples_list = $result["tuples_list"]; + sort($tuples_list); + for ($i = 0; $i < $result["count"]; $i++) { + echo "tuple[", $i, "]:", "\n"; + echo " id = ", $tuples_list[$i][0], "\n"; + echo " series = ", $tuples_list[$i][1], "\n"; + echo " year = ", $tuples_list[$i][2], "\n"; + echo " name = ", $tuples_list[$i][3], "...\n"; + echo " crawl = ", $tuples_list[$i][4], "\n"; + } + } catch (Exception $e) { + echo "catched exception: ", $e->getMessage(), "\n"; + } +} + +?> diff --git a/connector/php/test/run-test b/connector/php/test/run-test new file mode 120000 index 0000000000..1993bbd700 --- /dev/null +++ b/connector/php/test/run-test @@ -0,0 +1 @@ +bin/run-test.bash \ No newline at end of file diff --git a/connector/php/test/select.phpt b/connector/php/test/select.phpt new file mode 100644 index 0000000000..c9a7b1d96c --- /dev/null +++ b/connector/php/test/select.phpt @@ -0,0 +1,346 @@ +--TEST-- +Tarantool/box select commands test +--FILE-- +<?php +include "lib/php/tarantool_utest.php"; + +$tarantool = new Tarantool("localhost", 33013, 33015); +test_init($tarantool, 0); + +echo "---------- test begin ----------\n"; +echo "test select: key is integer\n"; +test_select($tarantool, 0, 0, 0); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test select: key is string \n"; +test_select($tarantool, 0, 1, "Star Wars"); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test select: key is object (expected error exception)\n"; +test_select($tarantool, 0, 0, $tarantool); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test select: key is array\n"; +test_select($tarantool, 0, 1, array("Star Wars")); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test select: key is empty array (expected error exception)\n"; +test_select($tarantool, 0, 0, array()); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test select: key is array of objects (expected error exception)\n"; +test_select($tarantool, 0, 0, array($tarantool, 1, 2)); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test select: multi keys select\n"; +test_select($tarantool, 0, 0, array(array(0), array(1), array(2))); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test select: key is array of array of objects (expected error exception)\n"; +test_select($tarantool, 0, 0, array(array(1, $tarantool))); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test select: key is array of diffirent elements (expected error exception)\n"; +test_select($tarantool, 0, 0, array(array(1, 2), 2)); +echo "----------- test end -----------\n\n"; + +test_clean($tarantool, 0); +?> +===DONE=== +--EXPECT-- +---------- test begin ---------- +test select: key is integer +result: +count = 1 +tuple[0]: + id = 0 + series = Star Wars + year = 1977 + name = A New Hope + crawl = A long time ago, in a galaxy far, far away... +It is a period of civil war. Rebel +spaceships, striking from a hidden +base, have won their first victory +against the evil Galactic Empire. + +During the battle, Rebel spies managed +to steal secret plans to the Empire's +ultimate weapon, the Death Star, an +armored space station with enough +power to destroy an entire planet. + +Pursued by the Empire's sinister agents, +Princess Leia races home aboard her +starship, custodian of the stolen plans +that can save her people and restore +freedom to the galaxy.... +----------- test end ----------- + +---------- test begin ---------- +test select: key is string +result: +count = 3 +tuple[0]: + id = 0 + series = Star Wars + year = 1977 + name = A New Hope + crawl = A long time ago, in a galaxy far, far away... +It is a period of civil war. Rebel +spaceships, striking from a hidden +base, have won their first victory +against the evil Galactic Empire. + +During the battle, Rebel spies managed +to steal secret plans to the Empire's +ultimate weapon, the Death Star, an +armored space station with enough +power to destroy an entire planet. + +Pursued by the Empire's sinister agents, +Princess Leia races home aboard her +starship, custodian of the stolen plans +that can save her people and restore +freedom to the galaxy.... +tuple[1]: + id = 1 + series = Star Wars + year = 1980 + name = The Empire Strikes Back + crawl = It is a dark time for the +Rebellion. Although the Death +Star has been destroyed. +Imperial troops have driven the +Rebel forces from their hidden +base and pursued them across +the galaxy. + +Evading the dreaded Imperial +Starfleet, a group of freedom +fighters led by Luke Skywalker +have established a new secret base +on the remote ice world +of Hoth. + +The evil lord Darth Vader, +obsessed with finding young +Skywalker, has dispatched +thousands of remote probes +into the far reaches of space.... +tuple[2]: + id = 2 + series = Star Wars + year = 1983 + name = Return of the Jedi + crawl = Luke Skywalker has returned +to his home planet of +Tatooine in an attempt +to rescue his friend +Han Solo from the +clutches of the vile +gangster Jabba the Hutt. + +Little does Luke know +that the GALACTIC EMPIRE +has secretly begun construction +on a new armored space station +even more powerful than the +first dreaded Death Star. + +When completed, this ultimate +weapon will spell certain +doom for the small band of +rebels struggling to restore +freedom to the galaxy... +----------- test end ----------- + +---------- test begin ---------- +test select: key is object (expected error exception) +catched exception: unsupported tuple type +----------- test end ----------- + +---------- test begin ---------- +test select: key is array +result: +count = 3 +tuple[0]: + id = 0 + series = Star Wars + year = 1977 + name = A New Hope + crawl = A long time ago, in a galaxy far, far away... +It is a period of civil war. Rebel +spaceships, striking from a hidden +base, have won their first victory +against the evil Galactic Empire. + +During the battle, Rebel spies managed +to steal secret plans to the Empire's +ultimate weapon, the Death Star, an +armored space station with enough +power to destroy an entire planet. + +Pursued by the Empire's sinister agents, +Princess Leia races home aboard her +starship, custodian of the stolen plans +that can save her people and restore +freedom to the galaxy.... +tuple[1]: + id = 1 + series = Star Wars + year = 1980 + name = The Empire Strikes Back + crawl = It is a dark time for the +Rebellion. Although the Death +Star has been destroyed. +Imperial troops have driven the +Rebel forces from their hidden +base and pursued them across +the galaxy. + +Evading the dreaded Imperial +Starfleet, a group of freedom +fighters led by Luke Skywalker +have established a new secret base +on the remote ice world +of Hoth. + +The evil lord Darth Vader, +obsessed with finding young +Skywalker, has dispatched +thousands of remote probes +into the far reaches of space.... +tuple[2]: + id = 2 + series = Star Wars + year = 1983 + name = Return of the Jedi + crawl = Luke Skywalker has returned +to his home planet of +Tatooine in an attempt +to rescue his friend +Han Solo from the +clutches of the vile +gangster Jabba the Hutt. + +Little does Luke know +that the GALACTIC EMPIRE +has secretly begun construction +on a new armored space station +even more powerful than the +first dreaded Death Star. + +When completed, this ultimate +weapon will spell certain +doom for the small band of +rebels struggling to restore +freedom to the galaxy... +----------- test end ----------- + +---------- test begin ---------- +test select: key is empty array (expected error exception) +catched exception: invalid tuples list: empty array +----------- test end ----------- + +---------- test begin ---------- +test select: key is array of objects (expected error exception) +catched exception: unsupported tuple type +----------- test end ----------- + +---------- test begin ---------- +test select: multi keys select +result: +count = 3 +tuple[0]: + id = 0 + series = Star Wars + year = 1977 + name = A New Hope + crawl = A long time ago, in a galaxy far, far away... +It is a period of civil war. Rebel +spaceships, striking from a hidden +base, have won their first victory +against the evil Galactic Empire. + +During the battle, Rebel spies managed +to steal secret plans to the Empire's +ultimate weapon, the Death Star, an +armored space station with enough +power to destroy an entire planet. + +Pursued by the Empire's sinister agents, +Princess Leia races home aboard her +starship, custodian of the stolen plans +that can save her people and restore +freedom to the galaxy.... +tuple[1]: + id = 1 + series = Star Wars + year = 1980 + name = The Empire Strikes Back + crawl = It is a dark time for the +Rebellion. Although the Death +Star has been destroyed. +Imperial troops have driven the +Rebel forces from their hidden +base and pursued them across +the galaxy. + +Evading the dreaded Imperial +Starfleet, a group of freedom +fighters led by Luke Skywalker +have established a new secret base +on the remote ice world +of Hoth. + +The evil lord Darth Vader, +obsessed with finding young +Skywalker, has dispatched +thousands of remote probes +into the far reaches of space.... +tuple[2]: + id = 2 + series = Star Wars + year = 1983 + name = Return of the Jedi + crawl = Luke Skywalker has returned +to his home planet of +Tatooine in an attempt +to rescue his friend +Han Solo from the +clutches of the vile +gangster Jabba the Hutt. + +Little does Luke know +that the GALACTIC EMPIRE +has secretly begun construction +on a new armored space station +even more powerful than the +first dreaded Death Star. + +When completed, this ultimate +weapon will spell certain +doom for the small band of +rebels struggling to restore +freedom to the galaxy... +----------- test end ----------- + +---------- test begin ---------- +test select: key is array of array of objects (expected error exception) +catched exception: unsupported field type +----------- test end ----------- + +---------- test begin ---------- +test select: key is array of diffirent elements (expected error exception) +catched exception: invalid tuples list: expected array of array +----------- test end ----------- + +===DONE=== \ No newline at end of file diff --git a/connector/php/test/update_fields.phpt b/connector/php/test/update_fields.phpt new file mode 100644 index 0000000000..a1a811efcd --- /dev/null +++ b/connector/php/test/update_fields.phpt @@ -0,0 +1,96 @@ +--TEST-- +Tarantool/box update fields commands test +--FILE-- +<?php +include "lib/php/tarantool_utest.php"; + +$tarantool = new Tarantool("localhost", 33013, 33015); +test_init($tarantool, 0); + +echo "---------- test begin ----------\n"; +echo "test update fields: do update w/o operations (expected error exception)\n"; +test_update_fields($tarantool, 0, 0, array(), TARANTOOL_FLAGS_RETURN_TUPLE); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test update fields: invalid operation list (expected error exception)\n"; +test_update_fields($tarantool, 0, 0, array($tarantool), TARANTOOL_FLAGS_RETURN_TUPLE); +echo "----------- test end -----------\n\n"; + +echo "---------- test begin ----------\n"; +echo "test update fields: do update arith operation\n"; +test_update_fields($tarantool, 0, 0, + array( + array( + "field" => 2, + "op" => TARANTOOL_OP_ADD, + "arg" => 30, + ), + array( + "field" => 0, + "op" => TARANTOOL_OP_ASSIGN, + "arg" => 5, + ), + array( + "field" => 1, + "op" => TARANTOOL_OP_ASSIGN, + "arg" => "", + ), + array( + "field" => 3, + "op" => TARANTOOL_OP_ASSIGN, + "arg" => "return", + ), + array( + "field" => 4, + "op" => TARANTOOL_OP_SPLICE, + "offset" => 1, + "length" => 64, + "list" => " <<splice string>> ", + ), + ), TARANTOOL_FLAGS_RETURN_TUPLE); +echo "----------- test end -----------\n\n"; + + +test_clean($tarantool, 0); +?> +--EXPECT-- +---------- test begin ---------- +test update fields: do update w/o operations (expected error exception) +ops count = 0 +catched exception: update fields failed: 514 +----------- test end ----------- + +---------- test begin ---------- +test update fields: invalid operation list (expected error exception) +ops count = 1 +catched exception: invalid operations list +----------- test end ----------- + +---------- test begin ---------- +test update fields: do update arith operation +ops count = 5 +result: +count = 1 +tuple: + id = 5 + series = + year = 2007 + name = return + crawl = A <<splice string>> ivil war. Rebel +spaceships, striking from a hidden +base, have won their first victory +against the evil Galactic Empire. + +During the battle, Rebel spies managed +to steal secret plans to the Empire's +ultimate weapon, the Death Star, an +armored space station with enough +power to destroy an entire planet. + +Pursued by the Empire's sinister agents, +Princess Leia races home aboard her +starship, custodian of the stolen plans +that can save her people and restore +freedom to the galaxy.... +----------- test end ----------- \ No newline at end of file -- GitLab