mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-26 00:32:41 +01:00
Merge all unmerged "libphutil" changes into Aracnist "wilds" branch
Ref T13098.
This commit is contained in:
parent
bd58840220
commit
01d31e291d
32 changed files with 4318 additions and 2555 deletions
|
@ -22,6 +22,8 @@ phutil_register_library_map(array(
|
||||||
'AphrontConnectionQueryException' => 'aphront/storage/exception/AphrontConnectionQueryException.php',
|
'AphrontConnectionQueryException' => 'aphront/storage/exception/AphrontConnectionQueryException.php',
|
||||||
'AphrontCountQueryException' => 'aphront/storage/exception/AphrontCountQueryException.php',
|
'AphrontCountQueryException' => 'aphront/storage/exception/AphrontCountQueryException.php',
|
||||||
'AphrontDatabaseConnection' => 'aphront/storage/connection/AphrontDatabaseConnection.php',
|
'AphrontDatabaseConnection' => 'aphront/storage/connection/AphrontDatabaseConnection.php',
|
||||||
|
'AphrontDatabaseTableRef' => 'xsprintf/AphrontDatabaseTableRef.php',
|
||||||
|
'AphrontDatabaseTableRefInterface' => 'xsprintf/AphrontDatabaseTableRefInterface.php',
|
||||||
'AphrontDatabaseTransactionState' => 'aphront/storage/connection/AphrontDatabaseTransactionState.php',
|
'AphrontDatabaseTransactionState' => 'aphront/storage/connection/AphrontDatabaseTransactionState.php',
|
||||||
'AphrontDeadlockQueryException' => 'aphront/storage/exception/AphrontDeadlockQueryException.php',
|
'AphrontDeadlockQueryException' => 'aphront/storage/exception/AphrontDeadlockQueryException.php',
|
||||||
'AphrontDuplicateKeyQueryException' => 'aphront/storage/exception/AphrontDuplicateKeyQueryException.php',
|
'AphrontDuplicateKeyQueryException' => 'aphront/storage/exception/AphrontDuplicateKeyQueryException.php',
|
||||||
|
@ -793,6 +795,7 @@ phutil_register_library_map(array(
|
||||||
'PhutilPygmentsSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilPygmentsSyntaxHighlighter.php',
|
'PhutilPygmentsSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilPygmentsSyntaxHighlighter.php',
|
||||||
'PhutilPythonFragmentLexer' => 'lexer/PhutilPythonFragmentLexer.php',
|
'PhutilPythonFragmentLexer' => 'lexer/PhutilPythonFragmentLexer.php',
|
||||||
'PhutilQsprintfInterface' => 'xsprintf/PhutilQsprintfInterface.php',
|
'PhutilQsprintfInterface' => 'xsprintf/PhutilQsprintfInterface.php',
|
||||||
|
'PhutilQueryString' => 'xsprintf/PhutilQueryString.php',
|
||||||
'PhutilQueryStringParser' => 'parser/PhutilQueryStringParser.php',
|
'PhutilQueryStringParser' => 'parser/PhutilQueryStringParser.php',
|
||||||
'PhutilQueryStringParserTestCase' => 'parser/__tests__/PhutilQueryStringParserTestCase.php',
|
'PhutilQueryStringParserTestCase' => 'parser/__tests__/PhutilQueryStringParserTestCase.php',
|
||||||
'PhutilRainbowSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilRainbowSyntaxHighlighter.php',
|
'PhutilRainbowSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilRainbowSyntaxHighlighter.php',
|
||||||
|
@ -955,6 +958,7 @@ phutil_register_library_map(array(
|
||||||
'nonempty' => 'utils/utils.php',
|
'nonempty' => 'utils/utils.php',
|
||||||
'phlog' => 'error/phlog.php',
|
'phlog' => 'error/phlog.php',
|
||||||
'pht' => 'internationalization/pht.php',
|
'pht' => 'internationalization/pht.php',
|
||||||
|
'phutil_build_http_querystring' => 'utils/utils.php',
|
||||||
'phutil_censor_credentials' => 'utils/utils.php',
|
'phutil_censor_credentials' => 'utils/utils.php',
|
||||||
'phutil_console_confirm' => 'console/format.php',
|
'phutil_console_confirm' => 'console/format.php',
|
||||||
'phutil_console_format' => 'console/format.php',
|
'phutil_console_format' => 'console/format.php',
|
||||||
|
@ -965,6 +969,7 @@ phutil_register_library_map(array(
|
||||||
'phutil_console_wrap' => 'console/format.php',
|
'phutil_console_wrap' => 'console/format.php',
|
||||||
'phutil_count' => 'internationalization/pht.php',
|
'phutil_count' => 'internationalization/pht.php',
|
||||||
'phutil_date_format' => 'utils/viewutils.php',
|
'phutil_date_format' => 'utils/viewutils.php',
|
||||||
|
'phutil_decode_mime_header' => 'utils/utils.php',
|
||||||
'phutil_deprecated' => 'moduleutils/moduleutils.php',
|
'phutil_deprecated' => 'moduleutils/moduleutils.php',
|
||||||
'phutil_error_listener_example' => 'error/phlog.php',
|
'phutil_error_listener_example' => 'error/phlog.php',
|
||||||
'phutil_escape_html' => 'markup/render.php',
|
'phutil_escape_html' => 'markup/render.php',
|
||||||
|
@ -996,6 +1001,7 @@ phutil_register_library_map(array(
|
||||||
'phutil_json_encode' => 'utils/utils.php',
|
'phutil_json_encode' => 'utils/utils.php',
|
||||||
'phutil_load_library' => 'moduleutils/core.php',
|
'phutil_load_library' => 'moduleutils/core.php',
|
||||||
'phutil_loggable_string' => 'utils/utils.php',
|
'phutil_loggable_string' => 'utils/utils.php',
|
||||||
|
'phutil_microseconds_since' => 'utils/utils.php',
|
||||||
'phutil_parse_bytes' => 'utils/viewutils.php',
|
'phutil_parse_bytes' => 'utils/viewutils.php',
|
||||||
'phutil_passthru' => 'future/exec/execx.php',
|
'phutil_passthru' => 'future/exec/execx.php',
|
||||||
'phutil_person' => 'internationalization/pht.php',
|
'phutil_person' => 'internationalization/pht.php',
|
||||||
|
@ -1075,6 +1081,10 @@ phutil_register_library_map(array(
|
||||||
'Phobject',
|
'Phobject',
|
||||||
'PhutilQsprintfInterface',
|
'PhutilQsprintfInterface',
|
||||||
),
|
),
|
||||||
|
'AphrontDatabaseTableRef' => array(
|
||||||
|
'Phobject',
|
||||||
|
'AphrontDatabaseTableRefInterface',
|
||||||
|
),
|
||||||
'AphrontDatabaseTransactionState' => 'Phobject',
|
'AphrontDatabaseTransactionState' => 'Phobject',
|
||||||
'AphrontDeadlockQueryException' => 'AphrontRecoverableQueryException',
|
'AphrontDeadlockQueryException' => 'AphrontRecoverableQueryException',
|
||||||
'AphrontDuplicateKeyQueryException' => 'AphrontQueryException',
|
'AphrontDuplicateKeyQueryException' => 'AphrontQueryException',
|
||||||
|
@ -1869,6 +1879,7 @@ phutil_register_library_map(array(
|
||||||
'PhutilPygmentizeParserTestCase' => 'PhutilTestCase',
|
'PhutilPygmentizeParserTestCase' => 'PhutilTestCase',
|
||||||
'PhutilPygmentsSyntaxHighlighter' => 'Phobject',
|
'PhutilPygmentsSyntaxHighlighter' => 'Phobject',
|
||||||
'PhutilPythonFragmentLexer' => 'PhutilLexer',
|
'PhutilPythonFragmentLexer' => 'PhutilLexer',
|
||||||
|
'PhutilQueryString' => 'Phobject',
|
||||||
'PhutilQueryStringParser' => 'Phobject',
|
'PhutilQueryStringParser' => 'Phobject',
|
||||||
'PhutilQueryStringParserTestCase' => 'PhutilTestCase',
|
'PhutilQueryStringParserTestCase' => 'PhutilTestCase',
|
||||||
'PhutilRainbowSyntaxHighlighter' => 'Phobject',
|
'PhutilRainbowSyntaxHighlighter' => 'Phobject',
|
||||||
|
|
|
@ -17,7 +17,7 @@ abstract class AphrontDatabaseConnection
|
||||||
abstract public function getInsertID();
|
abstract public function getInsertID();
|
||||||
abstract public function getAffectedRows();
|
abstract public function getAffectedRows();
|
||||||
abstract public function selectAllResults();
|
abstract public function selectAllResults();
|
||||||
abstract public function executeRawQuery($raw_query);
|
abstract public function executeQuery(PhutilQueryString $query);
|
||||||
abstract public function executeRawQueries(array $raw_queries);
|
abstract public function executeRawQueries(array $raw_queries);
|
||||||
abstract public function close();
|
abstract public function close();
|
||||||
abstract public function openConnection();
|
abstract public function openConnection();
|
||||||
|
@ -93,6 +93,27 @@ abstract class AphrontDatabaseConnection
|
||||||
throw new Exception(pht('Async queries are not supported.'));
|
throw new Exception(pht('Async queries are not supported.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this connection idle and safe to close?
|
||||||
|
*
|
||||||
|
* A connection is "idle" if it can be safely closed without loss of state.
|
||||||
|
* Connections inside a transaction or holding locks are not idle, even
|
||||||
|
* though they may not actively be executing queries.
|
||||||
|
*
|
||||||
|
* @return bool True if the connection is idle and can be safely closed.
|
||||||
|
*/
|
||||||
|
public function isIdle() {
|
||||||
|
if ($this->isInsideTransaction()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isHoldingAnyLock()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Global Locks )------------------------------------------------------- */
|
/* -( Global Locks )------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -66,12 +66,15 @@ final class AphrontIsolatedDatabaseConnection
|
||||||
return $this->allResults;
|
return $this->allResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function executeRawQuery($raw_query) {
|
public function executeQuery(PhutilQueryString $query) {
|
||||||
|
|
||||||
// NOTE: "[\s<>K]*" allows any number of (properly escaped) comments to
|
// NOTE: "[\s<>K]*" allows any number of (properly escaped) comments to
|
||||||
// appear prior to the allowed keyword, since this connection escapes
|
// appear prior to the allowed keyword, since this connection escapes
|
||||||
// them as "<K>" (above).
|
// them as "<K>" (above).
|
||||||
|
|
||||||
|
$display_query = $query->getMaskedString();
|
||||||
|
$raw_query = $query->getUnmaskedString();
|
||||||
|
|
||||||
$keywords = array(
|
$keywords = array(
|
||||||
'INSERT',
|
'INSERT',
|
||||||
'UPDATE',
|
'UPDATE',
|
||||||
|
@ -94,10 +97,10 @@ final class AphrontIsolatedDatabaseConnection
|
||||||
"trying to issue a query which does not begin with an allowed ".
|
"trying to issue a query which does not begin with an allowed ".
|
||||||
"keyword (%s): '%s'.",
|
"keyword (%s): '%s'.",
|
||||||
implode(', ', $keywords),
|
implode(', ', $keywords),
|
||||||
$raw_query));
|
$display_query));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->transcript[] = $raw_query;
|
$this->transcript[] = $display_query;
|
||||||
|
|
||||||
// NOTE: This method is intentionally simplified for now, since we're only
|
// NOTE: This method is intentionally simplified for now, since we're only
|
||||||
// using it to stub out inserts/updates. In the future it will probably need
|
// using it to stub out inserts/updates. In the future it will probably need
|
||||||
|
|
|
@ -152,7 +152,10 @@ abstract class AphrontBaseMySQLDatabaseConnection
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function executeRawQuery($raw_query) {
|
public function executeQuery(PhutilQueryString $query) {
|
||||||
|
$display_query = $query->getMaskedString();
|
||||||
|
$raw_query = $query->getUnmaskedString();
|
||||||
|
|
||||||
$this->lastResult = null;
|
$this->lastResult = null;
|
||||||
$retries = max(1, $this->getConfiguration('retries', 3));
|
$retries = max(1, $this->getConfiguration('retries', 3));
|
||||||
while ($retries--) {
|
while ($retries--) {
|
||||||
|
@ -165,7 +168,7 @@ abstract class AphrontBaseMySQLDatabaseConnection
|
||||||
array(
|
array(
|
||||||
'type' => 'query',
|
'type' => 'query',
|
||||||
'config' => $this->configuration,
|
'config' => $this->configuration,
|
||||||
'query' => $raw_query,
|
'query' => $display_query,
|
||||||
'write' => $is_write,
|
'write' => $is_write,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -297,10 +300,10 @@ abstract class AphrontBaseMySQLDatabaseConnection
|
||||||
throw new AphrontConnectionLostQueryException($message);
|
throw new AphrontConnectionLostQueryException($message);
|
||||||
case 2006: // Gone Away
|
case 2006: // Gone Away
|
||||||
$more = pht(
|
$more = pht(
|
||||||
"This error may occur if your MySQL '%s' or '%s' ".
|
'This error may occur if your configured MySQL "wait_timeout" or '.
|
||||||
"configuration values are set too low.",
|
'"max_allowed_packet" values are too small. This may also indicate '.
|
||||||
'wait_timeout',
|
'that something used the MySQL "KILL <process>" command to kill '.
|
||||||
'max_allowed_packet');
|
'the connection running the query.');
|
||||||
throw new AphrontConnectionLostQueryException("{$message}\n\n{$more}");
|
throw new AphrontConnectionLostQueryException("{$message}\n\n{$more}");
|
||||||
case 1213: // Deadlock
|
case 1213: // Deadlock
|
||||||
throw new AphrontDeadlockQueryException($message);
|
throw new AphrontDeadlockQueryException($message);
|
||||||
|
|
|
@ -81,6 +81,11 @@ final class AphrontMySQLiDatabaseConnection
|
||||||
$this->throwConnectionException($errno, $error, $user, $host);
|
$this->throwConnectionException($errno, $error, $user, $host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See T13238. Attempt to prevent "LOAD DATA LOCAL INFILE", which allows a
|
||||||
|
// malicious server to ask the client for any file. At time of writing,
|
||||||
|
// this option MUST be set after "real_connect()" on all PHP versions.
|
||||||
|
$conn->options(MYSQLI_OPT_LOCAL_INFILE, 0);
|
||||||
|
|
||||||
$this->connectionOpen = true;
|
$this->connectionOpen = true;
|
||||||
|
|
||||||
$ok = @$conn->set_charset('utf8mb4');
|
$ok = @$conn->set_charset('utf8mb4');
|
||||||
|
@ -122,7 +127,36 @@ final class AphrontMySQLiDatabaseConnection
|
||||||
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 LOCAL INFILE" 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) {
|
||||||
|
|
|
@ -14,21 +14,11 @@ final class PhutilGoogleAuthAdapter extends PhutilOAuthAuthAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAccountID() {
|
public function getAccountID() {
|
||||||
$emails = $this->getOAuthAccountData('emails', array());
|
return $this->getAccountEmail();
|
||||||
foreach ($emails as $email) {
|
|
||||||
if (idx($email, 'type') == 'account') {
|
|
||||||
return idx($email, 'value');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
'Expected to retrieve an "account" email from Google Plus API call '.
|
|
||||||
'to identify account, but failed.'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAccountEmail() {
|
public function getAccountEmail() {
|
||||||
return $this->getAccountID();
|
return $this->getOAuthAccountData('email');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAccountName() {
|
public function getAccountName() {
|
||||||
|
@ -40,8 +30,7 @@ final class PhutilGoogleAuthAdapter extends PhutilOAuthAuthAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAccountImageURI() {
|
public function getAccountImageURI() {
|
||||||
$image = $this->getOAuthAccountData('image', array());
|
$uri = $this->getOAuthAccountData('picture');
|
||||||
$uri = idx($image, 'url');
|
|
||||||
|
|
||||||
// Change the "sz" parameter ("size") from the default to 100 to ask for
|
// Change the "sz" parameter ("size") from the default to 100 to ask for
|
||||||
// a 100x100px image.
|
// a 100x100px image.
|
||||||
|
@ -55,24 +44,11 @@ final class PhutilGoogleAuthAdapter extends PhutilOAuthAuthAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAccountURI() {
|
public function getAccountURI() {
|
||||||
return $this->getOAuthAccountData('url');
|
return $this->getOAuthAccountData('link');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAccountRealName() {
|
public function getAccountRealName() {
|
||||||
$name = $this->getOAuthAccountData('name', array());
|
return $this->getOAuthAccountData('name');
|
||||||
|
|
||||||
// TODO: This could probably be made cleaner by looking up the API, but
|
|
||||||
// this should work to unbreak logins.
|
|
||||||
|
|
||||||
$parts = array();
|
|
||||||
$parts[] = idx($name, 'givenName');
|
|
||||||
unset($name['givenName']);
|
|
||||||
$parts[] = idx($name, 'familyName');
|
|
||||||
unset($name['familyName']);
|
|
||||||
$parts = array_merge($parts, $name);
|
|
||||||
$parts = array_filter($parts);
|
|
||||||
|
|
||||||
return implode(' ', $parts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getAuthenticateBaseURI() {
|
protected function getAuthenticateBaseURI() {
|
||||||
|
@ -105,77 +81,25 @@ final class PhutilGoogleAuthAdapter extends PhutilOAuthAuthAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadOAuthAccountData() {
|
protected function loadOAuthAccountData() {
|
||||||
$uri = new PhutilURI('https://www.googleapis.com/plus/v1/people/me');
|
$uri = new PhutilURI('https://www.googleapis.com/userinfo/v2/me');
|
||||||
$uri->setQueryParam('access_token', $this->getAccessToken());
|
$uri->setQueryParam('access_token', $this->getAccessToken());
|
||||||
|
|
||||||
$future = new HTTPSFuture($uri);
|
$future = new HTTPSFuture($uri);
|
||||||
list($status, $body) = $future->resolve();
|
list($status, $body) = $future->resolve();
|
||||||
|
|
||||||
if ($status->isError()) {
|
if ($status->isError()) {
|
||||||
$this->tryToThrowSpecializedError($status, $body);
|
|
||||||
throw $status;
|
throw $status;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return phutil_json_decode($body);
|
$result = phutil_json_decode($body);
|
||||||
} catch (PhutilJSONParserException $ex) {
|
} catch (PhutilJSONParserException $ex) {
|
||||||
throw new PhutilProxyException(
|
throw new PhutilProxyException(
|
||||||
pht('Expected valid JSON response from Google account data request.'),
|
pht('Expected valid JSON response from Google account data request.'),
|
||||||
$ex);
|
$ex);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private function tryToThrowSpecializedError($status, $raw_body) {
|
return $result;
|
||||||
if (!($status instanceof HTTPFutureHTTPResponseStatus)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($status->getStatusCode() != 403) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$body = phutil_json_decode($raw_body);
|
|
||||||
if (!$body) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($body['error']['errors'][0])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$error = $body['error']['errors'][0];
|
|
||||||
$domain = idx($error, 'domain');
|
|
||||||
$reason = idx($error, 'reason');
|
|
||||||
|
|
||||||
if ($domain == 'usageLimits' && $reason == 'accessNotConfigured') {
|
|
||||||
throw new PhutilAuthConfigurationException(
|
|
||||||
pht(
|
|
||||||
'Google returned an "%s" error. This usually means you need to '.
|
|
||||||
'enable the "Google+ API" in your Google Cloud Console, under '.
|
|
||||||
'"APIs".'.
|
|
||||||
"\n\n".
|
|
||||||
'Around March 2014, Google made some API changes which require this '.
|
|
||||||
'configuration adjustment.'.
|
|
||||||
"\n\n".
|
|
||||||
'Normally, you can resolve this issue by going to %s, then '.
|
|
||||||
'clicking "API Project", then "APIs & auth", then turning the '.
|
|
||||||
'"Google+ API" on. The names you see on the console may be '.
|
|
||||||
'different depending on how your integration is set up. If you '.
|
|
||||||
'are not sure, you can hunt through the projects until you find '.
|
|
||||||
'the one associated with the right Application ID under '.
|
|
||||||
'"Credentials". The Application ID this install is using is "%s".'.
|
|
||||||
"\n\n".
|
|
||||||
'(If you are unable to log into Phabricator, you can use '.
|
|
||||||
'"%s" to recover access to an administrator account.)'.
|
|
||||||
"\n\n".
|
|
||||||
'Full HTTP Response'.
|
|
||||||
"\n\n%s",
|
|
||||||
'accessNotConfigured',
|
|
||||||
'https://console.developers.google.com/',
|
|
||||||
$this->getClientID(),
|
|
||||||
'bin/auth recover',
|
|
||||||
$raw_body));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -535,6 +535,56 @@ final class Filesystem extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a random integer value in a given range.
|
||||||
|
*
|
||||||
|
* This method uses less-entropic random sources under older versions of PHP.
|
||||||
|
*
|
||||||
|
* @param int Minimum value, inclusive.
|
||||||
|
* @param int Maximum value, inclusive.
|
||||||
|
*/
|
||||||
|
public static function readRandomInteger($min, $max) {
|
||||||
|
if (!is_int($min)) {
|
||||||
|
throw new Exception(pht('Minimum value must be an integer.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_int($max)) {
|
||||||
|
throw new Exception(pht('Maximum value must be an integer.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($min > $max) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Minimum ("%d") must not be greater than maximum ("%d").',
|
||||||
|
$min,
|
||||||
|
$max));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Under PHP 7.2.0 and newer, we can just use "random_int()". This function
|
||||||
|
// is intended to generate cryptographically usable entropy.
|
||||||
|
if (function_exists('random_int')) {
|
||||||
|
return random_int($min, $max);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We could find a stronger source for this, but correctly converting raw
|
||||||
|
// bytes to an integer range without biases is fairly hard and it seems
|
||||||
|
// like we're more likely to get that wrong than suffer a PRNG prediction
|
||||||
|
// issue by falling back to "mt_rand()".
|
||||||
|
|
||||||
|
if (($max - $min) > mt_getrandmax()) {
|
||||||
|
throw new Exception(
|
||||||
|
pht('mt_rand() range is smaller than the requested range.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = mt_rand($min, $max);
|
||||||
|
if (!is_int($result)) {
|
||||||
|
throw new Exception(pht('Bad return value from mt_rand().'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identify the MIME type of a file. This returns only the MIME type (like
|
* Identify the MIME type of a file. This returns only the MIME type (like
|
||||||
* text/plain), not the encoding (like charset=utf-8).
|
* text/plain), not the encoding (like charset=utf-8).
|
||||||
|
|
|
@ -170,4 +170,42 @@ final class FilesystemTestCase extends PhutilTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRandomIntegers() {
|
||||||
|
$valid_ranges = array(
|
||||||
|
array(5, 5),
|
||||||
|
array(-1, 1),
|
||||||
|
array(0, 10000),
|
||||||
|
array(0, 999999999),
|
||||||
|
array(-65535, 65536),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($valid_ranges as $case) {
|
||||||
|
list($min, $max) = $case;
|
||||||
|
|
||||||
|
$result = Filesystem::readRandomInteger($min, $max);
|
||||||
|
|
||||||
|
$this->assertTrue($min <= $result, pht('%d <= %d', $min, $result));
|
||||||
|
$this->assertTrue($max >= $result, pht('%d >= %d', $max, $result));
|
||||||
|
}
|
||||||
|
|
||||||
|
$invalid_ranges = array(
|
||||||
|
array('1', '2'),
|
||||||
|
array(1.0, 2.0),
|
||||||
|
array(5, 3),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($invalid_ranges as $case) {
|
||||||
|
list($min, $max) = $case;
|
||||||
|
|
||||||
|
$caught = null;
|
||||||
|
try {
|
||||||
|
Filesystem::readRandomInteger($min, $max);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$caught = $ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertTrue($caught instanceof Exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -350,8 +350,19 @@ final class ExecFuture extends PhutilExecutableFuture {
|
||||||
list($err, $stdout, $stderr) = $this->resolve($timeout);
|
list($err, $stdout, $stderr) = $this->resolve($timeout);
|
||||||
if ($err) {
|
if ($err) {
|
||||||
$cmd = $this->command;
|
$cmd = $this->command;
|
||||||
|
|
||||||
|
if ($this->getWasKilledByTimeout()) {
|
||||||
|
// NOTE: The timeout can be a float and PhutilNumber only handles
|
||||||
|
// integers, so just use "%s" to render it.
|
||||||
|
$message = pht(
|
||||||
|
'Command killed by timeout after running for more than %s seconds.',
|
||||||
|
$this->terminateTimeout);
|
||||||
|
} else {
|
||||||
|
$message = pht('Command failed with error #%d!', $err);
|
||||||
|
}
|
||||||
|
|
||||||
throw new CommandException(
|
throw new CommandException(
|
||||||
pht('Command failed with error #%d!', $err),
|
$message,
|
||||||
$cmd,
|
$cmd,
|
||||||
$err,
|
$err,
|
||||||
$stdout,
|
$stdout,
|
||||||
|
|
|
@ -273,7 +273,7 @@ abstract class BaseHTTPFuture extends Future {
|
||||||
return strlen($data);
|
return strlen($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return strlen(http_build_query($data, '', '&'));
|
return strlen(phutil_build_http_querystring($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -244,7 +244,7 @@ final class HTTPFuture extends BaseHTTPFuture {
|
||||||
|
|
||||||
if ($this->getMethod() == 'GET') {
|
if ($this->getMethod() == 'GET') {
|
||||||
if (is_array($data)) {
|
if (is_array($data)) {
|
||||||
$data = http_build_query($data, '', '&');
|
$data = phutil_build_http_querystring($data);
|
||||||
if (strpos($uri, '?') !== false) {
|
if (strpos($uri, '?') !== false) {
|
||||||
$uri .= '&'.$data;
|
$uri .= '&'.$data;
|
||||||
} else {
|
} else {
|
||||||
|
@ -254,7 +254,7 @@ final class HTTPFuture extends BaseHTTPFuture {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_array($data)) {
|
if (is_array($data)) {
|
||||||
$data = http_build_query($data, '', '&')."\r\n";
|
$data = phutil_build_http_querystring($data)."\r\n";
|
||||||
$add_headers[] = array(
|
$add_headers[] = array(
|
||||||
'Content-Type',
|
'Content-Type',
|
||||||
'application/x-www-form-urlencoded',
|
'application/x-www-form-urlencoded',
|
||||||
|
|
|
@ -524,7 +524,7 @@ final class HTTPSFuture extends BaseHTTPFuture {
|
||||||
// If we don't have any files, just encode the data as a query string,
|
// If we don't have any files, just encode the data as a query string,
|
||||||
// make sure it's not including any files, and we're good to go.
|
// make sure it's not including any files, and we're good to go.
|
||||||
if (is_array($data)) {
|
if (is_array($data)) {
|
||||||
$data = http_build_query($data, '', '&');
|
$data = phutil_build_http_querystring($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->checkForDangerousCURLMagic($data, $is_query_string = true);
|
$this->checkForDangerousCURLMagic($data, $is_query_string = true);
|
||||||
|
|
|
@ -6,6 +6,7 @@ final class PhutilPostmarkFuture extends FutureProxy {
|
||||||
private $accessToken;
|
private $accessToken;
|
||||||
private $method;
|
private $method;
|
||||||
private $parameters;
|
private $parameters;
|
||||||
|
private $timeout;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
parent::__construct(null);
|
parent::__construct(null);
|
||||||
|
@ -27,6 +28,15 @@ final class PhutilPostmarkFuture extends FutureProxy {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setTimeout($timeout) {
|
||||||
|
$this->timeout = $timeout;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTimeout() {
|
||||||
|
return $this->timeout;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getProxiedFuture() {
|
protected function getProxiedFuture() {
|
||||||
if (!$this->future) {
|
if (!$this->future) {
|
||||||
if ($this->accessToken === null) {
|
if ($this->accessToken === null) {
|
||||||
|
@ -49,6 +59,11 @@ final class PhutilPostmarkFuture extends FutureProxy {
|
||||||
->addHeader('Accept', 'application/json')
|
->addHeader('Accept', 'application/json')
|
||||||
->addHeader('Content-Type', 'application/json');
|
->addHeader('Content-Type', 'application/json');
|
||||||
|
|
||||||
|
$timeout = $this->getTimeout();
|
||||||
|
if ($timeout) {
|
||||||
|
$future->setTimeout($timeout);
|
||||||
|
}
|
||||||
|
|
||||||
$this->future = $future;
|
$this->future = $future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ final class PhutilJavaFragmentLexer extends PhutilLexer {
|
||||||
array('(package|import\\s+static|import)\\b', 'kn', 'import'),
|
array('(package|import\\s+static|import)\\b', 'kn', 'import'),
|
||||||
array('('.implode('|', $constants).')\\b', 'kc'),
|
array('('.implode('|', $constants).')\\b', 'kc'),
|
||||||
array('(class|interface)\\b', 'kd', 'class'),
|
array('(class|interface)\\b', 'kd', 'class'),
|
||||||
array('"(\\\\\\\\|\\\\"|[^"]+)*"', 's'),
|
array('"(\\\\.|[^"\\\\]+)*"', 's'),
|
||||||
array("'(\\\\.|[^\\\\]|\\\\u[0-9a-f-A-F]{4})'", 's'),
|
array("'(\\\\.|[^\\\\]|\\\\u[0-9a-f-A-F]{4})'", 's'),
|
||||||
array('([^\\W\\d]|\\$)[\\w$]*:', 'nl'),
|
array('([^\\W\\d]|\\$)[\\w$]*:', 'nl'),
|
||||||
array('([^\\W\\d]|\\$)[\\w$]*', 'n'),
|
array('([^\\W\\d]|\\$)[\\w$]*', 'n'),
|
||||||
|
|
|
@ -11,7 +11,7 @@ final class PhutilRemarkupTestInterpreterRule
|
||||||
return sprintf(
|
return sprintf(
|
||||||
"Content: (%s)\nArgv: (%s)",
|
"Content: (%s)\nArgv: (%s)",
|
||||||
$content,
|
$content,
|
||||||
http_build_query($argv));
|
phutil_build_http_querystring($argv));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,15 +21,28 @@ final class PhutilPygmentsSyntaxHighlighter extends Phobject {
|
||||||
|
|
||||||
if ($language) {
|
if ($language) {
|
||||||
$language = $this->getPygmentsLexerNameFromLanguageName($language);
|
$language = $this->getPygmentsLexerNameFromLanguageName($language);
|
||||||
|
|
||||||
|
// See T13224. Under Ubuntu, avoid leaving an intermedite "dash" shell
|
||||||
|
// process so we hit "pygmentize" directly if we have to SIGKILL this
|
||||||
|
// because it explodes.
|
||||||
|
|
||||||
$future = new ExecFuture(
|
$future = new ExecFuture(
|
||||||
'pygmentize -O encoding=utf-8 -O stripnl=False -f html -l %s',
|
'exec pygmentize -O encoding=utf-8 -O stripnl=False -f html -l %s',
|
||||||
$language);
|
$language);
|
||||||
|
|
||||||
$scrub = false;
|
$scrub = false;
|
||||||
if ($language == 'php' && strpos($source, '<?') === false) {
|
if ($language == 'php' && strpos($source, '<?') === false) {
|
||||||
$source = "<?php\n".$source;
|
$source = "<?php\n".$source;
|
||||||
$scrub = true;
|
$scrub = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See T13224. In some cases, "pygmentize" has explosive runtime on small
|
||||||
|
// inputs. Put a hard cap on how long it is allowed to run for to limit
|
||||||
|
// the amount of damage it can do.
|
||||||
|
$future->setTimeout(15);
|
||||||
|
|
||||||
$future->write($source);
|
$future->write($source);
|
||||||
|
|
||||||
return new PhutilDefaultSyntaxHighlighterEnginePygmentsFuture(
|
return new PhutilDefaultSyntaxHighlighterEnginePygmentsFuture(
|
||||||
$future,
|
$future,
|
||||||
$source,
|
$source,
|
||||||
|
|
|
@ -174,7 +174,7 @@ final class PhutilURI extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->query) {
|
if ($this->query) {
|
||||||
$query = '?'.http_build_query($this->query, '', '&');
|
$query = '?'.phutil_build_http_querystring($this->query);
|
||||||
} else {
|
} else {
|
||||||
$query = null;
|
$query = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,10 @@ final class PhutilArgumentSpellingCorrector extends Phobject {
|
||||||
|
|
||||||
private $editDistanceMatrix;
|
private $editDistanceMatrix;
|
||||||
private $maximumDistance;
|
private $maximumDistance;
|
||||||
|
private $mode;
|
||||||
|
|
||||||
|
const MODE_COMMANDS = 'commands';
|
||||||
|
const MODE_FLAGS = 'flags';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a new corrector with parameters for correcting commands, like
|
* Build a new corrector with parameters for correcting commands, like
|
||||||
|
@ -31,6 +35,7 @@ final class PhutilArgumentSpellingCorrector extends Phobject {
|
||||||
|
|
||||||
return id(new self())
|
return id(new self())
|
||||||
->setEditDistanceMatrix($matrix)
|
->setEditDistanceMatrix($matrix)
|
||||||
|
->setMode(self::MODE_COMMANDS)
|
||||||
->setMaximumDistance($max_distance);
|
->setMaximumDistance($max_distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,9 +60,19 @@ final class PhutilArgumentSpellingCorrector extends Phobject {
|
||||||
|
|
||||||
return id(new self())
|
return id(new self())
|
||||||
->setEditDistanceMatrix($matrix)
|
->setEditDistanceMatrix($matrix)
|
||||||
|
->setMode(self::MODE_FLAGS)
|
||||||
->setMaximumDistance($max_distance);
|
->setMaximumDistance($max_distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setMode($mode) {
|
||||||
|
$this->mode = $mode;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMode() {
|
||||||
|
return $this->mode;
|
||||||
|
}
|
||||||
|
|
||||||
public function setEditDistanceMatrix(PhutilEditDistanceMatrix $matrix) {
|
public function setEditDistanceMatrix(PhutilEditDistanceMatrix $matrix) {
|
||||||
$this->editDistanceMatrix = $matrix;
|
$this->editDistanceMatrix = $matrix;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -87,6 +102,14 @@ final class PhutilArgumentSpellingCorrector extends Phobject {
|
||||||
throw new PhutilInvalidStateException('setMaximumDistance');
|
throw new PhutilInvalidStateException('setMaximumDistance');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're correcting commands, never correct an input which begins
|
||||||
|
// with "-", since this is almost certainly intended to be a flag.
|
||||||
|
if ($this->getMode() === self::MODE_COMMANDS) {
|
||||||
|
if (preg_match('/^-/', $input)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$input = $this->normalizeString($input);
|
$input = $this->normalizeString($input);
|
||||||
foreach ($options as $key => $option) {
|
foreach ($options as $key => $option) {
|
||||||
$options[$key] = $this->normalizeString($option);
|
$options[$key] = $this->normalizeString($option);
|
||||||
|
|
599
src/parser/xhpast/__tests__/data/anonymous_class.php.test
Normal file
599
src/parser/xhpast/__tests__/data/anonymous_class.php.test
Normal file
|
@ -0,0 +1,599 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$a = new class {};
|
||||||
|
$b = new class(10) extends c implements d {
|
||||||
|
private $num;
|
||||||
|
|
||||||
|
public function __construct($num) {
|
||||||
|
$this->num = $num;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
~~~~~~~~~~
|
||||||
|
pass
|
||||||
|
~~~~~~~~~~
|
||||||
|
{
|
||||||
|
"tree": [
|
||||||
|
9000,
|
||||||
|
0,
|
||||||
|
64,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9006,
|
||||||
|
0,
|
||||||
|
63,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9007,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9004,
|
||||||
|
2,
|
||||||
|
12,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9077,
|
||||||
|
2,
|
||||||
|
11,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9047,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9081,
|
||||||
|
4,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9074,
|
||||||
|
6,
|
||||||
|
11,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9051,
|
||||||
|
8,
|
||||||
|
11,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
8,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9005
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9005
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9005
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9006,
|
||||||
|
10,
|
||||||
|
11
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9005
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9004,
|
||||||
|
14,
|
||||||
|
63,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9077,
|
||||||
|
14,
|
||||||
|
62,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9047,
|
||||||
|
14,
|
||||||
|
14
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9081,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9074,
|
||||||
|
18,
|
||||||
|
62,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9051,
|
||||||
|
20,
|
||||||
|
62,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
20,
|
||||||
|
20
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9005
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9054,
|
||||||
|
25,
|
||||||
|
27,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9090,
|
||||||
|
27,
|
||||||
|
27
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9055,
|
||||||
|
29,
|
||||||
|
31,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9090,
|
||||||
|
31,
|
||||||
|
31
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9006,
|
||||||
|
33,
|
||||||
|
62,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9004,
|
||||||
|
35,
|
||||||
|
38,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9063,
|
||||||
|
35,
|
||||||
|
37,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9070,
|
||||||
|
35,
|
||||||
|
35,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9013,
|
||||||
|
35,
|
||||||
|
35
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9064,
|
||||||
|
37,
|
||||||
|
37,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9047,
|
||||||
|
37,
|
||||||
|
37
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9005
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9004,
|
||||||
|
40,
|
||||||
|
60,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9067,
|
||||||
|
40,
|
||||||
|
60,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9068,
|
||||||
|
40,
|
||||||
|
40,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9013,
|
||||||
|
40,
|
||||||
|
40
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9005
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9013,
|
||||||
|
44,
|
||||||
|
44
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9059,
|
||||||
|
45,
|
||||||
|
47,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9060,
|
||||||
|
46,
|
||||||
|
46,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9005
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9047,
|
||||||
|
46,
|
||||||
|
46
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9005
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9005
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9005
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9006,
|
||||||
|
49,
|
||||||
|
60,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9004,
|
||||||
|
51,
|
||||||
|
58,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9077,
|
||||||
|
51,
|
||||||
|
57,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9092,
|
||||||
|
51,
|
||||||
|
53,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9047,
|
||||||
|
51,
|
||||||
|
51
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9013,
|
||||||
|
53,
|
||||||
|
53
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9081,
|
||||||
|
55,
|
||||||
|
55
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9047,
|
||||||
|
57,
|
||||||
|
57
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
9095,
|
||||||
|
21,
|
||||||
|
23,
|
||||||
|
[
|
||||||
|
[
|
||||||
|
9086,
|
||||||
|
22,
|
||||||
|
22
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"stream": [
|
||||||
|
[
|
||||||
|
373,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
313,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
61,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
302,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
358,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
123,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
125,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
59,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
313,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
61,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
302,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
358,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
40,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
309,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
41,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
360,
|
||||||
|
7
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
311,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
361,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
311,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
123,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
[
|
||||||
|
350,
|
||||||
|
7
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
313,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
[
|
||||||
|
59,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
[
|
||||||
|
352,
|
||||||
|
6
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
339,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
311,
|
||||||
|
11
|
||||||
|
],
|
||||||
|
[
|
||||||
|
40,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
313,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
[
|
||||||
|
41,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
123,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
313,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
362,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
311,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
61,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
313,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
[
|
||||||
|
59,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
[
|
||||||
|
125,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
125,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
59,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
377,
|
||||||
|
1
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ final class PhutilXHPASTBinary extends Phobject {
|
||||||
* This is the version that would be obtained with an up-to-date XHPAST
|
* This is the version that would be obtained with an up-to-date XHPAST
|
||||||
* build. The //actual// XHPAST build version may vary.
|
* build. The //actual// XHPAST build version may vary.
|
||||||
*/
|
*/
|
||||||
const EXPECTED_VERSION = '7.1.2';
|
const EXPECTED_VERSION = '7.1.3';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The XHPAST build version.
|
* The XHPAST build version.
|
||||||
|
|
|
@ -671,13 +671,9 @@ final class PhutilUtilsTestCase extends PhutilTestCase {
|
||||||
phutil_var_export(
|
phutil_var_export(
|
||||||
array('foo' => array('bar' => array('baz' => array())))));
|
array('foo' => array('bar' => array('baz' => array())))));
|
||||||
|
|
||||||
// Objects
|
// NOTE: Object behavior differs across PHP versions. Older versions of
|
||||||
$this->assertEqual(
|
// PHP export objects as "stdClass::__set_state(array())". Newer versions
|
||||||
"stdClass::__set_state(array(\n))",
|
// of PHP (7.3+) export objects as "(object) array()".
|
||||||
phutil_var_export(new stdClass()));
|
|
||||||
$this->assertEqual(
|
|
||||||
"PhutilTestPhobject::__set_state(array(\n))",
|
|
||||||
phutil_var_export(new PhutilTestPhobject()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testFnmatch() {
|
public function testFnmatch() {
|
||||||
|
@ -883,4 +879,43 @@ final class PhutilUtilsTestCase extends PhutilTestCase {
|
||||||
return array_select_keys($map, $keys);
|
return array_select_keys($map, $keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testQueryStringEncoding() {
|
||||||
|
$expect = array();
|
||||||
|
|
||||||
|
// As a starting point, we expect every character to encode as an "%XX"
|
||||||
|
// escaped version.
|
||||||
|
foreach (range(0, 255) as $byte) {
|
||||||
|
$c = chr($byte);
|
||||||
|
$expect[$c] = sprintf('%%%02X', $byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We expect these characters to not be escaped.
|
||||||
|
$ranges = array(
|
||||||
|
range('a', 'z'),
|
||||||
|
range('A', 'Z'),
|
||||||
|
range('0', '9'),
|
||||||
|
array('-', '.', '_', '~'),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($ranges as $range) {
|
||||||
|
foreach ($range as $preserve_char) {
|
||||||
|
$expect[$preserve_char] = $preserve_char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (range(0, 255) as $byte) {
|
||||||
|
$c = chr($byte);
|
||||||
|
|
||||||
|
$expect_c = $expect[$c];
|
||||||
|
$expect_str = "{$expect_c}={$expect_c}";
|
||||||
|
|
||||||
|
$actual_str = phutil_build_http_querystring(array($c => $c));
|
||||||
|
|
||||||
|
$this->assertEqual(
|
||||||
|
$expect_str,
|
||||||
|
$actual_str,
|
||||||
|
pht('HTTP querystring for byte "%s".', sprintf('0x%02x', $byte)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1014,7 +1014,19 @@ function phutil_fwrite_nonblocking_stream($stream, $bytes) {
|
||||||
$write = array($stream);
|
$write = array($stream);
|
||||||
$except = array();
|
$except = array();
|
||||||
|
|
||||||
@stream_select($read, $write, $except, 0);
|
$result = @stream_select($read, $write, $except, 0);
|
||||||
|
if ($result === false) {
|
||||||
|
// See T13243. If the select is interrupted by a signal, it may return
|
||||||
|
// "false" indicating an underlying EINTR condition. In this case, the
|
||||||
|
// results (notably, "$write") are not usable because "stream_select()"
|
||||||
|
// didn't update them.
|
||||||
|
|
||||||
|
// In this case, treat this stream as blocked and tell the caller to
|
||||||
|
// retry, since EINTR is the only condition we're currently aware of that
|
||||||
|
// can cause "fread()" to return "0" and "stream_select()" to return
|
||||||
|
// "false" on the same stream.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$write) {
|
if (!$write) {
|
||||||
// The stream isn't writable, so we conclude that it probably really is
|
// The stream isn't writable, so we conclude that it probably really is
|
||||||
|
@ -1137,6 +1149,29 @@ function phutil_units($description) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the number of microseconds that have elapsed since an earlier
|
||||||
|
* timestamp (from `microtime(true)`).
|
||||||
|
*
|
||||||
|
* @param double Microsecond-precision timestamp, from `microtime(true)`.
|
||||||
|
* @return int Elapsed microseconds.
|
||||||
|
*/
|
||||||
|
function phutil_microseconds_since($timestamp) {
|
||||||
|
if (!is_float($timestamp)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Argument to "phutil_microseconds_since(...)" should be a value '.
|
||||||
|
'returned from "microtime(true)".'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$delta = (microtime(true) - $timestamp);
|
||||||
|
$delta = 1000000 * $delta;
|
||||||
|
$delta = (int)$delta;
|
||||||
|
|
||||||
|
return $delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a JSON dictionary.
|
* Decode a JSON dictionary.
|
||||||
*
|
*
|
||||||
|
@ -1514,3 +1549,39 @@ function phutil_hashes_are_identical($u, $v) {
|
||||||
|
|
||||||
return ($bits === 0);
|
return ($bits === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a query string from a dictionary.
|
||||||
|
*
|
||||||
|
* @param map<string, string> Dictionary of parameters.
|
||||||
|
* @return string HTTP query string.
|
||||||
|
*/
|
||||||
|
function phutil_build_http_querystring(array $parameters) {
|
||||||
|
// We want to encode in RFC3986 mode, but "http_build_query()" did not get
|
||||||
|
// a flag for that mode until PHP 5.4.0. This is equivalent to calling
|
||||||
|
// "http_build_query()" with the "PHP_QUERY_RFC3986" flag.
|
||||||
|
|
||||||
|
$query = array();
|
||||||
|
foreach ($parameters as $key => $value) {
|
||||||
|
$query[] = rawurlencode($key).'='.rawurlencode($value);
|
||||||
|
}
|
||||||
|
$query = implode($query, '&');
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
function phutil_decode_mime_header($header) {
|
||||||
|
if (function_exists('iconv_mime_decode')) {
|
||||||
|
return iconv_mime_decode($header, 0, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('mb_decode_mimeheader')) {
|
||||||
|
return mb_decode_mimeheader($header);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Unable to decode MIME header: install "iconv" or "mbstring" '.
|
||||||
|
'extension.'));
|
||||||
|
}
|
||||||
|
|
23
src/xsprintf/AphrontDatabaseTableRef.php
Normal file
23
src/xsprintf/AphrontDatabaseTableRef.php
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class AphrontDatabaseTableRef
|
||||||
|
extends Phobject
|
||||||
|
implements AphrontDatabaseTableRefInterface {
|
||||||
|
|
||||||
|
private $database;
|
||||||
|
private $table;
|
||||||
|
|
||||||
|
public function __construct($database, $table) {
|
||||||
|
$this->database = $database;
|
||||||
|
$this->table = $table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAphrontRefDatabaseName() {
|
||||||
|
return $this->database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAphrontRefTableName() {
|
||||||
|
return $this->table;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
src/xsprintf/AphrontDatabaseTableRefInterface.php
Normal file
8
src/xsprintf/AphrontDatabaseTableRefInterface.php
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface AphrontDatabaseTableRefInterface {
|
||||||
|
|
||||||
|
public function getAphrontRefDatabaseName();
|
||||||
|
public function getAphrontRefTableName();
|
||||||
|
|
||||||
|
}
|
39
src/xsprintf/PhutilQueryString.php
Normal file
39
src/xsprintf/PhutilQueryString.php
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhutilQueryString extends Phobject {
|
||||||
|
|
||||||
|
private $escaper;
|
||||||
|
private $argv;
|
||||||
|
|
||||||
|
public function __construct(PhutilQsprintfInterface $escaper, array $argv) {
|
||||||
|
$this->escaper = $escaper;
|
||||||
|
$this->argv = $argv;
|
||||||
|
|
||||||
|
// This makes sure we throw immediately if there are errors in the
|
||||||
|
// parameters.
|
||||||
|
$this->getMaskedString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString() {
|
||||||
|
return $this->getMaskedString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUnmaskedString() {
|
||||||
|
return $this->renderString(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMaskedString() {
|
||||||
|
return $this->renderString(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renderString($unmasked) {
|
||||||
|
return xsprintf(
|
||||||
|
'xsprintf_query',
|
||||||
|
array(
|
||||||
|
'escaper' => $this->escaper,
|
||||||
|
'unmasked' => $unmasked,
|
||||||
|
),
|
||||||
|
$this->argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,23 +20,34 @@
|
||||||
* "List" versions of %d, %s, %f and %B. These are appropriate for use in
|
* "List" versions of %d, %s, %f and %B. These are appropriate for use in
|
||||||
* an "IN" clause. For example:
|
* an "IN" clause. For example:
|
||||||
*
|
*
|
||||||
* qsprintf($escaper, 'WHERE hatID IN(%Ld)', $list_of_hats);
|
* qsprintf($escaper, 'WHERE hatID IN (%Ld)', $list_of_hats);
|
||||||
*
|
*
|
||||||
* %B ("Binary String")
|
* %B ("Binary String")
|
||||||
* Escapes a string for insertion into a pure binary column, ignoring
|
* Escapes a string for insertion into a pure binary column, ignoring
|
||||||
* tests for characters outside of the basic multilingual plane.
|
* tests for characters outside of the basic multilingual plane.
|
||||||
*
|
*
|
||||||
* %T ("Table")
|
* %C, %LC, %LK ("Column", "Key Column")
|
||||||
* Escapes a table name.
|
* Escapes a column name or a list of column names. The "%LK" variant
|
||||||
*
|
* escapes a list of key column specifications which may look like
|
||||||
* %C, %LC
|
* "column(32)".
|
||||||
* Escapes a column name or a list of column names.
|
|
||||||
*
|
*
|
||||||
* %K ("Comment")
|
* %K ("Comment")
|
||||||
* Escapes a comment.
|
* Escapes a comment.
|
||||||
*
|
*
|
||||||
* %Q ("Query Fragment")
|
* %Q, %LA, %LO, %LQ, %LJ ("Query Fragment")
|
||||||
* Injects a raw query fragment. Extremely dangerous! Not escaped!
|
* Injects a query fragment from a prior call to qsprintf(). The list
|
||||||
|
* variants join a list of query fragments with AND, OR, comma, or space.
|
||||||
|
*
|
||||||
|
* %Z ("Raw Query")
|
||||||
|
* Injects a raw, unescaped query fragment. Dangerous!
|
||||||
|
*
|
||||||
|
* %R ("Database and Table Reference")
|
||||||
|
* Behaves like "%T.%T" and prints a full reference to a table including
|
||||||
|
* the database. Accepts a AphrontDatabaseTableRefInterface.
|
||||||
|
*
|
||||||
|
* %P ("Password or Secret")
|
||||||
|
* Behaves like "%s", but shows "********" when the query is printed in
|
||||||
|
* logs or traces. Accepts a PhutilOpaqueEnvelope.
|
||||||
*
|
*
|
||||||
* %~ ("Substring")
|
* %~ ("Substring")
|
||||||
* Escapes a substring query for a LIKE (or NOT LIKE) clause. For example:
|
* Escapes a substring query for a LIKE (or NOT LIKE) clause. For example:
|
||||||
|
@ -57,16 +68,19 @@
|
||||||
*
|
*
|
||||||
* // Find all rows where `name` ends with $suffix.
|
* // Find all rows where `name` ends with $suffix.
|
||||||
* qsprintf($escaper, 'WHERE name LIKE %<', $suffix);
|
* qsprintf($escaper, 'WHERE name LIKE %<', $suffix);
|
||||||
|
*
|
||||||
|
* %T ("Table")
|
||||||
|
* Escapes a table name. In most cases, you should use "%R" instead.
|
||||||
*/
|
*/
|
||||||
function qsprintf(PhutilQsprintfInterface $escaper, $pattern /* , ... */) {
|
function qsprintf(PhutilQsprintfInterface $escaper, $pattern /* , ... */) {
|
||||||
$args = func_get_args();
|
$args = func_get_args();
|
||||||
array_shift($args);
|
array_shift($args);
|
||||||
return xsprintf('xsprintf_query', $escaper, $args);
|
return new PhutilQueryString($escaper, $args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function vqsprintf(PhutilQsprintfInterface $escaper, $pattern, array $argv) {
|
function vqsprintf(PhutilQsprintfInterface $escaper, $pattern, array $argv) {
|
||||||
array_unshift($argv, $pattern);
|
array_unshift($argv, $pattern);
|
||||||
return xsprintf('xsprintf_query', $escaper, $argv);
|
return new PhutilQueryString($escaper, $argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,12 +88,19 @@ function vqsprintf(PhutilQsprintfInterface $escaper, $pattern, array $argv) {
|
||||||
* @{function:qsprintf}.
|
* @{function:qsprintf}.
|
||||||
*/
|
*/
|
||||||
function xsprintf_query($userdata, &$pattern, &$pos, &$value, &$length) {
|
function xsprintf_query($userdata, &$pattern, &$pos, &$value, &$length) {
|
||||||
$type = $pattern[$pos];
|
$type = $pattern[$pos];
|
||||||
$escaper = $userdata;
|
|
||||||
$next = (strlen($pattern) > $pos + 1) ? $pattern[$pos + 1] : null;
|
|
||||||
|
|
||||||
|
if (is_array($userdata)) {
|
||||||
|
$escaper = $userdata['escaper'];
|
||||||
|
$unmasked = $userdata['unmasked'];
|
||||||
|
} else {
|
||||||
|
$escaper = $userdata;
|
||||||
|
$unmasked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$next = (strlen($pattern) > $pos + 1) ? $pattern[$pos + 1] : null;
|
||||||
$nullable = false;
|
$nullable = false;
|
||||||
$done = false;
|
$done = false;
|
||||||
|
|
||||||
$prefix = '';
|
$prefix = '';
|
||||||
|
|
||||||
|
@ -162,6 +183,73 @@ function xsprintf_query($userdata, &$pattern, &$pos, &$value, &$length) {
|
||||||
}
|
}
|
||||||
$value = implode(', ', $value);
|
$value = implode(', ', $value);
|
||||||
break;
|
break;
|
||||||
|
case 'K': // ...key columns.
|
||||||
|
// This is like "%LC", but for escaping column lists passed to key
|
||||||
|
// specifications. These should be escaped as "`column`(123)". For
|
||||||
|
// example:
|
||||||
|
//
|
||||||
|
// ALTER TABLE `x` ADD KEY `y` (`u`(16), `v`(32));
|
||||||
|
|
||||||
|
foreach ($value as $k => $v) {
|
||||||
|
$matches = null;
|
||||||
|
if (preg_match('/\((\d+)\)\z/', $v, $matches)) {
|
||||||
|
$v = substr($v, 0, -(strlen($matches[1]) + 2));
|
||||||
|
$prefix_len = '('.((int)$matches[1]).')';
|
||||||
|
} else {
|
||||||
|
$prefix_len = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$value[$k] = $escaper->escapeColumnName($v).$prefix_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = implode(', ', $value);
|
||||||
|
break;
|
||||||
|
case 'Q':
|
||||||
|
// TODO: Here, and in "%LO", "%LA", and "%LJ", we should eventually
|
||||||
|
// stop accepting strings.
|
||||||
|
foreach ($value as $k => $v) {
|
||||||
|
if (is_string($v)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$value[$k] = $v->getUnmaskedString();
|
||||||
|
}
|
||||||
|
$value = implode(', ', $value);
|
||||||
|
break;
|
||||||
|
case 'O':
|
||||||
|
foreach ($value as $k => $v) {
|
||||||
|
if (is_string($v)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$value[$k] = $v->getUnmaskedString();
|
||||||
|
}
|
||||||
|
if (count($value) == 1) {
|
||||||
|
$value = '('.head($value).')';
|
||||||
|
} else {
|
||||||
|
$value = '(('.implode(') OR (', $value).'))';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
foreach ($value as $k => $v) {
|
||||||
|
if (is_string($v)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$value[$k] = $v->getUnmaskedString();
|
||||||
|
}
|
||||||
|
if (count($value) == 1) {
|
||||||
|
$value = '('.head($value).')';
|
||||||
|
} else {
|
||||||
|
$value = '(('.implode(') AND (', $value).'))';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
foreach ($value as $k => $v) {
|
||||||
|
if (is_string($v)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$value[$k] = $v->getUnmaskedString();
|
||||||
|
}
|
||||||
|
$value = implode(' ', $value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new XsprintfUnknownConversionException("%L{$next}");
|
throw new XsprintfUnknownConversionException("%L{$next}");
|
||||||
}
|
}
|
||||||
|
@ -190,6 +278,13 @@ function xsprintf_query($userdata, &$pattern, &$pos, &$value, &$length) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Q': // Query Fragment
|
case 'Q': // Query Fragment
|
||||||
|
if ($value instanceof PhutilQueryString) {
|
||||||
|
$value = $value->getUnmaskedString();
|
||||||
|
}
|
||||||
|
$type = 's';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Z': // Raw Query Fragment
|
||||||
$type = 's';
|
$type = 's';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -234,6 +329,27 @@ function xsprintf_query($userdata, &$pattern, &$pos, &$value, &$length) {
|
||||||
$type = 's';
|
$type = 's';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'R': // Database + Table Reference
|
||||||
|
$database_name = $value->getAphrontRefDatabaseName();
|
||||||
|
$database_name = $escaper->escapeColumnName($database_name);
|
||||||
|
|
||||||
|
$table_name = $value->getAphrontRefTableName();
|
||||||
|
$table_name = $escaper->escapeColumnName($table_name);
|
||||||
|
|
||||||
|
$value = $database_name.'.'.$table_name;
|
||||||
|
$type = 's';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'P': // Password or Secret
|
||||||
|
if ($unmasked) {
|
||||||
|
$value = $value->openEnvelope();
|
||||||
|
$value = "'".$escaper->escapeUTF8String($value)."'";
|
||||||
|
} else {
|
||||||
|
$value = '********';
|
||||||
|
}
|
||||||
|
$type = 's';
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new XsprintfUnknownConversionException($type);
|
throw new XsprintfUnknownConversionException($type);
|
||||||
}
|
}
|
||||||
|
@ -242,6 +358,7 @@ function xsprintf_query($userdata, &$pattern, &$pos, &$value, &$length) {
|
||||||
if ($prefix) {
|
if ($prefix) {
|
||||||
$value = $prefix.$value;
|
$value = $prefix.$value;
|
||||||
}
|
}
|
||||||
|
|
||||||
$pattern[$pos] = $type;
|
$pattern[$pos] = $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,8 +367,13 @@ function qsprintf_check_type($value, $type, $query) {
|
||||||
case 'Ld':
|
case 'Ld':
|
||||||
case 'Ls':
|
case 'Ls':
|
||||||
case 'LC':
|
case 'LC':
|
||||||
|
case 'LK':
|
||||||
case 'LB':
|
case 'LB':
|
||||||
case 'Lf':
|
case 'Lf':
|
||||||
|
case 'LQ':
|
||||||
|
case 'LA':
|
||||||
|
case 'LO':
|
||||||
|
case 'LJ':
|
||||||
if (!is_array($value)) {
|
if (!is_array($value)) {
|
||||||
throw new AphrontParameterQueryException(
|
throw new AphrontParameterQueryException(
|
||||||
$query,
|
$query,
|
||||||
|
@ -275,8 +397,62 @@ function qsprintf_check_type($value, $type, $query) {
|
||||||
|
|
||||||
function qsprintf_check_scalar_type($value, $type, $query) {
|
function qsprintf_check_scalar_type($value, $type, $query) {
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
|
case 'LQ':
|
||||||
|
case 'LA':
|
||||||
|
case 'LO':
|
||||||
|
case 'LJ':
|
||||||
|
// TODO: See T13217. Remove this eventually.
|
||||||
|
if (is_string($value)) {
|
||||||
|
phlog(
|
||||||
|
pht(
|
||||||
|
'UNSAFE: Raw string ("%s") passed to query ("%s") subclause '.
|
||||||
|
'for "%%%s" conversion. Subclause conversions should be passed '.
|
||||||
|
'a list of PhutilQueryString objects.',
|
||||||
|
$value,
|
||||||
|
$query,
|
||||||
|
$type));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($value instanceof PhutilQueryString)) {
|
||||||
|
throw new AphrontParameterQueryException(
|
||||||
|
$query,
|
||||||
|
pht(
|
||||||
|
'Expected a list of PhutilQueryString objects for %%%s '.
|
||||||
|
'conversion.',
|
||||||
|
$type));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'Q':
|
case 'Q':
|
||||||
|
// TODO: See T13217. Remove this eventually.
|
||||||
|
if (is_string($value)) {
|
||||||
|
phlog(
|
||||||
|
pht(
|
||||||
|
'UNSAFE: Raw string ("%s") passed to query ("%s") for "%%Q" '.
|
||||||
|
'conversion. %%Q should be passed a query string.',
|
||||||
|
$value,
|
||||||
|
$query));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($value instanceof PhutilQueryString)) {
|
||||||
|
throw new AphrontParameterQueryException(
|
||||||
|
$query,
|
||||||
|
pht('Expected a PhutilQueryString for %%%s conversion.', $type));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Z':
|
||||||
|
if (!is_string($value)) {
|
||||||
|
throw new AphrontParameterQueryException(
|
||||||
|
$query,
|
||||||
|
pht('Value for "%%Z" conversion should be a raw string.'));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'LC':
|
case 'LC':
|
||||||
|
case 'LK':
|
||||||
case 'T':
|
case 'T':
|
||||||
case 'C':
|
case 'C':
|
||||||
if (!is_string($value)) {
|
if (!is_string($value)) {
|
||||||
|
@ -312,6 +488,28 @@ function qsprintf_check_scalar_type($value, $type, $query) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'R':
|
||||||
|
if (!($value instanceof AphrontDatabaseTableRefInterface)) {
|
||||||
|
throw new AphrontParameterQueryException(
|
||||||
|
$query,
|
||||||
|
pht(
|
||||||
|
'Parameter to "%s" conversion in "qsprintf(...)" is not an '.
|
||||||
|
'instance of AphrontDatabaseTableRefInterface.',
|
||||||
|
'%R'));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'P':
|
||||||
|
if (!($value instanceof PhutilOpaqueEnvelope)) {
|
||||||
|
throw new AphrontParameterQueryException(
|
||||||
|
$query,
|
||||||
|
pht(
|
||||||
|
'Parameter to "%s" conversion in "qsprintf(...)" is not an '.
|
||||||
|
'instance of PhutilOpaqueEnvelope.',
|
||||||
|
'%P'));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new XsprintfUnknownConversionException($type);
|
throw new XsprintfUnknownConversionException($type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ function queryfx(AphrontDatabaseConnection $conn, $sql /* , ... */) {
|
||||||
$query = call_user_func_array('qsprintf', $argv);
|
$query = call_user_func_array('qsprintf', $argv);
|
||||||
|
|
||||||
$conn->setLastActiveEpoch(time());
|
$conn->setLastActiveEpoch(time());
|
||||||
$conn->executeRawQuery($query);
|
$conn->executeQuery($query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function queryfx_all(AphrontDatabaseConnection $conn, $sql /* , ... */) {
|
function queryfx_all(AphrontDatabaseConnection $conn, $sql /* , ... */) {
|
||||||
|
|
|
@ -2746,6 +2746,21 @@ new_expr:
|
||||||
$1->appendChild($3);
|
$1->appendChild($3);
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
|
| T_NEW T_CLASS ctor_arguments extends_from implements_list
|
||||||
|
'{' class_statement_list '}' {
|
||||||
|
$$ = NNEW(n_CLASS_DECLARATION);
|
||||||
|
$$->appendChild($2);
|
||||||
|
$$->appendChild(NNEW(n_EMPTY));
|
||||||
|
$$->appendChild($4);
|
||||||
|
$$->appendChild($5);
|
||||||
|
$$->appendChild(NEXPAND($6, $7, $8));
|
||||||
|
NMORE($$, $8);
|
||||||
|
|
||||||
|
NTYPE($1, n_NEW);
|
||||||
|
$1->appendChild($$);
|
||||||
|
$1->appendChild($3);
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
class_constant:
|
class_constant:
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -12,12 +12,234 @@
|
||||||
|
|
||||||
#define FLEX_SCANNER
|
#define FLEX_SCANNER
|
||||||
#define YY_FLEX_MAJOR_VERSION 2
|
#define YY_FLEX_MAJOR_VERSION 2
|
||||||
#define YY_FLEX_MINOR_VERSION 5
|
#define YY_FLEX_MINOR_VERSION 6
|
||||||
#define YY_FLEX_SUBMINOR_VERSION 35
|
#define YY_FLEX_SUBMINOR_VERSION 4
|
||||||
#if YY_FLEX_SUBMINOR_VERSION > 0
|
#if YY_FLEX_SUBMINOR_VERSION > 0
|
||||||
#define FLEX_BETA
|
#define FLEX_BETA
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef yy_create_buffer
|
||||||
|
#define xhpast_create_buffer_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yy_create_buffer xhpast_create_buffer
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yy_delete_buffer
|
||||||
|
#define xhpast_delete_buffer_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yy_delete_buffer xhpast_delete_buffer
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yy_scan_buffer
|
||||||
|
#define xhpast_scan_buffer_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yy_scan_buffer xhpast_scan_buffer
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yy_scan_string
|
||||||
|
#define xhpast_scan_string_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yy_scan_string xhpast_scan_string
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yy_scan_bytes
|
||||||
|
#define xhpast_scan_bytes_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yy_scan_bytes xhpast_scan_bytes
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yy_init_buffer
|
||||||
|
#define xhpast_init_buffer_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yy_init_buffer xhpast_init_buffer
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yy_flush_buffer
|
||||||
|
#define xhpast_flush_buffer_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yy_flush_buffer xhpast_flush_buffer
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yy_load_buffer_state
|
||||||
|
#define xhpast_load_buffer_state_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yy_load_buffer_state xhpast_load_buffer_state
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yy_switch_to_buffer
|
||||||
|
#define xhpast_switch_to_buffer_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yy_switch_to_buffer xhpast_switch_to_buffer
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yypush_buffer_state
|
||||||
|
#define xhpastpush_buffer_state_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yypush_buffer_state xhpastpush_buffer_state
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yypop_buffer_state
|
||||||
|
#define xhpastpop_buffer_state_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yypop_buffer_state xhpastpop_buffer_state
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyensure_buffer_stack
|
||||||
|
#define xhpastensure_buffer_stack_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyensure_buffer_stack xhpastensure_buffer_stack
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yylex
|
||||||
|
#define xhpastlex_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yylex xhpastlex
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyrestart
|
||||||
|
#define xhpastrestart_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyrestart xhpastrestart
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yylex_init
|
||||||
|
#define xhpastlex_init_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yylex_init xhpastlex_init
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yylex_init_extra
|
||||||
|
#define xhpastlex_init_extra_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yylex_init_extra xhpastlex_init_extra
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yylex_destroy
|
||||||
|
#define xhpastlex_destroy_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yylex_destroy xhpastlex_destroy
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyget_debug
|
||||||
|
#define xhpastget_debug_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyget_debug xhpastget_debug
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyset_debug
|
||||||
|
#define xhpastset_debug_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyset_debug xhpastset_debug
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyget_extra
|
||||||
|
#define xhpastget_extra_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyget_extra xhpastget_extra
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyset_extra
|
||||||
|
#define xhpastset_extra_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyset_extra xhpastset_extra
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyget_in
|
||||||
|
#define xhpastget_in_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyget_in xhpastget_in
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyset_in
|
||||||
|
#define xhpastset_in_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyset_in xhpastset_in
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyget_out
|
||||||
|
#define xhpastget_out_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyget_out xhpastget_out
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyset_out
|
||||||
|
#define xhpastset_out_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyset_out xhpastset_out
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyget_leng
|
||||||
|
#define xhpastget_leng_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyget_leng xhpastget_leng
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyget_text
|
||||||
|
#define xhpastget_text_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyget_text xhpastget_text
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyget_lineno
|
||||||
|
#define xhpastget_lineno_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyget_lineno xhpastget_lineno
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyset_lineno
|
||||||
|
#define xhpastset_lineno_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyset_lineno xhpastset_lineno
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyget_column
|
||||||
|
#define xhpastget_column_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyget_column xhpastget_column
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyset_column
|
||||||
|
#define xhpastset_column_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyset_column xhpastset_column
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yywrap
|
||||||
|
#define xhpastwrap_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yywrap xhpastwrap
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyget_lval
|
||||||
|
#define xhpastget_lval_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyget_lval xhpastget_lval
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyset_lval
|
||||||
|
#define xhpastset_lval_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyset_lval xhpastset_lval
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyalloc
|
||||||
|
#define xhpastalloc_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyalloc xhpastalloc
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyrealloc
|
||||||
|
#define xhpastrealloc_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyrealloc xhpastrealloc
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef yyfree
|
||||||
|
#define xhpastfree_ALREADY_DEFINED
|
||||||
|
#else
|
||||||
|
#define yyfree xhpastfree
|
||||||
|
#endif
|
||||||
|
|
||||||
/* First, we deal with platform-specific or compiler-specific issues. */
|
/* First, we deal with platform-specific or compiler-specific issues. */
|
||||||
|
|
||||||
/* begin standard C headers. */
|
/* begin standard C headers. */
|
||||||
|
@ -88,29 +310,23 @@ typedef unsigned int flex_uint32_t;
|
||||||
#define UINT32_MAX (4294967295U)
|
#define UINT32_MAX (4294967295U)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SIZE_MAX
|
||||||
|
#define SIZE_MAX (~(size_t)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* ! C99 */
|
#endif /* ! C99 */
|
||||||
|
|
||||||
#endif /* ! FLEXINT_H */
|
#endif /* ! FLEXINT_H */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
/* begin standard C++ headers. */
|
||||||
|
|
||||||
/* The "const" storage-class-modifier is valid. */
|
/* TODO: this is always defined, so inline it */
|
||||||
#define YY_USE_CONST
|
|
||||||
|
|
||||||
#else /* ! __cplusplus */
|
|
||||||
|
|
||||||
/* C99 requires __STDC__ to be defined as 1. */
|
|
||||||
#if defined (__STDC__)
|
|
||||||
|
|
||||||
#define YY_USE_CONST
|
|
||||||
|
|
||||||
#endif /* defined (__STDC__) */
|
|
||||||
#endif /* ! __cplusplus */
|
|
||||||
|
|
||||||
#ifdef YY_USE_CONST
|
|
||||||
#define yyconst const
|
#define yyconst const
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||||
|
#define yynoreturn __attribute__((__noreturn__))
|
||||||
#else
|
#else
|
||||||
#define yyconst
|
#define yynoreturn
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* An opaque pointer. */
|
/* An opaque pointer. */
|
||||||
|
@ -165,7 +381,7 @@ struct yy_buffer_state
|
||||||
/* Size of input buffer in bytes, not including room for EOB
|
/* Size of input buffer in bytes, not including room for EOB
|
||||||
* characters.
|
* characters.
|
||||||
*/
|
*/
|
||||||
yy_size_t yy_buf_size;
|
int yy_buf_size;
|
||||||
|
|
||||||
/* Number of characters read into yy_ch_buf, not including EOB
|
/* Number of characters read into yy_ch_buf, not including EOB
|
||||||
* characters.
|
* characters.
|
||||||
|
@ -193,7 +409,7 @@ struct yy_buffer_state
|
||||||
|
|
||||||
int yy_bs_lineno; /**< The line count. */
|
int yy_bs_lineno; /**< The line count. */
|
||||||
int yy_bs_column; /**< The column count. */
|
int yy_bs_column; /**< The column count. */
|
||||||
|
|
||||||
/* Whether to try to fill the input buffer when we reach the
|
/* Whether to try to fill the input buffer when we reach the
|
||||||
* end of it.
|
* end of it.
|
||||||
*/
|
*/
|
||||||
|
@ -204,25 +420,25 @@ struct yy_buffer_state
|
||||||
};
|
};
|
||||||
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
|
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
|
||||||
|
|
||||||
void xhpastrestart (FILE *input_file ,yyscan_t yyscanner );
|
void yyrestart ( FILE *input_file , yyscan_t yyscanner );
|
||||||
void xhpast_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
|
void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
|
||||||
YY_BUFFER_STATE xhpast_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
|
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
|
||||||
void xhpast_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
|
void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
|
||||||
void xhpast_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
|
void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
|
||||||
void xhpastpush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
|
void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
|
||||||
void xhpastpop_buffer_state (yyscan_t yyscanner );
|
void yypop_buffer_state ( yyscan_t yyscanner );
|
||||||
|
|
||||||
YY_BUFFER_STATE xhpast_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
|
YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
|
||||||
YY_BUFFER_STATE xhpast_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
|
YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
|
||||||
YY_BUFFER_STATE xhpast_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
|
YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
|
||||||
|
|
||||||
void *xhpastalloc (yy_size_t ,yyscan_t yyscanner );
|
void *yyalloc ( yy_size_t , yyscan_t yyscanner );
|
||||||
void *xhpastrealloc (void *,yy_size_t ,yyscan_t yyscanner );
|
void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
|
||||||
void xhpastfree (void * ,yyscan_t yyscanner );
|
void yyfree ( void * , yyscan_t yyscanner );
|
||||||
|
|
||||||
/* Begin user sect3 */
|
/* Begin user sect3 */
|
||||||
|
|
||||||
#define xhpastwrap(n) 1
|
#define xhpastwrap(yyscanner) (/*CONSTCOND*/1)
|
||||||
#define YY_SKIP_YYWRAP
|
#define YY_SKIP_YYWRAP
|
||||||
|
|
||||||
#define yytext_ptr yytext_r
|
#define yytext_ptr yytext_r
|
||||||
|
@ -254,42 +470,46 @@ void xhpastfree (void * ,yyscan_t yyscanner );
|
||||||
#define YY_EXTRA_TYPE void *
|
#define YY_EXTRA_TYPE void *
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int xhpastlex_init (yyscan_t* scanner);
|
int yylex_init (yyscan_t* scanner);
|
||||||
|
|
||||||
int xhpastlex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
|
int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
|
||||||
|
|
||||||
/* Accessor methods to globals.
|
/* Accessor methods to globals.
|
||||||
These are made visible to non-reentrant scanners for convenience. */
|
These are made visible to non-reentrant scanners for convenience. */
|
||||||
|
|
||||||
int xhpastlex_destroy (yyscan_t yyscanner );
|
int yylex_destroy ( yyscan_t yyscanner );
|
||||||
|
|
||||||
int xhpastget_debug (yyscan_t yyscanner );
|
int yyget_debug ( yyscan_t yyscanner );
|
||||||
|
|
||||||
void xhpastset_debug (int debug_flag ,yyscan_t yyscanner );
|
void yyset_debug ( int debug_flag , yyscan_t yyscanner );
|
||||||
|
|
||||||
YY_EXTRA_TYPE xhpastget_extra (yyscan_t yyscanner );
|
YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
|
||||||
|
|
||||||
void xhpastset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
|
void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
|
||||||
|
|
||||||
FILE *xhpastget_in (yyscan_t yyscanner );
|
FILE *yyget_in ( yyscan_t yyscanner );
|
||||||
|
|
||||||
void xhpastset_in (FILE * in_str ,yyscan_t yyscanner );
|
void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
|
||||||
|
|
||||||
FILE *xhpastget_out (yyscan_t yyscanner );
|
FILE *yyget_out ( yyscan_t yyscanner );
|
||||||
|
|
||||||
void xhpastset_out (FILE * out_str ,yyscan_t yyscanner );
|
void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
|
||||||
|
|
||||||
int xhpastget_leng (yyscan_t yyscanner );
|
int yyget_leng ( yyscan_t yyscanner );
|
||||||
|
|
||||||
char *xhpastget_text (yyscan_t yyscanner );
|
char *yyget_text ( yyscan_t yyscanner );
|
||||||
|
|
||||||
int xhpastget_lineno (yyscan_t yyscanner );
|
int yyget_lineno ( yyscan_t yyscanner );
|
||||||
|
|
||||||
void xhpastset_lineno (int line_number ,yyscan_t yyscanner );
|
void yyset_lineno ( int _line_number , yyscan_t yyscanner );
|
||||||
|
|
||||||
YYSTYPE * xhpastget_lval (yyscan_t yyscanner );
|
int yyget_column ( yyscan_t yyscanner );
|
||||||
|
|
||||||
void xhpastset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
|
void yyset_column ( int _column_no , yyscan_t yyscanner );
|
||||||
|
|
||||||
|
YYSTYPE * yyget_lval ( yyscan_t yyscanner );
|
||||||
|
|
||||||
|
void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
|
||||||
|
|
||||||
/* Macros after this point can all be overridden by user definitions in
|
/* Macros after this point can all be overridden by user definitions in
|
||||||
* section 1.
|
* section 1.
|
||||||
|
@ -297,18 +517,18 @@ void xhpastset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
|
||||||
|
|
||||||
#ifndef YY_SKIP_YYWRAP
|
#ifndef YY_SKIP_YYWRAP
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" int xhpastwrap (yyscan_t yyscanner );
|
extern "C" int yywrap ( yyscan_t yyscanner );
|
||||||
#else
|
#else
|
||||||
extern int xhpastwrap (yyscan_t yyscanner );
|
extern int yywrap ( yyscan_t yyscanner );
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef yytext_ptr
|
#ifndef yytext_ptr
|
||||||
static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
|
static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef YY_NEED_STRLEN
|
#ifdef YY_NEED_STRLEN
|
||||||
static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
|
static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef YY_NO_INPUT
|
#ifndef YY_NO_INPUT
|
||||||
|
@ -336,10 +556,10 @@ static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
|
||||||
#ifndef YY_DECL
|
#ifndef YY_DECL
|
||||||
#define YY_DECL_IS_OURS 1
|
#define YY_DECL_IS_OURS 1
|
||||||
|
|
||||||
extern int xhpastlex \
|
extern int yylex \
|
||||||
(YYSTYPE * yylval_param ,yyscan_t yyscanner);
|
(YYSTYPE * yylval_param , yyscan_t yyscanner);
|
||||||
|
|
||||||
#define YY_DECL int xhpastlex \
|
#define YY_DECL int yylex \
|
||||||
(YYSTYPE * yylval_param , yyscan_t yyscanner)
|
(YYSTYPE * yylval_param , yyscan_t yyscanner)
|
||||||
#endif /* !YY_DECL */
|
#endif /* !YY_DECL */
|
||||||
|
|
||||||
|
@ -357,10 +577,155 @@ extern int xhpastlex \
|
||||||
#undef YY_DECL
|
#undef YY_DECL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#line 367 "scanner.l"
|
#ifndef xhpast_create_buffer_ALREADY_DEFINED
|
||||||
|
#undef yy_create_buffer
|
||||||
|
#endif
|
||||||
|
#ifndef xhpast_delete_buffer_ALREADY_DEFINED
|
||||||
|
#undef yy_delete_buffer
|
||||||
|
#endif
|
||||||
|
#ifndef xhpast_scan_buffer_ALREADY_DEFINED
|
||||||
|
#undef yy_scan_buffer
|
||||||
|
#endif
|
||||||
|
#ifndef xhpast_scan_string_ALREADY_DEFINED
|
||||||
|
#undef yy_scan_string
|
||||||
|
#endif
|
||||||
|
#ifndef xhpast_scan_bytes_ALREADY_DEFINED
|
||||||
|
#undef yy_scan_bytes
|
||||||
|
#endif
|
||||||
|
#ifndef xhpast_init_buffer_ALREADY_DEFINED
|
||||||
|
#undef yy_init_buffer
|
||||||
|
#endif
|
||||||
|
#ifndef xhpast_flush_buffer_ALREADY_DEFINED
|
||||||
|
#undef yy_flush_buffer
|
||||||
|
#endif
|
||||||
|
#ifndef xhpast_load_buffer_state_ALREADY_DEFINED
|
||||||
|
#undef yy_load_buffer_state
|
||||||
|
#endif
|
||||||
|
#ifndef xhpast_switch_to_buffer_ALREADY_DEFINED
|
||||||
|
#undef yy_switch_to_buffer
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastpush_buffer_state_ALREADY_DEFINED
|
||||||
|
#undef yypush_buffer_state
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastpop_buffer_state_ALREADY_DEFINED
|
||||||
|
#undef yypop_buffer_state
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastensure_buffer_stack_ALREADY_DEFINED
|
||||||
|
#undef yyensure_buffer_stack
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastlex_ALREADY_DEFINED
|
||||||
|
#undef yylex
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastrestart_ALREADY_DEFINED
|
||||||
|
#undef yyrestart
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastlex_init_ALREADY_DEFINED
|
||||||
|
#undef yylex_init
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastlex_init_extra_ALREADY_DEFINED
|
||||||
|
#undef yylex_init_extra
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastlex_destroy_ALREADY_DEFINED
|
||||||
|
#undef yylex_destroy
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastget_debug_ALREADY_DEFINED
|
||||||
|
#undef yyget_debug
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastset_debug_ALREADY_DEFINED
|
||||||
|
#undef yyset_debug
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastget_extra_ALREADY_DEFINED
|
||||||
|
#undef yyget_extra
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastset_extra_ALREADY_DEFINED
|
||||||
|
#undef yyset_extra
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastget_in_ALREADY_DEFINED
|
||||||
|
#undef yyget_in
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastset_in_ALREADY_DEFINED
|
||||||
|
#undef yyset_in
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastget_out_ALREADY_DEFINED
|
||||||
|
#undef yyget_out
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastset_out_ALREADY_DEFINED
|
||||||
|
#undef yyset_out
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastget_leng_ALREADY_DEFINED
|
||||||
|
#undef yyget_leng
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastget_text_ALREADY_DEFINED
|
||||||
|
#undef yyget_text
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastget_lineno_ALREADY_DEFINED
|
||||||
|
#undef yyget_lineno
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastset_lineno_ALREADY_DEFINED
|
||||||
|
#undef yyset_lineno
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastget_column_ALREADY_DEFINED
|
||||||
|
#undef yyget_column
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastset_column_ALREADY_DEFINED
|
||||||
|
#undef yyset_column
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastwrap_ALREADY_DEFINED
|
||||||
|
#undef yywrap
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastget_lval_ALREADY_DEFINED
|
||||||
|
#undef yyget_lval
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastset_lval_ALREADY_DEFINED
|
||||||
|
#undef yyset_lval
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastget_lloc_ALREADY_DEFINED
|
||||||
|
#undef yyget_lloc
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastset_lloc_ALREADY_DEFINED
|
||||||
|
#undef yyset_lloc
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastalloc_ALREADY_DEFINED
|
||||||
|
#undef yyalloc
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastrealloc_ALREADY_DEFINED
|
||||||
|
#undef yyrealloc
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastfree_ALREADY_DEFINED
|
||||||
|
#undef yyfree
|
||||||
|
#endif
|
||||||
|
#ifndef xhpasttext_ALREADY_DEFINED
|
||||||
|
#undef yytext
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastleng_ALREADY_DEFINED
|
||||||
|
#undef yyleng
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastin_ALREADY_DEFINED
|
||||||
|
#undef yyin
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastout_ALREADY_DEFINED
|
||||||
|
#undef yyout
|
||||||
|
#endif
|
||||||
|
#ifndef xhpast_flex_debug_ALREADY_DEFINED
|
||||||
|
#undef yy_flex_debug
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastlineno_ALREADY_DEFINED
|
||||||
|
#undef yylineno
|
||||||
|
#endif
|
||||||
|
#ifndef xhpasttables_fload_ALREADY_DEFINED
|
||||||
|
#undef yytables_fload
|
||||||
|
#endif
|
||||||
|
#ifndef xhpasttables_destroy_ALREADY_DEFINED
|
||||||
|
#undef yytables_destroy
|
||||||
|
#endif
|
||||||
|
#ifndef xhpastTABLES_NAME_ALREADY_DEFINED
|
||||||
|
#undef yyTABLES_NAME
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#line 368 "scanner.l"
|
||||||
|
|
||||||
|
|
||||||
#line 364 "scanner.lex.hpp"
|
#line 729 "scanner.lex.hpp"
|
||||||
#undef xhpastIN_HEADER
|
#undef xhpastIN_HEADER
|
||||||
#endif /* xhpastHEADER_H */
|
#endif /* xhpastHEADER_H */
|
||||||
/* @generated */
|
/* @generated */
|
||||||
|
|
|
@ -12,7 +12,7 @@ void print_node(xhpast::Node *node);
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc != 1) {
|
if (argc != 1) {
|
||||||
// Coupling: modify also src/parser/xhpast/bin/PhutilXHPASTBinary.php
|
// Coupling: modify also src/parser/xhpast/bin/PhutilXHPASTBinary.php
|
||||||
cout << "7.1.2\n";
|
cout << "7.1.3\n";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue