Differential D19998 Diff 47739 src/aphront/storage/connection/mysql/AphrontMySQLiDatabaseConnection.php
Changeset View
Changeset View
Standalone View
Standalone View
src/aphront/storage/connection/mysql/AphrontMySQLiDatabaseConnection.php
Show First 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | protected function connect() { | ||||
$conn = mysqli_init(); | $conn = mysqli_init(); | ||||
$timeout = $this->getConfiguration('timeout'); | $timeout = $this->getConfiguration('timeout'); | ||||
if ($timeout) { | if ($timeout) { | ||||
$conn->options(MYSQLI_OPT_CONNECT_TIMEOUT, $timeout); | $conn->options(MYSQLI_OPT_CONNECT_TIMEOUT, $timeout); | ||||
} | } | ||||
// See T13238. Attempt to prevent "LOAD DATA INFILE LOCAL", which allows a | |||||
// malicious server to ask the client for any file. | |||||
// NOTE: See T13238. This option does not appear to ever have any effect. | |||||
// Only the PHP level configuration of "mysqli.allow_local_infile" is | |||||
// effective in preventing "LOAD DATA INFILE LOCAL". It appears that the | |||||
// configuration option may overwrite the local option? Set the local | |||||
// option to the desired (safe) value anyway in case this starts working | |||||
// properly in some future version of PHP/MySQLi. | |||||
$conn->options(MYSQLI_OPT_LOCAL_INFILE, 0); | |||||
if ($this->getPersistent()) { | if ($this->getPersistent()) { | ||||
$host = 'p:'.$host; | $host = 'p:'.$host; | ||||
} | } | ||||
@$conn->real_connect( | @$conn->real_connect( | ||||
$host, | $host, | ||||
$user, | $user, | ||||
$pass, | $pass, | ||||
Show All 19 Lines | final class AphrontMySQLiDatabaseConnection | ||||
protected function rawQuery($raw_query) { | protected function rawQuery($raw_query) { | ||||
$conn = $this->requireConnection(); | $conn = $this->requireConnection(); | ||||
$time_limit = $this->getQueryTimeout(); | $time_limit = $this->getQueryTimeout(); | ||||
// If we have a query time limit, run this query synchronously but use | // If we have a query time limit, run this query synchronously but use | ||||
// the async API. This allows us to kill queries which take too long | // the async API. This allows us to kill queries which take too long | ||||
// without requiring any configuration on the server side. | // without requiring any configuration on the server side. | ||||
if ($time_limit && $this->supportsAsyncQueries()) { | if ($time_limit && $this->supportsAsyncQueries()) { | ||||
$conn->query($raw_query, MYSQLI_ASYNC); | $conn->query($raw_query, MYSQLI_ASYNC); | ||||
Lint: PHP Compatibility: This codebase targets PHP 5.2.3, but `MYSQLI_ASYNC` was not introduced until PHP 5.3.0. | |||||
$read = array($conn); | $read = array($conn); | ||||
$error = array($conn); | $error = array($conn); | ||||
$reject = array($conn); | $reject = array($conn); | ||||
$result = mysqli::poll($read, $error, $reject, $time_limit); | $result = mysqli::poll($read, $error, $reject, $time_limit); | ||||
if ($result === false) { | if ($result === false) { | ||||
$this->closeConnection(); | $this->closeConnection(); | ||||
throw new Exception( | throw new Exception( | ||||
pht('Failed to poll mysqli connection!')); | pht('Failed to poll mysqli connection!')); | ||||
} else if ($result === 0) { | } else if ($result === 0) { | ||||
$this->closeConnection(); | $this->closeConnection(); | ||||
throw new AphrontQueryTimeoutQueryException( | throw new AphrontQueryTimeoutQueryException( | ||||
pht( | pht( | ||||
'Query timed out after %s second(s)!', | 'Query timed out after %s second(s)!', | ||||
new PhutilNumber($time_limit))); | new PhutilNumber($time_limit))); | ||||
} | } | ||||
return @$conn->reap_async_query(); | return @$conn->reap_async_query(); | ||||
} | } | ||||
return @$conn->query($raw_query); | $trap = new PhutilErrorTrap(); | ||||
$result = @$conn->query($raw_query); | |||||
$err = $trap->getErrorsAsString(); | |||||
$trap->destroy(); | |||||
// See T13238 and PHI1014. Sometimes, the call to "$conn->query()" may fail | |||||
// without setting an error code on the connection. One way to reproduce | |||||
// this is to use "LOAD DATA INFILE LOCAL" with "mysqli.allow_local_infile" | |||||
// disabled. | |||||
// If we have no result and no error code, raise a synthetic query error | |||||
// with whatever error message was raised as a local PHP warning. | |||||
if (!$result) { | |||||
$error_code = $this->getErrorCode($conn); | |||||
if (!$error_code) { | |||||
if (strlen($err)) { | |||||
$message = $err; | |||||
} else { | |||||
$message = pht( | |||||
'Call to "mysqli->query()" failed, but did not set an error '. | |||||
'code or emit an error message.'); | |||||
} | |||||
$this->throwQueryCodeException(777777, $message); | |||||
} | |||||
} | |||||
return $result; | |||||
} | } | ||||
protected function rawQueries(array $raw_queries) { | protected function rawQueries(array $raw_queries) { | ||||
$conn = $this->requireConnection(); | $conn = $this->requireConnection(); | ||||
$have_result = false; | $have_result = false; | ||||
$results = array(); | $results = array(); | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | final class AphrontMySQLiDatabaseConnection | ||||
public function supportsAsyncQueries() { | public function supportsAsyncQueries() { | ||||
return defined('MYSQLI_ASYNC'); | return defined('MYSQLI_ASYNC'); | ||||
} | } | ||||
public function asyncQuery($raw_query) { | public function asyncQuery($raw_query) { | ||||
$this->checkWrite($raw_query); | $this->checkWrite($raw_query); | ||||
$async = $this->beginAsyncConnection(); | $async = $this->beginAsyncConnection(); | ||||
$async->query($raw_query, MYSQLI_ASYNC); | $async->query($raw_query, MYSQLI_ASYNC); | ||||
Lint: PHP Compatibility This codebase targets PHP 5.2.3, but MYSQLI_ASYNC was not introduced until PHP 5.3.0. Lint: PHP Compatibility: This codebase targets PHP 5.2.3, but `MYSQLI_ASYNC` was not introduced until PHP 5.3.0. | |||||
return $async; | return $async; | ||||
} | } | ||||
public static function resolveAsyncQueries(array $conns, array $asyncs) { | public static function resolveAsyncQueries(array $conns, array $asyncs) { | ||||
assert_instances_of($conns, __CLASS__); | assert_instances_of($conns, __CLASS__); | ||||
assert_instances_of($asyncs, 'mysqli'); | assert_instances_of($asyncs, 'mysqli'); | ||||
$read = $error = $reject = array(); | $read = $error = $reject = array(); | ||||
Show All 19 Lines |
This codebase targets PHP 5.2.3, but MYSQLI_ASYNC was not introduced until PHP 5.3.0.