Compare commits

..
134 Commits
Author SHA1 Message Date
Gabriel Caruso a66aeecc2c Update versions for PHP 8.0.2 2021-02-02 19:24:50 +00:00
Nikita Popov 3424432ec9 Fix build 2021-02-02 16:19:14 -03:00
Stanislav Malyshev f733ee1954 Fix bug #80672 - Null Dereference in SoapClient 2021-02-02 16:18:44 -03:00
Gabriel Caruso 5070a0f689 Update NEWS for PHP 8.0.2 2021-02-02 11:10:39 +00:00
Gabriel Caruso b4814d7456 [ci-skip] Fix typo in placeholder 2021-02-02 08:05:49 -03:00
Gabriel Caruso 08b44a47ca [ci-skip] Remove RC suffix to release non-RC 2021-02-02 08:02:36 -03:00
Gabriel Caruso 966ee42d34 [ci-skip] Fix placeholder for non-RC release 2021-02-02 07:56:25 -03:00
Stanislav Malyshev 946e00afd6 Rm unneeded function 2021-02-02 07:46:30 -03:00
Christoph M. Becker 605d9f55ad Alternative fix for bug 77423
That bug report originally was about `parse_url()` misbehaving, but the
security aspect was actually only regarding `FILTER_VALIDATE_URL`.
Since the changes to `parse_url_ex()` apparently affect userland code
which is relying on the sloppy URL parsing[1], this alternative
restores the old parsing behavior, but ensures that the userinfo is
checked for correctness for `FILTER_VALIDATE_URL`.

[1] <https://github.com/php/php-src/commit/5174de7cd33c3d4fa591c9c93859ff9989b07e8c#commitcomment-45967652>
2021-02-02 07:45:26 -03:00
Gabriel Caruso 5e21867c55 Update NEWS for PHP 8.0.2RC1 2021-01-19 15:41:46 +00:00
Gabriel Caruso 9ce200f6cb Fix NEWS placeholder for the next version
This aligns with the PHP-7.4 and PHP-7.3 branches, and should
fix the `sgolemon/php-release` script run for releasing 8.0.2.
2021-01-19 12:32:17 -03:00
Derick Rethans b5599a37d7 Merge branch 'PHP-7.4' into PHP-8.0 2021-01-19 14:59:19 +00:00
Derick Rethans a33d0c3aae Update NEWS and version 2021-01-19 14:58:38 +00:00
Derick Rethans e8a89c49db Update NEWS for PHP 7.4.15RC1 2021-01-19 14:44:32 +00:00
Nikita Popov f3415758d1 Fix observer tests on Windows
Use %e instead of a hardcoded forward slash.
2021-01-19 15:27:14 +01:00
Nikita Popov 05d168013a Fixed bug #80644: ResourceBundle::get() doesn't reset error state 2021-01-19 15:20:55 +01:00
Nikita Popov 1bdd8f7ae4 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fixed bug #42560
2021-01-19 11:44:22 +01: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. Becker f33105dcb6 ldap_search() and friends can return array
See the description of <https://www.php.net/ldap-search>, and also the
implementation.

Closes GH-6620.
2021-01-19 10:35:17 +01:00
Christoph M. Becker cfae999f1b Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fix #69279: Compressed ZIP Phar extractTo() creates garbage files
2021-01-19 10:30:28 +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
Dylan K. Taylor 872f302b8d Keep JIT region executable under ZTS
When one thread tries to compile a script, another thread may
already be executing JITed code. In this case we can't make the
memory non-executable.

This violates the W^X principle, but doesn't seem to be avoidable
for ZTS builds for now. The same problem does not exist for NTS,
as it's a different process executing there, which has it's own
memory protection mapping.

Closes GH-6595.
2021-01-19 10:25:42 +01:00
Nikita Popov fbd8e20ed5 Observe unused return values in JIT
Even if the return value is not used, it should still be available
to the observer.
2021-01-19 10:09:53 +01:00
Nikita Popov dd7d829896 Disable opcache optimizations during some observer tests
Opcache inlines functions that only return a constant. Disable
optimizations to prevent differences in tests where such functions
are used (or rewrite the test to not depend on it).
2021-01-19 10:02:08 +01:00
Nikita Popov f2364f316d SplFileObject::fgets() cannot return false
spl_filesystem_file_read() is called with silent=0, so it will
throw on failure.
2021-01-18 16:47:21 +01:00
Nikita Popov 7290dc4dcf Sync gzgets signature with fgets 2021-01-18 15:47:12 +01:00
Nikita Popov ebf461a025 Sync datefmt_get_calendar_object signature
In this case, it's only a matter of using the same type order
in both cases.
2021-01-18 14:39:32 +01:00
Nikita Popov 39077deea5 Sync intlcal_create_instance() and IntlCalendar::createInstance()
Remove the explicit mention of IntlGregorianCalendar in the latter.
It is a subclass of IntlCalendar, and as such covered if only
IntlCalendar is used as the return type.
2021-01-18 14:39:32 +01:00
Nikita Popov c31f9f7ee4 Sync date_diff and DateTime::diff return type
This function/method cannot return false.
2021-01-18 14:39:32 +01:00
Nikita Popov 48e2e5324e Fix parameter name of PharData::getMetadata()
The name should be the same as for Phar::getMetadata().
2021-01-18 14:09:00 +01:00
Dylan K. Taylor 0aad77418d Fix stub for Phar::setStub()
This fixes multiple issues:
 * The first parameter may be resource|string.
 * It's an overloaded signature. The second parameter cannot be
   passed if the first one is a string. Use UNKNOWN default
   value for that reason.
 * Make parameter names in PharData::setStub() match those in
   Phar.

Closes GH-6596.
2021-01-18 12:59:18 +01:00
Christoph M. Becker c321896a37 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fix #80595: Resetting POSTFIELDS to empty array breaks request
2021-01-18 11:01:01 +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
Nikita Popov 880bf62224 Fixed bug #80617: Type narrowing warning in ZEND_TYPE_INIT_CODE 2021-01-14 10:08:22 +01:00
Daniil Gentili f9fbba41b6 Fixed bug #80596: Fix anonymous class union typehint errors
Cut off part after null byte when resolving the class name, to
avoid cutting off a larger part lateron.

Closes GH-6601.
2021-01-14 10:04:27 +01:00
Dmitry Stogov 3edf5c969a Fixed bug #80422 (php_opcache.dll crashes when using Apache 2.4 with JIT) 2021-01-14 08:16:27 +03:00
Christoph M. Becker 41e9a8ebdc socket_create_pair() can no longer return NULL
Closes GH-6592.
2021-01-12 12:08:31 +01:00
David CARLIER 7a049cd6a4 Use arc4random_buf on macOS
macOS uses an AES based arc4random_buf implementation since at least
macOS 10.2.

Closes GH-6591.
2021-01-12 10:42:09 +01:00
Nikita Popov 973138f39d Add support for union types for internal functions
This closes the last hole in the supported types for internal
function arginfo types. It's now possible to represent unions of
multiple classes. This is done by storing them as TypeA|TypeB and
PHP will then convert this into an appropriate union type list.

Closes GH-6581.
2021-01-12 10:14:41 +01:00
Nikita Popov bc0f78a2da Use ephemeral port in socket_create_listen_used.phpt
Avoid parallelism issues.
2021-01-12 10:09:30 +01:00
Jens de Nies 94a151a018 Fixed bug #80545
This converts the remaining "non well-formed" warnings in bcmath
to ValueErrors, in line with the other warning promotions that
have been performed in this extension.

Closes GH-80545.
2021-01-12 09:50:27 +01:00
Christoph M. Becker 95a13ca989 Revert fix for bug 76813 and re2c version bump
CentOS 7 ships with re2c 0.13.5 by default, so we should not have
bumped the required re2c version to 0.13.7.  However, 0.13.5 does not
support default rules, so we cannot use them to fix bug 76813.

This reverts commit 420184ad52 and
5e15c9c41f.

Closes GH-6593.
2021-01-11 17:19:52 +01:00
Christoph M. Becker 52ed45745e Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Revert "Fix #76813: Access violation near NULL on source operand"
2021-01-11 13:21: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
Dmitry Stogov 35e0506a2e Add guard if lvalue of assignment may be a reference, but wasn't a reference during recording 2021-01-11 15:12:27 +03:00
George Peter Banyard f40838eaaa Rename `zip_ent parameter to zip_entry` for consistency
All other functions use ``zip_entry``
2021-01-08 22:26:24 +00:00
Christoph M. Becker 8ae02c8a95 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Avoid modifying the return value of readline_completion_function()
2021-01-07 13:48:17 +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
Dharman 34ef804b04 Make fetch_* OO same as func
Clsoses GH-6580.
2021-01-06 15:02:52 +01:00
Christoph M. Becker f674a3343c Fix #80592: all floats are the same in ODBC parameters
We must not release the strings until we are done with them.

Closes GH-6579.
2021-01-06 13:56:02 +01:00
Dharman 44a311dbbe Fix/improve mysqli stubs
* mysqli_commit $flags default value is 0, not -1.
* A number of functions cannot actually return null.
* mysqli_poll parameter names were incorrect, as this function
  has a different signature from select.
* fetch functions apart from fetch_all can return false on failure.
2021-01-06 11:28:45 +01:00
Christoph M. Becker 90081c5391 Add missing SKIPIF clause for require_hash.phpt 2021-01-06 11:00:10 +01:00
Christoph M. Becker 66a74f2f4a Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fix #77565: Incorrect locator detection in ZIP-based phars
2021-01-05 23:46:05 +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 b7689db7ab Prevent double-free of Phar ZIP stream
We must not alias the closed stream to `phar_archive_data.fp`, and use
PHAR_ZIP_FAIL() for consistency with the rest of this function.

Closes GH-6578.
2021-01-05 14:31:43 +01:00
Christoph M. Becker afc69e46b8 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fix memory leak in Phar::webPhar() on Windows
2021-01-05 14:25:44 +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
Nikita Popov dd335359e9 Fix infinite recursion in unlinked_instanceof
I suspect this is only a partial fix for the issue, it's probably
possible to recurse through a more complex pathway as well.

Fixes oss-fuzz #28961.
2021-01-05 13:03:41 +01:00
Nikita Popov 5e57f37247 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  gdbinit: use ____print_str to print htable keys
2021-01-05 10:12:43 +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
Christoph M. Becker 121790eaff [ci skip] Add forgotten NEWS entry (bug 80560) 2021-01-04 18:19:45 +01:00
George Peter Banyard 764b7bf108 Fix bug #80584: 0x and 0X are considered valid hex numbers by filter_var()
Closes GH-6573
2021-01-04 18:07:47 +01:00
Christoph M. Becker 9f96b2bdc8 Fix #76929: zip-based phar does not respect phar.require_hash
Based on the patch provided by david at bamsoftware.

Closes GH-6517.
2021-01-04 17:48:45 +01:00
Nikita Popov 821eaaf0b4 Fix newly added GMP test 2021-01-04 15:27:20 +01:00
George Peter Banyard 1b5c62facd Fix GMP comparison object handler
gmp_cmp() doesn't return false anymore in PHP 8 but will throw
an Error if compared to a non numeric string or another type of object.

Closes GH-6553
2021-01-04 14:47:50 +01:00
Nikita Popov af7445b9ac Try to fix intermittent failures of stream_server_reneg_limit.phpt on macos
Make sure the server has started up before we try to connect to it.
2021-01-04 14:31:42 +01:00
Nikita Popov 65f14b0d6c Throw ValueError instead of TypeError for malformed GMP number
If the passed argument has correct type (string) but does not
have a well-formed value, throw ValueError instead of TypeError.

Closes GH-6572.
2021-01-04 14:30:08 +01:00
Christoph M. Becker abe23bd9a3 SQLite3::query() cannot return null 2021-01-04 12:13:06 +01:00
David CARLIER 6e90c75507 Mac M1 crc32 detection support
Closes GH-6556.
2021-01-04 11:41:52 +01:00
Nikita Popov 151fce1129 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Disable non-cron travis jobs
2021-01-04 10:55:50 +01:00
Stanislav Malyshev bf2bb39eac Fix test name 2021-01-04 01:52:59 -08: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 4d1c1e4554 [ci skip] Update NEWS 2021-01-04 01:47:47 -08:00
Stanislav Malyshev ced4c0bfe6 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  [ci skip] Update NEWS
  [ci skip] Fix order
  [ci skip] Unpdate NEWS
  Fix #77423: parse_url() will deliver a wrong host to user
2021-01-04 01:47:09 -08: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 8768621149 Fix bug #79405 - gethostbyname() silently truncates after a null byte 2021-01-04 01:19:21 -08:00
Christoph M. Becker b132da7f9d 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-04 01:19:18 -08:00
Christoph M. Becker aab23282fc Fix imap stubs
Closes GH-6559.
2021-01-03 16:15:46 +01:00
Christoph M. Becker e470f9b389 ZipArchive methods do not return NULL
Closes GH-6563.
2021-01-03 16:12:10 +01: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
Christoph M. Becker cae0bcbab5 Fix parameter name
Levenshtein is about insertion, replacement and deletion.

Closes GH-6560.
2021-01-01 23:04:28 +01:00
Christoph M. Becker b2fba0ef62 Fix build
We cannot `RETURN_THROWS()` here, since `return_value` is not defined.
2021-01-01 17:41:48 +01:00
Máté Kocsis b23c865d15 Use RETURN_THROWS() in a few places 2021-01-01 16:52:48 +01:00
Christoph M. Becker 82f9e004da Fix ReflectionClass::getConstants() stub
If `zval_update_constant_ex()` fails, an exception has already been
thrown, so we clarify that in the implementation as well.

Closes GH-6557.
2021-01-01 14:46:28 +01:00
Christoph M. Becker 2e854791af [ci skip] Fix pgsql constant names in UPGRADING 2020-12-31 00:30:16 +01:00
Máté Kocsis 446ad04524 Fix refentry attribute replacing 2020-12-30 18:26:24 +01:00
George Peter Banyard abecaab09f Fix #80560: Strings containing only a base prefix return 0 object
Closes GH-6549.
2020-12-30 12:50:04 +01:00
Dmitry Stogov da0ca53f39 Initialize EX(call)->func by single instruction 2020-12-29 13:20:10 +03:00
Dmitry Stogov 56fde2a381 Reuse value stored in %r0 instead of immediate operand 2020-12-29 13:18:56 +03:00
Christoph M. Becker 13f898b56a Fix ffi stubs
Closes GH-6543.
2020-12-28 19:04:47 +01:00
Máté Kocsis 46a2c6a8d7 Fix return type of DateTimeImmutable::__set_state() 2020-12-28 14:45:13 +01:00
Máté Kocsis 9cec093b7f Add support for generating methodsynopses from stubs
Closes GH-6367
2020-12-28 14:44:43 +01:00
Christoph M. Becker 420184ad52 Bump minimum re2c version to 0.13.7
Closes GH-6516.
2020-12-28 13:43:31 +01:00
Christoph M. Becker 45b638afe0 php_formatted_print() throws on failure
Closes GH-6542.
2020-12-27 22:40:25 +01:00
Christoph M. Becker 57430e6f1e Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Replace sort() function calls with ksort() in basic ksort test
2020-12-27 18:32:03 +01:00
haszi 0db6f5267c Replace sort() function calls with ksort() in basic ksort test
Closes GH-6541.
2020-12-27 18:30:58 +01:00
Christoph M. Becker 269936e680 DateTime*::getOffset() no longer returns false as of PHP 8.0.0
Cf. <https://github.com/php/doc-en/pull/282>.

Closes GH-6539.
2020-12-26 15:13:05 +01:00
Dmitry Stogov 23bbff2b05 Eliminate redundand comparison insructions 2020-12-24 16:58:54 +03:00
Máté Kocsis ab4c5976d7 Fix the signature of FFI::typeof() and FFI::memcmp() 2020-12-24 11:45:32 +01:00
Máté Kocsis c1d766171b Add a few other RETURN_THROWS() 2020-12-24 11:44:15 +01:00
Máté Kocsis ed19cb6518 Fix the signature of FFI::sizeof() and FFI::alignof() 2020-12-24 11:39:09 +01:00
Christopher Jones 34aefa36f4 Fix PDO_OCI test 2020-12-24 17:48:39 +11:00
Semen Dubina 959d3c9636 Add regression test for bug #76770
Closes GH-3514.
2020-12-23 16:47:08 +01:00
Christoph M. Becker 7d9ddd61ec Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fix #80384: limit read buffer size
2020-12-23 13:52:45 +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 288332077f Fixed bug #80376 (last day of the month causes runway cpu usage) 2020-12-21 10:31:41 +00: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 27e250880b Fix bug #80537
This is an unavoidable breaking change to both the type and
parameter name.

The assertion that was supposed to prevent this was overly lax
and accepted any object type for string parameters.
2020-12-21 10:21:50 +01:00
Christopher Jones d6731d69bd Description typo 2020-12-21 15:46:26 +11:00
Christopher Jones 74959b47cd Bundle PECL OCI8 3.0.1 2020-12-21 15:15:16 +11:00
Christopher Jones 2877642037 Retrofit NEWS 2020-12-21 15:07:40 +11:00
Christoph M. Becker 32c6c29d79 Revert "DateTime:: and DateTimeImmutable::getTimestamp() may return false"
This reverts commit b67c232189.
2020-12-20 23:07:02 +01:00
Christoph M. Becker b67c232189 DateTime:: and DateTimeImmutable::getTimestamp() may return false 2020-12-20 19:32:12 +01:00
Christoph M. Becker 3c68f43251 Fix ext/date stubs
Closes GH-6523.
2020-12-20 18:14:20 +01:00
Nikita Popov 51f57e7b81 PDO MySQL: Handle boolean parameter binding with libmysql
Previously boolean parameters were simply silently ignored...
2020-12-18 11:01:26 +01:00
Nikita Popov ab84623108 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  MySQLnd: Support cursors in store/get result
2020-12-18 10:20:13 +01: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
Christoph M. Becker 1860ef22eb Fix #80521: Parameters with underscores no longer recognized
We have to use the proper value for the bitmask.
2020-12-16 20:04:52 +01:00
Nikita Popov c56701690a Detect overlarge step for character range()
This was done for int and float ranges, but not char ranges.

Fixes oss-fuzz #28666.
2020-12-16 17:01:15 +01:00
Nikita Popov 205d209de9 PDO MySQL: Use mysqlnd column names
mysqlnd already creates interned zend_strings for us, so let's
make use of them.

This also required updating the PDO case changing code to work
with potentially shared strings. For the lowercasing, use the
optimized zend_string_tolower() implementation.
2020-12-16 15:17:13 +01:00
Nikita Popov 1a66d64717 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fixed bug #67983
2020-12-16 10:53:48 +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 f6bd3dfdbc Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fix bug #80523
2020-12-16 10:20:43 +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 e586a35fc7 Merge branch 'PHP-7.4' into PHP-8.0 2020-12-15 14:13:43 +00:00
Derick Rethans 078cdd8f76 Prepare for 7.4.15 2020-12-15 14:13:29 +00:00
Gabriel Caruso 9eea9aae10 Prepare for PHP 8.0.2
This was missing from f1f78ac875.
2020-12-15 11:03:21 -03:00
Gabriel Caruso f1f78ac875 Next is 8.0.2 2020-12-15 10:30:55 -03:00
204 changed files with 26556 additions and 21870 deletions

No files matched your search

