diff --git a/.travis.yml b/.travis.yml index f6c7121abc..2da1743855 100644 --- a/.travis.yml +++ b/.travis.yml @@ -90,7 +90,6 @@ cache: directories: - $HOME/.composer/cache/ - $HOME/browserstack - - $HOME/runkit # Install APT packages # - git > 2.5.1 needed for worktrees # - mysql server does not seem to be always present on Travis Trusty environment diff --git a/build.xml b/build.xml index 7875e65cde..445b863d89 100644 --- a/build.xml +++ b/build.xml @@ -7,7 +7,7 @@ - + diff --git a/libraries/classes/Dbi/DbiMysqli.php b/libraries/classes/Dbi/DbiMysqli.php index f6fc5694d9..7f9589df1e 100644 --- a/libraries/classes/Dbi/DbiMysqli.php +++ b/libraries/classes/Dbi/DbiMysqli.php @@ -1,7 +1,7 @@ 'num', MYSQLI_PART_KEY_FLAG => 'part_key', MYSQLI_SET_FLAG => 'set', @@ -73,25 +44,22 @@ class DbiMysqli implements DbiExtension * @param string $password mysql user password * @param array $server host/port/socket/persistent * - * @return mixed false on error or a mysqli object on success + * @return \mysqli|bool false on error or a mysqli object on success */ - public function connect( - $user, $password, array $server - ) { + public function connect($user, $password, array $server) + { if ($server) { $server['host'] = (empty($server['host'])) ? 'localhost' : $server['host']; } - // NULL enables connection to the default socket - - $link = mysqli_init(); + $mysqli = \mysqli_init(); if (defined('PMA_ENABLE_LDI')) { - mysqli_options($link, MYSQLI_OPT_LOCAL_INFILE, true); + $mysqli->options(MYSQLI_OPT_LOCAL_INFILE, true); } else { - mysqli_options($link, MYSQLI_OPT_LOCAL_INFILE, false); + $mysqli->options(MYSQLI_OPT_LOCAL_INFILE, false); } $client_flags = 0; @@ -110,8 +78,7 @@ class DbiMysqli implements DbiExtension ! empty($server['ssl_ca_path']) || ! empty($server['ssl_ciphers']) ) { - mysqli_ssl_set( - $link, + $mysqli->ssl_set( $server['ssl_key'], $server['ssl_cert'], $server['ssl_ca'], @@ -125,8 +92,7 @@ class DbiMysqli implements DbiExtension * @link https://github.com/phpmyadmin/phpmyadmin/pull/11838 */ if (! $server['ssl_verify']) { - mysqli_options( - $link, + $mysqli->options( MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, $server['ssl_verify'] ); @@ -140,8 +106,7 @@ class DbiMysqli implements DbiExtension $host = $server['host']; } - $return_value = mysqli_real_connect( - $link, + $return_value = $mysqli->real_connect( $host, $user, $password, @@ -160,8 +125,8 @@ class DbiMysqli implements DbiExtension * - #2001 - SSL Connection is required. Please specify SSL options and retry. * - #9002 - SSL connection is required. Please specify SSL options and retry. */ - $error_number = mysqli_connect_errno(); - $error_message = mysqli_connect_error(); + $error_number = $mysqli->connect_errno; + $error_message = $mysqli->connect_error; if (! $server['ssl'] && ($error_number == 3159 || (($error_number == 2001 || $error_number == 9002) && stripos($error_message, 'SSL Connection is required') !== false)) ) { @@ -175,32 +140,32 @@ class DbiMysqli implements DbiExtension return false; } - return $link; + return $mysqli; } /** * selects given database * - * @param string $dbname database name to select - * @param mysqli $link the mysqli object + * @param string $databaseName database name to select + * @param \mysqli $mysqli the mysqli object * * @return boolean */ - public function selectDb($dbname, $link) + public function selectDb($databaseName, $mysqli) { - return mysqli_select_db($link, $dbname); + return $mysqli->select_db($databaseName); } /** * runs a query and returns the result * - * @param string $query query to execute - * @param mysqli $link mysqli object - * @param int $options query options + * @param string $query query to execute + * @param \mysqli $mysqli mysqli object + * @param int $options query options * - * @return mysqli_result|bool + * @return \mysqli_result|bool */ - public function realQuery($query, $link, $options) + public function realQuery($query, $mysqli, $options) { if ($options == ($options | DatabaseInterface::QUERY_STORE)) { $method = MYSQLI_STORE_RESULT; @@ -210,143 +175,143 @@ class DbiMysqli implements DbiExtension $method = 0; } - return mysqli_query($link, $query, $method); + return $mysqli->query($query, $method); } /** * Run the multi query and output the results * - * @param mysqli $link mysqli object - * @param string $query multi query statement to execute + * @param \mysqli $mysqli mysqli object + * @param string $query multi query statement to execute * - * @return mysqli_result collection | boolean(false) + * @return bool */ - public function realMultiQuery($link, $query) + public function realMultiQuery($mysqli, $query) { - return mysqli_multi_query($link, $query); + return $mysqli->multi_query($query); } /** * returns array of rows with associative and numeric keys from $result * - * @param mysqli_result $result result set identifier + * @param \mysqli_result $result result set identifier * - * @return array + * @return array|null */ public function fetchArray($result) { - return mysqli_fetch_array($result, MYSQLI_BOTH); + return $result->fetch_array(MYSQLI_BOTH); } /** * returns array of rows with associative keys from $result * - * @param mysqli_result $result result set identifier + * @param \mysqli_result $result result set identifier * - * @return array + * @return array|null */ public function fetchAssoc($result) { - return mysqli_fetch_array($result, MYSQLI_ASSOC); + return $result->fetch_array(MYSQLI_ASSOC); } /** * returns array of rows with numeric keys from $result * - * @param mysqli_result $result result set identifier + * @param \mysqli_result $result result set identifier * - * @return array + * @return array|null */ public function fetchRow($result) { - return mysqli_fetch_array($result, MYSQLI_NUM); + return $result->fetch_array(MYSQLI_NUM); } /** * Adjusts the result pointer to an arbitrary row in the result * - * @param mysqli_result $result database result - * @param integer $offset offset to seek + * @param \mysqli_result $result database result + * @param integer $offset offset to seek * * @return bool true on success, false on failure */ public function dataSeek($result, $offset) { - return mysqli_data_seek($result, $offset); + return $result->data_seek($offset); } /** * Frees memory associated with the result * - * @param mysqli_result $result database result + * @param \mysqli_result $result database result * * @return void */ public function freeResult($result) { - if ($result instanceof mysqli_result) { - mysqli_free_result($result); + if ($result instanceof \mysqli_result) { + $result->close(); } } /** * Check if there are any more query results from a multi query * - * @param mysqli $link the mysqli object + * @param \mysqli $mysqli the mysqli object * * @return bool true or false */ - public function moreResults($link) + public function moreResults($mysqli) { - return mysqli_more_results($link); + return $mysqli->more_results(); } /** * Prepare next result from multi_query * - * @param mysqli $link the mysqli object + * @param \mysqli $mysqli the mysqli object * * @return bool true or false */ - public function nextResult($link) + public function nextResult($mysqli) { - return mysqli_next_result($link); + return $mysqli->next_result(); } /** * Store the result returned from multi query * - * @param mysqli $link the mysqli object + * @param \mysqli $mysqli the mysqli object * - * @return mixed false when empty results / result set when not empty + * @return \mysqli_result|bool false when empty results / result set when not empty */ - public function storeResult($link) + public function storeResult($mysqli) { - return mysqli_store_result($link); + return $mysqli->store_result(); } /** * Returns a string representing the type of connection used * - * @param resource $link mysql link + * @param \mysqli $mysqli mysql link * * @return string type of connection used */ - public function getHostInfo($link) + public function getHostInfo($mysqli) { - return mysqli_get_host_info($link); + return $mysqli->host_info; } /** * Returns the version of the MySQL protocol used * - * @param resource $link mysql link + * @param \mysqli $mysqli mysql link * - * @return integer version of the MySQL protocol used + * @return string version of the MySQL protocol used */ - public function getProtoInfo($link) + public function getProtoInfo($mysqli) { - return mysqli_get_proto_info($link); + return $mysqli->protocol_version; } /** @@ -362,20 +327,20 @@ class DbiMysqli implements DbiExtension /** * returns last error message or false if no errors occurred * - * @param resource $link mysql link + * @param \mysqli $mysqli mysql link * * @return string|bool $error or false */ - public function getError($link) + public function getError($mysqli) { $GLOBALS['errno'] = 0; - if (null !== $link && false !== $link) { - $error_number = mysqli_errno($link); - $error_message = mysqli_error($link); + if (null !== $mysqli && false !== $mysqli) { + $error_number = $mysqli->errno; + $error_message = $mysqli->error; } else { - $error_number = mysqli_connect_errno(); - $error_message = mysqli_connect_error(); + $error_number = $mysqli->connect_errno; + $error_message = $mysqli->connect_error; } if (0 == $error_number) { return false; @@ -391,7 +356,7 @@ class DbiMysqli implements DbiExtension /** * returns the number of rows returned by last query * - * @param mysqli_result $result result set identifier + * @param \mysqli_result $result result set identifier * * @return string|int */ @@ -402,27 +367,27 @@ class DbiMysqli implements DbiExtension return 0; } - return @mysqli_num_rows($result); + return $result->num_rows; } /** * returns the number of rows affected by last query * - * @param mysqli $link the mysqli object + * @param \mysqli $mysqli the mysqli object * * @return int */ - public function affectedRows($link) + public function affectedRows($mysqli) { - return mysqli_affected_rows($link); + return $mysqli->affected_rows; } /** - * returns metainfo for fields in $result + * returns meta info for fields in $result * - * @param mysqli_result $result result set identifier + * @param \mysqli_result $result result set identifier * - * @return array meta info for fields in $result + * @return array|bool meta info for fields in $result */ public function getFieldsMeta($result) { @@ -462,9 +427,8 @@ class DbiMysqli implements DbiExtension $typeAr[MYSQLI_TYPE_BIT] = 'bit'; $typeAr[MYSQLI_TYPE_JSON] = 'json'; - $fields = mysqli_fetch_fields($result); + $fields = $result->fetch_fields(); - // this happens sometimes (seen under MySQL 4.0.25) if (!is_array($fields)) { return false; } @@ -501,58 +465,66 @@ class DbiMysqli implements DbiExtension /** * return number of fields in given $result * - * @param mysqli_result $result result set identifier + * @param \mysqli_result $result result set identifier * * @return int field count */ public function numFields($result) { - return mysqli_num_fields($result); + return $result->field_count; } /** * returns the length of the given field $i in $result * - * @param mysqli_result $result result set identifier - * @param int $i field + * @param \mysqli_result $result result set identifier + * @param int $i field * - * @return int length of field + * @return int|bool length of field */ public function fieldLen($result, $i) { - return mysqli_fetch_field_direct($result, $i)->length; + $fieldDefinition = $result->fetch_field_direct($i); + if ($fieldDefinition !== false) { + return $fieldDefinition->length; + } + return false; } /** * returns name of $i. field in $result * - * @param mysqli_result $result result set identifier - * @param int $i field + * @param \mysqli_result $result result set identifier + * @param int $i field * - * @return string name of $i. field in $result + * @return string|bool name of $i. field in $result */ public function fieldName($result, $i) { - return mysqli_fetch_field_direct($result, $i)->name; + $fieldDefinition = $result->fetch_field_direct($i); + if ($fieldDefinition !== false) { + return $fieldDefinition->name; + } + return false; } /** * returns concatenated string of human readable field flags * - * @param mysqli_result $result result set identifier - * @param int $i field + * @param \mysqli_result $result result set identifier + * @param int $i field * * @return string field flags */ public function fieldFlags($result, $i) { - $f = mysqli_fetch_field_direct($result, $i); - $type = $f->type; - $charsetnr = $f->charsetnr; - $f = $f->flags; + $fieldDefinition = $result->fetch_field_direct($i); + $type = $fieldDefinition->type; + $charsetNumber = $fieldDefinition->charsetnr; + $fieldDefinitionFlags = $fieldDefinition->flags; $flags = array(); foreach (self::$pma_mysqli_flag_names as $flag => $name) { - if ($f & $flag) { + if ($fieldDefinitionFlags & $flag) { $flags[] = $name; } } @@ -565,7 +537,7 @@ class DbiMysqli implements DbiExtension if (($type == MYSQLI_TYPE_TINY_BLOB || $type == MYSQLI_TYPE_BLOB || $type == MYSQLI_TYPE_MEDIUM_BLOB || $type == MYSQLI_TYPE_LONG_BLOB || $type == MYSQLI_TYPE_VAR_STRING || $type == MYSQLI_TYPE_STRING) - && 63 == $charsetnr + && 63 == $charsetNumber ) { $flags[] = 'binary'; } @@ -575,13 +547,13 @@ class DbiMysqli implements DbiExtension /** * returns properly escaped string for use in MySQL queries * - * @param mixed $link database link - * @param string $str string to be escaped + * @param \mysqli $mysqli database link + * @param string $string string to be escaped * * @return string a MySQL escaped string */ - public function escapeString($link, $str) + public function escapeString($mysqli, $string) { - return mysqli_real_escape_string($link, $str); + return $mysqli->real_escape_string($string); } } diff --git a/test/bootstrap-dist.php b/test/bootstrap-dist.php index 1c4d6eac15..cbe3289c3e 100644 --- a/test/bootstrap-dist.php +++ b/test/bootstrap-dist.php @@ -91,7 +91,3 @@ $GLOBALS['PMA_Theme'] = PhpMyAdmin\Theme::load('./themes/pmahomme'); $_SESSION['tmpval']['pftext'] = 'F'; $GLOBALS['lang'] = 'en'; $GLOBALS['PMA_Config'] = new PhpMyAdmin\Config(); - -// Check whether we have runkit extension -define('PMA_HAS_RUNKIT', function_exists('runkit_constant_redefine')); -$GLOBALS['runkit_internal_override'] = ini_get('runkit.internal_override'); diff --git a/test/ci-install-test b/test/ci-install-test index 4917bc7ed8..2fe1edee6b 100755 --- a/test/ci-install-test +++ b/test/ci-install-test @@ -1,4 +1,3 @@ #!/bin/sh -./test/install-runkit composer install --no-interaction diff --git a/test/classes/Dbi/DbiMysqliTest.php b/test/classes/Dbi/DbiMysqliTest.php index 05fa2ea331..10c85ea93a 100644 --- a/test/classes/Dbi/DbiMysqliTest.php +++ b/test/classes/Dbi/DbiMysqliTest.php @@ -1,4 +1,5 @@ object = new DbiMysqli(); } /** - * Tears down the fixture, for example, closes a network connection. - * This method is called after a test is executed. + * Test for selectDb * - * @access protected * @return void */ - protected function tearDown() + public function testSelectDb(): void { - unset($this->object); + $databaseName = 'test'; + $mysqli = $this->createMock(\mysqli::class); + $mysqli->expects($this->once()) + ->method('select_db') + ->with($this->equalTo($databaseName)) + ->willReturn(true); + + $this->assertTrue($this->object->selectDb($databaseName, $mysqli)); } /** - * Test for mysqli related functions, using runkit_function_redefine + * Test for realMultiQuery * * @return void - * - * @group medium - * @group runkit */ - public function testMysqliDBI() + public function testRealMultiQuery(): void { - if (! PMA_HAS_RUNKIT) { - $this->markTestSkipped("Cannot redefine function"); - } + $query = 'test'; + $mysqli = $this->createMock(\mysqli::class); + $mysqli->expects($this->once()) + ->method('multi_query') + ->with($this->equalTo($query)) + ->willReturn(true); - //FOR UT, we just test the right mysql client API is called - runkit_function_redefine( - 'mysqli_real_connect', '', 'return "mysqli_real_connect";' - ); - runkit_function_redefine('mysqli_init', '', 'return "mysqli_init";'); - runkit_function_redefine('mysqli_options', '', 'return "mysqli_options";'); - runkit_function_redefine('mysqli_query', '', 'return "mysqli_query";'); - runkit_function_redefine( - 'mysqli_multi_query', '', 'return "mysqli_multi_query";' - ); - runkit_function_redefine( - 'mysqli_fetch_array', '', 'return "mysqli_fetch_array";' - ); - runkit_function_redefine( - 'mysqli_data_seek', '', 'return "mysqli_data_seek";' - ); - runkit_function_redefine( - 'mysqli_more_results', '', 'return "mysqli_more_results";' - ); - runkit_function_redefine( - 'mysqli_next_result', '', 'return "mysqli_next_result";' - ); - runkit_function_redefine( - 'mysqli_get_host_info', '', 'return "mysqli_get_host_info";' - ); - runkit_function_redefine( - 'mysqli_get_proto_info', '', 'return "mysqli_get_proto_info";' - ); - runkit_function_redefine( - 'mysqli_get_client_info', '', 'return "mysqli_get_client_info";' - ); + $this->assertTrue($this->object->realMultiQuery($mysqli, $query)); + } - $user = 'PMA_user'; - $password = 'PMA_password'; - $server = array( - 'port' => 8080, - 'socket' => 123, - 'host' => 'locahost', - 'compress' => false, - 'ssl' => false, - ); + /** + * Test for fetchArray + * + * @return void + */ + public function testFetchArray(): void + { + $expected = []; + $result = $this->createMock(\mysqli_result::class); + $result->expects($this->once()) + ->method('fetch_array') + ->with($this->equalTo(MYSQLI_BOTH)) + ->willReturn($expected); - //test for connect - $ret = $this->object->connect( - $user, $password, $server - ); - $this->assertEquals( - 'mysqli_init', - $ret - ); + $this->assertEquals($expected, $this->object->fetchArray($result)); + } - //test for realQuery - $query = 'select * from DBI'; - $link = $ret; - $options = 0; - $ret = $this->object->realQuery($query, $link, $options); - $this->assertEquals( - 'mysqli_query', - $ret - ); + /** + * Test for fetchAssoc + * + * @return void + */ + public function testFetchAssoc(): void + { + $expected = []; + $result = $this->createMock(\mysqli_result::class); + $result->expects($this->once()) + ->method('fetch_array') + ->with($this->equalTo(MYSQLI_ASSOC)) + ->willReturn($expected); - //test for realMultiQuery - $ret = $this->object->realMultiQuery($link, $query); - $this->assertEquals( - 'mysqli_multi_query', - $ret - ); + $this->assertEquals($expected, $this->object->fetchAssoc($result)); + } - //test for fetchArray - $result = $ret; - $ret = $this->object->fetchArray($result); - $this->assertEquals( - 'mysqli_fetch_array', - $ret - ); + /** + * Test for fetchRow + * + * @return void + */ + public function testFetchRow(): void + { + $expected = []; + $result = $this->createMock(\mysqli_result::class); + $result->expects($this->once()) + ->method('fetch_array') + ->with($this->equalTo(MYSQLI_NUM)) + ->willReturn($expected); - //test for fetchAssoc - $result = $ret; - $ret = $this->object->fetchAssoc($result); - $this->assertEquals( - 'mysqli_fetch_array', - $ret - ); + $this->assertEquals($expected, $this->object->fetchRow($result)); + } - //test for fetchRow - $result = $ret; - $ret = $this->object->fetchRow($result); - $this->assertEquals( - 'mysqli_fetch_array', - $ret - ); + /** + * Test for dataSeek + * + * @return void + */ + public function testDataSeek(): void + { + $offset = 1; + $result = $this->createMock(\mysqli_result::class); + $result->expects($this->once()) + ->method('data_seek') + ->with($this->equalTo($offset)) + ->willReturn(true); - //test for dataSeek - $result = $ret; - $offset = 10; - $ret = $this->object->dataSeek($result, $offset); - $this->assertEquals( - 'mysqli_data_seek', - $ret - ); + $this->assertTrue($this->object->dataSeek($result, $offset)); + } - //test for moreResults - $link = $ret; - $ret = $this->object->moreResults($link); - $this->assertEquals( - 'mysqli_more_results', - $ret - ); + /** + * Test for freeResult + * + * @return void + */ + public function testFreeResult(): void + { + $result = $this->createMock(\mysqli_result::class); + $result->expects($this->once()) + ->method('close'); - //test for nextResult - $link = $ret; - $ret = $this->object->nextResult($link); - $this->assertEquals( - 'mysqli_next_result', - $ret - ); + $this->object->freeResult($result); + } - //test for getHostInfo - $link = $ret; - $ret = $this->object->getHostInfo($link); - $this->assertEquals( - 'mysqli_get_host_info', - $ret - ); + /** + * Test for moreResults + * + * @return void + */ + public function testMoreResults(): void + { + $mysqli = $this->createMock(\mysqli::class); + $mysqli->expects($this->once()) + ->method('more_results') + ->willReturn(true); - //test for getProtoInfo - $link = $ret; - $ret = $this->object->getProtoInfo($link); - $this->assertEquals( - 'mysqli_get_proto_info', - $ret - ); + $this->assertTrue($this->object->moreResults($mysqli)); + } - //test for getClientInfo - $ret = $this->object->getClientInfo(); - $this->assertEquals( - 'mysqli_get_client_info', - $ret - ); + /** + * Test for nextResult + * + * @return void + */ + public function testNextResult(): void + { + $mysqli = $this->createMock(\mysqli::class); + $mysqli->expects($this->once()) + ->method('next_result') + ->willReturn(true); + + $this->assertTrue($this->object->nextResult($mysqli)); + } + + /** + * Test for storeResult + * + * @return void + */ + public function testStoreResult(): void + { + $mysqli = $this->createMock(\mysqli::class); + $mysqli->expects($this->once()) + ->method('store_result') + ->willReturn(true); + + $this->assertTrue($this->object->storeResult($mysqli)); } /** * Test for numRows * * @return void - * - * @group medium */ - public function testNumRows() + public function testNumRows(): void { - $this->assertEquals( - 0, - $this->object->numRows(true) - ); + $this->assertEquals(0, $this->object->numRows(false)); + } + + /** + * Test for escapeString + * + * @return void + */ + public function testEscapeString(): void + { + $string = 'test'; + $mysqli = $this->createMock(\mysqli::class); + $mysqli->expects($this->once()) + ->method('real_escape_string') + ->willReturn($string); + + $this->assertEquals($string, $this->object->escapeString($mysqli, $string)); } } diff --git a/test/install-runkit b/test/install-runkit deleted file mode 100755 index b598b87f83..0000000000 --- a/test/install-runkit +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -set -e - -# Do not run as CGI -if [ -n "$GATEWAY_INTERFACE" ] ; then - echo 'Can not invoke as CGI!' - exit 1 -fi - -# These do not support runkit -case "$TRAVIS_PHP_VERSION" in - hhvm*|nightly) - exit 0 - ;; - 7.*) - exit 0 - # Disabled for now as it causes PHP crashes, we should retry with newer version - RVERSION=1.0.5b1 - wget https://github.com/runkit7/runkit7/releases/download/$RVERSION/runkit-$RVERSION.tgz - pecl install ./runkit-$RVERSION.tgz - ;; - *) - pecl install runkit - ;; -esac - -phpenv config-add test/php-runkit.ini diff --git a/test/php-runkit.ini b/test/php-runkit.ini deleted file mode 100644 index ee76560353..0000000000 --- a/test/php-runkit.ini +++ /dev/null @@ -1,7 +0,0 @@ -; PHP configuration tweaks for tests on Travis - -; Extension is automaticlaly enabled by PECL -; extension=runkit.so - -; Enable override of internal functions -runkit.internal_override=1