diff --git a/ChangeLog b/ChangeLog index c5023e8..31eb92f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +ngx_php7 0.0.16 changes: 01 Feb 2019 + * Add php impl ngx_header_set, ngx_header_get and ngx_header_gets. + + * Fixed when php script was error, response return 500 code. + + * Fixed core dump at php error handler. + + * Fixed nginx request keepalive to close by the right way. + ngx_php7 0.0.15 changes: 12 Jan 2019 * Fixed compiled pass on freebas 11.2 and used of clang compiler. diff --git a/config b/config index 7df843a..1ed8b29 100644 --- a/config +++ b/config @@ -10,15 +10,16 @@ NGX_PHP_SRCS="$ngx_addon_dir/src/ngx_http_php_module.c \ $ngx_addon_dir/src/ngx_http_php_socket.c \ $ngx_addon_dir/src/ngx_http_php_util.c \ $ngx_addon_dir/src/ngx_http_php_variable.c \ + $ngx_addon_dir/src/ngx_http_php_header.c \ $ngx_addon_dir/src/ngx_php_debug.c \ $ngx_addon_dir/src/php/impl/php_ngx.c \ - $ngx_addon_dir/src/php/impl/php_ngx_track.c \ $ngx_addon_dir/src/php/impl/php_ngx_core.c \ $ngx_addon_dir/src/php/impl/php_ngx_log.c \ $ngx_addon_dir/src/php/impl/php_ngx_request.c \ $ngx_addon_dir/src/php/impl/php_ngx_socket.c \ $ngx_addon_dir/src/php/impl/php_ngx_var.c \ $ngx_addon_dir/src/php/impl/php_ngx_sockets.c \ + $ngx_addon_dir/src/php/impl/php_ngx_header.c \ " NGX_PHP_DEPS="$ngx_addon_dir/src/ngx_http_php_module.h \ $ngx_addon_dir/src/ngx_http_php_core.h \ @@ -30,15 +31,16 @@ NGX_PHP_DEPS="$ngx_addon_dir/src/ngx_http_php_module.h \ $ngx_addon_dir/src/ngx_http_php_socket.h \ $ngx_addon_dir/src/ngx_http_php_util.h \ $ngx_addon_dir/src/ngx_http_php_variable.h \ + $ngx_addon_dir/src/ngx_http_php_header.h \ $ngx_addon_dir/src/ngx_php_debug.h \ $ngx_addon_dir/src/php/impl/php_ngx.h \ - $ngx_addon_dir/src/php/impl/php_ngx_track.h \ $ngx_addon_dir/src/php/impl/php_ngx_core.h \ $ngx_addon_dir/src/php/impl/php_ngx_log.h \ $ngx_addon_dir/src/php/impl/php_ngx_request.h \ $ngx_addon_dir/src/php/impl/php_ngx_socket.h \ $ngx_addon_dir/src/php/impl/php_ngx_var.h \ $ngx_addon_dir/src/php/impl/php_ngx_sockets.h \ + $ngx_addon_dir/src/php/impl/php_ngx_header.h \ " if [ -z "$PHP_CONFIG" ]; then diff --git a/src/ngx_http_php_core.c b/src/ngx_http_php_core.c index f92ba84..baf0a38 100644 --- a/src/ngx_http_php_core.c +++ b/src/ngx_http_php_core.c @@ -227,7 +227,7 @@ ngx_php_error_cb(int type, error_type_str = "Unknown error"; break; } - buffer_len = spprintf(&buffer, 0, "\n%s: %s in %s on line %d\n", error_type_str, buffer, error_filename, error_lineno); + buffer_len = spprintf(&buffer, 0, "%s: %s in %s on line %d", error_type_str, buffer, error_filename, error_lineno); ngx_buf_t *b; ngx_http_php_rputs_chain_list_t *chain; @@ -239,6 +239,18 @@ ngx_php_error_cb(int type, r = ngx_php_request; ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); + if ( ctx == NULL ) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s", buffer); + + ngx_php_debug("ngx_php error handler, ctx is nil."); + + efree(buffer); + zend_bailout(); + + ngx_http_php_zend_uthread_exit(r); + return ; + } + ns.data = (u_char *)buffer; ns.len = buffer_len; @@ -270,12 +282,18 @@ ngx_php_error_cb(int type, r->headers_out.content_length_n += ns.len; } - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, " %s: %s in %s on line %d \n", error_type_str, buffer, error_filename, error_lineno); + if (!r->headers_out.status) { + r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR; + } - ngx_http_php_zend_uthread_exit(r); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s", buffer); + + ngx_php_debug("ngx_php error handler."); efree(buffer); zend_bailout(); + + ngx_http_php_zend_uthread_exit(r); return ; } diff --git a/src/ngx_http_php_core.h b/src/ngx_http_php_core.h index 0933231..99e4f05 100644 --- a/src/ngx_http_php_core.h +++ b/src/ngx_http_php_core.h @@ -32,6 +32,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include "php/impl/php_ngx.h" +#include "php/impl/php_ngx_sockets.h" #include "ngx_http_php_socket.h" @@ -123,6 +124,7 @@ typedef struct ngx_http_php_ctx_s { ngx_int_t delay_time; ngx_event_t sleep; + php_ngx_socket_t *php_socket; ngx_http_php_socket_upstream_t *upstream; ngx_str_t host; in_port_t port; diff --git a/src/ngx_http_php_handler.c b/src/ngx_http_php_handler.c index 06d54b3..2a9dbd1 100644 --- a/src/ngx_http_php_handler.c +++ b/src/ngx_http_php_handler.c @@ -303,9 +303,17 @@ ngx_http_php_rewrite_inline_handler(ngx_http_request_t *r) set_output: rc = ngx_php_get_request_status(); + /*if ( r->keepalive == 0 ) { + return NGX_OK; + }*/ + ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); - if ( ctx->generator_closure ) { + if ( ctx == NULL ) { + return NGX_ERROR; + } + + if ( ctx && ctx->generator_closure ) { zval_ptr_dtor(ctx->generator_closure); } @@ -578,9 +586,17 @@ ngx_http_php_access_inline_handler(ngx_http_request_t *r) set_output: rc = ngx_php_get_request_status(); + /*if ( r->keepalive == 0 ) { + return NGX_OK; + }*/ + ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); - if (ctx->generator_closure) { + if ( ctx == NULL ) { + return NGX_ERROR; + } + + if ( ctx && ctx->generator_closure ) { zval_ptr_dtor(ctx->generator_closure); } @@ -927,6 +943,9 @@ ngx_http_php_content_inline_handler(ngx_http_request_t *r) return rc; } + ngx_php_debug("ctx->phase_status: %d", (int)ctx->phase_status); + ngx_php_debug("r->keepalive: %d", r->keepalive); + if (ctx->phase_status == NGX_DECLINED) { //ngx_http_php_content_inline_uthread_routine(r); @@ -961,9 +980,20 @@ ngx_http_php_content_inline_handler(ngx_http_request_t *r) set_output: rc = ngx_php_get_request_status(); + /*if ( r->keepalive == 0 ) { + return NGX_OK; + }*/ + ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); - if (ctx->generator_closure) { + ngx_php_debug("r: %p, ctx: %p", r, ctx); + + if ( ctx == NULL ) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_php ctx is nil at content inline handler."); + return NGX_ERROR; + } + + if ( ctx && ctx->generator_closure ) { zval_ptr_dtor(ctx->generator_closure); } @@ -1024,7 +1054,7 @@ ngx_http_php_content_inline_handler(ngx_http_request_t *r) ngx_http_output_filter(r, chain->out); - //ngx_http_set_ctx(r, NULL, ngx_http_php_module); + ngx_http_set_ctx(r, NULL, ngx_http_php_module); return NGX_OK; diff --git a/src/ngx_http_php_header.c b/src/ngx_http_php_header.c new file mode 100644 index 0000000..2d40ba3 --- /dev/null +++ b/src/ngx_http_php_header.c @@ -0,0 +1,98 @@ +/* +============================================================================== +Copyright (c) 2016-2019, rryqszq4 +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +============================================================================== +*/ + +#include "ngx_http_php_header.h" + +ngx_str_t * +ngx_http_php_output_header_get(ngx_http_request_t *r, const u_char *key_data, size_t key_len) +{ + ngx_str_t *value; + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_uint_t i; + + value = NULL; + + if (ngx_strncasecmp((u_char *)key_data, (u_char *)"content-type", 12) == 0){ + value = &r->headers_out.content_type; + }else { + part = &r->headers_out.headers.part; + header = part->elts; + + for ( i = 0; /* void */; i++) { + if ( i >= part->nelts ) { + if ( part->next == NULL ) { + break; + } + part = part->next; + header = part->elts; + i = 0; + } + + if ( ngx_strncasecmp((u_char *)key_data, header[i].key.data, header[i].key.len) == 0 ) { + value = &header[i].value; + break; + } + } + } + + return value; +} + +ngx_int_t +ngx_http_php_output_header_set(ngx_http_request_t *r, + const u_char *key_data, size_t key_len, + const u_char *value_data, size_t value_len) +{ + ngx_table_elt_t *h; + + if ( ngx_strncasecmp((u_char *)key_data, (u_char *)"content-type", 12) == 0 ){ + r->headers_out.content_type.data = (u_char *)value_data; + r->headers_out.content_type.len = value_len; + r->headers_out.content_type_len = value_len; + }else if ( ngx_strncasecmp((u_char *)key_data, (u_char *)"content-length", 14) == 0 ) { + r->headers_out.content_length_n = value_len; + }else { + h = ngx_list_push(&r->headers_out.headers); + + if ( h == NULL ) { + return 0; + } + + h->hash = 1; + h->key.len = key_len; + h->key.data = (u_char *)key_data; + h->value.len = value_len; + h->value.data = (u_char *)value_data; + } + + return 1; +} + + + diff --git a/src/ngx_http_php_header.h b/src/ngx_http_php_header.h new file mode 100644 index 0000000..4db3a4a --- /dev/null +++ b/src/ngx_http_php_header.h @@ -0,0 +1,38 @@ +/* +============================================================================== +Copyright (c) 2016-2019, rryqszq4 +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +============================================================================== +*/ + +#ifndef __NGX_HTTP_PHP_HEADER_H_ +#define __NGX_HTTP_PHP_HEADER_H_ + +#include "ngx_http_php_module.h" + +ngx_str_t *ngx_http_php_output_header_get(ngx_http_request_t *r, const u_char *key_data, size_t key_len); + +ngx_int_t ngx_http_php_output_header_set(ngx_http_request_t *r, const u_char *key_data, size_t key_len, const u_char *value_data, size_t value_len); + +#endif \ No newline at end of file diff --git a/src/ngx_http_php_module.c b/src/ngx_http_php_module.c index ce051d3..8bdd1f9 100644 --- a/src/ngx_http_php_module.c +++ b/src/ngx_http_php_module.c @@ -33,6 +33,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "php/impl/php_ngx_socket.h" #include "php/impl/php_ngx_var.h" #include "php/impl/php_ngx_sockets.h" +#include "php/impl/php_ngx_header.h" #include #include @@ -534,16 +535,16 @@ ngx_http_php_init_worker(ngx_cycle_t *cycle) old_zend_error_cb = zend_error_cb; zend_error_cb = ngx_php_error_cb; - ori_compile_file = zend_compile_file; - zend_compile_file = ngx_compile_file; + //ori_compile_file = zend_compile_file; + //zend_compile_file = ngx_compile_file; - ori_compile_string = zend_compile_string; - zend_compile_string = ngx_compile_string; + //ori_compile_string = zend_compile_string; + //zend_compile_string = ngx_compile_string; - ori_execute_ex = zend_execute_ex; - zend_execute_ex = ngx_execute_ex; + //ori_execute_ex = zend_execute_ex; + //zend_execute_ex = ngx_execute_ex; - zend_execute_internal = ngx_execute_internal; + //zend_execute_internal = ngx_execute_internal; php_impl_ngx_core_init(0 TSRMLS_CC); php_impl_ngx_log_init(0 TSRMLS_CC); @@ -551,6 +552,7 @@ ngx_http_php_init_worker(ngx_cycle_t *cycle) php_impl_ngx_socket_init(0 TSRMLS_CC); php_impl_ngx_var_init(0 TSRMLS_CC); php_impl_ngx_sockets_init(0 TSRMLS_CC); + php_impl_ngx_header_init(0 TSRMLS_CC); return NGX_OK; } diff --git a/src/ngx_http_php_module.h b/src/ngx_http_php_module.h index ade5aef..f5331ff 100644 --- a/src/ngx_http_php_module.h +++ b/src/ngx_http_php_module.h @@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define NGX_HTTP_PHP_MODULE_NAME "ngx_php" -#define NGX_HTTP_PHP_MODULE_VERSION "0.0.15" +#define NGX_HTTP_PHP_MODULE_VERSION "0.0.16" extern ngx_module_t ngx_http_php_module; ngx_http_request_t *ngx_php_request; diff --git a/src/ngx_http_php_sleep.c b/src/ngx_http_php_sleep.c index 66bce49..d28dc30 100644 --- a/src/ngx_http_php_sleep.c +++ b/src/ngx_http_php_sleep.c @@ -83,7 +83,7 @@ ngx_http_php_sleep(ngx_http_request_t *r) cln->handler = ngx_http_php_sleep_cleanup; cln->data = r; - r->keepalive = 0; + //r->keepalive = 0; return NGX_OK; } diff --git a/src/ngx_http_php_socket.c b/src/ngx_http_php_socket.c index 05ccd38..16c3221 100644 --- a/src/ngx_http_php_socket.c +++ b/src/ngx_http_php_socket.c @@ -246,7 +246,7 @@ ngx_http_php_socket_resolve_retval_handler(ngx_http_request_t *r, /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */ - ctx->phase_status = NGX_AGAIN; + //ctx->phase_status = NGX_AGAIN; c = peer->connection; c->data = u; @@ -282,6 +282,8 @@ ngx_http_php_socket_resolve_retval_handler(ngx_http_request_t *r, "php socket connected: fd:%d", (int) c->fd); ngx_php_debug("php socket connected: fd:%d", (int) c->fd); + ctx->phase_status = NGX_OK; + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { return NGX_ERROR; @@ -300,6 +302,8 @@ ngx_http_php_socket_resolve_retval_handler(ngx_http_request_t *r, // rc == NGX_AGAIN + ctx->phase_status = NGX_AGAIN; + ngx_add_timer(c->write, 5 * 1000); return NGX_AGAIN; @@ -310,15 +314,12 @@ ngx_http_php_socket_finalize(ngx_http_request_t *r, ngx_http_php_socket_upstream_t *u) { ngx_connection_t *c; - ngx_http_php_ctx_t *ctx; ngx_php_debug("request: %p, u: %p, u->cleanup: %p", r, u, u->cleanup); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "php finalize socket"); - ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); - if (u->cleanup) { *u->cleanup = NULL; u->cleanup = NULL; @@ -350,10 +351,6 @@ ngx_http_php_socket_finalize(ngx_http_request_t *r, ngx_php_debug("socket end"); - ctx->delay_time = 1; - - ngx_http_php_sleep(r); - } static void @@ -640,7 +637,7 @@ ngx_http_php_socket_connect(ngx_http_request_t *r) ngx_del_timer(c->read); } - r->keepalive = 0; + //r->keepalive = 0; u = ctx->upstream; @@ -762,6 +759,10 @@ ngx_http_php_socket_close(ngx_http_request_t *r) ngx_http_php_socket_finalize(r, u); + ctx->delay_time = 1; + + ngx_http_php_sleep(r); + return ; } @@ -870,6 +871,36 @@ ngx_http_php_socket_recv(ngx_http_request_t *r) return NGX_OK; } +void +ngx_http_php_socket_clear(ngx_http_request_t *r) +{ + ngx_http_php_socket_upstream_t *u; + ngx_http_php_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); + + u = ctx->upstream; + + if (u == NULL || + u->peer.connection == NULL ) + { + return ; + } + + u->enabled_receive = 0; + + if (u->request != r) { + + } + + ngx_php_debug("u->peer.connected: %p, r->connection: %p", u->peer.connection, r->connection); + + ngx_http_php_socket_finalize(r, u); + + return ; +} + + diff --git a/src/ngx_http_php_socket.h b/src/ngx_http_php_socket.h index 1a1cf3a..ab2d5c2 100644 --- a/src/ngx_http_php_socket.h +++ b/src/ngx_http_php_socket.h @@ -86,6 +86,6 @@ void ngx_http_php_socket_close(ngx_http_request_t *r); ngx_int_t ngx_http_php_socket_send(ngx_http_request_t *r); ngx_int_t ngx_http_php_socket_recv(ngx_http_request_t *r); - +void ngx_http_php_socket_clear(ngx_http_request_t *r); #endif \ No newline at end of file diff --git a/src/ngx_http_php_zend_uthread.c b/src/ngx_http_php_zend_uthread.c index 61eb0f8..0608c52 100644 --- a/src/ngx_http_php_zend_uthread.c +++ b/src/ngx_http_php_zend_uthread.c @@ -468,6 +468,7 @@ ngx_http_php_zend_uthread_create(ngx_http_request_t *r, char *func_prefix) }else { ngx_php_debug("r:%p, closure:%p, retval:%d", r, ctx->generator_closure, Z_TYPE(retval)); efree(ctx->generator_closure); + ctx->generator_closure = NULL; } } @@ -479,7 +480,8 @@ ngx_http_php_zend_uthread_resume(ngx_http_request_t *r) ngx_http_php_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); if (ctx == NULL) { - + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_php ctx is nil at zend_uthread_resume."); + return ; } ngx_php_debug("ctx: %p", ctx); @@ -491,6 +493,13 @@ ngx_http_php_zend_uthread_resume(ngx_http_request_t *r) zval retval; closure = ctx->generator_closure; + ngx_php_debug("closure: %p", closure); + if (!closure) { + if (ctx->upstream) { + ngx_http_php_socket_clear(r); + } + return ; + } if (ctx->upstream && ctx->upstream->enabled_receive == 1) { ngx_php_debug("buf write in php var."); @@ -511,9 +520,14 @@ ngx_http_php_zend_uthread_resume(ngx_http_request_t *r) ctx->phase_status = NGX_AGAIN; }else { ctx->phase_status = NGX_OK; + + //zval_ptr_dtor(ctx->recv_buf); + if ( ctx->generator_closure ) { + efree(ctx->generator_closure); + ctx->generator_closure = NULL; + } + ngx_http_core_run_phases(r); - efree(ctx->generator_closure); - ctx->generator_closure = NULL; } }zend_catch { @@ -530,18 +544,15 @@ ngx_http_php_zend_uthread_exit(ngx_http_request_t *r) ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); - if (ctx == NULL) { - - } - - if (ctx->generator_closure) { + if ( ctx && ctx->generator_closure ) { //ngx_http_php_zend_uthread_resume(r); ctx->phase_status = NGX_OK; - ngx_http_core_run_phases(r); efree(ctx->generator_closure); ctx->generator_closure = NULL; } + ngx_http_core_run_phases(r); + } diff --git a/src/php/impl/php_ngx.c b/src/php/impl/php_ngx.c index e9b25ff..ca7b04c 100644 --- a/src/php/impl/php_ngx.c +++ b/src/php/impl/php_ngx.c @@ -35,6 +35,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "php_ngx_request.h" #include "php_ngx_sockets.h" #include "php_ngx_var.h" +#include "php_ngx_header.h" #include "../../ngx_http_php_module.h" @@ -358,6 +359,10 @@ static const zend_function_entry additional_functions[] = { PHP_FE(ngx_var_get, ngx_var_get_arginfo) PHP_FE(ngx_var_set, ngx_var_set_arginfo) + PHP_FE(ngx_header_set, ngx_header_set_arginfo) + PHP_FE(ngx_header_get, ngx_header_get_arginfo) + PHP_FE(ngx_header_gets, ngx_header_gets_arginfo) + {NULL, NULL, NULL, 0, 0} }; diff --git a/src/php/impl/php_ngx.h b/src/php/impl/php_ngx.h index fd60b27..d660506 100644 --- a/src/php/impl/php_ngx.h +++ b/src/php/impl/php_ngx.h @@ -41,7 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include "php_ngx_track.h" +//#include "php_ngx_track.h" extern ngx_http_request_t * ngx_php_request; diff --git a/src/php/impl/php_ngx_header.c b/src/php/impl/php_ngx_header.c new file mode 100644 index 0000000..21b60ca --- /dev/null +++ b/src/php/impl/php_ngx_header.c @@ -0,0 +1,149 @@ +/* +============================================================================== +Copyright (c) 2016-2019, rryqszq4 +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +============================================================================== +*/ + +#include "php_ngx_header.h" +#include "../../ngx_http_php_module.h" + +PHP_FUNCTION(ngx_header_set) +{ + ngx_http_request_t *r; + ngx_table_elt_t *h; + zend_string *key_str; + zval *value; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Sz", &key_str, &value) == FAILURE) { + RETURN_NULL(); + } + + r = ngx_php_request; + + if (ngx_strncasecmp((u_char *)ZSTR_VAL(key_str), (u_char *)"content-type", 12) == 0){ + r->headers_out.content_type.data = (u_char *)Z_STRVAL_P(value); + r->headers_out.content_type.len = Z_STRLEN_P(value); + r->headers_out.content_type_len = Z_STRLEN_P(value); + }else if ( ngx_strncasecmp((u_char *)ZSTR_VAL(key_str), (u_char *)"content-length", 14) == 0 ) { + r->headers_out.content_length_n = Z_LVAL_P(value); + }else { + h = ngx_list_push(&r->headers_out.headers); + + if ( h == NULL ) { + RETURN_FALSE; + } + + h->hash = 1; + h->key.len = ZSTR_LEN(key_str); + h->key.data = (u_char *)ZSTR_VAL(key_str); + h->value.len = Z_STRLEN_P(value); + h->value.data = (u_char *)Z_STRVAL_P(value); + } + + RETURN_TRUE; +} + +PHP_FUNCTION(ngx_header_get) +{ + zend_string *key_str; + ngx_http_request_t *r; + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_uint_t i; + unsigned found; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S", &key_str) == FAILURE){ + RETURN_NULL(); + } + + r = ngx_php_request; + found = 0; + + if (ngx_strncasecmp((u_char *)ZSTR_VAL(key_str), (u_char *)"content-type", 12) == 0){ + ZVAL_STRINGL(return_value, (char *)r->headers_out.content_type.data, r->headers_out.content_type.len); + found = 1; + }else { + part = &r->headers_out.headers.part; + header = part->elts; + + for ( i = 0; /* void */; i++) { + if ( i >= part->nelts ) { + if ( part->next == NULL ) { + break; + } + part = part->next; + header = part->elts; + i = 0; + } + + if ( ngx_strncasecmp((u_char *)ZSTR_VAL(key_str), header[i].key.data, header[i].key.len) == 0 ) { + ZVAL_STRINGL(return_value, (char *)header[i].value.data, header[i].value.len); + found = 1; + break; + } + } + } + + if ( !found ) { + RETURN_NULL(); + } +} + +PHP_FUNCTION(ngx_header_gets) +{ + ngx_http_request_t *r; + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_uint_t i; + + r = ngx_php_request; + part = &r->headers_out.headers.part; + header = part->elts; + + array_init(return_value); + + if ( r->headers_out.content_type.len ) { + add_assoc_stringl(return_value, "content-type", (char *)r->headers_out.content_type.data, r->headers_out.content_type.len); + } + + for ( i = 0; /* void */; i++ ) { + if ( i >= part->nelts ) { + if ( part->next == NULL ) { + break; + } + part = part->next; + header = part->elts; + i = 0; + } + + add_assoc_stringl_ex(return_value, (char *)header[i].key.data, header[i].key.len, (char *)header[i].value.data, header[i].value.len); + } +} + +void +php_impl_ngx_header_init(int module_number TSRMLS_DC) +{ + +} diff --git a/src/php/impl/php_ngx_header.h b/src/php/impl/php_ngx_header.h new file mode 100644 index 0000000..5dd8cad --- /dev/null +++ b/src/php/impl/php_ngx_header.h @@ -0,0 +1,55 @@ +/* +============================================================================== +Copyright (c) 2016-2019, rryqszq4 +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +============================================================================== +*/ + +#ifndef __PHP_NGX_HEADER_H__ +#define __PHP_NGX_HEADER_H__ + +#include +#include +#include +#include + +ZEND_BEGIN_ARG_INFO_EX(ngx_header_set_arginfo, 0, 0, 2) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ngx_header_get_arginfo, 0, 0, 1) + ZEND_ARG_INFO(0, key) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ngx_header_gets_arginfo, 0, 0, 0) +ZEND_END_ARG_INFO() + +PHP_FUNCTION(ngx_header_set); +PHP_FUNCTION(ngx_header_get); +PHP_FUNCTION(ngx_header_gets); + +void php_impl_ngx_header_init(int module_number TSRMLS_DC); + +#endif diff --git a/src/php/impl/php_ngx_sockets.c b/src/php/impl/php_ngx_sockets.c index 1c11880..9ad23ea 100644 --- a/src/php/impl/php_ngx_sockets.c +++ b/src/php/impl/php_ngx_sockets.c @@ -30,50 +30,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../../ngx_http_php_socket.h" #include "php_ngx_sockets.h" -static int le_socket; +//static int le_socket; #define le_socket_name php_ngx_sockets_le_socket_name //static int php_ngx_socket_le_socket(void); -static php_ngx_socket *php_ngx_socket_create(void); -static void php_ngx_socket_destroy(zend_resource *rsrc); +static php_ngx_socket_t *php_ngx_socket_create(void); +//static void php_ngx_socket_destroy(zend_resource *rsrc); /*static int php_ngx_socket_le_socket(void) { return le_socket; }*/ -static php_ngx_socket *php_ngx_socket_create(void) +static php_ngx_socket_t *php_ngx_socket_create(void) { - ngx_http_request_t *r; - ngx_http_php_ctx_t *ctx; - ngx_http_php_socket_upstream_t *u; - php_ngx_socket *ngx_sock; + php_ngx_socket_t *php_sock; - ngx_sock = emalloc(sizeof(php_ngx_socket)); - r = ngx_php_request; - ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); - - u = ctx->upstream; - ngx_sock->upstream = u; - ngx_sock->type = 0; - ngx_sock->error = 0; + php_sock = emalloc(sizeof(php_ngx_socket_t)); + php_sock->type = 0; + php_sock->error = 0; - return ngx_sock; + return php_sock; } -static void php_ngx_socket_destroy(zend_resource *rsrc) +/*static void php_ngx_socket_destroy(zend_resource *rsrc) { - php_ngx_socket *ngx_sock; + php_ngx_socket_t *php_sock; - ngx_sock = rsrc->ptr; + php_sock = rsrc->ptr; - efree(ngx_sock); -} + efree(php_sock); + efree(rsrc); +}*/ PHP_FUNCTION(ngx_socket_create) { zend_long arg1, arg2, arg3; - php_ngx_socket *ngx_sock; + php_ngx_socket_t *php_sock; + + ngx_http_request_t *r; + ngx_http_php_ctx_t *ctx; arg1 = AF_INET; arg2 = SOCK_STREAM; @@ -81,21 +77,26 @@ PHP_FUNCTION(ngx_socket_create) #define SOL_TCP IPPROTO_TCP #endif arg3 = SOL_TCP; - ngx_sock = php_ngx_socket_create(); + php_sock = php_ngx_socket_create(); if (zend_parse_parameters(ZEND_NUM_ARGS(), "|lll", &arg1, &arg2, &arg3) == FAILURE) { return ; } - ngx_sock->type = arg1; + php_sock->type = arg1; - RETURN_RES(zend_register_resource(ngx_sock, le_socket)); + r = ngx_php_request; + ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); + ctx->php_socket = php_sock; + ngx_http_set_ctx(r, ctx, ngx_http_php_module); + + RETURN_TRUE; } PHP_FUNCTION(ngx_socket_connect) { zval *arg1; - php_ngx_socket *ngx_sock; + //php_ngx_socket_t *php_sock; char *addr; size_t addr_len; zend_long port = 0; @@ -104,18 +105,16 @@ PHP_FUNCTION(ngx_socket_connect) ngx_http_request_t *r; ngx_http_php_ctx_t *ctx; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &arg1, &addr, &addr_len, &port) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|l", &arg1, &addr, &addr_len, &port) == FAILURE) { return ; } - if ((ngx_sock = (php_ngx_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) { - RETURN_FALSE; - } + //php_sock = Z_RES_P(arg1)->ptr; r = ngx_php_request; ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); - switch(ngx_sock->type) { + switch(ctx->php_socket->type) { case AF_INET: { ctx->host.data = ngx_palloc(r->pool, addr_len + 1); ctx->host.len = addr_len; @@ -129,7 +128,7 @@ PHP_FUNCTION(ngx_socket_connect) } default: - php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", ngx_sock->type); + php_error_docref(NULL, E_WARNING, "Unsupported socket type %d", ctx->php_socket->type); RETURN_FALSE; } @@ -144,19 +143,27 @@ PHP_FUNCTION(ngx_socket_connect) PHP_FUNCTION(ngx_socket_close) { zval *arg1; - php_ngx_socket *ngx_sock; + //php_ngx_socket_t *php_sock; ngx_http_request_t *r; + ngx_http_php_ctx_t *ctx; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &arg1) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg1) == FAILURE) { return ; } - if ((ngx_sock = (php_ngx_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) { + /*if ((ngx_sock = (php_ngx_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) { RETURN_FALSE; - } + }*/ + //php_sock = Z_RES_P(arg1)->ptr; + //efree(php_sock); + r = ngx_php_request; + ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); + + efree(ctx->php_socket); + ctx->php_socket = NULL; ngx_http_php_socket_close(r); @@ -166,7 +173,7 @@ PHP_FUNCTION(ngx_socket_close) PHP_FUNCTION(ngx_socket_send) { zval *arg1; - php_ngx_socket *ngx_sock; + //php_ngx_socket_t *php_sock; size_t buf_len, retval; zend_long len; char *buf; @@ -178,7 +185,7 @@ PHP_FUNCTION(ngx_socket_send) ngx_buf_t *b; ngx_chain_t *cl; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsl", &arg1, &buf, &buf_len, &len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zsl", &arg1, &buf, &buf_len, &len) == FAILURE) { return ; } @@ -187,9 +194,10 @@ PHP_FUNCTION(ngx_socket_send) RETURN_FALSE; } - if ((ngx_sock = (php_ngx_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) { + /*if ((ngx_sock = (php_ngx_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) { RETURN_FALSE; - } + }*/ + //php_sock = Z_RES_P(arg1)->ptr; r = ngx_php_request; ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); @@ -218,7 +226,7 @@ PHP_FUNCTION(ngx_socket_recv) { zval *arg1, *buf; //zend_string *recv_buf; - php_ngx_socket *ngx_sock; + //php_ngx_socket_t *php_sock; int retval; zend_long len = 1024; @@ -228,13 +236,14 @@ PHP_FUNCTION(ngx_socket_recv) //ngx_buf_t *b; //long size = 1024; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|l", &arg1, &buf, &len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|l", &arg1, &buf, &len) == FAILURE) { return ; } - if ((ngx_sock = (php_ngx_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) { + /*if ((ngx_sock = (php_ngx_socket *)zend_fetch_resource(Z_RES_P(arg1), le_socket_name, le_socket)) == NULL) { RETURN_FALSE; - } + }*/ + //php_sock = Z_RES_P(arg1)->ptr; r = ngx_php_request; ctx = ngx_http_get_module_ctx(r, ngx_http_php_module); @@ -244,6 +253,7 @@ PHP_FUNCTION(ngx_socket_recv) //b = &u->buffer; ctx->recv_buf = buf; + zval_ptr_dtor(ctx->recv_buf); retval = ngx_http_php_socket_recv(r); @@ -259,6 +269,6 @@ PHP_FUNCTION(ngx_socket_recv) void php_impl_ngx_sockets_init(int module_number TSRMLS_DC) { - le_socket = zend_register_list_destructors_ex(php_ngx_socket_destroy, NULL, le_socket_name, module_number); + //le_socket = zend_register_list_destructors_ex(php_ngx_socket_destroy, NULL, le_socket_name, module_number); } diff --git a/src/php/impl/php_ngx_sockets.h b/src/php/impl/php_ngx_sockets.h index d3fe832..07afd96 100644 --- a/src/php/impl/php_ngx_sockets.h +++ b/src/php/impl/php_ngx_sockets.h @@ -39,11 +39,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define php_ngx_sockets_le_socket_name "ngx_socket" typedef struct { - ngx_http_php_socket_upstream_t *upstream; + //ngx_http_php_socket_upstream_t *upstream; int type; int error; } php_ngx_socket; +typedef struct php_ngx_socket_s { + + int type; + int error; + +} php_ngx_socket_t; + ZEND_BEGIN_ARG_INFO_EX(arginfo_ngx_socket_create, 0, 0, 0) ZEND_ARG_INFO(0, domain) ZEND_ARG_INFO(0, type) diff --git a/t/003-error b/t/003-error.t similarity index 52% rename from t/003-error rename to t/003-error.t index 9d98215..61605f2 100644 --- a/t/003-error +++ b/t/003-error.t @@ -16,11 +16,5 @@ location = /error { } --- request GET /error ---- response_body -hello ngx_php -Fatal error: Uncaught Error: Class 'abc' not found in ngx_php eval code:4 -Stack trace: -#0 [internal function]: ngx_content_6a50af555ddc38eb1560f83e04f54a6c() -#1 {main} - thrown in ngx_php eval code on line 4 +--- error_code: 500 diff --git a/t/012-function.t b/t/012-function.t index 7d0c803..87f98dc 100644 --- a/t/012-function.t +++ b/t/012-function.t @@ -48,3 +48,6 @@ ngx_socket_send ngx_socket_recv ngx_var_get ngx_var_set +ngx_header_set +ngx_header_get +ngx_header_gets diff --git a/t/014-ngx_var.t b/t/014-ngx_var.t index 2312915..29ded95 100644 --- a/t/014-ngx_var.t +++ b/t/014-ngx_var.t @@ -9,7 +9,7 @@ __DATA__ ngx_var_get --- config location = /ngx_var_get { - set $a 1234567890; + set $a 1234567890; content_by_php ' $a = ngx_var::get("a"); var_dump($a); @@ -26,7 +26,7 @@ string(10) "1234567890" ngx_var_set --- config location = /ngx_var_set{ - set $a 1234567890; + set $a 1234567890; content_by_php ' ngx_var::set("a", "abc"); $a = ngx_var::get("a"); diff --git a/t/015-ngx_header.t b/t/015-ngx_header.t new file mode 100644 index 0000000..35340ed --- /dev/null +++ b/t/015-ngx_header.t @@ -0,0 +1,58 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: set content-type of response headers +--- config +location = /ngx_header { + content_by_php ' + ngx_header_set("Content-Type", "text/html; charset=UTF-8"); + echo "Testing ngx_header!\n"; + '; +} +--- request +GET /ngx_header +--- response_headers +Content-Type: text/html; charset=UTF-8 +--- response_body +Testing ngx_header! + + + +=== TEST 2: set content-length of response headers +--- config +location = /ngx_header { + content_by_php ' + $str = "Testing ngx_header!\n"; + echo $str; + echo $str; + ngx_header_set("Content-Length", strlen($str)); + '; +} +--- request +GET /ngx_header +--- response_headers +Content-Length: 20 +--- response_body +Testing ngx_header! + + + +=== TEST 3: set other part of reponse headers +--- config +location = /ngx_header { + content_by_php ' + ngx_header_set("X-Foo", "abc"); + echo "Testing ngx_header!\n"; + '; +} +--- request +GET /ngx_header +--- response_headers +X-Foo: abc +--- response_body +Testing ngx_header! diff --git a/t/lib/mysql.php b/t/lib/mysql.php index aa7df89..e05ada7 100644 --- a/t/lib/mysql.php +++ b/t/lib/mysql.php @@ -13,6 +13,12 @@ class mysql { private $packet_data = null; + private $headerNum = 0; + private $headerCurr = 0; + private $resultState = 0; + private $resultFields = array(); + private $resultRows = array(); + public function __construct() { $this->socket = ngx_socket_create(); } @@ -60,26 +66,55 @@ private function print_bin($result) { //var_dump($bytes); } + private function length_encoded_integer($data, &$start) { + $first = ord(substr($data, $start, 1)); + #var_dump($first); + if ($first <= 250) { + $start += 1; + return $first; + } + if ($first === 251) { + $start += 1; + return null; + } + if ($first === 252) { + $ret = unpack('v', substr($data, $start, 2)); + $start += 2; + return $ret[1]; + } + if ($first === 253) { + $ret = unpack('V', substr($data, $start, 3)."\0"); + $start += 3; + return $ret[1]; + } + + $ret = unpack('P', substr($data, $start, 8)); + $start += 8; + return $ret[1]; + } + private function write_packet($data, $len, $chr=1) { $pack = $this->set_byte3($len).chr($chr).$data; - var_dump("pack: ".$pack); + #var_dump("pack: ".$pack); //$pack = substr_replace(pack("V", $len), chr(1), 3, 1).$data; //var_dump(($pack == $pack1)); - $this->print_bin($pack); + #$this->print_bin($pack); yield ngx_socket_send($this->socket, $pack, strlen($pack)); } - private function read_packet($idx=0) { + /*private function read_packet_1($idx=0) { yield ngx_socket_recv($this->socket, $result, 4); $this->print_bin($result); $len = unpack('v',substr($result, $idx, 3)); var_dump($len); $len1 = $len = $len[1]; + var_dump($len1); $data = ''; yield ngx_socket_recv($this->socket, $data, $len); + $this->print_bin($data); $len = ord($data[0]); if ($len == 0x00) { var_dump("OK packet"); @@ -90,105 +125,146 @@ private function read_packet($idx=0) { var_dump("EOF packet"); }else{ var_dump("Data packet"); - if ($len1 == 1) { + if ($len1 == 1 && $this->resultState == 1) { + var_dump("fields"); yield from $this->result_set_packet(); yield from $this->result_set_packet(); yield from $this->result_set_packet(); yield from $this->result_set_packet(); + $this->resultState = 2; + }else if ($this->resultState == 2) { + var_dump("rows"); + + } } //$this->print_bin($result.$data); $this->packet_data = $data; + }*/ + + private function read_packet() { + #var_dump("read_packet"); + do { + $result = null; + yield ngx_socket_recv($this->socket, $result, 4); + } while (empty($result)); + #$this->print_bin($result); + $field_count = unpack('v', substr($result, 0, 3))[1]; + #var_dump("field_count: ".$field_count); + $data = ''; + yield ngx_socket_recv($this->socket, $data, $field_count); + #$this->print_bin($data); + if ($field_count != 1) { + $field_count = ord(substr($data, 0, 1)); + } + if ($field_count === 0x00) { + #var_dump("OK packet"); + $this->ok_packet($data); + }else if ($field_count === 0xff) { + #var_dump("Error packet"); + $this->error_packet($data); + }else if ($field_count === 0xfe) { + #var_dump("EOF packet"); + if ($this->resultState == 2) { + yield from $this->read_packet(); + } + if ($this->resultState == 201) { + $this->resultState = 0; + } + }else { + #var_dump("Data packet"); + if ($field_count == 1 && $this->resultState == 0) { + #var_dump("header set"); + $this->headerNum = ord($data); + #var_dump($this->headerNum); + $this->resultState = 1; + yield from $this->read_packet(); + }else if ($this->resultState == 1) { + #var_dump('fields'); + if ($this->headerCurr < $this->headerNum - 1) { + $this->field_data_packet($data); + $this->headerCurr++; + yield from $this->read_packet(); + }else { + $this->field_data_packet($data); + $this->headerCurr++; + $this->resultState = 2; + yield from $this->read_packet(); + } + }else if ($this->resultState == 2 || $this->resultState == 201) { + $this->resultState = 201; + #var_dump("rows"); + #var_dump($data); + $this->row_data_packet($data); + yield from $this->read_packet(); + }else { + return $data; + } + } } private function handshake_packet() { + $data = ( yield from $this->read_packet() ); - } - - private function auth_packet() { - - } - - private function result_set_packet() { - yield ngx_socket_recv($this->socket, $result, 4); - $this->print_bin($result); - $len = unpack('v',substr($result, 0, 3)); - $len = $len[1]; - yield ngx_socket_recv($this->socket, $result, $len); - $this->print_bin($result); - - } - - public function connect($host="127.0.0.1", $port=3306, $user="root", $password="123456") { - yield ngx_socket_connect($this->socket, $host, $port); - - yield from $this->read_packet(); - $data = $this->packet_data; - - var_dump("packet length: ".$len); + #var_dump("packet length: ".$len); $protocol_ver = ord(substr($data, 0, 1)); - var_dump("protocol version: ".$protocol_ver); + #var_dump("protocol version: ".$protocol_ver); - var_dump(strpos($data, "\0", 2)); + #var_dump(strpos($data, "\0", 2)); - var_dump("server version: ".substr($data, 1, strpos($data, "\0", 2)-1)); + #var_dump("server version: ".substr($data, 1, strpos($data, "\0", 2)-1)); $pos = strpos($data, "\0", 2)+1; $thread_id = unpack("V", substr($data, $pos, 4)); $thread_id = $thread_id[1]; - var_dump("thread id: ".$thread_id); + #var_dump("thread id: ".$thread_id); $pos += 4; - var_dump($pos); + #var_dump($pos); $scramble = substr($data, $pos, 8); - var_dump($scramble); - - #$pos = 1+$protocol_ver+4 + 9; + #var_dump($scramble); $capabilities = unpack('v', substr($data, $pos+9, 2)); $capabilities = $capabilities[1]; - var_dump("server capabilities: ".$capabilities); + #var_dump("server capabilities: ".$capabilities); $server_lang = ord(substr($data, $pos+9+2,1)); - var_dump("server lang: ".$server_lang); + #var_dump("server lang: ".$server_lang); $server_status = unpack('v', substr($data, $pos+9+2+1, 2)); $server_status = $server_status[1]; - var_dump("server status: ".$server_status); + #var_dump("server status: ".$server_status); $more_capabilites = unpack('v', substr($data, $pos+9+2+1+2,2)); $more_capabilites = $more_capabilites[1]; - var_dump("more capabilities: ".$more_capabilites); + #var_dump("more capabilities: ".$more_capabilites); $capabilities = $capabilities | ($more_capabilites << 16); - var_dump("server capabilities: ".$capabilities); + #var_dump("server capabilities: ".$capabilities); $scramble_2 = substr($data, $pos+9+2+1+2+2+1+10, 21-8-1); - var_dump($scramble_2); + #var_dump($scramble_2); $scramble = $scramble.$scramble_2; - var_dump("scramble: ".$scramble); - var_dump(strlen($scramble)); - - #$data = substr($data, $pos); - - #$data = substr($data, 1, $protocol_ver+1); + #var_dump("scramble: ".$scramble); + #var_dump(strlen($scramble)); + return $scramble; + } - //$this->print_bin($result.$data); - - #client + private function auth_packet($scramble, $user, $password, $database) { + // client $client_flags = 0x3f7cf; - $database = "sakila"; - $user = "root"; - $password = "123456"; + //$database = "sakila"; + //$user = "root"; + //$password = "123456"; $stage1 = sha1($password,1); $stage2 = sha1($stage1,1); $stage3 = sha1($scramble.$stage2,1); @@ -213,30 +289,137 @@ public function connect($host="127.0.0.1", $port=3306, $user="root", $password=" .$user."\0" .chr(strlen($token)).$token .$database."\0"; - var_dump($req); + #var_dump($req); $pack_len = 4 + 4 + 1 + 23 + strlen($user) + 1 + strlen($token) + 1 + strlen($database) + 1; - var_dump($pack_len); + #var_dump($pack_len); yield from $this->write_packet($req, $pack_len); yield from $this->read_packet(); - $data = $this->packet_data; - var_dump($data); + } - $query = "select * from sakila.city limit 1;"; - #$query = "select sleep(1);"; - $req = chr(0x03).$query; - $pack_len = strlen($query) + 1; + private function ok_packet($data) { + $start = 1; + $rows_len = $this->length_encoded_integer($data, $start); + #var_dump($rows_len); + $insert_id = $this->length_encoded_integer($data, $start); + #var_dump($insert_id); + $server_status = unpack('v', substr($data, $start, 2))[1]; + $start += 2; + #var_dump($server_status); + $warning_count = unpack('v', substr($data, $start, 2))[1]; + $start += 2; + #var_dump($warning_count); + $message = substr($data, $start); + #var_dump($message); + } + + private function error_packet($data) { + $start = 1; + $errno = unpack('v', substr($data, $start, 2))[1]; + $start += 2; + #var_dump($errno); + $sql_state = substr($data, $start, 6); + $start += 6; + #var_dump($sql_state); + $message = substr($data, $start); + #var_dump($message); + } + + /*private function result_set_packet() { + yield ngx_socket_recv($this->socket, $result, 4); + $this->print_bin($result); + $len = unpack('v',substr($result, 0, 3)); + $len = $len[1]; + yield ngx_socket_recv($this->socket, $result, $len); + $this->print_bin($result); + var_dump("data field"); + $this->field_data_packet($result); + }*/ + + private function field_data_packet($result) { + $start = 0; + $field = array(); + $field['catalog'] = $catalog = $this->parse_field_data($result, $start); + #var_dump($catalog); + $field['db'] = $db = $this->parse_field_data($result, $start); + #var_dump($db); + $field['table'] = $table = $this->parse_field_data($result, $start); + #var_dump($table); + $field['ori_table'] == $ori_table = $this->parse_field_data($result, $start); + #var_dump($ori_table); + $field['column'] = $column = $this->parse_field_data($result, $start); + #var_dump($column); + $field['ori_column'] = $ori_column = $this->parse_field_data($result, $start); + #var_dump($ori_column); + + #$this->print_bin(substr($result, $start)); + + #$this->print_bin(substr($result, $start, 1)); + // 0xC0 + $start += 1; + #$this->print_bin(substr($result, $start, 2)); + $field['charset'] = $charset = unpack('v', substr($result, $start, 2))[1]; + #var_dump($charset); + $start += 2; + $field['length'] = $length = unpack('V', substr($result, $start, 4))[1]; + #var_dump($length); + $start += 4; + $field['type'] = $type = ord(substr($result, $start, 1)); + #var_dump($type); + $start += 1; + $field['flag'] = $flag = unpack('v', substr($result, $start, 2))[1]; + #var_dump($flag); + $start += 2; + $field['decimals'] = $decimals = unpack('v', substr($result, $start, 2))[1]; + #var_dump($decimals); + + $this->resultFields[] = $field; + } + + private function parse_field_data($result, &$start) { + $len = ord(substr($result, $start, 1)); + #var_dump($len); + $field = substr($result, $start + 1, $len); + $start = $start + 1 + $len; + return $field; + } + + private function row_data_packet($data) { + $start = 0; + $row = array(); + foreach ($this->resultFields as $field) { + $len = $this->length_encoded_integer($data, $start); + #var_dump($len); + + $value = substr($data, $start, $len); + #var_dump($value); + $start += $len; + $row[$field['column']] = $value; + } + #var_dump($row); + $this->rows[] = $row; + } + + public function connect($host="127.0.0.1", $port=3306, $user="root", $password="123456") { + yield ngx_socket_connect($this->socket, $host, $port); + + $scramble = ( yield from $this->handshake_packet() ); + + yield from $this->auth_packet($scramble, $user, $password, $database); + } + + public function query($sql) { + $req = chr(0x03).$sql; + $pack_len = strlen($sql) + 1; yield from $this->write_packet($req, $pack_len, 0); - yield from $this->read_packet(0); - $data = $this->packet_data; - var_dump($data); - - $this->print_bin($data); + // result set packet + yield from $this->read_packet(); + return $this->rows; } public function close() {