diff options
author | Darek Slusarczyk <dariusz.slusarczyk@oracle.com> | 2021-02-22 11:03:24 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2021-02-23 09:30:46 +0100 |
commit | da011a312a6c6cd7ff12fe1aa0de1e33fba2f167 (patch) | |
tree | c3e37dadfa5ea7aec39ca3695779fe30c7bd96f6 /ext/pdo_mysql | |
parent | 7f8ea83ef438fbcfa1cbc636d701491d4e773245 (diff) | |
download | php-git-da011a312a6c6cd7ff12fe1aa0de1e33fba2f167.tar.gz |
Fix #80329: Add option to specify LOAD DATA LOCAL white list folder
* allow the user to specify a folder where files that can be sent
via LOAD DATA LOCAL can exist
* add mysqli.local_infile_directory for mysqli
(ignored if mysqli.allow_local_infile is enabled)
* add PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY for pdo_mysql
(ignored if PDO::MYSQL_ATTR_LOCAL_INFILE is enabled)
* add related tests
* fixes for building with libmysql 8.x
* small improvement in existing tests
* update php.ini-[development|production] files
Closes GH-6448.
Co-authored-by: Nikita Popov <nikic@php.net>
Diffstat (limited to 'ext/pdo_mysql')
-rw-r--r-- | ext/pdo_mysql/config.w32 | 5 | ||||
-rw-r--r-- | ext/pdo_mysql/mysql_driver.c | 29 | ||||
-rw-r--r-- | ext/pdo_mysql/pdo_mysql.c | 3 | ||||
-rw-r--r-- | ext/pdo_mysql/php_pdo_mysql_int.h | 3 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/bug70389.phpt | 4 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/foo/bar/bar.data | 3 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/foo/foo.data | 3 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/pdo_mysql___construct_options.phpt | 5 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt | 25 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/pdo_mysql_local_infile_default_off.phpt | 5 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/pdo_mysql_local_infile_directory_allowed.phpt | 85 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/pdo_mysql_local_infile_directory_denied.phpt | 76 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/pdo_mysql_local_infile_overrides_local_infile_directory.phpt | 85 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/skipifinfilenotallowed.inc | 6 |
14 files changed, 325 insertions, 12 deletions
diff --git a/ext/pdo_mysql/config.w32 b/ext/pdo_mysql/config.w32 index 8b5577273d..48e47f7871 100644 --- a/ext/pdo_mysql/config.w32 +++ b/ext/pdo_mysql/config.w32 @@ -10,7 +10,10 @@ if (PHP_PDO_MYSQL != "no") { ADD_EXTENSION_DEP('pdo_mysql', 'pdo'); } else { if (CHECK_LIB("libmysql.lib", "pdo_mysql", PHP_PDO_MYSQL) && - CHECK_HEADER_ADD_INCLUDE("mysql.h", "CFLAGS_PDO_MYSQL", PHP_PHP_BUILD + "\\include\\mysql;" + PHP_PDO_MYSQL)) { + CHECK_HEADER_ADD_INCLUDE("mysql.h", "CFLAGS_PDO_MYSQL", + PHP_PDO_MYSQL + "\\include;" + + PHP_PHP_BUILD + "\\include\\mysql;" + + PHP_PDO_MYSQL)) { EXTENSION("pdo_mysql", "pdo_mysql.c mysql_driver.c mysql_statement.c", null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); } else { WARNING("pdo_mysql not enabled; libraries and headers not found"); diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c index 6b42335878..94fa2411d6 100644 --- a/ext/pdo_mysql/mysql_driver.c +++ b/ext/pdo_mysql/mysql_driver.c @@ -521,6 +521,24 @@ static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_ ZVAL_BOOL(return_value, H->local_infile); break; +#if MYSQL_VERSION_ID >= 80021 || defined(PDO_USE_MYSQLND) + case PDO_MYSQL_ATTR_LOCAL_INFILE_DIRECTORY: + { + const char* local_infile_directory = NULL; +#ifdef PDO_USE_MYSQLND + local_infile_directory = H->server->data->options->local_infile_directory; +#else + mysql_get_option(H->server, MYSQL_OPT_LOAD_DATA_LOCAL_DIR, &local_infile_directory); +#endif + if (local_infile_directory) { + ZVAL_STRING(return_value, local_infile_directory); + } else { + ZVAL_NULL(return_value); + } + break; + } +#endif + default: PDO_DBG_RETURN(0); } @@ -724,6 +742,17 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options) #endif } +#if MYSQL_VERSION_ID >= 80021 || defined(PDO_USE_MYSQLND) + zend_string *local_infile_directory = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_LOCAL_INFILE_DIRECTORY, NULL); + if (local_infile_directory && !php_check_open_basedir(ZSTR_VAL(local_infile_directory))) { + if (mysql_options(H->server, MYSQL_OPT_LOAD_DATA_LOCAL_DIR, (const char *)ZSTR_VAL(local_infile_directory))) { + zend_string_release(local_infile_directory); + pdo_mysql_error(dbh); + goto cleanup; + } + zend_string_release(local_infile_directory); + } +#endif #ifdef MYSQL_OPT_RECONNECT /* since 5.0.3, the default for this option is 0 if not specified. * we want the old behaviour diff --git a/ext/pdo_mysql/pdo_mysql.c b/ext/pdo_mysql/pdo_mysql.c index 84828edaa4..1bfc5ff874 100644 --- a/ext/pdo_mysql/pdo_mysql.c +++ b/ext/pdo_mysql/pdo_mysql.c @@ -124,6 +124,9 @@ static PHP_MINIT_FUNCTION(pdo_mysql) #ifdef PDO_USE_MYSQLND REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_VERIFY_SERVER_CERT", (zend_long)PDO_MYSQL_ATTR_SSL_VERIFY_SERVER_CERT); #endif +#if MYSQL_VERSION_ID >= 80021 || defined(PDO_USE_MYSQLND) + REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_LOCAL_INFILE_DIRECTORY", (zend_long)PDO_MYSQL_ATTR_LOCAL_INFILE_DIRECTORY); +#endif #ifdef PDO_USE_MYSQLND mysqlnd_reverse_api_register_api(&pdo_mysql_reverse_api); diff --git a/ext/pdo_mysql/php_pdo_mysql_int.h b/ext/pdo_mysql/php_pdo_mysql_int.h index 75287e7904..6077ce8245 100644 --- a/ext/pdo_mysql/php_pdo_mysql_int.h +++ b/ext/pdo_mysql/php_pdo_mysql_int.h @@ -178,6 +178,9 @@ enum { #ifdef PDO_USE_MYSQLND PDO_MYSQL_ATTR_SSL_VERIFY_SERVER_CERT, #endif +#if MYSQL_VERSION_ID >= 80021 || defined(PDO_USE_MYSQLND) + PDO_MYSQL_ATTR_LOCAL_INFILE_DIRECTORY, +#endif }; #endif diff --git a/ext/pdo_mysql/tests/bug70389.phpt b/ext/pdo_mysql/tests/bug70389.phpt index 7815b21255..adfd65f5ab 100644 --- a/ext/pdo_mysql/tests/bug70389.phpt +++ b/ext/pdo_mysql/tests/bug70389.phpt @@ -26,8 +26,8 @@ var_dump($flags); array(3) { [%d]=> bool(true) - [1001]=> + [%d]=> bool(true) - [12]=> + [%d]=> bool(true) } diff --git a/ext/pdo_mysql/tests/foo/bar/bar.data b/ext/pdo_mysql/tests/foo/bar/bar.data new file mode 100644 index 0000000000..3fa90ba016 --- /dev/null +++ b/ext/pdo_mysql/tests/foo/bar/bar.data @@ -0,0 +1,3 @@ +97;first +98;second +99;third diff --git a/ext/pdo_mysql/tests/foo/foo.data b/ext/pdo_mysql/tests/foo/foo.data new file mode 100644 index 0000000000..70d8d301e9 --- /dev/null +++ b/ext/pdo_mysql/tests/foo/foo.data @@ -0,0 +1,3 @@ +1;one +2;two +3;three diff --git a/ext/pdo_mysql/tests/pdo_mysql___construct_options.phpt b/ext/pdo_mysql/tests/pdo_mysql___construct_options.phpt index efbf3c51c8..76db58dff2 100644 --- a/ext/pdo_mysql/tests/pdo_mysql___construct_options.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql___construct_options.phpt @@ -156,6 +156,11 @@ MySQLPDOTest::skip(); set_option_and_check(33, PDO::MYSQL_ATTR_DIRECT_QUERY, 1, 'PDO::MYSQL_ATTR_DIRECT_QUERY'); set_option_and_check(34, PDO::MYSQL_ATTR_DIRECT_QUERY, 0, 'PDO::MYSQL_ATTR_DIRECT_QUERY'); + if (defined('PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY')) { + set_option_and_check(35, PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY, null, 'PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY'); + // libmysqlclient returns the directory with a trailing slash. + // set_option_and_check(36, PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY, __DIR__, 'PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY'); + } } catch (PDOException $e) { printf("[001] %s, [%s] %s Line: %s\n", $e->getMessage(), diff --git a/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt b/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt index c9877f3ac1..205e059b54 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt @@ -13,6 +13,16 @@ if (!extension_loaded('mysqli') && !extension_loaded('mysqlnd')) { <?php require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); + function get_client_version() { + if (extension_loaded('mysqli')) { + return mysqli_get_client_version(); + } + /* XXX the MySQL client library version isn't exposed with any + constants, the single possibility is to use the PDO::getAttribute(). + This however will fail with no connection. */ + return MySQLPDOTest::getClientVersion(MySQLPDOTest::factory()); + } + $expected = array( 'MYSQL_ATTR_USE_BUFFERED_QUERY' => true, 'MYSQL_ATTR_LOCAL_INFILE' => true, @@ -38,15 +48,12 @@ if (!extension_loaded('mysqli') && !extension_loaded('mysqlnd')) { if (extension_loaded('mysqlnd')) { $expected['MYSQL_ATTR_SSL_VERIFY_SERVER_CERT'] = true; $expected['MYSQL_ATTR_SERVER_PUBLIC_KEY'] = true; - } else if (extension_loaded('mysqli')) { - if (mysqli_get_client_version() > 50605) { - $expected['MYSQL_ATTR_SERVER_PUBLIC_KEY'] = true; - } - } else if (MySQLPDOTest::getClientVersion(MySQLPDOTest::factory()) > 50605) { - /* XXX the MySQL client library version isn't exposed with any - constants, the single possibility is to use the PDO::getAttribute(). - This however will fail with no connection. */ - $expected['MYSQL_ATTR_SERVER_PUBLIC_KEY'] = true; + } else if (get_client_version() > 50605) { + $expected['MYSQL_ATTR_SERVER_PUBLIC_KEY'] = true; + } + + if (MySQLPDOTest::isPDOMySQLnd() || get_client_version() >= 80021) { + $expected['MYSQL_ATTR_LOCAL_INFILE_DIRECTORY'] = true; } /* diff --git a/ext/pdo_mysql/tests/pdo_mysql_local_infile_default_off.phpt b/ext/pdo_mysql/tests/pdo_mysql_local_infile_default_off.phpt index 810adce7e7..9a12f837fb 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_local_infile_default_off.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_local_infile_default_off.phpt @@ -5,6 +5,9 @@ ensure default for local infile is off require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc'); require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); MySQLPDOTest::skip(); +if (!defined('PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY')) { + die("skip No MYSQL_ATTR_LOCAL_INFILE_DIRECTORY support"); +} ?> --FILE-- <?php @@ -17,8 +20,10 @@ $pass = PDO_MYSQL_TEST_PASS; $db = new PDO($dsn, $user, $pass); echo var_export($db->getAttribute(PDO::MYSQL_ATTR_LOCAL_INFILE)), "\n"; +echo var_export($db->getAttribute(PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY)), "\n"; echo "done!\n"; ?> --EXPECT-- false +NULL done! diff --git a/ext/pdo_mysql/tests/pdo_mysql_local_infile_directory_allowed.phpt b/ext/pdo_mysql/tests/pdo_mysql_local_infile_directory_allowed.phpt new file mode 100644 index 0000000000..edabfbc07f --- /dev/null +++ b/ext/pdo_mysql/tests/pdo_mysql_local_infile_directory_allowed.phpt @@ -0,0 +1,85 @@ +--TEST-- +PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY vs access allowed +--SKIPIF-- +<?php +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc'); +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); +MySQLPDOTest::skip(); +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipifinfilenotallowed.inc'); +if (!defined('PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY')) { + die("skip No MYSQL_ATTR_LOCAL_INFILE_DIRECTORY support"); +} +?> +--FILE-- +<?php + function exec_and_count($offset, &$db, $sql, $exp) { + try { + $ret = $db->exec($sql); + if ($ret !== $exp) { + printf("[%03d] Expecting '%s'/%s got '%s'/%s when running '%s', [%s] %s\n", + $offset, $exp, gettype($exp), $ret, gettype($ret), $sql, + $db->errorCode(), implode(' ', $db->errorInfo())); + return false; + } + } catch (PDOException $e) { + printf("[%03d] '%s' has failed, [%s] %s\n", + $offset, $sql, $db->errorCode(), implode(' ', $db->errorInfo())); + return false; + } + + return true; + } + + require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); + putenv('PDOTEST_ATTR='.serialize([ + PDO::MYSQL_ATTR_LOCAL_INFILE=>false, + PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY=>__DIR__."/foo" + ])); + $db = MySQLPDOTest::factory(); + MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db)); + + try { + exec_and_count(1, $db, 'DROP TABLE IF EXISTS test', 0); + exec_and_count(2, $db, sprintf('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, col1 CHAR(10)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE), 0); + + $filepath = str_replace('\\', '/', __DIR__.'/foo/bar/bar.data'); + + $sql = sprintf("LOAD DATA LOCAL INFILE %s INTO TABLE test FIELDS TERMINATED BY ';' LINES TERMINATED BY '\n'", $db->quote($filepath)); + if (exec_and_count(3, $db, $sql, 3)) { + $stmt = $db->query('SELECT id, col1 FROM test ORDER BY id ASC'); + $expected = array( + array("id" => 97, "col1" => "first"), + array("id" => 98, "col1" => "second"), + array("id" => 99, "col1" => "third"), + ); + $ret = $stmt->fetchAll(PDO::FETCH_ASSOC); + foreach ($expected as $offset => $exp) { + foreach ($exp as $key => $value) { + $actual_value = trim(strval($ret[$offset][$key])); + if ($actual_value != $value) { + printf("Results seem wrong, check manually\n"); + echo "------ EXPECTED OUTPUT ------\n"; + var_dump($expected); + echo "------ ACTUAL OUTPUT ------\n"; + var_dump($ret); + break 2; + } + } + } + } + } catch (PDOException $e) { + printf("[001] %s, [%s] %s\n", + $e->getMessage(), + $db->errorCode(), implode(' ', $db->errorInfo())); + } + + print "done!"; +?> +--CLEAN-- +<?php +require dirname(__FILE__) . '/mysql_pdo_test.inc'; +$db = MySQLPDOTest::factory(); +$db->exec('DROP TABLE IF EXISTS test'); +?> +--EXPECT-- +done! diff --git a/ext/pdo_mysql/tests/pdo_mysql_local_infile_directory_denied.phpt b/ext/pdo_mysql/tests/pdo_mysql_local_infile_directory_denied.phpt new file mode 100644 index 0000000000..c955c1daad --- /dev/null +++ b/ext/pdo_mysql/tests/pdo_mysql_local_infile_directory_denied.phpt @@ -0,0 +1,76 @@ +--TEST-- +PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY vs access denied +--SKIPIF-- +<?php +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc'); +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); +MySQLPDOTest::skip(); +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipifinfilenotallowed.inc'); +if (!defined('PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY')) { + die("skip No MYSQL_ATTR_LOCAL_INFILE_DIRECTORY support"); +} +?> +--FILE-- +<?php + function exec_and_count($offset, &$db, $sql, $exp) { + try { + $ret = $db->exec($sql); + if ($ret !== $exp) { + printf("[%03d] Expecting '%s'/%s got '%s'/%s when running '%s', [%s] %s\n", + $offset, $exp, gettype($exp), $ret, gettype($ret), $sql, + $db->errorCode(), implode(' ', $db->errorInfo())); + return false; + } + } catch (PDOException $e) { + printf("[%03d] '%s' has failed, [%s] %s\n", + $offset, $sql, $db->errorCode(), implode(' ', $db->errorInfo())); + return false; + } + + return true; + } + + require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); + putenv('PDOTEST_ATTR='.serialize([ + PDO::MYSQL_ATTR_LOCAL_INFILE=>false, + PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY=>__DIR__."/foo/bar" + ])); + $db = MySQLPDOTest::factory(); + MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db)); + + try { + exec_and_count(1, $db, 'DROP TABLE IF EXISTS test', 0); + exec_and_count(2, $db, sprintf('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, col1 CHAR(10)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE), 0); + + $filepath = str_replace('\\', '/', __DIR__.'/foo/foo.data'); + + $sql = sprintf("LOAD DATA LOCAL INFILE %s INTO TABLE test FIELDS TERMINATED BY ';' LINES TERMINATED BY '\n'", $db->quote($filepath)); + if (exec_and_count(3, $db, $sql, false)) { + $stmt = $db->query('SELECT id, col1 FROM test ORDER BY id ASC'); + $expected = array(); + $ret = $stmt->fetchAll(PDO::FETCH_ASSOC); + if ($ret != $expected) { + printf("Results seem wrong, check manually\n"); + echo "------ EXPECTED OUTPUT ------\n"; + var_dump($expected); + echo "------ ACTUAL OUTPUT ------\n"; + var_dump($ret); + } + } + } catch (PDOException $e) { + printf("[001] %s, [%s] %s\n", + $e->getMessage(), + $db->errorCode(), implode(' ', $db->errorInfo())); + } + + print "done!"; +?> +--CLEAN-- +<?php +require dirname(__FILE__) . '/mysql_pdo_test.inc'; +$db = MySQLPDOTest::factory(); +$db->exec('DROP TABLE IF EXISTS test'); +?> +--EXPECTF-- +Warning: PDO::exec(): SQLSTATE[HY000]: General error: 2068 LOAD DATA LOCAL INFILE %s in %s on line %d +done! diff --git a/ext/pdo_mysql/tests/pdo_mysql_local_infile_overrides_local_infile_directory.phpt b/ext/pdo_mysql/tests/pdo_mysql_local_infile_overrides_local_infile_directory.phpt new file mode 100644 index 0000000000..c6d60fd1ab --- /dev/null +++ b/ext/pdo_mysql/tests/pdo_mysql_local_infile_overrides_local_infile_directory.phpt @@ -0,0 +1,85 @@ +--TEST-- +PDO::MYSQL_ATTR_LOCAL_INFILE overrides PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY +--SKIPIF-- +<?php +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc'); +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); +MySQLPDOTest::skip(); +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipifinfilenotallowed.inc'); +if (!defined('PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY')) { + die("skip No MYSQL_ATTR_LOCAL_INFILE_DIRECTORY support"); +} +?> +--FILE-- +<?php + function exec_and_count($offset, &$db, $sql, $exp) { + try { + $ret = $db->exec($sql); + if ($ret !== $exp) { + printf("[%03d] Expecting '%s'/%s got '%s'/%s when running '%s', [%s] %s\n", + $offset, $exp, gettype($exp), $ret, gettype($ret), $sql, + $db->errorCode(), implode(' ', $db->errorInfo())); + return false; + } + } catch (PDOException $e) { + printf("[%03d] '%s' has failed, [%s] %s\n", + $offset, $sql, $db->errorCode(), implode(' ', $db->errorInfo())); + return false; + } + + return true; + } + + require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); + putenv('PDOTEST_ATTR='.serialize([ + PDO::MYSQL_ATTR_LOCAL_INFILE=>true, + PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY=>__DIR__."/foo/bar" + ])); + $db = MySQLPDOTest::factory(); + MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db)); + + try { + exec_and_count(1, $db, 'DROP TABLE IF EXISTS test', 0); + exec_and_count(2, $db, sprintf('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, col1 CHAR(10)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE), 0); + + $filepath = str_replace('\\', '/', __DIR__.'/foo/foo.data'); + + $sql = sprintf("LOAD DATA LOCAL INFILE %s INTO TABLE test FIELDS TERMINATED BY ';' LINES TERMINATED BY '\n'", $db->quote($filepath)); + if (exec_and_count(3, $db, $sql, 3)) { + $stmt = $db->query('SELECT id, col1 FROM test ORDER BY id ASC'); + $expected = array( + array("id" => 1, "col1" => "one"), + array("id" => 2, "col1" => "two"), + array("id" => 3, "col1" => "three"), + ); + $ret = $stmt->fetchAll(PDO::FETCH_ASSOC); + foreach ($expected as $offset => $exp) { + foreach ($exp as $key => $value) { + $actual_value = trim(strval($ret[$offset][$key])); + if ($actual_value != $value) { + printf("Results seem wrong, check manually\n"); + echo "------ EXPECTED OUTPUT ------\n"; + var_dump($expected); + echo "------ ACTUAL OUTPUT ------\n"; + var_dump($ret); + break 2; + } + } + } + } + } catch (PDOException $e) { + printf("[001] %s, [%s] %s\n", + $e->getMessage(), + $db->errorCode(), implode(' ', $db->errorInfo())); + } + + print "done!"; +?> +--CLEAN-- +<?php +require dirname(__FILE__) . '/mysql_pdo_test.inc'; +$db = MySQLPDOTest::factory(); +$db->exec('DROP TABLE IF EXISTS test'); +?> +--EXPECT-- +done! diff --git a/ext/pdo_mysql/tests/skipifinfilenotallowed.inc b/ext/pdo_mysql/tests/skipifinfilenotallowed.inc new file mode 100644 index 0000000000..abfea299b7 --- /dev/null +++ b/ext/pdo_mysql/tests/skipifinfilenotallowed.inc @@ -0,0 +1,6 @@ +<?php +$db = MySQLPDOTest::factory(); +$stmt = $db->query("SHOW VARIABLES LIKE 'local_infile'"); +if (($row = $stmt->fetch(PDO::FETCH_ASSOC)) && ($row['value'] != 'ON')) + die("skip Server variable 'local_infile' seems not set to 'ON', found '". $row['value'] ."'"); +?> |