Compare commits

..
Author SHA1 Message Date
Derick Rethans 41c207aed2 Update versions for PHP 7.4.15RC2 2021-01-19 15:09:58 +00:00
Derick Rethans 9544aac446 Update NEWS for PHP 7.4.15RC2 2021-01-19 15:09:58 +00:00
Derick Rethans 03596d7648 Reset date so I can try again 2021-01-19 15:08:41 +00:00
Derick Rethans 3c10649464 Set right version 2021-01-19 15:01:07 +00:00
Derick Rethans e8a89c49db Update NEWS for PHP 7.4.15RC1 2021-01-19 14:44:32 +00:00
sj-i 5d31ee302d Fixed bug #42560
Check open_basedir after the fallback to the system's temporary
directory in tempnam().

In order to preserve the current behavior of upload_tmp_dir
(do not check explicitly specified dir, but check fallback),
new flags are added to check open_basedir for explicit dir
and for fallback.

Closes GH-6526.
2021-01-19 11:41:58 +01:00
Christoph M. BeckerandAnna Filina 68f5289e9e Fix #69279: Compressed ZIP Phar extractTo() creates garbage files
When extracting compressed files from an uncompressed Phar, we must not
use the direct file pointer, but rather get an uncompressed file
pointer.

We also add a test to show that deflated and stored entries are
properly extracted.

This also fixes #79912, which appears to be a duplicate of #69279.

Co-authored-by: Anna Filina <afilina@gmail.com>

Closes GH-6599.
2021-01-19 10:28:54 +01:00
Christoph M. Becker 38ad37ad43 Fix #80595: Resetting POSTFIELDS to empty array breaks request
This is mainly to work around https://github.com/curl/curl/issues/6455,
but not building the mime structure for empty hashtables is a general
performance optimization, so we do not restrict it to affected cURL
versions (7.56.0 to 7.75.0).

The minor change to bug79033.phpt is unexpected, but should not matter
in practice.

Closes GH-6606.
2021-01-18 10:57:56 +01:00
Christoph M. Becker 25103c37aa Revert "Fix #76813: Access violation near NULL on source operand"
This reverts commit 5e15c9c41f, since
re2c default rules are only available as of re2c 0.13.7.
2021-01-11 13:21:12 +01:00
Christoph M. Becker 9450893dc6 Avoid modifying the return value of readline_completion_function()
The internal function `_readline_command_generator()` modifies the
internal array pointer of `readline_completion_function()`'s return
value.  We therefore separate the array, what also avoids failing
assertions regarding the array refcount.

Closes GH-6582.
2021-01-07 13:46:09 +01:00
Christoph M. Becker d1b1c04398 Fix #77565: Incorrect locator detection in ZIP-based phars
We must not assume that the first end of central dir signature in a ZIP
archive actually designates the end of central directory record, since
the data in the archive may contain arbitrary byte patterns.  Thus, we
better search from the end of the data, what is also slightly more
efficient.

There is, however, no way to detect the end of central directory
signature by searching from the end of the ZIP archive with absolute
certainty, since the signature could be part of the trailing comment.
To mitigate, we check that the comment length fits to the found
position, but that might still not be the correct position in rare
cases.

Closes GH-6507.
2021-01-05 23:40:24 +01:00
Christoph M. Becker 5c963731e2 Fix memory leak in Phar::webPhar() on Windows
Closes GH-6574.
2021-01-05 14:21:35 +01:00
Dylan K. Taylor 6b631f073d gdbinit: use ____print_str to print htable keys
I noticed this problem while dumping the contents of EG(function_table),
where keys for closures start with a null byte. printf interprets this
as a zero-length string and emits nothing. This allows the key to be
rendered properly in readable form.

Closes GH-6577.
2021-01-05 10:11:56 +01:00
Nikita Popov 46d6daea7a Disable non-cron travis jobs
This was already done for PHP-8.0 and master, do it for PHP-7.4
as well.
2021-01-04 10:52:37 +01:00
Stanislav Malyshev e65932060a [ci skip] Update NEWS 2021-01-04 01:46:32 -08:00
Stanislav Malyshev ec589a27da Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  [ci skip] Fix order
2021-01-04 01:46:11 -08:00
Stanislav Malyshev 65d7ade684 [ci skip] Fix order 2021-01-04 01:45:15 -08:00
Stanislav Malyshev 2498385dd9 Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  [ci skip] Unpdate NEWS
2021-01-04 01:44:18 -08:00
Stanislav Malyshev 8967e66559 [ci skip] Unpdate NEWS 2021-01-04 01:43:45 -08:00
Stanislav Malyshev 434c2b1bdb Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3:
  Fix #77423: parse_url() will deliver a wrong host to user
2021-01-01 21:29:08 -08:00
Stanislav Malyshev 128fca4037 Merge branch 'PHP-7.2' into PHP-7.3
* PHP-7.2:
  Fix #77423: parse_url() will deliver a wrong host to user
2021-01-01 21:06:07 -08:00
Christoph M. Becker 2d3d72412a Fix #77423: parse_url() will deliver a wrong host to user
To avoid that `parse_url()` returns an erroneous host, which would be
valid for `FILTER_VALIDATE_URL`, we make sure that only userinfo which
is valid according to RFC 3986 is treated as such.

For consistency with the existing url parsing code, we use ctype
functions, although that is not necessarily correct.
2021-01-01 20:08:01 -08:00
haszi 0db6f5267c Replace sort() function calls with ksort() in basic ksort test
Closes GH-6541.
2020-12-27 18:30:58 +01:00
Adam SeitzandChristoph M. Becker 70dfbe0068 Fix #80384: limit read buffer size
In the case of a stream with no filters, php_stream_fill_read_buffer
only reads stream->chunk_size into the read buffer. If the stream has
filters attached, it could unnecessarily buffer a large amount of data.

With this change, php_stream_fill_read_buffer only proceeds until either
the requested size or stream->chunk_size is available in the read buffer.

Co-authored-by: Christoph M. Becker <cmbecker69@gmx.de>

Closes GH-6444.
2020-12-23 13:49:56 +01:00
Derick Rethans b043759cb4 Fixed bug #80376 (last day of the month causes runway cpu usage) 2020-12-21 10:30:40 +00:00
Nikita Popov bc166844e3 MySQLnd: Support cursors in store/get result
This fixes two related issues:

1. When a PS with cursor is used in store_result/get_result,
   perform a COM_FETCH with maximum number of rows rather than
   silently switching to an unbuffered result set (in the case of
   store_result) or erroring (in the case of get_result).
   In the future, we might want to make get_result unbuffered for
   PS with cursors, as using cursors with buffered result sets
   doesn't really make sense. Unlike store_result, get_result
   isn't very explicit about what kind of result set is desired.
2. If the client did not request a cursor, but the server reports
   that a cursor exists, ignore this and treat the PS as if it
   has no cursor (i.e. to not use COM_FETCH). It appears to be a
   server side bug that a cursor used inside an SP will be reported
   to the client, even though the client cannot use the cursor.

Fixes bug #64638, bug #72862, bug #77935.

Closes GH-6518.
2020-12-18 10:19:13 +01:00
Nikita Popov 315f3f8dc9 Fixed bug #67983
We need to check the BIT case first, otherwise it will get skipped
in INT_AND_FLOAT_NATIVE mode.
2020-12-16 10:52:27 +01:00
Nikita Popov 118ff03335 Fix bug #80523
Don't truncate the file length to unsigned int...

I have no idea whether that fully fixes the problem because the
process gets OOM killed before finishing, but at least the
immediate parse error is gone now.
2020-12-16 10:20:20 +01:00
Derick Rethans 078cdd8f76 Prepare for 7.4.15 2020-12-15 14:13:29 +00:00
38 changed files with 23885 additions and 20712 deletions

No files matched your search

+2 -1
View File
@@ -352,7 +352,8 @@ define ____print_ht
end
printf "[%d] ", $i
if $p->key
printf "%s => ", $p->key->val
____print_str $p->key->val $p->key->len
printf " => "
else
printf "%d => ", $p->h
end
+3
View File
@@ -70,10 +70,13 @@ jobs:
include:
- env: ENABLE_MAINTAINER_ZTS=0 ENABLE_DEBUG=0
arch: amd64
if: type = cron
- env: ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1
arch: amd64
if: type = cron
- env: ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1 SKIP_IO_CAPTURE_TESTS=1 ARM64=1
arch: arm64
if: type = cron
before_script:
- ccache --version
+29 -1
View File
@@ -1,5 +1,33 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
21 Jan 2021, PHP 7.4.15RC2
- Core:
. Fixed bug #80523 (bogus parse error on >4GB source code). (Nikita)
. Fixed bug #80384 (filter buffers entire read until file closed). (Adam
Seitz, cmb)
- Curl:
. Fixed bug #80595 (Resetting POSTFIELDS to empty array breaks request). (cmb)
- Date:
. Fixed bug #80376 (last day of the month causes runway cpu usage. (Derick)
- MySQLi:
. Fixed bug #67983 (mysqlnd with MYSQLI_OPT_INT_AND_FLOAT_NATIVE fails to
interpret bit columns). (Nikita)
. Fixed bug #64638 (Fetching resultsets from stored procedure with cursor
fails). (Nikita)
. Fixed bug #72862 (segfault using prepared statements on stored procedures
that use a cursor). (Nikita)
. Fixed bug #77935 (Crash in mysqlnd_fetch_stmt_row_cursor when calling an SP
with a cursor). (Nikita)
- Phar:
. Fixed bug #77565 (Incorrect locator detection in ZIP-based phars). (cmb)
. Fixed bug #69279 (Compressed ZIP Phar extractTo() creates garbage files).
(cmb)
07 Jan 2021, PHP 7.4.14
- Core:
@@ -50,7 +78,7 @@ PHP NEWS
PROCEDURE resultset SIGNAL). (Nikita)
- Standard:
. Fixed bug #77423 (FILTER_VALIDATE_URL accepts URLs with invalid userinfo).
. Fixed bug #77423 (FILTER_VALIDATE_URL accepts URLs with invalid userinfo).
(CVE-2020-7071) (cmb)
. Fixed bug #80366 (Return Value of zend_fstat() not Checked). (sagpant, cmb)
. Fixed bug #80411 (References to null-serialized object break serialize()).
+3 -3
View File
@@ -177,7 +177,7 @@ static void yy_pop_state(void)
zend_stack_del_top(&SCNG(state_stack));
}
static void yy_scan_buffer(char *str, unsigned int len)
static void yy_scan_buffer(char *str, size_t len)
{
YYCURSOR = (YYCTYPE*)str;
YYLIMIT = YYCURSOR + len;
@@ -554,7 +554,7 @@ ZEND_API int open_file_for_scanning(zend_file_handle *file_handle)
}
}
SCNG(yy_start) = (unsigned char *)buf;
yy_scan_buffer(buf, (unsigned int)size);
yy_scan_buffer(buf, size);
} else {
zend_error_noreturn(E_COMPILE_ERROR, "zend_stream_mmap() failed");
}
@@ -722,7 +722,7 @@ ZEND_API int zend_prepare_string_for_scanning(zval *str, char *filename)
}
}
yy_scan_buffer(buf, (unsigned int)size);
yy_scan_buffer(buf, size);
new_compiled_filename = zend_string_init(filename, strlen(filename), 0);
zend_set_compiled_filename(new_compiled_filename);
+1 -1
View File
@@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice.
dnl ----------------------------------------------------------------------------
AC_PREREQ([2.68])
AC_INIT([PHP],[7.4.14],[https://bugs.php.net],[php],[https://www.php.net])
AC_INIT([PHP],[7.4.15RC2],[https://bugs.php.net],[php],[https://www.php.net])
AC_CONFIG_SRCDIR([main/php_version.h])
AC_CONFIG_AUX_DIR([build])
AC_PRESERVE_HELP_ORDER
+8 -1
View File
@@ -2969,7 +2969,14 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue) /* {{{
case CURLOPT_POSTFIELDS:
if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) {
return build_mime_structure_from_hash(ch, zvalue);
if (zend_hash_num_elements(HASH_OF(zvalue)) == 0) {
/* no need to build the mime structure for empty hashtables;
also works around https://github.com/curl/curl/issues/6455 */
curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDS, "");
error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, 0);
} else {
return build_mime_structure_from_hash(ch, zvalue);
}
} else {
#if LIBCURL_VERSION_NUM >= 0x071101
zend_string *tmp_str;
+2 -1
View File
@@ -21,9 +21,10 @@ var_dump(curl_getinfo($ch)["request_header"]);
string(%d) "array(0) {
}
"
string(90) "POST /get.inc?test=post HTTP/1.1
string(%d) "POST /get.inc?test=post HTTP/1.1
Host: localhost:%d
Accept: */*
Content-Length: 0
Content-Type: application/x-www-form-urlencoded
"
+30
View File
@@ -0,0 +1,30 @@
--TEST--
Bug #80595 (Resetting POSTFIELDS to empty array breaks request)
--SKIPIF--
<?php include 'skipif.inc'; ?>
--FILE--
<?php
include 'server.inc';
$host = curl_cli_server_start();
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_URL => "{$host}/get.inc?test=post",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, ['foo' => 'bar']);
var_dump(curl_exec($ch));
curl_setopt($ch, CURLOPT_POSTFIELDS, []);
var_dump(curl_exec($ch));
?>
--EXPECT--
string(43) "array(1) {
["foo"]=>
string(3) "bar"
}
"
string(13) "array(0) {
}
"
+22837 -20045
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+35
View File
@@ -0,0 +1,35 @@
--TEST--
Bug #67983: mysqlnd with MYSQLI_OPT_INT_AND_FLOAT_NATIVE fails to interpret bit columns
--SKIPIF--
<?php
require_once('skipif.inc');
require_once('skipifconnectfailure.inc');
if (!$IS_MYSQLND) {
die("skip mysqlnd only test");
}
?>
--FILE--
<?php
require_once("connect.inc");
$connection = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
mysqli_options($connection, MYSQLI_OPT_INT_AND_FLOAT_NATIVE, true);
mysqli_set_charset($connection, 'utf8');
mysqli_query($connection, 'DROP TABLE IF EXISTS test');
mysqli_query($connection, 'CREATE TABLE test (id BIT(8))');
mysqli_query($connection, 'INSERT INTO test VALUES (0), (1), (42)');
$res = mysqli_query($connection, 'SELECT * FROM test');
while ($result = mysqli_fetch_assoc($res)) {
var_dump($result['id']);
}
?>
--EXPECT--
int(0)
int(1)
int(42)
+38
View File
@@ -0,0 +1,38 @@
--TEST--
Bug #77935: Crash in mysqlnd_fetch_stmt_row_cursor when calling an SP with a cursor
--SKIPIF--
<?php
require_once('skipif.inc');
require_once('skipifconnectfailure.inc');
?>
--FILE--
<?php
require_once(__DIR__ . '/connect.inc');
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$db = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
$db->query('DROP PROCEDURE IF EXISTS testSp');
$db->query(<<<'SQL'
CREATE
PROCEDURE `testSp`()
BEGIN
DECLARE `cur` CURSOR FOR SELECT 1;
OPEN `cur`;
CLOSE `cur`;
SELECT 1;
END;
SQL);
$stmt = $db->prepare("CALL testSp()");
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
var_dump($row);
}
?>
--EXPECT--
array(1) {
[1]=>
int(1)
}
+16 -33
View File
@@ -110,21 +110,7 @@ if (!function_exists('mysqli_stmt_get_result'))
mysqli_stmt_close($stmt);
if (!$stmt = mysqli_stmt_init($link))
printf("[032] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
printf("[033] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
if (!mysqli_stmt_execute($stmt))
printf("[034] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
$id = NULL;
$label = NULL;
if (true !== ($tmp = mysqli_stmt_bind_result($stmt, $id, $label)))
printf("[035] Expecting boolean/true, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
// get_result cannot be used in PS cursor mode
// get_result can be used in PS cursor mode
if (!$stmt = mysqli_stmt_init($link))
printf("[030] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
@@ -137,24 +123,11 @@ if (!function_exists('mysqli_stmt_get_result'))
if (!mysqli_stmt_execute($stmt))
printf("[033] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
$res = mysqli_stmt_get_result($stmt);
// we expect no segfault if we try to fetch a row because get_result should throw an error or return false
mysqli_fetch_assoc($res);
} catch (\mysqli_sql_exception $e) {
echo $e->getMessage() . "\n";
$result = mysqli_stmt_get_result($stmt);
while ($row = mysqli_fetch_assoc($result)) {
var_dump($row);
}
try {
$res = $stmt->get_result();
// we expect no segfault if we try to fetch a row because get_result should throw an error or return false
$res->fetch_assoc();
} catch (\mysqli_sql_exception $e) {
echo $e->getMessage() . "\n";
}
mysqli_report(MYSQLI_REPORT_OFF);
if (!$stmt = mysqli_stmt_init($link))
printf("[034] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
@@ -213,8 +186,18 @@ Warning: mysqli_stmt_fetch(): invalid object or resource mysqli_stmt
Warning: mysqli_stmt_get_result(): invalid object or resource mysqli_stmt
in %s on line %d
mysqli_stmt_get_result() cannot be used with cursors
get_result() cannot be used with cursors
array(2) {
["id"]=>
int(1)
["label"]=>
string(1) "a"
}
array(2) {
["id"]=>
int(2)
["label"]=>
string(1) "b"
}
[040] [2014] [Commands out of sync; you can't run this command now]
[041] [0] []
array(2) {
@@ -0,0 +1,99 @@
--TEST--
PS using cursor and returning multiple result sets
--SKIPIF--
<?php
require_once('skipif.inc');
require_once('skipifconnectfailure.inc');
?>
--FILE--
<?php
require_once(__DIR__ . '/connect.inc');
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$db = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
$db->query('DROP PROCEDURE IF EXISTS testPs');
$db->query(<<<'SQL'
CREATE PROCEDURE testPs() BEGIN
DECLARE testCursor CURSOR FOR SELECT 'stuff';
OPEN testCursor;
CLOSE testCursor;
SELECT 1 as a, 2 as b;
SELECT 3 as a, 4 as b;
END
SQL
);
echo "use_result:\n";
$stmt = $db->prepare("call testPs()");
$stmt->execute();
$stmt->bind_result($v1, $v2);
while ($stmt->fetch()) {
var_dump($v1, $v2);
}
$stmt->next_result();
$stmt->bind_result($v1, $v2);
while ($stmt->fetch()) {
var_dump($v1, $v2);
}
$stmt->next_result();
echo "\nstore_result:\n";
$stmt = $db->prepare("call testPs()");
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($v1, $v2);
while ($stmt->fetch()) {
var_dump($v1, $v2);
}
$stmt->next_result();
$stmt->store_result();
$stmt->bind_result($v1, $v2);
while ($stmt->fetch()) {
var_dump($v1, $v2);
}
$stmt->next_result();
echo "\nget_result:\n";
$stmt = $db->prepare("call testPs()");
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
var_dump($row);
}
$stmt->next_result();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
var_dump($row);
}
$stmt->next_result();
?>
--EXPECT--
use_result:
int(1)
int(2)
int(3)
int(4)
store_result:
int(1)
int(2)
int(3)
int(4)
get_result:
array(2) {
["a"]=>
int(1)
["b"]=>
int(2)
}
array(2) {
["a"]=>
int(3)
["b"]=>
int(4)
}
+71 -58
View File
@@ -40,6 +40,36 @@ enum_func_status mysqlnd_stmt_execute_batch_generate_request(MYSQLND_STMT * cons
static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt);
static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, const unsigned int param_no);
static enum_func_status mysqlnd_stmt_send_cursor_fetch_command(
const MYSQLND_STMT_DATA *stmt, unsigned max_rows)
{
MYSQLND_CONN_DATA *conn = stmt->conn;
zend_uchar buf[MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
const MYSQLND_CSTRING payload = {(const char*) buf, sizeof(buf)};
int4store(buf, stmt->stmt_id);
int4store(buf + MYSQLND_STMT_ID_LENGTH, max_rows);
if (conn->command->stmt_fetch(conn, payload) == FAIL) {
COPY_CLIENT_ERROR(stmt->error_info, *conn->error_info);
return FAIL;
}
return PASS;
}
static zend_bool mysqlnd_stmt_check_state(const MYSQLND_STMT_DATA *stmt)
{
const MYSQLND_CONN_DATA *conn = stmt->conn;
if (stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
return 0;
}
if (stmt->cursor_exists) {
return GET_CONNECTION_STATE(&conn->state) == CONN_READY;
} else {
return GET_CONNECTION_STATE(&conn->state) == CONN_FETCHING_DATA;
}
}
/* {{{ mysqlnd_stmt::store_result */
static MYSQLND_RES *
MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
@@ -60,14 +90,8 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
DBG_RETURN(NULL);
}
if (stmt->cursor_exists) {
/* Silently convert buffered to unbuffered, for now */
DBG_RETURN(s->m->use_result(s));
}
/* Nothing to store for UPSERT/LOAD DATA*/
if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
{
if (!mysqlnd_stmt_check_state(stmt)) {
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_RETURN(NULL);
}
@@ -78,6 +102,12 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
SET_EMPTY_ERROR(conn->error_info);
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PS_BUFFERED_SETS);
if (stmt->cursor_exists) {
if (mysqlnd_stmt_send_cursor_fetch_command(stmt, -1) == FAIL) {
DBG_RETURN(NULL);
}
}
result = stmt->result;
result->type = MYSQLND_RES_PS_BUF;
/* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */
@@ -152,19 +182,8 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
DBG_RETURN(NULL);
}
if (stmt->cursor_exists) {
/* Prepared statement cursors are not supported as of yet */
char * msg;
mnd_sprintf(&msg, 0, "%s() cannot be used with cursors", get_active_function_name());
SET_CLIENT_ERROR(stmt->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, msg);
if (msg) {
mnd_sprintf_free(msg);
}
DBG_RETURN(NULL);
}
/* Nothing to store for UPSERT/LOAD DATA*/
if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
if (!mysqlnd_stmt_check_state(stmt)) {
SET_CLIENT_ERROR(stmt->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_RETURN(NULL);
}
@@ -173,6 +192,12 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
SET_EMPTY_ERROR(conn->error_info);
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
if (stmt->cursor_exists) {
if (mysqlnd_stmt_send_cursor_fetch_command(stmt, -1) == FAIL) {
DBG_RETURN(NULL);
}
}
do {
result = conn->m->result_init(stmt->result->field_count);
if (!result) {
@@ -561,28 +586,30 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s, enum_mysqlnd_parse_e
DBG_INF_FMT("server_status=%u cursor=%u", UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status),
UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS);
if (UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS) {
DBG_INF("cursor exists");
stmt->cursor_exists = TRUE;
SET_CONNECTION_STATE(&conn->state, CONN_READY);
/* Only cursor read */
stmt->default_rset_handler = s->m->use_result;
DBG_INF("use_result");
} else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
DBG_INF("asked for cursor but got none");
/*
We have asked for CURSOR but got no cursor, because the condition
above is not fulfilled. Then...
if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
if (UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS) {
DBG_INF("cursor exists");
stmt->cursor_exists = TRUE;
SET_CONNECTION_STATE(&conn->state, CONN_READY);
/* Only cursor read */
stmt->default_rset_handler = s->m->use_result;
DBG_INF("use_result");
} else {
DBG_INF("asked for cursor but got none");
/*
We have asked for CURSOR but got no cursor, because the condition
above is not fulfilled. Then...
This is a single-row result set, a result set with no rows, EXPLAIN,
SHOW VARIABLES, or some other command which either a) bypasses the
cursors framework in the server and writes rows directly to the
network or b) is more efficient if all (few) result set rows are
precached on client and server's resources are freed.
*/
/* preferred is buffered read */
stmt->default_rset_handler = s->m->store_result;
DBG_INF("store_result");
This is a single-row result set, a result set with no rows, EXPLAIN,
SHOW VARIABLES, or some other command which either a) bypasses the
cursors framework in the server and writes rows directly to the
network or b) is more efficient if all (few) result set rows are
precached on client and server's resources are freed.
*/
/* preferred is buffered read */
stmt->default_rset_handler = s->m->store_result;
DBG_INF("store_result");
}
} else {
DBG_INF("no cursor");
/* preferred is unbuffered read */
@@ -940,11 +967,7 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s)
}
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
if (!stmt->field_count ||
(!stmt->cursor_exists && GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA) ||
(stmt->cursor_exists && GET_CONNECTION_STATE(&conn->state) != CONN_READY) ||
(stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE))
{
if (!stmt->field_count || !mysqlnd_stmt_check_state(stmt)) {
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
DBG_ERR("command out of sync");
DBG_RETURN(NULL);
@@ -974,7 +997,6 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned
MYSQLND_STMT * s = (MYSQLND_STMT *) param;
MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
zend_uchar buf[MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
MYSQLND_PACKET_ROW * row_packet;
DBG_ENTER("mysqlnd_fetch_stmt_row_cursor");
@@ -998,18 +1020,9 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(conn->error_info);
int4store(buf, stmt->stmt_id);
int4store(buf + MYSQLND_STMT_ID_LENGTH, 1); /* for now fetch only one row */
{
const MYSQLND_CSTRING payload = {(const char*) buf, sizeof(buf)};
ret = conn->command->stmt_fetch(conn, payload);
if (ret == FAIL) {
COPY_CLIENT_ERROR(stmt->error_info, *conn->error_info);
DBG_RETURN(FAIL);
}
/* for now fetch only one row */
if (mysqlnd_stmt_send_cursor_fetch_command(stmt, 1) == FAIL) {
DBG_RETURN(FAIL);
}
row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE;
+23 -22
View File
@@ -1616,8 +1616,28 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
}
MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, STAT_BYTES_RECEIVED_PURE_DATA_TEXT, len);
}
if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
/*
BIT fields are specially handled. As they come as bit mask, they have
to be converted to human-readable representation.
*/
ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len);
/*
We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
later in this function there will be an advancement.
*/
p -= len;
if (Z_TYPE_P(current_field) == IS_LONG && !as_int_or_float) {
/* we are using the text protocol, so convert to string */
char tmp[22];
const size_t tmp_len = sprintf((char *)&tmp, ZEND_ULONG_FMT, Z_LVAL_P(current_field));
ZVAL_STRINGL(current_field, tmp, tmp_len);
} else if (Z_TYPE_P(current_field) == IS_STRING) {
/* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
}
}
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
if (as_int_or_float && perm_bind.php_type == IS_LONG) {
else if (as_int_or_float && perm_bind.php_type == IS_LONG) {
zend_uchar save = *(p + len);
/* We have to make it ASCIIZ temporarily */
*(p + len) = '\0';
@@ -1661,28 +1681,9 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
*(p + len) = '\0';
ZVAL_DOUBLE(current_field, atof((char *) p));
*(p + len) = save;
} else
}
#endif /* MYSQLND_STRING_TO_INT_CONVERSION */
if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
/*
BIT fields are specially handled. As they come as bit mask, they have
to be converted to human-readable representation.
*/
ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len);
/*
We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
later in this function there will be an advancement.
*/
p -= len;
if (Z_TYPE_P(current_field) == IS_LONG && !as_int_or_float) {
/* we are using the text protocol, so convert to string */
char tmp[22];
const size_t tmp_len = sprintf((char *)&tmp, ZEND_ULONG_FMT, Z_LVAL_P(current_field));
ZVAL_STRINGL(current_field, tmp, tmp_len);
} else if (Z_TYPE_P(current_field) == IS_STRING) {
/* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
}
} else if (len == 0) {
else if (len == 0) {
ZVAL_EMPTY_STRING(current_field);
} else if (len == 1) {
ZVAL_INTERNED_STR(current_field, ZSTR_CHAR((zend_uchar)*(char *)p));
+18 -20
View File
@@ -609,7 +609,7 @@ PHP_METHOD(Phar, webPhar)
if (NULL == (z_script_name = zend_hash_str_find(_server, "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) ||
IS_STRING != Z_TYPE_P(z_script_name) ||
!strstr(Z_STRVAL_P(z_script_name), basename)) {
return;
goto finish;
}
if (NULL != (z_path_info = zend_hash_str_find(_server, "PATH_INFO", sizeof("PATH_INFO")-1)) &&
@@ -634,7 +634,7 @@ PHP_METHOD(Phar, webPhar)
testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1);
if (!(pt = strstr(testit, basename))) {
efree(testit);
return;
goto finish;
}
path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1);
@@ -659,7 +659,7 @@ PHP_METHOD(Phar, webPhar)
if (!(pt = strstr(path_info, basename))) {
/* this can happen with rewrite rules - and we have no idea what to do then, so return */
return;
goto finish;
}
entry_len = strlen(path_info);
@@ -685,7 +685,7 @@ PHP_METHOD(Phar, webPhar)
}
efree(pt);
return;
goto finish;
}
fci.param_count = 1;
@@ -703,7 +703,7 @@ PHP_METHOD(Phar, webPhar)
}
efree(pt);
return;
goto finish;
}
if (Z_TYPE_P(fci.retval) == IS_UNDEF || Z_TYPE(retval) == IS_UNDEF) {
@@ -712,7 +712,7 @@ PHP_METHOD(Phar, webPhar)
}
zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false");
efree(pt);
return;
goto finish;
}
switch (Z_TYPE(retval)) {
@@ -731,7 +731,7 @@ PHP_METHOD(Phar, webPhar)
efree(pt);
zend_bailout();
return;
goto finish;
default:
if (free_pathinfo) {
efree(path_info);
@@ -739,7 +739,7 @@ PHP_METHOD(Phar, webPhar)
efree(pt);
zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false");
return;
goto finish;
}
}
@@ -812,9 +812,6 @@ PHP_METHOD(Phar, webPhar)
if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) ||
(info = phar_get_entry_info(phar, entry, entry_len, NULL, 0)) == NULL) {
phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len);
#ifdef PHP_WIN32
efree(fname);
#endif
zend_bailout();
}
@@ -838,10 +835,8 @@ PHP_METHOD(Phar, webPhar)
}
efree(pt);
efree(entry);
#ifdef PHP_WIN32
efree(fname);
#endif
RETURN_FALSE;
RETVAL_FALSE;
goto finish;
}
break;
case IS_STRING:
@@ -855,10 +850,8 @@ PHP_METHOD(Phar, webPhar)
}
efree(pt);
efree(entry);
#ifdef PHP_WIN32
efree(fname);
#endif
RETURN_FALSE;
RETVAL_FALSE;
goto finish;
}
}
}
@@ -868,6 +861,11 @@ PHP_METHOD(Phar, webPhar)
code = phar_file_type(&PHAR_G(mime_types), entry, &mime_type);
}
phar_file_action(phar, info, mime_type, code, entry, entry_len, fname, pt, ru, ru_len);
finish: ;
#ifdef PHP_WIN32
efree(fname);
#endif
}
/* }}} */
@@ -4277,7 +4275,7 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
return FAILURE;
}
if (!phar_get_efp(entry, 0)) {
if ((phar_get_fp_type(entry) == PHAR_FP && (entry->flags & PHAR_ENT_COMPRESSION_MASK)) || !phar_get_efp(entry, 0)) {
if (FAILURE == phar_open_entry_fp(entry, error, 1)) {
if (error) {
spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer: %s", entry->filename, fullpath, *error);
+29
View File
@@ -0,0 +1,29 @@
--TEST--
Bug #69279 (Compressed ZIP Phar extractTo() creates garbage files)
--SKIPIF--
<?php
if (!extension_loaded('phar')) die('skip phar extension not available');
?>
--INI--
phar.readonly=0
--FILE--
<?php
$w = new Phar(__DIR__ . "/bug69279.phar.zip");
$w["bug69279.txt"] = "Sample content.";
$w->compressFiles(Phar::GZ);
unset($w);
$r = new Phar(__DIR__ . "/bug69279.phar.zip");
var_dump($r["bug69279.txt"]->isCompressed());
$r->extractTo(__DIR__, NULL, TRUE);
var_dump(file_get_contents(__DIR__ . "/bug69279.txt"));
?>
--EXPECT--
bool(true)
string(15) "Sample content."
--CLEAN--
<?php
@unlink(__DIR__ . "/bug69279.txt");
@unlink(__DIR__ . "/bug69279.phar.zip");
?>
+26
View File
@@ -0,0 +1,26 @@
--TEST--
Bug #69279 (Compressed ZIP Phar extractTo() creates garbage files)
--SKIPIF--
<?php
if (!extension_loaded('phar')) die('skip phar extension not available');
?>
--FILE--
<?php
$phar = new PharData(__DIR__ . '/bug69279a.zip');
mkdir(__DIR__ . '/bug69279a');
var_dump($phar->extractTo(__DIR__ . '/bug69279a', null, true));
var_dump(strncmp(file_get_contents(__DIR__ . '/bug69279a/1.txt'), 'Lorem ipsum', 11));
var_dump(strncmp(file_get_contents(__DIR__ . '/bug69279a/2.txt'), 'foo', 3));
var_dump(strncmp(file_get_contents(__DIR__ . '/bug69279a/3.txt'), 'Lorem ipsum', 11));
?>
--EXPECT--
bool(true)
int(0)
int(0)
int(0)
--CLEAN--
<?php
@unlink(__DIR__ . '/bug69279a/1.txt');
@unlink(__DIR__ . '/bug69279a/2.txt');
@unlink(__DIR__ . '/bug69279a/3.txt');
@rmdir(__DIR__ . '/bug69279a');
Binary file not shown.
+1 -1
View File
@@ -14,7 +14,7 @@ $r = new Phar($fname, 0);
==DONE==
--EXPECTF--
UnexpectedValueException: phar error: corrupted central directory entry, no magic signature in zip-based phar "%sbug69441.phar" in %sbug69441.php:%d
UnexpectedValueException: phar error: end of central directory not found in zip-based phar "%sbug69441.phar" in %sbug69441.php:%d
Stack trace:
#0 %s%ebug69441.php(%d): Phar->__construct('%s', 0)
#1 {main}
+13
View File
@@ -0,0 +1,13 @@
--TEST--
Bug #77565 (Incorrect locator detection in ZIP-based phars)
--SKIPIF--
<?php
if (!extension_loaded('phar')) die('skip phar extension not available');
?>
--FILE--
<?php
$phar = new PharData(__DIR__ . '/bug77565.zip');
var_dump($phar['1.zip']->getFilename());
?>
--EXPECT--
string(5) "1.zip"
Binary file not shown.
+35
View File
@@ -0,0 +1,35 @@
--TEST--
Bug #79912 (Phar::decompressFiles not working)
--SKIPIF--
<?php
if (!extension_loaded('phar')) die('skip phar extension is not available');
?>
--INI--
phar.readonly=0
--FILE--
<?php
$phar = new Phar(__DIR__ . "/bug79912.phar");
$phar->addFromString("test.txt", "This is a test file.This is a test file.This is a test file.");
$file = $phar["test.txt"];
var_dump($file->compress(Phar::GZ)); //true (success)
var_dump($file->getContent());
var_dump($file->isCompressed()); //true (the file is compressed)
var_dump($phar->decompressFiles()); //true (success)
var_dump($file->isCompressed()); //false (the file should not be compressed anymore)
var_dump($phar->extractTo(__DIR__ . "/bug79912")); //true
var_dump(file_get_contents(__DIR__ . "/bug79912/test.txt")); //the extracted file in the folder should be decompressed
?>
--EXPECT--
bool(true)
string(60) "This is a test file.This is a test file.This is a test file."
bool(true)
bool(true)
bool(false)
bool(true)
string(60) "This is a test file.This is a test file.This is a test file."
--CLEAN--
<?php
@unlink(__DIR__ . "/bug79912/test.txt");
@rmdir(__DIR__ . "/bug79912");
@unlink(__DIR__ . "/bug79912.phar");
?>
+1 -1
View File
@@ -12,5 +12,5 @@ try {
?>
===DONE===
--EXPECTF--
phar error: corrupt zip archive, zip file comment truncated in zip-based phar "%sfilecomment.zip"
phar error: end of central directory not found in zip-based phar "%sfilecomment.zip"
===DONE===
+70 -49
View File
@@ -161,6 +161,29 @@ static void phar_zip_u2d_time(time_t time, char *dtime, char *ddate) /* {{{ */
}
/* }}} */
static char *phar_find_eocd(const char *s, size_t n)
{
const char *end = s + n + sizeof("PK\5\6") - 1 - sizeof(phar_zip_dir_end);
/* search backwards for end of central directory signatures */
do {
uint16_t comment_len;
const char *eocd_start = zend_memnrstr(s, "PK\5\6", sizeof("PK\5\6") - 1, end);
if (eocd_start == NULL) {
return NULL;
}
ZEND_ASSERT(eocd_start + sizeof(phar_zip_dir_end) <= s + n);
comment_len = PHAR_GET_16(((phar_zip_dir_end *) eocd_start)->comment_len);
if (eocd_start + sizeof(phar_zip_dir_end) + comment_len == s + n) {
/* we can't be sure, but this looks like the proper EOCD signature */
return (char *) eocd_start;
}
end = eocd_start;
} while (end > s);
return NULL;
}
/**
* Does not check for a previously opened phar in the cache.
*
@@ -205,57 +228,55 @@ int phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alia
return FAILURE;
}
while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) {
if ((p - buf) + sizeof(locator) <= (size_t)size && !memcmp(p + 1, "K\5\6", 3)) {
memcpy((void *)&locator, (void *) p, sizeof(locator));
if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) {
/* split archives not handled */
php_stream_close(fp);
if (error) {
spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname);
}
return FAILURE;
if ((p = phar_find_eocd(buf, size)) != NULL) {
memcpy((void *)&locator, (void *) p, sizeof(locator));
if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) {
/* split archives not handled */
php_stream_close(fp);
if (error) {
spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname);
}
if (PHAR_GET_16(locator.counthere) != PHAR_GET_16(locator.count)) {
if (error) {
spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname);
}
php_stream_close(fp);
return FAILURE;
}
mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
mydata->is_persistent = PHAR_G(persist);
/* read in archive comment, if any */
if (PHAR_GET_16(locator.comment_len)) {
metadata = p + sizeof(locator);
if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
if (error) {
spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
}
php_stream_close(fp);
pefree(mydata, mydata->is_persistent);
return FAILURE;
}
mydata->metadata_len = PHAR_GET_16(locator.comment_len);
if (phar_parse_metadata(&metadata, &mydata->metadata, PHAR_GET_16(locator.comment_len)) == FAILURE) {
mydata->metadata_len = 0;
/* if not valid serialized data, it is a regular string */
ZVAL_NEW_STR(&mydata->metadata, zend_string_init(metadata, PHAR_GET_16(locator.comment_len), mydata->is_persistent));
}
} else {
ZVAL_UNDEF(&mydata->metadata);
}
goto foundit;
return FAILURE;
}
if (PHAR_GET_16(locator.counthere) != PHAR_GET_16(locator.count)) {
if (error) {
spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname);
}
php_stream_close(fp);
return FAILURE;
}
mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
mydata->is_persistent = PHAR_G(persist);
/* read in archive comment, if any */
if (PHAR_GET_16(locator.comment_len)) {
metadata = p + sizeof(locator);
if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
if (error) {
spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
}
php_stream_close(fp);
pefree(mydata, mydata->is_persistent);
return FAILURE;
}
mydata->metadata_len = PHAR_GET_16(locator.comment_len);
if (phar_parse_metadata(&metadata, &mydata->metadata, PHAR_GET_16(locator.comment_len)) == FAILURE) {
mydata->metadata_len = 0;
/* if not valid serialized data, it is a regular string */
ZVAL_NEW_STR(&mydata->metadata, zend_string_init(metadata, PHAR_GET_16(locator.comment_len), mydata->is_persistent));
}
} else {
ZVAL_UNDEF(&mydata->metadata);
}
goto foundit;
}
php_stream_close(fp);
+1
View File
@@ -555,6 +555,7 @@ static char **_readline_completion_cb(const char *text, int start, int end)
if (call_user_function(NULL, NULL, &_readline_completion, &_readline_array, 3, params) == SUCCESS) {
if (Z_TYPE(_readline_array) == IS_ARRAY) {
SEPARATE_ARRAY(&_readline_array);
if (zend_hash_num_elements(Z_ARRVAL(_readline_array))) {
matches = rl_completion_matches(text,_readline_command_generator);
} else {
+1 -5
View File
@@ -831,10 +831,6 @@ PHP_FUNCTION(tempnam)
Z_PARAM_PATH(prefix, prefix_len)
ZEND_PARSE_PARAMETERS_END();
if (php_check_open_basedir(dir)) {
RETURN_FALSE;
}
p = php_basename(prefix, prefix_len, NULL, 0);
if (ZSTR_LEN(p) > 64) {
ZSTR_VAL(p)[63] = '\0';
@@ -842,7 +838,7 @@ PHP_FUNCTION(tempnam)
RETVAL_FALSE;
if ((fd = php_open_temporary_fd_ex(dir, ZSTR_VAL(p), &opened_path, 1)) >= 0) {
if ((fd = php_open_temporary_fd_ex(dir, ZSTR_VAL(p), &opened_path, PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ALWAYS)) >= 0) {
close(fd);
RETVAL_STR(opened_path);
}
+27 -27
View File
@@ -53,17 +53,17 @@ var_dump( $temp_array);
echo "\n-- Testing ksort() by supplying string array (case insensitive), 'flag' = SORT_STRING|SORT_FLAG_CASE --\n";
$temp_array = $unsorted_strings;
var_dump( sort($temp_array, SORT_STRING|SORT_FLAG_CASE) ); // expecting : bool(true)
var_dump( ksort($temp_array, SORT_STRING|SORT_FLAG_CASE) ); // expecting : bool(true)
var_dump( $temp_array);
echo "\n-- Testing ksort() by supplying string array (natural), 'flag' = SORT_NATURAL --\n";
$temp_array = $unsorted_strings;
var_dump( sort($temp_array, SORT_NATURAL) ); // expecting : bool(true)
var_dump( ksort($temp_array, SORT_NATURAL) ); // expecting : bool(true)
var_dump( $temp_array);
echo "\n-- Testing ksort() by supplying string array (natural, case insensitive), 'flag' = SORT_NATURAL|SORT_FLAG_CASE --\n";
$temp_array = $unsorted_strings;
var_dump( sort($temp_array, SORT_NATURAL|SORT_FLAG_CASE) ); // expecting : bool(true)
var_dump( ksort($temp_array, SORT_NATURAL|SORT_FLAG_CASE) ); // expecting : bool(true)
var_dump( $temp_array);
echo "\n-- Testing ksort() by supplying numeric array, 'flag' = SORT_NUMERIC --\n";
@@ -168,63 +168,63 @@ array(8) {
-- Testing ksort() by supplying string array (case insensitive), 'flag' = SORT_STRING|SORT_FLAG_CASE --
bool(true)
array(8) {
[0]=>
["b"]=>
string(6) "banana"
[1]=>
["l"]=>
string(5) "lemon"
[2]=>
["o"]=>
string(6) "orange"
[3]=>
["O"]=>
string(6) "Orange"
[4]=>
["O1"]=>
string(7) "Orange1"
[5]=>
["o2"]=>
string(7) "orange2"
[6]=>
["o20"]=>
string(8) "orange20"
[7]=>
["O3"]=>
string(7) "Orange3"
}
-- Testing ksort() by supplying string array (natural), 'flag' = SORT_NATURAL --
bool(true)
array(8) {
[0]=>
["O"]=>
string(6) "Orange"
[1]=>
["O1"]=>
string(7) "Orange1"
[2]=>
["O3"]=>
string(7) "Orange3"
[3]=>
["b"]=>
string(6) "banana"
[4]=>
["l"]=>
string(5) "lemon"
[5]=>
["o"]=>
string(6) "orange"
[6]=>
["o2"]=>
string(7) "orange2"
[7]=>
["o20"]=>
string(8) "orange20"
}
-- Testing ksort() by supplying string array (natural, case insensitive), 'flag' = SORT_NATURAL|SORT_FLAG_CASE --
bool(true)
array(8) {
[0]=>
["b"]=>
string(6) "banana"
[1]=>
["l"]=>
string(5) "lemon"
[2]=>
["o"]=>
string(6) "orange"
[3]=>
["O"]=>
string(6) "Orange"
[4]=>
["O1"]=>
string(7) "Orange1"
[5]=>
["o2"]=>
string(7) "orange2"
[6]=>
["O3"]=>
string(7) "Orange3"
[7]=>
["o20"]=>
string(8) "orange20"
}
+17
View File
@@ -0,0 +1,17 @@
--TEST--
Bug #42560 Empty directory argument to tempnam yields open_basedir problems
--FILE--
<?php
$tmpdir = sys_get_temp_dir();
ini_set('open_basedir', $tmpdir);
$tempnam = tempnam('', 'test');
var_dump($tempnam !== false);
var_dump(file_exists($tempnam));
if (file_exists($tempnam)) {
unlink($tempnam);
}
?>
--EXPECT--
bool(true)
bool(true)
+1 -1
View File
@@ -52,6 +52,6 @@ fclose($f2);
--EXPECT--
filter onCreate
filtered 8192 bytes.
filtered 128 bytes and closing.
filtered 128 bytes and closing. Stream has reached end-of-file.
int(8320)
filter onClose
+8 -2
View File
@@ -301,13 +301,19 @@ PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, zend_strin
def_tmp:
temp_dir = php_get_temporary_directory();
if (temp_dir && *temp_dir != '\0' && (!(flags & PHP_TMP_FILE_OPEN_BASEDIR_CHECK) || !php_check_open_basedir(temp_dir))) {
if (temp_dir &&
*temp_dir != '\0' &&
(!(flags & PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ON_FALLBACK) || !php_check_open_basedir(temp_dir))) {
return php_do_open_temporary_file(temp_dir, pfx, opened_path_p);
} else {
return -1;
}
}
if ((flags & PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ON_EXPLICIT_DIR) && php_check_open_basedir(dir)) {
return -1;
}
/* Try the directory given as parameter. */
fd = php_do_open_temporary_file(dir, pfx, opened_path_p);
if (fd == -1) {
@@ -322,7 +328,7 @@ def_tmp:
PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, zend_string **opened_path_p)
{
return php_open_temporary_fd_ex(dir, pfx, opened_path_p, 0);
return php_open_temporary_fd_ex(dir, pfx, opened_path_p, PHP_TMP_FILE_DEFAULT);
}
PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, zend_string **opened_path_p)
+9 -1
View File
@@ -19,8 +19,16 @@
#ifndef PHP_OPEN_TEMPORARY_FILE_H
#define PHP_OPEN_TEMPORARY_FILE_H
#define PHP_TMP_FILE_OPEN_BASEDIR_CHECK (1<<0)
#define PHP_TMP_FILE_DEFAULT 0
#define PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ON_FALLBACK (1<<0)
#define PHP_TMP_FILE_SILENT (1<<1)
#define PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ON_EXPLICIT_DIR (1<<2)
#define PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ALWAYS \
(PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ON_FALLBACK | PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ON_EXPLICIT_DIR)
/* for compatibility purpose */
#define PHP_TMP_FILE_OPEN_BASEDIR_CHECK PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ON_FALLBACK
BEGIN_EXTERN_C()
PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, zend_string **opened_path_p);
+4 -4
View File
@@ -2,7 +2,7 @@
/* edit configure.ac to change version number */
#define PHP_MAJOR_VERSION 7
#define PHP_MINOR_VERSION 4
#define PHP_RELEASE_VERSION 14
#define PHP_EXTRA_VERSION ""
#define PHP_VERSION "7.4.14"
#define PHP_VERSION_ID 70414
#define PHP_RELEASE_VERSION 15
#define PHP_EXTRA_VERSION "RC2"
#define PHP_VERSION "7.4.15RC2"
#define PHP_VERSION_ID 70415
+1 -1
View File
@@ -1009,7 +1009,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
/* in non-debug mode we have no problem with 0-length files */
{
#endif
fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), "php", &temp_filename, 1);
fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), "php", &temp_filename, PHP_TMP_FILE_OPEN_BASEDIR_CHECK_ON_FALLBACK);
upload_cnt--;
if (fd == -1) {
sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file");
+2 -1
View File
@@ -542,6 +542,7 @@ PHPAPI int _php_stream_fill_read_buffer(php_stream *stream, size_t size)
/* allocate/fill the buffer */
if (stream->readfilters.head) {
size_t to_read_now = MIN(size, stream->chunk_size);
char *chunk_buf;
php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL };
php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out, *brig_swap;
@@ -549,7 +550,7 @@ PHPAPI int _php_stream_fill_read_buffer(php_stream *stream, size_t size)
/* allocate a buffer for reading chunks */
chunk_buf = emalloc(stream->chunk_size);
while (!stream->eof && (stream->writepos - stream->readpos < (zend_off_t)size)) {
while (!stream->eof && (stream->writepos - stream->readpos < (zend_off_t)to_read_now)) {
ssize_t justread = 0;
int flags;
php_stream_bucket *bucket;
+28
View File
@@ -0,0 +1,28 @@
--TEST--
Bug #80384 large reads cause filters to internally buffer large amounts of memory
--FILE--
<?php
/* First, create a file to read */
$tmp_filename = __DIR__ . "/bug80384.tmp";
$fp = fopen($tmp_filename, 'w');
for ($i=0; $i<1024; $i++) {
fwrite($fp, str_repeat('ABCDEFGH', 1024));
}
fclose($fp);
/* Stream the file through a filter */
$fp = fopen($tmp_filename, 'r');
$filter = stream_filter_append($fp, "string.rot13");
$mem_start = memory_get_usage();
fread($fp, 8 * 1024 * 1024);
$mem_final = memory_get_usage();
fclose($fp);
var_dump($mem_final - $mem_start < 32768);
?>
--CLEAN--
<?php
unlink(__DIR__ . "/bug80384.tmp");
?>
--EXPECT--
bool(true)
+1 -1
View File
@@ -63,7 +63,7 @@ bool(false)
Warning: tempnam(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d
bool(false)
Warning: tempnam(): open_basedir restriction in effect. File() is not within the allowed path(s): (.) in %s on line %d
Warning: tempnam(): open_basedir restriction in effect. File(%s) is not within the allowed path(s): (.) in %s on line %d
bool(false)
string(%d) "%s"
bool(true)