+2 -1
View File
@@ -340,7 +340,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
+78 -2
View File
@@ -1,6 +1,78 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
17 Dec 2020, PHP 8.0.1RC1
04 Feb 2021, PHP 8.0.2
- 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)
. Fixed bug #80596 (Invalid union type TypeError in anonymous classes).
(Daniil Gentili)
. Fixed bug #80617 (GCC throws warning about type narrowing in
ZEND_TYPE_INIT_CODE). (Nikita)
- BCMath:
. Fixed bug #80545 (bcadd('a', 'a') doesn't throw an exception).
(Jens de Nies)
- 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)
- DOM:
. Fixed bug #80537 (Wrong parameter type in DOMElement::removeAttributeNode
stub). (Nikita)
- Filter:
. Fixed bug #80584 (0x and 0X are considered valid hex numbers by
filter_var()). (girgias)
- GMP:
. Fixed bug #80560 (Strings containing only a base prefix return 0 object).
(girgias)
- Intl:
. Fixed bug #80644 (Missing resource causes subsequent get() calls to fail).
(Nikita)
- 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)
- ODBC:
. Fixed bug #80592 (all floats are the same in ODBC parameters). (cmb)
- Opcache:
. Fixed bug #80422 (php_opcache.dll crashes when using Apache 2.4 with JIT).
(Dmitry)
- PDO_Firebird:
. Fixed bug #80521 (Parameters with underscores no longer recognized). (cmb,
Simonov Denis)
- Phar:
. Fixed bug #76929 (zip-based phar does not respect phar.require_hash).
(david at bamsoftware, cmb)
. Fixed bug #77565 (Incorrect locator detection in ZIP-based phars). (cmb)
. Fixed bug #69279 (Compressed ZIP Phar extractTo() creates garbage files).
(cmb)
- Phpdbg:
. Reverted fix for bug #76813 (Access violation near NULL on source operand).
(cmb)
- SOAP:
. Fixed bug #80672 (Null Dereference in SoapClient). (CVE-2021-21702) (cmb, Stas)
07 Jan 2021, PHP 8.0.1
- Core:
. Fixed bug #80345 (PHPIZE configuration has outdated PHP_RELEASE_VERSION).
@@ -26,6 +98,9 @@ PHP NEWS
- Intl:
. Fixed bug #80425 (MessageFormatAdapter::getArgTypeList redefined). (Nikita)
- OCI8
. Create Windows DLLs for Oracle Client 19c. (cmb)
- Opcache:
. Fixed bug #80404 (Incorrect range inference result when division results
in float). (Nikita)
@@ -81,6 +156,8 @@ PHP NEWS
. Fixed #62004 (SplFileObject: fgets after seek returns wrong line). (cmb)
- Standard:
. 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)
- Tidy:
@@ -469,4 +546,3 @@ PHP NEWS
. Fixed bug #71417 (fread() does not report zlib.inflate errors). (cmb)
. Fixed bug #78792 (zlib.output_compression disabled by Content-Type: image/).
(cmb)
+2 -2
View File
@@ -888,8 +888,8 @@ PHP 8.0 UPGRADE NOTES
and this function is no longer needed to protect against XXE attacks.
- PGSQL / PDO PGSQL:
. The constant PG_VERSION_STR has now the same value as PG_VERSION, and thus
is deprecated.
. The constant PGSQL_LIBPQ_VERSION_STR has now the same value as
PGSQL_LIBPQ_VERSION, and thus is deprecated.
. Function aliases in the pgsql extension have been deprecated.
- Zip:
@@ -0,0 +1,30 @@
--TEST--
Union with anonymous class type
--FILE--
<?php
$a = new class {
public function testParam(self|string $a)
{
}
public function test(): self|string
{
return new \stdClass;
}
};
try {
$a->testParam(null);
} catch (\Throwable $e) {
echo $e->getMessage()."\n";
}
try {
$a->test();
} catch (\Throwable $e) {
echo $e->getMessage()."\n";
}
?>
--EXPECTF--
class@anonymous(): Argument #1 ($a) must be of type class@anonymous|string, null given, called in %s on line %d
class@anonymous::test(): Return value must be of type class@anonymous|string, stdClass returned
@@ -0,0 +1,17 @@
--TEST--
Infinite recursion in unlinked_instanceof()
--FILE--
<?php
interface I {}
spl_autoload_register(function() {
class X {
function test(): I {}
}
class Y extends X {
function test(): C {}
}
});
class C extends Z implements C {}
?>
--EXPECTF--
Fatal error: Declaration of Y::test(): C must be compatible with X::test(): I in %s on line %d
+1 -1
View File
@@ -20,7 +20,7 @@
#ifndef ZEND_H
#define ZEND_H
#define ZEND_VERSION "4.0.1RC1"
#define ZEND_VERSION "4.0.2"
#define ZEND_ENGINE_3
+33 -3
View File
@@ -2455,10 +2455,40 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
for (i = 0; i < num_args; i++) {
if (ZEND_TYPE_HAS_CLASS(new_arg_info[i].type)) {
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(new_arg_info[i].type)
&& "Only simple classes are currently supported");
&& "Should be stored as simple name");
const char *class_name = ZEND_TYPE_LITERAL_NAME(new_arg_info[i].type);
ZEND_TYPE_SET_PTR(new_arg_info[i].type,
zend_string_init_interned(class_name, strlen(class_name), 1));
size_t num_types = 1;
const char *p = class_name;
while ((p = strchr(p, '|'))) {
num_types++;
p++;
}
if (num_types == 1) {
/* Simple class type */
ZEND_TYPE_SET_PTR(new_arg_info[i].type,
zend_string_init_interned(class_name, strlen(class_name), 1));
} else {
/* Union type */
zend_type_list *list = malloc(ZEND_TYPE_LIST_SIZE(num_types));
list->num_types = num_types;
ZEND_TYPE_SET_LIST(new_arg_info[i].type, list);
const char *start = class_name;
uint32_t j = 0;
while (true) {
const char *end = strchr(start, '|');
zend_string *str =
zend_string_init(start, end ? end - start : strlen(start), 1);
list->types[j] = (zend_type) ZEND_TYPE_INIT_CLASS(str, 0, 0);
if (!end) {
break;
}
start = end + 1;
j++;
}
}
}
}
}
+13 -3
View File
@@ -1167,7 +1167,15 @@ static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scop
name = scope->parent->name;
}
}
return name;
/* The resolved name for anonymous classes contains null bytes. Cut off everything after the
* null byte here, to avoid larger parts of the type being omitted by printing code later. */
size_t len = strlen(ZSTR_VAL(name));
if (len != ZSTR_LEN(name)) {
ZEND_ASSERT(scope && "This should only happen with resolved types");
return zend_string_init(ZSTR_VAL(name), len, 0);
}
return zend_string_copy(name);
}
zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope) {
@@ -1179,11 +1187,13 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
if (ZEND_TYPE_HAS_CE(*list_type)) {
str = add_type_string(str, ZEND_TYPE_CE(*list_type)->name);
} else {
str = add_type_string(str, resolve_class_name(ZEND_TYPE_NAME(*list_type), scope));
zend_string *resolved = resolve_class_name(ZEND_TYPE_NAME(*list_type), scope);
str = add_type_string(str, resolved);
zend_string_release(resolved);
}
} ZEND_TYPE_LIST_FOREACH_END();
} else if (ZEND_TYPE_HAS_NAME(type)) {
str = zend_string_copy(resolve_class_name(ZEND_TYPE_NAME(type), scope));
str = resolve_class_name(ZEND_TYPE_NAME(type), scope);
} else if (ZEND_TYPE_HAS_CE(type)) {
str = zend_string_copy(ZEND_TYPE_CE(type)->name);
}
+35 -16
View File
@@ -763,6 +763,17 @@ static zend_bool zend_verify_weak_scalar_type_hint(uint32_t type_mask, zval *arg
}
#if ZEND_DEBUG
static bool can_convert_to_string(zval *zv) {
/* We don't call cast_object here, because this check must be side-effect free. As this
* is only used for a sanity check of arginfo/zpp consistency, it's okay if we accept
* more than actually allowed here. */
if (Z_TYPE_P(zv) == IS_OBJECT) {
return Z_OBJ_HT_P(zv)->cast_object != zend_std_cast_object_tostring
|| Z_OBJCE_P(zv)->__tostring;
}
return Z_TYPE_P(zv) <= IS_STRING;
}
/* Used to sanity-check internal arginfo types without performing any actual type conversions. */
static zend_bool zend_verify_weak_scalar_type_hint_no_sideeffect(uint32_t type_mask, zval *arg)
{
@@ -776,10 +787,7 @@ static zend_bool zend_verify_weak_scalar_type_hint_no_sideeffect(uint32_t type_m
if ((type_mask & MAY_BE_DOUBLE) && zend_parse_arg_double_weak(arg, &dval)) {
return 1;
}
/* We don't call cast_object here, because this check must be side-effect free. As this
* is only used for a sanity check of arginfo/zpp consistency, it's okay if we accept
* more than actually allowed here. */
if ((type_mask & MAY_BE_STRING) && (Z_TYPE_P(arg) < IS_STRING || Z_TYPE_P(arg) == IS_OBJECT)) {
if ((type_mask & MAY_BE_STRING) && can_convert_to_string(arg)) {
return 1;
}
if ((type_mask & MAY_BE_BOOL) == MAY_BE_BOOL && zend_parse_arg_bool_weak(arg, &bval)) {
@@ -943,6 +951,13 @@ ZEND_API zend_bool zend_value_instanceof_static(zval *zv) {
return instanceof_function(Z_OBJCE_P(zv), called_scope);
}
/* The cache_slot may only be NULL in debug builds, where arginfo verification of
* internal functions is enabled. Avoid unnecessary checks in release builds. */
#if ZEND_DEBUG
# define HAVE_CACHE_SLOT (cache_slot != NULL)
#else
# define HAVE_CACHE_SLOT 1
#endif
static zend_always_inline zend_bool zend_check_type_slow(
zend_type type, zval *arg, zend_reference *ref, void **cache_slot, zend_class_entry *scope,
@@ -954,31 +969,39 @@ static zend_always_inline zend_bool zend_check_type_slow(
if (ZEND_TYPE_HAS_LIST(type)) {
zend_type *list_type;
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
if (*cache_slot) {
if (HAVE_CACHE_SLOT && *cache_slot) {
ce = *cache_slot;
} else {
ce = zend_fetch_class(ZEND_TYPE_NAME(*list_type),
(ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
if (!ce) {
cache_slot++;
if (HAVE_CACHE_SLOT) {
cache_slot++;
}
continue;
}
*cache_slot = ce;
if (HAVE_CACHE_SLOT) {
*cache_slot = ce;
}
}
if (instanceof_function(Z_OBJCE_P(arg), ce)) {
return 1;
}
cache_slot++;
if (HAVE_CACHE_SLOT) {
cache_slot++;
}
} ZEND_TYPE_LIST_FOREACH_END();
} else {
if (EXPECTED(*cache_slot)) {
if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) {
ce = (zend_class_entry *) *cache_slot;
} else {
ce = zend_fetch_class(ZEND_TYPE_NAME(type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
if (UNEXPECTED(!ce)) {
goto builtin_types;
}
*cache_slot = (void *) ce;
if (HAVE_CACHE_SLOT) {
*cache_slot = (void *) ce;
}
}
if (instanceof_function(Z_OBJCE_P(arg), ce)) {
return 1;
@@ -1071,8 +1094,6 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ
for (i = 0; i < num_args; ++i) {
zend_arg_info *cur_arg_info;
void *dummy_cache_slot = NULL;
if (EXPECTED(i < fbc->common.num_args)) {
cur_arg_info = &fbc->common.arg_info[i];
} else if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_VARIADIC)) {
@@ -1082,7 +1103,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ
}
if (ZEND_TYPE_IS_SET(cur_arg_info->type)
&& UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &dummy_cache_slot, fbc->common.scope, 0, /* is_internal */ 1))) {
&& UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, /* cache_slot */ NULL, fbc->common.scope, 0, /* is_internal */ 1))) {
return 0;
}
arg++;
@@ -1207,8 +1228,6 @@ static ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, con
static bool zend_verify_internal_return_type(zend_function *zf, zval *ret)
{
zend_internal_arg_info *ret_info = zf->internal_function.arg_info - 1;
void *dummy_cache_slot = NULL;
if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_VOID) {
if (UNEXPECTED(Z_TYPE_P(ret) != IS_NULL)) {
zend_verify_void_return_error(zf, zend_zval_type_name(ret), "");
@@ -1217,7 +1236,7 @@ static bool zend_verify_internal_return_type(zend_function *zf, zval *ret)
return 1;
}
if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &dummy_cache_slot, NULL, 1, /* is_internal */ 1))) {
if (UNEXPECTED(!zend_check_type(ret_info->type, ret, /* cache_slot */ NULL, NULL, 1, /* is_internal */ 1))) {
zend_verify_internal_return_error(zf, ret);
return 0;
}
+2 -1
View File
@@ -311,7 +311,8 @@ static zend_bool unlinked_instanceof(zend_class_entry *ce1, zend_class_entry *ce
zend_class_entry *ce = zend_lookup_class_ex(
ce1->interface_names[i].name, ce1->interface_names[i].lc_name,
ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
if (ce && unlinked_instanceof(ce, ce2)) {
/* Avoid recursing if class implements ifself. */
if (ce && ce != ce1 && unlinked_instanceof(ce, ce2)) {
return 1;
}
}
+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;
@@ -571,7 +571,7 @@ ZEND_API zend_result 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");
}
@@ -772,7 +772,7 @@ ZEND_API void zend_prepare_string_for_scanning(zval *str, const 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);
+13
View File
@@ -195,6 +195,19 @@ static zend_always_inline zend_string *zend_string_dup(zend_string *s, bool pers
}
}
static zend_always_inline zend_string *zend_string_separate(zend_string *s, bool persistent)
{
if (ZSTR_IS_INTERNED(s) || GC_REFCOUNT(s) > 1) {
if (!ZSTR_IS_INTERNED(s)) {
GC_DELREF(s);
}
return zend_string_init(ZSTR_VAL(s), ZSTR_LEN(s), persistent);
}
zend_string_forget_hash_val(s);
return s;
}
static zend_always_inline zend_string *zend_string_realloc(zend_string *s, size_t len, bool persistent)
{
zend_string *ret;
+1 -1
View File
@@ -150,7 +150,7 @@ typedef struct {
/* Type mask excluding the flags above. */
#define _ZEND_TYPE_MAY_BE_MASK ((1u << 20) - 1)
/* Must have same value as MAY_BE_NULL */
#define _ZEND_TYPE_NULLABLE_BIT 0x2
#define _ZEND_TYPE_NULLABLE_BIT 0x2u
#define ZEND_TYPE_IS_SET(t) \
(((t).type_mask & _ZEND_TYPE_MASK) != 0)
+595 -72
View File
@@ -111,7 +111,7 @@ class SimpleType {
$this->isBuiltin = $isBuiltin;
}
public static function fromNode(Node $node) {
public static function fromNode(Node $node): SimpleType {
if ($node instanceof Node\Name) {
if ($node->toLowerString() === 'static') {
// PHP internally considers "static" a builtin type.
@@ -127,11 +127,48 @@ class SimpleType {
throw new Exception("Unexpected node type");
}
public function isNull() {
public static function fromPhpDoc(string $type): SimpleType
{
switch (strtolower($type)) {
case "void":
case "null":
case "false":
case "bool":
case "int":
case "float":
case "string":
case "array":
case "iterable":
case "object":
case "resource":
case "mixed":
case "self":
case "static":
return new SimpleType(strtolower($type), true);
}
if (strpos($type, "[]") !== false) {
return new SimpleType("array", true);
}
return new SimpleType($type, false);
}
public static function null(): SimpleType
{
return new SimpleType("null", true);
}
public static function void(): SimpleType
{
return new SimpleType("void", true);
}
public function isNull(): bool {
return $this->isBuiltin && $this->name === 'null';
}
public function toTypeCode() {
public function toTypeCode(): string {
assert($this->isBuiltin);
switch (strtolower($this->name)) {
case "bool":
@@ -209,19 +246,30 @@ class Type {
$this->types = $types;
}
public static function fromNode(Node $node) {
public static function fromNode(Node $node): Type {
if ($node instanceof Node\UnionType) {
return new Type(array_map(['SimpleType', 'fromNode'], $node->types));
}
if ($node instanceof Node\NullableType) {
return new Type([
SimpleType::fromNode($node->type),
new SimpleType('null', true),
SimpleType::null(),
]);
}
return new Type([SimpleType::fromNode($node)]);
}
public static function fromPhpDoc(string $phpDocType) {
$types = explode("|", $phpDocType);
$simpleTypes = [];
foreach ($types as $type) {
$simpleTypes[] = SimpleType::fromPhpDoc($type);
}
return new Type($simpleTypes);
}
public function isNullable(): bool {
foreach ($this->types as $type) {
if ($type->isNull()) {
@@ -245,20 +293,17 @@ class Type {
return null;
}
public function tryToRepresentableType(): ?RepresentableType {
$classType = null;
public function toArginfoType(): ?ArginfoType {
$classTypes = [];
$builtinTypes = [];
foreach ($this->types as $type) {
if ($type->isBuiltin) {
$builtinTypes[] = $type;
} else if ($classType === null) {
$classType = $type;
} else {
// We can only represent a single class type.
return null;
$classTypes[] = $type;
}
}
return new RepresentableType($classType, $builtinTypes);
return new ArginfoType($classTypes, $builtinTypes);
}
public static function equals(?Type $a, ?Type $b): bool {
@@ -278,20 +323,45 @@ class Type {
return true;
}
public function __toString() {
if ($this->types === null) {
return 'mixed';
}
return implode('|', array_map(
function ($type) { return $type->name; },
$this->types)
);
}
}
class RepresentableType {
/** @var ?SimpleType $classType */
public $classType;
/** @var SimpleType[] $builtinTypes */
public $builtinTypes;
class ArginfoType {
/** @var ClassType[] $classTypes */
public $classTypes;
public function __construct(?SimpleType $classType, array $builtinTypes) {
$this->classType = $classType;
/** @var SimpleType[] $builtinTypes */
private $builtinTypes;
public function __construct(array $classTypes, array $builtinTypes) {
$this->classTypes = $classTypes;
$this->builtinTypes = $builtinTypes;
}
public function hasClassType(): bool {
return !empty($this->classTypes);
}
public function toClassTypeString(): string {
return implode('|', array_map(function(SimpleType $type) {
return $type->toEscapedName();
}, $this->classTypes));
}
public function toTypeMask(): string {
if (empty($this->builtinTypes)) {
return '0';
}
return implode('|', array_map(function(SimpleType $type) {
return $type->toTypeMask();
}, $this->builtinTypes));
@@ -311,14 +381,17 @@ class ArgInfo {
public $isVariadic;
/** @var Type|null */
public $type;
/** @var Type|null */
public $phpDocType;
/** @var string|null */
public $defaultValue;
public function __construct(string $name, int $sendBy, bool $isVariadic, ?Type $type, ?string $defaultValue) {
public function __construct(string $name, int $sendBy, bool $isVariadic, ?Type $type, ?Type $phpDocType, ?string $defaultValue) {
$this->name = $name;
$this->sendBy = $sendBy;
$this->isVariadic = $isVariadic;
$this->type = $type;
$this->phpDocType = $phpDocType;
$this->defaultValue = $defaultValue;
}
@@ -342,22 +415,52 @@ class ArgInfo {
throw new Exception("Invalid sendBy value");
}
public function hasDefaultValue(): bool {
public function getMethodSynopsisType(): Type {
if ($this->type) {
return $this->type;
}
if ($this->phpDocType) {
return $this->phpDocType;
}
throw new Exception("A parameter must have a type");
}
public function hasProperDefaultValue(): bool {
return $this->defaultValue !== null && $this->defaultValue !== "UNKNOWN";
}
public function getDefaultValueString(): string {
if ($this->hasDefaultValue()) {
public function getDefaultValueAsArginfoString(): string {
if ($this->hasProperDefaultValue()) {
return '"' . addslashes($this->defaultValue) . '"';
}
return "NULL";
}
public function getDefaultValueAsMethodSynopsisString(): ?string {
if ($this->defaultValue === null) {
return null;
}
switch ($this->defaultValue) {
case 'UNKNOWN':
return null;
case 'false':
case 'true':
case 'null':
return "&{$this->defaultValue};";
}
return $this->defaultValue;
}
}
interface FunctionOrMethodName {
public function getDeclaration(): string;
public function getArgInfoName(): string;
public function getMethodSynopsisFilename(): string;
public function __toString(): string;
public function isMethod(): bool;
public function isConstructor(): bool;
@@ -399,6 +502,10 @@ class FunctionName implements FunctionOrMethodName {
return "arginfo_$underscoreName";
}
public function getMethodSynopsisFilename(): string {
return implode('_', $this->name->parts);
}
public function __toString(): string {
return $this->name->toString();
}
@@ -439,6 +546,10 @@ class MethodName implements FunctionOrMethodName {
return "arginfo_class_{$this->getDeclarationClassName()}_{$this->methodName}";
}
public function getMethodSynopsisFilename(): string {
return $this->getDeclarationClassName() . "_{$this->methodName}";
}
public function __toString(): string {
return "$this->className::$this->methodName";
}
@@ -461,16 +572,23 @@ class ReturnInfo {
public $byRef;
/** @var Type|null */
public $type;
/** @var Type|null */
public $phpDocType;
public function __construct(bool $byRef, ?Type $type) {
public function __construct(bool $byRef, ?Type $type, ?Type $phpDocType) {
$this->byRef = $byRef;
$this->type = $type;
$this->phpDocType = $phpDocType;
}
public function equals(ReturnInfo $other): bool {
return $this->byRef === $other->byRef
&& Type::equals($this->type, $other->type);
}
public function getMethodSynopsisType(): ?Type {
return $this->type ?? $this->phpDocType;
}
}
class FuncInfo {
@@ -538,6 +656,47 @@ class FuncInfo {
return !($this->flags & Class_::MODIFIER_STATIC) && $this->isMethod() && !$this->name->isConstructor();
}
/** @return string[] */
public function getModifierNames(): array
{
if (!$this->isMethod()) {
return [];
}
$result = [];
if ($this->flags & Class_::MODIFIER_FINAL) {
$result[] = "final";
} elseif ($this->flags & Class_::MODIFIER_ABSTRACT && $this->classFlags & ~Class_::MODIFIER_ABSTRACT) {
$result[] = "abstract";
}
if ($this->flags & Class_::MODIFIER_PROTECTED) {
$result[] = "protected";
} elseif ($this->flags & Class_::MODIFIER_PRIVATE) {
$result[] = "private";
} else {
$result[] = "public";
}
if ($this->flags & Class_::MODIFIER_STATIC) {
$result[] = "static";
}
return $result;
}
public function hasParamWithUnknownDefaultValue(): bool
{
foreach ($this->args as $arg) {
if ($arg->defaultValue && !$arg->hasProperDefaultValue()) {
return true;
}
}
return false;
}
public function equalsApartFromName(FuncInfo $other): bool {
if (count($this->args) !== count($other->args)) {
return false;
@@ -583,13 +742,13 @@ class FuncInfo {
return sprintf(
"\tZEND_MALIAS(%s, %s, %s, %s, %s)\n",
$this->alias->getDeclarationClassName(), $this->name->methodName,
$this->alias->methodName, $this->getArgInfoName(), $this->getFlagsAsString()
$this->alias->methodName, $this->getArgInfoName(), $this->getFlagsAsArginfoString()
);
} else if ($this->alias instanceof FunctionName) {
return sprintf(
"\tZEND_ME_MAPPING(%s, %s, %s, %s)\n",
$this->name->methodName, $this->alias->getNonNamespacedName(),
$this->getArgInfoName(), $this->getFlagsAsString()
$this->getArgInfoName(), $this->getFlagsAsArginfoString()
);
} else {
throw new Error("Cannot happen");
@@ -600,14 +759,14 @@ class FuncInfo {
return sprintf(
"\tZEND_ABSTRACT_ME_WITH_FLAGS(%s, %s, %s, %s)\n",
$declarationClassName, $this->name->methodName, $this->getArgInfoName(),
$this->getFlagsAsString()
$this->getFlagsAsArginfoString()
);
}
return sprintf(
"\tZEND_ME(%s, %s, %s, %s)\n",
$declarationClassName, $this->name->methodName, $this->getArgInfoName(),
$this->getFlagsAsString()
$this->getFlagsAsArginfoString()
);
}
} else if ($this->name instanceof FunctionName) {
@@ -645,7 +804,7 @@ class FuncInfo {
}
}
private function getFlagsAsString(): string
private function getFlagsAsArginfoString(): string
{
$flags = "ZEND_ACC_PUBLIC";
if ($this->flags & Class_::MODIFIER_PROTECTED) {
@@ -673,6 +832,114 @@ class FuncInfo {
return $flags;
}
/**
* @param FuncInfo[] $funcMap
* @param FuncInfo[] $aliasMap
* @throws Exception
*/
public function getMethodSynopsisDocument(array $funcMap, array $aliasMap): ?string {
$doc = new DOMDocument();
$doc->formatOutput = true;
$methodSynopsis = $this->getMethodSynopsisElement($funcMap, $aliasMap, $doc);
if (!$methodSynopsis) {
return null;
}
$doc->appendChild($methodSynopsis);
return $doc->saveXML();
}
/**
* @param FuncInfo[] $funcMap
* @param FuncInfo[] $aliasMap
* @throws Exception
*/
public function getMethodSynopsisElement(array $funcMap, array $aliasMap, DOMDocument $doc): ?DOMElement {
if ($this->hasParamWithUnknownDefaultValue()) {
return null;
}
if ($this->name->isConstructor()) {
$synopsisType = "constructorsynopsis";
} elseif ($this->name->isDestructor()) {
$synopsisType = "destructorsynopsis";
} else {
$synopsisType = "methodsynopsis";
}
$methodSynopsis = $doc->createElement($synopsisType);
$aliasedFunc = $this->aliasType === "alias" && isset($funcMap[$this->alias->__toString()]) ? $funcMap[$this->alias->__toString()] : null;
$aliasFunc = $aliasMap[$this->name->__toString()] ?? null;
if (($this->aliasType === "alias" && $aliasedFunc !== null && $aliasedFunc->isMethod() !== $this->isMethod()) ||
($aliasFunc !== null && $aliasFunc->isMethod() !== $this->isMethod())
) {
$role = $doc->createAttribute("role");
$role->value = $this->isMethod() ? "oop" : "procedural";
$methodSynopsis->appendChild($role);
}
$methodSynopsis->appendChild(new DOMText("\n "));
foreach ($this->getModifierNames() as $modifierString) {
$modifierElement = $doc->createElement('modifier', $modifierString);
$methodSynopsis->appendChild($modifierElement);
$methodSynopsis->appendChild(new DOMText(" "));
}
$returnType = $this->return->getMethodSynopsisType();
if ($returnType) {
$this->appendMethodSynopsisTypeToElement($doc, $methodSynopsis, $returnType);
}
$methodname = $doc->createElement('methodname', $this->name->__toString());
$methodSynopsis->appendChild($methodname);
if (empty($this->args)) {
$methodSynopsis->appendChild(new DOMText("\n "));
$void = $doc->createElement('void');
$methodSynopsis->appendChild($void);
} else {
foreach ($this->args as $arg) {
$methodSynopsis->appendChild(new DOMText("\n "));
$methodparam = $doc->createElement('methodparam');
if ($arg->defaultValue !== null) {
$methodparam->setAttribute("choice", "opt");
}
if ($arg->isVariadic) {
$methodparam->setAttribute("rep", "repeat");
}
$methodSynopsis->appendChild($methodparam);
$this->appendMethodSynopsisTypeToElement($doc, $methodparam, $arg->getMethodSynopsisType());
$parameter = $doc->createElement('parameter', $arg->name);
if ($arg->sendBy !== ArgInfo::SEND_BY_VAL) {
$parameter->setAttribute("role", "reference");
}
$methodparam->appendChild($parameter);
$defaultValue = $arg->getDefaultValueAsMethodSynopsisString();
if ($defaultValue !== null) {
$initializer = $doc->createElement('initializer');
if (preg_match('/^[a-zA-Z_][a-zA-Z_0-9]*$/', $defaultValue)) {
$constant = $doc->createElement('constant', $defaultValue);
$initializer->appendChild($constant);
} else {
$initializer->nodeValue = $defaultValue;
}
$methodparam->appendChild($initializer);
}
}
}
$methodSynopsis->appendChild(new DOMText("\n "));
return $methodSynopsis;
}
public function discardInfoForOldPhpVersions(): void {
$this->return->type = null;
foreach ($this->args as $arg) {
@@ -680,6 +947,22 @@ class FuncInfo {
$arg->defaultValue = null;
}
}
private function appendMethodSynopsisTypeToElement(DOMDocument $doc, DOMElement $elementToAppend, Type $type) {
if (count($type->types) > 1) {
$typeElement = $doc->createElement('type');
$typeElement->setAttribute("class", "union");
foreach ($type->types as $type) {
$unionTypeElement = $doc->createElement('type', $type->name);
$typeElement->appendChild($unionTypeElement);
}
} else {
$typeElement = $doc->createElement('type', $type->types[0]->name);
}
$elementToAppend->appendChild($typeElement);
}
}
class ClassInfo {
@@ -736,8 +1019,26 @@ class DocCommentTag {
return $this->value;
}
public function getVariableName(): string {
public function getType(): string {
$value = $this->getValue();
$matches = [];
if ($this->name === "param") {
preg_match('/^\s*([\w\|\\\\\[\]]+)\s*\$\w+.*$/', $value, $matches);
} elseif ($this->name === "return") {
preg_match('/^\s*([\w\|\\\\\[\]]+)\s*$/', $value, $matches);
}
if (isset($matches[1]) === false) {
throw new Exception("@$this->name doesn't contain a type or has an invalid format \"$value\"");
}
return $matches[1];
}
public function getVariableName(): string {
$value = $this->value;
if ($value === null || strlen($value) === 0) {
throw new Exception("@$this->name doesn't have any value");
}
@@ -745,13 +1046,13 @@ class DocCommentTag {
$matches = [];
if ($this->name === "param") {
preg_match('/^\s*[\w\|\\\\]+\s*\$(\w+).*$/', $value, $matches);
preg_match('/^\s*[\w\|\\\\\[\]]+\s*\$(\w+).*$/', $value, $matches);
} elseif ($this->name === "prefer-ref") {
preg_match('/^\s*\$(\w+).*$/', $value, $matches);
}
if (isset($matches[1]) === false) {
throw new Exception("@$this->name doesn't contain variable name or has an invalid format \"$value\"");
throw new Exception("@$this->name doesn't contain a variable name or has an invalid format \"$value\"");
}
return $matches[1];
@@ -786,7 +1087,7 @@ function parseFunctionLike(
$alias = null;
$isDeprecated = false;
$verify = true;
$haveDocReturnType = false;
$docReturnType = null;
$docParamTypes = [];
if ($comment) {
@@ -811,9 +1112,9 @@ function parseFunctionLike(
} else if ($tag->name === 'no-verify') {
$verify = false;
} else if ($tag->name === 'return') {
$haveDocReturnType = true;
$docReturnType = $tag->getType();
} else if ($tag->name === 'param') {
$docParamTypes[$tag->getVariableName()] = true;
$docParamTypes[$tag->getVariableName()] = $tag->getType();
}
}
}
@@ -867,6 +1168,7 @@ function parseFunctionLike(
$sendBy,
$param->variadic,
$type,
isset($docParamTypes[$varName]) ? Type::fromPhpDoc($docParamTypes[$varName]) : null,
$param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null
);
if (!$param->default && !$param->variadic) {
@@ -879,13 +1181,14 @@ function parseFunctionLike(
}
$returnType = $func->getReturnType();
if ($returnType === null && !$haveDocReturnType && !$name->isConstructor() && !$name->isDestructor()) {
if ($returnType === null && $docReturnType === null && !$name->isConstructor() && !$name->isDestructor()) {
throw new Exception("Missing return type for function $name()");
}
$return = new ReturnInfo(
$func->returnsByRef(),
$returnType ? Type::fromNode($returnType) : null
$returnType ? Type::fromNode($returnType) : null,
$docReturnType ? Type::fromPhpDoc($docReturnType) : null
);
return new FuncInfo(
@@ -1070,24 +1373,23 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
$simpleReturnType->toEscapedName(), $returnType->isNullable()
);
}
} else if (null !== $representableType = $returnType->tryToRepresentableType()) {
if ($representableType->classType !== null) {
} else {
$arginfoType = $returnType->toArginfoType();
if ($arginfoType->hasClassType()) {
$code .= sprintf(
"ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(%s, %d, %d, %s, %s)\n",
$funcInfo->getArgInfoName(), $funcInfo->return->byRef,
$funcInfo->numRequiredArgs,
$representableType->classType->toEscapedName(), $representableType->toTypeMask()
$arginfoType->toClassTypeString(), $arginfoType->toTypeMask()
);
} else {
$code .= sprintf(
"ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(%s, %d, %d, %s)\n",
$funcInfo->getArgInfoName(), $funcInfo->return->byRef,
$funcInfo->numRequiredArgs,
$representableType->toTypeMask()
$arginfoType->toTypeMask()
);
}
} else {
throw new Exception('Unimplemented');
}
} else {
$code .= sprintf(
@@ -1098,7 +1400,7 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
foreach ($funcInfo->args as $argInfo) {
$argKind = $argInfo->isVariadic ? "ARG_VARIADIC" : "ARG";
$argDefaultKind = $argInfo->hasDefaultValue() ? "_WITH_DEFAULT_VALUE" : "";
$argDefaultKind = $argInfo->hasProperDefaultValue() ? "_WITH_DEFAULT_VALUE" : "";
$argType = $argInfo->type;
if ($argType !== null) {
if (null !== $simpleArgType = $argType->tryToSimpleType()) {
@@ -1107,41 +1409,39 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
"\tZEND_%s_TYPE_INFO%s(%s, %s, %s, %d%s)\n",
$argKind, $argDefaultKind, $argInfo->getSendByString(), $argInfo->name,
$simpleArgType->toTypeCode(), $argType->isNullable(),
$argInfo->hasDefaultValue() ? ", " . $argInfo->getDefaultValueString() : ""
$argInfo->hasProperDefaultValue() ? ", " . $argInfo->getDefaultValueAsArginfoString() : ""
);
} else {
$code .= sprintf(
"\tZEND_%s_OBJ_INFO%s(%s, %s, %s, %d%s)\n",
$argKind,$argDefaultKind, $argInfo->getSendByString(), $argInfo->name,
$simpleArgType->toEscapedName(), $argType->isNullable(),
$argInfo->hasDefaultValue() ? ", " . $argInfo->getDefaultValueString() : ""
$argInfo->hasProperDefaultValue() ? ", " . $argInfo->getDefaultValueAsArginfoString() : ""
);
}
} else if (null !== $representableType = $argType->tryToRepresentableType()) {
if ($representableType->classType !== null) {
} else {
$arginfoType = $argType->toArginfoType();
if ($arginfoType->hasClassType()) {
$code .= sprintf(
"\tZEND_%s_OBJ_TYPE_MASK(%s, %s, %s, %s, %s)\n",
$argKind, $argInfo->getSendByString(), $argInfo->name,
$representableType->classType->toEscapedName(),
$representableType->toTypeMask(),
$argInfo->getDefaultValueString()
$arginfoType->toClassTypeString(), $arginfoType->toTypeMask(),
$argInfo->getDefaultValueAsArginfoString()
);
} else {
$code .= sprintf(
"\tZEND_%s_TYPE_MASK(%s, %s, %s, %s)\n",
$argKind, $argInfo->getSendByString(), $argInfo->name,
$representableType->toTypeMask(),
$argInfo->getDefaultValueString()
$arginfoType->toTypeMask(),
$argInfo->getDefaultValueAsArginfoString()
);
}
} else {
throw new Exception('Unimplemented');
}
} else {
$code .= sprintf(
"\tZEND_%s_INFO%s(%s, %s%s)\n",
$argKind, $argDefaultKind, $argInfo->getSendByString(), $argInfo->name,
$argInfo->hasDefaultValue() ? ", " . $argInfo->getDefaultValueString() : ""
$argInfo->hasProperDefaultValue() ? ", " . $argInfo->getDefaultValueAsArginfoString() : ""
);
}
}
@@ -1253,6 +1553,194 @@ function generateFunctionEntries(?Name $className, array $funcInfos): string {
return $code;
}
/**
* @param FuncInfo[] $funcMap
* @param FuncInfo[] $aliasMap
* @return array<string, string>
*/
function generateMethodSynopses(array $funcMap, array $aliasMap): array {
$result = [];
foreach ($funcMap as $funcInfo) {
$methodSynopsis = $funcInfo->getMethodSynopsisDocument($funcMap, $aliasMap);
if ($methodSynopsis !== null) {
$result[$funcInfo->name->getMethodSynopsisFilename() . ".xml"] = $methodSynopsis;
}
}
return $result;
}
/**
* @param FuncInfo[] $funcMap
* @param FuncInfo[] $aliasMap
* @return array<string, string>
*/
function replaceMethodSynopses(string $targetDirectory, array $funcMap, array $aliasMap): array {
$methodSynopses = [];
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($targetDirectory),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($it as $file) {
$pathName = $file->getPathName();
if (!preg_match('/\.xml$/i', $pathName)) {
continue;
}
$xml = file_get_contents($pathName);
if ($xml === false) {
continue;
}
if (stripos($xml, "<methodsynopsis") === false && stripos($xml, "<constructorsynopsis") === false && stripos($xml, "<destructorsynopsis") === false) {
continue;
}
$replacedXml = preg_replace("/&([A-Za-z0-9._{}%-]+?;)/", "REPLACED-ENTITY-$1", $xml);
$doc = new DOMDocument();
$doc->formatOutput = false;
$doc->preserveWhiteSpace = true;
$doc->validateOnParse = true;
$success = $doc->loadXML($replacedXml);
if (!$success) {
echo "Failed opening $pathName\n";
continue;
}
$docComparator = new DOMDocument();
$docComparator->preserveWhiteSpace = false;
$docComparator->formatOutput = true;
$methodSynopsisElements = [];
foreach ($doc->getElementsByTagName("constructorsynopsis") as $element) {
$methodSynopsisElements[] = $element;
}
foreach ($doc->getElementsByTagName("destructorsynopsis") as $element) {
$methodSynopsisElements[] = $element;
}
foreach ($doc->getElementsByTagName("methodsynopsis") as $element) {
$methodSynopsisElements[] = $element;
}
foreach ($methodSynopsisElements as $methodSynopsis) {
if (!$methodSynopsis instanceof DOMElement) {
continue;
}
$list = $methodSynopsis->getElementsByTagName("methodname");
$item = $list->item(0);
if (!$item instanceof DOMElement) {
continue;
}
$funcName = $item->textContent;
if (!isset($funcMap[$funcName])) {
continue;
}
$funcInfo = $funcMap[$funcName];
$newMethodSynopsis = $funcInfo->getMethodSynopsisElement($funcMap, $aliasMap, $doc);
if ($newMethodSynopsis === null) {
continue;
}
// Retrieve current signature
$params = [];
$list = $methodSynopsis->getElementsByTagName("methodparam");
foreach ($list as $i => $item) {
if (!$item instanceof DOMElement) {
continue;
}
$paramList = $item->getElementsByTagName("parameter");
if ($paramList->count() !== 1) {
continue;
}
$paramName = $paramList->item(0)->textContent;
$paramTypes = [];
$paramList = $item->getElementsByTagName("type");
foreach ($paramList as $type) {
if (!$type instanceof DOMElement) {
continue;
}
$paramTypes[] = $type->textContent;
}
$params[$paramName] = ["index" => $i, "type" => $paramTypes];
}
// Check if there is any change - short circuit if there is not any.
$xml1 = $doc->saveXML($methodSynopsis);
$xml1 = preg_replace("/&([A-Za-z0-9._{}%-]+?;)/", "REPLACED-ENTITY-$1", $xml1);
$docComparator->loadXML($xml1);
$xml1 = $docComparator->saveXML();
$methodSynopsis->parentNode->replaceChild($newMethodSynopsis, $methodSynopsis);
$xml2 = $doc->saveXML($newMethodSynopsis);
$xml2 = preg_replace("/&([A-Za-z0-9._{}%-]+?;)/", "REPLACED-ENTITY-$1", $xml2);
$docComparator->loadXML($xml2);
$xml2 = $docComparator->saveXML();
if ($xml1 === $xml2) {
continue;
}
// Update parameter references
$paramList = $doc->getElementsByTagName("parameter");
/** @var DOMElement $paramElement */
foreach ($paramList as $paramElement) {
if ($paramElement->parentNode && $paramElement->parentNode->nodeName === "methodparam") {
continue;
}
$name = $paramElement->textContent;
if (!isset($params[$name])) {
continue;
}
$index = $params[$name]["index"];
if (!isset($funcInfo->args[$index])) {
continue;
}
$paramElement->textContent = $funcInfo->args[$index]->name;
}
// Return the updated XML
$replacedXml = $doc->saveXML();
$replacedXml = preg_replace(
[
"/REPLACED-ENTITY-([A-Za-z0-9._{}%-]+?;)/",
"/<refentry\s+xmlns=\"([a-z0-9.:\/]+)\"\s+xml:id=\"([a-z0-9._-]+)\"\s*>/i",
"/<refentry\s+xmlns=\"([a-z0-9.:\/]+)\"\s+xmlns:xlink=\"([a-z0-9.:\/]+)\"\s+xml:id=\"([a-z0-9._-]+)\"\s*>/i",
],
[
"&$1",
"<refentry xml:id=\"$2\" xmlns=\"$1\">",
"<refentry xml:id=\"$3\" xmlns=\"$1\" xmlns:xlink=\"$2\">",
],
$replacedXml
);
$methodSynopses[$pathName] = $replacedXml;
}
}
return $methodSynopses;
}
function installPhpParser(string $version, string $phpParserDir) {
$lockFile = __DIR__ . "/PHP-Parser-install-lock";
$lockFd = fopen($lockFile, 'w+');
@@ -1318,16 +1806,22 @@ function initPhpParser() {
}
$optind = null;
$options = getopt("fh", ["force-regeneration", "parameter-stats", "help", "verify"], $optind);
$options = getopt("fh", ["force-regeneration", "parameter-stats", "help", "verify", "generate-methodsynopses", "replace-methodsynopses"], $optind);
$context = new Context;
$printParameterStats = isset($options["parameter-stats"]);
$verify = isset($options["verify"]);
$generateMethodSynopses = isset($options["generate-methodsynopses"]);
$replaceMethodSynopses = isset($options["replace-methodsynopses"]);
$context->forceRegeneration = isset($options["f"]) || isset($options["force-regeneration"]);
$context->forceParse = $context->forceRegeneration || $printParameterStats || $verify;
$context->forceParse = $context->forceRegeneration || $printParameterStats || $verify || $generateMethodSynopses || $replaceMethodSynopses;
$targetMethodSynopses = $argv[$optind + 1] ?? null;
if ($replaceMethodSynopses && $targetMethodSynopses === null) {
die("A target directory must be provided.\n");
}
if (isset($options["h"]) || isset($options["help"])) {
die("\nusage: gen-stub.php [ -f | --force-regeneration ] [ --parameter-stats ] [ --verify ] [ -h | --help ] [ name.stub.php | directory ]\n\n");
die("\nusage: gen-stub.php [ -f | --force-regeneration ] [ --generate-methodsynopses ] [ --replace-methodsynopses ] [ --parameter-stats ] [ --verify ] [ -h | --help ] [ name.stub.php | directory ] [ directory ]\n\n");
}
$fileInfos = [];
@@ -1363,23 +1857,26 @@ if ($printParameterStats) {
echo json_encode($parameterStats, JSON_PRETTY_PRINT), "\n";
}
if ($verify) {
$errors = [];
$funcMap = [];
$aliases = [];
/** @var FuncInfo[] $funcMap */
$funcMap = [];
/** @var FuncInfo[] $aliasMap */
$aliasMap = [];
foreach ($fileInfos as $fileInfo) {
foreach ($fileInfo->getAllFuncInfos() as $funcInfo) {
/** @var FuncInfo $funcInfo */
$funcMap[$funcInfo->name->__toString()] = $funcInfo;
foreach ($fileInfos as $fileInfo) {
foreach ($fileInfo->getAllFuncInfos() as $funcInfo) {
/** @var FuncInfo $funcInfo */
$funcMap[$funcInfo->name->__toString()] = $funcInfo;
if ($funcInfo->aliasType === "alias") {
$aliases[] = $funcInfo;
}
if ($funcInfo->aliasType === "alias") {
$aliasMap[$funcInfo->alias->__toString()] = $funcInfo;
}
}
}
foreach ($aliases as $aliasFunc) {
if ($verify) {
$errors = [];
foreach ($aliasMap as $aliasFunc) {
if (!isset($funcMap[$aliasFunc->alias->__toString()])) {
$errors[] = "Aliased function {$aliasFunc->alias}() cannot be found";
continue;
@@ -1412,7 +1909,6 @@ if ($verify) {
}
if ($aliasedArg === null) {
assert($aliasArg !== null);
$errors[] = "{$aliasedFunc->name}(): Argument \$$aliasArg->name of alias function {$aliasFunc->name}() is missing";
return null;
}
@@ -1447,3 +1943,30 @@ if ($verify) {
exit(1);
}
}
if ($generateMethodSynopses) {
$methodSynopsesDirectory = getcwd() . "/methodsynopses";
$methodSynopses = generateMethodSynopses($funcMap, $aliasMap);
if (!empty($methodSynopses)) {
if (!file_exists($methodSynopsesDirectory)) {
mkdir($methodSynopsesDirectory);
}
foreach ($methodSynopses as $filename => $content) {
if (file_put_contents("$methodSynopsesDirectory/$filename", $content)) {
echo "Saved $filename\n";
}
}
}
}
if ($replaceMethodSynopses) {
$methodSynopses = replaceMethodSynopses($targetMethodSynopses, $funcMap, $aliasMap);
foreach ($methodSynopses as $filename => $content) {
if (file_put_contents($filename, $content)) {
echo "Saved $filename\n";
}
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice.
dnl ----------------------------------------------------------------------------
AC_PREREQ([2.68])
AC_INIT([PHP],[8.0.1RC1],[https://bugs.php.net],[php],[https://www.php.net])
AC_INIT([PHP],[8.0.2],[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
+144 -53
View File
@@ -129,20 +129,23 @@ PHP_MINFO_FUNCTION(bcmath)
/* {{{ php_str2num
Convert to bc_num detecting scale */
static void php_str2num(bc_num *num, char *str)
static zend_result php_str2num(bc_num *num, char *str)
{
char *p;
if (!(p = strchr(str, '.'))) {
if (!bc_str2num(num, str, 0)) {
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
return FAILURE;
}
return;
return SUCCESS;
}
if (!bc_str2num(num, str, strlen(p+1))) {
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
return FAILURE;
}
return SUCCESS;
}
/* }}} */
@@ -174,15 +177,26 @@ PHP_FUNCTION(bcadd)
bc_init_num(&first);
bc_init_num(&second);
bc_init_num(&result);
php_str2num(&first, ZSTR_VAL(left));
php_str2num(&second, ZSTR_VAL(right));
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
zend_argument_value_error(2, "is not well-formed");
goto cleanup;
}
bc_add (first, second, &result, scale);
RETVAL_STR(bc_num2str_ex(result, scale));
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
return;
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
};
}
/* }}} */
@@ -214,15 +228,26 @@ PHP_FUNCTION(bcsub)
bc_init_num(&first);
bc_init_num(&second);
bc_init_num(&result);
php_str2num(&first, ZSTR_VAL(left));
php_str2num(&second, ZSTR_VAL(right));
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
zend_argument_value_error(2, "is not well-formed");
goto cleanup;
}
bc_sub (first, second, &result, scale);
RETVAL_STR(bc_num2str_ex(result, scale));
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
return;
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
};
}
/* }}} */
@@ -254,15 +279,26 @@ PHP_FUNCTION(bcmul)
bc_init_num(&first);
bc_init_num(&second);
bc_init_num(&result);
php_str2num(&first, ZSTR_VAL(left));
php_str2num(&second, ZSTR_VAL(right));
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
zend_argument_value_error(2, "is not well-formed");
goto cleanup;
}
bc_multiply (first, second, &result, scale);
RETVAL_STR(bc_num2str_ex(result, scale));
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
return;
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
};
}
/* }}} */
@@ -294,8 +330,16 @@ PHP_FUNCTION(bcdiv)
bc_init_num(&first);
bc_init_num(&second);
bc_init_num(&result);
php_str2num(&first, ZSTR_VAL(left));
php_str2num(&second, ZSTR_VAL(right));
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
zend_argument_value_error(2, "is not well-formed");
goto cleanup;
}
switch (bc_divide(first, second, &result, scale)) {
case 0: /* OK */
@@ -306,10 +350,11 @@ PHP_FUNCTION(bcdiv)
break;
}
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
return;
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
};
}
/* }}} */
@@ -341,8 +386,16 @@ PHP_FUNCTION(bcmod)
bc_init_num(&first);
bc_init_num(&second);
bc_init_num(&result);
php_str2num(&first, ZSTR_VAL(left));
php_str2num(&second, ZSTR_VAL(right));
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
zend_argument_value_error(2, "is not well-formed");
goto cleanup;
}
switch (bc_modulo(first, second, &result, scale)) {
case 0:
@@ -353,9 +406,11 @@ PHP_FUNCTION(bcmod)
break;
}
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
};
}
/* }}} */
@@ -389,18 +444,32 @@ PHP_FUNCTION(bcpowmod)
bc_init_num(&second);
bc_init_num(&mod);
bc_init_num(&result);
php_str2num(&first, ZSTR_VAL(left));
php_str2num(&second, ZSTR_VAL(right));
php_str2num(&mod, ZSTR_VAL(modulus));
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
zend_argument_value_error(2, "is not well-formed");
goto cleanup;
}
if (php_str2num(&mod, ZSTR_VAL(modulus)) == FAILURE) {
zend_argument_value_error(3, "is not well-formed");
goto cleanup;
}
if (bc_raisemod(first, second, mod, &result, scale) == SUCCESS) {
RETVAL_STR(bc_num2str_ex(result, scale));
}
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&mod);
bc_free_num(&result);
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&mod);
bc_free_num(&result);
};
}
/* }}} */
@@ -432,14 +501,26 @@ PHP_FUNCTION(bcpow)
bc_init_num(&first);
bc_init_num(&second);
bc_init_num(&result);
php_str2num(&first, ZSTR_VAL(left));
php_str2num(&second, ZSTR_VAL(right));
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
zend_argument_value_error(2, "is not well-formed");
goto cleanup;
}
bc_raise (first, second, &result, scale);
RETVAL_STR(bc_num2str_ex(result, scale));
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&result);
};
}
/* }}} */
@@ -468,7 +549,11 @@ PHP_FUNCTION(bcsqrt)
}
bc_init_num(&result);
php_str2num(&result, ZSTR_VAL(left));
if (php_str2num(&result, ZSTR_VAL(left)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
if (bc_sqrt (&result, scale) != 0) {
RETVAL_STR(bc_num2str_ex(result, scale));
@@ -476,8 +561,9 @@ PHP_FUNCTION(bcsqrt)
zend_argument_value_error(1, "must be greater than or equal to 0");
}
bc_free_num(&result);
return;
cleanup: {
bc_free_num(&result);
};
}
/* }}} */
@@ -510,16 +596,21 @@ PHP_FUNCTION(bccomp)
bc_init_num(&second);
if (!bc_str2num(&first, ZSTR_VAL(left), scale)) {
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
if (!bc_str2num(&second, ZSTR_VAL(right), scale)) {
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
zend_argument_value_error(2, "is not well-formed");
goto cleanup;
}
RETVAL_LONG(bc_compare(first, second));
bc_free_num(&first);
bc_free_num(&second);
return;
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
};
}
/* }}} */
+25
View File
@@ -0,0 +1,25 @@
--TEST--
Bug #80545 (bcadd('a', 'a') and bcadd('1', 'a') doesn't throw an exception)
--SKIPIF--
<?php
if (!extension_loaded('bcmath')) die('skip bcmath extension not available');
?>
--FILE--
<?php
try {
bcadd('a', 'a');
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
bcadd('1', 'a');
} catch (\ValueError $e) {
echo $e->getMessage();
}
?>
--EXPECT--
bcadd(): Argument #1 ($num1) is not well-formed
bcadd(): Argument #2 ($num2) is not well-formed
+75 -31
View File
@@ -14,12 +14,39 @@ echo bcadd("", "2", 2),"\n";
echo bcadd("+0", "2"), "\n";
echo bcadd("-0", "2"), "\n";
echo bcadd(" 0", "2");
echo bcadd("1e1", "2");
echo bcadd("1,1", "2");
echo bcadd("Hello", "2");
echo bcadd("1 1", "2");
echo "\n", "\n";
echo "\n";
try {
echo bcadd(" 0", "2");
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
echo bcadd("1e1", "2");
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
echo bcadd("1,1", "2");
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
echo bcadd("Hello", "2");
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
echo bcadd("1 1", "2");
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
echo "\n";
echo bccomp("1", "2"),"\n";
echo bccomp("1.1", "2", 2),"\n";
@@ -27,11 +54,38 @@ echo bccomp("", "2"),"\n";
echo bccomp("+0", "2"), "\n";
echo bccomp("-0", "2"), "\n";
echo bccomp(" 0", "2");
echo bccomp("1e1", "2");
echo bccomp("1,1", "2");
echo bccomp("Hello", "2");
echo bccomp("1 1", "2");
echo "\n";
try {
echo bccomp(" 0", "2");
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
echo bccomp("1e1", "2");
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
echo bccomp("1,1", "2");
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
echo bccomp("Hello", "2");
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
echo bccomp("1 1", "2");
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
?>
--EXPECTF--
3
@@ -40,16 +94,11 @@ echo bccomp("1 1", "2");
2
2
Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
2
Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
2
Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
2
Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
2
Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
2
bcadd(): Argument #1 ($num1) is not well-formed
bcadd(): Argument #1 ($num1) is not well-formed
bcadd(): Argument #1 ($num1) is not well-formed
bcadd(): Argument #1 ($num1) is not well-formed
bcadd(): Argument #1 ($num1) is not well-formed
-1
-1
@@ -57,13 +106,8 @@ Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
-1
-1
Warning: bccomp(): bcmath function argument is not well-formed in %s on line %d
-1
Warning: bccomp(): bcmath function argument is not well-formed in %s on line %d
-1
Warning: bccomp(): bcmath function argument is not well-formed in %s on line %d
-1
Warning: bccomp(): bcmath function argument is not well-formed in %s on line %d
-1
Warning: bccomp(): bcmath function argument is not well-formed in %s on line %d
-1
bccomp(): Argument #1 ($num1) is not well-formed
bccomp(): Argument #1 ($num1) is not well-formed
bccomp(): Argument #1 ($num1) is not well-formed
bccomp(): Argument #1 ($num1) is not well-formed
bccomp(): Argument #1 ($num1) is not well-formed
+8 -1
View File
@@ -2722,7 +2722,14 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue, bool i
case CURLOPT_POSTFIELDS:
if (Z_TYPE_P(zvalue) == IS_ARRAY) {
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 {
zend_string *tmp_str;
zend_string *str = zval_get_tmp_string(zvalue, &tmp_str);
+1
View File
@@ -25,5 +25,6 @@ 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) {
}
"
+23303 -20532
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+10 -10
View File
@@ -57,7 +57,7 @@ function date_sub(DateTime $object, DateInterval $interval): DateTime {}
function date_timezone_get(DateTimeInterface $object): DateTimeZone|false {}
function date_timezone_set(DateTimeInterface $object, DateTimeZone $timezone): DateTime {}
function date_timezone_set(DateTime $object, DateTimeZone $timezone): DateTime {}
function date_offset_get(DateTimeInterface $object): int {}
@@ -105,12 +105,12 @@ function date_default_timezone_get(): string {}
function date_sunrise(
int $timestamp, int $returnFormat = SUNFUNCS_RET_STRING,
?float $latitude = null, ?float $longitude = null, ?float $zenith = null,
float $utcOffset = 0): string|int|float|false {}
?float $utcOffset = null): string|int|float|false {}
function date_sunset(
int $timestamp, int $returnFormat = SUNFUNCS_RET_STRING,
?float $latitude = null, ?float $longitude = null, ?float $zenith = null,
float $utcOffset = 0): string|int|float|false {}
?float $utcOffset = null): string|int|float|false {}
function date_sun_info(int $timestamp, float $latitude, float $longitude): array {}
@@ -125,7 +125,7 @@ interface DateTimeInterface
/** @return DateTimeZone|false */
public function getTimezone();
/** @return int|false */
/** @return int */
public function getOffset();
/** @return int|false */
@@ -202,7 +202,7 @@ class DateTime implements DateTimeInterface
public function setTimezone(DateTimeZone $timezone) {}
/**
* @return int|false
* @return int
* @alias date_offset_get
*/
public function getOffset() {}
@@ -238,7 +238,7 @@ class DateTime implements DateTimeInterface
public function getTimestamp() {}
/**
* @return DateInterval|false
* @return DateInterval
* @alias date_diff
*/
public function diff(DateTimeInterface $targetObject, bool $absolute = false) {}
@@ -251,7 +251,7 @@ class DateTimeImmutable implements DateTimeInterface
/** @return void */
public function __wakeup() {}
/** @return DateTimeZone */
/** @return DateTimeImmutable */
public static function __set_state(array $array) {}
/**
@@ -279,7 +279,7 @@ class DateTimeImmutable implements DateTimeInterface
public function getTimezone() {}
/**
* @return int|false
* @return int
* @alias date_offset_get
*/
public function getOffset() {}
@@ -291,7 +291,7 @@ class DateTimeImmutable implements DateTimeInterface
public function getTimestamp() {}
/**
* @return DateInterval|false
* @return DateInterval
* @alias date_diff
*/
public function diff(DateTimeInterface $targetObject, bool $absolute = false) {}
@@ -361,7 +361,7 @@ class DateTimeZone
public static function listAbbreviations() {}
/**
* @return array|false
* @return array
* @alias timezone_identifiers_list
*/
public static function listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null) {}
+3 -3
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 07d0e6179d838847d4a5d454f8b56438f8df19c0 */
* Stub hash: 880a93d8a3461635447318317869fa7d3d7762dd */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0)
@@ -110,7 +110,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_date_timezone_get, 0, 1, Dat
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_timezone_set, 0, 2, DateTime, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
ZEND_ARG_OBJ_INFO(0, timezone, DateTimeZone, 0)
ZEND_END_ARG_INFO()
@@ -214,7 +214,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_date_sunrise, 0, 1, MAY_BE_STRIN
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, latitude, IS_DOUBLE, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, longitude, IS_DOUBLE, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, zenith, IS_DOUBLE, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, utcOffset, IS_DOUBLE, 0, "0")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, utcOffset, IS_DOUBLE, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_date_sunset arginfo_date_sunrise
+8
View File
@@ -0,0 +1,8 @@
--TEST--
Bug #76770 'U' modifier in 'datetime::createFromFormat' adds seconds to other specifiers
--FILE--
<?php
var_dump(datetime::createFromFormat('U H', '3600 01')->getTimestamp());
?>
--EXPECT--
int(3600)
+2 -2
View File
@@ -129,7 +129,7 @@ class DOMNodeList implements IteratorAggregate, Countable
public function getIterator(): Iterator {}
/** @return ?DOMNode */
/** @return DOMNode|null */
public function item(int $index) {}
}
@@ -205,7 +205,7 @@ class DOMElement implements DOMParentNode, DOMChildNode
public function removeAttributeNS(?string $namespace, string $localName) {}
/** @return DOMAttr|false */
public function removeAttributeNode(string $qualifiedName) {}
public function removeAttributeNode(DOMAttr $attr) {}
/** @return DOMAttr|bool */
public function setAttribute(string $qualifiedName, string $value) {}
+6 -6
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 128108b08807ce0b125fc7b963bf3c5b77e6987a */
* Stub hash: 7cba1a7a34cc4789871faf44fc4794a48db26e61 */
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_dom_import_simplexml, 0, 1, DOMElement, 1)
ZEND_ARG_TYPE_INFO(0, node, IS_OBJECT, 0)
@@ -197,7 +197,9 @@ ZEND_END_ARG_INFO()
#define arginfo_class_DOMElement_removeAttributeNS arginfo_class_DOMElement_getAttributeNS
#define arginfo_class_DOMElement_removeAttributeNode arginfo_class_DOMElement_getAttribute
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMElement_removeAttributeNode, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, attr, DOMAttr, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMElement_setAttribute, 0, 0, 2)
ZEND_ARG_TYPE_INFO(0, qualifiedName, IS_STRING, 0)
@@ -210,11 +212,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMElement_setAttributeNS, 0, 0, 3)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMElement_setAttributeNode, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, attr, DOMAttr, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_DOMElement_setAttributeNode arginfo_class_DOMElement_removeAttributeNode
#define arginfo_class_DOMElement_setAttributeNodeNS arginfo_class_DOMElement_setAttributeNode
#define arginfo_class_DOMElement_setAttributeNodeNS arginfo_class_DOMElement_removeAttributeNode
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMElement_setIdAttribute, 0, 0, 2)
ZEND_ARG_TYPE_INFO(0, qualifiedName, IS_STRING, 0)
+9 -9
View File
@@ -3865,7 +3865,7 @@ ZEND_METHOD(FFI, cast) /* {{{ */
RETURN_OBJ(&cdata->std);
} else {
zend_wrong_parameter_class_error(2, "FFI\\CData", zv);
return;
RETURN_THROWS();
}
}
@@ -4006,7 +4006,7 @@ ZEND_METHOD(FFI, typeof) /* {{{ */
}
} else {
zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
return;
RETURN_THROWS();
}
ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
@@ -4110,7 +4110,7 @@ ZEND_METHOD(FFI, addr) /* {{{ */
ZVAL_DEREF(zv);
if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
return;
RETURN_THROWS();
}
cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
@@ -4165,7 +4165,7 @@ ZEND_METHOD(FFI, sizeof) /* {{{ */
type = ZEND_FFI_TYPE(ctype->type);
} else {
zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
return;
RETURN_THROWS();
}
RETURN_LONG(type->size);
@@ -4191,7 +4191,7 @@ ZEND_METHOD(FFI, alignof) /* {{{ */
type = ZEND_FFI_TYPE(ctype->type);
} else {
zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
return;
RETURN_THROWS();
}
RETURN_LONG(type->align);
@@ -4246,7 +4246,7 @@ ZEND_METHOD(FFI, memcpy) /* {{{ */
}
} else {
zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
return;
RETURN_THROWS();
}
memcpy(ptr1, ptr2, size);
@@ -4290,7 +4290,7 @@ ZEND_METHOD(FFI, memcmp) /* {{{ */
}
} else {
zend_wrong_parameter_class_error(1, "FFI\\CData or string", zv1);
return;
RETURN_THROWS();
}
ZVAL_DEREF(zv2);
@@ -4314,7 +4314,7 @@ ZEND_METHOD(FFI, memcmp) /* {{{ */
}
} else {
zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
return;
RETURN_THROWS();
}
ret = memcmp(ptr1, ptr2, size);
@@ -4416,7 +4416,7 @@ ZEND_METHOD(FFI, isNull) /* {{{ */
ZVAL_DEREF(zv);
if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
return;
RETURN_THROWS();
}
cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
+8 -8
View File
@@ -10,7 +10,7 @@ final class FFI
public static function load(string $filename): ?FFI {}
public static function scope(string $name): ?FFI {}
public static function scope(string $name): FFI {}
public static function new(FFI\CType|string $type, bool $owned = true, bool $persistent = false): ?FFI\CData {}
@@ -18,7 +18,7 @@ final class FFI
public static function free(FFI\CData $ptr): void {}
/**
* @param FFI\CData|string|int|null $ptr
* @param FFI\CData|int|float|bool|null $ptr
* @prefer-ref $ptr
*/
public static function cast(FFI\CType|string $type, $ptr): ?FFI\CData {}
@@ -26,18 +26,18 @@ final class FFI
public static function type(string $type): ?FFI\CType {}
/** @prefer-ref $ptr */
public static function typeof(FFI\CData $ptr): ?FFI\CType {}
public static function typeof(FFI\CData $ptr): FFI\CType {}
public static function arrayType(FFI\CType $type, array $dimensions): ?FFI\CType {}
public static function arrayType(FFI\CType $type, array $dimensions): FFI\CType {}
/** @prefer-ref $ptr */
public static function addr(FFI\CData $ptr): FFI\CData {}
/** @prefer-ref $ptr */
public static function sizeof(object $ptr): ?int {}
public static function sizeof(FFI\CData|FFI\CType $ptr): int {}
/** @prefer-ref $ptr */
public static function alignof(object $ptr): ?int {}
public static function alignof(FFI\CData|FFI\CType $ptr): int {}
/**
* @param FFI\CData|string $from
@@ -52,13 +52,13 @@ final class FFI
* @prefer-ref $ptr2
* @param string|FFI\CData $ptr2
*/
public static function memcmp($ptr1, $ptr2, int $size): ?int {}
public static function memcmp($ptr1, $ptr2, int $size): int {}
/** @prefer-ref $ptr */
public static function memset(FFI\CData $ptr, int $value, int $size): void {}
/** @prefer-ref $ptr */
public static function string(FFI\CData $ptr, ?int $size = null): ?string {}
public static function string(FFI\CData $ptr, ?int $size = null): string {}
/** @prefer-ref $ptr */
public static function isNull(FFI\CData $ptr): bool {}
+8 -8
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: abd3bc186ae3f71f2b7eb1d47f3b6bab84fb2bda */
* Stub hash: 5aeec68fea7a94cd643464acfb10bf4cfcc863da */
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_cdef, 0, 0, FFI, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, code, IS_STRING, 0, "\"\"")
@@ -10,7 +10,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_load, 0, 1, FFI, 1)
ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_scope, 0, 1, FFI, 1)
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_scope, 0, 1, FFI, 0)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
ZEND_END_ARG_INFO()
@@ -33,11 +33,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_type, 0, 1, FFI\\CType,
ZEND_ARG_TYPE_INFO(0, type, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_typeof, 0, 1, FFI\\CType, 1)
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_typeof, 0, 1, FFI\\CType, 0)
ZEND_ARG_OBJ_INFO(ZEND_SEND_PREFER_REF, ptr, FFI\\CData, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_arrayType, 0, 2, FFI\\CType, 1)
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_arrayType, 0, 2, FFI\\CType, 0)
ZEND_ARG_OBJ_INFO(0, type, FFI\\CType, 0)
ZEND_ARG_TYPE_INFO(0, dimensions, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
@@ -46,8 +46,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_addr, 0, 1, FFI\\CData,
ZEND_ARG_OBJ_INFO(ZEND_SEND_PREFER_REF, ptr, FFI\\CData, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_sizeof, 0, 1, IS_LONG, 1)
ZEND_ARG_TYPE_INFO(ZEND_SEND_PREFER_REF, ptr, IS_OBJECT, 0)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_sizeof, 0, 1, IS_LONG, 0)
ZEND_ARG_OBJ_TYPE_MASK(ZEND_SEND_PREFER_REF, ptr, FFI\\CData|FFI\\CType, 0, NULL)
ZEND_END_ARG_INFO()
#define arginfo_class_FFI_alignof arginfo_class_FFI_sizeof
@@ -58,7 +58,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_memcpy, 0, 3, IS_VOID,
ZEND_ARG_TYPE_INFO(0, size, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_memcmp, 0, 3, IS_LONG, 1)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_memcmp, 0, 3, IS_LONG, 0)
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, ptr1)
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, ptr2)
ZEND_ARG_TYPE_INFO(0, size, IS_LONG, 0)
@@ -70,7 +70,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_memset, 0, 3, IS_VOID,
ZEND_ARG_TYPE_INFO(0, size, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_string, 0, 1, IS_STRING, 1)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_string, 0, 1, IS_STRING, 0)
ZEND_ARG_OBJ_INFO(ZEND_SEND_PREFER_REF, ptr, FFI\\CData, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, size, IS_LONG, 1, "null")
ZEND_END_ARG_INFO()
+26
View File
@@ -233,6 +233,9 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
p++; len--;
if (allow_hex && (*p == 'x' || *p == 'X')) {
p++; len--;
if (len == 0) {
RETURN_VALIDATION_FAILED
}
if (php_filter_parse_hex(p, len, &ctx_value) < 0) {
error = 1;
}
@@ -553,6 +556,22 @@ void php_filter_validate_domain(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
}
/* }}} */
static int is_userinfo_valid(zend_string *str)
{
const char *valid = "-._~!$&'()*+,;=:";
const char *p = ZSTR_VAL(str);
while (p - ZSTR_VAL(str) < ZSTR_LEN(str)) {
if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) {
p++;
} else if (*p == '%' && p - ZSTR_VAL(str) <= ZSTR_LEN(str) - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) {
p += 3;
} else {
return 0;
}
}
return 1;
}
void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
{
php_url *url;
@@ -608,6 +627,13 @@ bad_url:
php_url_free(url);
RETURN_VALIDATION_FAILED
}
if (url->user != NULL && !is_userinfo_valid(url->user)) {
php_url_free(url);
RETURN_VALIDATION_FAILED
}
php_url_free(url);
}
/* }}} */
+15
View File
@@ -0,0 +1,15 @@
--TEST--
Bug #77423 (parse_url() will deliver a wrong host to user)
--FILE--
<?php
$urls = array(
"http://php.net\@aliyun.com/aaa.do",
"https://example.com\uFF03@bing.com",
);
foreach ($urls as $url) {
var_dump(filter_var($url, FILTER_VALIDATE_URL));
}
?>
--EXPECT--
bool(false)
bool(false)
+18
View File
@@ -0,0 +1,18 @@
--TEST--
Bug #80584: "0x" and "0X" are considered valid hex numbers by filter_var()
--SKIPIF--
<?php
if (!extension_loaded('filter')) die('skip filter extension not available');
?>
--FILE--
<?php
var_dump(filter_var('0x', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX));
var_dump(filter_var('0X', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX));
var_dump(filter_var('', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX));
var_dump(filter_var('0', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX));
?>
--EXPECT--
bool(false)
bool(false)
bool(false)
int(0)
+10 -5
View File
@@ -174,7 +174,7 @@ if (IS_GMP(zval)) { \
gmp_create(return_value, &gmpnumber)
static void gmp_strval(zval *result, mpz_t gmpnum, int base);
static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos);
static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos);
static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg);
/*
@@ -429,9 +429,14 @@ static int gmp_compare(zval *op1, zval *op2) /* {{{ */
zval result;
gmp_cmp(&result, op1, op2);
if (Z_TYPE(result) == IS_FALSE) {
/* An error/exception occurs if one of the operands is not a numeric string
* or an object which is different from GMP */
if (EG(exception)) {
return 1;
}
/* result can only be a zend_long if gmp_cmp hasn't thrown an Error */
ZEND_ASSERT(Z_TYPE(result) == IS_LONG);
return Z_LVAL(result);
}
/* }}} */
@@ -585,7 +590,7 @@ ZEND_MODULE_INFO_D(gmp)
/* {{{ convert_to_gmp
* Convert zval to be gmp number */
static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos)
static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos)
{
switch (Z_TYPE_P(val)) {
case IS_LONG:
@@ -596,7 +601,7 @@ static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t a
zend_bool skip_lead = 0;
int ret;
if (Z_STRLEN_P(val) > 2 && numstr[0] == '0') {
if (Z_STRLEN_P(val) >= 2 && numstr[0] == '0') {
if ((base == 0 || base == 16) && (numstr[1] == 'x' || numstr[1] == 'X')) {
base = 16;
skip_lead = 1;
@@ -614,7 +619,7 @@ static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t a
"Cannot convert variable to GMP, it is not an integer string");
return FAILURE;
}
zend_argument_type_error(arg_pos, "is not an integer string");
zend_argument_value_error(arg_pos, "is not an integer string");
return FAILURE;
}
+1 -1
View File
@@ -25,7 +25,7 @@ Check for number base recognition
$test[] = gmp_init("0x4d2", 16);
try {
$test[] = gmp_init("4d2");
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
$test[] = gmp_init("4d2", 16);
+1 -1
View File
@@ -7,7 +7,7 @@ Bug #66872: Crash when passing string to gmp_testbit
try {
var_dump(gmp_testbit("abc", 1));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
+222
View File
@@ -0,0 +1,222 @@
--TEST--
Bug #80560: Strings containing only a base prefix return 0 object
--SKIPIF--
<?php if (!extension_loaded("gmp")) print "skip"; ?>
--FILE--
<?php
$functions1 = [
'gmp_init',
'gmp_export',
'gmp_intval',
'gmp_strval',
'gmp_neg',
'gmp_abs',
'gmp_fact',
'gmp_sqrt',
'gmp_sqrtrem',
'gmp_perfect_square',
'gmp_perfect_power',
'gmp_prob_prime',
'gmp_sign',
'gmp_random_seed',
'gmp_popcount',
'gmp_com',
'gmp_nextprime',
];
$functions1_need_int_2 = [
'gmp_testbit',
'gmp_scan0',
'gmp_scan1',
'gmp_binomial',
'gmp_root',
'gmp_rootrem',
'gmp_pow',
];
$functions2 = [
'gmp_add',
'gmp_sub',
'gmp_mul',
'gmp_div',
'gmp_div_q',
'gmp_div_r',
'gmp_div_qr',
'gmp_divexact',
'gmp_mod',
'gmp_gcd',
'gmp_gcdext',
'gmp_lcm',
'gmp_invert',
'gmp_jacobi',
'gmp_legendre',
'gmp_kronecker',
'gmp_cmp',
'gmp_random_range',
'gmp_and',
'gmp_or',
'gmp_xor',
'gmp_hamdist',
];
$functions3 = [
'gmp_powm',
];
echo 'Explicit base with gmp_init:', \PHP_EOL;
echo 'Hexadecimal', \PHP_EOL;
try {
var_dump(gmp_init('0X', 16));
} catch (\ValueError $e) {
echo $e->getMessage(), \PHP_EOL;
}
try {
var_dump(gmp_init('0x', 16));
} catch (\ValueError $e) {
echo $e->getMessage(), \PHP_EOL;
}
echo 'Binary', \PHP_EOL;
try {
var_dump(gmp_init('0B', 2));
} catch (\ValueError $e) {
echo $e->getMessage(), \PHP_EOL;
}
try {
var_dump(gmp_init('0b', 2));
} catch (\ValueError $e) {
echo $e->getMessage(), \PHP_EOL;
}
echo 'Fuzzing gmp functions:', \PHP_EOL;
foreach ($functions1 as $function) {
try {
$function('0B');
echo $function, ' failed with 0B', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0b');
echo $function, ' failed with 0b', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0X');
echo $function, ' failed with 0X', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0x');
echo $function, ' failed with 0x', \PHP_EOL;
} catch (\ValueError) { }
}
foreach ($functions1_need_int_2 as $function) {
try {
$function('0B', 1);
echo $function, ' failed with 0B', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0b', 1);
echo $function, ' failed with 0b', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0X', 1);
echo $function, ' failed with 0X', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0x', 1);
echo $function, ' failed with 0x', \PHP_EOL;
} catch (\ValueError) { }
}
foreach ($functions2 as $function) {
try {
$function('0B', 1);
echo $function, ' arg 1 failed with 0B', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0b', 1);
echo $function, ' arg 1 failed with 0b', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0X', 1);
echo $function, ' arg 1 failed with 0X', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0x', 1);
echo $function, ' arg 1 failed with 0x', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, '0B');
echo $function, ' arg 2 failed with 0B', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, '0b');
echo $function, ' arg 2 failed with 0b', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, '0X');
echo $function, ' arg 2 failed with 0X', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, '0x');
echo $function, ' arg 2 failed with 0x', \PHP_EOL;
} catch (\ValueError) { }
}
foreach ($functions3 as $function) {
try {
$function('0B', 1, 1);
echo $function, ' arg 1 failed with 0B', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0b', 1, 1);
echo $function, ' arg 1 failed with 0b', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0X', 1, 1);
echo $function, ' arg 1 failed with 0X', \PHP_EOL;
} catch (\ValueError) { }
try {
$function('0x', 1, 1);
echo $function, ' arg 1 failed with 0x', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, '0B', 1);
echo $function, ' arg 2 failed with 0B', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, '0b', 1);
echo $function, ' arg 2 failed with 0b', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, '0X', 1);
echo $function, ' arg 2 failed with 0X', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, '0x', 1);
echo $function, ' arg 2 failed with 0x', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, 1, '0B');
echo $function, ' arg 3 failed with 0B', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, 1, '0b');
echo $function, ' arg 3 failed with 0b', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, 1, '0X');
echo $function, ' arg 3 failed with 0X', \PHP_EOL;
} catch (\ValueError) { }
try {
$function(1, 1, '0x');
echo $function, ' arg 3 failed with 0x', \PHP_EOL;
} catch (\ValueError) { }
}
echo "Done\n";
?>
--EXPECT--
Explicit base with gmp_init:
Hexadecimal
gmp_init(): Argument #1 ($num) is not an integer string
gmp_init(): Argument #1 ($num) is not an integer string
Binary
gmp_init(): Argument #1 ($num) is not an integer string
gmp_init(): Argument #1 ($num) is not an integer string
Fuzzing gmp functions:
Done
+23
View File
@@ -0,0 +1,23 @@
--TEST--
Invalid comparison with a GMP object
--SKIPIF--
<?php if (!extension_loaded("gmp")) print "skip"; ?>
--FILE--
<?php
try {
var_dump("hapfegfbu" > gmp_init(0));
} catch (\Error $e) {
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
}
try {
var_dump((new DateTime()) > gmp_init(0));
} catch (\Error $e) {
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
}
?>
--EXPECT--
ValueError: main(): Argument #2 is not an integer string
TypeError: main(): Argument #2 must be of type GMP|string|int, DateTime given
+3 -3
View File
@@ -7,7 +7,7 @@ gmp_abs() basic tests
try {
var_dump(gmp_strval(gmp_abs("")));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
var_dump(gmp_strval(gmp_abs("0")));
@@ -24,13 +24,13 @@ var_dump(gmp_strval(gmp_abs("0000")));
try {
// Base 8
var_dump(gmp_strval(gmp_abs("09876543")));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
try {
// Base 8
var_dump(gmp_strval(gmp_abs("-099987654")));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
+1 -1
View File
@@ -13,7 +13,7 @@ var_dump(gmp_strval(gmp_and(4545, -20)));
try {
var_dump(gmp_strval(gmp_and("test", "no test")));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
+1 -1
View File
@@ -9,7 +9,7 @@ var_dump(gmp_strval(gmp_com(0)));
var_dump(gmp_strval(gmp_com("0")));
try {
var_dump(gmp_strval(gmp_com("test")));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
var_dump(gmp_strval(gmp_com("2394876545678")));
+1 -1
View File
@@ -8,7 +8,7 @@ gmp_fact() basic tests
var_dump(gmp_strval(gmp_fact(0)));
try {
var_dump(gmp_strval(gmp_fact("")));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
var_dump(gmp_strval(gmp_fact("0")));
+3 -3
View File
@@ -15,17 +15,17 @@ try {
try {
var_dump(gmp_init("",36));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
try {
var_dump(gmp_init("foo",3));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
try {
var_dump(gmp_strval(gmp_init("993247326237679187178",3)));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
+2 -2
View File
@@ -16,7 +16,7 @@ var_dump(gmp_intval($g));
try {
var_dump(gmp_intval(""));
} catch (TypeError $e) {
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
try {
@@ -31,7 +31,7 @@ try {
}
try {
var_dump(gmp_intval("1.0001"));
} catch (TypeError $e) {
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
+1 -1
View File
@@ -7,7 +7,7 @@ gmp_mod tests()
try {
var_dump(gmp_mod("",""));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
var_dump(gmp_mod(0,1));
+1 -1
View File
@@ -12,7 +12,7 @@ var_dump(gmp_intval(gmp_neg("-1")));
try {
var_dump(gmp_intval(gmp_neg("")));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
+1 -1
View File
@@ -25,7 +25,7 @@ try {
try {
$n = gmp_nextprime("");
var_dump(gmp_strval($n));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
try {
+1 -1
View File
@@ -13,7 +13,7 @@ var_dump(gmp_strval(gmp_or(4545, -20)));
try {
var_dump(gmp_strval(gmp_or("test", "no test")));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
+1 -1
View File
@@ -108,7 +108,7 @@ var_dump(gmp_strval(gmp_random_range(-10000, 0)));
// standard non conversion error
try {
var_dump(gmp_random_seed('not a number'));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
+2 -2
View File
@@ -13,13 +13,13 @@ var_dump(gmp_sign("-34535345345"));
try {
var_dump(gmp_sign("+34534573457345"));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
try {
$n = gmp_init("098909878976786545");
var_dump(gmp_sign($n));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
try {
+1 -1
View File
@@ -7,7 +7,7 @@ gmp_strval() tests
try {
var_dump(gmp_strval(""));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
try {
+1 -1
View File
@@ -7,7 +7,7 @@ gmp_sub() tests
try {
var_dump(gmp_sub("", ""));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
try {
+1 -1
View File
@@ -13,7 +13,7 @@ var_dump(gmp_strval(gmp_xor(4545, -20)));
try {
var_dump(gmp_strval(gmp_xor("test", "no test")));
} catch (\TypeError $e) {
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
+2 -2
View File
@@ -21,7 +21,7 @@ function imap_close($imap, int $flags = 0): bool {}
function imap_num_msg($imap): int|false {}
/** @param resource $imap */
function imap_num_recent($imap): int|false {}
function imap_num_recent($imap): int {}
/** @param resource $imap */
function imap_headers($imap): array|false {}
@@ -179,7 +179,7 @@ function imap_sort($imap, int $criteria, bool $reverse, int $flags = 0, ?string
function imap_uid($imap, int $message_num): int|false {}
/** @param resource $imap */
function imap_msgno($imap, int $message_uid): int|false {}
function imap_msgno($imap, int $message_uid): int {}
/** @param resource $imap */
function imap_list($imap, string $reference, string $pattern): array|false {}
+5 -3
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 326cb0410034aecc702e9397cd88ef91adaa254c */
* Stub hash: d6d158112a802d867646b8f85402b8762599180b */
ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_open, 0, 0, 3)
ZEND_ARG_TYPE_INFO(0, mailbox, IS_STRING, 0)
@@ -26,7 +26,9 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imap_num_msg, 0, 1, MAY_BE_LONG|
ZEND_ARG_INFO(0, imap)
ZEND_END_ARG_INFO()
#define arginfo_imap_num_recent arginfo_imap_num_msg
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imap_num_recent, 0, 1, IS_LONG, 0)
ZEND_ARG_INFO(0, imap)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imap_headers, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_INFO(0, imap)
@@ -218,7 +220,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imap_uid, 0, 2, MAY_BE_LONG|MAY_
ZEND_ARG_TYPE_INFO(0, message_num, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imap_msgno, 0, 2, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imap_msgno, 0, 2, IS_LONG, 0)
ZEND_ARG_INFO(0, imap)
ZEND_ARG_TYPE_INFO(0, message_uid, IS_LONG, 0)
ZEND_END_ARG_INFO()
+1 -1
View File
@@ -8,7 +8,7 @@ class IntlCalendar
/**
* @param IntlTimeZone|DateTimeZone|string|null $timezone
* @return IntlCalendar|IntlGregorianCalendar|null
* @return IntlCalendar|null
* @alias intlcal_create_instance
*/
public static function createInstance($timezone = null, ?string $locale = null) {}
+1 -1
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: ee755d4a500e2d1ba4d589c233b7d09a06b5cce8 */
* Stub hash: 18a92d3af801f11e5c3b90e5d272fd98b3515c40 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlCalendar___construct, 0, 0, 0)
ZEND_END_ARG_INFO()
+1 -1
View File
@@ -48,7 +48,7 @@ class IntlDateFormatter
public function getTimeZoneId() {}
/**
* @return IntlCalendar|null|false
* @return IntlCalendar|false|null
* @alias datefmt_get_calendar_object
*/
public function getCalendarObject() {}
+1 -1
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 437726f2d61a93d530e7e3b6df0741ae68c64697 */
* Stub hash: 62742b5f463272f43970e98900a89d513c4fb839 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlDateFormatter___construct, 0, 0, 3)
ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 1)
@@ -171,8 +171,9 @@ static void resourcebundle_array_fetch(zend_object *object, zval *offset, zval *
char *pbuf;
ResourceBundle_object *rb;
intl_error_reset( NULL );
rb = php_intl_resourcebundle_fetch_object(object);
intl_error_reset(NULL);
intl_error_reset(INTL_DATA_ERROR_P(rb));
if(Z_TYPE_P(offset) == IS_LONG) {
is_numeric = 1;
@@ -28,6 +28,10 @@ function ut_main() {
$t = ut_resourcebundle_get( $r, 'nonexisting' );
$str_res .= debug( $t );
// Make sure accessing existing after non-existing works.
$t = ut_resourcebundle_get( $r, 'teststring' );
$str_res .= debug( $t );
return $str_res;
}
include_once( 'ut_common.inc' );
@@ -55,3 +59,5 @@ testtable: 3
testarray: string 3
NULL
2: Cannot load resource element 'nonexisting': U_MISSING_RESOURCE_ERROR
Hello World!
0: U_ZERO_ERROR
+3 -3
View File
@@ -35,19 +35,19 @@ function ldap_sasl_bind($ldap, ?string $dn = null, ?string $password = null, ?st
/**
* @param resource|array $ldap
* @return resource|false
* @return resource|array|false
*/
function ldap_read($ldap, array|string $base, array|string $filter, array $attributes = [], int $attributes_only = 0, int $sizelimit = -1, int $timelimit = -1, int $deref = LDAP_DEREF_NEVER, ?array $controls = null) {}
/**
* @param resource|array $ldap
* @return resource|false
* @return resource|array|false
*/
function ldap_list($ldap, array|string $base, array|string $filter, array $attributes = [], int $attributes_only = 0, int $sizelimit = -1, int $timelimit = -1, int $deref = LDAP_DEREF_NEVER, ?array $controls = null) {}
/**
* @param resource|array $ldap
* @return resource|false
* @return resource|array|false
*/
function ldap_search($ldap, array|string $base, array|string $filter, array $attributes = [], int $attributes_only = 0, int $sizelimit = -1, int $timelimit = -1, int $deref = LDAP_DEREF_NEVER, ?array $controls = null) {}
+1 -1
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 836e18943977613fc0abf7443ad4d5afdbe65a0a */
* Stub hash: 9d6315aeee2e3a1be51c05b65a960ed433bbe4ec */
#if defined(HAVE_ORALDAP)
ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_connect, 0, 0, 0)
+29 -29
View File
@@ -36,7 +36,7 @@ class mysqli
public function change_user(string $username, string $password, ?string $database) {}
/**
* @return string|null
* @return string
* @alias mysqli_character_set_name
*/
public function character_set_name() {}
@@ -51,7 +51,7 @@ class mysqli
* @return bool
* @alias mysqli_commit
*/
public function commit(int $flags = -1, ?string $name = null) {}
public function commit(int $flags = 0, ?string $name = null) {}
/**
* @return mysqli|null|false
@@ -101,7 +101,7 @@ class mysqli
#endif
/**
* @return string|null
* @return string
* @alias mysqli_get_server_info
*/
public function get_server_info() {}
@@ -152,7 +152,7 @@ class mysqli
* @return int|false
* @alias mysqli_poll
*/
public static function poll(?array &$read, ?array &$write, array &$error, int $seconds, int $microseconds = 0) {}
public static function poll(?array &$read, ?array &$error, array &$reject, int $seconds, int $microseconds = 0) {}
#endif
/**
@@ -342,7 +342,7 @@ class mysqli_result implements IteratorAggregate
#if defined(MYSQLI_USE_MYSQLND)
/**
* @return array|false
* @return array
* @alias mysqli_fetch_all
*/
public function fetch_all(int $mode = MYSQLI_NUM) {}
@@ -355,19 +355,19 @@ class mysqli_result implements IteratorAggregate
public function fetch_array(int $mode = MYSQLI_BOTH) {}
/**
* @return array|null
* @return array|null|false
* @alias mysqli_fetch_assoc
*/
public function fetch_assoc() {}
/**
* @return object|null
* @return object|null|false
* @alias mysqli_fetch_object
*/
public function fetch_object(string $class = "stdClass", array $constructor_args = []) {}
/**
* @return array|null
* @return array|null|false
* @alias mysqli_fetch_row
*/
public function fetch_row() {}
@@ -392,7 +392,7 @@ class mysqli_stmt
public function __construct(mysqli $mysql, ?string $query = null) {}
/**
* @return int|false
* @return int
* @alias mysqli_stmt_attr_get
*/
public function attr_get(int $attribute) {}
@@ -529,11 +529,11 @@ function mysqli_begin_transaction(mysqli $mysql, int $flags = 0, ?string $name =
function mysqli_change_user(mysqli $mysql, string $username, string $password, ?string $database): bool {}
function mysqli_character_set_name(mysqli $mysql): ?string {}
function mysqli_character_set_name(mysqli $mysql): string {}
function mysqli_close(mysqli $mysql): bool {}
function mysqli_commit(mysqli $mysql, int $flags = -1, ?string $name = null): bool {}
function mysqli_commit(mysqli $mysql, int $flags = 0, ?string $name = null): bool {}
function mysqli_connect(
?string $hostname = null,
@@ -556,7 +556,7 @@ function mysqli_debug(string $options): bool {}
function mysqli_errno(mysqli $mysql): int {}
function mysqli_error(mysqli $mysql): ?string {}
function mysqli_error(mysqli $mysql): string {}
function mysqli_error_list(mysqli $mysql): array {}
@@ -574,16 +574,16 @@ function mysqli_fetch_field_direct(mysqli_result $result, int $index): object|fa
function mysqli_fetch_lengths(mysqli_result $result): array|false {}
#if defined(MYSQLI_USE_MYSQLND)
function mysqli_fetch_all(mysqli_result $result, int $mode = MYSQLI_NUM): array|false {}
function mysqli_fetch_all(mysqli_result $result, int $mode = MYSQLI_NUM): array {}
#endif
function mysqli_fetch_array(mysqli_result $result, int $mode = MYSQLI_BOTH): array|null|false {}
function mysqli_fetch_assoc(mysqli_result $result): ?array {}
function mysqli_fetch_assoc(mysqli_result $result): array|null|false {}
function mysqli_fetch_object(mysqli_result $result, string $class = "stdClass", array $constructor_args = []): ?object {}
function mysqli_fetch_object(mysqli_result $result, string $class = "stdClass", array $constructor_args = []): object|null|false {}
function mysqli_fetch_row(mysqli_result $result): ?array {}
function mysqli_fetch_row(mysqli_result $result): array|null|false {}
function mysqli_field_count(mysqli $mysql): int {}
@@ -638,10 +638,16 @@ function mysqli_num_rows(mysqli_result $result): int|string {}
/** @param string|int $value */
function mysqli_options(mysqli $mysql, int $option, $value): bool {}
/**
* @param string|int $value
* @alias mysqli_options
*/
function mysqli_set_opt(mysqli $mysql, int $option, $value): bool {}
function mysqli_ping(mysqli $mysql): bool {}
#if defined(MYSQLI_USE_MYSQLND)
function mysqli_poll(?array &$read, ?array &$write, array &$error, int $seconds, int $microseconds = 0): int|false {}
function mysqli_poll(?array &$read, ?array &$error, array &$reject, int $seconds, int $microseconds = 0): int|false {}
#endif
function mysqli_prepare(mysqli $mysql, string $query): mysqli_stmt|false {}
@@ -663,6 +669,9 @@ function mysqli_real_connect(
function mysqli_real_escape_string(mysqli $mysql, string $string): string {}
/** @alias mysqli_real_escape_string */
function mysqli_escape_string(mysqli $mysql, string $string): string {}
function mysqli_real_query(mysqli $mysql, string $query): bool {}
#if defined(MYSQLI_USE_MYSQLND)
@@ -695,7 +704,7 @@ function mysqli_stmt_data_seek(mysqli_stmt $statement, int $offset): void {}
function mysqli_stmt_errno(mysqli_stmt $statement): int {}
function mysqli_stmt_error(mysqli_stmt $statement): ?string {}
function mysqli_stmt_error(mysqli_stmt $statement): string {}
function mysqli_stmt_error_list(mysqli_stmt $statement): array {}
@@ -735,9 +744,9 @@ function mysqli_stmt_send_long_data(mysqli_stmt $statement, int $param_num, stri
function mysqli_stmt_store_result(mysqli_stmt $statement): bool {}
function mysqli_stmt_sqlstate(mysqli_stmt $statement): ?string {}
function mysqli_stmt_sqlstate(mysqli_stmt $statement): string {}
function mysqli_sqlstate(mysqli $mysql): ?string {}
function mysqli_sqlstate(mysqli $mysql): string {}
function mysqli_ssl_set(
mysqli $mysql,
@@ -761,12 +770,3 @@ function mysqli_use_result(mysqli $mysql): mysqli_result|false {}
function mysqli_warning_count(mysqli $mysql): int {}
function mysqli_refresh(mysqli $mysql, int $flags): bool {}
/** @alias mysqli_real_escape_string */
function mysqli_escape_string(mysqli $mysql, string $string): string {}
/**
* @param string|int $value
* @alias mysqli_options
*/
function mysqli_set_opt(mysqli $mysql, int $option, $value): bool {}
+6 -29
View File
@@ -614,17 +614,13 @@ PHP_FUNCTION(mysqli_character_set_name)
{
MY_MYSQL *mysql;
zval *mysql_link;
const char *cs_name;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
RETURN_THROWS();
}
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
cs_name = mysql_character_set_name(mysql->mysql);
if (cs_name) {
RETURN_STRING(cs_name);
}
RETURN_STRING(mysql_character_set_name(mysql->mysql));
}
/* }}} */
@@ -801,16 +797,12 @@ PHP_FUNCTION(mysqli_error)
{
MY_MYSQL *mysql;
zval *mysql_link;
const char *err;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
RETURN_THROWS();
}
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
err = mysql_error(mysql->mysql);
if (err) {
RETURN_STRING(err);
}
RETURN_STRING(mysql_error(mysql->mysql));
}
/* }}} */
@@ -1337,10 +1329,7 @@ PHP_FUNCTION(mysqli_get_client_info)
}
}
const char * info = mysql_get_client_info();
if (info) {
RETURN_STRING(info);
}
RETURN_STRING(mysql_get_client_info());
}
/* }}} */
@@ -2151,16 +2140,12 @@ PHP_FUNCTION(mysqli_sqlstate)
{
MY_MYSQL *mysql;
zval *mysql_link;
const char *state;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
RETURN_THROWS();
}
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
state = mysql_sqlstate(mysql->mysql);
if (state) {
RETURN_STRING(state);
}
RETURN_STRING(mysql_sqlstate(mysql->mysql));
}
/* }}} */
@@ -2360,17 +2345,13 @@ PHP_FUNCTION(mysqli_stmt_error)
{
MY_STMT *stmt;
zval *mysql_stmt;
const char * err;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
RETURN_THROWS();
}
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
err = mysql_stmt_error(stmt->stmt);
if (err) {
RETURN_STRING(err);
}
RETURN_STRING(mysql_stmt_error(stmt->stmt));
}
/* }}} */
@@ -2501,17 +2482,13 @@ PHP_FUNCTION(mysqli_stmt_sqlstate)
{
MY_STMT *stmt;
zval *mysql_stmt;
const char * state;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
RETURN_THROWS();
}
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
state = mysql_stmt_sqlstate(stmt->stmt);
if (state) {
RETURN_STRING(state);
}
RETURN_STRING(mysql_stmt_sqlstate(stmt->stmt));
}
/* }}} */
+23 -30
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 480939b71e1dacbdbb4634dbabf375943e399b6f */
* Stub hash: 5a8b778eaa9efcca7d3ad8bfdbaa31d9d07b25e8 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_affected_rows, 0, 1, MAY_BE_LONG|MAY_BE_STRING)
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
@@ -23,7 +23,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_change_user, 0, 4, _IS_BO
ZEND_ARG_TYPE_INFO(0, database, IS_STRING, 1)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_character_set_name, 0, 1, IS_STRING, 1)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_character_set_name, 0, 1, IS_STRING, 0)
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
ZEND_END_ARG_INFO()
@@ -31,11 +31,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_close, 0, 1, _IS_BOOL, 0)
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_commit, 0, 1, _IS_BOOL, 0)
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, name, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_mysqli_commit arginfo_mysqli_begin_transaction
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_mysqli_connect, 0, 0, mysqli, MAY_BE_NULL|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, hostname, IS_STRING, 1, "null")
@@ -97,7 +93,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_lengths, 0, 1, MAY_
ZEND_END_ARG_INFO()
#if defined(MYSQLI_USE_MYSQLND)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_all, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_fetch_all, 0, 1, IS_ARRAY, 0)
ZEND_ARG_OBJ_INFO(0, result, mysqli_result, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "MYSQLI_NUM")
ZEND_END_ARG_INFO()
@@ -108,11 +104,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_array, 0, 1, MAY_BE
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "MYSQLI_BOTH")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_fetch_assoc, 0, 1, IS_ARRAY, 1)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_assoc, 0, 1, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE)
ZEND_ARG_OBJ_INFO(0, result, mysqli_result, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_fetch_object, 0, 1, IS_OBJECT, 1)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_object, 0, 1, MAY_BE_OBJECT|MAY_BE_NULL|MAY_BE_FALSE)
ZEND_ARG_OBJ_INFO(0, result, mysqli_result, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, class, IS_STRING, 0, "\"stdClass\"")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, constructor_args, IS_ARRAY, 0, "[]")
@@ -159,13 +155,11 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_get_links_stats, 0, 0, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_get_host_info, 0, 1, IS_STRING, 0)
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
ZEND_END_ARG_INFO()
#define arginfo_mysqli_get_host_info arginfo_mysqli_character_set_name
#define arginfo_mysqli_get_proto_info arginfo_mysqli_errno
#define arginfo_mysqli_get_server_info arginfo_mysqli_get_host_info
#define arginfo_mysqli_get_server_info arginfo_mysqli_character_set_name
#define arginfo_mysqli_get_server_version arginfo_mysqli_errno
@@ -176,7 +170,9 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_mysqli_init, 0, 0, mysqli, MAY_BE_FALSE)
ZEND_END_ARG_INFO()
#define arginfo_mysqli_info arginfo_mysqli_character_set_name
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_info, 0, 1, IS_STRING, 1)
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
ZEND_END_ARG_INFO()
#define arginfo_mysqli_insert_id arginfo_mysqli_affected_rows
@@ -206,13 +202,15 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_options, 0, 3, _IS_BOOL,
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
#define arginfo_mysqli_set_opt arginfo_mysqli_options
#define arginfo_mysqli_ping arginfo_mysqli_close
#if defined(MYSQLI_USE_MYSQLND)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_poll, 0, 4, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(1, read, IS_ARRAY, 1)
ZEND_ARG_TYPE_INFO(1, write, IS_ARRAY, 1)
ZEND_ARG_TYPE_INFO(1, error, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(1, error, IS_ARRAY, 1)
ZEND_ARG_TYPE_INFO(1, reject, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, microseconds, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
@@ -249,6 +247,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_real_escape_string, 0, 2,
ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_mysqli_escape_string arginfo_mysqli_real_escape_string
#define arginfo_mysqli_real_query arginfo_mysqli_multi_query
#if defined(MYSQLI_USE_MYSQLND)
@@ -313,7 +313,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_stmt_errno, 0, 1, IS_LONG
ZEND_ARG_OBJ_INFO(0, statement, mysqli_stmt, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_stmt_error, 0, 1, IS_STRING, 1)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_stmt_error, 0, 1, IS_STRING, 0)
ZEND_ARG_OBJ_INFO(0, statement, mysqli_stmt, 0)
ZEND_END_ARG_INFO()
@@ -418,10 +418,6 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_refresh, 0, 2, _IS_BOOL,
ZEND_ARG_TYPE_INFO(0, flags, IS_LONG, 0)
ZEND_END_ARG_INFO()
#define arginfo_mysqli_escape_string arginfo_mysqli_real_escape_string
#define arginfo_mysqli_set_opt arginfo_mysqli_options
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, hostname, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, username, IS_STRING, 1, "null")
@@ -451,10 +447,7 @@ ZEND_END_ARG_INFO()
#define arginfo_class_mysqli_close arginfo_class_mysqli_character_set_name
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_commit, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, name, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_mysqli_commit arginfo_class_mysqli_begin_transaction
#define arginfo_class_mysqli_connect arginfo_class_mysqli___construct
@@ -496,8 +489,8 @@ ZEND_END_ARG_INFO()
#if defined(MYSQLI_USE_MYSQLND)
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_poll, 0, 0, 4)
ZEND_ARG_TYPE_INFO(1, read, IS_ARRAY, 1)
ZEND_ARG_TYPE_INFO(1, write, IS_ARRAY, 1)
ZEND_ARG_TYPE_INFO(1, error, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(1, error, IS_ARRAY, 1)
ZEND_ARG_TYPE_INFO(1, reject, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, microseconds, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
@@ -878,6 +871,7 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(mysqli_num_fields, arginfo_mysqli_num_fields)
ZEND_FE(mysqli_num_rows, arginfo_mysqli_num_rows)
ZEND_FE(mysqli_options, arginfo_mysqli_options)
ZEND_FALIAS(mysqli_set_opt, mysqli_options, arginfo_mysqli_set_opt)
ZEND_FE(mysqli_ping, arginfo_mysqli_ping)
#if defined(MYSQLI_USE_MYSQLND)
ZEND_FE(mysqli_poll, arginfo_mysqli_poll)
@@ -887,6 +881,7 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(mysqli_query, arginfo_mysqli_query)
ZEND_FE(mysqli_real_connect, arginfo_mysqli_real_connect)
ZEND_FE(mysqli_real_escape_string, arginfo_mysqli_real_escape_string)
ZEND_FALIAS(mysqli_escape_string, mysqli_real_escape_string, arginfo_mysqli_escape_string)
ZEND_FE(mysqli_real_query, arginfo_mysqli_real_query)
#if defined(MYSQLI_USE_MYSQLND)
ZEND_FE(mysqli_reap_async_query, arginfo_mysqli_reap_async_query)
@@ -938,8 +933,6 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(mysqli_use_result, arginfo_mysqli_use_result)
ZEND_FE(mysqli_warning_count, arginfo_mysqli_warning_count)
ZEND_FE(mysqli_refresh, arginfo_mysqli_refresh)
ZEND_FALIAS(mysqli_escape_string, mysqli_real_escape_string, arginfo_mysqli_escape_string)
ZEND_FALIAS(mysqli_set_opt, mysqli_options, arginfo_mysqli_set_opt)
ZEND_FE_END
};
+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 -19
View File
@@ -109,7 +109,7 @@ if (!function_exists('mysqli_stmt_get_result'))
mysqli_stmt_close($stmt);
// 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));
@@ -122,24 +122,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));
@@ -196,8 +183,18 @@ if (!function_exists('mysqli_stmt_get_result'))
mysqli_stmt object is not fully initialized
mysqli_stmt object is not fully initialized
mysqli_stmt object is not fully initialized
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
@@ -37,6 +37,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 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)
@@ -57,14 +87,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);
}
@@ -75,6 +99,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; */
@@ -149,19 +179,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);
}
@@ -170,6 +189,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) {
@@ -578,28 +603,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 */
@@ -957,11 +984,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);
@@ -991,7 +1014,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");
@@ -1015,18 +1037,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
@@ -1604,8 +1604,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';
@@ -1649,28 +1669,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 {
else {
ZVAL_STRINGL_FAST(current_field, (char *)p, len);
}
p += len;
+31 -14
View File
@@ -8,7 +8,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
<summary>Extension for Oracle Database</summary>
<description>
The OCI8 extension let you access Oracle Database.
The OCI8 extension lets you access Oracle Database.
Use 'pecl install oci8' to install for PHP 8.
@@ -53,12 +53,12 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
<active>no</active>
</lead>
<date>2020-11-26</date>
<date>2020-12-21</date>
<time>12:00:00</time>
<version>
<release>3.0.0</release>
<api>3.0.0</api>
<release>3.0.1</release>
<api>3.0.1</api>
</version>
<stability>
<release>stable</release>
@@ -68,15 +68,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
<notes>
This version is for PHP 8 only.
Deprecated old OCI8 function aliases. (Jens de Nies)
Removed obsolete no-op function oci_internal_debug(). (Jens de Nies)
The OCI-Lob class is now called OCILob for standards compliance.
The OCI-Collection class is now called OCICollection for standards compliance.
Generate arginfo from function stubs. (Jens de Nies)
Updated Windows build environment to build with newer Oracle Client libraries. (cmb)
</notes>
<contents>
<dir name="/">
@@ -451,7 +443,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
<dependencies>
<required>
<php>
<min>7.0.0</min>
<min>8.0.0</min>
</php>
<pearinstaller>
<min>1.4.0b1</min>
@@ -484,6 +476,31 @@ Internal change: Convert some parameter parsing to the Fast Parameter Parsing AP
</notes>
</release>
<release>
<version>
<release>3.0.0</release>
<api>3.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://www.php.net/license">PHP</license>
<notes>
This version is for PHP 8 only.
Deprecated old OCI8 function aliases. (Jens de Nies)
Removed obsolete no-op function oci_internal_debug(). (Jens de Nies)
The OCI-Lob class is now called OCILob for standards compliance.
The OCI-Collection class is now called OCICollection for standards compliance.
Generate arginfo from function stubs. (Jens de Nies)
</notes>
</release>
<release>
<version>
<release>2.1.8</release>
+1 -1
View File
@@ -41,7 +41,7 @@
*/
#undef PHP_OCI8_VERSION
#endif
#define PHP_OCI8_VERSION "3.0.0"
#define PHP_OCI8_VERSION "3.0.1"
extern zend_module_entry oci8_module_entry;
#define phpext_oci8_ptr &oci8_module_entry
+3 -3
View File
@@ -57,11 +57,11 @@ function get_attr($conn)
?>
--EXPECT--
**Test 1.1 - Default values for the attribute **************
The value of DRIVER_NAME is PHP OCI8 : 3.0.0
The value of DRIVER_NAME is PHP OCI8 : 3.0.1
***Test 1.2 - Get the values from different connections **************
Testing with oci_pconnect()
The value of DRIVER_NAME is PHP OCI8 : 3.0.0
The value of DRIVER_NAME is PHP OCI8 : 3.0.1
Testing with oci_new_connect()
The value of DRIVER_NAME is PHP OCI8 : 3.0.0
The value of DRIVER_NAME is PHP OCI8 : 3.0.1
Done
+6 -5
View File
@@ -963,6 +963,7 @@ PHP_FUNCTION(odbc_prepare)
typedef struct odbc_params_t {
SQLLEN vallen;
int fp;
zend_string *zstr;
} odbc_params_t;
static void odbc_release_params(odbc_result *result, odbc_params_t *params) {
@@ -971,6 +972,9 @@ static void odbc_release_params(odbc_result *result, odbc_params_t *params) {
if (params[i].fp != -1) {
close(params[i].fp);
}
if (params[i].zstr) {
zend_string_release(params[i].zstr);
}
}
efree(params);
}
@@ -1004,6 +1008,7 @@ PHP_FUNCTION(odbc_execute)
params = (odbc_params_t *)safe_emalloc(sizeof(odbc_params_t), result->numparams, 0);
for(i = 0; i < result->numparams; i++) {
params[i].fp = -1;
params[i].zstr = NULL;
}
i = 1;
@@ -1017,6 +1022,7 @@ PHP_FUNCTION(odbc_execute)
params[i-1].vallen = ZSTR_LEN(tmpstr);
params[i-1].fp = -1;
params[i-1].zstr = tmpstr;
if (IS_SQL_BINARY(result->param_info[i-1].sqltype)) {
ctype = SQL_C_BINARY;
@@ -1030,7 +1036,6 @@ PHP_FUNCTION(odbc_execute)
if (ZSTR_LEN(tmpstr) != strlen(ZSTR_VAL(tmpstr))) {
odbc_release_params(result, params);
zend_string_release(tmpstr);
RETURN_FALSE;
}
filename = estrndup(&ZSTR_VAL(tmpstr)[1], ZSTR_LEN(tmpstr) - 2);
@@ -1040,14 +1045,12 @@ PHP_FUNCTION(odbc_execute)
if (php_check_open_basedir(filename)) {
efree(filename);
odbc_release_params(result, params);
zend_string_release(tmpstr);
RETURN_FALSE;
}
if ((params[i-1].fp = open(filename,O_RDONLY)) == -1) {
php_error_docref(NULL, E_WARNING,"Can't open file %s", filename);
odbc_release_params(result, params);
zend_string_release(tmpstr);
efree(filename);
RETURN_FALSE;
}
@@ -1076,10 +1079,8 @@ PHP_FUNCTION(odbc_execute)
if (rc == SQL_ERROR) {
odbc_sql_error(result->conn_ptr, result->stmt, "SQLBindParameter");
odbc_release_params(result, params);
zend_string_release(tmpstr);
RETURN_FALSE;
}
zend_string_release(tmpstr);
if (++i > result->numparams) break;
} ZEND_HASH_FOREACH_END();
}
+31
View File
@@ -0,0 +1,31 @@
--TEST--
Bug #80592 (all floats are the same in ODBC parameters)
--SKIPIF--
<?php include 'skipif.inc'; ?>
--FILE--
<?php
include 'config.inc';
$conn = odbc_connect($dsn, $user, $pass);
odbc_exec($conn,"CREATE TABLE bug80592 (f1 float not null, f2 float not null, f3 float not null)");
$stmt = odbc_prepare($conn, "INSERT INTO bug80592 (f1, f2, f3) values (?, ?, ?)");
odbc_execute($stmt, [1.0, 2.0, 3.0]);
$res = odbc_exec($conn, "SELECT f1, f2, f3 from bug80592");
var_dump(odbc_fetch_array($res));
?>
--CLEAN--
<?php
include 'config.inc';
$conn = odbc_connect($dsn, $user, $pass);
odbc_exec($conn, "DROP TABLE bug80592");
?>
--EXPECT--
array(3) {
["f1"]=>
string(3) "1.0"
["f2"]=>
string(3) "2.0"
["f3"]=>
string(3) "3.0"
}
+6 -6
View File
@@ -462,12 +462,12 @@ static const func_info_t func_infos[] = {
F1("mysqli_get_charset", MAY_BE_NULL | MAY_BE_OBJECT),
F1("mysqli_fetch_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("mysqli_fetch_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("mysqli_fetch_all", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("mysqli_fetch_all", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("mysqli_fetch_object", MAY_BE_NULL | MAY_BE_OBJECT),
F1("mysqli_affected_rows", MAY_BE_LONG | MAY_BE_STRING),
F1("mysqli_character_set_name", MAY_BE_NULL | MAY_BE_STRING),
F1("mysqli_character_set_name", MAY_BE_STRING),
F0("mysqli_debug", MAY_BE_TRUE),
F1("mysqli_error", MAY_BE_NULL | MAY_BE_STRING),
F1("mysqli_error", MAY_BE_STRING),
F1("mysqli_reap_async_query", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_OBJECT),
F1("mysqli_stmt_get_result", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_get_warnings", MAY_BE_FALSE | MAY_BE_OBJECT),
@@ -490,13 +490,13 @@ static const func_info_t func_infos[] = {
F1("mysqli_stmt_affected_rows", MAY_BE_LONG | MAY_BE_STRING),
F1("mysqli_stmt_insert_id", MAY_BE_LONG | MAY_BE_STRING),
F1("mysqli_stmt_num_rows", MAY_BE_LONG | MAY_BE_STRING),
F1("mysqli_sqlstate", MAY_BE_NULL | MAY_BE_STRING),
F1("mysqli_sqlstate", MAY_BE_STRING),
F0("mysqli_ssl_set", MAY_BE_TRUE),
F1("mysqli_stat", MAY_BE_FALSE | MAY_BE_STRING),
F1("mysqli_stmt_error", MAY_BE_NULL | MAY_BE_STRING),
F1("mysqli_stmt_error", MAY_BE_STRING),
F1("mysqli_stmt_init", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_stmt_result_metadata", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_stmt_sqlstate", MAY_BE_NULL | MAY_BE_STRING),
F1("mysqli_stmt_sqlstate", MAY_BE_STRING),
F1("mysqli_store_result", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("mysqli_use_result", MAY_BE_FALSE | MAY_BE_OBJECT),
+15 -6
View File
@@ -2842,7 +2842,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
res_addr,
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, target_label, target_label2,
NULL)) {
NULL, 0)) {
goto jit_failure;
}
goto done;
@@ -2871,7 +2871,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
RES_REG_ADDR(),
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, target_label, target_label2,
NULL)) {
NULL, 0)) {
goto jit_failure;
}
goto done;
@@ -3962,15 +3962,24 @@ ZEND_EXT_API void zend_jit_unprotect(void)
{
#ifdef HAVE_MPROTECT
if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE) != 0) {
int opts = PROT_READ | PROT_WRITE;
#ifdef ZTS
/* Another thread may be executing JITed code. */
opts |= PROT_EXEC;
#endif
if (mprotect(dasm_buf, dasm_size, opts) != 0) {
fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
}
}
#elif _WIN32
if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
DWORD old;
if (!VirtualProtect(dasm_buf, dasm_size, PAGE_READWRITE, &old)) {
DWORD old, new;
#ifdef ZTS
new = PAGE_EXECUTE_READWRITE;
#else
new = PAGE_READWRITE;
#endif
if (!VirtualProtect(dasm_buf, dasm_size, new, &old)) {
DWORD err = GetLastError();
char *msg = php_win32_error_to_msg(err);
fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
+110 -6
View File
@@ -1625,6 +1625,10 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
break;
}
ADD_OP2_TRACE_GUARD();
if (op1_type != IS_UNKNOWN
&& (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) {
ADD_OP1_TRACE_GUARD();
}
break;
case ZEND_CAST:
if (opline->extended_value != op1_type) {
@@ -3431,6 +3435,89 @@ static void zend_jit_trace_update_condition_ranges(const zend_op *opline, const
}
}
static zend_bool zend_jit_may_skip_comparison(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ssa *ssa, const zend_op **ssa_opcodes)
{
zend_uchar prev_opcode;
if (opline->op1_type == IS_CONST
&& Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_LONG
&& Z_LVAL_P(RT_CONSTANT(opline, opline->op1)) == 0) {
if (ssa_op->op2_use >= 0) {
if ((ssa_op-1)->op1_def == ssa_op->op2_use) {
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
if (prev_opcode == ZEND_PRE_INC
|| prev_opcode == ZEND_PRE_DEC
|| prev_opcode == ZEND_POST_INC
|| prev_opcode == ZEND_POST_DEC) {
return 1;
}
} else if ((ssa_op-1)->result_def == ssa_op->op2_use) {
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
if (prev_opcode == ZEND_ADD
|| prev_opcode == ZEND_SUB) {
return 1;
}
}
}
} else if (opline->op2_type == IS_CONST
&& Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG
&& Z_LVAL_P(RT_CONSTANT(opline, opline->op2)) == 0) {
if (ssa_op->op1_use >= 0) {
if ((ssa_op-1)->op1_def == ssa_op->op1_use) {
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
if (prev_opcode == ZEND_PRE_INC
|| prev_opcode == ZEND_PRE_DEC
|| prev_opcode == ZEND_POST_INC
|| prev_opcode == ZEND_POST_DEC) {
return 1;
}
} else if ((ssa_op-1)->result_def == ssa_op->op1_use) {
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
if (prev_opcode == ZEND_ADD
|| prev_opcode == ZEND_SUB) {
return 1;
}
}
}
} else {
const zend_ssa_op *prev_ssa_op = ssa_op - 1;
prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
if ((prev_opcode == ZEND_JMPZ || prev_opcode == ZEND_JMPNZ)
&& prev_ssa_op != ssa->ops
&& prev_ssa_op->op1_use >= 0
&& prev_ssa_op->op1_use == (prev_ssa_op-1)->result_def) {
prev_ssa_op--;
prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
}
if (ssa_op->op1_use == prev_ssa_op->op1_use
&& ssa_op->op2_use == prev_ssa_op->op2_use) {
if (prev_opcode == ZEND_IS_EQUAL
|| prev_opcode == ZEND_IS_NOT_EQUAL
|| prev_opcode == ZEND_IS_SMALLER
|| prev_opcode == ZEND_IS_SMALLER_OR_EQUAL
|| prev_opcode == ZEND_CASE
|| prev_opcode == ZEND_IS_IDENTICAL
|| prev_opcode == ZEND_IS_NOT_IDENTICAL
|| prev_opcode == ZEND_CASE_STRICT) {
if (ssa_op->op1_use < 0) {
if (opline->op1.constant != ssa_opcodes[prev_ssa_op - ssa->ops]->op1.constant) {
return 0;
}
}
if (ssa_op->op2_use < 0) {
if (opline->op2.constant != ssa_opcodes[prev_ssa_op - ssa->ops]->op2.constant) {
return 0;
}
}
return 1;
}
}
}
return 0;
}
static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
{
const void *handler = NULL;
@@ -3451,6 +3538,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
const void *exit_addr;
uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_data_info;
zend_bool send_result = 0;
zend_bool skip_comparison;
zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
zend_class_entry *ce;
zend_bool ce_is_instanceof;
@@ -4422,6 +4510,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op2_info = OP2_INFO();
CHECK_OP2_TRACE_TYPE();
op1_info = OP1_INFO();
CHECK_OP1_TRACE_TYPE();
op1_def_info = OP1_DEF_INFO();
op1_addr = OP1_REG_ADDR();
op1_def_addr = OP1_DEF_REG_ADDR();
@@ -4675,8 +4764,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
case ZEND_IS_SMALLER_OR_EQUAL:
case ZEND_CASE:
op1_info = OP1_INFO();
CHECK_OP1_TRACE_TYPE();
op2_info = OP2_INFO();
skip_comparison =
ssa_op != ssa->ops &&
(op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes);
CHECK_OP1_TRACE_TYPE();
CHECK_OP2_TRACE_TYPE();
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
zend_bool exit_if_true = 0;
@@ -4697,7 +4791,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
RES_REG_ADDR(),
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, -1, -1, exit_addr)) {
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
goto jit_failure;
}
zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
@@ -4709,7 +4803,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
RES_REG_ADDR(),
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, -1, -1, exit_addr)) {
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
goto jit_failure;
}
}
@@ -4718,8 +4812,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
case ZEND_IS_NOT_IDENTICAL:
case ZEND_CASE_STRICT:
op1_info = OP1_INFO();
CHECK_OP1_TRACE_TYPE();
op2_info = OP2_INFO();
skip_comparison =
ssa_op != ssa->ops &&
(op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes);
CHECK_OP1_TRACE_TYPE();
CHECK_OP2_TRACE_TYPE();
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
zend_bool exit_if_true = 0;
@@ -4743,7 +4842,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
RES_REG_ADDR(),
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, -1, -1, exit_addr)) {
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
goto jit_failure;
}
zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
@@ -4755,7 +4854,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
RES_REG_ADDR(),
zend_may_throw(opline, ssa_op, op_array, ssa),
smart_branch_opcode, -1, -1, exit_addr)) {
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
goto jit_failure;
}
}
@@ -7530,6 +7629,11 @@ static void zend_jit_trace_init_caches(void)
static void zend_jit_trace_reset_caches(void)
{
JIT_G(tracing) = 0;
#ifdef ZTS
if (!JIT_G(exit_counters)) {
JIT_G(exit_counters) = calloc(JIT_G(max_exit_counters), 1);
}
#endif
}
static void zend_jit_trace_restart(void)
+41 -27
View File
@@ -6745,7 +6745,8 @@ static int zend_jit_cmp_long_long(dasm_State **Dst,
zend_uchar smart_branch_opcode,
uint32_t target_label,
uint32_t target_label2,
const void *exit_addr)
const void *exit_addr,
zend_bool skip_comparison)
{
zend_bool swap = 0;
zend_bool result;
@@ -6780,7 +6781,13 @@ static int zend_jit_cmp_long_long(dasm_State **Dst,
return 1;
}
if (Z_MODE(op1_addr) == IS_REG) {
if (skip_comparison) {
if (Z_MODE(op1_addr) != IS_REG &&
(Z_MODE(op2_addr) == IS_REG ||
(Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL))) {
swap = 1;
}
} else if (Z_MODE(op1_addr) == IS_REG) {
if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
| test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr))
} else {
@@ -7567,7 +7574,8 @@ static int zend_jit_cmp(dasm_State **Dst,
zend_uchar smart_branch_opcode,
uint32_t target_label,
uint32_t target_label2,
const void *exit_addr)
const void *exit_addr,
zend_bool skip_comparison)
{
zend_bool same_ops = (opline->op1_type == opline->op2_type) && (opline->op1.var == opline->op2.var);
zend_bool has_slow;
@@ -7603,7 +7611,7 @@ static int zend_jit_cmp(dasm_State **Dst,
| IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
}
}
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) {
return 0;
}
if (op1_info & MAY_BE_DOUBLE) {
@@ -7805,7 +7813,8 @@ static int zend_jit_identical(dasm_State **Dst,
zend_uchar smart_branch_opcode,
uint32_t target_label,
uint32_t target_label2,
const void *exit_addr)
const void *exit_addr,
zend_bool skip_comparison)
{
uint32_t identical_label = (uint32_t)-1;
uint32_t not_identical_label = (uint32_t)-1;
@@ -7838,7 +7847,7 @@ static int zend_jit_identical(dasm_State **Dst,
if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
(op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) {
return 0;
}
return 1;
@@ -8725,7 +8734,7 @@ static int zend_jit_stack_check(dasm_State **Dst, const zend_op *opline, uint32_
return 1;
}
static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, zend_function *func, zend_bool is_closure, zend_bool use_this, zend_bool stack_check)
static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_function *func, zend_bool is_closure, zend_bool use_this, zend_bool stack_check)
{
uint32_t used_stack;
@@ -8798,7 +8807,7 @@ static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, zen
#ifdef _WIN32
if (0) {
#else
if (func && func->type == ZEND_INTERNAL_FUNCTION) {
if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
#endif
| SET_EX_OPLINE opline, r0
| EXT_CALL zend_jit_int_extend_stack_helper, r0
@@ -8830,7 +8839,7 @@ static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, zen
#ifdef _WIN32
if (0) {
#else
if (func && func->type == ZEND_INTERNAL_FUNCTION) {
if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
#endif
| // call->func = func;
|1:
@@ -8838,7 +8847,14 @@ static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, zen
} else {
if (!is_closure) {
| // call->func = func;
| mov aword EX:RX->func, r0
if (func
&& op_array == &func->op_array
&& (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
&& (sizeof(void*) != 8 || IS_SIGNED_32BIT(func))) {
| ADDR_OP2_2 mov, aword EX:RX->func, func, r1
} else {
| mov aword EX:RX->func, r0
}
} else {
| // call->func = &closure->func;
| lea r1, aword [r0 + offsetof(zend_closure, func)]
@@ -9200,8 +9216,11 @@ static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t
#endif
/* load constant address later */
} else if (func && op_array == &func->op_array) {
/* recursive call */
| mov r0, EX->func
/* recursive call */
if (!(func->op_array.fn_flags & ZEND_ACC_IMMUTABLE) ||
(sizeof(void*) == 8 && !IS_SIGNED_32BIT(func))) {
| mov r0, EX->func
}
} else {
| // if (CACHED_PTR(opline->result.num))
| mov r0, EX->run_time_cache
@@ -9289,7 +9308,7 @@ static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t
|3:
}
if (!zend_jit_push_call_frame(Dst, opline, func, 0, 0, stack_check)) {
if (!zend_jit_push_call_frame(Dst, opline, op_array, func, 0, 0, stack_check)) {
return 0;
}
@@ -9534,7 +9553,7 @@ static int zend_jit_init_method_call(dasm_State **Dst,
}
if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
if (!zend_jit_push_call_frame(Dst, opline, func, 0, use_this, stack_check)) {
if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 0, use_this, stack_check)) {
return 0;
}
}
@@ -9633,7 +9652,7 @@ static int zend_jit_init_closure_call(dasm_State **Dst,
}
}
if (!zend_jit_push_call_frame(Dst, opline, func, 1, 0, stack_check)) {
if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 1, 0, stack_check)) {
return 0;
}
@@ -11412,6 +11431,13 @@ static int zend_jit_return(dasm_State **Dst, const zend_op *opline, const zend_o
return_value_used = -1;
}
if (ZEND_OBSERVER_ENABLED) {
| LOAD_ZVAL_ADDR FCARG2a, op1_addr
| mov FCARG1a, FP
| SET_EX_OPLINE opline, r0
| EXT_CALL zend_observer_fcall_end, r0
}
// if (!EX(return_value))
if (Z_MODE(op1_addr) == IS_REG && Z_REG(op1_addr) == ZREG_R1) {
if (return_value_used != 0) {
@@ -11478,12 +11504,6 @@ static int zend_jit_return(dasm_State **Dst, const zend_op *opline, const zend_o
if (return_value_used == 0) {
|9:
if (ZEND_OBSERVER_ENABLED) {
| xor FCARG2a, FCARG2a
| mov FCARG1a, FP
| SET_EX_OPLINE opline, r0
| EXT_CALL zend_observer_fcall_end, r0
}
return 1;
}
@@ -11552,12 +11572,6 @@ static int zend_jit_return(dasm_State **Dst, const zend_op *opline, const zend_o
}
|9:
if (ZEND_OBSERVER_ENABLED) {
| LOAD_ZVAL_ADDR FCARG2a, ret_addr
| mov FCARG1a, FP
| SET_EX_OPLINE opline, r0
| EXT_CALL zend_observer_fcall_end, r0
}
return 1;
}
@@ -70,6 +70,8 @@ CODE;
$serverCode = sprintf($serverCode, $certFile);
$clientCode = <<<'CODE'
phpt_wait();
$cmd = 'openssl s_client -connect 127.0.0.1:64321';
$descriptorSpec = [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]];
$process = proc_open($cmd, $descriptorSpec, $pipes);
+10 -11
View File
@@ -138,23 +138,22 @@ int pdo_stmt_describe_columns(pdo_stmt_t *stmt) /* {{{ */
/* if we are applying case conversions on column names, do so now */
if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
char *s = ZSTR_VAL(stmt->columns[col].name);
zend_string *orig_name = stmt->columns[col].name;
switch (stmt->dbh->desired_case) {
case PDO_CASE_UPPER:
case PDO_CASE_LOWER:
stmt->columns[col].name = zend_string_tolower(orig_name);
zend_string_release(orig_name);
break;
case PDO_CASE_UPPER: {
stmt->columns[col].name = zend_string_separate(orig_name, 0);
char *s = ZSTR_VAL(stmt->columns[col].name);
while (*s != '\0') {
*s = toupper(*s);
s++;
}
break;
case PDO_CASE_LOWER:
while (*s != '\0') {
*s = tolower(*s);
s++;
}
break;
default:
;
}
EMPTY_SWITCH_DEFAULT_CASE()
}
}
+1 -1
View File
@@ -136,7 +136,7 @@ static const char classes_array[] = {
/* 092 \ */ 0,
/* 093 ] */ 0,
/* 094 ^ */ 0,
/* 095 _ */ 65, /* CHR_IDENT | CHR_INTRODUCER */
/* 095 _ */ 68, /* CHR_IDENT | CHR_INTRODUCER */
/* 096 ` */ 0,
/* 097 a */ 37, /* CHR_LETTER | CHR_IDENT | CHR_HEX */
/* 098 b */ 37, /* CHR_LETTER | CHR_IDENT | CHR_HEX */
+21
View File
@@ -0,0 +1,21 @@
--TEST--
Bug #80521 (Parameters with underscores no longer recognized)
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
<?php
require 'testdb.inc';
$dbh->exec("CREATE TABLE bug80521 (foo INTEGER)");
var_dump($dbh->prepare("SELECT foo FROM bug80521 WHERE foo = :foo_bar"));
?>
--EXPECTF--
object(PDOStatement)#%d (1) {
["queryString"]=>
string(45) "SELECT foo FROM bug80521 WHERE foo = :foo_bar"
}
--CLEAN--
<?php
require 'testdb.inc';
$dbh->exec("DROP TABLE bug80521");
?>
+18
View File
@@ -367,6 +367,10 @@ static const char * const pdo_param_event_names[] =
"PDO_PARAM_EVT_NORMALIZE",
};
#ifndef PDO_USE_MYSQLND
static unsigned char libmysql_false_buffer = 0;
static unsigned char libmysql_true_buffer = 1;
#endif
static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type) /* {{{ */
{
@@ -503,6 +507,16 @@ static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_da
*b->length = Z_STRLEN_P(parameter);
PDO_DBG_RETURN(1);
case IS_FALSE:
b->buffer_type = MYSQL_TYPE_TINY;
b->buffer = &libmysql_false_buffer;
PDO_DBG_RETURN(1);
case IS_TRUE:
b->buffer_type = MYSQL_TYPE_TINY;
b->buffer = &libmysql_true_buffer;
PDO_DBG_RETURN(1);
case IS_LONG:
b->buffer_type = MYSQL_TYPE_LONG;
b->buffer = &Z_LVAL_P(parameter);
@@ -619,7 +633,11 @@ static int pdo_mysql_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */
if (S->H->fetch_table_names) {
cols[i].name = strpprintf(0, "%s.%s", S->fields[i].table, S->fields[i].name);
} else {
#ifdef PDO_USE_MYSQLND
cols[i].name = zend_string_copy(S->fields[i].sname);
#else
cols[i].name = zend_string_init(S->fields[i].name, S->fields[i].name_length, 0);
#endif
}
cols[i].precision = S->fields[i].decimals;
@@ -51,8 +51,15 @@ SQL
}
// invalid offset
$tmp = @$stmt->getColumnMeta(-1);
printf(" 1.3 Expecting false got %s\n", var_export($tmp, true));
echo " 1.3 ";
try {
$tmp = $stmt->getColumnMeta(-1);
} catch (ValueError $e) {
if (false !== $tmp) {
printf("[1.3] Expecting false got %s\n", var_export($tmp, true));
}
echo $e->getMessage(), "\n";
}
// PDOStatement::getColumnMeta(): Argument #1 must be of type int, array given in
echo " 1.4 ";
@@ -311,7 +318,7 @@ Preparations before the test
Test 1. calling function with invalid parameters
1.1 Expecting false got false
1.2 PDOStatement::getColumnMeta() expects exactly 1 argument, 0 given
1.3 Expecting false got false
1.3 PDOStatement::getColumnMeta(): Argument #1 ($column) must be greater than or equal to 0
1.4 PDOStatement::getColumnMeta(): Argument #1 ($column) must be of type int, array given
1.5 PDOStatement::getColumnMeta() expects exactly 1 argument, 2 given
1.6 Expecting false because of invalid offset got false
+12 -8
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);
@@ -707,7 +707,6 @@ PHP_METHOD(Phar, webPhar)
efree(pt);
zend_bailout();
return;
default:
zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false");
@@ -718,6 +717,9 @@ cleanup_fail:
}
efree(entry);
efree(pt);
#ifdef PHP_WIN32
efree(fname);
#endif
RETURN_THROWS();
}
}
@@ -791,9 +793,6 @@ cleanup_fail:
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();
}
@@ -847,6 +846,11 @@ cleanup_fail:
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
}
/* }}} */
@@ -4234,7 +4238,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);
+5 -5
View File
@@ -134,10 +134,10 @@ class Phar extends RecursiveDirectoryIterator implements Countable, ArrayAccess
public function setSignatureAlgorithm(int $algo, ?string $privateKey = null) {}
/**
* @param resource $stub
* @param resource|string $stub
* @return bool
*/
public function setStub($stub, int $length = -1) {}
public function setStub($stub, int $length = UNKNOWN) {}
/** @return void */
public function startBuffering() {}
@@ -298,7 +298,7 @@ class PharData extends RecursiveDirectoryIterator implements Countable, ArrayAcc
* @return mixed
* @implementation-alias Phar::getMetadata
*/
public function getMetadata(array $unserialize_options = []) {}
public function getMetadata(array $unserializeOptions = []) {}
/**
* @return bool
@@ -408,11 +408,11 @@ class PharData extends RecursiveDirectoryIterator implements Countable, ArrayAcc
public function setSignatureAlgorithm(int $algo, ?string $privateKey = null) {}
/**
* @param resource $newstub
* @param resource|string $stub
* @return bool
* @implementation-alias Phar::setStub
*/
public function setStub($newstub, int $maxlen = -1) {}
public function setStub($stub, int $length = UNKNOWN) {}
/**
* @return void
+4 -9
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: e06a2ea3d97778e61aca0f91fda7b72c29ef171d */
* Stub hash: 3575a0330ff6102461655bc84add44e8b08b585f */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Phar___construct, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
@@ -139,7 +139,7 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Phar_setStub, 0, 0, 1)
ZEND_ARG_INFO(0, stub)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, length, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Phar_startBuffering arginfo_class_Phar___destruct
@@ -254,9 +254,7 @@ ZEND_END_ARG_INFO()
#define arginfo_class_PharData_getPath arginfo_class_Phar___destruct
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PharData_getMetadata, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, unserialize_options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
#define arginfo_class_PharData_getMetadata arginfo_class_Phar_getMetadata
#define arginfo_class_PharData_getModified arginfo_class_Phar___destruct
@@ -292,10 +290,7 @@ ZEND_END_ARG_INFO()
#define arginfo_class_PharData_setSignatureAlgorithm arginfo_class_Phar_setSignatureAlgorithm
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PharData_setStub, 0, 0, 1)
ZEND_ARG_INFO(0, newstub)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, maxlen, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()
#define arginfo_class_PharData_setStub arginfo_class_Phar_setStub
#define arginfo_class_PharData_startBuffering arginfo_class_Phar___destruct
+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
@@ -12,7 +12,7 @@ $r = new Phar($fname, 0);
}
?>
--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");
?>
+2
View File
@@ -1,5 +1,7 @@
--TEST--
Phar: invalid aliases
--INI--
phar.require_hash=0
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
<?php if (!extension_loaded("zlib")) die("skip no zlib"); ?>
+2
View File
@@ -1,5 +1,7 @@
--TEST--
Phar: process bzip2-compressed zip entry
--INI--
phar.require_hash=0
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?>
Loaded 100 of 204 files, more files were not shown because too many files have changed in this diff. Show more