summaryrefslogtreecommitdiff
path: root/ext/pdo
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo')
-rw-r--r--ext/pdo/pdo_dbh.c4
-rw-r--r--ext/pdo/pdo_sql_parser.c204
-rw-r--r--ext/pdo/pdo_sql_parser.re2
-rw-r--r--ext/pdo/pdo_stmt.c20
-rw-r--r--ext/pdo/tests/bug_44159.phpt2
-rw-r--r--ext/pdo/tests/bug_47769.phpt (renamed from ext/pdo/tests/bug47769.phpt)2
-rw-r--r--ext/pdo/tests/bug_52098.phpt59
-rw-r--r--ext/pdo/tests/bug_61292.phpt (renamed from ext/pdo/tests/bug61292.phpt)2
-rw-r--r--ext/pdo/tests/bug_65946.phpt (renamed from ext/pdo/tests/bug65946.phpt)2
-rw-r--r--ext/pdo/tests/bug_71447.phpt104
10 files changed, 262 insertions, 139 deletions
diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c
index 0b2053d0d3..624281c18b 100644
--- a/ext/pdo/pdo_dbh.c
+++ b/ext/pdo/pdo_dbh.c
@@ -436,10 +436,8 @@ static void pdo_stmt_construct(zend_execute_data *execute_data, pdo_stmt_t *stmt
zval retval;
fci.size = sizeof(zend_fcall_info);
- fci.function_table = &dbstmt_ce->function_table;
ZVAL_UNDEF(&fci.function_name);
fci.object = Z_OBJ_P(object);
- fci.symbol_table = NULL;
fci.retval = &retval;
fci.param_count = 0;
fci.params = NULL;
@@ -449,7 +447,7 @@ static void pdo_stmt_construct(zend_execute_data *execute_data, pdo_stmt_t *stmt
fcc.initialized = 1;
fcc.function_handler = dbstmt_ce->constructor;
- fcc.calling_scope = EG(scope);
+ fcc.calling_scope = zend_get_executed_scope();
fcc.called_scope = Z_OBJCE_P(object);
fcc.object = Z_OBJ_P(object);
diff --git a/ext/pdo/pdo_sql_parser.c b/ext/pdo/pdo_sql_parser.c
index 84f6ac3c6e..0095c3d8dc 100644
--- a/ext/pdo/pdo_sql_parser.c
+++ b/ext/pdo/pdo_sql_parser.c
@@ -54,7 +54,6 @@ static int scan(Scanner *s)
#line 55 "ext/pdo/pdo_sql_parser.c"
{
YYCTYPE yych;
- unsigned int yyaccept = 0;
if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
yych = *YYCURSOR;
@@ -62,31 +61,32 @@ static int scan(Scanner *s)
case 0x00: goto yy2;
case '"': goto yy3;
case '\'': goto yy5;
- case '-': goto yy11;
- case '/': goto yy9;
+ case '(':
+ case ')':
+ case '*':
+ case '+':
+ case ',':
+ case '.': goto yy9;
+ case '-': goto yy10;
+ case '/': goto yy11;
case ':': goto yy6;
case '?': goto yy7;
default: goto yy12;
}
yy2:
YYCURSOR = YYMARKER;
- switch (yyaccept) {
- case 0: goto yy4;
- case 1: goto yy10;
- }
+ goto yy4;
yy3:
- yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
- if (yych >= 0x01) goto yy43;
+ if (yych >= 0x01) goto yy37;
yy4:
#line 63 "ext/pdo/pdo_sql_parser.re"
{ SKIP_ONE(PDO_PARSER_TEXT); }
-#line 85 "ext/pdo/pdo_sql_parser.c"
+#line 86 "ext/pdo/pdo_sql_parser.c"
yy5:
- yyaccept = 0;
yych = *(YYMARKER = ++YYCURSOR);
if (yych <= 0x00) goto yy4;
- goto yy38;
+ goto yy32;
yy6:
yych = *++YYCURSOR;
switch (yych) {
@@ -152,14 +152,14 @@ yy6:
case 'w':
case 'x':
case 'y':
- case 'z': goto yy32;
- case ':': goto yy35;
+ case 'z': goto yy26;
+ case ':': goto yy29;
default: goto yy4;
}
yy7:
++YYCURSOR;
switch ((yych = *YYCURSOR)) {
- case '?': goto yy29;
+ case '?': goto yy23;
default: goto yy8;
}
yy8:
@@ -167,133 +167,89 @@ yy8:
{ RET(PDO_PARSER_BIND_POS); }
#line 169 "ext/pdo/pdo_sql_parser.c"
yy9:
- ++YYCURSOR;
- switch ((yych = *YYCURSOR)) {
- case '*': goto yy19;
- default: goto yy13;
- }
+ yych = *++YYCURSOR;
+ goto yy4;
yy10:
-#line 65 "ext/pdo/pdo_sql_parser.re"
- { RET(PDO_PARSER_TEXT); }
-#line 179 "ext/pdo/pdo_sql_parser.c"
-yy11:
yych = *++YYCURSOR;
switch (yych) {
- case '-': goto yy14;
- default: goto yy13;
+ case '-': goto yy21;
+ default: goto yy4;
+ }
+yy11:
+ yych = *(YYMARKER = ++YYCURSOR);
+ switch (yych) {
+ case '*': goto yy15;
+ default: goto yy4;
}
yy12:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
-yy13:
switch (yych) {
case 0x00:
case '"':
case '\'':
+ case '(':
+ case ')':
+ case '*':
+ case '+':
+ case ',':
+ case '-':
+ case '.':
+ case '/':
case ':':
- case '?': goto yy10;
+ case '?': goto yy14;
default: goto yy12;
}
yy14:
+#line 65 "ext/pdo/pdo_sql_parser.re"
+ { RET(PDO_PARSER_TEXT); }
+#line 208 "ext/pdo/pdo_sql_parser.c"
+yy15:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
switch (yych) {
- case 0x00:
- case '"':
- case '\'':
- case ':':
- case '?': goto yy17;
- case '\n':
- case '\r': goto yy12;
- default: goto yy14;
+ case '*': goto yy17;
+ default: goto yy15;
}
-yy16:
-#line 64 "ext/pdo/pdo_sql_parser.re"
- { RET(PDO_PARSER_TEXT); }
-#line 216 "ext/pdo/pdo_sql_parser.c"
yy17:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
switch (yych) {
- case '\n':
- case '\r': goto yy16;
- default: goto yy17;
+ case '*': goto yy17;
+ case '/': goto yy19;
+ default: goto yy15;
}
yy19:
- yyaccept = 1;
- YYMARKER = ++YYCURSOR;
- if (YYLIMIT <= YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- switch (yych) {
- case 0x00:
- case '"':
- case '\'':
- case ':':
- case '?': goto yy21;
- case '*': goto yy23;
- default: goto yy19;
- }
+ ++YYCURSOR;
+yy20:
+#line 64 "ext/pdo/pdo_sql_parser.re"
+ { RET(PDO_PARSER_TEXT); }
+#line 231 "ext/pdo/pdo_sql_parser.c"
yy21:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
switch (yych) {
- case '*': goto yy26;
+ case '\n':
+ case '\r': goto yy20;
default: goto yy21;
}
yy23:
- yyaccept = 1;
- YYMARKER = ++YYCURSOR;
- if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
- yych = *YYCURSOR;
- switch (yych) {
- case 0x00:
- case '"':
- case '\'':
- case ':':
- case '?': goto yy21;
- case '*': goto yy23;
- case '/': goto yy25;
- default: goto yy19;
- }
-yy25:
- yych = *++YYCURSOR;
- switch (yych) {
- case 0x00:
- case '"':
- case '\'':
- case ':':
- case '?': goto yy16;
- default: goto yy12;
- }
-yy26:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
switch (yych) {
- case '*': goto yy26;
- case '/': goto yy28;
- default: goto yy21;
+ case '?': goto yy23;
+ default: goto yy25;
}
-yy28:
- yych = *++YYCURSOR;
- goto yy16;
-yy29:
- ++YYCURSOR;
- if (YYLIMIT <= YYCURSOR) YYFILL(1);
- yych = *YYCURSOR;
- switch (yych) {
- case '?': goto yy29;
- default: goto yy31;
- }
-yy31:
+yy25:
#line 60 "ext/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_TEXT); }
-#line 296 "ext/pdo/pdo_sql_parser.c"
-yy32:
+#line 252 "ext/pdo/pdo_sql_parser.c"
+yy26:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
@@ -360,65 +316,65 @@ yy32:
case 'w':
case 'x':
case 'y':
- case 'z': goto yy32;
- default: goto yy34;
+ case 'z': goto yy26;
+ default: goto yy28;
}
-yy34:
+yy28:
#line 61 "ext/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_BIND); }
-#line 370 "ext/pdo/pdo_sql_parser.c"
-yy35:
+#line 326 "ext/pdo/pdo_sql_parser.c"
+yy29:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
switch (yych) {
- case ':': goto yy35;
- default: goto yy31;
+ case ':': goto yy29;
+ default: goto yy25;
}
-yy37:
+yy31:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
-yy38:
+yy32:
switch (yych) {
case 0x00: goto yy2;
- case '\'': goto yy40;
- case '\\': goto yy39;
- default: goto yy37;
+ case '\'': goto yy34;
+ case '\\': goto yy33;
+ default: goto yy31;
}
-yy39:
+yy33:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
if (yych <= 0x00) goto yy2;
- goto yy37;
-yy40:
+ goto yy31;
+yy34:
++YYCURSOR;
#line 59 "ext/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_TEXT); }
-#line 400 "ext/pdo/pdo_sql_parser.c"
-yy42:
+#line 356 "ext/pdo/pdo_sql_parser.c"
+yy36:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
-yy43:
+yy37:
switch (yych) {
case 0x00: goto yy2;
- case '"': goto yy45;
- case '\\': goto yy44;
- default: goto yy42;
+ case '"': goto yy39;
+ case '\\': goto yy38;
+ default: goto yy36;
}
-yy44:
+yy38:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
if (yych <= 0x00) goto yy2;
- goto yy42;
-yy45:
+ goto yy36;
+yy39:
++YYCURSOR;
#line 58 "ext/pdo/pdo_sql_parser.re"
{ RET(PDO_PARSER_TEXT); }
-#line 422 "ext/pdo/pdo_sql_parser.c"
+#line 378 "ext/pdo/pdo_sql_parser.c"
}
#line 66 "ext/pdo/pdo_sql_parser.re"
diff --git a/ext/pdo/pdo_sql_parser.re b/ext/pdo/pdo_sql_parser.re
index af6c278fef..3279b47056 100644
--- a/ext/pdo/pdo_sql_parser.re
+++ b/ext/pdo/pdo_sql_parser.re
@@ -49,7 +49,7 @@ static int scan(Scanner *s)
BINDCHR = [:][a-zA-Z0-9_]+;
QUESTION = [?];
COMMENTS = ("/*"([^*]+|[*]+[^/*])*[*]*"*/"|"--"[^\r\n]*);
- SPECIALS = [:?"'];
+ SPECIALS = [:?"'-/];
MULTICHAR = ([:]{2,}|[?]{2,});
ANYNOEOF = [\001-\377];
*/
diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c
index 6019c39aba..c2f3c13399 100644
--- a/ext/pdo/pdo_stmt.c
+++ b/ext/pdo/pdo_stmt.c
@@ -740,9 +740,7 @@ static int do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */
}
if (ce->constructor) {
- fci->function_table = &ce->function_table;
ZVAL_UNDEF(&fci->function_name);
- fci->symbol_table = NULL;
fci->retval = &stmt->fetch.cls.retval;
fci->param_count = 0;
fci->params = NULL;
@@ -752,7 +750,7 @@ static int do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */
fcc->initialized = 1;
fcc->function_handler = ce->constructor;
- fcc->calling_scope = EG(scope);
+ fcc->calling_scope = zend_get_executed_scope();
fcc->called_scope = ce;
return 1;
} else if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args)) {
@@ -1241,7 +1239,6 @@ static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, zend_long mode, int fetch_all)
return 0;
}
/* fall through */
-
default:
if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_SERIALIZE can only be used together with PDO::FETCH_CLASS");
@@ -1542,16 +1539,16 @@ static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt,
{
struct pdo_bound_param_data param = {{{0}}};
zend_long param_type = PDO_PARAM_STR;
- zval *parameter;
+ zval *parameter, *driver_params = NULL;
param.paramno = -1;
if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
"lz|llz!", &param.paramno, &parameter, &param_type, &param.max_value_len,
- &param.driver_params)) {
+ &driver_params)) {
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|llz!", &param.name,
&parameter, &param_type, &param.max_value_len,
- &param.driver_params)) {
+ &driver_params)) {
return 0;
}
}
@@ -1565,6 +1562,10 @@ static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt,
return 0;
}
+ if (driver_params) {
+ ZVAL_COPY(&param.driver_params, driver_params);
+ }
+
ZVAL_COPY(&param.parameter, parameter);
if (!really_register_bound_param(&param, stmt, is_param)) {
if (!Z_ISUNDEF(param.parameter)) {
@@ -2215,6 +2216,7 @@ static union _zend_function *dbstmt_method_get(zend_object **object_pp, zend_str
lc_method_name = zend_string_alloc(ZSTR_LEN(method_name), 0);
zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
+
if ((fbc = zend_hash_find_ptr(&object->ce->function_table, lc_method_name)) == NULL) {
pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object);
/* instance not created by PDO object */
@@ -2239,6 +2241,9 @@ static union _zend_function *dbstmt_method_get(zend_object **object_pp, zend_str
out:
zend_string_release(lc_method_name);
+ if (!fbc) {
+ fbc = std_object_handlers.get_method(object_pp, method_name, key);
+ }
return fbc;
}
@@ -2619,6 +2624,7 @@ static union _zend_function *row_method_get(
}
zend_string_release(lc_method_name);
+
return fbc;
}
diff --git a/ext/pdo/tests/bug_44159.phpt b/ext/pdo/tests/bug_44159.phpt
index 9f1961c267..4382fbddda 100644
--- a/ext/pdo/tests/bug_44159.phpt
+++ b/ext/pdo/tests/bug_44159.phpt
@@ -1,5 +1,5 @@
--TEST--
-Bug #44159 (Crash: $pdo->setAttribute(PDO::STATEMENT_ATTR_CLASS, NULL))
+PDO Common: Bug #44159 (Crash: $pdo->setAttribute(PDO::STATEMENT_ATTR_CLASS, NULL))
--SKIPIF--
<?php # vim:ft=php
if (!extension_loaded('pdo')) die('skip PDO not available');
diff --git a/ext/pdo/tests/bug47769.phpt b/ext/pdo/tests/bug_47769.phpt
index b0b38325d1..f713effd5d 100644
--- a/ext/pdo/tests/bug47769.phpt
+++ b/ext/pdo/tests/bug_47769.phpt
@@ -1,5 +1,5 @@
--TEST--
-Bug #47769 (Strange extends PDO)
+PDO Common: Bug #47769 (Strange extends PDO)
--SKIPIF--
<?php
if (!extension_loaded("pdo_sqlite"))
diff --git a/ext/pdo/tests/bug_52098.phpt b/ext/pdo/tests/bug_52098.phpt
new file mode 100644
index 0000000000..c9d39af522
--- /dev/null
+++ b/ext/pdo/tests/bug_52098.phpt
@@ -0,0 +1,59 @@
+--TEST--
+PDO Common: Bug #52098 Own PDOStatement implementation ignore __call()
+--SKIPIF--
+<?php # vim:ft=php
+if (!extension_loaded('pdo')) die('skip');
+$dir = getenv('REDIR_TEST_DIR');
+if (false == $dir) die('skip no driver');
+require_once $dir . 'pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.dirname(__FILE__) . '/../../pdo/tests/');
+require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
+$db = PDOTest::factory();
+
+@$db->exec("DROP TABLE test");
+$db->exec("CREATE TABLE test (x int)");
+$db->exec("INSERT INTO test VALUES (1)");
+
+class MyStatement extends PDOStatement
+{
+ public function __call($name, $arguments)
+ {
+ echo "Calling object method '$name'" . implode(', ', $arguments). "\n";
+ }
+}
+/*
+Test prepared statement with PDOStatement class.
+*/
+$derived = $db->prepare('SELECT * FROM test', array(PDO::ATTR_STATEMENT_CLASS=>array('MyStatement')));
+$derived->execute();
+$derived->foo();
+$derived->fetchAll();
+$derived = null;
+
+/*
+Test regular statement with PDOStatement class.
+*/
+$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('MyStatement'));
+$r = $db->query('SELECT * FROM test');
+echo $r->bar();
+$r->fetchAll();
+$r = null;
+
+/*
+Test object instance of PDOStatement class.
+*/
+$obj = new MyStatement;
+echo $obj->lucky();
+
+$db->exec("DROP TABLE test");
+?>
+===DONE===
+--EXPECTF--
+Calling object method 'foo'
+Calling object method 'bar'
+Calling object method 'lucky'
+===DONE=== \ No newline at end of file
diff --git a/ext/pdo/tests/bug61292.phpt b/ext/pdo/tests/bug_61292.phpt
index 05b2e9c011..0e41be3859 100644
--- a/ext/pdo/tests/bug61292.phpt
+++ b/ext/pdo/tests/bug_61292.phpt
@@ -1,5 +1,5 @@
--TEST--
-Bug #61292 (Segfault while calling a method on an overloaded PDO object)
+PDO Common: Bug #61292 (Segfault while calling a method on an overloaded PDO object)
--SKIPIF--
<?php
if (!extension_loaded('pdo')) die('skip');
diff --git a/ext/pdo/tests/bug65946.phpt b/ext/pdo/tests/bug_65946.phpt
index af6088cea9..13a622ecb8 100644
--- a/ext/pdo/tests/bug65946.phpt
+++ b/ext/pdo/tests/bug_65946.phpt
@@ -1,5 +1,5 @@
--TEST--
-Bug #65946 (pdo_sql_parser.c permanently converts values bound to strings)
+PDO Common: Bug #65946 (pdo_sql_parser.c permanently converts values bound to strings)
--SKIPIF--
<?php
if (!extension_loaded('pdo')) die('skip');
diff --git a/ext/pdo/tests/bug_71447.phpt b/ext/pdo/tests/bug_71447.phpt
new file mode 100644
index 0000000000..8b5c0732f1
--- /dev/null
+++ b/ext/pdo/tests/bug_71447.phpt
@@ -0,0 +1,104 @@
+--TEST--
+PDO Common: Bug #71447 (Quotes inside comments not properly handled)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo')) die('skip');
+$dir = getenv('REDIR_TEST_DIR');
+if (false == $dir) die('skip no driver');
+require_once $dir . 'pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.dirname(__FILE__) . '/../../pdo/tests/');
+require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
+
+$db = PDOTest::factory();
+$db->setAttribute (\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
+$db->setAttribute (\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_NUM);
+$db->setAttribute (\PDO::ATTR_EMULATE_PREPARES, false);
+$db->exec('CREATE TABLE test(id int)');
+$db->exec('INSERT INTO test VALUES(1)');
+
+// Comment without quotes or placeholders
+$stmt = $db->prepare("
+ SELECT -- Thats all folks!
+ '\"abc\":8000'
+ FROM test
+");
+
+$stmt->execute();
+var_dump($stmt->fetchColumn());
+
+// Comment and placeholder within a string
+$stmt = $db->prepare("
+ SELECT
+ '\"abc\":8001 -- Wat?'
+ FROM test
+");
+
+$stmt->execute();
+var_dump($stmt->fetchColumn());
+
+// Comment with single quote
+$stmt = $db->prepare("
+ SELECT -- That's all folks!
+ '\"abc\":8002'
+ FROM test
+");
+
+$stmt->execute();
+var_dump($stmt->fetchColumn());
+
+// C-Style comment with single quote
+$stmt = $db->prepare("
+ SELECT /* That's all folks! */
+ '\"abc\":8003'
+ FROM test
+");
+
+$stmt->execute();
+var_dump($stmt->fetchColumn());
+
+// Comment with double quote
+$stmt = $db->prepare("
+ SELECT -- Is it only \"single quotes?
+ '\"abc\":8004'
+ FROM test
+");
+
+$stmt->execute();
+var_dump($stmt->fetchColumn());
+
+// Comment with ? placeholder
+$stmt = $db->prepare("
+ SELECT -- What about question marks here?
+ *
+ FROM test
+ WHERE id = ?
+");
+
+$stmt->execute([1]);
+var_dump($stmt->fetchColumn());
+
+// Comment with named placeholder
+$stmt = $db->prepare("
+ SELECT -- What about placeholders :bar
+ *
+ FROM test
+ WHERE id = :id
+");
+
+$stmt->execute(['id' => 1]);
+var_dump($stmt->fetchColumn());
+
+
+?>
+--EXPECT--
+string(10) ""abc":8000"
+string(18) ""abc":8001 -- Wat?"
+string(10) ""abc":8002"
+string(10) ""abc":8003"
+string(10) ""abc":8004"
+string(1) "1"
+string(1) "1"