diff --git a/.github/actions/apt-x64/action.yml b/.github/actions/apt-x64/action.yml index 704388fee8c7c..8f2f608278f07 100644 --- a/.github/actions/apt-x64/action.yml +++ b/.github/actions/apt-x64/action.yml @@ -6,8 +6,21 @@ runs: run: | set -x - sudo apt-get update - sudo apt-get install \ + export DEBIAN_FRONTEND=noninteractive + + # Install sudo in Docker for consistent actions + if ! type "sudo" > /dev/null; then + apt-get update -y | true + apt-get install -y sudo + fi + + sudo apt-get update -y | true + sudo apt-get install -y \ + autoconf \ + gcc \ + make \ + curl \ + unzip \ bison \ re2c \ locales \ @@ -20,6 +33,7 @@ runs: libtidy-dev \ libenchant-2-dev \ libaspell-dev \ + libbz2-dev \ libpspell-dev \ libsasl2-dev \ libxpm-dev \ @@ -60,15 +74,3 @@ runs: libjpeg-dev \ libpng-dev \ libfreetype6-dev - - mkdir /opt/oracle - wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip - unzip instantclient-basiclite-linuxx64.zip && rm instantclient-basiclite-linuxx64.zip - wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-sdk-linuxx64.zip - unzip instantclient-sdk-linuxx64.zip && rm instantclient-sdk-linuxx64.zip - mv instantclient_*_* /opt/oracle/instantclient - # interferes with libldap2 headers - rm /opt/oracle/instantclient/sdk/include/ldap.h - # fix debug build warning: zend_signal: handler was replaced for signal (2) after startup - echo DISABLE_INTERRUPT=on > /opt/oracle/instantclient/network/admin/sqlnet.ora - sudo sh -c 'echo /opt/oracle/instantclient >/etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig' diff --git a/.github/actions/install-linux-x32/action.yml b/.github/actions/install-linux-x32/action.yml index bf5f09cd779d4..4ef87ee03fd3f 100644 --- a/.github/actions/install-linux-x32/action.yml +++ b/.github/actions/install-linux-x32/action.yml @@ -6,7 +6,7 @@ runs: run: | set -x make install - mkdir /etc/php.d + mkdir -p /etc/php.d chmod 777 /etc/php.d echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini diff --git a/.github/actions/install-linux/action.yml b/.github/actions/install-linux/action.yml index d2f7ea23b2ef1..576357b94f1c5 100644 --- a/.github/actions/install-linux/action.yml +++ b/.github/actions/install-linux/action.yml @@ -1,8 +1,4 @@ name: Install -inputs: - withOci: - default: true - required: false runs: using: composite steps: @@ -10,9 +6,7 @@ runs: run: | set -x sudo make install - sudo mkdir /etc/php.d + sudo mkdir -p /etc/php.d sudo chmod 777 /etc/php.d echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini - ${{ inputs.withOci == 'true' && 'echo extension=oci8.so > /etc/php.d/oci8.ini' || '' }} - ${{ inputs.withOci == 'true' && 'echo extension=pdo_oci.so > /etc/php.d/pdo_oci.ini' || '' }} diff --git a/.github/actions/setup-oracle/action.yml b/.github/actions/setup-oracle/action.yml index 11c16fe93d525..1208e93a24893 100644 --- a/.github/actions/setup-oracle/action.yml +++ b/.github/actions/setup-oracle/action.yml @@ -11,3 +11,20 @@ runs: --name oracle \ -h oracle \ -d gvenzl/oracle-xe:slim + + mkdir /opt/oracle + wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip + unzip instantclient-basiclite-linuxx64.zip && rm instantclient-basiclite-linuxx64.zip + wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-sdk-linuxx64.zip + unzip instantclient-sdk-linuxx64.zip && rm instantclient-sdk-linuxx64.zip + mv instantclient_*_* /opt/oracle/instantclient + # interferes with libldap2 headers + rm /opt/oracle/instantclient/sdk/include/ldap.h + # fix debug build warning: zend_signal: handler was replaced for signal (2) after startup + echo DISABLE_INTERRUPT=on > /opt/oracle/instantclient/network/admin/sqlnet.ora + sudo sh -c 'echo /opt/oracle/instantclient >/etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig' + + sudo mkdir -p /etc/php.d + sudo chmod 777 /etc/php.d + echo extension=oci8.so > /etc/php.d/oci8.ini + echo extension=pdo_oci.so > /etc/php.d/pdo_oci.ini diff --git a/.github/actions/setup-x64/action.yml b/.github/actions/setup-x64/action.yml index 91cf7ea51c356..bec213375b7c5 100644 --- a/.github/actions/setup-x64/action.yml +++ b/.github/actions/setup-x64/action.yml @@ -12,6 +12,8 @@ runs: # Ensure local_infile tests can run. mysql -uroot -proot -e "SET GLOBAL local_infile = true" docker exec sql1 /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U SA -P "" -Q "create login pdo_test with password='password', check_policy=off; create user pdo_test for login pdo_test; grant alter, control to pdo_test;" + docker exec sql1 /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U SA -P "" -Q "create login odbc_test with password='password', check_policy=off; create user odbc_test for login odbc_test; grant alter, control, delete to odbc_test;" + docker exec sql1 /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U SA -P "" -Q "ALTER SERVER ROLE sysadmin ADD MEMBER odbc_test;" sudo locale-gen de_DE ./.github/scripts/setup-slapd.sh diff --git a/.github/actions/test-linux/action.yml b/.github/actions/test-linux/action.yml index 9b7d0d100608f..7657ff8c85ad2 100644 --- a/.github/actions/test-linux/action.yml +++ b/.github/actions/test-linux/action.yml @@ -30,6 +30,10 @@ runs: export PDO_OCI_TEST_DSN="oci:dbname=localhost/XEPDB1;charset=AL32UTF8" export PGSQL_TEST_CONNSTR="host=postgres dbname=test port=5432 user=postgres password=postgres" export PDO_PGSQL_TEST_DSN="host=postgres dbname=test port=5432 user=postgres password=postgres" + export ODBC_TEST_USER="odbc_test" + export ODBC_TEST_PASS="password" + export ODBC_TEST_DSN="Driver={ODBC Driver 17 for SQL Server};Server=127.0.0.1;Database=master;uid=$ODBC_TEST_USER;pwd=$ODBC_TEST_PASS" + export PDO_ODBC_TEST_DSN="odbc:$ODBC_TEST_DSN" export SKIP_IO_CAPTURE_TESTS=1 export TEST_PHP_JUNIT=junit.out.xml export STACK_LIMIT_DEFAULTS_CHECK=1 diff --git a/.github/nightly_matrix.php b/.github/nightly_matrix.php index 5c89c0e8986dc..16cc1bb501114 100644 --- a/.github/nightly_matrix.php +++ b/.github/nightly_matrix.php @@ -81,6 +81,25 @@ function get_matrix_include(array $branches) { return $jobs; } +function get_windows_matrix_include(array $branches) { + $jobs = []; + foreach ($branches as $branch) { + $jobs[] = [ + 'branch' => $branch, + 'x64' => true, + 'zts' => true, + 'opcache' => true, + ]; + $jobs[] = [ + 'branch' => $branch, + 'x64' => false, + 'zts' => false, + 'opcache' => false, + ]; + } + return $jobs; +} + $trigger = $argv[1] ?? 'schedule'; $attempt = (int) ($argv[2] ?? 1); $discard_cache = ($trigger === 'schedule' && $attempt !== 1) || $trigger === 'workflow_dispatch'; @@ -90,8 +109,10 @@ function get_matrix_include(array $branches) { $branches = get_branches(); $matrix_include = get_matrix_include($branches); +$windows_matrix_include = get_windows_matrix_include($branches); $f = fopen(getenv('GITHUB_OUTPUT'), 'a'); fwrite($f, 'branches=' . json_encode($branches, JSON_UNESCAPED_SLASHES) . "\n"); fwrite($f, 'matrix-include=' . json_encode($matrix_include, JSON_UNESCAPED_SLASHES) . "\n"); +fwrite($f, 'windows-matrix-include=' . json_encode($windows_matrix_include, JSON_UNESCAPED_SLASHES) . "\n"); fclose($f); diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 34eb6ff9e8e6e..abd0ac01c67aa 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -13,6 +13,7 @@ jobs: outputs: branches: ${{ steps.set-matrix.outputs.branches }} matrix-include: ${{ steps.set-matrix.outputs.matrix-include }} + windows-matrix-include: ${{ steps.set-matrix.outputs.windows-matrix-include }} steps: - uses: actions/checkout@v3 with: @@ -637,7 +638,7 @@ jobs: - name: make install run: | sudo make install - sudo mkdir /etc/php.d + sudo mkdir -p /etc/php.d sudo chmod 777 /etc/php.d echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini @@ -837,17 +838,13 @@ jobs: with: token: ${{ secrets.ACTION_MONITORING_SLACK }} WINDOWS: + needs: GENERATE_MATRIX + if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} strategy: fail-fast: false matrix: - include: - - x64: true - zts: true - opcache: true - - x64: false - zts: false - opcache: false - name: "WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + include: ${{ fromJson(needs.GENERATE_MATRIX.outputs.windows-matrix-include) }} + name: "${{ matrix.branch.name }}_WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" runs-on: windows-2019 env: PHP_BUILD_CACHE_BASE_DIR: C:\build-cache @@ -865,6 +862,8 @@ jobs: run: git config --global core.autocrlf false && git config --global core.eol lf - name: git checkout uses: actions/checkout@v3 + with: + ref: ${{ matrix.branch.ref }} - name: Setup uses: ./.github/actions/setup-windows - name: Build diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 236fb31c28ecf..048492913da39 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -6,7 +6,7 @@ on: - NEWS - UPGRADING - UPGRADING.INTERNALS - - README.md + - '**/README.*' - CONTRIBUTING.md - CODING_STANDARDS.md branches: @@ -21,7 +21,7 @@ on: - NEWS - UPGRADING - UPGRADING.INTERNALS - - README.md + - '**/README.*' - CONTRIBUTING.md - CODING_STANDARDS.md branches: @@ -37,12 +37,21 @@ env: jobs: LINUX_X64: services: + mysql: + image: mysql:8 + env: + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: root postgres: image: postgres env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: test + env: + MYSQL_TEST_HOST: mysql + PDO_MYSQL_TEST_DSN: mysql:host=mysql;dbname=test + PDO_MYSQL_TEST_HOST: mysql strategy: fail-fast: false matrix: @@ -55,17 +64,21 @@ jobs: asan: true name: "LINUX_X64_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}${{ matrix.asan && '_ASAN' || '' }}" runs-on: ubuntu-22.04 + container: + image: ${{ matrix.asan && 'ubuntu:23.04' || null }} steps: - name: git checkout uses: actions/checkout@v3 + - name: apt + uses: ./.github/actions/apt-x64 - name: Create MSSQL container + if: ${{ !matrix.asan }} uses: ./.github/actions/setup-mssql - name: Create Oracle container + if: ${{ !matrix.asan }} uses: ./.github/actions/setup-oracle - name: Setup Caddy server uses: ./.github/actions/setup-caddy - - name: apt - uses: ./.github/actions/apt-x64 - name: ccache uses: hendrikmuhs/ccache-action@v1.2 with: @@ -86,9 +99,8 @@ jobs: run: make -j$(/usr/bin/nproc) >/dev/null - name: make install uses: ./.github/actions/install-linux - with: - withOci: ${{ !matrix.asan }} - name: Setup + if: ${{ !matrix.asan }} uses: ./.github/actions/setup-x64 - name: Test if: matrix.asan == false @@ -105,6 +117,7 @@ jobs: ${{ !matrix.asan && '-d opcache.jit_buffer_size=16M' || '' }} ${{ matrix.asan && '--asan -x' || '' }} - name: Verify generated files are up to date + if: ${{ !matrix.asan }} uses: ./.github/actions/verify-generated-files MACOS_DEBUG_NTS: runs-on: macos-11 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 60a630f5735ff..53ea64bcfc69f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -75,8 +75,8 @@ accompanied by [pull requests](#pull-requests). You can find the extremely large list of RFCs that have been previously considered on the [PHP Wiki](https://wiki.php.net/rfc). -To create a RFC, discuss it with the extension maintainer, and discuss it on the -development mailing list internals@lists.php.net. RFC Wiki accounts can be +To create an RFC, discuss it with the extension maintainer, and discuss it on +the development mailing list internals@lists.php.net. RFC Wiki accounts can be requested on https://wiki.php.net/start?do=register. PHP extension maintainers can be found in the [EXTENSIONS](/EXTENSIONS) file in the PHP source code repository. Mailing list subscription is explained on the @@ -318,7 +318,7 @@ detailed [information on Git](https://git-scm.com/). PHP is developed through the efforts of a large number of people. Collaboration is a Good Thing(tm), and Git lets us do this. Thus, following some basic rules -with regards to Git usage will: +with regard to Git usage will: * Make everybody happier, especially those responsible for maintaining PHP itself. @@ -348,7 +348,7 @@ Having said that, here are the organizational rules: `--enable-zts` switch to ensure your code handles TSRM correctly and doesn't break for those who need that. -Currently we have the following branches in use: +Currently, we have the following branches in use: | Branch | | | --------- | --------- | diff --git a/NEWS b/NEWS index c5f24c90b174d..1fc291a33a4bf 100644 --- a/NEWS +++ b/NEWS @@ -1,13 +1,33 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.3.0beta3 +?? ??? ????, PHP 8.3.0RC1 + +- Core: + . Fixed bug GH-11937 (Constant ASTs containing objects). (ilutov) + +17 Aug 2023, PHP 8.3.0beta3 - Core: . Fixed strerror_r detection at configuration time. (Kévin Dunglas) + . Fixed segfault during freeing of some incompletely initialized objects due + to OOM error (PDO, SPL, XSL). (ilutov) + . Fixed trait typed properties using a DNF type not being correctly bound. + (Girgias) + . Fixed trait property types not being arena allocated if copied from + an internal trait. (Girgias) + . Fixed deep copy of property DNF type during lazy class load. + (Girgias, ilutov) + . Fixed memory freeing of DNF types for non arena allocated types. + (Girgias, ju1ius) - DOM: . adoptNode now respects the strict error checking property. (nielsdos) . Align DOMChildNode parent checks with spec. (nielsdos) + . Fixed bug #80927 (Removing documentElement after creating attribute node: + possible use-after-free). (nielsdos) + . Fix various namespace prefix conflict resolution bugs. (nielsdos) + . Fix calling createAttributeNS() without prefix causing the default + namespace of the element to change. (nielsdos) - Opcache: . Avoid resetting JIT counter handlers from multiple processes/threads. diff --git a/UPGRADING b/UPGRADING index 1aa82831d5240..5696920d96a7a 100644 --- a/UPGRADING +++ b/UPGRADING @@ -53,6 +53,12 @@ PHP 8.3 UPGRADE NOTES . Using the DOMParentNode and DOMChildNode methods without a document now works instead of throwing a HIERARCHY_REQUEST_ERR DOMException. This is in line with the behaviour spec demands. + . createAttributeNS() without specifying a prefix would incorrectly create a default + namespace, placing the element inside the namespace instead of the attribute. + This bug is now fixed. + . createAttributeNS() would previously incorrectly throw a NAMESPACE_ERR when the + prefix was already used for a different uri. It now correctly chooses a + different prefix when there's a prefix name conflict. - FFI: . C functions that have a return type of void now return null instead of @@ -67,6 +73,9 @@ PHP 8.3 UPGRADE NOTES modifiable pointers but was rejected due to complexity. For this reason, it was decided to remove the feature instead. +- Phar: + . The type of Phar class constants are now declared. + - Standard: . The range() function has had various changes: * A TypeError is now thrown when passing objects, resources, or arrays @@ -221,6 +230,10 @@ PHP 8.3 UPGRADE NOTES only paths starting with `..` were disallowed. This could easily be circumvented by prepending `./` to the path. . User exception handlers now catch exceptions during shutdown. + . The resultant HTML of highlight_string and highlight_file has changed. + Whitespace between outer HTML tags is removed. Newlines and spaces + are no longer converted to HTML entities. The whole HTML is now wrapped in +
 tag. The outer  has been merged with .
 
 - Calendar
   . easter_date() now supports years from 1970 to 2,000,000,000 on 64-bit systems,
@@ -248,7 +261,7 @@ PHP 8.3 UPGRADE NOTES
     now returns true on success, previously null was returned.
   . IntlBreakiterator::setText() now returns false on failure, previously
     null was returned.
-    now returns true on sucess, previously null was returned.
+    now returns true on success, previously null was returned.
   . IntlChar::enumCharNames is now returning a boolean.
     Previously it returned null on success and false on failure.
 
@@ -285,6 +298,8 @@ PHP 8.3 UPGRADE NOTES
     constructor.
   . mysqli_poll now raises a ValueError when the read nor error arguments are
     passed.
+  . mysqli_field_seek and mysqli_result::field_seek now specify return type
+    as true instead of bool.
 
 - ODBC
   . odbc_autocommit() now accepts null for the $enable parameter.
@@ -437,7 +452,7 @@ PHP 8.3 UPGRADE NOTES
     A warning is emitted when trying to decrement values of type null, as
     this will change in the next major version.
     Internal objects that implement an _IS_NUMBER cast but not a do_operator
-    handler that overrides addition and substraction now can be incremented
+    handler that overrides addition and subtraction now can be incremented
     and decrement as if one would do $o += 1 or $o -= 1
 
 - DOM:
@@ -482,6 +497,9 @@ PHP 8.3 UPGRADE NOTES
 - PCNTL:
   . SIGINFO
 
+- PDO_ODBC
+  . PDO_ODBC_TYPE
+
 - PGSQL:
   . PGSQL_TRACE_SUPPRESS_TIMESTAMPS
   . PGSQL_TRACE_REGRESS_MODE
diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index 1a8c5970c7f01..f35d54846f25d 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -148,6 +148,8 @@ PHP 8.3 INTERNALS UPGRADE NOTES
      dom_parent_node_before() now use an uint32_t argument for the number of nodes instead of int.
    - There is now a helper function php_dom_get_content_into_zval() to get the contents of a node.
      This avoids allocation if possible.
+   - The function dom_set_old_ns() has been moved into ext/libxml as php_libxml_set_old_ns() and
+     is now publicly exposed as an API.
 
  g. ext/libxml
    - Two new functions: php_libxml_invalidate_node_list_cache_from_doc() and
diff --git a/Zend/Makefile.frag b/Zend/Makefile.frag
index 054a63bf60af5..9d7f1c55aade4 100644
--- a/Zend/Makefile.frag
+++ b/Zend/Makefile.frag
@@ -20,10 +20,6 @@ $(srcdir)/zend_language_parser.c: $(srcdir)/zend_language_parser.y
 	@$(SED) -e 's,^int zendparse\(.*\),ZEND_API int zendparse\1,g' < $(srcdir)/zend_language_parser.h \
 	> $(srcdir)/zend_language_parser.h.tmp && \
 	mv $(srcdir)/zend_language_parser.h.tmp $(srcdir)/zend_language_parser.h
-	@nlinit=`echo 'nl="'; echo '"'`; eval "$$nlinit"; \
-	$(SED) -e "s/^#ifndef YYTOKENTYPE/#include \"zend.h\"\\$${nl}#ifndef YYTOKENTYPE/" < $(srcdir)/zend_language_parser.h \
-	> $(srcdir)/zend_language_parser.h.tmp && \
-	mv $(srcdir)/zend_language_parser.h.tmp $(srcdir)/zend_language_parser.h
 
 $(srcdir)/zend_ini_parser.h: $(srcdir)/zend_ini_parser.c
 $(srcdir)/zend_ini_parser.c: $(srcdir)/zend_ini_parser.y
diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h
index 6dc947e3cc839..30a63a9d06869 100644
--- a/Zend/Optimizer/zend_func_infos.h
+++ b/Zend/Optimizer/zend_func_infos.h
@@ -316,31 +316,6 @@ static const func_info_t func_infos[] = {
 	FN("oci_get_implicit_resultset", MAY_BE_RESOURCE|MAY_BE_FALSE),
 	FN("oci_password_change", MAY_BE_RESOURCE|MAY_BE_BOOL),
 	FN("oci_new_cursor", MAY_BE_RESOURCE|MAY_BE_FALSE),
-	FN("odbc_prepare", MAY_BE_RESOURCE|MAY_BE_FALSE),
-	FN("odbc_exec", MAY_BE_RESOURCE|MAY_BE_FALSE),
-	FN("odbc_connect", MAY_BE_RESOURCE|MAY_BE_FALSE),
-	FN("odbc_pconnect", MAY_BE_RESOURCE|MAY_BE_FALSE),
-	FN("odbc_tables", MAY_BE_RESOURCE|MAY_BE_FALSE),
-	FN("odbc_columns", MAY_BE_RESOURCE|MAY_BE_FALSE),
-	FN("odbc_gettypeinfo", MAY_BE_RESOURCE|MAY_BE_FALSE),
-	FN("odbc_primarykeys", MAY_BE_RESOURCE|MAY_BE_FALSE),
-#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
-	FN("odbc_procedurecolumns", MAY_BE_RESOURCE|MAY_BE_FALSE),
-#endif
-#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
-	FN("odbc_procedures", MAY_BE_RESOURCE|MAY_BE_FALSE),
-#endif
-#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35)
-	FN("odbc_foreignkeys", MAY_BE_RESOURCE|MAY_BE_FALSE),
-#endif
-	FN("odbc_specialcolumns", MAY_BE_RESOURCE|MAY_BE_FALSE),
-	FN("odbc_statistics", MAY_BE_RESOURCE|MAY_BE_FALSE),
-#if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35)
-	FN("odbc_tableprivileges", MAY_BE_RESOURCE|MAY_BE_FALSE),
-#endif
-#if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35)
-	FN("odbc_columnprivileges", MAY_BE_RESOURCE|MAY_BE_FALSE),
-#endif
 	F1("opcache_get_status", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_FALSE),
 	F1("opcache_get_configuration", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_FALSE),
 	F1("openssl_x509_parse", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_FALSE),
diff --git a/Zend/tests/bug35655.phpt b/Zend/tests/bug35655.phpt
index 47e7a7bd7e2e8..2caa3e372e7d2 100644
--- a/Zend/tests/bug35655.phpt
+++ b/Zend/tests/bug35655.phpt
@@ -19,7 +19,10 @@ EOT
 highlight_string($code);
 ?>
 --EXPECT--
-
-
<?php
  $x 
= <<<EOT
some string    
EOT
  
$y 2;
?> -
-
+

+<?php
+  $x = <<<EOT
+some string    
+EOT
+  $y = 2;
+?>
diff --git a/Zend/tests/bug42767.phpt b/Zend/tests/bug42767.phpt index b57177e4b5e58..0f0c3a4961722 100644 --- a/Zend/tests/bug42767.phpt +++ b/Zend/tests/bug42767.phpt @@ -11,7 +11,4 @@ highlight.html = #000000 highlight_string(' --EXPECT-- - -<?php /*some comment.. - - +
<?php /*some comment..
diff --git a/Zend/tests/bug71086.phpt b/Zend/tests/bug71086.phpt index 3e64f9c13a518..8e0b7befe8f07 100644 --- a/Zend/tests/bug71086.phpt +++ b/Zend/tests/bug71086.phpt @@ -8,7 +8,5 @@ var_dump($highlightedString); ?> --EXPECT-- -string(169) " -<?php 
 09 09 09
; -
-
" +string(139) "
<?php 
+ 09 09 09;
" diff --git a/Zend/tests/new_oom.inc b/Zend/tests/new_oom.inc new file mode 100644 index 0000000000000..fa62764310a94 --- /dev/null +++ b/Zend/tests/new_oom.inc @@ -0,0 +1,15 @@ +newInstanceWithoutConstructor(); + } +} catch (Throwable) { +} diff --git a/Zend/tests/new_oom.phpt b/Zend/tests/new_oom.phpt new file mode 100644 index 0000000000000..1e9b0593e6bea --- /dev/null +++ b/Zend/tests/new_oom.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test OOM on new of each class +--SKIPIF-- + +--FILE-- +&1"); + if ($output && preg_match('(^\nFatal error: Allowed memory size of [0-9]+ bytes exhausted[^\r\n]* \(tried to allocate [0-9]+ bytes\) in [^\r\n]+ on line [0-9]+$)', $output) !== 1) { + echo "Class $class failed\n"; + echo $output, "\n"; + } +} + +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/tests/nowdoc_013.phpt b/Zend/tests/nowdoc_013.phpt index 61543f74e3b16..e2b9c98015eee 100644 --- a/Zend/tests/nowdoc_013.phpt +++ b/Zend/tests/nowdoc_013.phpt @@ -20,7 +20,9 @@ EOF; highlight_string($code); ?> --EXPECT-- - -<?php
  $x 
= <<<'EOT'
some string    
EOT
  
$y 2;
?> -
-
+
<?php
+  $x = <<<'EOT'
+some string    
+EOT
+  $y = 2;
+?>
diff --git a/Zend/tests/nowdoc_014.phpt b/Zend/tests/nowdoc_014.phpt index 694490b17d584..b4cd3ac07fca6 100644 --- a/Zend/tests/nowdoc_014.phpt +++ b/Zend/tests/nowdoc_014.phpt @@ -18,7 +18,8 @@ EOF; highlight_string($code); ?> --EXPECT-- - -<?php
  $x 
= <<<'EOT'
EOT
  
$y 2;
?> -
-
+
<?php
+  $x = <<<'EOT'
+EOT
+  $y = 2;
+?>
diff --git a/Zend/tests/type_declarations/dnf_types/variance/invalid_invariance1_var.phpt b/Zend/tests/type_declarations/dnf_types/variance/invalid_invariance1_var.phpt new file mode 100644 index 0000000000000..1a8a31f066ed6 --- /dev/null +++ b/Zend/tests/type_declarations/dnf_types/variance/invalid_invariance1_var.phpt @@ -0,0 +1,18 @@ +--TEST-- +Property types must be invariant +--FILE-- + +--EXPECTF-- +Fatal error: Type of B::$prop must be (X&Y&Z)|L (as in class A) in %s on line %d diff --git a/Zend/tests/type_declarations/typed_properties_095.phpt b/Zend/tests/type_declarations/typed_properties_095.phpt index 5caf862e72da7..321b07e34c73f 100644 --- a/Zend/tests/type_declarations/typed_properties_095.phpt +++ b/Zend/tests/type_declarations/typed_properties_095.phpt @@ -75,6 +75,8 @@ object(_ZendTestClass)#1 (3) { uninitialized(Traversable&Countable) ["readonlyProp"]=> uninitialized(int) + ["dnfProperty"]=> + uninitialized(Iterator|(Traversable&Countable)) } int(123) Cannot assign string to property _ZendTestClass::$intProp of type int @@ -91,6 +93,8 @@ object(Test)#4 (3) { uninitialized(Traversable&Countable) ["readonlyProp"]=> uninitialized(int) + ["dnfProperty"]=> + uninitialized(Iterator|(Traversable&Countable)) } int(123) Cannot assign string to property _ZendTestClass::$staticIntProp of type int diff --git a/Zend/tests/type_declarations/union_types/internal_trait_use_typed_union.phpt b/Zend/tests/type_declarations/union_types/internal_trait_use_typed_union.phpt new file mode 100644 index 0000000000000..62bbefc8f5a0b --- /dev/null +++ b/Zend/tests/type_declarations/union_types/internal_trait_use_typed_union.phpt @@ -0,0 +1,39 @@ +--TEST-- +Internal trait used typed property (union type) +--EXTENSIONS-- +zend_test +--FILE-- +getType(); +$types = $union->getTypes(); +var_dump($types, (string)$types[0], (string)$types[1]); + +?> +===DONE=== +--EXPECT-- +object(C)#1 (1) { + ["testProp"]=> + NULL + ["classUnionProp"]=> + uninitialized(Traversable|Countable) +} +array(2) { + [0]=> + object(ReflectionNamedType)#4 (0) { + } + [1]=> + object(ReflectionNamedType)#5 (0) { + } +} +string(11) "Traversable" +string(9) "Countable" +===DONE=== diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 34ab803321aae..d0b863335e291 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2756,6 +2756,28 @@ ZEND_API void zend_add_magic_method(zend_class_entry *ce, zend_function *fptr, z ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arg_info_toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() +static zend_always_inline void zend_normalize_internal_type(zend_type *type) { + ZEND_ASSERT(!ZEND_TYPE_HAS_LITERAL_NAME(*type)); + zend_type *current; + ZEND_TYPE_FOREACH(*type, current) { + if (ZEND_TYPE_HAS_NAME(*current)) { + zend_string *name = zend_new_interned_string(ZEND_TYPE_NAME(*current)); + zend_alloc_ce_cache(name); + ZEND_TYPE_SET_PTR(*current, name); + } else if (ZEND_TYPE_HAS_LIST(*current)) { + zend_type *inner; + ZEND_TYPE_FOREACH(*current, inner) { + ZEND_ASSERT(!ZEND_TYPE_HAS_LITERAL_NAME(*inner) && !ZEND_TYPE_HAS_LIST(*inner)); + if (ZEND_TYPE_HAS_NAME(*inner)) { + zend_string *name = zend_new_interned_string(ZEND_TYPE_NAME(*inner)); + zend_alloc_ce_cache(name); + ZEND_TYPE_SET_PTR(*inner, name); + } + } ZEND_TYPE_FOREACH_END(); + } + } ZEND_TYPE_FOREACH_END(); +} + /* registers all functions in *library_functions in the function hash */ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type) /* {{{ */ { @@ -2934,10 +2956,12 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend memcpy(new_arg_info, arg_info, sizeof(zend_internal_arg_info) * num_args); reg_function->arg_info = new_arg_info + 1; for (i = 0; i < num_args; i++) { - if (ZEND_TYPE_IS_COMPLEX(new_arg_info[i].type)) { - ZEND_ASSERT(ZEND_TYPE_HAS_NAME(new_arg_info[i].type) - && "Should be stored as simple name"); + if (ZEND_TYPE_HAS_LITERAL_NAME(new_arg_info[i].type)) { + // gen_stubs.php does not support codegen for DNF types in arg infos. + // As a temporary workaround, we split the type name on `|` characters, + // converting it to an union type if necessary. const char *class_name = ZEND_TYPE_LITERAL_NAME(new_arg_info[i].type); + new_arg_info[i].type.type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT; size_t num_types = 1; const char *p = class_name; @@ -2948,8 +2972,10 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend 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)); + zend_string *str = zend_string_init_interned(class_name, strlen(class_name), 1); + zend_alloc_ce_cache(str); + ZEND_TYPE_SET_PTR(new_arg_info[i].type, str); + new_arg_info[i].type.type_mask |= _ZEND_TYPE_NAME_BIT; } else { /* Union type */ zend_type_list *list = malloc(ZEND_TYPE_LIST_SIZE(num_types)); @@ -2961,8 +2987,8 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend uint32_t j = 0; while (true) { const char *end = strchr(start, '|'); - zend_string *str = zend_string_init_interned( - start, end ? end - start : strlen(start), 1); + zend_string *str = zend_string_init_interned(start, end ? end - start : strlen(start), 1); + zend_alloc_ce_cache(str); list->types[j] = (zend_type) ZEND_TYPE_INIT_CLASS(str, 0, 0); if (!end) { break; @@ -2977,10 +3003,14 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend zend_error(E_CORE_WARNING, "iterable type is now a compile time alias for array|Traversable," " regenerate the argument info via the php-src gen_stub build script"); */ - zend_type legacy_iterable = ZEND_TYPE_INIT_CLASS_CONST_MASK(ZSTR_KNOWN(ZEND_STR_TRAVERSABLE), - (new_arg_info[i].type.type_mask|MAY_BE_ARRAY)); + zend_type legacy_iterable = ZEND_TYPE_INIT_CLASS_MASK( + ZSTR_KNOWN(ZEND_STR_TRAVERSABLE), + (new_arg_info[i].type.type_mask | MAY_BE_ARRAY) + ); new_arg_info[i].type = legacy_iterable; } + + zend_normalize_internal_type(&new_arg_info[i].type); } } @@ -4367,16 +4397,7 @@ ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, z property_info->type = type; if (is_persistent_class(ce)) { - zend_type *single_type; - ZEND_TYPE_FOREACH(property_info->type, single_type) { - // TODO Add support and test cases when gen_stub support added - ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*single_type)); - if (ZEND_TYPE_HAS_NAME(*single_type)) { - zend_string *name = zend_new_interned_string(ZEND_TYPE_NAME(*single_type)); - ZEND_TYPE_SET_PTR(*single_type, name); - zend_alloc_ce_cache(name); - } - } ZEND_TYPE_FOREACH_END(); + zend_normalize_internal_type(&property_info->type); } zend_hash_update_ptr(&ce->properties_info, name, property_info); diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 0bbb3a820c291..4c1a87e288a73 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -313,7 +313,7 @@ typedef void (*zend_ast_apply_func)(zend_ast **ast_ptr, void *context); ZEND_API void zend_ast_apply(zend_ast *ast, zend_ast_apply_func fn, void *context); static zend_always_inline size_t zend_ast_size(uint32_t children) { - return sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children; + return XtOffsetOf(zend_ast, child) + (sizeof(zend_ast *) * children); } static zend_always_inline bool zend_ast_is_special(zend_ast *ast) { diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 5dff47798b01a..8d56da9eac6d1 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1499,14 +1499,6 @@ ZEND_API zend_string *zend_mangle_property_name(const char *src1, size_t src1_le } /* }}} */ -static zend_always_inline size_t zend_strnlen(const char* s, size_t maxlen) /* {{{ */ -{ - size_t len = 0; - while (*s++ && maxlen--) len++; - return len; -} -/* }}} */ - ZEND_API zend_result zend_unmangle_property_name_ex(const zend_string *name, const char **class_name, const char **prop_name, size_t *prop_len) /* {{{ */ { size_t class_name_len; @@ -1553,6 +1545,35 @@ ZEND_API zend_result zend_unmangle_property_name_ex(const zend_string *name, con } /* }}} */ +static bool array_is_const_ex(zend_array *array, uint32_t *max_checks) +{ + if (zend_hash_num_elements(array) > *max_checks) { + return false; + } + *max_checks -= zend_hash_num_elements(array); + + zval *element; + ZEND_HASH_FOREACH_VAL(array, element) { + if (Z_TYPE_P(element) < IS_ARRAY) { + continue; + } else if (Z_TYPE_P(element) == IS_ARRAY) { + if (!array_is_const_ex(array, max_checks)) { + return false; + } + } else { + return false; + } + } ZEND_HASH_FOREACH_END(); + + return true; +} + +static bool array_is_const(zend_array *array) +{ + uint32_t max_checks = 50; + return array_is_const_ex(array, &max_checks); +} + static bool can_ct_eval_const(zend_constant *c) { if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) { return 0; @@ -1563,9 +1584,13 @@ static bool can_ct_eval_const(zend_constant *c) { && (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) { return 1; } - if (Z_TYPE(c->value) < IS_OBJECT + if (Z_TYPE(c->value) < IS_ARRAY && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) { return 1; + } else if (Z_TYPE(c->value) == IS_ARRAY + && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION) + && array_is_const(Z_ARR(c->value))) { + return 1; } return 0; } @@ -1792,7 +1817,10 @@ static bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend c = &cc->value; /* Substitute case-sensitive (or lowercase) persistent class constants */ - if (Z_TYPE_P(c) < IS_OBJECT) { + if (Z_TYPE_P(c) < IS_ARRAY) { + ZVAL_COPY_OR_DUP(zv, c); + return 1; + } else if (Z_TYPE_P(c) == IS_ARRAY && array_is_const(Z_ARR_P(c))) { ZVAL_COPY_OR_DUP(zv, c); return 1; } @@ -6402,7 +6430,7 @@ static zend_type zend_compile_single_typename(zend_ast *ast) /* Transform iterable into a type union alias */ if (type_code == IS_ITERABLE) { /* Set iterable bit for BC compat during Reflection and string representation of type */ - zend_type iterable = (zend_type) ZEND_TYPE_INIT_CLASS_CONST_MASK(ZSTR_KNOWN(ZEND_STR_TRAVERSABLE), + zend_type iterable = (zend_type) ZEND_TYPE_INIT_CLASS_MASK(ZSTR_KNOWN(ZEND_STR_TRAVERSABLE), (MAY_BE_ARRAY|_ZEND_TYPE_ITERABLE_BIT)); return iterable; } diff --git a/Zend/zend_highlight.c b/Zend/zend_highlight.c index 501eed5757133..167ee27192ed4 100644 --- a/Zend/zend_highlight.c +++ b/Zend/zend_highlight.c @@ -28,9 +28,6 @@ ZEND_API void zend_html_putc(char c) { switch (c) { - case '\n': - ZEND_PUTS("
"); - break; case '<': ZEND_PUTS("<"); break; @@ -40,11 +37,8 @@ ZEND_API void zend_html_putc(char c) case '&': ZEND_PUTS("&"); break; - case ' ': - ZEND_PUTS(" "); - break; case '\t': - ZEND_PUTS("    "); + ZEND_PUTS(" "); break; default: ZEND_PUTC(c); @@ -88,8 +82,7 @@ ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini char *last_color = syntax_highlighter_ini->highlight_html; char *next_color; - zend_printf(""); - zend_printf("\n", last_color); + zend_printf("
", last_color);
 	/* highlight stuff coming back from zendlex() */
 	while ((token_type=lex_scan(&token, NULL))) {
 		switch (token_type) {
@@ -162,10 +155,9 @@ ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini
 	}
 
 	if (last_color != syntax_highlighter_ini->highlight_html) {
-		zend_printf("\n");
+		zend_printf("");
 	}
-	zend_printf("\n");
-	zend_printf("");
+	zend_printf("
"); /* Discard parse errors thrown during tokenization */ zend_clear_exception(); diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 6bae341727a79..bea9912564ec3 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -60,20 +60,33 @@ static void ZEND_COLD emit_incompatible_method_error( const zend_function *parent, zend_class_entry *parent_scope, inheritance_status status); -static void zend_type_copy_ctor(zend_type *type, bool persistent) { +static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent); + +static void zend_type_list_copy_ctor( + zend_type *const parent_type, + bool use_arena, + bool persistent +) { + const zend_type_list *const old_list = ZEND_TYPE_LIST(*parent_type); + size_t size = ZEND_TYPE_LIST_SIZE(old_list->num_types); + zend_type_list *new_list = use_arena + ? zend_arena_alloc(&CG(arena), size) : pemalloc(size, persistent); + + memcpy(new_list, old_list, size); + ZEND_TYPE_SET_LIST(*parent_type, new_list); + if (use_arena) { + ZEND_TYPE_FULL_MASK(*parent_type) |= _ZEND_TYPE_ARENA_BIT; + } + + zend_type *list_type; + ZEND_TYPE_LIST_FOREACH(new_list, list_type) { + zend_type_copy_ctor(list_type, use_arena, persistent); + } ZEND_TYPE_LIST_FOREACH_END(); +} + +static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent) { if (ZEND_TYPE_HAS_LIST(*type)) { - zend_type_list *old_list = ZEND_TYPE_LIST(*type); - size_t size = ZEND_TYPE_LIST_SIZE(old_list->num_types); - zend_type_list *new_list = ZEND_TYPE_USES_ARENA(*type) - ? zend_arena_alloc(&CG(arena), size) : pemalloc(size, persistent); - memcpy(new_list, old_list, ZEND_TYPE_LIST_SIZE(old_list->num_types)); - ZEND_TYPE_SET_PTR(*type, new_list); - - zend_type *list_type; - ZEND_TYPE_LIST_FOREACH(new_list, list_type) { - ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type)); - zend_string_addref(ZEND_TYPE_NAME(*list_type)); - } ZEND_TYPE_LIST_FOREACH_END(); + zend_type_list_copy_ctor(type, use_arena, persistent); } else if (ZEND_TYPE_HAS_NAME(*type)) { zend_string_addref(ZEND_TYPE_NAME(*type)); } @@ -2506,7 +2519,8 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL; zend_type type = property_info->type; - zend_type_copy_ctor(&type, /* persistent */ 0); + /* Assumption: only userland classes can use traits, as such the type must be arena allocated */ + zend_type_copy_ctor(&type, /* use arena */ true, /* persistent */ false); new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type); if (property_info->attributes) { @@ -2920,15 +2934,8 @@ static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce) Z_PTR(p->val) = new_prop_info; memcpy(new_prop_info, prop_info, sizeof(zend_property_info)); new_prop_info->ce = ce; - if (ZEND_TYPE_HAS_LIST(new_prop_info->type)) { - zend_type_list *new_list; - zend_type_list *list = ZEND_TYPE_LIST(new_prop_info->type); - - new_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(list->num_types)); - memcpy(new_list, list, ZEND_TYPE_LIST_SIZE(list->num_types)); - ZEND_TYPE_SET_PTR(new_prop_info->type, list); - ZEND_TYPE_FULL_MASK(new_prop_info->type) |= _ZEND_TYPE_ARENA_BIT; - } + /* Deep copy the type information */ + zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false); } } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index dc968bc395303..0aecde93c95cc 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -110,17 +110,9 @@ ZEND_API void destroy_zend_function(zend_function *function) ZEND_API void zend_type_release(zend_type type, bool persistent) { if (ZEND_TYPE_HAS_LIST(type)) { - zend_type *list_type, *sublist_type; + zend_type *list_type; ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) { - if (ZEND_TYPE_HAS_LIST(*list_type)) { - ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*list_type), sublist_type) { - if (ZEND_TYPE_HAS_NAME(*sublist_type)) { - zend_string_release(ZEND_TYPE_NAME(*sublist_type)); - } - } ZEND_TYPE_LIST_FOREACH_END(); - } else if (ZEND_TYPE_HAS_NAME(*list_type)) { - zend_string_release(ZEND_TYPE_NAME(*list_type)); - } + zend_type_release(*list_type, persistent); } ZEND_TYPE_LIST_FOREACH_END(); if (!ZEND_TYPE_USES_ARENA(type)) { pefree(ZEND_TYPE_LIST(type), persistent); diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 4b47debc8032d..2c2d8ed7aa7fb 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -264,6 +264,16 @@ zend_memnrstr(const char *haystack, const char *needle, size_t needle_len, const } } +static zend_always_inline size_t zend_strnlen(const char* s, size_t maxlen) +{ +#if defined(HAVE_STRNLEN) + return strnlen(s, maxlen); +#else + const char *p = memchr(s, '\0', maxlen); + return p ? p-s : maxlen; +#endif +} + ZEND_API zend_result ZEND_FASTCALL increment_function(zval *op1); ZEND_API zend_result ZEND_FASTCALL decrement_function(zval *op2); diff --git a/Zend/zend_types.h b/Zend/zend_types.h index df9bff9015eac..bf4fd9d18a41a 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -115,6 +115,7 @@ typedef void (*copy_ctor_func_t)(zval *pElement); * ZEND_TYPE_IS_ONLY_MASK() - checks if type-hint refer to standard type only * ZEND_TYPE_IS_COMPLEX() - checks if type is a type_list, or contains a class either as a CE or as a name * ZEND_TYPE_HAS_NAME() - checks if type-hint contains some class as zend_string * + * ZEND_TYPE_HAS_LITERAL_NAME() - checks if type-hint contains some class as const char * * ZEND_TYPE_IS_INTERSECTION() - checks if the type_list represents an intersection type list * ZEND_TYPE_IS_UNION() - checks if the type_list represents a union type list * @@ -145,8 +146,10 @@ typedef struct { #define _ZEND_TYPE_MASK ((1u << 25) - 1) /* Only one of these bits may be set. */ #define _ZEND_TYPE_NAME_BIT (1u << 24) +// Used to signify that type.ptr is not a `zend_string*` but a `const char*`, +#define _ZEND_TYPE_LITERAL_NAME_BIT (1u << 23) #define _ZEND_TYPE_LIST_BIT (1u << 22) -#define _ZEND_TYPE_KIND_MASK (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_NAME_BIT) +#define _ZEND_TYPE_KIND_MASK (_ZEND_TYPE_LIST_BIT|_ZEND_TYPE_NAME_BIT|_ZEND_TYPE_LITERAL_NAME_BIT) /* For BC behaviour with iterable type */ #define _ZEND_TYPE_ITERABLE_BIT (1u << 21) /* Whether the type list is arena allocated */ @@ -171,6 +174,9 @@ typedef struct { #define ZEND_TYPE_HAS_NAME(t) \ ((((t).type_mask) & _ZEND_TYPE_NAME_BIT) != 0) +#define ZEND_TYPE_HAS_LITERAL_NAME(t) \ + ((((t).type_mask) & _ZEND_TYPE_LITERAL_NAME_BIT) != 0) + #define ZEND_TYPE_HAS_LIST(t) \ ((((t).type_mask) & _ZEND_TYPE_LIST_BIT) != 0) @@ -289,11 +295,14 @@ typedef struct { #define ZEND_TYPE_INIT_CLASS(class_name, allow_null, extra_flags) \ ZEND_TYPE_INIT_PTR(class_name, _ZEND_TYPE_NAME_BIT, allow_null, extra_flags) +#define ZEND_TYPE_INIT_CLASS_MASK(class_name, type_mask) \ + ZEND_TYPE_INIT_PTR_MASK(class_name, _ZEND_TYPE_NAME_BIT | (type_mask)) + #define ZEND_TYPE_INIT_CLASS_CONST(class_name, allow_null, extra_flags) \ - ZEND_TYPE_INIT_PTR(class_name, _ZEND_TYPE_NAME_BIT, allow_null, extra_flags) + ZEND_TYPE_INIT_PTR(class_name, _ZEND_TYPE_LITERAL_NAME_BIT, allow_null, extra_flags) #define ZEND_TYPE_INIT_CLASS_CONST_MASK(class_name, type_mask) \ - ZEND_TYPE_INIT_PTR_MASK(class_name, _ZEND_TYPE_NAME_BIT | (type_mask)) + ZEND_TYPE_INIT_PTR_MASK(class_name, (_ZEND_TYPE_LITERAL_NAME_BIT | (type_mask))) typedef union _zend_value { zend_long lval; /* long value */ diff --git a/build/gen_stub.php b/build/gen_stub.php index 1fff123d84c0d..0ab8ca26adfb8 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -272,7 +272,7 @@ public static function fromString(string $typeString): SimpleType } $matches = []; - $isArray = preg_match("/array\s*<\s*([A-Za-z0-9_-|]+)?(\s*,\s*)?([A-Za-z0-9_-|]+)?\s*>/i", $typeString, $matches); + $isArray = preg_match("/array\s*<\s*([A-Za-z0-9_|-]+)?(\s*,\s*)?([A-Za-z0-9_|-]+)?\s*>/i", $typeString, $matches); if ($isArray) { if (empty($matches[1]) || empty($matches[3])) { throw new Exception("array<> type hint must have both a key and a value"); diff --git a/ext/bcmath/libbcmath/src/add.c b/ext/bcmath/libbcmath/src/add.c index a57ed32afaee1..1e6285a0df19a 100644 --- a/ext/bcmath/libbcmath/src/add.c +++ b/ext/bcmath/libbcmath/src/add.c @@ -39,34 +39,30 @@ N1 is added to N2 and the result placed into RESULT. SCALE_MIN is the minimum scale for the result. */ -void bc_add (bc_num n1, bc_num n2, bc_num *result, size_t scale_min) +void bc_add(bc_num n1, bc_num n2, bc_num *result, size_t scale_min) { bc_num sum = NULL; - int cmp_res; - size_t res_scale; if (n1->n_sign == n2->n_sign) { - sum = _bc_do_add (n1, n2, scale_min); + sum = _bc_do_add(n1, n2, scale_min); sum->n_sign = n1->n_sign; } else { /* subtraction must be done. */ /* Compare magnitudes. */ - cmp_res = _bc_do_compare(n1, n2, false, false); - switch (cmp_res) { + switch (_bc_do_compare(n1, n2, false, false)) { case -1: /* n1 is less than n2, subtract n1 from n2. */ - sum = _bc_do_sub (n2, n1, scale_min); + sum = _bc_do_sub(n2, n1, scale_min); sum->n_sign = n2->n_sign; break; - case 0: + case 0: /* They are equal! return zero with the correct scale! */ - res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale)); - sum = bc_new_num (1, res_scale); - memset (sum->n_value, 0, res_scale+1); + sum = bc_new_num (1, MAX(scale_min, MAX(n1->n_scale, n2->n_scale))); + memset(sum->n_value, 0, sum->n_scale + 1); break; - case 1: + case 1: /* n2 is less than n1, subtract n2 from n1. */ - sum = _bc_do_sub (n1, n2, scale_min); + sum = _bc_do_sub(n1, n2, scale_min); sum->n_sign = n1->n_sign; } } diff --git a/ext/bcmath/libbcmath/src/bcmath.h b/ext/bcmath/libbcmath/src/bcmath.h index 38ad86b34c718..de51ee7457110 100644 --- a/ext/bcmath/libbcmath/src/bcmath.h +++ b/ext/bcmath/libbcmath/src/bcmath.h @@ -61,7 +61,7 @@ typedef struct bc_struct { #include "../../php_bcmath.h" /* Needed for BCG() macro */ /* The base used in storing the numbers in n_value above. - Currently this MUST be 10. */ + Currently, this MUST be 10. */ #define BASE 10 diff --git a/ext/bcmath/libbcmath/src/compare.c b/ext/bcmath/libbcmath/src/compare.c index d21de720cb145..f8b36cb9c3155 100644 --- a/ext/bcmath/libbcmath/src/compare.c +++ b/ext/bcmath/libbcmath/src/compare.c @@ -30,9 +30,9 @@ *************************************************************************/ #include -#include #include "bcmath.h" #include "private.h" +#include /* Compare two bc numbers. Return value is 0 if equal, -1 if N1 is less @@ -46,9 +46,11 @@ int _bc_do_compare(bc_num n1, bc_num n2, bool use_sign, bool ignore_last) /* First, compare signs. */ if (use_sign && n1->n_sign != n2->n_sign) { if (n1->n_sign == PLUS) { - return (1); /* Positive N1 > Negative N2 */ + /* Positive N1 > Negative N2 */ + return (1); } else { - return (-1); /* Negative N1 < Positive N1 */ + /* Negative N1 < Positive N1 */ + return (-1); } } @@ -107,7 +109,7 @@ int _bc_do_compare(bc_num n1, bc_num n2, bool use_sign, bool ignore_last) /* They are equal up to the last part of the equal part of the fraction. */ if (n1->n_scale != n2->n_scale) { if (n1->n_scale > n2->n_scale) { - for (count = n1->n_scale-n2->n_scale; count>0; count--) { + for (count = n1->n_scale - n2->n_scale; count > 0; count--) { if (*n1ptr++ != 0) { /* Magnitude of n1 > n2. */ if (!use_sign || n1->n_sign == PLUS) { @@ -118,7 +120,7 @@ int _bc_do_compare(bc_num n1, bc_num n2, bool use_sign, bool ignore_last) } } } else { - for (count = n2->n_scale-n1->n_scale; count>0; count--) { + for (count = n2->n_scale - n1->n_scale; count > 0; count--) { if (*n2ptr++ != 0) { /* Magnitude of n1 < n2. */ if (!use_sign || n1->n_sign == PLUS) { diff --git a/ext/bcmath/libbcmath/src/debug.c b/ext/bcmath/libbcmath/src/debug.c index a9ed000196a08..d723dba86fe3c 100644 --- a/ext/bcmath/libbcmath/src/debug.c +++ b/ext/bcmath/libbcmath/src/debug.c @@ -36,7 +36,7 @@ /* pn prints the number NUM in base 10. */ -static void out_char (char c) +static void out_char(char c) { putchar(c); } @@ -45,16 +45,16 @@ static void out_char (char c) void pn(bc_num num) { bc_out_num(num, 10, out_char, 0); - out_char ('\n'); + out_char('\n'); } /* pv prints a character array as if it was a string of bcd digits. */ -void pv (char *name, unsigned char *num, size_t len) +void pv(char *name, unsigned char *num, size_t len) { printf("%s=", name); - for (size_t i = 0; i < len; i++){ - printf ("%c",BCD_CHAR(num[i])); + for (size_t i = 0; i < len; i++) { + printf("%c", BCD_CHAR(num[i])); } printf("\n"); } diff --git a/ext/bcmath/libbcmath/src/div.c b/ext/bcmath/libbcmath/src/div.c index b18f65d9db402..f45188455e7f2 100644 --- a/ext/bcmath/libbcmath/src/div.c +++ b/ext/bcmath/libbcmath/src/div.c @@ -33,6 +33,7 @@ #include "private.h" #include #include +#include #include "zend_alloc.h" @@ -43,7 +44,7 @@ static void _one_mult(unsigned char *num, size_t size, int digit, unsigned char *result) { - int carry, value; + size_t carry, value; unsigned char *nptr, *rptr; if (digit == 0) { @@ -53,8 +54,8 @@ static void _one_mult(unsigned char *num, size_t size, int digit, unsigned char memcpy(result, num, size); } else { /* Initialize */ - nptr = (unsigned char *) (num+size-1); - rptr = (unsigned char *) (result+size-1); + nptr = (unsigned char *) (num + size - 1); + rptr = (unsigned char *) (result + size - 1); carry = 0; while (size-- > 0) { @@ -74,59 +75,55 @@ static void _one_mult(unsigned char *num, size_t size, int digit, unsigned char /* The full division routine. This computes N1 / N2. It returns true if the division is ok and the result is in QUOT. The number of digits after the decimal point is SCALE. It returns false if division - by zero is tried. The algorithm is found in Knuth Vol 2. p237. */ + by zero is tried. The algorithm is found in Knuth Vol 2. p237. */ bool bc_divide(bc_num n1, bc_num n2, bc_num *quot, int scale) { bc_num qval; unsigned char *num1, *num2; unsigned char *ptr1, *ptr2, *n2ptr, *qptr; - int scale1, val; - unsigned int len1, len2, scale2, qdigits, extra, count; - unsigned int qdig, qguess, borrow, carry; + int scale1, val; + unsigned int len1, len2, scale2, qdigits, extra, count; + unsigned int qdig, qguess, borrow, carry; unsigned char *mval; + unsigned int norm; bool zero; - unsigned int norm; /* Test for divide by zero. */ if (bc_is_zero(n2)) { return false; } - /* Test for divide by 1. If it is we must truncate. */ - if (n2->n_scale == 0) { - if (n2->n_len == 1 && *n2->n_value == 1) { - qval = bc_new_num (n1->n_len, scale); - qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS); - memset (&qval->n_value[n1->n_len],0,scale); - memcpy (qval->n_value, n1->n_value, n1->n_len + MIN(n1->n_scale,scale)); - bc_free_num (quot); - *quot = qval; - } + /* Test for divide by 1. If it is we must truncate. */ + if (n2->n_scale == 0 && n2->n_len == 1 && *n2->n_value == 1) { + qval = bc_new_num (n1->n_len, scale); + qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS); + memset(&qval->n_value[n1->n_len], 0, scale); + memcpy(qval->n_value, n1->n_value, n1->n_len + MIN(n1->n_scale, scale)); + bc_free_num (quot); + *quot = qval; } /* Set up the divide. Move the decimal point on n1 by n2's scale. Remember, zeros on the end of num2 are wasted effort for dividing. */ scale2 = n2->n_scale; - n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1; - while ((scale2 > 0) && (*n2ptr-- == 0)) { + n2ptr = (unsigned char *) n2->n_value + n2->n_len + scale2 - 1; + while ((scale2 > 0) && (*n2ptr == 0)) { scale2--; + n2ptr--; } len1 = n1->n_len + scale2; scale1 = n1->n_scale - scale2; - if (scale1 < scale) { - extra = scale - scale1; - } else { - extra = 0; - } - num1 = (unsigned char *) safe_emalloc (1, n1->n_len+n1->n_scale, extra+2); - memset (num1, 0, n1->n_len+n1->n_scale+extra+2); - memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale); + extra = MAX(scale - scale1, 0); + + num1 = (unsigned char *) safe_emalloc(1, n1->n_len + n1->n_scale, extra + 2); + memset(num1, 0, n1->n_len + n1->n_scale + extra + 2); + memcpy(num1 + 1, n1->n_value, n1->n_len + n1->n_scale); len2 = n2->n_len + scale2; - num2 = (unsigned char *) safe_emalloc (1, len2, 1); - memcpy (num2, n2->n_value, len2); - *(num2+len2) = 0; + num2 = (unsigned char *) safe_emalloc(1, len2, 1); + memcpy(num2, n2->n_value, len2); + *(num2 + len2) = 0; n2ptr = num2; while (*n2ptr == 0) { n2ptr++; @@ -134,22 +131,22 @@ bool bc_divide(bc_num n1, bc_num n2, bc_num *quot, int scale) } /* Calculate the number of quotient digits. */ - if (len2 > len1+scale) { - qdigits = scale+1; + if (len2 > len1 + scale) { + qdigits = scale + 1; zero = true; } else { zero = false; if (len2 > len1) { /* One for the zero integer part. */ - qdigits = scale+1; + qdigits = scale + 1; } else { - qdigits = len1-len2+scale+1; + qdigits = len1 - len2 + scale + 1; } } /* Allocate and zero the storage for the quotient. */ - qval = bc_new_num (qdigits-scale,scale); - memset (qval->n_value, 0, qdigits); + qval = bc_new_num (qdigits - scale, scale); + memset(qval->n_value, 0, qdigits); /* Allocate storage for the temporary storage mval. */ mval = (unsigned char *) safe_emalloc(1, len2, 1); @@ -157,38 +154,34 @@ bool bc_divide(bc_num n1, bc_num n2, bc_num *quot, int scale) /* Now for the full divide algorithm. */ if (!zero) { /* Normalize */ - norm = 10 / ((int)*n2ptr + 1); + norm = 10 / ((int) *n2ptr + 1); if (norm != 1) { - _one_mult (num1, len1+scale1+extra+1, norm, num1); - _one_mult (n2ptr, len2, norm, n2ptr); + _one_mult(num1, len1 + scale1 + extra + 1, norm, num1); + _one_mult(n2ptr, len2, norm, n2ptr); } /* Initialize divide loop. */ qdig = 0; if (len2 > len1) { - qptr = (unsigned char *) qval->n_value+len2-len1; + qptr = (unsigned char *) qval->n_value + len2 - len1; } else { qptr = (unsigned char *) qval->n_value; } /* Loop */ - while (qdig <= len1+scale-len2) { + while (qdig <= len1 + scale - len2) { /* Calculate the quotient digit guess. */ if (*n2ptr == num1[qdig]) { qguess = 9; } else { - qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr; + qguess = (num1[qdig] * 10 + num1[qdig + 1]) / *n2ptr; } /* Test qguess. */ - if ( - n2ptr[1]*qguess > (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + num1[qdig+2] - ) { + if (n2ptr[1] * qguess > (num1[qdig] * 10 + num1[qdig + 1] - *n2ptr * qguess) * 10 + num1[qdig + 2]) { qguess--; /* And again. */ - if ( - n2ptr[1]*qguess > (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + num1[qdig+2] - ) { + if (n2ptr[1] * qguess > (num1[qdig] * 10 + num1[qdig + 1] - *n2ptr * qguess) * 10 + num1[qdig + 2]) { qguess--; } } @@ -197,10 +190,10 @@ bool bc_divide(bc_num n1, bc_num n2, bc_num *quot, int scale) borrow = 0; if (qguess != 0) { *mval = 0; - _one_mult (n2ptr, len2, qguess, mval+1); - ptr1 = (unsigned char *) num1+qdig+len2; - ptr2 = (unsigned char *) mval+len2; - for (count = 0; count < len2+1; count++) { + _one_mult(n2ptr, len2, qguess, mval + 1); + ptr1 = (unsigned char *) num1 + qdig + len2; + ptr2 = (unsigned char *) mval + len2; + for (count = 0; count < len2 + 1; count++) { val = (int) *ptr1 - (int) *ptr2-- - borrow; if (val < 0) { val += 10; @@ -215,8 +208,8 @@ bool bc_divide(bc_num n1, bc_num n2, bc_num *quot, int scale) /* Test for negative result. */ if (borrow == 1) { qguess--; - ptr1 = (unsigned char *) num1+qdig+len2; - ptr2 = (unsigned char *) n2ptr+len2-1; + ptr1 = (unsigned char *) num1 + qdig + len2; + ptr2 = (unsigned char *) n2ptr + len2 - 1; carry = 0; for (count = 0; count < len2; count++) { val = (int) *ptr1 + (int) *ptr2-- + carry; @@ -240,7 +233,7 @@ bool bc_divide(bc_num n1, bc_num n2, bc_num *quot, int scale) } /* Clean up and return the number. */ - qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS ); + qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS); if (bc_is_zero(qval)) { qval->n_sign = PLUS; } diff --git a/ext/bcmath/libbcmath/src/divmod.c b/ext/bcmath/libbcmath/src/divmod.c index 2999cd8cd1c34..d4f9d4d38cfa9 100644 --- a/ext/bcmath/libbcmath/src/divmod.c +++ b/ext/bcmath/libbcmath/src/divmod.c @@ -53,16 +53,16 @@ bool bc_divmod(bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, size_t scale } /* Calculate final scale. */ - rscale = MAX (num1->n_scale, num2->n_scale+scale); + rscale = MAX (num1->n_scale, num2->n_scale + scale); bc_init_num(&temp); /* Calculate it. */ - bc_divide (num1, num2, &temp, 0); + bc_divide(num1, num2, &temp, 0); if (quot) { quotient = bc_copy_num(temp); } - bc_multiply (temp, num2, &temp, rscale); - bc_sub (num1, temp, rem, rscale); + bc_multiply(temp, num2, &temp, rscale); + bc_sub(num1, temp, rem, rscale); bc_free_num (&temp); if (quot) { diff --git a/ext/bcmath/libbcmath/src/doaddsub.c b/ext/bcmath/libbcmath/src/doaddsub.c index 29de12fb272c8..c5eeab94b93fb 100644 --- a/ext/bcmath/libbcmath/src/doaddsub.c +++ b/ext/bcmath/libbcmath/src/doaddsub.c @@ -69,12 +69,12 @@ bc_num _bc_do_add(bc_num n1, bc_num n2, size_t scale_min) /* Add the fraction part. First copy the longer fraction.*/ if (n1bytes != n2bytes) { if (n1bytes > n2bytes) { - while (n1bytes>n2bytes) { + while (n1bytes > n2bytes) { *sumptr-- = *n1ptr--; n1bytes--; } } else { - while (n2bytes>n1bytes) { + while (n2bytes > n1bytes) { *sumptr-- = *n2ptr--; n2bytes--; } @@ -87,7 +87,7 @@ bc_num _bc_do_add(bc_num n1, bc_num n2, size_t scale_min) carry = 0; while ((n1bytes > 0) && (n2bytes > 0)) { *sumptr = *n1ptr-- + *n2ptr-- + carry; - if (*sumptr > (BASE-1)) { + if (*sumptr > (BASE - 1)) { carry = 1; *sumptr -= BASE; } else { @@ -105,7 +105,7 @@ bc_num _bc_do_add(bc_num n1, bc_num n2, size_t scale_min) } while (n1bytes-- > 0) { *sumptr = *n1ptr-- + carry; - if (*sumptr > (BASE-1)) { + if (*sumptr > (BASE - 1)) { carry = true; *sumptr -= BASE; } else { @@ -120,7 +120,7 @@ bc_num _bc_do_add(bc_num n1, bc_num n2, size_t scale_min) } /* Adjust sum and return. */ - _bc_rm_leading_zeros (sum); + _bc_rm_leading_zeros(sum); return sum; } @@ -132,10 +132,11 @@ bc_num _bc_do_add(bc_num n1, bc_num n2, size_t scale_min) bc_num _bc_do_sub(bc_num n1, bc_num n2, size_t scale_min) { bc_num diff; - int diff_scale, diff_len; + size_t diff_scale, diff_len; size_t min_scale, min_len; + size_t borrow, count; + int val; char *n1ptr, *n2ptr, *diffptr; - int borrow, count, val; /* Allocate temporary storage. */ diff_len = MAX(n1->n_len, n2->n_len); @@ -153,9 +154,9 @@ bc_num _bc_do_sub(bc_num n1, bc_num n2, size_t scale_min) } /* Initialize the subtract. */ - n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1); - n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1); - diffptr = (char *) (diff->n_value + diff_len + diff_scale -1); + n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale - 1); + n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale - 1); + diffptr = (char *) (diff->n_value + diff_len + diff_scale - 1); /* Subtract the numbers. */ borrow = 0; @@ -169,7 +170,7 @@ bc_num _bc_do_sub(bc_num n1, bc_num n2, size_t scale_min) } else { /* n2 has the longer scale */ for (count = n2->n_scale - min_scale; count > 0; count--) { - val = - *n2ptr-- - borrow; + val = -*n2ptr-- - borrow; if (val < 0) { val += BASE; borrow = 1; @@ -192,7 +193,7 @@ bc_num _bc_do_sub(bc_num n1, bc_num n2, size_t scale_min) *diffptr-- = val; } - /* If n1 has more digits then n2, we now do that subtract. */ + /* If n1 has more digits than n2, we now do that subtract. */ if (diff_len != min_len) { for (count = diff_len - min_len; count > 0; count--) { val = *n1ptr-- - borrow; @@ -207,6 +208,6 @@ bc_num _bc_do_sub(bc_num n1, bc_num n2, size_t scale_min) } /* Clean up and return. */ - _bc_rm_leading_zeros (diff); + _bc_rm_leading_zeros(diff); return diff; } diff --git a/ext/bcmath/libbcmath/src/init.c b/ext/bcmath/libbcmath/src/init.c index ec1d082b5fb3b..cef55324689f9 100644 --- a/ext/bcmath/libbcmath/src/init.c +++ b/ext/bcmath/libbcmath/src/init.c @@ -32,22 +32,22 @@ #include "bcmath.h" #include #include +#include #include "zend_alloc.h" /* new_num allocates a number and sets fields to known values. */ bc_num _bc_new_num_ex(size_t length, size_t scale, bool persistent) { - bc_num temp; /* PHP Change: malloc() -> pemalloc(), removed free_list code */ - temp = (bc_num) safe_pemalloc (1, sizeof(bc_struct)+length, scale, persistent); + bc_num temp = (bc_num) safe_pemalloc(1, sizeof(bc_struct) + length, scale, persistent); temp->n_sign = PLUS; temp->n_len = length; temp->n_scale = scale; temp->n_refs = 1; /* PHP Change: malloc() -> pemalloc() */ - temp->n_ptr = (char *) safe_pemalloc (1, length, scale, persistent); + temp->n_ptr = (char *) safe_pemalloc(1, length, scale, persistent); temp->n_value = temp->n_ptr; - memset (temp->n_ptr, 0, length+scale); + memset(temp->n_ptr, 0, length + scale); return temp; } @@ -63,7 +63,7 @@ void _bc_free_num_ex(bc_num *num, bool persistent) if ((*num)->n_refs == 0) { if ((*num)->n_ptr) { /* PHP Change: free() -> pefree(), removed free_list code */ - pefree ((*num)->n_ptr, persistent); + pefree((*num)->n_ptr, persistent); } pefree(*num, persistent); } @@ -75,10 +75,10 @@ void _bc_free_num_ex(bc_num *num, bool persistent) void bc_init_numbers(void) { - BCG(_zero_) = _bc_new_num_ex (1,0,1); - BCG(_one_) = _bc_new_num_ex (1,0,1); + BCG(_zero_) = _bc_new_num_ex(1, 0, 1); + BCG(_one_) = _bc_new_num_ex(1, 0, 1); BCG(_one_)->n_value[0] = 1; - BCG(_two_) = _bc_new_num_ex (1,0,1); + BCG(_two_) = _bc_new_num_ex(1, 0, 1); BCG(_two_)->n_value[0] = 2; } diff --git a/ext/bcmath/libbcmath/src/int2num.c b/ext/bcmath/libbcmath/src/int2num.c index e46ab06e2c7d3..dba972e7f914c 100644 --- a/ext/bcmath/libbcmath/src/int2num.c +++ b/ext/bcmath/libbcmath/src/int2num.c @@ -37,7 +37,7 @@ void bc_int2num(bc_num *num, int val) { char buffer[30]; char *bptr, *vptr; - int ix = 1; + int ix = 1; char neg = 0; /* Sign. */ @@ -55,7 +55,8 @@ void bc_int2num(bc_num *num, int val) while (val != 0) { *bptr++ = val % BASE; val = val / BASE; - ix++; /* Count the digits. */ + /* Count the digits. */ + ix++; } /* Make the number. */ diff --git a/ext/bcmath/libbcmath/src/nearzero.c b/ext/bcmath/libbcmath/src/nearzero.c index 9cecbdf390654..d590dc161bc7c 100644 --- a/ext/bcmath/libbcmath/src/nearzero.c +++ b/ext/bcmath/libbcmath/src/nearzero.c @@ -30,8 +30,8 @@ *************************************************************************/ #include -#include #include "bcmath.h" +#include /* In some places we need to check if the number NUM is almost zero. Specifically, all but the last digit is 0 and the last digit is 1. @@ -53,9 +53,5 @@ bool bc_is_near_zero(bc_num num, size_t scale) count--; } - if (count != 0 && (count != 1 || *--nptr != 1)) { - return false; - } else { - return true; - } + return count == 0 || (count == 1 && *--nptr == 1); } diff --git a/ext/bcmath/libbcmath/src/num2long.c b/ext/bcmath/libbcmath/src/num2long.c index 1e0fca68cd530..09305c35c30bf 100644 --- a/ext/bcmath/libbcmath/src/num2long.c +++ b/ext/bcmath/libbcmath/src/num2long.c @@ -39,16 +39,13 @@ long bc_num2long(bc_num num) { - long val; - char *nptr; - /* Extract the int value, ignore the fraction. */ - val = 0; - nptr = num->n_value; + long val = 0; + const char *nptr = num->n_value; for (size_t index = num->n_len; index > 0; index--) { char n = *nptr++; - if (val > LONG_MAX/BASE) { + if (val > LONG_MAX / BASE) { return 0; } val *= BASE; diff --git a/ext/bcmath/libbcmath/src/num2str.c b/ext/bcmath/libbcmath/src/num2str.c index f5667220e783d..904de2795af31 100644 --- a/ext/bcmath/libbcmath/src/num2str.c +++ b/ext/bcmath/libbcmath/src/num2str.c @@ -38,8 +38,8 @@ zend_string *bc_num2str_ex(bc_num num, size_t scale) { zend_string *str; char *sptr; - char *nptr; - int index, signch; + size_t index; + bool signch; /* Number of sign chars. */ signch = num->n_sign != PLUS && !bc_is_zero_for_scale(num, MIN(num->n_scale, scale)); @@ -55,18 +55,18 @@ zend_string *bc_num2str_ex(bc_num num, size_t scale) if (signch) *sptr++ = '-'; /* Load the whole number. */ - nptr = num->n_value; - for (index=num->n_len; index>0; index--) { + const char *nptr = num->n_value; + for (index = num->n_len; index > 0; index--) { *sptr++ = BCD_CHAR(*nptr++); } /* Now the fraction. */ if (scale > 0) { *sptr++ = '.'; - for (index=0; indexn_scale; index++) { + for (index = 0; index < scale && index < num->n_scale; index++) { *sptr++ = BCD_CHAR(*nptr++); } - for (index = num->n_scale; indexn_scale; index < scale; index++) { *sptr++ = BCD_CHAR(0); } } diff --git a/ext/bcmath/libbcmath/src/output.c b/ext/bcmath/libbcmath/src/output.c index e0fa507bc1b03..47a82d20655e3 100644 --- a/ext/bcmath/libbcmath/src/output.c +++ b/ext/bcmath/libbcmath/src/output.c @@ -31,6 +31,7 @@ #include "bcmath.h" #include +#include #include "zend_alloc.h" @@ -39,7 +40,7 @@ /* This structure is used for saving digits in the conversion process. */ typedef struct stk_rec { - long digit; + long digit; struct stk_rec *next; } stk_rec; @@ -52,93 +53,93 @@ static const char ref_str[] = "0123456789ABCDEF"; non-zero, we must output one space before the number. OUT_CHAR is the actual routine for writing the characters. */ -void bc_out_long (long val, size_t size, bool space, void (*out_char)(char) ) +void bc_out_long(long val, size_t size, bool space, void (*out_char)(char)) { char digits[40]; size_t len, ix; - if (space) (*out_char) (' '); + if (space) (*out_char)(' '); snprintf(digits, sizeof(digits), "%ld", val); len = strlen(digits); while (size > len) { - (*out_char) ('0'); + (*out_char)('0'); size--; } - for (ix=0; ix < len; ix++) { - (*out_char) (digits[ix]); + for (ix = 0; ix < len; ix++) { + (*out_char)(digits[ix]); } } /* Output of a bcd number. NUM is written in base O_BASE using OUT_CHAR as the routine to do the actual output of the characters. */ -void bc_out_num (bc_num num, int o_base, void (*out_char)(char), bool leading_zero) +void bc_out_num(bc_num num, int o_base, void (*out_char)(char), bool leading_zero) { char *nptr; - int index, fdigit; + int index, fdigit; bool pre_space; stk_rec *digits, *temp; bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit; /* The negative sign if needed. */ - if (num->n_sign == MINUS) (*out_char) ('-'); + if (num->n_sign == MINUS) (*out_char)('-'); /* Output the number. */ - if (bc_is_zero (num)) { - (*out_char) ('0'); + if (bc_is_zero(num)) { + (*out_char)('0'); } else { if (o_base == 10) { /* The number is in base 10, do it the fast way. */ nptr = num->n_value; if (num->n_len > 1 || *nptr != 0) { - for (index=num->n_len; index>0; index--) { - (*out_char) (BCD_CHAR(*nptr++)); + for (index = num->n_len; index > 0; index--) { + (*out_char)(BCD_CHAR(*nptr++)); } } else { nptr++; } if (leading_zero && bc_is_zero(num)) { - (*out_char) ('0'); + (*out_char)('0'); } /* Now the fraction. */ if (num->n_scale > 0) { - (*out_char) ('.'); - for (index=0; indexn_scale; index++) { - (*out_char) (BCD_CHAR(*nptr++)); + (*out_char)('.'); + for (index = 0; index < num->n_scale; index++) { + (*out_char)(BCD_CHAR(*nptr++)); } } } else { /* special case ... */ - if (leading_zero && bc_is_zero (num)) { - (*out_char) ('0'); + if (leading_zero && bc_is_zero(num)) { + (*out_char)('0'); } /* The number is some other base. */ digits = NULL; - bc_init_num (&int_part); - bc_divide (num, BCG(_one_), &int_part, 0); - bc_init_num (&frac_part); - bc_init_num (&cur_dig); - bc_init_num (&base); - bc_sub (num, int_part, &frac_part, 0); + bc_init_num(&int_part); + bc_divide(num, BCG(_one_), &int_part, 0); + bc_init_num(&frac_part); + bc_init_num(&cur_dig); + bc_init_num(&base); + bc_sub(num, int_part, &frac_part, 0); /* Make the INT_PART and FRAC_PART positive. */ int_part->n_sign = PLUS; frac_part->n_sign = PLUS; - bc_int2num (&base, o_base); - bc_init_num (&max_o_digit); - bc_int2num (&max_o_digit, o_base-1); + bc_int2num(&base, o_base); + bc_init_num(&max_o_digit); + bc_int2num(&max_o_digit, o_base - 1); /* Get the digits of the integer part and push them on a stack. */ while (!bc_is_zero(int_part)) { - bc_modulo (int_part, base, &cur_dig, 0); + bc_modulo(int_part, base, &cur_dig, 0); /* PHP Change: malloc() -> emalloc() */ - temp = (stk_rec *) emalloc (sizeof(stk_rec)); - temp->digit = bc_num2long (cur_dig); + temp = (stk_rec *) emalloc(sizeof(stk_rec)); + temp->digit = bc_num2long(cur_dig); temp->next = digits; digits = temp; - bc_divide (int_part, base, &int_part, 0); + bc_divide(int_part, base, &int_part, 0); } /* Print the digits on the stack. */ @@ -148,9 +149,9 @@ void bc_out_num (bc_num num, int o_base, void (*out_char)(char), bool leading_ze temp = digits; digits = digits->next; if (o_base <= 16) { - (*out_char) (ref_str[ (int) temp->digit]); + (*out_char)(ref_str[(int) temp->digit]); } else { - bc_out_long (temp->digit, max_o_digit->n_len, 1, out_char); + bc_out_long(temp->digit, max_o_digit->n_len, 1, out_char); } efree(temp); } @@ -158,21 +159,21 @@ void bc_out_num (bc_num num, int o_base, void (*out_char)(char), bool leading_ze /* Get and print the digits of the fraction part. */ if (num->n_scale > 0) { - (*out_char) ('.'); + (*out_char)('.'); pre_space = false; - t_num = bc_copy_num (BCG(_one_)); + t_num = bc_copy_num(BCG(_one_)); while (t_num->n_len <= num->n_scale) { - bc_multiply (frac_part, base, &frac_part, num->n_scale); - fdigit = bc_num2long (frac_part); - bc_int2num (&int_part, fdigit); - bc_sub (frac_part, int_part, &frac_part, 0); + bc_multiply(frac_part, base, &frac_part, num->n_scale); + fdigit = bc_num2long(frac_part); + bc_int2num(&int_part, fdigit); + bc_sub(frac_part, int_part, &frac_part, 0); if (o_base <= 16) { - (*out_char) (ref_str[fdigit]); + (*out_char)(ref_str[fdigit]); } else { - bc_out_long (fdigit, max_o_digit->n_len, pre_space, out_char); + bc_out_long(fdigit, max_o_digit->n_len, pre_space, out_char); pre_space = true; } - bc_multiply (t_num, base, &t_num, 0); + bc_multiply(t_num, base, &t_num, 0); } bc_free_num (&t_num); } diff --git a/ext/bcmath/libbcmath/src/raise.c b/ext/bcmath/libbcmath/src/raise.c index 4560e4e6916a5..61d64ace94744 100644 --- a/ext/bcmath/libbcmath/src/raise.c +++ b/ext/bcmath/libbcmath/src/raise.c @@ -50,7 +50,7 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) /* Special case if exponent is a zero. */ if (exponent == 0) { bc_free_num (result); - *result = bc_copy_num (BCG(_one_)); + *result = bc_copy_num(BCG(_one_)); return; } @@ -61,35 +61,35 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) rscale = scale; } else { is_neg = false; - rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale)); + rscale = MIN (num1->n_scale * exponent, MAX(scale, num1->n_scale)); } /* Set initial value of temp. */ - power = bc_copy_num (num1); + power = bc_copy_num(num1); pwrscale = num1->n_scale; while ((exponent & 1) == 0) { - pwrscale = 2*pwrscale; - bc_multiply (power, power, &power, pwrscale); + pwrscale = 2 * pwrscale; + bc_multiply(power, power, &power, pwrscale); exponent = exponent >> 1; } - temp = bc_copy_num (power); + temp = bc_copy_num(power); calcscale = pwrscale; exponent = exponent >> 1; /* Do the calculation. */ while (exponent > 0) { - pwrscale = 2*pwrscale; - bc_multiply (power, power, &power, pwrscale); + pwrscale = 2 * pwrscale; + bc_multiply(power, power, &power, pwrscale); if ((exponent & 1) == 1) { calcscale = pwrscale + calcscale; - bc_multiply (temp, power, &temp, calcscale); + bc_multiply(temp, power, &temp, calcscale); } exponent = exponent >> 1; } /* Assign the value. */ if (is_neg) { - bc_divide (BCG(_one_), temp, result, rscale); + bc_divide(BCG(_one_), temp, result, rscale); bc_free_num (&temp); } else { bc_free_num (result); diff --git a/ext/bcmath/libbcmath/src/raisemod.c b/ext/bcmath/libbcmath/src/raisemod.c index badee6fca6faa..93bd4193da45c 100644 --- a/ext/bcmath/libbcmath/src/raisemod.c +++ b/ext/bcmath/libbcmath/src/raisemod.c @@ -59,26 +59,26 @@ raise_mod_status bc_raisemod(bc_num base, bc_num expo, bc_num mod, bc_num *resul } /* Set initial values. */ - power = bc_copy_num (base); - exponent = bc_copy_num (expo); - modulus = bc_copy_num (mod); - temp = bc_copy_num (BCG(_one_)); + power = bc_copy_num(base); + exponent = bc_copy_num(expo); + modulus = bc_copy_num(mod); + temp = bc_copy_num(BCG(_one_)); bc_init_num(&parity); /* Do the calculation. */ rscale = MAX(scale, power->n_scale); - if ( !bc_compare(modulus, BCG(_one_)) ) { + if (!bc_compare(modulus, BCG(_one_))) { bc_free_num (&temp); temp = bc_new_num (1, scale); } else { - while ( !bc_is_zero(exponent) ) { - (void) bc_divmod (exponent, BCG(_two_), &exponent, &parity, 0); - if ( !bc_is_zero(parity) ) { - bc_multiply (temp, power, &temp, rscale); - (void) bc_modulo (temp, modulus, &temp, scale); + while (!bc_is_zero(exponent)) { + (void) bc_divmod(exponent, BCG(_two_), &exponent, &parity, 0); + if (!bc_is_zero(parity)) { + bc_multiply(temp, power, &temp, rscale); + (void) bc_modulo(temp, modulus, &temp, scale); } - bc_multiply (power, power, &power, rscale); - (void) bc_modulo (power, modulus, &power, scale); + bc_multiply(power, power, &power, rscale); + (void) bc_modulo(power, modulus, &power, scale); } } diff --git a/ext/bcmath/libbcmath/src/recmul.c b/ext/bcmath/libbcmath/src/recmul.c index 0a4563d10b204..ec89c461fa188 100644 --- a/ext/bcmath/libbcmath/src/recmul.c +++ b/ext/bcmath/libbcmath/src/recmul.c @@ -50,9 +50,7 @@ int mul_base_digits = MUL_BASE_DIGITS; static bc_num new_sub_num(size_t length, size_t scale, char *value) { - bc_num temp; - - temp = (bc_num) emalloc (sizeof(bc_struct)); + bc_num temp = (bc_num) emalloc(sizeof(bc_struct)); temp->n_sign = PLUS; temp->n_len = length; @@ -66,22 +64,21 @@ static bc_num new_sub_num(size_t length, size_t scale, char *value) static void _bc_simp_mul(bc_num n1, size_t n1len, bc_num n2, int n2len, bc_num *prod) { char *n1ptr, *n2ptr, *pvptr; - char *n1end, *n2end; /* To the end of n1 and n2. */ - int indx, sum, prodlen; + char *n1end, *n2end; /* To the end of n1 and n2. */ + int sum = 0; - prodlen = n1len+n2len+1; + int prodlen = n1len + n2len + 1; *prod = bc_new_num (prodlen, 0); n1end = (char *) (n1->n_value + n1len - 1); n2end = (char *) (n2->n_value + n2len - 1); pvptr = (char *) ((*prod)->n_value + prodlen - 1); - sum = 0; /* Here is the loop... */ - for (indx = 0; indx < prodlen-1; indx++) { - n1ptr = (char *) (n1end - MAX(0, indx-n2len+1)); - n2ptr = (char *) (n2end - MIN(indx, n2len-1)); + for (int index = 0; index < prodlen - 1; index++) { + n1ptr = (char *) (n1end - MAX(0, index - n2len + 1)); + n2ptr = (char *) (n2end - MIN(index, n2len - 1)); while ((n1ptr >= n1->n_value) && (n2ptr <= n2end)) { sum += *n1ptr * *n2ptr; n1ptr--; @@ -98,7 +95,7 @@ static void _bc_simp_mul(bc_num n1, size_t n1len, bc_num n2, int n2len, bc_num * multiply algorithm. Note: if sub is called, accum must be larger that what is being subtracted. Also, accum and val must have n_scale = 0. (e.g. they must look like integers. *) */ -static void _bc_shift_addsub (bc_num accum, bc_num val, int shift, bool sub) +static void _bc_shift_addsub(bc_num accum, bc_num val, int shift, bool sub) { signed char *accp, *valp; unsigned int carry = 0; @@ -107,11 +104,11 @@ static void _bc_shift_addsub (bc_num accum, bc_num val, int shift, bool sub) if (val->n_value[0] == 0) { count--; } - assert(accum->n_len+accum->n_scale >= shift+count); + assert(accum->n_len + accum->n_scale >= shift + count); /* Set up pointers and others */ - accp = (signed char *)(accum->n_value + accum->n_len + accum->n_scale - shift - 1); - valp = (signed char *)(val->n_value + val->n_len - 1); + accp = (signed char *) (accum->n_value + accum->n_len + accum->n_scale - shift - 1); + valp = (signed char *) (val->n_value + val->n_len - 1); if (sub) { /* Subtraction, carry is really borrow. */ @@ -137,7 +134,7 @@ static void _bc_shift_addsub (bc_num accum, bc_num val, int shift, bool sub) /* Addition */ while (count--) { *accp += *valp-- + carry; - if (*accp > (BASE-1)) { + if (*accp > (BASE - 1)) { carry = 1; *accp-- -= BASE; } else { @@ -147,7 +144,7 @@ static void _bc_shift_addsub (bc_num accum, bc_num val, int shift, bool sub) } while (carry) { *accp += carry; - if (*accp > (BASE-1)) { + if (*accp > (BASE - 1)) { *accp-- -= BASE; } else { carry = 0; @@ -168,40 +165,40 @@ static void _bc_rec_mul(bc_num u, size_t ulen, bc_num v, size_t vlen, bc_num *pr { bc_num u0, u1, v0, v1; bc_num m1, m2, m3, d1, d2; - int n, prodlen, m1zero; - int d1len, d2len; + size_t n; + bool m1zero; /* Base case? */ - if ((ulen+vlen) < mul_base_digits + if ((ulen + vlen) < mul_base_digits || ulen < MUL_SMALL_DIGITS || vlen < MUL_SMALL_DIGITS ) { - _bc_simp_mul (u, ulen, v, vlen, prod); + _bc_simp_mul(u, ulen, v, vlen, prod); return; } /* Calculate n -- the u and v split point in digits. */ - n = (MAX(ulen, vlen)+1) / 2; + n = (MAX(ulen, vlen) + 1) / 2; /* Split u and v. */ if (ulen < n) { - u1 = bc_copy_num (BCG(_zero_)); - u0 = new_sub_num (ulen,0, u->n_value); + u1 = bc_copy_num(BCG(_zero_)); + u0 = new_sub_num(ulen, 0, u->n_value); } else { - u1 = new_sub_num (ulen-n, 0, u->n_value); - u0 = new_sub_num (n, 0, u->n_value+ulen-n); + u1 = new_sub_num(ulen - n, 0, u->n_value); + u0 = new_sub_num(n, 0, u->n_value + ulen - n); } if (vlen < n) { - v1 = bc_copy_num (BCG(_zero_)); - v0 = new_sub_num (vlen,0, v->n_value); + v1 = bc_copy_num(BCG(_zero_)); + v0 = new_sub_num(vlen, 0, v->n_value); } else { - v1 = new_sub_num (vlen-n, 0, v->n_value); - v0 = new_sub_num (n, 0, v->n_value+vlen-n); + v1 = new_sub_num(vlen - n, 0, v->n_value); + v0 = new_sub_num(n, 0, v->n_value + vlen - n); } - _bc_rm_leading_zeros (u1); - _bc_rm_leading_zeros (u0); - _bc_rm_leading_zeros (v1); - _bc_rm_leading_zeros (v0); + _bc_rm_leading_zeros(u1); + _bc_rm_leading_zeros(u0); + _bc_rm_leading_zeros(v1); + _bc_rm_leading_zeros(v0); m1zero = bc_is_zero(u1) || bc_is_zero(v1); @@ -209,42 +206,39 @@ static void _bc_rec_mul(bc_num u, size_t ulen, bc_num v, size_t vlen, bc_num *pr bc_init_num(&d1); bc_init_num(&d2); - bc_sub (u1, u0, &d1, 0); - d1len = d1->n_len; - bc_sub (v0, v1, &d2, 0); - d2len = d2->n_len; + bc_sub(u1, u0, &d1, 0); + bc_sub(v0, v1, &d2, 0); /* Do recursive multiplies and shifted adds. */ if (m1zero) { - m1 = bc_copy_num (BCG(_zero_)); + m1 = bc_copy_num(BCG(_zero_)); } else { - _bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1); + _bc_rec_mul(u1, u1->n_len, v1, v1->n_len, &m1); } if (bc_is_zero(d1) || bc_is_zero(d2)) { - m2 = bc_copy_num (BCG(_zero_)); + m2 = bc_copy_num(BCG(_zero_)); } else { - _bc_rec_mul (d1, d1len, d2, d2len, &m2); + _bc_rec_mul(d1, d1->n_len, d2, d2->n_len, &m2); } if (bc_is_zero(u0) || bc_is_zero(v0)) { - m3 = bc_copy_num (BCG(_zero_)); + m3 = bc_copy_num(BCG(_zero_)); } else { - _bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3); + _bc_rec_mul(u0, u0->n_len, v0, v0->n_len, &m3); } /* Initialize product */ - prodlen = ulen+vlen+1; - *prod = bc_new_num(prodlen, 0); + *prod = bc_new_num(ulen + vlen + 1, 0); if (!m1zero) { - _bc_shift_addsub (*prod, m1, 2*n, 0); - _bc_shift_addsub (*prod, m1, n, 0); + _bc_shift_addsub(*prod, m1, 2 * n, false); + _bc_shift_addsub(*prod, m1, n, false); } - _bc_shift_addsub (*prod, m3, n, 0); - _bc_shift_addsub (*prod, m3, 0, 0); - _bc_shift_addsub (*prod, m2, n, d1->n_sign != d2->n_sign); + _bc_shift_addsub(*prod, m3, n, false); + _bc_shift_addsub(*prod, m3, 0, false); + _bc_shift_addsub(*prod, m2, n, d1->n_sign != d2->n_sign); /* Now clean up! */ bc_free_num (&u1); @@ -272,13 +266,13 @@ void bc_multiply(bc_num n1, bc_num n2, bc_num *prod, size_t scale) len1 = n1->n_len + n1->n_scale; len2 = n2->n_len + n2->n_scale; full_scale = n1->n_scale + n2->n_scale; - prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale))); + prod_scale = MIN(full_scale, MAX(scale, MAX(n1->n_scale, n2->n_scale))); /* Do the multiply */ - _bc_rec_mul (n1, len1, n2, len2, &pval); + _bc_rec_mul(n1, len1, n2, len2, &pval); /* Assign to prod and clean up the number. */ - pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS ); + pval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS); pval->n_value = pval->n_ptr; pval->n_len = len2 + len1 + 1 - full_scale; pval->n_scale = prod_scale; diff --git a/ext/bcmath/libbcmath/src/rmzero.c b/ext/bcmath/libbcmath/src/rmzero.c index c2e749bec43a8..8228e54f4aa57 100644 --- a/ext/bcmath/libbcmath/src/rmzero.c +++ b/ext/bcmath/libbcmath/src/rmzero.c @@ -38,7 +38,7 @@ void _bc_rm_leading_zeros(bc_num num) { - /* We can move n_value to point to the first non zero digit! */ + /* We can move n_value to point to the first non-zero digit! */ while (*num->n_value == 0 && num->n_len > 1) { num->n_value++; num->n_len--; diff --git a/ext/bcmath/libbcmath/src/sqrt.c b/ext/bcmath/libbcmath/src/sqrt.c index d28838b155358..f29f9ce484bad 100644 --- a/ext/bcmath/libbcmath/src/sqrt.c +++ b/ext/bcmath/libbcmath/src/sqrt.c @@ -30,8 +30,8 @@ *************************************************************************/ #include "bcmath.h" -#include #include +#include /* Take the square root NUM and return it in NUM with SCALE digits after the decimal place. */ @@ -39,20 +39,20 @@ bool bc_sqrt(bc_num *num, size_t scale) { /* Initial checks. */ - int cmp_res = bc_compare (*num, BCG(_zero_)); + int cmp_res = bc_compare(*num, BCG(_zero_)); if (cmp_res < 0) { return false; /* error */ } else { if (cmp_res == 0) { bc_free_num (num); - *num = bc_copy_num (BCG(_zero_)); + *num = bc_copy_num(BCG(_zero_)); return true; } } - cmp_res = bc_compare (*num, BCG(_one_)); + cmp_res = bc_compare(*num, BCG(_one_)); if (cmp_res == 0) { bc_free_num (num); - *num = bc_copy_num (BCG(_one_)); + *num = bc_copy_num(BCG(_one_)); return true; } @@ -64,22 +64,22 @@ bool bc_sqrt(bc_num *num, size_t scale) rscale = MAX (scale, (*num)->n_scale); bc_init_num(&guess1); bc_init_num(&diff); - point5 = bc_new_num (1,1); + point5 = bc_new_num (1, 1); point5->n_value[1] = 5; /* Calculate the initial guess. */ if (cmp_res < 0) { /* The number is between 0 and 1. Guess should start at 1. */ - guess = bc_copy_num (BCG(_one_)); + guess = bc_copy_num(BCG(_one_)); cscale = (*num)->n_scale; } else { /* The number is greater than 1. Guess should start at 10^(exp/2). */ bc_init_num(&guess); - bc_int2num (&guess,10); + bc_int2num(&guess, 10); - bc_int2num (&guess1,(*num)->n_len); - bc_multiply (guess1, point5, &guess1, 0); + bc_int2num(&guess1, (*num)->n_len); + bc_multiply(guess1, point5, &guess1, 0); guess1->n_scale = 0; bc_raise_bc_exponent(guess, guess1, &guess, 0); bc_free_num (&guess1); @@ -90,14 +90,14 @@ bool bc_sqrt(bc_num *num, size_t scale) bool done = false; while (!done) { bc_free_num (&guess1); - guess1 = bc_copy_num (guess); - bc_divide (*num, guess, &guess, cscale); - bc_add (guess, guess1, &guess, 0); - bc_multiply (guess, point5, &guess, cscale); - bc_sub (guess, guess1, &diff, cscale+1); - if (bc_is_near_zero (diff, cscale)) { - if (cscale < rscale+1) { - cscale = MIN (cscale*3, rscale+1); + guess1 = bc_copy_num(guess); + bc_divide(*num, guess, &guess, cscale); + bc_add(guess, guess1, &guess, 0); + bc_multiply(guess, point5, &guess, cscale); + bc_sub(guess, guess1, &diff, cscale + 1); + if (bc_is_near_zero(diff, cscale)) { + if (cscale < rscale + 1) { + cscale = MIN (cscale * 3, rscale + 1); } else { done = true; } @@ -106,7 +106,7 @@ bool bc_sqrt(bc_num *num, size_t scale) /* Assign the number and clean up. */ bc_free_num (num); - bc_divide (guess,BCG(_one_),num,rscale); + bc_divide(guess, BCG(_one_), num, rscale); bc_free_num (&guess); bc_free_num (&guess1); bc_free_num (&point5); diff --git a/ext/bcmath/libbcmath/src/str2num.c b/ext/bcmath/libbcmath/src/str2num.c index 7bba9a9f6c149..cc876285d59c0 100644 --- a/ext/bcmath/libbcmath/src/str2num.c +++ b/ext/bcmath/libbcmath/src/str2num.c @@ -35,22 +35,21 @@ /* Convert strings to bc numbers. Base 10 only.*/ -bool bc_str2num (bc_num *num, char *str, size_t scale) +bool bc_str2num(bc_num *num, char *str, size_t scale) { - size_t digits, strscale; + size_t digits = 0; + size_t strscale = 0; char *ptr, *nptr; - bool zero_int = false; size_t trailing_zeros = 0; + bool zero_int = false; /* Prepare num. */ bc_free_num (num); /* Check for valid number and count digits. */ ptr = str; - digits = 0; - strscale = 0; - if ( (*ptr == '+') || (*ptr == '-')) { + if ((*ptr == '+') || (*ptr == '-')) { /* Skip Sign */ ptr++; } @@ -79,11 +78,11 @@ bool bc_str2num (bc_num *num, char *str, size_t scale) } if (trailing_zeros > 0) { - /* Trailining zeros should not take part in the computation of the overall scale, as it is pointless. */ + /* Trailing zeros should not take part in the computation of the overall scale, as it is pointless. */ strscale = strscale - trailing_zeros; } - if ((*ptr != '\0') || (digits+strscale == 0)) { - *num = bc_copy_num (BCG(_zero_)); + if ((*ptr != '\0') || (digits + strscale == 0)) { + *num = bc_copy_num(BCG(_zero_)); return *ptr == '\0'; } @@ -113,7 +112,7 @@ bool bc_str2num (bc_num *num, char *str, size_t scale) *nptr++ = 0; digits = 0; } - for (;digits > 0; digits--) { + for (; digits > 0; digits--) { *nptr++ = CH_VAL(*ptr++); } @@ -121,12 +120,12 @@ bool bc_str2num (bc_num *num, char *str, size_t scale) if (strscale > 0) { /* skip the decimal point! */ ptr++; - for (;strscale > 0; strscale--) { + for (; strscale > 0; strscale--) { *nptr++ = CH_VAL(*ptr++); } } - if (bc_is_zero (*num)) { + if (bc_is_zero(*num)) { (*num)->n_sign = PLUS; } diff --git a/ext/bcmath/libbcmath/src/sub.c b/ext/bcmath/libbcmath/src/sub.c index 4907ae5bcecdb..d90f1a8858f29 100644 --- a/ext/bcmath/libbcmath/src/sub.c +++ b/ext/bcmath/libbcmath/src/sub.c @@ -33,6 +33,7 @@ #include "private.h" #include #include +#include /* Here is the full subtract routine that takes care of negative numbers. N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN @@ -41,31 +42,29 @@ void bc_sub(bc_num n1, bc_num n2, bc_num *result, size_t scale_min) { bc_num diff = NULL; - int cmp_res; if (n1->n_sign != n2->n_sign) { - diff = _bc_do_add (n1, n2, scale_min); + diff = _bc_do_add(n1, n2, scale_min); diff->n_sign = n1->n_sign; } else { /* subtraction must be done. */ /* Compare magnitudes. */ - cmp_res = _bc_do_compare(n1, n2, false, false); - switch (cmp_res) { + switch (_bc_do_compare(n1, n2, false, false)) { case -1: /* n1 is less than n2, subtract n1 from n2. */ - diff = _bc_do_sub (n2, n1, scale_min); + diff = _bc_do_sub(n2, n1, scale_min); diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS); break; - case 0: { + case 0: { /* They are equal! return zero! */ size_t res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale)); diff = bc_new_num (1, res_scale); - memset (diff->n_value, 0, res_scale+1); + memset(diff->n_value, 0, res_scale + 1); break; } - case 1: + case 1: /* n2 is less than n1, subtract n2 from n1. */ - diff = _bc_do_sub (n1, n2, scale_min); + diff = _bc_do_sub(n1, n2, scale_min); diff->n_sign = n1->n_sign; break; } diff --git a/ext/bcmath/libbcmath/src/zero.c b/ext/bcmath/libbcmath/src/zero.c index edcd188acb8db..550ea97df6743 100644 --- a/ext/bcmath/libbcmath/src/zero.c +++ b/ext/bcmath/libbcmath/src/zero.c @@ -30,12 +30,12 @@ *************************************************************************/ #include "bcmath.h" -#include #include +#include /* In some places we need to check if the number NUM is zero. */ -bool bc_is_zero_for_scale (bc_num num, size_t scale) +bool bc_is_zero_for_scale(bc_num num, size_t scale) { size_t count; char *nptr; diff --git a/ext/date/php_date.stub.php b/ext/date/php_date.stub.php index 5105bdb320a05..e0717fa7f4c85 100644 --- a/ext/date/php_date.stub.php +++ b/ext/date/php_date.stub.php @@ -766,7 +766,7 @@ class DateObjectError extends DateError /** * @strict-properties */ -class DateRangeError extends DateRangeError +class DateRangeError extends DateError { } @@ -780,7 +780,7 @@ class DateException extends Exception /** * @strict-properties */ -class DateInvalidTimeZoneException extends Exception +class DateInvalidTimeZoneException extends DateException { } diff --git a/ext/date/php_date_arginfo.h b/ext/date/php_date_arginfo.h index 311d035026e47..bbede1f39596e 100644 --- a/ext/date/php_date_arginfo.h +++ b/ext/date/php_date_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 30e6ffeefc0c0ecd66f3f40c9211277ce02d7187 */ + * Stub hash: 0f204ac6646be79b515189a384fce9bcea9a4f42 */ 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) @@ -1161,12 +1161,12 @@ static zend_class_entry *register_class_DateObjectError(zend_class_entry *class_ return class_entry; } -static zend_class_entry *register_class_DateRangeError(zend_class_entry *class_entry_DateRangeError) +static zend_class_entry *register_class_DateRangeError(zend_class_entry *class_entry_DateError) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "DateRangeError", class_DateRangeError_methods); - class_entry = zend_register_internal_class_ex(&ce, class_entry_DateRangeError); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateError); class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; return class_entry; @@ -1183,12 +1183,12 @@ static zend_class_entry *register_class_DateException(zend_class_entry *class_en return class_entry; } -static zend_class_entry *register_class_DateInvalidTimeZoneException(zend_class_entry *class_entry_Exception) +static zend_class_entry *register_class_DateInvalidTimeZoneException(zend_class_entry *class_entry_DateException) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "DateInvalidTimeZoneException", class_DateInvalidTimeZoneException_methods); - class_entry = zend_register_internal_class_ex(&ce, class_entry_Exception); + class_entry = zend_register_internal_class_ex(&ce, class_entry_DateException); class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES; return class_entry; diff --git a/ext/dom/document.c b/ext/dom/document.c index bfb06d7e4cca4..234b71be1d87c 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -140,7 +140,6 @@ int dom_document_encoding_read(dom_object *obj, zval *retval) zend_result dom_document_encoding_write(dom_object *obj, zval *newval) { xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj); - zend_string *str; xmlCharEncodingHandlerPtr handler; if (docp == NULL) { @@ -148,11 +147,15 @@ zend_result dom_document_encoding_write(dom_object *obj, zval *newval) return FAILURE; } - str = zval_try_get_string(newval); - if (UNEXPECTED(!str)) { - return FAILURE; + /* Typed property, can only be IS_STRING or IS_NULL. */ + ZEND_ASSERT(Z_TYPE_P(newval) == IS_STRING || Z_TYPE_P(newval) == IS_NULL); + + if (Z_TYPE_P(newval) == IS_NULL) { + goto invalid_encoding; } + zend_string *str = Z_STR_P(newval); + handler = xmlFindCharEncodingHandler(ZSTR_VAL(str)); if (handler != NULL) { @@ -162,12 +165,14 @@ zend_result dom_document_encoding_write(dom_object *obj, zval *newval) } docp->encoding = xmlStrdup((const xmlChar *) ZSTR_VAL(str)); } else { - zend_value_error("Invalid document encoding"); - return FAILURE; + goto invalid_encoding; } - zend_string_release_ex(str, 0); return SUCCESS; + +invalid_encoding: + zend_value_error("Invalid document encoding"); + return FAILURE; } /* }}} */ @@ -805,7 +810,7 @@ PHP_METHOD(DOMDocument, importNode) xmlNodePtr root = xmlDocGetRootElement(docp); nsptr = xmlSearchNsByHref (nodep->doc, root, nodep->ns->href); - if (nsptr == NULL) { + if (nsptr == NULL || nsptr->prefix == NULL) { int errorcode; nsptr = dom_get_ns(root, (char *) nodep->ns->href, &errorcode, (char *) nodep->ns->prefix); } @@ -910,8 +915,8 @@ PHP_METHOD(DOMDocument, createAttributeNS) nodep = (xmlNodePtr) xmlNewDocProp(docp, (xmlChar *) localname, NULL); if (nodep != NULL && uri_len > 0) { nsptr = xmlSearchNsByHref(nodep->doc, root, (xmlChar *) uri); - if (nsptr == NULL) { - nsptr = dom_get_ns(root, uri, &errorcode, prefix); + if (nsptr == NULL || nsptr->prefix == NULL) { + nsptr = dom_get_ns(root, uri, &errorcode, prefix ? prefix : "default"); } xmlSetNs(nodep, nsptr); } diff --git a/ext/dom/element.c b/ext/dom/element.c index d09518419228b..fabc3c514bf96 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -655,45 +655,6 @@ PHP_METHOD(DOMElement, getAttributeNS) } /* }}} end dom_element_get_attribute_ns */ -static xmlNsPtr _dom_new_reconNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) /* {{{ */ -{ - xmlNsPtr def; - xmlChar prefix[50]; - int counter = 1; - - if ((tree == NULL) || (ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) { - return NULL; - } - - /* Code taken from libxml2 (2.6.20) xmlNewReconciliedNs - * - * Find a close prefix which is not already in use. - * Let's strip namespace prefixes longer than 20 chars ! - */ - if (ns->prefix == NULL) - snprintf((char *) prefix, sizeof(prefix), "default"); - else - snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix); - - def = xmlSearchNs(doc, tree, prefix); - while (def != NULL) { - if (counter > 1000) return(NULL); - if (ns->prefix == NULL) - snprintf((char *) prefix, sizeof(prefix), "default%d", counter++); - else - snprintf((char *) prefix, sizeof(prefix), "%.20s%d", - (char *)ns->prefix, counter++); - def = xmlSearchNs(doc, tree, prefix); - } - - /* - * OK, now we are ready to create a new one. - */ - def = xmlNewNs(tree, ns->href, prefix); - return(def); -} -/* }}} */ - /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-ElSetAttrNS Since: DOM Level 2 */ @@ -756,27 +717,18 @@ PHP_METHOD(DOMElement, setAttributeNS) tmpnsptr = tmpnsptr->next; } if (tmpnsptr == NULL) { - nsptr = _dom_new_reconNs(elemp->doc, elemp, nsptr); + nsptr = dom_get_ns_resolve_prefix_conflict(elemp, (const char *) nsptr->href); } } } if (nsptr == NULL) { - if (prefix == NULL) { - if (is_xmlns == 1) { - xmlNewNs(elemp, (xmlChar *)value, NULL); - xmlReconciliateNs(elemp->doc, elemp); - } else { - errorcode = NAMESPACE_ERR; - } + if (is_xmlns == 1) { + xmlNewNs(elemp, (xmlChar *)value, prefix == NULL ? NULL : (xmlChar *)localname); } else { - if (is_xmlns == 1) { - xmlNewNs(elemp, (xmlChar *)value, (xmlChar *)localname); - } else { - nsptr = dom_get_ns(elemp, uri, &errorcode, prefix); - } - xmlReconciliateNs(elemp->doc, elemp); + nsptr = dom_get_ns(elemp, uri, &errorcode, prefix); } + xmlReconciliateNs(elemp->doc, elemp); } else { if (is_xmlns == 1) { if (nsptr->href) { @@ -1497,7 +1449,7 @@ PHP_METHOD(DOMElement, toggleAttribute) } ns->next = NULL; - dom_set_old_ns(thisp->doc, ns); + php_libxml_set_old_ns(thisp->doc, ns); dom_reconcile_ns(thisp->doc, thisp); } else { /* TODO: in the future when namespace bugs are fixed, diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 5a066db8d708c..bada817e301e8 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -32,10 +32,6 @@ #define PHP_XPATH 1 #define PHP_XPTR 2 -/* libxml2 doesn't expose this constant as part of their public API. - * See xmlDOMReconcileNSOptions in tree.c */ -#define PHP_LIBXML2_DOM_RECONNS_REMOVEREDUND (1 << 0) - /* {{{ class entries */ PHP_DOM_EXPORT zend_class_entry *dom_node_class_entry; PHP_DOM_EXPORT zend_class_entry *dom_domexception_class_entry; @@ -1436,35 +1432,6 @@ void dom_normalize (xmlNodePtr nodep) } /* }}} end dom_normalize */ - -/* {{{ void dom_set_old_ns(xmlDoc *doc, xmlNs *ns) */ -void dom_set_old_ns(xmlDoc *doc, xmlNs *ns) { - if (doc == NULL) - return; - - ZEND_ASSERT(ns->next == NULL); - - /* Note: we'll use a prepend strategy instead of append to - * make sure we don't lose performance when the list is long. - * As libxml2 could assume the xml node is the first one, we'll place our - * new entries after the first one. */ - - if (doc->oldNs == NULL) { - doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (doc->oldNs == NULL) { - return; - } - memset(doc->oldNs, 0, sizeof(xmlNs)); - doc->oldNs->type = XML_LOCAL_NAMESPACE; - doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE); - doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml"); - } else { - ns->next = doc->oldNs->next; - } - doc->oldNs->next = ns; -} -/* }}} end dom_set_old_ns */ - static void dom_reconcile_ns_internal(xmlDocPtr doc, xmlNodePtr nodep, xmlNodePtr search_parent) { xmlNsPtr nsptr, nsdftptr, curns, prevns = NULL; @@ -1486,7 +1453,7 @@ static void dom_reconcile_ns_internal(xmlDocPtr doc, xmlNodePtr nodep, xmlNodePt /* Note: we can't get here if the ns is already on the oldNs list. * This is because in that case the definition won't be on the node, and * therefore won't be in the nodep->nsDef list. */ - dom_set_old_ns(doc, curns); + php_libxml_set_old_ns(doc, curns); curns = prevns; } } @@ -1502,8 +1469,7 @@ static void dom_libxml_reconcile_ensure_namespaces_are_declared(xmlNodePtr nodep * Although libxml2 currently does not use this for the reconciliation, it still * makes sense to do this just in case libxml2's internal change in the future. */ xmlDOMWrapCtxt dummy_ctxt = {0}; - bool remove_redundant = nodep->nsDef == NULL && nodep->ns != NULL; - xmlDOMWrapReconcileNamespaces(&dummy_ctxt, nodep, /* options */ remove_redundant ? PHP_LIBXML2_DOM_RECONNS_REMOVEREDUND : 0); + xmlDOMWrapReconcileNamespaces(&dummy_ctxt, nodep, /* options */ 0); } void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep) /* {{{ */ @@ -1586,6 +1552,35 @@ int dom_check_qname(char *qname, char **localname, char **prefix, int uri_len, i } /* }}} */ +/* Creates a new namespace declaration with a random prefix with the given uri on the tree. + * This is used to resolve a namespace prefix conflict in cases where spec does not want a + * namespace error in case of conflicts, but demands a resolution. */ +xmlNsPtr dom_get_ns_resolve_prefix_conflict(xmlNodePtr tree, const char *uri) +{ + ZEND_ASSERT(tree != NULL); + xmlDocPtr doc = tree->doc; + + if (UNEXPECTED(doc == NULL)) { + return NULL; + } + + /* Code adapted from libxml2 (2.10.4) */ + char prefix[50]; + int counter = 1; + snprintf(prefix, sizeof(prefix), "default"); + xmlNsPtr nsptr = xmlSearchNs(doc, tree, (const xmlChar *) prefix); + while (nsptr != NULL) { + if (counter > 1000) { + return NULL; + } + snprintf(prefix, sizeof(prefix), "default%d", counter++); + nsptr = xmlSearchNs(doc, tree, (const xmlChar *) prefix); + } + + /* Search yielded no conflict */ + return xmlNewNs(tree, (const xmlChar *) uri, (const xmlChar *) prefix); +} + /* http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS @@ -1603,28 +1598,21 @@ xmlNsPtr dom_get_ns(xmlNodePtr nodep, char *uri, int *errorcode, char *prefix) { if (! ((prefix && !strcmp (prefix, "xml") && strcmp(uri, (char *)XML_XML_NAMESPACE)) || (prefix && !strcmp (prefix, "xmlns") && strcmp(uri, (char *)DOM_XMLNS_NAMESPACE)) || (prefix && !strcmp(uri, (char *)DOM_XMLNS_NAMESPACE) && strcmp (prefix, "xmlns")))) { - /* Reuse the old namespaces from doc->oldNs if possible, before creating a new one. - * This will prevent the oldNs list from growing with duplicates. */ - xmlDocPtr doc = nodep->doc; - if (doc && doc->oldNs != NULL) { - nsptr = doc->oldNs; - do { - if (xmlStrEqual(nsptr->prefix, (xmlChar *)prefix) && xmlStrEqual(nsptr->href, (xmlChar *)uri)) { - goto out; - } - nsptr = nsptr->next; - } while (nsptr); - } - /* Couldn't reuse one, create a new one. */ nsptr = xmlNewNs(nodep, (xmlChar *)uri, (xmlChar *)prefix); if (UNEXPECTED(nsptr == NULL)) { - goto err; + /* Either memory allocation failure, or it's because of a prefix conflict. + * We'll assume a conflict and try again. If it was a memory allocation failure we'll just fail again, whatever. + * This isn't needed for every caller (such as createElementNS & DOMElement::__construct), but isn't harmful and simplifies the mental model "when do I use which function?". + * This branch will also be taken unlikely anyway as in those cases it'll be for allocation failure. */ + nsptr = dom_get_ns_resolve_prefix_conflict(nodep, uri); + if (UNEXPECTED(nsptr == NULL)) { + goto err; + } } } else { goto err; } -out: *errorcode = 0; return nsptr; err: diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index f0a2d598625c3..4d415256788af 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -128,7 +128,6 @@ void php_dom_throw_error_with_message(int error_code, char *error_message, int s void node_list_unlink(xmlNodePtr node); int dom_check_qname(char *qname, char **localname, char **prefix, int uri_len, int name_len); xmlNsPtr dom_get_ns(xmlNodePtr node, char *uri, int *errorcode, char *prefix); -void dom_set_old_ns(xmlDoc *doc, xmlNs *ns); void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep); void dom_reconcile_ns_list(xmlDocPtr doc, xmlNodePtr nodep, xmlNodePtr last); xmlNsPtr dom_get_nsdecl(xmlNode *node, xmlChar *localName); @@ -152,6 +151,7 @@ zend_string *dom_node_concatenated_name_helper(size_t name_len, const char *name zend_string *dom_node_get_node_name_attribute_or_element(const xmlNode *nodep); bool php_dom_is_node_connected(const xmlNode *node); bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, xmlDocPtr new_document); +xmlNsPtr dom_get_ns_resolve_prefix_conflict(xmlNodePtr tree, const char *uri); /* parentnode */ void dom_parent_node_prepend(dom_object *context, zval *nodes, uint32_t nodesc); diff --git a/ext/dom/processinginstruction.c b/ext/dom/processinginstruction.c index afabab1d983ba..2e8695e276c2e 100644 --- a/ext/dom/processinginstruction.c +++ b/ext/dom/processinginstruction.c @@ -118,8 +118,6 @@ int dom_processinginstruction_data_write(dom_object *obj, zval *newval) ZEND_ASSERT(Z_TYPE_P(newval) == IS_STRING); zend_string *str = Z_STR_P(newval); - php_libxml_invalidate_node_list_cache_from_doc(nodep->doc); - xmlNodeSetContentLen(nodep, (xmlChar *) ZSTR_VAL(str), ZSTR_LEN(str)); return SUCCESS; diff --git a/ext/dom/tests/DOMDocument_importNode_attribute_prefix_conflict.phpt b/ext/dom/tests/DOMDocument_importNode_attribute_prefix_conflict.phpt new file mode 100644 index 0000000000000..d00fedbfb3d6c --- /dev/null +++ b/ext/dom/tests/DOMDocument_importNode_attribute_prefix_conflict.phpt @@ -0,0 +1,65 @@ +--TEST-- +DOMDocument::importNode() with attribute prefix name conflict +--EXTENSIONS-- +dom +--FILE-- +loadXML(''); +$dom2->loadXML(''); +$attribute = $dom1->documentElement->getAttributeNode('foo:bar'); +$imported = $dom2->importNode($attribute); +$dom2->documentElement->setAttributeNodeNS($imported); + +echo $dom1->saveXML(); +echo $dom2->saveXML(); + +echo "--- Non-default namespace test case with a default namespace in the destination ---\n"; + +$dom1 = new DOMDocument(); +$dom2 = new DOMDocument(); +$dom1->loadXML(''); +$dom2->loadXML(''); +$attribute = $dom1->documentElement->getAttributeNode('foo:bar'); +$imported = $dom2->importNode($attribute); +$dom2->documentElement->setAttributeNodeNS($imported); + +echo $dom1->saveXML(); +echo $dom2->saveXML(); + +echo "--- Default namespace test case ---\n"; + +// We don't expect the namespace to be imported because default namespaces on the same element don't apply to attributes +// but the attribute should be imported +$dom1 = new DOMDocument(); +$dom2 = new DOMDocument(); +$dom1->loadXML(''); +$dom2->loadXML(''); +$attribute = $dom1->documentElement->getAttributeNode('bar'); +$imported = $dom2->importNode($attribute); +$dom2->documentElement->setAttributeNodeNS($imported); + +echo $dom1->saveXML(); +echo $dom2->saveXML(); + +?> +--EXPECT-- +--- Non-default namespace test case without a default namespace in the destination --- + + + + +--- Non-default namespace test case with a default namespace in the destination --- + + + + +--- Default namespace test case --- + + + + diff --git a/ext/dom/tests/DOMElement_setAttributeNS_prefix_conflict.phpt b/ext/dom/tests/DOMElement_setAttributeNS_prefix_conflict.phpt new file mode 100644 index 0000000000000..fc491b59ea31d --- /dev/null +++ b/ext/dom/tests/DOMElement_setAttributeNS_prefix_conflict.phpt @@ -0,0 +1,35 @@ +--TEST-- +DOMElement::setAttributeNS() with prefix name conflict +--EXTENSIONS-- +dom +--FILE-- +loadXML(''); +$dom->documentElement->setAttributeNS('http://php.net/2', 'foo:bar', 'no1'); +echo $dom->saveXML(); +$dom->documentElement->setAttributeNS('http://php.net/2', 'bar', 'no2'); +echo $dom->saveXML(); + +echo "--- Default namespace test case ---\n"; + +$dom = new DOMDocument(); +$dom->loadXML(''); +$dom->documentElement->setAttributeNS('http://php.net/2', 'bar', 'no1'); +echo $dom->saveXML(); +$dom->documentElement->setAttributeNS('http://php.net/2', 'bar', 'no2'); +echo $dom->saveXML(); +?> +--EXPECT-- +--- Non-default namespace test case --- + + + + +--- Default namespace test case --- + + + + diff --git a/ext/dom/tests/bug80927.phpt b/ext/dom/tests/bug80927.phpt new file mode 100644 index 0000000000000..5c12e8fb867d9 --- /dev/null +++ b/ext/dom/tests/bug80927.phpt @@ -0,0 +1,89 @@ +--TEST-- +Bug #80927 (Removing documentElement after creating attribute node: possible use-after-free) +--EXTENSIONS-- +dom +--FILE-- +appendChild($dom->createElement("html")); + $a = $dom->createAttributeNS("fake_ns", "test:test"); + $dom->removeChild($dom->documentElement); + + echo $dom->saveXML(); + + var_dump($a->namespaceURI); + var_dump($a->prefix); +} + +enum Test2Variation { + case REMOVE_DOCUMENT; + case REMOVE_CHILD; +} + +function test2(Test2Variation $variation) { + $dom = new DOMDocument(); + $dom->appendChild($dom->createElement("html")); + $a = $dom->createAttributeNS("fake_ns", "test:test"); + + $foo = $dom->appendChild($dom->createElement('foo')); + $foo->appendChild($dom->documentElement); + + unset($foo); + + match ($variation) { + Test2Variation::REMOVE_DOCUMENT => $dom->documentElement->remove(), + Test2Variation::REMOVE_CHILD => $dom->documentElement->firstElementChild->remove(), + }; + + echo $dom->saveXML(); + + var_dump($a->namespaceURI); + var_dump($a->prefix); +} + +function test3() { + $dom = new DOMDocument(); + $dom->appendChild($dom->createElement('html')); + $foobar = $dom->documentElement->appendChild($dom->createElementNS('some:ns', 'foo:bar')); + $foobar2 = $foobar->appendChild($dom->createElementNS('some:ns', 'foo:bar2')); + $foobar->remove(); + unset($foobar); + $dom->documentElement->appendChild($foobar2); + + echo $dom->saveXML(); + + var_dump($foobar2->namespaceURI); + var_dump($foobar2->prefix); +} + +echo "--- Remove namespace declarator for attribute, root ---\n"; +test1(); +echo "--- Remove namespace declarator for attribute, moved root ---\n"; +test2(Test2Variation::REMOVE_DOCUMENT); +echo "--- Remove namespace declarator for attribute, moved root child ---\n"; +test2(Test2Variation::REMOVE_CHILD); +echo "--- Remove namespace declarator for element ---\n"; +test3(); + +?> +--EXPECT-- +--- Remove namespace declarator for attribute, root --- + +string(7) "fake_ns" +string(4) "test" +--- Remove namespace declarator for attribute, moved root --- + +string(7) "fake_ns" +string(4) "test" +--- Remove namespace declarator for attribute, moved root child --- + + +string(7) "fake_ns" +string(4) "test" +--- Remove namespace declarator for element --- + + +string(7) "some:ns" +string(3) "foo" diff --git a/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_with_prefix.phpt b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_with_prefix.phpt new file mode 100644 index 0000000000000..1ca679d576d2f --- /dev/null +++ b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_with_prefix.phpt @@ -0,0 +1,36 @@ +--TEST-- +DOMDocument::createAttributeNS() with prefix name conflict - setAttributeNodeNS variation, with prefix +--EXTENSIONS-- +dom +--FILE-- +appendChild($doc->createElement('container')); + +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns2', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns3', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns4', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +?> +--EXPECT-- +NULL + + + +NULL + + + +NULL + + + +NULL + + diff --git a/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_without_prefix.phpt b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_without_prefix.phpt new file mode 100644 index 0000000000000..6ab6c2292a787 --- /dev/null +++ b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttributeNS_without_prefix.phpt @@ -0,0 +1,36 @@ +--TEST-- +DOMDocument::createAttributeNS() with prefix name conflict - setAttributeNodeNS variation, without prefix +--EXTENSIONS-- +dom +--FILE-- +appendChild($doc->createElement('container')); + +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns2', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns3', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNodeNS($doc->createAttributeNS('http://php.net/ns4', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +?> +--EXPECT-- +NULL + + + +NULL + + + +NULL + + + +NULL + + diff --git a/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_mixed_prefix.phpt b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_mixed_prefix.phpt new file mode 100644 index 0000000000000..a53d7304dc87e --- /dev/null +++ b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_mixed_prefix.phpt @@ -0,0 +1,20 @@ +--TEST-- +DOMDocument::createAttributeNS() with prefix name conflict - setAttributeNode variation (DOM Level 3), mixed +--EXTENSIONS-- +dom +--FILE-- +appendChild($doc->createElement('container')); + +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +?> +--EXPECT-- +NULL +string(18) "http://php.net/ns1" + + diff --git a/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_with_prefix.phpt b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_with_prefix.phpt new file mode 100644 index 0000000000000..161eadd353ba6 --- /dev/null +++ b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_with_prefix.phpt @@ -0,0 +1,36 @@ +--TEST-- +DOMDocument::createAttributeNS() with prefix name conflict - setAttributeNode variation (DOM Level 3), with prefix +--EXTENSIONS-- +dom +--FILE-- +appendChild($doc->createElement('container')); + +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns2', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns3', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns4', 'foo:hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +?> +--EXPECT-- +NULL + + + +string(18) "http://php.net/ns1" + + + +string(18) "http://php.net/ns2" + + + +string(18) "http://php.net/ns3" + + diff --git a/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_without_prefix.phpt b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_without_prefix.phpt new file mode 100644 index 0000000000000..34717ff6ab5be --- /dev/null +++ b/ext/dom/tests/createAttributeNS_prefix_conflicts/setAttribute_without_prefix.phpt @@ -0,0 +1,36 @@ +--TEST-- +DOMDocument::createAttributeNS() with prefix name conflict - setAttributeNode variation (DOM Level 3), without prefix +--EXTENSIONS-- +dom +--FILE-- +appendChild($doc->createElement('container')); + +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns1', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns2', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns3', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; +var_dump($doc->documentElement->setAttributeNode($doc->createAttributeNS('http://php.net/ns4', 'hello'))?->namespaceURI); +echo $doc->saveXML(), "\n"; + +?> +--EXPECT-- +NULL + + + +string(18) "http://php.net/ns1" + + + +string(18) "http://php.net/ns2" + + + +string(18) "http://php.net/ns3" + + diff --git a/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt b/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt index 64f2fbfa007a9..b43f7c34bae1d 100644 --- a/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt +++ b/ext/dom/tests/delayed_freeing/namespace_definition_crash_in_attribute.phpt @@ -39,9 +39,9 @@ echo $doc->saveXML($attr3->parentNode), "\n"; ?> --EXPECT-- - + - + string(15) "hello content 2" string(0) "" string(8) "some:ns2" @@ -49,5 +49,5 @@ NULL string(0) "" string(7) "some:ns" string(7) "some:ns" - hello="" + default1:hello="" diff --git a/ext/dom/tests/gh12002.phpt b/ext/dom/tests/gh12002.phpt new file mode 100644 index 0000000000000..7d1ae944646ae --- /dev/null +++ b/ext/dom/tests/gh12002.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-12002 (DOMDocument::encoding memory leak with invalid encoding) +--EXTENSIONS-- +dom +--FILE-- +encoding = make_nonconst('utf-8'); +var_dump($dom->encoding); +try { + $dom->encoding = make_nonconst('foobar'); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +var_dump($dom->encoding); +$dom->encoding = make_nonconst('utf-16le'); +var_dump($dom->encoding); +try { + $dom->encoding = NULL; +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +var_dump($dom->encoding); + +?> +--EXPECT-- +string(5) "utf-8" +Invalid document encoding +string(5) "utf-8" +string(8) "utf-16le" +Invalid document encoding +string(8) "utf-16le" diff --git a/ext/exif/exif.c b/ext/exif/exif.c index fa5ec9c855d4a..aa83fd969ef42 100644 --- a/ext/exif/exif.c +++ b/ext/exif/exif.c @@ -234,18 +234,6 @@ static ssize_t exif_read_from_stream_file_looped(php_stream *stream, char *buf, return total_read; } -/* {{{ php_strnlen - * get length of string if buffer if less than buffer size or buffer size */ -static size_t php_strnlen(char* str, size_t maxlen) { - size_t len = 0; - - if (str && maxlen && *str) { - do { - len++; - } while (--maxlen && *(++str)); - } - return len; -} /* }}} */ /* {{{ error messages */ @@ -2223,7 +2211,7 @@ static void exif_iif_add_value(image_info_type *image_info, int section_index, c value = NULL; } if (value) { - length = (int)php_strnlen(value, length); + length = (int)zend_strnlen(value, length); info_value->s = estrndup(value, length); info_data->length = length; } else { @@ -2254,7 +2242,7 @@ static void exif_iif_add_value(image_info_type *image_info, int section_index, c } if (value) { if (tag == TAG_MAKER_NOTE) { - length = (int) php_strnlen(value, length); + length = (int) zend_strnlen(value, length); } /* do not recompute length here */ @@ -3034,11 +3022,11 @@ static int exif_process_string(char **result, char *value, size_t byte_count) { /* we cannot use strlcpy - here the problem is that we cannot use strlen to * determine length of string and we cannot use strlcpy with len=byte_count+1 * because then we might get into an EXCEPTION if we exceed an allocated - * memory page...so we use php_strnlen in conjunction with memcpy and add the NUL + * memory page...so we use zend_strnlen in conjunction with memcpy and add the NUL * char. * estrdup would sometimes allocate more memory and does not return length */ - if ((byte_count=php_strnlen(value, byte_count)) > 0) { + if ((byte_count=zend_strnlen(value, byte_count)) > 0) { return exif_process_undefined(result, value, byte_count); } (*result) = estrndup("", 1); /* force empty string */ @@ -3412,7 +3400,7 @@ static bool exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entr switch(tag) { case TAG_COPYRIGHT: /* check for " NUL NUL" */ - if (byte_count>1 && (length=php_strnlen(value_ptr, byte_count)) > 0) { + if (byte_count>1 && (length=zend_strnlen(value_ptr, byte_count)) > 0) { if (lengthCopyrightPhotographer); @@ -3776,10 +3764,10 @@ static void exif_process_APP12(image_info_type *ImageInfo, char *buffer, size_t { size_t l1, l2=0; - if ((l1 = php_strnlen(buffer+2, length-2)) > 0) { + if ((l1 = zend_strnlen(buffer+2, length-2)) > 0) { exif_iif_add_tag(ImageInfo, SECTION_APP12, "Company", TAG_NONE, TAG_FMT_STRING, l1, buffer+2, l1); if (length > 2+l1+1) { - l2 = php_strnlen(buffer+2+l1+1, length-2-l1-1); + l2 = zend_strnlen(buffer+2+l1+1, length-2-l1-1); exif_iif_add_tag(ImageInfo, SECTION_APP12, "Info", TAG_NONE, TAG_FMT_STRING, l2, buffer+2+l1+1, l2); } } diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c index 93e83a95b5f1c..75f78dd174238 100644 --- a/ext/iconv/iconv.c +++ b/ext/iconv/iconv.c @@ -44,6 +44,14 @@ #undef iconv #endif +#if defined(__NetBSD__) +// unfortunately, netbsd has still the old non posix conformant signature +// libiconv tends to match the eventual system's iconv too. +#define ICONV_CONST const +#else +#define ICONV_CONST +#endif + #include "zend_smart_str.h" #include "ext/standard/base64.h" #include "ext/standard/quot_print.h" @@ -360,7 +368,7 @@ static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, out_p = ZSTR_VAL((d)->s) + ZSTR_LEN((d)->s); - if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { + if (iconv(cd, (ICONV_CONST char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { switch (errno) { case EINVAL: return PHP_ICONV_ERR_ILLEGAL_CHAR; @@ -456,7 +464,7 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len, out_p = ZSTR_VAL(out_buf); while (in_left > 0) { - result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left); + result = iconv(cd, (ICONV_CONST char **) &in_p, &in_left, (char **) &out_p, &out_left); out_size = bsz - out_left; if (result == (size_t)(-1)) { if (ignore_ilseq && errno == EILSEQ) { @@ -576,7 +584,7 @@ static php_iconv_err_t _php_iconv_strlen(size_t *pretval, const char *str, size_ more = in_left > 0; - iconv(cd, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); + iconv(cd, more ? (ICONV_CONST char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); if (out_left == sizeof(buf)) { break; } else { @@ -683,7 +691,7 @@ static php_iconv_err_t _php_iconv_substr(smart_str *pretval, more = in_left > 0 && len > 0; - iconv(cd1, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); + iconv(cd1, more ? (ICONV_CONST char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); if (out_left == sizeof(buf)) { break; } @@ -805,7 +813,7 @@ static php_iconv_err_t _php_iconv_strpos(size_t *pretval, more = in_left > 0; - iconv_ret = iconv(cd, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); + iconv_ret = iconv(cd, more ? (ICONV_CONST char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); if (out_left == sizeof(buf)) { break; } @@ -1012,7 +1020,7 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn out_left = out_size - out_reserved; - if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { + if (iconv(cd, (ICONV_CONST char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { switch (errno) { case EINVAL: err = PHP_ICONV_ERR_ILLEGAL_CHAR; @@ -1096,7 +1104,7 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn out_p = buf; out_left = out_size; - if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { + if (iconv(cd, (ICONV_CONST char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { switch (errno) { case EINVAL: err = PHP_ICONV_ERR_ILLEGAL_CHAR; @@ -2365,7 +2373,7 @@ static int php_iconv_stream_filter_append_bucket( tcnt = self->stub_len; while (tcnt > 0) { - if (iconv(self->cd, &pt, &tcnt, &pd, &ocnt) == (size_t)-1) { + if (iconv(self->cd, (ICONV_CONST char **)&pt, &tcnt, &pd, &ocnt) == (size_t)-1) { switch (errno) { case EILSEQ: php_error_docref(NULL, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset); @@ -2431,7 +2439,7 @@ static int php_iconv_stream_filter_append_bucket( while (icnt > 0) { if ((ps == NULL ? iconv(self->cd, NULL, NULL, &pd, &ocnt): - iconv(self->cd, (char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) { + iconv(self->cd, (ICONV_CONST char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) { switch (errno) { case EILSEQ: php_error_docref(NULL, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset); diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 97ceec45ddbfd..24ba80bd5de39 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -103,6 +103,39 @@ zend_module_entry libxml_module_entry = { /* }}} */ +static void php_libxml_set_old_ns_list(xmlDocPtr doc, xmlNsPtr first, xmlNsPtr last) +{ + if (UNEXPECTED(doc == NULL)) { + return; + } + + ZEND_ASSERT(last->next == NULL); + + /* Note: we'll use a prepend strategy instead of append to + * make sure we don't lose performance when the list is long. + * As libxml2 could assume the xml node is the first one, we'll place our + * new entries after the first one. */ + + if (UNEXPECTED(doc->oldNs == NULL)) { + doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); + if (doc->oldNs == NULL) { + return; + } + memset(doc->oldNs, 0, sizeof(xmlNs)); + doc->oldNs->type = XML_LOCAL_NAMESPACE; + doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE); + doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml"); + } else { + last->next = doc->oldNs->next; + } + doc->oldNs->next = first; +} + +PHP_LIBXML_API void php_libxml_set_old_ns(xmlDocPtr doc, xmlNsPtr ns) +{ + php_libxml_set_old_ns_list(doc, ns, ns); +} + static void php_libxml_unlink_entity(void *data, void *table, const xmlChar *name) { xmlEntityPtr entity = data; @@ -211,8 +244,41 @@ static void php_libxml_node_free(xmlNodePtr node) xmlHashScan(dtd->pentities, php_libxml_unlink_entity, dtd->pentities); /* No unlinking of notations, see remark above at case XML_NOTATION_NODE. */ } - ZEND_FALLTHROUGH; + xmlFreeNode(node); + break; } + case XML_ELEMENT_NODE: + if (node->nsDef && node->doc) { + /* Make the namespace declaration survive the destruction of the holding element. + * This prevents a use-after-free on the namespace declaration. + * + * The main problem is that libxml2 doesn't have a reference count on the namespace declaration. + * We don't actually need to save the namespace declaration if we know the subtree it belongs to + * has no references from userland. However, we can't know that without traversing the whole subtree + * (=> slow), or without adding some subtree metadata (=> also slow). + * So we have to assume we need to save everything. + * + * However, namespace declarations are quite rare in comparison to other node types. + * Most node types are either elements, text or attributes. + * And you only need one namespace declaration per namespace (in principle). + * So I expect the number of namespace declarations to be low for an average XML document. + * + * In the worst possible case we have to save all namespace declarations when we for example remove + * the whole document. But given the above reasoning this likely won't be a lot of declarations even + * in the worst case. + * A single declaration only takes about 48 bytes of memory, and I don't expect the worst case to occur + * very often (why would you remove the whole document?). + */ + xmlNsPtr ns = node->nsDef; + xmlNsPtr last = ns; + while (last->next) { + last = last->next; + } + php_libxml_set_old_ns_list(node->doc, ns, last); + node->nsDef = NULL; + } + xmlFreeNode(node); + break; default: xmlFreeNode(node); break; diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h index 3bd5202f58790..78a5df8f97e66 100644 --- a/ext/libxml/php_libxml.h +++ b/ext/libxml/php_libxml.h @@ -134,6 +134,7 @@ PHP_LIBXML_API int php_libxml_xmlCheckUTF8(const unsigned char *s); PHP_LIBXML_API void php_libxml_switch_context(zval *context, zval *oldcontext); PHP_LIBXML_API void php_libxml_issue_error(int level, const char *msg); PHP_LIBXML_API bool php_libxml_disable_entity_loader(bool disable); +PHP_LIBXML_API void php_libxml_set_old_ns(xmlDocPtr doc, xmlNsPtr ns); /* Init/shutdown functions*/ PHP_LIBXML_API void php_libxml_initialize(void); diff --git a/ext/mysqli/mysqli.stub.php b/ext/mysqli/mysqli.stub.php index bb39ab5bbd147..4fd55442b7447 100644 --- a/ext/mysqli/mysqli.stub.php +++ b/ext/mysqli/mysqli.stub.php @@ -1144,7 +1144,7 @@ public function fetch_column(int $column = 0): null|int|float|string|false {} * @tentative-return-type * @alias mysqli_field_seek */ - public function field_seek(int $index): bool {} + public function field_seek(int $index): true {} // TODO make return type void /** * @tentative-return-type @@ -1457,7 +1457,7 @@ function mysqli_fetch_column(mysqli_result $result, int $column = 0): null|int|f function mysqli_field_count(mysqli $mysql): int {} -function mysqli_field_seek(mysqli_result $result, int $index): bool {} +function mysqli_field_seek(mysqli_result $result, int $index): true {} // TODO make return type void function mysqli_field_tell(mysqli_result $result): int {} diff --git a/ext/mysqli/mysqli_arginfo.h b/ext/mysqli/mysqli_arginfo.h index eacfc83a67103..ee4a2013809e9 100644 --- a/ext/mysqli/mysqli_arginfo.h +++ b/ext/mysqli/mysqli_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 656fe3f3475bb2f43d89ebf34361940e2f746373 */ + * Stub hash: a54ef005e9535458e886b7845a25a1c742a114ac */ 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) @@ -130,7 +130,7 @@ ZEND_END_ARG_INFO() #define arginfo_mysqli_field_count arginfo_mysqli_errno -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_field_seek, 0, 2, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_field_seek, 0, 2, IS_TRUE, 0) ZEND_ARG_OBJ_INFO(0, result, mysqli_result, 0) ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -628,7 +628,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_mysqli_result_fetch_column ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, column, IS_LONG, 0, "0") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_mysqli_result_field_seek, 0, 1, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_mysqli_result_field_seek, 0, 1, IS_TRUE, 0) ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0) ZEND_END_ARG_INFO() diff --git a/ext/mysqli/tests/gh8978.phpt b/ext/mysqli/tests/gh8978.phpt new file mode 100644 index 0000000000000..92de63b381ca8 --- /dev/null +++ b/ext/mysqli/tests/gh8978.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug GH-8267 (Invalid error message when connection via SSL fails) +--EXTENSIONS-- +mysqli +--SKIPIF-- + +--FILE-- +getMessage()."\n"; +} + +echo 'done!'; +?> +--EXPECTF-- +Warning: failed loading cafile stream: `x509.ca' in %s +Cannot connect to MySQL using SSL +done! diff --git a/ext/mysqlnd/config9.m4 b/ext/mysqlnd/config9.m4 index 188023cbb5cde..80a6301076566 100644 --- a/ext/mysqlnd/config9.m4 +++ b/ext/mysqlnd/config9.m4 @@ -6,8 +6,8 @@ PHP_ARG_ENABLE([mysqlnd], [no], [yes]) -PHP_ARG_ENABLE([mysqlnd_compression_support], - [whether to disable compressed protocol support in mysqlnd], +PHP_ARG_ENABLE([mysqlnd-compression-support], + [whether to enable compressed protocol support in mysqlnd], [AS_HELP_STRING([--disable-mysqlnd-compression-support], [Disable support for the MySQL compressed protocol in mysqlnd])], [yes], diff --git a/ext/mysqlnd/mysqlnd_commands.c b/ext/mysqlnd/mysqlnd_commands.c index eba60c2cb8e08..ba214e5ff776a 100644 --- a/ext/mysqlnd/mysqlnd_commands.c +++ b/ext/mysqlnd/mysqlnd_commands.c @@ -542,6 +542,8 @@ MYSQLND_METHOD(mysqlnd_command, enable_ssl)(MYSQLND_CONN_DATA * const conn, cons conn->vio->data->m.set_client_option(conn->vio, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify); if (FAIL == conn->vio->data->m.enable_ssl(conn->vio)) { + SET_CONNECTION_STATE(&conn->state, CONN_QUIT_SENT); + SET_CLIENT_ERROR(conn->error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "Cannot connect to MySQL using SSL"); goto end; } } diff --git a/ext/mysqlnd/mysqlnd_connection.c b/ext/mysqlnd/mysqlnd_connection.c index 05b0dab63b007..d46029889fad0 100644 --- a/ext/mysqlnd/mysqlnd_connection.c +++ b/ext/mysqlnd/mysqlnd_connection.c @@ -725,19 +725,20 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, DBG_RETURN(PASS); } err: - if (transport.s) { - mnd_sprintf_free(transport.s); - transport.s = NULL; - } - - DBG_ERR_FMT("[%u] %.128s (trying to connect via %s)", conn->error_info->error_no, conn->error_info->error, conn->scheme.s); + DBG_ERR_FMT("[%u] %.128s (trying to connect via %s)", conn->error_info->error_no, conn->error_info->error, transport.s ? transport.s : conn->scheme.s); if (!conn->error_info->error_no) { + /* There was an unknown error if the connection failed but we have no error number */ char * msg; - mnd_sprintf(&msg, 0, "%s (trying to connect via %s)",conn->error_info->error, conn->scheme.s); + mnd_sprintf(&msg, 0, "Unknown error while trying to connect via %s", transport.s ? transport.s : conn->scheme.s); SET_CLIENT_ERROR(conn->error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, msg); mnd_sprintf_free(msg); } + if (transport.s) { + mnd_sprintf_free(transport.s); + transport.s = NULL; + } + conn->m->free_contents(conn); MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_FAILURE); DBG_RETURN(FAIL); diff --git a/ext/mysqlnd/mysqlnd_vio.c b/ext/mysqlnd/mysqlnd_vio.c index 79fc92d500a25..312bf7e2782ff 100644 --- a/ext/mysqlnd/mysqlnd_vio.c +++ b/ext/mysqlnd/mysqlnd_vio.c @@ -569,7 +569,6 @@ MYSQLND_METHOD(mysqlnd_vio, enable_ssl)(MYSQLND_VIO * const net) php_stream_xport_crypto_enable(net_stream, 1) < 0) { DBG_ERR("Cannot connect to MySQL by using SSL"); - php_error_docref(NULL, E_WARNING, "Cannot connect to MySQL by using SSL"); DBG_RETURN(FAIL); } net->data->ssl = TRUE; diff --git a/ext/odbc/odbc.stub.php b/ext/odbc/odbc.stub.php index 9606a38633f34..3c03090ed08e5 100644 --- a/ext/odbc/odbc.stub.php +++ b/ext/odbc/odbc.stub.php @@ -2,520 +2,442 @@ /** @generate-class-entries */ -/** - * @var string - * @cvalue PHP_ODBC_TYPE - */ -const ODBC_TYPE = UNKNOWN; -/** - * @var int - * @cvalue PHP_ODBC_BINMODE_PASSTHRU - */ -const ODBC_BINMODE_PASSTHRU = UNKNOWN; -/** - * @var int - * @cvalue PHP_ODBC_BINMODE_RETURN - */ -const ODBC_BINMODE_RETURN = UNKNOWN; -/** - * @var int - * @cvalue PHP_ODBC_BINMODE_CONVERT - */ -const ODBC_BINMODE_CONVERT = UNKNOWN; - -/* Define Constants for options. These Constants are defined in */ - -/** - * @var int - * @cvalue SQL_ODBC_CURSORS - */ -const SQL_ODBC_CURSORS = UNKNOWN; -/** - * @var int - * @cvalue SQL_CUR_USE_DRIVER - */ -const SQL_CUR_USE_DRIVER = UNKNOWN; -/** - * @var int - * @cvalue SQL_CUR_USE_IF_NEEDED - */ -const SQL_CUR_USE_IF_NEEDED = UNKNOWN; -/** - * @var int - * @cvalue SQL_CUR_USE_ODBC - */ -const SQL_CUR_USE_ODBC = UNKNOWN; - -/** - * @var int - * @cvalue SQL_CONCURRENCY - */ -const SQL_CONCURRENCY = UNKNOWN; -/** - * @var int - * @cvalue SQL_CONCUR_READ_ONLY - */ -const SQL_CONCUR_READ_ONLY = UNKNOWN; -/** - * @var int - * @cvalue SQL_CONCUR_LOCK - */ -const SQL_CONCUR_LOCK = UNKNOWN; -/** - * @var int - * @cvalue SQL_CONCUR_ROWVER - */ -const SQL_CONCUR_ROWVER = UNKNOWN; -/** - * @var int - * @cvalue SQL_CONCUR_VALUES - */ -const SQL_CONCUR_VALUES = UNKNOWN; - -/** - * @var int - * @cvalue SQL_CURSOR_TYPE - */ -const SQL_CURSOR_TYPE = UNKNOWN; -/** - * @var int - * @cvalue SQL_CURSOR_FORWARD_ONLY - */ -const SQL_CURSOR_FORWARD_ONLY = UNKNOWN; -/** - * @var int - * @cvalue SQL_CURSOR_KEYSET_DRIVEN - */ -const SQL_CURSOR_KEYSET_DRIVEN = UNKNOWN; -/** - * @var int - * @cvalue SQL_CURSOR_DYNAMIC - */ -const SQL_CURSOR_DYNAMIC = UNKNOWN; -/** - * @var int - * @cvalue SQL_CURSOR_STATIC - */ -const SQL_CURSOR_STATIC = UNKNOWN; - -/** - * @var int - * @cvalue SQL_KEYSET_SIZE - */ -const SQL_KEYSET_SIZE = UNKNOWN; - -/* these are for the Data Source type */ - -/** - * @var int - * @cvalue SQL_FETCH_FIRST - */ -const SQL_FETCH_FIRST = UNKNOWN; -/** - * @var int - * @cvalue SQL_FETCH_NEXT - */ -const SQL_FETCH_NEXT = UNKNOWN; - -/* register the standard data types */ - -/** - * @var int - * @cvalue SQL_CHAR - */ -const SQL_CHAR = UNKNOWN; -/** - * @var int - * @cvalue SQL_VARCHAR - */ -const SQL_VARCHAR = UNKNOWN; -/** - * @var int - * @cvalue SQL_LONGVARCHAR - */ -const SQL_LONGVARCHAR = UNKNOWN; -/** - * @var int - * @cvalue SQL_DECIMAL - */ -const SQL_DECIMAL = UNKNOWN; -/** - * @var int - * @cvalue SQL_NUMERIC - */ -const SQL_NUMERIC = UNKNOWN; -/** - * @var int - * @cvalue SQL_BIT - */ -const SQL_BIT = UNKNOWN; -/** - * @var int - * @cvalue SQL_TINYINT - */ -const SQL_TINYINT = UNKNOWN; -/** - * @var int - * @cvalue SQL_SMALLINT - */ -const SQL_SMALLINT = UNKNOWN; -/** - * @var int - * @cvalue SQL_INTEGER - */ -const SQL_INTEGER = UNKNOWN; -/** - * @var int - * @cvalue SQL_BIGINT - */ -const SQL_BIGINT = UNKNOWN; -/** - * @var int - * @cvalue SQL_REAL - */ -const SQL_REAL = UNKNOWN; -/** - * @var int - * @cvalue SQL_FLOAT - */ -const SQL_FLOAT = UNKNOWN; -/** - * @var int - * @cvalue SQL_DOUBLE - */ -const SQL_DOUBLE = UNKNOWN; -/** - * @var int - * @cvalue SQL_BINARY - */ -const SQL_BINARY = UNKNOWN; -/** - * @var int - * @cvalue SQL_VARBINARY - */ -const SQL_VARBINARY = UNKNOWN; -/** - * @var int - * @cvalue SQL_LONGVARBINARY - */ -const SQL_LONGVARBINARY = UNKNOWN; -/** - * @var int - * @cvalue SQL_DATE - */ -const SQL_DATE = UNKNOWN; -/** - * @var int - * @cvalue SQL_TIME - */ -const SQL_TIME = UNKNOWN; -/** - * @var int - * @cvalue SQL_TIMESTAMP - */ -const SQL_TIMESTAMP = UNKNOWN; - -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) -/** - * @var int - * @cvalue SQL_TYPE_DATE - */ -const SQL_TYPE_DATE = UNKNOWN; -/** - * @var int - * @cvalue SQL_TYPE_TIME - */ -const SQL_TYPE_TIME = UNKNOWN; -/** - * @var int - * @cvalue SQL_TYPE_TIMESTAMP - */ -const SQL_TYPE_TIMESTAMP = UNKNOWN; -/** - * @var int - * @cvalue SQL_WCHAR - */ -const SQL_WCHAR = UNKNOWN; -/** - * @var int - * @cvalue SQL_WVARCHAR - */ -const SQL_WVARCHAR = UNKNOWN; -/** - * @var int - * @cvalue SQL_WLONGVARCHAR - */ -const SQL_WLONGVARCHAR = UNKNOWN; - -/* SQLSpecialColumns values */ - -/** - * @var int - * @cvalue SQL_BEST_ROWID - */ -const SQL_BEST_ROWID = UNKNOWN; -/** - * @var int - * @cvalue SQL_ROWVER - */ -const SQL_ROWVER = UNKNOWN; -/** - * @var int - * @cvalue SQL_SCOPE_CURROW - */ -const SQL_SCOPE_CURROW = UNKNOWN; -/** - * @var int - * @cvalue SQL_SCOPE_TRANSACTION - */ -const SQL_SCOPE_TRANSACTION = UNKNOWN; -/** - * @var int - * @cvalue SQL_SCOPE_SESSION - */ -const SQL_SCOPE_SESSION = UNKNOWN; -/** - * @var int - * @cvalue SQL_NO_NULLS - */ -const SQL_NO_NULLS = UNKNOWN; -/** - * @var int - * @cvalue SQL_NULLABLE - */ -const SQL_NULLABLE = UNKNOWN; - -/* SQLStatistics values */ - -/** - * @var int - * @cvalue SQL_INDEX_UNIQUE - */ -const SQL_INDEX_UNIQUE = UNKNOWN; -/** - * @var int - * @cvalue SQL_INDEX_ALL - */ -const SQL_INDEX_ALL = UNKNOWN; -/** - * @var int - * @cvalue SQL_ENSURE - */ -const SQL_ENSURE = UNKNOWN; -/** - * @var int - * @cvalue SQL_QUICK - */ -const SQL_QUICK = UNKNOWN; - -#endif - - - -function odbc_close_all(): void {} - -/** @param resource $statement */ -function odbc_binmode($statement, int $mode): bool {} - -/** @param resource $statement */ -function odbc_longreadlen($statement, int $length): bool {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_prepare($odbc, string $query) {} - -/** @param resource $statement */ -function odbc_execute($statement, array $params = []): bool {} - -/** @param resource $statement */ -function odbc_cursor($statement): string|false {} - -#ifdef HAVE_SQLDATASOURCES -/** @param resource $odbc */ -function odbc_data_source($odbc, int $fetch_type): array|null|false {} -#endif - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_exec($odbc, string $query) {} - -/** - * @param resource $odbc - * @return resource|false - * @alias odbc_exec - */ -function odbc_do($odbc, string $query) {} - -#ifdef PHP_ODBC_HAVE_FETCH_HASH -/** @param resource $statement */ -function odbc_fetch_object($statement, int $row = -1): stdClass|false {} - -/** @param resource $statement */ -function odbc_fetch_array($statement, int $row = -1): array|false {} -#endif - -/** - * @param resource $statement - * @param array $array - */ -function odbc_fetch_into($statement, &$array, int $row = 0): int|false {} - -/** @param resource $statement */ -function odbc_fetch_row($statement, ?int $row = null): bool {} - -/** @param resource $statement */ -function odbc_result($statement, string|int $field): string|bool|null {} - -/** - * @param resource $statement - * @deprecated - */ -function odbc_result_all($statement, string $format = ""): int|false {} - -/** @param resource $statement */ -function odbc_free_result($statement): bool {} - -/** - * @return resource|false - */ -function odbc_connect(string $dsn, string $user, #[\SensitiveParameter] string $password, int $cursor_option = SQL_CUR_USE_DRIVER) {} - -/** - * @return resource|false - */ -function odbc_pconnect(string $dsn, string $user, #[\SensitiveParameter] string $password, int $cursor_option = SQL_CUR_USE_DRIVER) {} - -/** @param resource $odbc */ -function odbc_close($odbc): void {} - -/** @param resource $statement */ -function odbc_num_rows($statement): int {} - -#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) -/** @param resource $statement */ -function odbc_next_result($statement): bool {} -#endif - -/** @param resource $statement */ -function odbc_num_fields($statement): int {} - -/** @param resource $statement */ -function odbc_field_name($statement, int $field): string|false {} - -/** @param resource $statement */ -function odbc_field_type($statement, int $field): string|false {} - -/** @param resource $statement */ -function odbc_field_len($statement, int $field): int|false {} - -/** - * @param resource $statement - * @alias odbc_field_len - */ -function odbc_field_precision($statement, int $field): int|false {} - -/** @param resource $statement */ -function odbc_field_scale($statement, int $field): int|false {} - -/** @param resource $statement */ -function odbc_field_num($statement, string $field): int|false {} - -/** @param resource $odbc */ -function odbc_autocommit($odbc, ?bool $enable = null): int|bool {} - -/** @param resource $odbc */ -function odbc_commit($odbc): bool {} - -/** @param resource $odbc */ -function odbc_rollback($odbc): bool {} - -/** @param resource|null $odbc */ -function odbc_error($odbc = null): string {} - -/** @param resource|null $odbc */ -function odbc_errormsg($odbc = null): string {} - -/** @param resource $odbc */ -function odbc_setoption($odbc, int $which, int $option, int $value): bool {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_tables($odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $types = null) {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_columns($odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $column = null) {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_gettypeinfo($odbc, int $data_type = 0) {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_primarykeys($odbc, ?string $catalog, string $schema, string $table) {} - -#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_procedurecolumns($odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null, ?string $column = null) {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_procedures($odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null) {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_foreignkeys($odbc, ?string $pk_catalog, string $pk_schema, string $pk_table, string $fk_catalog, string $fk_schema, string $fk_table) {} -#endif - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_specialcolumns($odbc, int $type, ?string $catalog, string $schema, string $table, int $scope, int $nullable) {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_statistics($odbc, ?string $catalog, string $schema, string $table, int $unique, int $accuracy) {} - -#if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_tableprivileges($odbc, ?string $catalog, string $schema, string $table) {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_columnprivileges($odbc, ?string $catalog, string $schema, string $table, string $column) {} -#endif - -/* odbc_utils.c */ - -function odbc_connection_string_is_quoted(string $str): bool {} - -function odbc_connection_string_should_quote(string $str): bool {} - -function odbc_connection_string_quote(string $str): string {} +namespace ODBC { + /** + * @strict-properties + * @not-serializable + */ + class Connection + { + } + + /** + * @strict-properties + * @not-serializable + */ + class Result + { + } +} + +namespace { + /** + * @var string + * @cvalue PHP_ODBC_TYPE + */ + const ODBC_TYPE = UNKNOWN; + /** + * @var int + * @cvalue PHP_ODBC_BINMODE_PASSTHRU + */ + const ODBC_BINMODE_PASSTHRU = UNKNOWN; + /** + * @var int + * @cvalue PHP_ODBC_BINMODE_RETURN + */ + const ODBC_BINMODE_RETURN = UNKNOWN; + /** + * @var int + * @cvalue PHP_ODBC_BINMODE_CONVERT + */ + const ODBC_BINMODE_CONVERT = UNKNOWN; + + /* Define Constants for options. These Constants are defined in */ + + /** + * @var int + * @cvalue SQL_ODBC_CURSORS + */ + const SQL_ODBC_CURSORS = UNKNOWN; + /** + * @var int + * @cvalue SQL_CUR_USE_DRIVER + */ + const SQL_CUR_USE_DRIVER = UNKNOWN; + /** + * @var int + * @cvalue SQL_CUR_USE_IF_NEEDED + */ + const SQL_CUR_USE_IF_NEEDED = UNKNOWN; + /** + * @var int + * @cvalue SQL_CUR_USE_ODBC + */ + const SQL_CUR_USE_ODBC = UNKNOWN; + + /** + * @var int + * @cvalue SQL_CONCURRENCY + */ + const SQL_CONCURRENCY = UNKNOWN; + /** + * @var int + * @cvalue SQL_CONCUR_READ_ONLY + */ + const SQL_CONCUR_READ_ONLY = UNKNOWN; + /** + * @var int + * @cvalue SQL_CONCUR_LOCK + */ + const SQL_CONCUR_LOCK = UNKNOWN; + /** + * @var int + * @cvalue SQL_CONCUR_ROWVER + */ + const SQL_CONCUR_ROWVER = UNKNOWN; + /** + * @var int + * @cvalue SQL_CONCUR_VALUES + */ + const SQL_CONCUR_VALUES = UNKNOWN; + + /** + * @var int + * @cvalue SQL_CURSOR_TYPE + */ + const SQL_CURSOR_TYPE = UNKNOWN; + /** + * @var int + * @cvalue SQL_CURSOR_FORWARD_ONLY + */ + const SQL_CURSOR_FORWARD_ONLY = UNKNOWN; + /** + * @var int + * @cvalue SQL_CURSOR_KEYSET_DRIVEN + */ + const SQL_CURSOR_KEYSET_DRIVEN = UNKNOWN; + /** + * @var int + * @cvalue SQL_CURSOR_DYNAMIC + */ + const SQL_CURSOR_DYNAMIC = UNKNOWN; + /** + * @var int + * @cvalue SQL_CURSOR_STATIC + */ + const SQL_CURSOR_STATIC = UNKNOWN; + + /** + * @var int + * @cvalue SQL_KEYSET_SIZE + */ + const SQL_KEYSET_SIZE = UNKNOWN; + + /* these are for the Data Source type */ + + /** + * @var int + * @cvalue SQL_FETCH_FIRST + */ + const SQL_FETCH_FIRST = UNKNOWN; + /** + * @var int + * @cvalue SQL_FETCH_NEXT + */ + const SQL_FETCH_NEXT = UNKNOWN; + + /* register the standard data types */ + + /** + * @var int + * @cvalue SQL_CHAR + */ + const SQL_CHAR = UNKNOWN; + /** + * @var int + * @cvalue SQL_VARCHAR + */ + const SQL_VARCHAR = UNKNOWN; + /** + * @var int + * @cvalue SQL_LONGVARCHAR + */ + const SQL_LONGVARCHAR = UNKNOWN; + /** + * @var int + * @cvalue SQL_DECIMAL + */ + const SQL_DECIMAL = UNKNOWN; + /** + * @var int + * @cvalue SQL_NUMERIC + */ + const SQL_NUMERIC = UNKNOWN; + /** + * @var int + * @cvalue SQL_BIT + */ + const SQL_BIT = UNKNOWN; + /** + * @var int + * @cvalue SQL_TINYINT + */ + const SQL_TINYINT = UNKNOWN; + /** + * @var int + * @cvalue SQL_SMALLINT + */ + const SQL_SMALLINT = UNKNOWN; + /** + * @var int + * @cvalue SQL_INTEGER + */ + const SQL_INTEGER = UNKNOWN; + /** + * @var int + * @cvalue SQL_BIGINT + */ + const SQL_BIGINT = UNKNOWN; + /** + * @var int + * @cvalue SQL_REAL + */ + const SQL_REAL = UNKNOWN; + /** + * @var int + * @cvalue SQL_FLOAT + */ + const SQL_FLOAT = UNKNOWN; + /** + * @var int + * @cvalue SQL_DOUBLE + */ + const SQL_DOUBLE = UNKNOWN; + /** + * @var int + * @cvalue SQL_BINARY + */ + const SQL_BINARY = UNKNOWN; + /** + * @var int + * @cvalue SQL_VARBINARY + */ + const SQL_VARBINARY = UNKNOWN; + /** + * @var int + * @cvalue SQL_LONGVARBINARY + */ + const SQL_LONGVARBINARY = UNKNOWN; + /** + * @var int + * @cvalue SQL_DATE + */ + const SQL_DATE = UNKNOWN; + /** + * @var int + * @cvalue SQL_TIME + */ + const SQL_TIME = UNKNOWN; + /** + * @var int + * @cvalue SQL_TIMESTAMP + */ + const SQL_TIMESTAMP = UNKNOWN; + + #if (defined(ODBCVER) && (ODBCVER >= 0x0300)) + /** + * @var int + * @cvalue SQL_TYPE_DATE + */ + const SQL_TYPE_DATE = UNKNOWN; + /** + * @var int + * @cvalue SQL_TYPE_TIME + */ + const SQL_TYPE_TIME = UNKNOWN; + /** + * @var int + * @cvalue SQL_TYPE_TIMESTAMP + */ + const SQL_TYPE_TIMESTAMP = UNKNOWN; + /** + * @var int + * @cvalue SQL_WCHAR + */ + const SQL_WCHAR = UNKNOWN; + /** + * @var int + * @cvalue SQL_WVARCHAR + */ + const SQL_WVARCHAR = UNKNOWN; + /** + * @var int + * @cvalue SQL_WLONGVARCHAR + */ + const SQL_WLONGVARCHAR = UNKNOWN; + + /* SQLSpecialColumns values */ + + /** + * @var int + * @cvalue SQL_BEST_ROWID + */ + const SQL_BEST_ROWID = UNKNOWN; + /** + * @var int + * @cvalue SQL_ROWVER + */ + const SQL_ROWVER = UNKNOWN; + /** + * @var int + * @cvalue SQL_SCOPE_CURROW + */ + const SQL_SCOPE_CURROW = UNKNOWN; + /** + * @var int + * @cvalue SQL_SCOPE_TRANSACTION + */ + const SQL_SCOPE_TRANSACTION = UNKNOWN; + /** + * @var int + * @cvalue SQL_SCOPE_SESSION + */ + const SQL_SCOPE_SESSION = UNKNOWN; + /** + * @var int + * @cvalue SQL_NO_NULLS + */ + const SQL_NO_NULLS = UNKNOWN; + /** + * @var int + * @cvalue SQL_NULLABLE + */ + const SQL_NULLABLE = UNKNOWN; + + /* SQLStatistics values */ + + /** + * @var int + * @cvalue SQL_INDEX_UNIQUE + */ + const SQL_INDEX_UNIQUE = UNKNOWN; + /** + * @var int + * @cvalue SQL_INDEX_ALL + */ + const SQL_INDEX_ALL = UNKNOWN; + /** + * @var int + * @cvalue SQL_ENSURE + */ + const SQL_ENSURE = UNKNOWN; + /** + * @var int + * @cvalue SQL_QUICK + */ + const SQL_QUICK = UNKNOWN; + + #endif + + function odbc_close_all(): void {} + + function odbc_binmode(ODBC\Result $statement, int $mode): bool {} + + function odbc_longreadlen(ODBC\Result $statement, int $length): bool {} + + function odbc_prepare(ODBC\Connection $odbc, string $query): ODBC\Result|false {} + + function odbc_execute(ODBC\Result $statement, array $params = []): bool {} + + function odbc_cursor(ODBC\Result $statement): string|false {} + + #ifdef HAVE_SQLDATASOURCES + function odbc_data_source(ODBC\Connection $odbc, int $fetch_type): array|null|false {} + #endif + + function odbc_exec(ODBC\Connection $odbc, string $query): ODBC\Result|false {} + + /** @alias odbc_exec */ + function odbc_do(ODBC\Connection $odbc, string $query): ODBC\Result|false {} + + #ifdef PHP_ODBC_HAVE_FETCH_HASH + function odbc_fetch_object(ODBC\Result $statement, ?int $row = null): stdClass|false {} + + function odbc_fetch_array(ODBC\Result $statement, ?int $row = null): array|false {} + #endif + + /** @param array $array */ + function odbc_fetch_into(ODBC\Result $statement, &$array, ?int $row = null): int|false {} + + function odbc_fetch_row(ODBC\Result $statement, ?int $row = null): bool {} + + function odbc_result(ODBC\Result $statement, string|int $field): string|bool|null {} + + /** @deprecated */ + function odbc_result_all(ODBC\Result $statement, string $format = ""): int|false {} + + function odbc_free_result(ODBC\Result $statement): bool {} + + function odbc_connect(string $dsn, string $user, #[\SensitiveParameter] string $password, int $cursor_option = SQL_CUR_USE_DRIVER): ODBC\Connection|false {} + + function odbc_pconnect(string $dsn, string $user, #[\SensitiveParameter] string $password, int $cursor_option = SQL_CUR_USE_DRIVER): ODBC\Connection|false {} + + function odbc_close(ODBC\Connection $odbc): void {} + + function odbc_num_rows(ODBC\Result $statement): int {} + + #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) + function odbc_next_result(ODBC\Result $statement): bool {} + #endif + + function odbc_num_fields(ODBC\Result $statement): int {} + + function odbc_field_name(ODBC\Result $statement, int $field): string|false {} + + function odbc_field_type(ODBC\Result $statement, int $field): string|false {} + + function odbc_field_len(ODBC\Result $statement, int $field): int|false {} + + /** @alias odbc_field_len */ + function odbc_field_precision(ODBC\Result $statement, int $field): int|false {} + + function odbc_field_scale(ODBC\Result $statement, int $field): int|false {} + + function odbc_field_num(ODBC\Result $statement, string $field): int|false {} + + function odbc_autocommit(ODBC\Connection $odbc, ?bool $enable = null): int|bool {} + + function odbc_commit(ODBC\Connection $odbc): bool {} + + function odbc_rollback(ODBC\Connection $odbc): bool {} + + function odbc_error(?ODBC\Connection $odbc = null): string {} + + function odbc_errormsg(?ODBC\Connection $odbc = null): string {} + + function odbc_setoption(ODBC\Connection|ODBC\Result $odbc, int $which, int $option, int $value): bool {} + + function odbc_tables(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $types = null): ODBC\Result|false {} + + function odbc_columns(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $column = null): ODBC\Result|false {} + + function odbc_gettypeinfo(ODBC\Connection $odbc, int $data_type = 0): ODBC\Result|false {} + + function odbc_primarykeys(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table): ODBC\Result|false {} + + #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) + function odbc_procedurecolumns(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null, ?string $column = null): ODBC\Result|false {} + + function odbc_procedures(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null): ODBC\Result|false {} + + function odbc_foreignkeys(ODBC\Connection $odbc, ?string $pk_catalog, string $pk_schema, string $pk_table, string $fk_catalog, string $fk_schema, string $fk_table): ODBC\Result|false {} + #endif + + function odbc_specialcolumns(ODBC\Connection $odbc, int $type, ?string $catalog, string $schema, string $table, int $scope, int $nullable): ODBC\Result|false {} + + function odbc_statistics(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table, int $unique, int $accuracy): ODBC\Result|false {} + + #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) + function odbc_tableprivileges(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table): ODBC\Result|false {} + + function odbc_columnprivileges(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table, string $column): ODBC\Result|false {} + #endif + + /* odbc_utils.c */ + + function odbc_connection_string_is_quoted(string $str): bool {} + + function odbc_connection_string_should_quote(string $str): bool {} + + function odbc_connection_string_quote(string $str): string {} +} diff --git a/ext/odbc/odbc_arginfo.h b/ext/odbc/odbc_arginfo.h index 574d829daad42..b2f1619ce2d96 100644 --- a/ext/odbc/odbc_arginfo.h +++ b/ext/odbc/odbc_arginfo.h @@ -1,36 +1,36 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0417b68a519527b0ee916bad75116ffe4a3ad304 */ + * Stub hash: 4d41f8189da5268979026fa5f54d6acacc17e5be */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_close_all, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_binmode, 0, 2, _IS_BOOL, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO(0, mode, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_longreadlen, 0, 2, _IS_BOOL, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_prepare, 0, 0, 2) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_prepare, 0, 2, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_execute, 0, 1, _IS_BOOL, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, params, IS_ARRAY, 0, "[]") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_cursor, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_END_ARG_INFO() #if defined(HAVE_SQLDATASOURCES) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_data_source, 0, 2, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE) - ZEND_ARG_INFO(0, odbc) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, fetch_type, IS_LONG, 0) ZEND_END_ARG_INFO() #endif @@ -41,44 +41,44 @@ ZEND_END_ARG_INFO() #if defined(PHP_ODBC_HAVE_FETCH_HASH) ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_fetch_object, 0, 1, stdClass, MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, row, IS_LONG, 0, "-1") + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, row, IS_LONG, 1, "null") ZEND_END_ARG_INFO() #endif #if defined(PHP_ODBC_HAVE_FETCH_HASH) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_fetch_array, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, row, IS_LONG, 0, "-1") + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, row, IS_LONG, 1, "null") ZEND_END_ARG_INFO() #endif ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_fetch_into, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_INFO(1, array) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, row, IS_LONG, 0, "0") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, row, IS_LONG, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_fetch_row, 0, 1, _IS_BOOL, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, row, IS_LONG, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_result, 0, 2, MAY_BE_STRING|MAY_BE_BOOL|MAY_BE_NULL) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_MASK(0, field, MAY_BE_STRING|MAY_BE_LONG, NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_result_all, 0, 1, MAY_BE_LONG|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, format, IS_STRING, 0, "\"\"") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_free_result, 0, 1, _IS_BOOL, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_connect, 0, 0, 3) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_connect, 0, 3, ODBC\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, dsn, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, user, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, password, IS_STRING, 0) @@ -88,30 +88,30 @@ ZEND_END_ARG_INFO() #define arginfo_odbc_pconnect arginfo_odbc_connect ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_close, 0, 1, IS_VOID, 0) - ZEND_ARG_INFO(0, odbc) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_num_rows, 0, 1, IS_LONG, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_END_ARG_INFO() #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_next_result, 0, 1, _IS_BOOL, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_END_ARG_INFO() #endif #define arginfo_odbc_num_fields arginfo_odbc_num_rows ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_field_name, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO(0, field, IS_LONG, 0) ZEND_END_ARG_INFO() #define arginfo_odbc_field_type arginfo_odbc_field_name ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_field_len, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO(0, field, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -120,65 +120,65 @@ ZEND_END_ARG_INFO() #define arginfo_odbc_field_scale arginfo_odbc_field_len ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_field_num, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_autocommit, 0, 1, MAY_BE_LONG|MAY_BE_BOOL) - ZEND_ARG_INFO(0, odbc) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_commit, 0, 1, _IS_BOOL, 0) - ZEND_ARG_INFO(0, odbc) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_END_ARG_INFO() #define arginfo_odbc_rollback arginfo_odbc_commit ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_error, 0, 0, IS_STRING, 0) - ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, odbc, "null") + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, odbc, ODBC\\Connection, 1, "null") ZEND_END_ARG_INFO() #define arginfo_odbc_errormsg arginfo_odbc_error ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_setoption, 0, 4, _IS_BOOL, 0) - ZEND_ARG_INFO(0, odbc) + ZEND_ARG_OBJ_TYPE_MASK(0, odbc, ODBC\\Connection|ODBC\\Result, 0, NULL) ZEND_ARG_TYPE_INFO(0, which, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, value, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_tables, 0, 0, 1) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_tables, 0, 1, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, table, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, types, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_columns, 0, 0, 1) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_columns, 0, 1, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, table, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, column, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_gettypeinfo, 0, 0, 1) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_gettypeinfo, 0, 1, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, data_type, IS_LONG, 0, "0") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_primarykeys, 0, 0, 4) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_primarykeys, 0, 4, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) ZEND_END_ARG_INFO() #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_procedurecolumns, 0, 0, 1) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_procedurecolumns, 0, 1, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, procedure, IS_STRING, 1, "null") @@ -187,8 +187,8 @@ ZEND_END_ARG_INFO() #endif #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_procedures, 0, 0, 1) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_procedures, 0, 1, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, procedure, IS_STRING, 1, "null") @@ -196,8 +196,8 @@ ZEND_END_ARG_INFO() #endif #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_foreignkeys, 0, 0, 7) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_foreignkeys, 0, 7, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, pk_catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, pk_schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, pk_table, IS_STRING, 0) @@ -207,8 +207,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_foreignkeys, 0, 0, 7) ZEND_END_ARG_INFO() #endif -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_specialcolumns, 0, 0, 7) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_specialcolumns, 0, 7, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, type, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) @@ -217,8 +217,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_specialcolumns, 0, 0, 7) ZEND_ARG_TYPE_INFO(0, nullable, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_statistics, 0, 0, 6) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_statistics, 0, 6, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) @@ -227,8 +227,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_statistics, 0, 0, 6) ZEND_END_ARG_INFO() #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_tableprivileges, 0, 0, 4) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_tableprivileges, 0, 4, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) @@ -236,8 +236,8 @@ ZEND_END_ARG_INFO() #endif #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_columnprivileges, 0, 0, 5) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_columnprivileges, 0, 5, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) @@ -392,6 +392,16 @@ static const zend_function_entry ext_functions[] = { ZEND_FE_END }; + +static const zend_function_entry class_ODBC_Connection_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_ODBC_Result_methods[] = { + ZEND_FE_END +}; + static void register_odbc_symbols(int module_number) { REGISTER_STRING_CONSTANT("ODBC_TYPE", PHP_ODBC_TYPE, CONST_PERSISTENT); @@ -491,3 +501,25 @@ static void register_odbc_symbols(int module_number) zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "odbc_pconnect", sizeof("odbc_pconnect") - 1), 2, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0); } + +static zend_class_entry *register_class_ODBC_Connection(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ODBC", "Connection", class_ODBC_Connection_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE; + + return class_entry; +} + +static zend_class_entry *register_class_ODBC_Result(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ODBC", "Result", class_ODBC_Result_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE; + + return class_entry; +} diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 804e79b063636..9892b63baf2ca 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -29,6 +29,8 @@ #include "ext/standard/info.h" #include "ext/standard/php_string.h" #include "ext/standard/php_standard.h" +#include "Zend/zend_interfaces.h" +#include "zend_smart_str.h" #include "php_odbc.h" #include "php_odbc_includes.h" @@ -49,18 +51,135 @@ #include "odbc_arginfo.h" -/* - * not defined elsewhere - */ +#define CHECK_ODBC_CONNECTION(conn) \ + if (conn == NULL) { \ + zend_throw_error(NULL, "ODBC connection has already been closed"); \ + RETURN_THROWS(); \ + } -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif +#define CHECK_ODBC_RESULT(result) \ + if (result->conn_ptr == NULL) { \ + zend_throw_error(NULL, "ODBC result has already been closed"); \ + RETURN_THROWS(); \ + } void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent); +static void safe_odbc_disconnect(void *handle); + +static int le_pconn; + +static zend_class_entry *odbc_connection_ce, *odbc_result_ce; +static zend_object_handlers odbc_connection_object_handlers, odbc_result_object_handlers; + +static inline odbc_link *odbc_link_from_obj(zend_object *obj) { + return (odbc_link *)((char *)(obj) - XtOffsetOf(odbc_link, std)); +} + +#define Z_ODBC_LINK_P(zv) odbc_link_from_obj(Z_OBJ_P(zv)) +#define Z_ODBC_CONNECTION_P(zv) Z_ODBC_LINK_P(zv)->connection + +static zend_object *odbc_connection_create_object(zend_class_entry *class_type) { + odbc_link *intern = zend_object_alloc(sizeof(odbc_link), class_type); + + zend_object_std_init(&intern->std, class_type); + object_properties_init(&intern->std, class_type); + intern->std.handlers = &odbc_connection_object_handlers; + + return &intern->std; +} + +static zend_function *odbc_connection_get_constructor(zend_object *object) { + zend_throw_error(NULL, "Cannot directly construct ODBC\\Connection, use odbc_connect() or odbc_pconnect() instead"); + return NULL; +} + +static void odbc_link_free(odbc_link *link) +{ + /* If aborted via timer expiration, don't try to call any unixODBC function */ + if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { + safe_odbc_disconnect(link->connection->hdbc); + SQLFreeConnect(link->connection->hdbc); + SQLFreeEnv(link->connection->henv); + } + efree(link->connection); + link->connection = NULL; + ODBCG(num_links)--; + if (!link->persistent) { + zend_hash_del(&ODBCG(connections), link->hash); + } + zend_string_release(link->hash); +} + +static void odbc_connection_free_obj(zend_object *obj) +{ + odbc_link *link = odbc_link_from_obj(obj); + + if (link->connection) { + odbc_link_free(link); + } + + zend_object_std_dtor(&link->std); +} + +static inline odbc_result *odbc_result_from_obj(zend_object *obj) { + return (odbc_result *)((char *)(obj) - XtOffsetOf(odbc_result, std)); +} + +#define Z_ODBC_RESULT_P(zv) odbc_result_from_obj(Z_OBJ_P(zv)) -static int le_result, le_conn, le_pconn; +static zend_object *odbc_result_create_object(zend_class_entry *class_type) { + odbc_result *intern = zend_object_alloc(sizeof(odbc_result), class_type); + + zend_object_std_init(&intern->std, class_type); + object_properties_init(&intern->std, class_type); + intern->std.handlers = &odbc_result_object_handlers; + + return &intern->std; +} + +static zend_function *odbc_result_get_constructor(zend_object *object) { + zend_throw_error(NULL, "Cannot directly construct ODBC\\Result, use an appropriate odbc_* function instead"); + return NULL; +} + +static void odbc_result_free(odbc_result *res) +{ + int i; + + if (res->values) { + for(i = 0; i < res->numcols; i++) { + if (res->values[i].value) + efree(res->values[i].value); + } + efree(res->values); + res->values = NULL; + } + /* If aborted via timer expiration, don't try to call any unixODBC function */ + if (res->stmt && !(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { +#if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35) + SQLTransact(res->conn_ptr->henv, res->conn_ptr->hdbc, + (SQLUSMALLINT) SQL_COMMIT); +#endif + SQLFreeStmt(res->stmt,SQL_DROP); + /* We don't want the connection to be closed after the last statement has been closed + * Connections will be closed on shutdown + * zend_list_delete(res->conn_ptr->id); + */ + } + if (res->param_info) { + efree(res->param_info); + } + efree(res); +} + +static void odbc_result_free_obj(zend_object *obj) +{ + odbc_result *result = odbc_result_from_obj(obj); + + odbc_result_free(result); + + zend_object_std_dtor(&result->std); +} #define SAFE_SQL_NTS(n) ((SQLSMALLINT) ((n)?(SQL_NTS):0)) @@ -93,44 +212,18 @@ ZEND_TSRMLS_CACHE_DEFINE() ZEND_GET_MODULE(odbc) #endif -/* {{{ _free_odbc_result */ -static void _free_odbc_result(zend_resource *rsrc) -{ - odbc_result *res = (odbc_result *)rsrc->ptr; - int i; +static void close_results_with_connection(const odbc_connection *conn) { + zval *p; - if (res) { - if (res->values) { - for(i = 0; i < res->numcols; i++) { - if (res->values[i].value) - efree(res->values[i].value); - } - efree(res->values); - res->values = NULL; - } - /* If aborted via timer expiration, don't try to call any unixODBC function */ - if (res->stmt && !(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { -#if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35) - SQLTransact(res->conn_ptr->henv, res->conn_ptr->hdbc, - (SQLUSMALLINT) SQL_COMMIT); -#endif - SQLFreeStmt(res->stmt,SQL_DROP); - /* We don't want the connection to be closed after the last statement has been closed - * Connections will be closed on shutdown - * zend_list_delete(res->conn_ptr->id); - */ - } - if (res->param_info) { - efree(res->param_info); + ZEND_HASH_FOREACH_VAL(&ODBCG(results), p) { + odbc_result *result = Z_ODBC_RESULT_P(p); + if (result->conn_ptr == conn) { + odbc_result_free((odbc_result*) p); } - efree(res); - } + } ZEND_HASH_FOREACH_END(); } -/* }}} */ -/* {{{ safe_odbc_disconnect - * disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) - */ +/* disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) */ static void safe_odbc_disconnect( void *handle ) { int ret; @@ -142,51 +235,13 @@ static void safe_odbc_disconnect( void *handle ) SQLDisconnect( handle ); } } -/* }}} */ - -/* {{{ _close_odbc_conn */ -static void _close_odbc_conn(zend_resource *rsrc) -{ - zend_resource *p; - odbc_result *res; - - odbc_connection *conn = (odbc_connection *)rsrc->ptr; - - ZEND_HASH_FOREACH_PTR(&EG(regular_list), p) { - if (p->ptr && (p->type == le_result)) { - res = (odbc_result *)p->ptr; - if (res->conn_ptr == conn) { - zend_list_close(p); - } - } - } ZEND_HASH_FOREACH_END(); - - /* If aborted via timer expiration, don't try to call any unixODBC function */ - if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { - safe_odbc_disconnect(conn->hdbc); - SQLFreeConnect(conn->hdbc); - SQLFreeEnv(conn->henv); - } - efree(conn); - ODBCG(num_links)--; -} -/* }}} */ /* {{{ void _close_odbc_pconn */ static void _close_odbc_pconn(zend_resource *rsrc) { - zend_resource *p; - odbc_result *res; odbc_connection *conn = (odbc_connection *)rsrc->ptr; - ZEND_HASH_FOREACH_PTR(&EG(regular_list), p) { - if (p->ptr && (p->type == le_result)) { - res = (odbc_result *)p->ptr; - if (res->conn_ptr == conn) { - zend_list_close(p); - } - } - } ZEND_HASH_FOREACH_END(); + close_results_with_connection(conn); /* If aborted via timer expiration, don't try to call any unixODBC function */ if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { @@ -198,6 +253,7 @@ static void _close_odbc_pconn(zend_resource *rsrc) ODBCG(num_links)--; ODBCG(num_persistent)--; + rsrc->ptr = NULL; } /* }}} */ @@ -378,6 +434,8 @@ static PHP_GINIT_FUNCTION(odbc) ZEND_TSRMLS_CACHE_UPDATE(); #endif odbc_globals->num_persistent = 0; + zend_hash_init(&odbc_globals->results, 0, NULL, NULL, 1); + zend_hash_init(&odbc_globals->connections, 0, NULL, NULL, 1); } /* {{{ PHP_MINIT_FUNCTION */ @@ -389,11 +447,29 @@ PHP_MINIT_FUNCTION(odbc) #endif REGISTER_INI_ENTRIES(); - le_result = zend_register_list_destructors_ex(_free_odbc_result, NULL, "odbc result", module_number); - le_conn = zend_register_list_destructors_ex(_close_odbc_conn, NULL, "odbc link", module_number); le_pconn = zend_register_list_destructors_ex(NULL, _close_odbc_pconn, "odbc link persistent", module_number); odbc_module_entry.type = type; + odbc_connection_ce = register_class_ODBC_Connection(); + odbc_connection_ce->create_object = odbc_connection_create_object; + + memcpy(&odbc_connection_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + odbc_connection_object_handlers.offset = XtOffsetOf(odbc_link, std); + odbc_connection_object_handlers.free_obj = odbc_connection_free_obj; + odbc_connection_object_handlers.get_constructor = odbc_connection_get_constructor; + odbc_connection_object_handlers.clone_obj = NULL; + odbc_connection_object_handlers.compare = zend_objects_not_comparable; + + odbc_result_ce = register_class_ODBC_Result(); + odbc_result_ce->create_object = odbc_result_create_object; + + memcpy(&odbc_result_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + odbc_result_object_handlers.offset = XtOffsetOf(odbc_result, std); + odbc_result_object_handlers.free_obj = odbc_result_free_obj; + odbc_result_object_handlers.get_constructor = odbc_result_get_constructor; + odbc_result_object_handlers.clone_obj = NULL; + odbc_result_object_handlers.compare = zend_objects_not_comparable; + #if defined(HAVE_IBMDB2) && defined(_AIX) /* atexit() handler in the DB2/AIX library segfaults in PHP CLI */ /* DB2NOEXITLIST env variable prevents DB2 from invoking atexit() */ @@ -427,6 +503,9 @@ PHP_RSHUTDOWN_FUNCTION(odbc) /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(odbc) { + zend_hash_destroy(&ODBCG(results)); + zend_hash_destroy(&ODBCG(connections)); + UNREGISTER_INI_ENTRIES(); return SUCCESS; } @@ -510,13 +589,12 @@ void php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAMETERS, int mode) zval *pv_res; zend_long flag; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &pv_res, &flag) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pv_res, odbc_result_ce, &flag) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (mode) { result->longreadlen = flag; @@ -656,13 +734,12 @@ void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type) RETCODE rc; zval *pv_conn; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_conn) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_conn, odbc_connection_ce) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); rc = SQLTransact(conn->henv, conn->hdbc, (SQLUSMALLINT)((type)?SQL_COMMIT:SQL_ROLLBACK)); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { @@ -674,17 +751,6 @@ void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type) } /* }}} */ -/* {{{ _close_pconn_with_res */ -static int _close_pconn_with_res(zend_resource *le, zend_resource *res) -{ - if (le->type == le_pconn && (((odbc_connection *)(le->ptr))->res == res)){ - return 1; - }else{ - return 0; - } -} -/* }}} */ - /* {{{ odbc_column_lengths */ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type) { @@ -703,13 +769,12 @@ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type) zval *pv_res; zend_long pv_num; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &pv_res, &pv_num) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pv_res, odbc_result_ce, &pv_num) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (pv_num < 1) { zend_argument_value_error(2, "must be greater than 0"); @@ -737,30 +802,26 @@ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ Close all ODBC connections */ PHP_FUNCTION(odbc_close_all) { - zend_resource *p; + zval *p; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); } /* Loop through list and close all statements */ - ZEND_HASH_FOREACH_PTR(&EG(regular_list), p) { - if (p->ptr && (p->type == le_result)) { - zend_list_close(p); - } + ZEND_HASH_FOREACH_VAL(&ODBCG(results), p) { + odbc_result_free((odbc_result*) p); } ZEND_HASH_FOREACH_END(); - /* Second loop through list, now close all connections */ - ZEND_HASH_FOREACH_PTR(&EG(regular_list), p) { - if (p->ptr) { - if (p->type == le_conn){ - zend_list_close(p); - } else if (p->type == le_pconn){ - zend_list_close(p); - /* Delete the persistent connection */ - zend_hash_apply_with_argument(&EG(persistent_list), - (apply_func_arg_t) _close_pconn_with_res, (void *)p); - } + /* Second loop through list, now close all non-persistent connections */ + ZEND_HASH_FOREACH_VAL(&ODBCG(connections), p) { + odbc_link_free((odbc_link*) p); + } ZEND_HASH_FOREACH_END(); + + /* Third loop through persistent list, now close all persistent connections */ + ZEND_HASH_FOREACH_VAL(&EG(persistent_list), p) { + if (Z_RES_P(p)->type == le_pconn) { + zend_list_close(Z_RES_P(p)); } } ZEND_HASH_FOREACH_END(); } @@ -794,29 +855,29 @@ PHP_FUNCTION(odbc_prepare) SQLUINTEGER scrollopts; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pv_conn, &query, &query_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pv_conn, odbc_connection_ce, &query, &query_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); result->numparams = 0; result->param_info = NULL; rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -853,7 +914,7 @@ PHP_FUNCTION(odbc_prepare) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -871,12 +932,10 @@ PHP_FUNCTION(odbc_prepare) odbc_sql_error(result->conn_ptr, result->stmt, "SQLDescribeParameter"); SQLFreeStmt(result->stmt, SQL_RESET_PARAMS); efree(result->param_info); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } - - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -915,13 +974,12 @@ PHP_FUNCTION(odbc_execute) int i, ne; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|h", &pv_res, &pv_param_ht) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|h", &pv_res, odbc_result_ce, &pv_param_ht) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->numparams > 0) { if ((ne = zend_hash_num_elements(pv_param_ht)) < result->numparams) { @@ -1075,13 +1133,12 @@ PHP_FUNCTION(odbc_cursor) odbc_result *result; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); rc = SQLGetInfo(result->conn_ptr->hdbc,SQL_MAX_CURSOR_NAME_LEN, (void *)&max_len,sizeof(max_len),&len); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { @@ -1133,7 +1190,7 @@ PHP_FUNCTION(odbc_data_source) UCHAR server_name[100], desc[200]; SQLSMALLINT len1=0, len2=0, fetch_type; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &zv_conn, &zv_fetch_type) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &zv_conn, odbc_connection_ce, &zv_fetch_type) == FAILURE) { RETURN_THROWS(); } @@ -1144,9 +1201,8 @@ PHP_FUNCTION(odbc_data_source) RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(zv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(zv_conn); + CHECK_ODBC_CONNECTION(conn); /* now we have the "connection" lets call the DataSource object */ rc = SQLDataSources(conn->henv, @@ -1196,26 +1252,26 @@ PHP_FUNCTION(odbc_exec) SQLUINTEGER scrollopts; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pv_conn, &query, &query_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pv_conn, odbc_connection_ce, &query, &query_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -1242,7 +1298,7 @@ PHP_FUNCTION(odbc_exec) */ odbc_sql_error(conn, result->stmt, "SQLExecDirect"); SQLFreeStmt(result->stmt, SQL_DROP); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -1251,7 +1307,7 @@ PHP_FUNCTION(odbc_exec) /* For insert, update etc. cols == 0 */ if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -1260,7 +1316,6 @@ PHP_FUNCTION(odbc_exec) Z_ADDREF_P(pv_conn); result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -1276,30 +1331,21 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type) RETCODE rc; SQLSMALLINT sql_c_type; char *buf = NULL; + zval *pv_res, tmp; + zend_long pv_row = -1; + bool pv_row_is_null = true; #ifdef HAVE_SQL_EXTENDED_FETCH SQLULEN crow; SQLUSMALLINT RowStatus[1]; - SQLLEN rownum; - zval *pv_res, tmp; - zend_long pv_row = -1; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &pv_res, &pv_row) == FAILURE) { - RETURN_THROWS(); - } - - rownum = pv_row; -#else - zval *pv_res, tmp; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { - RETURN_THROWS(); - } #endif - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l!", &pv_res, odbc_result_ce, &pv_row, &pv_row_is_null) == FAILURE) { RETURN_THROWS(); } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); + if (result->numcols == 0) { php_error_docref(NULL, E_WARNING, "No tuples available at this result index"); RETURN_FALSE; @@ -1307,8 +1353,8 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type) #ifdef HAVE_SQL_EXTENDED_FETCH if (result->fetch_abs) { - if (rownum > 0) { - rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus); + if (!pv_row_is_null) { + rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,(SQLLEN) pv_row,&crow,RowStatus); } else { rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus); } @@ -1322,12 +1368,11 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type) array_init(return_value); -#ifdef HAVE_SQL_EXTENDED_FETCH - if (rownum > 0 && result->fetch_abs) - result->fetched = rownum; - else -#endif + if (!pv_row_is_null && result->fetch_abs) { + result->fetched = (SQLLEN) pv_row; + } else { result->fetched++; + } for(i = 0; i < result->numcols; i++) { sql_c_type = SQL_C_CHAR; @@ -1437,28 +1482,19 @@ PHP_FUNCTION(odbc_fetch_into) SQLSMALLINT sql_c_type; char *buf = NULL; zval *pv_res, *pv_res_arr, tmp; -#ifdef HAVE_SQL_EXTENDED_FETCH zend_long pv_row = 0; + bool pv_row_is_null = true; +#ifdef HAVE_SQL_EXTENDED_FETCH SQLULEN crow; SQLUSMALLINT RowStatus[1]; - SQLLEN rownum = -1; -#endif /* HAVE_SQL_EXTENDED_FETCH */ - -#ifdef HAVE_SQL_EXTENDED_FETCH - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz|l", &pv_res, &pv_res_arr, &pv_row) == FAILURE) { - RETURN_THROWS(); - } +#endif - rownum = pv_row; -#else - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz", &pv_res, &pv_res_arr) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oz|l!", &pv_res, odbc_result_ce, &pv_res_arr, &pv_row, &pv_row_is_null) == FAILURE) { RETURN_THROWS(); } -#endif /* HAVE_SQL_EXTENDED_FETCH */ - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->numcols == 0) { php_error_docref(NULL, E_WARNING, "No tuples available at this result index"); @@ -1472,8 +1508,8 @@ PHP_FUNCTION(odbc_fetch_into) #ifdef HAVE_SQL_EXTENDED_FETCH if (result->fetch_abs) { - if (rownum > 0) { - rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,rownum,&crow,RowStatus); + if (!pv_row_is_null) { + rc = SQLExtendedFetch(result->stmt,SQL_FETCH_ABSOLUTE,(SQLLEN) pv_row,&crow,RowStatus); } else { rc = SQLExtendedFetch(result->stmt,SQL_FETCH_NEXT,1,&crow,RowStatus); } @@ -1485,12 +1521,11 @@ PHP_FUNCTION(odbc_fetch_into) RETURN_FALSE; } -#ifdef HAVE_SQL_EXTENDED_FETCH - if (rownum > 0 && result->fetch_abs) - result->fetched = rownum; - else -#endif + if (!pv_row_is_null && result->fetch_abs) { + result->fetched = (SQLLEN) pv_row; + } else { result->fetched++; + } for(i = 0; i < result->numcols; i++) { sql_c_type = SQL_C_CHAR; @@ -1569,13 +1604,13 @@ PHP_FUNCTION(solid_fetch_prev) RETCODE rc; zval *pv_res; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res; + CHECK_ODBC_RESULT(result); + if (result->numcols == 0) { php_error_docref(NULL, E_WARNING, "No tuples available at this result index"); RETURN_FALSE; @@ -1601,20 +1636,19 @@ PHP_FUNCTION(odbc_fetch_row) odbc_result *result; RETCODE rc; zval *pv_res; - zend_long pv_row; - bool pv_row_is_null = 1; + zend_long pv_row = 0; + bool pv_row_is_null = true; #ifdef HAVE_SQL_EXTENDED_FETCH SQLULEN crow; SQLUSMALLINT RowStatus[1]; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l!", &pv_res, &pv_row, &pv_row_is_null) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l!", &pv_res, odbc_result_ce, &pv_row, &pv_row_is_null) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->numcols == 0) { php_error_docref(NULL, E_WARNING, "No tuples available at this result index"); @@ -1665,7 +1699,7 @@ PHP_FUNCTION(odbc_result) #endif ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_RESOURCE(pv_res) + Z_PARAM_OBJECT_OF_CLASS(pv_res, odbc_result_ce) Z_PARAM_STR_OR_LONG(pv_field_str, pv_field_long) ZEND_PARSE_PARAMETERS_END(); @@ -1677,9 +1711,8 @@ PHP_FUNCTION(odbc_result) field_ind = (int) pv_field_long - 1; } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->numcols == 0) { php_error_docref(NULL, E_WARNING, "No tuples available at this result index"); @@ -1873,13 +1906,12 @@ PHP_FUNCTION(odbc_result_all) SQLUSMALLINT RowStatus[1]; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|s", &pv_res, &pv_format, &pv_format_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s", &pv_res, odbc_result_ce, &pv_format, &pv_format_len) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->numcols == 0) { php_error_docref(NULL, E_WARNING, "No tuples available at this result index"); @@ -2007,13 +2039,12 @@ PHP_FUNCTION(odbc_free_result) odbc_result *result; int i; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->values) { for (i = 0; i < result->numcols; i++) { @@ -2046,18 +2077,23 @@ PHP_FUNCTION(odbc_pconnect) /* }}} */ /* {{{ odbc_sqlconnect */ -int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int cur_opt, int persistent) +bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, int persistent, zend_string *hash) { RETCODE rc; + odbc_link *link; - *conn = (odbc_connection *)pemalloc(sizeof(odbc_connection), persistent); - memset(*conn, 0, sizeof(odbc_connection)); - (*conn)->persistent = persistent; - SQLAllocEnv(&((*conn)->henv)); - SQLAllocConnect((*conn)->henv, &((*conn)->hdbc)); + object_init_ex(zv, odbc_connection_ce); + link = Z_ODBC_LINK_P(zv); + link->connection = (odbc_connection *)pemalloc(sizeof(odbc_connection), persistent); + memset(link->connection, 0, sizeof(odbc_connection)); + + link->persistent = persistent; + link->hash = hash; + SQLAllocEnv(link->connection->henv); + SQLAllocConnect(link->connection->henv, link->connection->hdbc); #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) - SQLSetConnectOption((*conn)->hdbc, SQL_TRANSLATE_OPTION, + SQLSetConnectOption((link->connection->hdbc, SQL_TRANSLATE_OPTION, SQL_SOLID_XLATOPT_NOCNV); #endif #ifdef HAVE_OPENLINK @@ -2065,16 +2101,15 @@ int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int char dsnbuf[1024]; short dsnbuflen; - rc = SQLDriverConnect((*conn)->hdbc, NULL, db, SQL_NTS, dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT); + rc = SQLDriverConnect(link->connection->hdbc, NULL, db, SQL_NTS, dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT); } #else if (cur_opt != SQL_CUR_DEFAULT) { - rc = SQLSetConnectOption((*conn)->hdbc, SQL_ODBC_CURSORS, cur_opt); + rc = SQLSetConnectOption(link->connection->hdbc, SQL_ODBC_CURSORS, cur_opt); if (rc != SQL_SUCCESS) { /* && rc != SQL_SUCCESS_WITH_INFO ? */ - odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLSetConnectOption"); - SQLFreeConnect((*conn)->hdbc); - pefree(*conn, persistent); - return FALSE; + odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLSetConnectOption"); + SQLFreeConnect(link->connection->hdbc); + return false; } } /* Possible fix for bug #10250 @@ -2132,9 +2167,9 @@ int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int } if (direct) { - rc = SQLDriverConnect((*conn)->hdbc, NULL, (SQLCHAR *) ldb, strlen(ldb), dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT); + rc = SQLDriverConnect(link->connection->hdbc, NULL, (SQLCHAR *) ldb, strlen(ldb), dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT); } else { - rc = SQLConnect((*conn)->hdbc, (SQLCHAR *) db, SQL_NTS, (SQLCHAR *) uid, SQL_NTS, (SQLCHAR *) pwd, SQL_NTS); + rc = SQLConnect(link->connection->hdbc, (SQLCHAR *) db, SQL_NTS, (SQLCHAR *) uid, SQL_NTS, (SQLCHAR *) pwd, SQL_NTS); } if (ldb) { @@ -2142,17 +2177,15 @@ int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int } } #else - rc = SQLConnect((*conn)->hdbc, (SQLCHAR *) db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS); + rc = SQLConnect(link->connection->hdbc, (SQLCHAR *) db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS); #endif #endif if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLConnect"); - SQLFreeConnect((*conn)->hdbc); - pefree((*conn), persistent); - return FALSE; + odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLConnect"); + SQLFreeConnect(link->connection->hdbc); + return false; } -/* (*conn)->open = 1;*/ - return TRUE; + return true; } /* }}} */ @@ -2195,42 +2228,43 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) persistent = 0; } + smart_str hashed_details = {0}; + smart_str_append_printf(&hashed_details, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt); + try_and_get_another_connection: if (persistent) { - char *hashed_details; - int hashed_len; zend_resource *le; - hashed_len = spprintf(&hashed_details, 0, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt); - /* the link is not in the persistent list */ - if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashed_details, hashed_len)) == NULL) { + if ((le = zend_hash_find_ptr(&EG(persistent_list), hashed_details.s)) == NULL) { if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) { - php_error_docref(NULL, E_WARNING, "Too many open links (%ld)", ODBCG(num_links)); - efree(hashed_details); + php_error_docref(NULL, E_WARNING, "Too many open links (" ZEND_LONG_FMT ")", ODBCG(num_links)); + smart_str_free(&hashed_details); RETURN_FALSE; } if (ODBCG(max_persistent) != -1 && ODBCG(num_persistent) >= ODBCG(max_persistent)) { - php_error_docref(NULL, E_WARNING,"Too many open persistent links (%ld)", ODBCG(num_persistent)); - efree(hashed_details); + php_error_docref(NULL, E_WARNING,"Too many open persistent links (" ZEND_LONG_FMT ")", ODBCG(num_persistent)); + smart_str_free(&hashed_details); RETURN_FALSE; } - if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 1)) { - efree(hashed_details); + if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, 1, hashed_details.s)) { + smart_str_free(&hashed_details); + zval_ptr_dtor(return_value); RETURN_FALSE; } - if (zend_register_persistent_resource(hashed_details, hashed_len, db_conn, le_pconn) == NULL) { - free(db_conn); - efree(hashed_details); + db_conn = Z_ODBC_CONNECTION_P(return_value); + + if (zend_register_persistent_resource(ZSTR_VAL(hashed_details.s), ZSTR_LEN(hashed_details.s), db_conn, le_pconn) == NULL) { + smart_str_free(&hashed_details); + zval_ptr_dtor(return_value); RETURN_FALSE; } + ODBCG(num_persistent)++; ODBCG(num_links)++; - db_conn->res = zend_register_resource(db_conn, le_pconn); - RETVAL_RES(db_conn->res); } else { /* found connection */ ZEND_ASSERT(le->type == le_pconn); @@ -2253,7 +2287,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) &dead, 0, NULL); if (ret == SQL_SUCCESS && dead == SQL_CD_TRUE) { /* Bail early here, since we know it's gone */ - zend_hash_str_del(&EG(persistent_list), hashed_details, hashed_len); + zend_hash_del(&EG(persistent_list), hashed_details.s); goto try_and_get_another_connection; } /* If the driver doesn't support it, or returns @@ -2265,7 +2299,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) d_name, sizeof(d_name), &len); if(ret != SQL_SUCCESS || len == 0) { - zend_hash_str_del(&EG(persistent_list), hashed_details, hashed_len); + zend_hash_del(&EG(persistent_list), hashed_details.s); /* Commented out to fix a possible double closure error * when working with persistent connections as submitted by * bug #15758 @@ -2276,23 +2310,29 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) goto try_and_get_another_connection; } } + + object_init_ex(return_value, odbc_connection_ce); + odbc_link *link = Z_ODBC_LINK_P(return_value); + link->connection = db_conn; + link->hash = zend_string_copy(hashed_details.s); + link->persistent = 1; } - efree(hashed_details); - db_conn->res = zend_register_resource(db_conn, le_pconn); - RETVAL_RES(db_conn->res); } else { /* non persistent */ if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) { - php_error_docref(NULL, E_WARNING,"Too many open connections (%ld)",ODBCG(num_links)); + php_error_docref(NULL, E_WARNING,"Too many open connections (" ZEND_LONG_FMT ")", ODBCG(num_links)); + smart_str_free(&hashed_details); RETURN_FALSE; } - if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 0)) { + if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, 0, hashed_details.s)) { + smart_str_free(&hashed_details); RETURN_FALSE; } - db_conn->res = zend_register_resource(db_conn, le_conn); - RETVAL_RES(db_conn->res); ODBCG(num_links)++; } + + zend_hash_update(&ODBCG(connections), hashed_details.s, return_value); + smart_str_free(&hashed_details); } /* }}} */ @@ -2300,37 +2340,22 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) PHP_FUNCTION(odbc_close) { zval *pv_conn; - zend_resource *p; - odbc_connection *conn; - odbc_result *res; - int is_pconn = 0; + odbc_link *link; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_conn) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_conn, odbc_connection_ce) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + link = Z_ODBC_LINK_P(pv_conn); + CHECK_ODBC_CONNECTION(link->connection); - if (Z_RES_P(pv_conn)->type == le_pconn) { - is_pconn = 1; + if (link->persistent) { + zend_hash_del(&EG(persistent_list), link->hash); } - ZEND_HASH_FOREACH_PTR(&EG(regular_list), p) { - if (p->ptr && (p->type == le_result)) { - res = (odbc_result *)p->ptr; - if (res->conn_ptr == conn) { - zend_list_close(p); - } - } - } ZEND_HASH_FOREACH_END(); - - zend_list_close(Z_RES_P(pv_conn)); + close_results_with_connection(link->connection); - if(is_pconn){ - zend_hash_apply_with_argument(&EG(persistent_list), (apply_func_arg_t) _close_pconn_with_res, (void *) Z_RES_P(pv_conn)); - } + odbc_link_free(link); } /* }}} */ @@ -2341,13 +2366,12 @@ PHP_FUNCTION(odbc_num_rows) SQLLEN rows; zval *pv_res; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); SQLRowCount(result->stmt, &rows); RETURN_LONG(rows); @@ -2362,13 +2386,12 @@ PHP_FUNCTION(odbc_next_result) zval *pv_res; int rc, i; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->values) { for(i = 0; i < result->numcols; i++) { @@ -2413,13 +2436,12 @@ PHP_FUNCTION(odbc_num_fields) odbc_result *result; zval *pv_res; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); RETURN_LONG(result->numcols); } @@ -2432,13 +2454,12 @@ PHP_FUNCTION(odbc_field_name) zval *pv_res; zend_long pv_num; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &pv_res, &pv_num) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pv_res, odbc_result_ce, &pv_num) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (pv_num < 1) { zend_argument_value_error(2, "must be greater than 0"); @@ -2468,13 +2489,12 @@ PHP_FUNCTION(odbc_field_type) zval *pv_res; zend_long pv_num; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &pv_res, &pv_num) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pv_res, odbc_result_ce, &pv_num) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (pv_num < 1) { zend_argument_value_error(2, "must be greater than 0"); @@ -2518,13 +2538,12 @@ PHP_FUNCTION(odbc_field_num) odbc_result *result; zval *pv_res; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pv_res, &fname, &fname_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pv_res, odbc_result_ce, &fname, &fname_len) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->numcols == 0) { php_error_docref(NULL, E_WARNING, "No tuples available at this result index"); @@ -2555,13 +2574,12 @@ PHP_FUNCTION(odbc_autocommit) bool pv_onoff = 0; bool pv_onoff_is_null = true; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|b!", &pv_conn, &pv_onoff, &pv_onoff_is_null) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|b!", &pv_conn, odbc_connection_ce, &pv_onoff, &pv_onoff_is_null) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); if (!pv_onoff_is_null) { rc = SQLSetConnectOption(conn->hdbc, SQL_AUTOCOMMIT, pv_onoff ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF); @@ -2604,14 +2622,14 @@ static void php_odbc_lasterror(INTERNAL_FUNCTION_PARAMETERS, int mode) zval *pv_handle = NULL; char *ret; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r!", &pv_handle) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &pv_handle, odbc_connection_ce) == FAILURE) { RETURN_THROWS(); } if (pv_handle) { - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_handle), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_handle); + CHECK_ODBC_CONNECTION(conn); + if (mode == 0) { ret = conn->laststate; } else { @@ -2652,36 +2670,42 @@ PHP_FUNCTION(odbc_errormsg) */ PHP_FUNCTION(odbc_setoption) { - odbc_connection *conn; + odbc_link *link; odbc_result *result; RETCODE rc; zval *pv_handle; zend_long pv_which, pv_opt, pv_val; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlll", &pv_handle, &pv_which, &pv_opt, &pv_val) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "olll", &pv_handle, &pv_which, &pv_opt, &pv_val) == FAILURE) { RETURN_THROWS(); } switch (pv_which) { case 1: /* SQLSetConnectOption */ - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_handle), "ODBC-Link", le_conn, le_pconn))) { + if (!instanceof_function(Z_OBJCE_P(pv_handle), odbc_connection_ce)) { + zend_argument_type_error(1, "must be of type ODBC\\Connection for SQLSetConnectOption()"); RETURN_THROWS(); } + link = Z_ODBC_LINK_P(pv_handle); + CHECK_ODBC_CONNECTION(link->connection); - if (conn->persistent) { + if (link->persistent) { php_error_docref(NULL, E_WARNING, "Unable to set option for persistent connection"); RETURN_FALSE; } - rc = SQLSetConnectOption(conn->hdbc, (unsigned short) pv_opt, pv_val); + rc = SQLSetConnectOption(link->connection->hdbc, (unsigned short) pv_opt, pv_val); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - odbc_sql_error(conn, SQL_NULL_HSTMT, "SetConnectOption"); + odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SetConnectOption"); RETURN_FALSE; } break; case 2: /* SQLSetStmtOption */ - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_handle), "ODBC result", le_result)) == NULL) { + if (!instanceof_function(Z_OBJCE_P(pv_handle), odbc_result_ce)) { + zend_argument_type_error(1, "must be of type ODBC\\Result for SQLSetStmtOption()"); RETURN_THROWS(); } + result = Z_ODBC_RESULT_P(pv_handle); + CHECK_ODBC_RESULT(result); rc = SQLSetStmtOption(result->stmt, (unsigned short) pv_opt, pv_val); @@ -2713,27 +2737,27 @@ PHP_FUNCTION(odbc_tables) size_t cat_len = 0, schema_len = 0, table_len = 0, type_len = 0; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|s!s!s!s!", &pv_conn, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s!s!s!s!", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &table, &table_len, &type, &type_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2750,7 +2774,7 @@ PHP_FUNCTION(odbc_tables) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLTables"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2759,7 +2783,7 @@ PHP_FUNCTION(odbc_tables) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -2767,7 +2791,6 @@ PHP_FUNCTION(odbc_tables) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -2781,27 +2804,27 @@ PHP_FUNCTION(odbc_columns) size_t cat_len = 0, schema_len = 0, table_len = 0, column_len = 0; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|s!s!s!s!", &pv_conn, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s!s!s!s!", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &table, &table_len, &column, &column_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2820,7 +2843,7 @@ PHP_FUNCTION(odbc_columns) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLColumns"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2829,7 +2852,7 @@ PHP_FUNCTION(odbc_columns) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -2837,7 +2860,6 @@ PHP_FUNCTION(odbc_columns) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -2852,27 +2874,27 @@ PHP_FUNCTION(odbc_columnprivileges) size_t cat_len = 0, schema_len, table_len, column_len; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os!sss", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &table, &table_len, &column, &column_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2884,7 +2906,7 @@ PHP_FUNCTION(odbc_columnprivileges) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLColumnPrivileges"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2893,7 +2915,7 @@ PHP_FUNCTION(odbc_columnprivileges) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -2901,7 +2923,6 @@ PHP_FUNCTION(odbc_columnprivileges) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ #endif /* HAVE_DBMAKER || HAVE_SOLID*/ @@ -2917,7 +2938,7 @@ PHP_FUNCTION(odbc_foreignkeys) size_t pcat_len = 0, pschema_len, ptable_len, fcat_len, fschema_len, ftable_len; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs!sssss", &pv_conn, &pcat, &pcat_len, &pschema, &pschema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os!sssss", &pv_conn, odbc_connection_ce, &pcat, &pcat_len, &pschema, &pschema_len, &ptable, &ptable_len, &fcat, &fcat_len, &fschema, &fschema_len, &ftable, &ftable_len) == FAILURE) { RETURN_THROWS(); } @@ -2934,22 +2955,22 @@ PHP_FUNCTION(odbc_foreignkeys) EMPTY_TO_NULL(ftable); #endif - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2972,7 +2993,7 @@ PHP_FUNCTION(odbc_foreignkeys) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -2980,7 +3001,6 @@ PHP_FUNCTION(odbc_foreignkeys) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ #endif /* HAVE_SOLID */ @@ -2995,28 +3015,28 @@ PHP_FUNCTION(odbc_gettypeinfo) RETCODE rc; SQLSMALLINT data_type; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &pv_conn, &pv_data_type) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &pv_conn, odbc_connection_ce, &pv_data_type) == FAILURE) { RETURN_THROWS(); } data_type = (SQLSMALLINT) pv_data_type; - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3024,7 +3044,7 @@ PHP_FUNCTION(odbc_gettypeinfo) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLGetTypeInfo"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3033,7 +3053,7 @@ PHP_FUNCTION(odbc_gettypeinfo) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -3041,7 +3061,6 @@ PHP_FUNCTION(odbc_gettypeinfo) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -3055,26 +3074,26 @@ PHP_FUNCTION(odbc_primarykeys) size_t cat_len = 0, schema_len, table_len; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os!ss", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3085,7 +3104,7 @@ PHP_FUNCTION(odbc_primarykeys) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLPrimaryKeys"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3094,7 +3113,7 @@ PHP_FUNCTION(odbc_primarykeys) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -3102,7 +3121,6 @@ PHP_FUNCTION(odbc_primarykeys) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -3117,27 +3135,27 @@ PHP_FUNCTION(odbc_procedurecolumns) size_t cat_len = 0, schema_len = 0, proc_len = 0, col_len = 0; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|s!s!s!s!", &pv_conn, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s!s!s!s!", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &proc, &proc_len, &col, &col_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3149,7 +3167,7 @@ PHP_FUNCTION(odbc_procedurecolumns) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLProcedureColumns"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3158,7 +3176,7 @@ PHP_FUNCTION(odbc_procedurecolumns) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -3166,7 +3184,6 @@ PHP_FUNCTION(odbc_procedurecolumns) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ #endif /* HAVE_SOLID */ @@ -3182,26 +3199,26 @@ PHP_FUNCTION(odbc_procedures) size_t cat_len = 0, schema_len = 0, proc_len = 0; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|s!s!s!", &pv_conn, &cat, &cat_len, &schema, &schema_len, &proc, &proc_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s!s!s!", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &proc, &proc_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3212,7 +3229,7 @@ PHP_FUNCTION(odbc_procedures) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLProcedures"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3221,7 +3238,7 @@ PHP_FUNCTION(odbc_procedures) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -3229,7 +3246,6 @@ PHP_FUNCTION(odbc_procedures) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ #endif /* HAVE_SOLID */ @@ -3246,7 +3262,7 @@ PHP_FUNCTION(odbc_specialcolumns) SQLUSMALLINT type, scope, nullable; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rls!ssll", &pv_conn, &vtype, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ols!ssll", &pv_conn, odbc_connection_ce, &vtype, &cat, &cat_len, &schema, &schema_len, &name, &name_len, &vscope, &vnullable) == FAILURE) { RETURN_THROWS(); } @@ -3255,22 +3271,22 @@ PHP_FUNCTION(odbc_specialcolumns) scope = (SQLUSMALLINT) vscope; nullable = (SQLUSMALLINT) vnullable; - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3283,7 +3299,7 @@ PHP_FUNCTION(odbc_specialcolumns) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLSpecialColumns"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3292,7 +3308,7 @@ PHP_FUNCTION(odbc_specialcolumns) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -3300,7 +3316,6 @@ PHP_FUNCTION(odbc_specialcolumns) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -3316,7 +3331,7 @@ PHP_FUNCTION(odbc_statistics) SQLUSMALLINT unique, reserved; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs!ssll", &pv_conn, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os!ssll", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &name, &name_len, &vunique, &vreserved) == FAILURE) { RETURN_THROWS(); } @@ -3324,22 +3339,22 @@ PHP_FUNCTION(odbc_statistics) unique = (SQLUSMALLINT) vunique; reserved = (SQLUSMALLINT) vreserved; - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3352,7 +3367,7 @@ PHP_FUNCTION(odbc_statistics) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLStatistics"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3361,7 +3376,7 @@ PHP_FUNCTION(odbc_statistics) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -3369,7 +3384,6 @@ PHP_FUNCTION(odbc_statistics) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -3384,26 +3398,26 @@ PHP_FUNCTION(odbc_tableprivileges) size_t cat_len = 0, schema_len, table_len; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os!ss", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3414,7 +3428,7 @@ PHP_FUNCTION(odbc_tableprivileges) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLTablePrivileges"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3423,7 +3437,7 @@ PHP_FUNCTION(odbc_tableprivileges) if (result->numcols > 0) { if (!odbc_bindcols(result)) { - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } else { @@ -3431,7 +3445,6 @@ PHP_FUNCTION(odbc_tableprivileges) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ #endif /* HAVE_DBMAKER */ diff --git a/ext/odbc/php_odbc_includes.h b/ext/odbc/php_odbc_includes.h index 21c74d317c68c..383cea5e67557 100644 --- a/ext/odbc/php_odbc_includes.h +++ b/ext/odbc/php_odbc_includes.h @@ -191,10 +191,15 @@ typedef struct odbc_connection { ODBC_SQL_CONN_T hdbc; char laststate[6]; char lasterrormsg[SQL_MAX_MESSAGE_LENGTH]; - zend_resource *res; - int persistent; } odbc_connection; +typedef struct odbc_link { + odbc_connection *connection; + zend_string *hash; + bool persistent; + zend_object std; +} odbc_link; + typedef struct odbc_result_value { char name[256]; char *value; @@ -220,8 +225,9 @@ typedef struct odbc_result { zend_long longreadlen; int binmode; int fetched; - odbc_param_info * param_info; + odbc_param_info *param_info; odbc_connection *conn_ptr; + zend_object std; } odbc_result; ZEND_BEGIN_MODULE_GLOBALS(odbc) @@ -240,8 +246,8 @@ ZEND_BEGIN_MODULE_GLOBALS(odbc) zend_long default_cursortype; char laststate[6]; char lasterrormsg[SQL_MAX_MESSAGE_LENGTH]; - HashTable *resource_list; - HashTable *resource_plist; + HashTable results; + HashTable connections; ZEND_END_MODULE_GLOBALS(odbc) int odbc_add_result(HashTable *list, odbc_result *result); diff --git a/ext/odbc/tests/CONFLICTS b/ext/odbc/tests/CONFLICTS deleted file mode 100644 index a3722b55c518a..0000000000000 --- a/ext/odbc/tests/CONFLICTS +++ /dev/null @@ -1 +0,0 @@ -odbc diff --git a/ext/odbc/tests/bug44618.phpt b/ext/odbc/tests/bug44618.phpt index efead0e995189..ee7b10a7e908e 100644 --- a/ext/odbc/tests/bug44618.phpt +++ b/ext/odbc/tests/bug44618.phpt @@ -3,7 +3,13 @@ Bug #44618 (Fetching may rely on uninitialized data) --EXTENSIONS-- odbc --SKIPIF-- - + --FILE-- 7, 'name'=>'test 7'), array('id'=>6, 'name'=>'test 6'), ); -$sql = "UPDATE FOO +$sql = "UPDATE bug47803 SET [PAR_CHR] = ? WHERE [PAR_ID] = ?"; $result = odbc_prepare($link, $sql); @@ -69,7 +68,7 @@ foreach ($upd_params as &$k) { } odbc_free_result($result); -$sql = "SELECT * FROM FOO WHERE [PAR_ID] = ?"; +$sql = "SELECT * FROM bug47803 WHERE [PAR_ID] = ?"; $result = odbc_prepare($link, $sql); if (!$result) { print ('[sql] prep: '.$sql); @@ -89,6 +88,17 @@ out: if ($result) odbc_free_result($result); odbc_close($link); +?> +--CLEAN-- + --EXPECT-- array(3) { @@ -171,15 +181,3 @@ array(3) { ["PAR_CHR"]=> string(6) "test 7" } ---CLEAN-- - diff --git a/ext/odbc/tests/bug60616.phpt b/ext/odbc/tests/bug60616.phpt index 468d3d5234a42..9c060ebc39f36 100644 --- a/ext/odbc/tests/bug60616.phpt +++ b/ext/odbc/tests/bug60616.phpt @@ -2,12 +2,23 @@ odbc_exec(): Getting accurate unicode data from query --EXTENSIONS-- odbc +mbstring --SKIPIF-- - --FILE-- ---EXPECT-- -EUC-JP matched -ASCII matched --CLEAN-- +--EXPECT-- +EUC-JP matched +ASCII matched + diff --git a/ext/odbc/tests/bug68087.phpt b/ext/odbc/tests/bug68087.phpt index 6d4d4cc0b2bd6..250df2ef5acee 100644 --- a/ext/odbc/tests/bug68087.phpt +++ b/ext/odbc/tests/bug68087.phpt @@ -14,14 +14,11 @@ $id_2_date = '2014-09-24'; $conn = odbc_connect($dsn, $user, $pass); -@odbc_exec($conn, 'CREATE DATABASE odbcTEST'); +odbc_exec($conn, 'CREATE TABLE bug68087 (ID INT, VARCHAR_COL VARCHAR(100), DATE_COL DATE)'); -odbc_exec($conn, 'CREATE TABLE FOO (ID INT, VARCHAR_COL VARCHAR(100), DATE_COL DATE)'); +odbc_exec($conn, "INSERT INTO bug68087(ID, VARCHAR_COL, DATE_COL) VALUES (1, 'hello', '$id_1_date'), (2, 'helloagain', '$id_2_date')"); -odbc_exec($conn, "INSERT INTO FOO(ID, VARCHAR_COL, DATE_COL) VALUES (1, 'hello', '$id_1_date')"); -odbc_exec($conn, "INSERT INTO FOO(ID, VARCHAR_COL, DATE_COL) VALUES (2, 'helloagain', '$id_2_date')"); - -$res = odbc_exec($conn, 'SELECT * FROM FOO ORDER BY ID ASC'); +$res = odbc_exec($conn, 'SELECT * FROM bug68087 ORDER BY ID ASC'); while(odbc_fetch_row($res)) { $id = odbc_result($res, "ID"); @@ -44,16 +41,15 @@ while(odbc_fetch_row($res)) { } ?> ---EXPECT-- -Date_1 matched -Date_2 matched --CLEAN-- +--EXPECT-- +Date_1 matched +Date_2 matched diff --git a/ext/odbc/tests/bug69354.phpt b/ext/odbc/tests/bug69354.phpt index 3aab7aa4e9393..47933576130ab 100644 --- a/ext/odbc/tests/bug69354.phpt +++ b/ext/odbc/tests/bug69354.phpt @@ -11,13 +11,11 @@ include 'config.inc'; $conn = odbc_connect($dsn, $user, $pass); -@odbc_exec($conn, 'CREATE DATABASE odbcTEST'); +odbc_exec($conn, 'CREATE TABLE bug69354 (ID INT, VARCHAR_COL VARCHAR(100))'); -odbc_exec($conn, 'CREATE TABLE FOO (ID INT, VARCHAR_COL VARCHAR(100))'); +odbc_exec($conn, "INSERT INTO bug69354(ID, VARCHAR_COL) VALUES (1, '" . str_repeat("a", 100) . "')"); -odbc_exec($conn, "INSERT INTO FOO(ID, VARCHAR_COL) VALUES (1, '" . str_repeat("a", 100) . "')"); - -$res = odbc_exec($conn,"select VARCHAR_COL from FOO"); +$res = odbc_exec($conn,"SELECT VARCHAR_COL FROM bug69354"); if ($res) { if (odbc_fetch_row($res)) { $ret = odbc_result($res,'varchar_col'); @@ -27,17 +25,16 @@ if ($res) { } } ?> ---EXPECT-- -100 -a -a --CLEAN-- +--EXPECT-- +100 +a +a diff --git a/ext/odbc/tests/bug69975.phpt b/ext/odbc/tests/bug69975.phpt index 3617ee7198062..4ab0613eae947 100644 --- a/ext/odbc/tests/bug69975.phpt +++ b/ext/odbc/tests/bug69975.phpt @@ -9,26 +9,25 @@ odbc include 'config.inc'; $conn = odbc_connect($dsn, $user, $pass); -@odbc_exec($conn, 'CREATE DATABASE odbcTEST'); -odbc_exec($conn, 'CREATE TABLE FOO (ID INT, VARCHAR_COL NVARCHAR(MAX))'); -odbc_exec($conn, "INSERT INTO FOO VALUES (1, 'foo')"); +odbc_exec($conn, 'CREATE TABLE bug69975 (ID INT, VARCHAR_COL NVARCHAR(MAX))'); +odbc_exec($conn, "INSERT INTO bug69975 VALUES (1, 'foo')"); -$result = odbc_exec($conn, "SELECT VARCHAR_COL FROM FOO"); +$result = odbc_exec($conn, "SELECT VARCHAR_COL FROM bug69975"); var_dump(odbc_fetch_array($result)); echo "ready"; ?> +--CLEAN-- + --EXPECT-- array(1) { ["VARCHAR_COL"]=> string(3) "foo" } ready ---CLEAN-- - diff --git a/ext/odbc/tests/bug71171.phpt b/ext/odbc/tests/bug71171.phpt index d2cef550e3b31..029c31962f6f4 100644 --- a/ext/odbc/tests/bug71171.phpt +++ b/ext/odbc/tests/bug71171.phpt @@ -11,33 +11,30 @@ include 'config.inc'; $conn = odbc_connect($dsn, $user, $pass); -@odbc_exec($conn, 'CREATE DATABASE odbcTEST'); +odbc_exec($conn, 'CREATE TABLE bug71171 (ID INT, VARCHAR_COL NVARCHAR(40))'); -odbc_exec($conn, 'CREATE TABLE FOO (ID INT, VARCHAR_COL NVARCHAR(40))'); +odbc_exec($conn, "INSERT INTO bug71171(ID, VARCHAR_COL) VALUES (1, '" . chr(0x81) . "')"); -odbc_exec($conn, "INSERT INTO FOO(ID, VARCHAR_COL) VALUES (1, '" . chr(0x81) . "')"); - -$res = odbc_exec($conn,"SELECT ID FROM FOO WHERE VARCHAR_COL = '" . chr(0x81) . "'"); +$res = odbc_exec($conn,"SELECT ID FROM bug71171 WHERE VARCHAR_COL = '" . chr(0x81) . "'"); if ($res) { while($record = odbc_fetch_array($res)) var_dump($record); } odbc_close($conn); ?> ---EXPECT-- -array(1) { - ["ID"]=> - string(1) "1" -} --CLEAN-- +--EXPECT-- +array(1) { + ["ID"]=> + string(1) "1" +} diff --git a/ext/odbc/tests/bug73448.phpt b/ext/odbc/tests/bug73448.phpt index eae5aa8ec0e98..8ec4456323214 100644 --- a/ext/odbc/tests/bug73448.phpt +++ b/ext/odbc/tests/bug73448.phpt @@ -4,6 +4,8 @@ Bug #73448 odbc_errormsg returns trash, always 513 bytes odbc --SKIPIF-- +--CONFLICTS-- +odbc --FILE-- +--CLEAN-- + --EXPECT-- array(3) { @@ -38,18 +48,7 @@ array(3) { ["i"]=> string(3) "102" ["txt"]=> - string(12) "Müsliriegel" + string(17) "Lorem ipsum dolor" ["k"]=> string(2) "34" } ---CLEAN-- - diff --git a/ext/odbc/tests/bug78473.phpt b/ext/odbc/tests/bug78473.phpt index 3903187a36219..bed712e37bd8d 100644 --- a/ext/odbc/tests/bug78473.phpt +++ b/ext/odbc/tests/bug78473.phpt @@ -11,6 +11,6 @@ try { } var_dump(STDIN); ?> ---EXPECTF-- -odbc_close(): supplied resource is not a valid ODBC-Link resource -resource(%d) of type (stream) +--EXPECT-- +odbc_close(): Argument #1 ($odbc) must be of type ODBC\Connection, resource given +resource(1) of type (stream) diff --git a/ext/odbc/tests/odbc_close_all_001.phpt b/ext/odbc/tests/odbc_close_all_001.phpt new file mode 100644 index 0000000000000..9641ac4bd7e4a --- /dev/null +++ b/ext/odbc/tests/odbc_close_all_001.phpt @@ -0,0 +1,38 @@ +--TEST-- +odbc_close_all(): Basic test +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +resource(5) of type (odbc link) +resource(7) of type (odbc link persistent) +resource(8) of type (odbc result) +resource(9) of type (odbc result) +resource(5) of type (Unknown) +resource(7) of type (Unknown) +resource(8) of type (Unknown) +resource(9) of type (Unknown) diff --git a/ext/odbc/tests/odbc_columns_001.phpt b/ext/odbc/tests/odbc_columns_001.phpt index 489d2ccd84ef0..920735b791003 100644 --- a/ext/odbc/tests/odbc_columns_001.phpt +++ b/ext/odbc/tests/odbc_columns_001.phpt @@ -4,6 +4,8 @@ odbc_columns(): Basic test odbc --SKIPIF-- +--CONFLICTS-- +odbc --FILE-- +--CLEAN-- + --EXPECTF-- resource(%d) of type (odbc result) diff --git a/ext/odbc/tests/odbc_commit_001.phpt b/ext/odbc/tests/odbc_commit_001.phpt new file mode 100644 index 0000000000000..5db0b0627e5b8 --- /dev/null +++ b/ext/odbc/tests/odbc_commit_001.phpt @@ -0,0 +1,31 @@ +--TEST-- +odbc_commit(): Basic test for odbc_commit() +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECT-- +bool(true) +string(1) "1" diff --git a/ext/odbc/tests/odbc_cursor_001.phpt b/ext/odbc/tests/odbc_cursor_001.phpt new file mode 100644 index 0000000000000..b7111393d8341 --- /dev/null +++ b/ext/odbc/tests/odbc_cursor_001.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test odbc_cursor() +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +string(%d) "SQL_CUR%s" diff --git a/ext/odbc/tests/odbc_data_source_001.phpt b/ext/odbc/tests/odbc_data_source_001.phpt index b546de2cd9d8c..be3c1226b68b9 100644 --- a/ext/odbc/tests/odbc_data_source_001.phpt +++ b/ext/odbc/tests/odbc_data_source_001.phpt @@ -4,10 +4,10 @@ odbc_data_source(): Basic test odbc --SKIPIF-- --FILE-- --FILE-- --EXPECTF-- -Warning: odbc_exec(): Argument #3 must be of type int, string given in %s on line %d - -Warning: odbc_exec(): SQL error: %s in %s on line %d - -Warning: odbc_exec(): Argument #3 must be of type int, string given in %s on line %d - -Warning: odbc_exec(): SQL error: %s in %s on line %d - -Warning: odbc_exec(): SQL error: %s in %s on line %d - -Warning: odbc_exec(): SQL error: %s in %s on line %d - Warning: odbc_exec(): SQL error: %s in %s on line %d Warning: odbc_exec(): SQL error: %s in %s on line %d diff --git a/ext/odbc/tests/odbc_exec_002.phpt b/ext/odbc/tests/odbc_exec_002.phpt index 44c1baad5ac8e..347d633905384 100644 --- a/ext/odbc/tests/odbc_exec_002.phpt +++ b/ext/odbc/tests/odbc_exec_002.phpt @@ -11,14 +11,10 @@ include 'config.inc'; $conn = odbc_connect($dsn, $user, $pass); -odbc_exec($conn, 'CREATE DATABASE odbcTEST'); +odbc_exec($conn, 'CREATE TABLE exec2 (TEST INT)'); +odbc_exec($conn, 'INSERT INTO exec2 VALUES (1), (2)'); -odbc_exec($conn, 'CREATE TABLE FOO (TEST INT)'); - -odbc_exec($conn, 'INSERT INTO FOO VALUES (1)'); -odbc_exec($conn, 'INSERT INTO FOO VALUES (2)'); - -$res = odbc_exec($conn, 'SELECT * FROM FOO'); +$res = odbc_exec($conn, 'SELECT * FROM exec2'); var_dump(odbc_fetch_row($res)); var_dump(odbc_result($res, 'test')); @@ -28,8 +24,7 @@ var_dump(odbc_fetch_array($res)); --EXPECT-- bool(true) diff --git a/ext/odbc/tests/odbc_fetch_array_001.phpt b/ext/odbc/tests/odbc_fetch_array_001.phpt new file mode 100644 index 0000000000000..bf13ed25e4d64 --- /dev/null +++ b/ext/odbc/tests/odbc_fetch_array_001.phpt @@ -0,0 +1,44 @@ +--TEST-- +odbc_fetch_array(): Getting data from query +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +array(1) { + ["foo"]=> + string(1) "1" +} +array(1) { + ["foo"]=> + string(1) "2" +} +array(1) { + ["foo"]=> + string(1) "2" +} +bool(false) diff --git a/ext/odbc/tests/odbc_fetch_into_001.phpt b/ext/odbc/tests/odbc_fetch_into_001.phpt new file mode 100644 index 0000000000000..19f7f79268c58 --- /dev/null +++ b/ext/odbc/tests/odbc_fetch_into_001.phpt @@ -0,0 +1,57 @@ +--TEST-- +odbc_fetch_into(): Getting data from query +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +int(1) +array(1) { + [0]=> + string(1) "1" +} +int(1) +array(1) { + [0]=> + string(1) "2" +} +int(1) +array(1) { + [0]=> + string(1) "2" +} +bool(false) +array(0) { +} diff --git a/ext/odbc/tests/odbc_fetch_object_001.phpt b/ext/odbc/tests/odbc_fetch_object_001.phpt new file mode 100644 index 0000000000000..62a8fc3b2c7e5 --- /dev/null +++ b/ext/odbc/tests/odbc_fetch_object_001.phpt @@ -0,0 +1,44 @@ +--TEST-- +odbc_fetch_object(): Getting data from query +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +object(stdClass)#%d (%d) { + ["foo"]=> + string(1) "1" +} +object(stdClass)#%d (%d) { + ["foo"]=> + string(1) "2" +} +object(stdClass)#%d (%d) { + ["foo"]=> + string(1) "2" +} +bool(false) diff --git a/ext/odbc/tests/odbc_fetch_row_001.phpt b/ext/odbc/tests/odbc_fetch_row_001.phpt new file mode 100644 index 0000000000000..4e5e6b69d5b88 --- /dev/null +++ b/ext/odbc/tests/odbc_fetch_row_001.phpt @@ -0,0 +1,50 @@ +--TEST-- +odbc_fetch_row(): Getting data from query +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +bool(false) +bool(true) +string(1) "1" +bool(true) +string(1) "2" +bool(true) +string(1) "2" +bool(false) diff --git a/ext/odbc/tests/odbc_field_len_001.phpt b/ext/odbc/tests/odbc_field_len_001.phpt new file mode 100644 index 0000000000000..81b6fe9344fd8 --- /dev/null +++ b/ext/odbc/tests/odbc_field_len_001.phpt @@ -0,0 +1,42 @@ +--TEST-- +odbc_field_len(): Getting the length of the field +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} +var_dump(odbc_field_len($res, 1)); +var_dump(odbc_field_len($res, 2)); +var_dump(odbc_field_len($res, 3)); +var_dump(odbc_field_len($res, 4)); + +odbc_close($conn); +?> +--CLEAN-- + +--EXPECTF-- +odbc_field_len(): Argument #2 ($field) must be greater than 0 +int(10) +int(2147483647) +int(50) + +Warning: odbc_field_len(): Field index larger than number of fields in %s on line %d +bool(false) diff --git a/ext/odbc/tests/odbc_field_name_001.phpt b/ext/odbc/tests/odbc_field_name_001.phpt new file mode 100644 index 0000000000000..f26e9cd205629 --- /dev/null +++ b/ext/odbc/tests/odbc_field_name_001.phpt @@ -0,0 +1,41 @@ +--TEST-- +odbc_field_name(): Getting the name of the field +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} +var_dump(odbc_field_name($res, 1)); +var_dump(odbc_field_name($res, 2)); +var_dump(odbc_field_name($res, 3)); +var_dump(odbc_field_name($res, 4)); + +?> +--CLEAN-- + +--EXPECTF-- +odbc_field_name(): Argument #2 ($field) must be greater than 0 +string(3) "foo" +string(3) "bar" +string(3) "baz" + +Warning: odbc_field_name(): Field index larger than number of fields in %s on line %d +bool(false) diff --git a/ext/odbc/tests/odbc_field_num_001.phpt b/ext/odbc/tests/odbc_field_num_001.phpt new file mode 100644 index 0000000000000..3191f939fc243 --- /dev/null +++ b/ext/odbc/tests/odbc_field_num_001.phpt @@ -0,0 +1,33 @@ +--TEST-- +odbc_field_scale(): Getting the scale of the field +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +int(1) +int(2) +int(3) +bool(false) diff --git a/ext/odbc/tests/odbc_field_precision_001.phpt b/ext/odbc/tests/odbc_field_precision_001.phpt new file mode 100644 index 0000000000000..ccbe851f1d6b2 --- /dev/null +++ b/ext/odbc/tests/odbc_field_precision_001.phpt @@ -0,0 +1,41 @@ +--TEST-- +odbc_field_precision(): Getting the precision of the field +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} +var_dump(odbc_field_precision($res, 1)); +var_dump(odbc_field_precision($res, 2)); +var_dump(odbc_field_precision($res, 3)); +var_dump(odbc_field_precision($res, 4)); + +?> +--CLEAN-- + +--EXPECTF-- +odbc_field_precision(): Argument #2 ($field) must be greater than 0 +int(10) +int(7) +int(50) + +Warning: odbc_field_precision(): Field index larger than number of fields in %s on line %d +bool(false) diff --git a/ext/odbc/tests/odbc_field_scale_001.phpt b/ext/odbc/tests/odbc_field_scale_001.phpt new file mode 100644 index 0000000000000..5fef7c2d9e6a1 --- /dev/null +++ b/ext/odbc/tests/odbc_field_scale_001.phpt @@ -0,0 +1,41 @@ +--TEST-- +odbc_field_scale(): Getting the scale of the field +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} +var_dump(odbc_field_scale($res, 1)); +var_dump(odbc_field_scale($res, 2)); +var_dump(odbc_field_scale($res, 3)); +var_dump(odbc_field_scale($res, 4)); + +?> +--CLEAN-- + +--EXPECTF-- +odbc_field_scale(): Argument #2 ($field) must be greater than 0 +int(0) +int(0) +int(0) + +Warning: odbc_field_scale(): Field index larger than number of fields in %s on line %d +bool(false) diff --git a/ext/odbc/tests/odbc_field_type_001.phpt b/ext/odbc/tests/odbc_field_type_001.phpt new file mode 100644 index 0000000000000..374136c4e47b2 --- /dev/null +++ b/ext/odbc/tests/odbc_field_type_001.phpt @@ -0,0 +1,41 @@ +--TEST-- +odbc_field_type(): Getting the type of the field +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} +var_dump(odbc_field_type($res, 1)); +var_dump(odbc_field_type($res, 2)); +var_dump(odbc_field_type($res, 3)); +var_dump(odbc_field_type($res, 4)); + +?> +--CLEAN-- + +--EXPECTF-- +odbc_field_type(): Argument #2 ($field) must be greater than 0 +string(3) "int" +string(4) "text" +string(9) "varbinary" + +Warning: odbc_field_type(): Field index larger than number of fields in %s on line %d +bool(false) diff --git a/ext/odbc/tests/odbc_free_result_001.phpt b/ext/odbc/tests/odbc_free_result_001.phpt index 653e5a0d9facb..8fc4075581a2f 100644 --- a/ext/odbc/tests/odbc_free_result_001.phpt +++ b/ext/odbc/tests/odbc_free_result_001.phpt @@ -11,15 +11,11 @@ include 'config.inc'; $conn = odbc_connect($dsn, $user, $pass); -odbc_exec($conn, 'CREATE DATABASE odbcTEST'); +odbc_exec($conn, 'CREATE TABLE free_result (TEST INT NOT NULL)'); -odbc_exec($conn, 'CREATE TABLE FOO (TEST INT NOT NULL)'); -odbc_exec($conn, 'ALTER TABLE FOO ADD PRIMARY KEY (TEST)'); +odbc_exec($conn, 'INSERT INTO free_result VALUES (1), (2)'); -odbc_exec($conn, 'INSERT INTO FOO VALUES (1)'); -odbc_exec($conn, 'INSERT INTO FOO VALUES (2)'); - -$res = odbc_exec($conn, 'SELECT * FROM FOO'); +$res = odbc_exec($conn, 'SELECT * FROM free_result'); var_dump(odbc_fetch_row($res)); var_dump(odbc_result($res, 'test')); @@ -44,8 +40,7 @@ try { --EXPECT-- bool(true) diff --git a/ext/odbc/tests/odbc_gettypeinfo_001.phpt b/ext/odbc/tests/odbc_gettypeinfo_001.phpt new file mode 100644 index 0000000000000..76b06089181fa --- /dev/null +++ b/ext/odbc/tests/odbc_gettypeinfo_001.phpt @@ -0,0 +1,154 @@ +--TEST-- +odbc_gettypeinfo(): Getting info about data types +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +array(20) { + ["TYPE_NAME"]=> + string(14) "datetimeoffset" + ["DATA_TYPE"]=> + string(4) "-155" + ["COLUMN_SIZE"]=> + string(2) "34" + ["LITERAL_PREFIX"]=> + string(1) "'" + ["LITERAL_SUFFIX"]=> + string(1) "'" + ["CREATE_PARAMS"]=> + string(5) "scale" + ["NULLABLE"]=> + string(1) "1" + ["CASE_SENSITIVE"]=> + string(1) "0" + ["SEARCHABLE"]=> + string(1) "3" + ["UNSIGNED_ATTRIBUTE"]=> + NULL + ["FIXED_PREC_SCALE"]=> + string(1) "0" + ["AUTO_UNIQUE_VALUE"]=> + NULL + ["LOCAL_TYPE_NAME"]=> + string(14) "datetimeoffset" + ["MINIMUM_SCALE"]=> + string(1) "0" + ["MAXIMUM_SCALE"]=> + string(1) "7" + ["SQL_DATA_TYPE"]=> + string(4) "-155" + ["SQL_DATETIME_SUB"]=> + string(1) "0" + ["NUM_PREC_RADIX"]=> + NULL + ["INTERVAL_PRECISION"]=> + NULL + ["USERTYPE"]=> + string(1) "0" +} +array(20) { + ["TYPE_NAME"]=> + string(4) "char" + ["DATA_TYPE"]=> + string(1) "1" + ["COLUMN_SIZE"]=> + string(4) "8000" + ["LITERAL_PREFIX"]=> + string(1) "'" + ["LITERAL_SUFFIX"]=> + string(1) "'" + ["CREATE_PARAMS"]=> + string(6) "length" + ["NULLABLE"]=> + string(1) "1" + ["CASE_SENSITIVE"]=> + string(1) "0" + ["SEARCHABLE"]=> + string(1) "3" + ["UNSIGNED_ATTRIBUTE"]=> + NULL + ["FIXED_PREC_SCALE"]=> + string(1) "0" + ["AUTO_UNIQUE_VALUE"]=> + NULL + ["LOCAL_TYPE_NAME"]=> + string(4) "char" + ["MINIMUM_SCALE"]=> + NULL + ["MAXIMUM_SCALE"]=> + NULL + ["SQL_DATA_TYPE"]=> + string(1) "1" + ["SQL_DATETIME_SUB"]=> + NULL + ["NUM_PREC_RADIX"]=> + NULL + ["INTERVAL_PRECISION"]=> + NULL + ["USERTYPE"]=> + string(1) "1" +} +array(20) { + ["TYPE_NAME"]=> + string(7) "numeric" + ["DATA_TYPE"]=> + string(1) "2" + ["COLUMN_SIZE"]=> + string(2) "38" + ["LITERAL_PREFIX"]=> + NULL + ["LITERAL_SUFFIX"]=> + NULL + ["CREATE_PARAMS"]=> + string(15) "precision,scale" + ["NULLABLE"]=> + string(1) "1" + ["CASE_SENSITIVE"]=> + string(1) "0" + ["SEARCHABLE"]=> + string(1) "2" + ["UNSIGNED_ATTRIBUTE"]=> + string(1) "0" + ["FIXED_PREC_SCALE"]=> + string(1) "0" + ["AUTO_UNIQUE_VALUE"]=> + string(1) "0" + ["LOCAL_TYPE_NAME"]=> + string(7) "numeric" + ["MINIMUM_SCALE"]=> + string(1) "0" + ["MAXIMUM_SCALE"]=> + string(2) "38" + ["SQL_DATA_TYPE"]=> + string(1) "2" + ["SQL_DATETIME_SUB"]=> + NULL + ["NUM_PREC_RADIX"]=> + string(2) "10" + ["INTERVAL_PRECISION"]=> + NULL + ["USERTYPE"]=> + string(2) "10" +} diff --git a/ext/odbc/tests/odbc_longreadlen_001.phpt b/ext/odbc/tests/odbc_longreadlen_001.phpt new file mode 100644 index 0000000000000..d27fa8bf9581a --- /dev/null +++ b/ext/odbc/tests/odbc_longreadlen_001.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test odbc_longreadlen() +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECT-- +string(4) "what" diff --git a/ext/odbc/tests/odbc_num_fields_001.phpt b/ext/odbc/tests/odbc_num_fields_001.phpt new file mode 100644 index 0000000000000..f5c55d583a2dd --- /dev/null +++ b/ext/odbc/tests/odbc_num_fields_001.phpt @@ -0,0 +1,35 @@ +--TEST-- +odbc_num_fields(): Getting the number of fields +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECT-- +int(3) +int(3) diff --git a/ext/odbc/tests/odbc_num_rows_001.phpt b/ext/odbc/tests/odbc_num_rows_001.phpt new file mode 100644 index 0000000000000..342762f920f7c --- /dev/null +++ b/ext/odbc/tests/odbc_num_rows_001.phpt @@ -0,0 +1,35 @@ +--TEST-- +odbc_num_rows(): Getting the number of rows +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECT-- +int(3) +int(0) diff --git a/ext/odbc/tests/odbc_primarykeys_001.phpt b/ext/odbc/tests/odbc_primarykeys_001.phpt new file mode 100644 index 0000000000000..543a22733da71 --- /dev/null +++ b/ext/odbc/tests/odbc_primarykeys_001.phpt @@ -0,0 +1,93 @@ +--TEST-- +odbc_primarykeys(): Basic test for odbc_primarykeys() +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +bool(false) +bool(false) +bool(false) +array(%d) { + ["TABLE_CAT"]=> + string(%d) "PrimarykeysTest" + ["TABLE_SCHEM"]=> + string(%d) "dbo" + ["TABLE_NAME"]=> + string(%d) "primarykeys" + ["COLUMN_NAME"]=> + string(%d) "test" + ["KEY_SEQ"]=> + string(%d) "1" + ["PK_NAME"]=> + string(%d) "primarykeys_pk" +} +array(%d) { + ["TABLE_CAT"]=> + string(%d) "PrimarykeysTest" + ["TABLE_SCHEM"]=> + string(%d) "dbo" + ["TABLE_NAME"]=> + string(%d) "primarykeys" + ["COLUMN_NAME"]=> + string(%d) "test" + ["KEY_SEQ"]=> + string(%d) "1" + ["PK_NAME"]=> + string(%d) "primarykeys_pk" +} diff --git a/ext/odbc/tests/odbc_rollback_001.phpt b/ext/odbc/tests/odbc_rollback_001.phpt new file mode 100644 index 0000000000000..6f4cf3d6926d7 --- /dev/null +++ b/ext/odbc/tests/odbc_rollback_001.phpt @@ -0,0 +1,31 @@ +--TEST-- +odbc_rollback(): Basic test for odbc_rollback() +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECT-- +bool(true) +bool(false) diff --git a/ext/odbc/tests/odbc_setoption_001.phpt b/ext/odbc/tests/odbc_setoption_001.phpt new file mode 100644 index 0000000000000..3f2202100aa64 --- /dev/null +++ b/ext/odbc/tests/odbc_setoption_001.phpt @@ -0,0 +1,24 @@ +--TEST-- +odbc_setoption(): Basic test for odbc_setoption() +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(true) +int(0) diff --git a/ext/odbc/tests/odbc_setoption_002.phpt b/ext/odbc/tests/odbc_setoption_002.phpt new file mode 100644 index 0000000000000..e93d45b6fb414 --- /dev/null +++ b/ext/odbc/tests/odbc_setoption_002.phpt @@ -0,0 +1,25 @@ +--TEST-- +odbc_setoption(): Test for odbc_setoption() with persistent connection +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: odbc_setoption(): Unable to set option for persistent connection in %s on line %d +bool(false) +int(1) diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index c8330c1e79057..b10e5a8046ab1 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -188,7 +188,7 @@ static zend_ast *zend_persist_ast(zend_ast *ast) node = (zend_ast *) copy; } else { uint32_t children = zend_ast_get_num_children(ast); - node = zend_shared_memdup(ast, sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children); + node = zend_shared_memdup(ast, zend_ast_size(children)); for (i = 0; i < children; i++) { if (node->child[i]) { node->child[i] = zend_persist_ast(node->child[i]); diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index dfc281eb7f6f7..2d4a3c92afa29 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -87,7 +87,7 @@ static void zend_persist_ast_calc(zend_ast *ast) } } else { uint32_t children = zend_ast_get_num_children(ast); - ADD_SIZE(sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children); + ADD_SIZE(zend_ast_size(children)); for (i = 0; i < children; i++) { if (ast->child[i]) { zend_persist_ast_calc(ast->child[i]); diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 833afa0d0f579..ce9c7967e7271 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -1414,6 +1414,12 @@ static void dbh_free(pdo_dbh_t *dbh, bool free_persistent) static void pdo_dbh_free_storage(zend_object *std) { pdo_dbh_t *dbh = php_pdo_dbh_fetch_inner(std); + + /* dbh might be null if we OOMed during object initialization. */ + if (!dbh) { + return; + } + if (dbh->driver_data && dbh->methods && dbh->methods->rollback && pdo_is_in_transaction(dbh)) { dbh->methods->rollback(dbh); dbh->in_txn = false; diff --git a/ext/pdo/tests/bug_36798.phpt b/ext/pdo/tests/bug_36798.phpt index dea1a5b92a23c..da258bc87d34d 100644 --- a/ext/pdo/tests/bug_36798.phpt +++ b/ext/pdo/tests/bug_36798.phpt @@ -13,6 +13,8 @@ if (!strncasecmp(getenv('PDOTEST_DSN'), 'oci', strlen('oci'))){ if (!strpos(strtolower(getenv('PDOTEST_DSN')), 'charset=we8mswin1252')) die('skip expected output valid for Oracle with WE8MSWIN1252 character set'); } elseif (!strncasecmp(getenv('PDOTEST_DSN'), 'dblib', strlen('dblib'))) { die('skip not for pdo_dblib'); +} elseif (!strncasecmp(getenv('PDOTEST_DSN'), 'odbc', strlen('odbc'))) { + die('skip not for pdo_odbc'); } ?> diff --git a/ext/pdo_odbc/pdo_odbc.c b/ext/pdo_odbc/pdo_odbc.c index 98e684bc5a95b..8e090a397f061 100644 --- a/ext/pdo_odbc/pdo_odbc.c +++ b/ext/pdo_odbc/pdo_odbc.c @@ -25,6 +25,7 @@ #include "pdo/php_pdo_driver.h" #include "php_pdo_odbc.h" #include "php_pdo_odbc_int.h" +#include "pdo_odbc_arginfo.h" /* {{{ pdo_odbc_deps[] */ static const zend_module_dep pdo_odbc_deps[] = { @@ -96,6 +97,8 @@ PHP_MINIT_FUNCTION(pdo_odbc) } #endif + register_pdo_odbc_symbols(module_number); + REGISTER_PDO_CLASS_CONST_LONG("ODBC_ATTR_USE_CURSOR_LIBRARY", PDO_ODBC_ATTR_USE_CURSOR_LIBRARY); REGISTER_PDO_CLASS_CONST_LONG("ODBC_ATTR_ASSUME_UTF8", PDO_ODBC_ATTR_ASSUME_UTF8); REGISTER_PDO_CLASS_CONST_LONG("ODBC_SQL_USE_IF_NEEDED", SQL_CUR_USE_IF_NEEDED); diff --git a/ext/pdo_odbc/pdo_odbc.stub.php b/ext/pdo_odbc/pdo_odbc.stub.php new file mode 100644 index 0000000000000..745be283375da --- /dev/null +++ b/ext/pdo_odbc/pdo_odbc.stub.php @@ -0,0 +1,9 @@ + --FILE-- prefix[0] == 0) || old) && strnlen(hdr->name, 100) == sizeof(".phar/signature.bin")-1 && !strncmp(hdr->name, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) { + if (((!old && hdr->prefix[0] == 0) || old) && zend_strnlen(hdr->name, 100) == sizeof(".phar/signature.bin")-1 && !strncmp(hdr->name, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) { zend_off_t curloc; size_t sig_len; @@ -499,7 +492,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, char *alia entry.link = NULL; /* link field is null-terminated unless it has 100 non-null chars. * Thus we cannot use strlen. */ - linkname_len = strnlen(hdr->linkname, 100); + linkname_len = zend_strnlen(hdr->linkname, 100); if (entry.tar_type == TAR_LINK) { if (!zend_hash_str_exists(&myphar->manifest, hdr->linkname, linkname_len)) { if (error) { diff --git a/ext/phar/tests/cache_list/frontcontroller15.phpt b/ext/phar/tests/cache_list/frontcontroller15.phpt index 1a9490be9c91c..4c7c1dddec905 100644 --- a/ext/phar/tests/cache_list/frontcontroller15.phpt +++ b/ext/phar/tests/cache_list/frontcontroller15.phpt @@ -14,7 +14,4 @@ files/frontcontroller8.phar --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/phar/tests/cache_list/frontcontroller3.phpt b/ext/phar/tests/cache_list/frontcontroller3.phpt index 04dad8a7ca306..0d01acb6d1c25 100644 --- a/ext/phar/tests/cache_list/frontcontroller3.phpt +++ b/ext/phar/tests/cache_list/frontcontroller3.phpt @@ -14,7 +14,4 @@ files/frontcontroller.phar --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/phar/tests/cache_list/frontcontroller9.phpt b/ext/phar/tests/cache_list/frontcontroller9.phpt index ddc129912164b..a894b192678e0 100644 --- a/ext/phar/tests/cache_list/frontcontroller9.phpt +++ b/ext/phar/tests/cache_list/frontcontroller9.phpt @@ -14,7 +14,4 @@ files/frontcontroller3.phar --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/phar/tests/frontcontroller15.phpt b/ext/phar/tests/frontcontroller15.phpt index 99d2476490b9a..f821e66bbbde0 100644 --- a/ext/phar/tests/frontcontroller15.phpt +++ b/ext/phar/tests/frontcontroller15.phpt @@ -13,7 +13,4 @@ files/frontcontroller8.phar --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/phar/tests/frontcontroller3.phpt b/ext/phar/tests/frontcontroller3.phpt index 045aca26c1d0b..55b42a6f5e29c 100644 --- a/ext/phar/tests/frontcontroller3.phpt +++ b/ext/phar/tests/frontcontroller3.phpt @@ -13,7 +13,4 @@ files/frontcontroller.phar --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/phar/tests/frontcontroller9.phpt b/ext/phar/tests/frontcontroller9.phpt index 54b50b4821226..f18ea4c111dbb 100644 --- a/ext/phar/tests/frontcontroller9.phpt +++ b/ext/phar/tests/frontcontroller9.phpt @@ -13,7 +13,4 @@ files/frontcontroller3.phar --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/phar/tests/tar/frontcontroller15.phar.phpt b/ext/phar/tests/tar/frontcontroller15.phar.phpt index 941baef6b7a9a..243f9c3e33943 100644 --- a/ext/phar/tests/tar/frontcontroller15.phar.phpt +++ b/ext/phar/tests/tar/frontcontroller15.phar.phpt @@ -13,7 +13,4 @@ files/frontcontroller8.phar.tar --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/phar/tests/tar/frontcontroller3.phar.phpt b/ext/phar/tests/tar/frontcontroller3.phar.phpt index edbd20858ab2d..98c12e27814fc 100644 --- a/ext/phar/tests/tar/frontcontroller3.phar.phpt +++ b/ext/phar/tests/tar/frontcontroller3.phar.phpt @@ -13,7 +13,4 @@ files/frontcontroller.phar.tar --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/phar/tests/tar/frontcontroller9.phar.phpt b/ext/phar/tests/tar/frontcontroller9.phar.phpt index 2cbfdaa832246..997b438367ffa 100644 --- a/ext/phar/tests/tar/frontcontroller9.phar.phpt +++ b/ext/phar/tests/tar/frontcontroller9.phar.phpt @@ -13,7 +13,4 @@ files/frontcontroller3.phar.tar --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/phar/tests/zip/frontcontroller15.phar.phpt b/ext/phar/tests/zip/frontcontroller15.phar.phpt index f10b91f68e15f..d106af1487657 100644 --- a/ext/phar/tests/zip/frontcontroller15.phar.phpt +++ b/ext/phar/tests/zip/frontcontroller15.phar.phpt @@ -15,7 +15,4 @@ files/frontcontroller8.phar.zip --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/phar/tests/zip/frontcontroller3.phar.phpt b/ext/phar/tests/zip/frontcontroller3.phar.phpt index 9c4581c124356..f0103d3e26c06 100644 --- a/ext/phar/tests/zip/frontcontroller3.phar.phpt +++ b/ext/phar/tests/zip/frontcontroller3.phar.phpt @@ -15,7 +15,4 @@ files/frontcontroller.phar.zip --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/phar/tests/zip/frontcontroller9.phar.phpt b/ext/phar/tests/zip/frontcontroller9.phar.phpt index 9f118e6c5b9bd..20e3ab432eb1e 100644 --- a/ext/phar/tests/zip/frontcontroller9.phar.phpt +++ b/ext/phar/tests/zip/frontcontroller9.phar.phpt @@ -13,7 +13,4 @@ files/frontcontroller3.phar.zip --EXPECTHEADERS-- Content-type: text/html; charset=UTF-8 --EXPECT-- - -<?php function hio(){} - - +
<?php function hio(){}
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index a6aa6931be16f..6dc3bc463626f 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -643,6 +643,7 @@ static int format_default_value(smart_str *str, zval *value) { } ZEND_HASH_FOREACH_END(); smart_str_appendc(str, ']'); } else if (Z_TYPE_P(value) == IS_OBJECT) { + /* This branch may only be reached for default properties, which don't support arbitrary objects. */ zend_object *obj = Z_OBJ_P(value); zend_class_entry *class = obj->ce; ZEND_ASSERT(class->ce_flags & ZEND_ACC_ENUM); diff --git a/ext/reflection/tests/gh11937_1.inc b/ext/reflection/tests/gh11937_1.inc new file mode 100644 index 0000000000000..4d55213f2f831 --- /dev/null +++ b/ext/reflection/tests/gh11937_1.inc @@ -0,0 +1,13 @@ +getAttributes('Attr')[0]; + +?> +--EXPECT-- +array(2) { + [0]=> + enum(TestEnum::One) + [1]=> + enum(TestEnum::Two) +} +Attribute [ Attr ] { + - Arguments [1] { + Argument #0 [ new \Foo(TestEnum::CASES) ] + } +} diff --git a/ext/reflection/tests/gh11937_2.inc b/ext/reflection/tests/gh11937_2.inc new file mode 100644 index 0000000000000..d6e21e6ba5c55 --- /dev/null +++ b/ext/reflection/tests/gh11937_2.inc @@ -0,0 +1,4 @@ +getAttributes('Attr')[0]; + +?> +--EXPECT-- +array(1) { + [0]=> + object(Foo)#1 (0) { + } +} +Attribute [ Attr ] { + - Arguments [1] { + Argument #0 [ FOOS ] + } +} diff --git a/ext/simplexml/tests/SimpleXMLElement_asXML_fragment_filename.phpt b/ext/simplexml/tests/SimpleXMLElement_asXML_fragment_filename.phpt new file mode 100644 index 0000000000000..0ab6c432499f8 --- /dev/null +++ b/ext/simplexml/tests/SimpleXMLElement_asXML_fragment_filename.phpt @@ -0,0 +1,29 @@ +--TEST-- +SimpleXMLElement::asXML() with a fragment and a filename +--EXTENSIONS-- +simplexml +--FILE-- + + + + bar + + +XML); +$sxe->container2->asXML(__DIR__."/SimpleXMLElement_asXML_fragment_filename_output.tmp"); + +// Note: the strange indent is correct: the indent text node preceding container2 is not emitted. +echo file_get_contents(__DIR__."/SimpleXMLElement_asXML_fragment_filename_output.tmp"); + +?> +--CLEAN-- + +--EXPECT-- + + bar + diff --git a/ext/snmp/snmp.stub.php b/ext/snmp/snmp.stub.php index 9f4557e6f8fac..87496c936fe4d 100644 --- a/ext/snmp/snmp.stub.php +++ b/ext/snmp/snmp.stub.php @@ -132,7 +132,7 @@ function snmp_set_enum_print(bool $enable): true {} function snmp_set_oid_output_format(int $format): true {} /** @alias snmp_set_oid_output_format */ -function snmp_set_oid_numeric_print(int $format): bool {} +function snmp_set_oid_numeric_print(int $format): true {} function snmp2_get(string $hostname, string $community, array|string $object_id, int $timeout = -1, int $retries = -1): mixed {} diff --git a/ext/snmp/snmp_arginfo.h b/ext/snmp/snmp_arginfo.h index a268cd6e5d5ef..f19b91f4ec54d 100644 --- a/ext/snmp/snmp_arginfo.h +++ b/ext/snmp/snmp_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: ada00ea99d91d7e48e9965c5891227f97fd779a6 */ + * Stub hash: 449ae0af39f24f3e5696b88a30d2a440628c409b */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_snmpget, 0, 3, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, hostname, IS_STRING, 0) @@ -46,9 +46,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_snmp_set_oid_output_format, 0, 1 ZEND_ARG_TYPE_INFO(0, format, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_snmp_set_oid_numeric_print, 0, 1, _IS_BOOL, 0) - ZEND_ARG_TYPE_INFO(0, format, IS_LONG, 0) -ZEND_END_ARG_INFO() +#define arginfo_snmp_set_oid_numeric_print arginfo_snmp_set_oid_output_format #define arginfo_snmp2_get arginfo_snmpget diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c index 74dc7731fd152..74dc3b8c99fa1 100644 --- a/ext/spl/spl_dllist.c +++ b/ext/spl/spl_dllist.c @@ -295,12 +295,13 @@ static void spl_dllist_object_free_storage(zend_object *object) /* {{{ */ zend_object_std_dtor(&intern->std); - while (intern->llist->count > 0) { - spl_ptr_llist_pop(intern->llist, &tmp); - zval_ptr_dtor(&tmp); + if (intern->llist) { + while (intern->llist->count > 0) { + spl_ptr_llist_pop(intern->llist, &tmp); + zval_ptr_dtor(&tmp); + } + spl_ptr_llist_destroy(intern->llist); } - - spl_ptr_llist_destroy(intern->llist); SPL_LLIST_CHECK_DELREF(intern->traverse_pointer); } /* }}} */ diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 7687544fc6043..95ab191b77824 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -48,6 +48,8 @@ typedef struct _spl_fixedarray { zend_long size; /* It is possible to resize this, so this can't be combined with the object */ zval *elements; + /* If positive, it's a resize within a resize and the value gives the desired size. If -1, it's not. */ + zend_long cached_resize; } spl_fixedarray; typedef struct _spl_fixedarray_object { @@ -115,6 +117,7 @@ static void spl_fixedarray_init(spl_fixedarray *array, zend_long size) } else { spl_fixedarray_default_ctor(array); } + array->cached_resize = -1; } /* Copies the range [begin, end) into the fixedarray, beginning at `offset`. @@ -146,6 +149,7 @@ static void spl_fixedarray_copy_ctor(spl_fixedarray *to, spl_fixedarray *from) */ static void spl_fixedarray_dtor_range(spl_fixedarray *array, zend_long from, zend_long to) { + array->size = from; zval *begin = array->elements + from, *end = array->elements + to; while (begin != end) { zval_ptr_dtor(begin++); @@ -181,19 +185,35 @@ static void spl_fixedarray_resize(spl_fixedarray *array, zend_long size) return; } + if (UNEXPECTED(array->cached_resize >= 0)) { + /* We're already resizing, so just remember the desired size. + * The resize will happen later. */ + array->cached_resize = size; + return; + } + array->cached_resize = size; + /* clearing the array */ if (size == 0) { spl_fixedarray_dtor(array); array->elements = NULL; + array->size = 0; } else if (size > array->size) { array->elements = safe_erealloc(array->elements, size, sizeof(zval), 0); spl_fixedarray_init_elems(array, array->size, size); + array->size = size; } else { /* size < array->size */ + /* Size set in spl_fixedarray_dtor_range() */ spl_fixedarray_dtor_range(array, size, array->size); array->elements = erealloc(array->elements, sizeof(zval) * size); } - array->size = size; + /* If resized within the destructor, take the last resize command and perform it */ + zend_long cached_resize = array->cached_resize; + array->cached_resize = -1; + if (cached_resize != size) { + spl_fixedarray_resize(array, cached_resize); + } } static HashTable* spl_fixedarray_object_get_gc(zend_object *obj, zval **table, int *n) diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index 4f242d3a3c394..5d61741425185 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -372,6 +372,11 @@ static spl_ptr_heap *spl_ptr_heap_clone(spl_ptr_heap *from) { /* {{{ */ /* }}} */ static void spl_ptr_heap_destroy(spl_ptr_heap *heap) { /* {{{ */ + /* Heap might be null if we OOMed during object initialization. */ + if (!heap) { + return; + } + int i; for (i = 0; i < heap->count; ++i) { diff --git a/ext/spl/tests/bug81992.phpt b/ext/spl/tests/bug81992.phpt new file mode 100644 index 0000000000000..52235218a78f6 --- /dev/null +++ b/ext/spl/tests/bug81992.phpt @@ -0,0 +1,32 @@ +--TEST-- +Bug #81992 (SplFixedArray::setSize() causes use-after-free) +--FILE-- +getMessage(), "\n"; + } + try { + var_dump($obj[4]); + } catch (Throwable $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$obj = new SplFixedArray(5); +$obj[0] = str_repeat("A", 10); +$obj[2] = str_repeat('B', 10); +$obj[3] = new InvalidDestructor(); +$obj[4] = str_repeat('C', 10); +$obj->setSize(2); +?> +--EXPECT-- +string(10) "AAAAAAAAAA" +Index invalid or out of range +Index invalid or out of range diff --git a/ext/spl/tests/bug81992b.phpt b/ext/spl/tests/bug81992b.phpt new file mode 100644 index 0000000000000..ba4736dfff1f3 --- /dev/null +++ b/ext/spl/tests/bug81992b.phpt @@ -0,0 +1,66 @@ +--TEST-- +Bug #81992 (SplFixedArray::setSize() causes use-after-free) - setSize variation +--FILE-- +obj->setSize($this->desiredSize); + echo "Destroyed, size is now still ", $this->obj->getSize(), "\n"; + } +} + +class DestructorLogger { + public function __construct(private int $id) {} + + public function __destruct() { + echo "Destroyed the logger with id ", $this->id, "\n"; + } +} + +function test(int $desiredSize) { + $obj = new SplFixedArray(5); + $obj[0] = str_repeat("A", 10); + $obj[1] = new DestructorLogger(1); + $obj[2] = str_repeat('B', 10); + $obj[3] = new InvalidDestructor($desiredSize, $obj); + $obj[4] = new DestructorLogger(4); + $obj->setSize(2); + echo "Size is now ", $obj->getSize(), "\n"; + echo "Done\n"; +} + +echo "--- Smaller size test ---\n"; +test(1); +echo "--- Equal size test ---\n"; +test(2); +echo "--- Larger size test ---\n"; +test(10); +?> +--EXPECT-- +--- Smaller size test --- +In destructor +Destroyed, size is now still 2 +Destroyed the logger with id 4 +Destroyed the logger with id 1 +Size is now 1 +Done +--- Equal size test --- +In destructor +Destroyed, size is now still 2 +Destroyed the logger with id 4 +Size is now 2 +Done +Destroyed the logger with id 1 +--- Larger size test --- +In destructor +Destroyed, size is now still 2 +Destroyed the logger with id 4 +Size is now 10 +Done +Destroyed the logger with id 1 diff --git a/ext/standard/tests/general_functions/highlight_heredoc.phpt b/ext/standard/tests/general_functions/highlight_heredoc.phpt index ee4e2e8281b02..d5d25f5eaf63e 100644 --- a/ext/standard/tests/general_functions/highlight_heredoc.phpt +++ b/ext/standard/tests/general_functions/highlight_heredoc.phpt @@ -16,6 +16,12 @@ DDDD; highlight_string($str); ?> --EXPECT-- - -
$x=<<<DD
jhdsjkfhjdsh
DD
."";
$a=<<<DDDD
jhdsjkfhjdsh
DDDD;
-
+

+$x=<<<DD
+jhdsjkfhjdsh
+DD
+."";
+$a=<<<DDDD
+jhdsjkfhjdsh
+DDDD;
+
diff --git a/ext/standard/tests/strings/highlight_file.phpt b/ext/standard/tests/strings/highlight_file.phpt index 28bde64a18237..048399216c907 100644 --- a/ext/standard/tests/strings/highlight_file.phpt +++ b/ext/standard/tests/strings/highlight_file.phpt @@ -42,16 +42,14 @@ Warning: highlight_file(%shighlight_file.dat): Failed to open stream: No such fi Warning: highlight_file(): Failed opening '%shighlight_file.dat' for highlighting in %s on line %d bool(false) - -<?php echo "test"?> - -bool(true) - -<?php echo "test ?> - -bool(true) - -
<?php
class test {
    public 
$var 1;
    private function 
foo() { echo "foo"; }
    public function 
bar() { var_dump(test::foo()); }
}
?> -
-
bool(true) +
<?php echo "test"; ?>
bool(true) +
<?php echo "test ?>
bool(true) +

+<?php
+class test {
+    public $var = 1;
+    private function foo() { echo "foo"; }
+    public function bar() { var_dump(test::foo()); }
+}
+?>
bool(true) Done diff --git a/ext/standard/tests/strings/show_source_basic.phpt b/ext/standard/tests/strings/show_source_basic.phpt index 4f21adf712409..a4d04c346b42d 100644 --- a/ext/standard/tests/strings/show_source_basic.phpt +++ b/ext/standard/tests/strings/show_source_basic.phpt @@ -21,7 +21,19 @@ show_source(__FILE__); ?> --EXPECT-- *** Test by calling method or function with its expected arguments *** - -<?php
echo "*** Test by calling method or function with its expected arguments ***\n";
$foo 'bar';
$baz "something ".$foo."\n";

if ( 
$foo == 'bar' )
{
  
$baz 'baz';
}

 
/* some code here */

show_source(__FILE__);

?>
-
-
+
<?php
+echo "*** Test by calling method or function with its expected arguments ***\n";
+$foo = 'bar';
+$baz = "something ".$foo."\n";
+
+if ( $foo == 'bar' )
+{
+  $baz = 'baz';
+}
+
+ /* some code here */
+
+show_source(__FILE__);
+
+?>
+
diff --git a/ext/standard/tests/strings/show_source_variation1.phpt b/ext/standard/tests/strings/show_source_variation1.phpt index 099dd233a1e95..27977809f0133 100644 --- a/ext/standard/tests/strings/show_source_variation1.phpt +++ b/ext/standard/tests/strings/show_source_variation1.phpt @@ -22,7 +22,19 @@ echo $foo; --EXPECT-- *** Test by calling method or function with its expected arguments and php output *** baz - -<?php
echo "*** Test by calling method or function with its expected arguments and php output ***\n";
$foo 'bar';
$baz "something ".$foo."\n";

if ( 
$foo == 'bar' )
{
  
$baz "baz\n";
}

 
/* some code here */
echo $baz;
show_source(__FILE__);
echo 
$foo;
?>
-
-
bar +
<?php
+echo "*** Test by calling method or function with its expected arguments and php output ***\n";
+$foo = 'bar';
+$baz = "something ".$foo."\n";
+
+if ( $foo == 'bar' )
+{
+  $baz = "baz\n";
+}
+
+ /* some code here */
+echo $baz;
+show_source(__FILE__);
+echo $foo;
+?>
+
bar diff --git a/ext/standard/tests/strings/show_source_variation2.phpt b/ext/standard/tests/strings/show_source_variation2.phpt index ca26ef29c9cec..064398356068c 100644 --- a/ext/standard/tests/strings/show_source_variation2.phpt +++ b/ext/standard/tests/strings/show_source_variation2.phpt @@ -21,7 +21,19 @@ var_dump($source); ?> --EXPECT-- *** Test by calling method or function with its expected arguments and output to variable *** -string(1975) " -<?php
echo "*** Test by calling method or function with its expected arguments and output to variable ***\n";
$foo 'bar';
$baz "something ".$foo."\n";

if ( 
$foo == 'bar' )
{
  
$baz "baz\n";
}

 
/* some code here */
$source show_source(__FILE__true);

var_dump($source);
?>
-
-
" +string(1705) "
<?php
+echo "*** Test by calling method or function with its expected arguments and output to variable ***\n";
+$foo = 'bar';
+$baz = "something ".$foo."\n";
+
+if ( $foo == 'bar' )
+{
+  $baz = "baz\n";
+}
+
+ /* some code here */
+$source = show_source(__FILE__, true);
+
+var_dump($source);
+?>
+
" diff --git a/ext/xsl/php_xsl.c b/ext/xsl/php_xsl.c index 82e782d18f9d1..5ecb7fd9b0b68 100644 --- a/ext/xsl/php_xsl.c +++ b/ext/xsl/php_xsl.c @@ -59,11 +59,15 @@ void xsl_objects_free_storage(zend_object *object) zend_object_std_dtor(&intern->std); - zend_hash_destroy(intern->parameter); - FREE_HASHTABLE(intern->parameter); + if (intern->parameter) { + zend_hash_destroy(intern->parameter); + FREE_HASHTABLE(intern->parameter); + } - zend_hash_destroy(intern->registered_phpfunctions); - FREE_HASHTABLE(intern->registered_phpfunctions); + if (intern->registered_phpfunctions) { + zend_hash_destroy(intern->registered_phpfunctions); + FREE_HASHTABLE(intern->registered_phpfunctions); + } if (intern->node_list) { zend_hash_destroy(intern->node_list); diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index b4ea2b27c9e9d..ec82c727650b3 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -884,11 +884,116 @@ static void le_throwing_resource_dtor(zend_resource *rsrc) zend_throw_exception(NULL, "Throwing resource destructor called", 0); } +static ZEND_METHOD(_ZendTestClass, takesUnionType) +{ + zend_object *obj; + ZEND_PARSE_PARAMETERS_START(1, 1); + Z_PARAM_OBJ(obj) + ZEND_PARSE_PARAMETERS_END(); + // we have to perform type-checking to avoid arginfo/zpp mismatch error + bool type_matches = ( + instanceof_function(obj->ce, zend_standard_class_def) + || + instanceof_function(obj->ce, zend_ce_iterator) + ); + if (!type_matches) { + zend_string *ty = zend_type_to_string(execute_data->func->internal_function.arg_info->type); + zend_argument_type_error(1, "must be of type %s, %s given", ty->val, obj->ce->name->val); + zend_string_release(ty); + RETURN_THROWS(); + } + + RETURN_NULL(); +} + +// Returns a newly allocated DNF type `Iterator|(Traversable&Countable)`. +// +// We need to generate it "manually" because gen_stubs.php does not support codegen for DNF types ATM. +static zend_type create_test_dnf_type(void) { + zend_string *class_Iterator = zend_string_init_interned("Iterator", sizeof("Iterator") - 1, true); + zend_alloc_ce_cache(class_Iterator); + zend_string *class_Traversable = ZSTR_KNOWN(ZEND_STR_TRAVERSABLE); + zend_string *class_Countable = zend_string_init_interned("Countable", sizeof("Countable") - 1, true); + zend_alloc_ce_cache(class_Countable); + // + zend_type_list *intersection_list = malloc(ZEND_TYPE_LIST_SIZE(2)); + intersection_list->num_types = 2; + intersection_list->types[0] = (zend_type) ZEND_TYPE_INIT_CLASS(class_Traversable, 0, 0); + intersection_list->types[1] = (zend_type) ZEND_TYPE_INIT_CLASS(class_Countable, 0, 0); + zend_type_list *union_list = malloc(ZEND_TYPE_LIST_SIZE(2)); + union_list->num_types = 2; + union_list->types[0] = (zend_type) ZEND_TYPE_INIT_CLASS(class_Iterator, 0, 0); + union_list->types[1] = (zend_type) ZEND_TYPE_INIT_INTERSECTION(intersection_list, 0); + return (zend_type) ZEND_TYPE_INIT_UNION(union_list, 0); +} + +static void register_ZendTestClass_dnf_property(zend_class_entry *ce) { + zend_string *prop_name = zend_string_init_interned("dnfProperty", sizeof("dnfProperty") - 1, true); + zval default_value; + ZVAL_UNDEF(&default_value); + zend_type type = create_test_dnf_type(); + zend_declare_typed_property(ce, prop_name, &default_value, ZEND_ACC_PUBLIC, NULL, type); +} + +// arg_info for `zend_test_internal_dnf_arguments` +// The types are upgraded to DNF types in `register_dynamic_function_entries()` +static zend_internal_arg_info arginfo_zend_test_internal_dnf_arguments[] = { + // first entry is a zend_internal_function_info (see zend_compile.h): {argument_count, return_type, unused} + {(const char*)(uintptr_t)(1), {0}, NULL}, + {"arg", {0}, NULL} +}; + +static ZEND_NAMED_FUNCTION(zend_test_internal_dnf_arguments) +{ + zend_object *obj; + ZEND_PARSE_PARAMETERS_START(1, 1); + Z_PARAM_OBJ(obj) + ZEND_PARSE_PARAMETERS_END(); + // we have to perform type-checking to avoid arginfo/zpp mismatch error + bool type_matches = ( + instanceof_function(obj->ce, zend_ce_iterator) + || ( + instanceof_function(obj->ce, zend_ce_traversable) + && instanceof_function(obj->ce, zend_ce_countable) + ) + ); + if (!type_matches) { + zend_string *ty = zend_type_to_string(arginfo_zend_test_internal_dnf_arguments[1].type); + zend_argument_type_error(1, "must be of type %s, %s given", ty->val, obj->ce->name->val); + zend_string_release(ty); + RETURN_THROWS(); + } + + RETURN_OBJ_COPY(obj); +} + +static const zend_function_entry dynamic_function_entries[] = { + { + .fname = "zend_test_internal_dnf_arguments", + .handler = zend_test_internal_dnf_arguments, + .arg_info = arginfo_zend_test_internal_dnf_arguments, + .num_args = 1, + .flags = 0, + }, + ZEND_FE_END, +}; + +static void register_dynamic_function_entries(int module_type) { + // return-type is at index 0 + arginfo_zend_test_internal_dnf_arguments[0].type = create_test_dnf_type(); + arginfo_zend_test_internal_dnf_arguments[1].type = create_test_dnf_type(); + // + zend_register_functions(NULL, dynamic_function_entries, NULL, module_type); +} + PHP_MINIT_FUNCTION(zend_test) { + register_dynamic_function_entries(type); + zend_test_interface = register_class__ZendTestInterface(); zend_test_class = register_class__ZendTestClass(zend_test_interface); + register_ZendTestClass_dnf_property(zend_test_class); zend_test_class->create_object = zend_test_class_new; zend_test_class->get_static_method = zend_test_class_static_method_get; diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index e3905a99c72eb..312ad689b31d4 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -53,6 +53,8 @@ public function returnsStatic(): static {} public function returnsThrowable(): Throwable {} static public function variadicTest(string|Iterator ...$elements) : static {} + + public function takesUnionType(stdclass|Iterator $arg): void {} } class _ZendTestChildClass extends _ZendTestClass @@ -63,6 +65,7 @@ public function returnsThrowable(): Exception {} trait _ZendTestTrait { /** @var mixed */ public $testProp; + public Traversable|Countable $classUnionProp; public function testMethod(): bool {} } diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 3a6a927984724..d5546638949b1 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: abd7a656256f9cf05466f09efcc78ef4c4c9f62b */ + * Stub hash: b458993ee586284b1e33848313d9ddf61273604e */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -172,6 +172,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestClass_variadicTes ZEND_ARG_VARIADIC_OBJ_TYPE_MASK(0, elements, Iterator, MAY_BE_STRING) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestClass_takesUnionType, 0, 1, IS_VOID, 0) + ZEND_ARG_OBJ_TYPE_MASK(0, arg, stdclass|Iterator, 0, NULL) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class__ZendTestChildClass_returnsThrowable, 0, 0, Exception, 0) ZEND_END_ARG_INFO() @@ -258,6 +262,7 @@ static ZEND_METHOD(_ZendTestClass, __toString); static ZEND_METHOD(_ZendTestClass, returnsStatic); static ZEND_METHOD(_ZendTestClass, returnsThrowable); static ZEND_METHOD(_ZendTestClass, variadicTest); +static ZEND_METHOD(_ZendTestClass, takesUnionType); static ZEND_METHOD(_ZendTestChildClass, returnsThrowable); static ZEND_METHOD(_ZendTestTrait, testMethod); static ZEND_METHOD(ZendTestParameterAttribute, __construct); @@ -340,6 +345,7 @@ static const zend_function_entry class__ZendTestClass_methods[] = { ZEND_ME(_ZendTestClass, returnsStatic, arginfo_class__ZendTestClass_returnsStatic, ZEND_ACC_PUBLIC) ZEND_ME(_ZendTestClass, returnsThrowable, arginfo_class__ZendTestClass_returnsThrowable, ZEND_ACC_PUBLIC) ZEND_ME(_ZendTestClass, variadicTest, arginfo_class__ZendTestClass_variadicTest, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(_ZendTestClass, takesUnionType, arginfo_class__ZendTestClass_takesUnionType, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -591,6 +597,19 @@ static zend_class_entry *register_class__ZendTestTrait(void) zend_declare_property_ex(class_entry, property_testProp_name, &property_testProp_default_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(property_testProp_name); + zval property_classUnionProp_default_value; + ZVAL_UNDEF(&property_classUnionProp_default_value); + zend_string *property_classUnionProp_name = zend_string_init("classUnionProp", sizeof("classUnionProp") - 1, 1); + zend_string *property_classUnionProp_class_Traversable = zend_string_init("Traversable", sizeof("Traversable") - 1, 1); + zend_string *property_classUnionProp_class_Countable = zend_string_init("Countable", sizeof("Countable") - 1, 1); + zend_type_list *property_classUnionProp_type_list = malloc(ZEND_TYPE_LIST_SIZE(2)); + property_classUnionProp_type_list->num_types = 2; + property_classUnionProp_type_list->types[0] = (zend_type) ZEND_TYPE_INIT_CLASS(property_classUnionProp_class_Traversable, 0, 0); + property_classUnionProp_type_list->types[1] = (zend_type) ZEND_TYPE_INIT_CLASS(property_classUnionProp_class_Countable, 0, 0); + zend_type property_classUnionProp_type = ZEND_TYPE_INIT_UNION(property_classUnionProp_type_list, 0); + zend_declare_typed_property(class_entry, property_classUnionProp_name, &property_classUnionProp_default_value, ZEND_ACC_PUBLIC, NULL, property_classUnionProp_type); + zend_string_release(property_classUnionProp_name); + return class_entry; } diff --git a/ext/zend_test/tests/internal_dnf_arguments.phpt b/ext/zend_test/tests/internal_dnf_arguments.phpt new file mode 100644 index 0000000000000..eb6f5fb514f00 --- /dev/null +++ b/ext/zend_test/tests/internal_dnf_arguments.phpt @@ -0,0 +1,34 @@ +--TEST-- +DNF types for internal functions +--EXTENSIONS-- +zend_test +spl +reflection +--FILE-- +getReturnType()); +$paramType = $rf->getParameters()[0]->getType(); +var_dump((string)$paramType); + +try { + zend_test_internal_dnf_arguments(new stdClass); +} catch (\Throwable $err) { + echo $err->getMessage(), "\n"; +} + +$obj = new \ArrayIterator([]); +$result = zend_test_internal_dnf_arguments($obj); +var_dump($result); + +?> +--EXPECT-- +string(32) "Iterator|(Traversable&Countable)" +string(32) "Iterator|(Traversable&Countable)" +zend_test_internal_dnf_arguments(): Argument #1 ($arg) must be of type Iterator|(Traversable&Countable), stdClass given +object(ArrayIterator)#5 (1) { + ["storage":"ArrayIterator":private]=> + array(0) { + } +} diff --git a/ext/zip/config.m4 b/ext/zip/config.m4 index 5111f91ee358b..3b60bb3e54303 100644 --- a/ext/zip/config.m4 +++ b/ext/zip/config.m4 @@ -65,7 +65,4 @@ if test "$PHP_ZIP" != "no"; then PHP_NEW_EXTENSION(zip, $PHP_ZIP_SOURCES, $ext_shared) PHP_SUBST(ZIP_SHARED_LIBADD) - - dnl so we always include the known-good working hack. - PHP_ADD_MAKEFILE_FRAGMENT fi diff --git a/ext/zip/php_zip.h b/ext/zip/php_zip.h index f57006363917e..520b2599bacc4 100644 --- a/ext/zip/php_zip.h +++ b/ext/zip/php_zip.h @@ -39,7 +39,7 @@ extern zend_module_entry zip_module_entry; /* Additionnal flags not from libzip */ #define ZIP_FL_OPEN_FILE_NOW (1u<<30) -#define PHP_ZIP_VERSION "1.22.1" +#define PHP_ZIP_VERSION "1.22.2" #ifdef HAVE_LIBZIP_VERSION #define LIBZIP_VERSION_STR zip_libzip_version() diff --git a/main/spprintf.c b/main/spprintf.c index 37b81dc6d530b..64bde33406073 100644 --- a/main/spprintf.c +++ b/main/spprintf.c @@ -175,13 +175,6 @@ /* }}} */ -#if !HAVE_STRNLEN -static size_t strnlen(const char *s, size_t maxlen) { - char *r = memchr(s, '\0', maxlen); - return r ? r-s : maxlen; -} -#endif - /* * Do format conversion placing the output in buffer */ @@ -552,7 +545,7 @@ static void xbuf_format_converter(void *xbuf, bool is_char, const char *fmt, va_ if (!adjust_precision) { s_len = strlen(s); } else { - s_len = strnlen(s, precision); + s_len = zend_strnlen(s, precision); } } else { s = S_NULL; diff --git a/php.ini-development b/php.ini-development index c837e82c2fe8e..445bedf26b01b 100644 --- a/php.ini-development +++ b/php.ini-development @@ -1211,9 +1211,6 @@ mysqli.default_user = ; https://php.net/mysqli.default-pw mysqli.default_pw = -; Allow or prevent reconnect -mysqli.reconnect = Off - ; If this option is enabled, closing a persistent connection will rollback ; any pending transactions of this connection, before it is put back ; into the persistent connection pool. diff --git a/php.ini-production b/php.ini-production index 0c9c82f56a348..20e48837cd03f 100644 --- a/php.ini-production +++ b/php.ini-production @@ -1213,9 +1213,6 @@ mysqli.default_user = ; https://php.net/mysqli.default-pw mysqli.default_pw = -; Allow or prevent reconnect -mysqli.reconnect = Off - ; If this option is enabled, closing a persistent connection will rollback ; any pending transactions of this connection, before it is put back ; into the persistent connection pool. diff --git a/run-tests.php b/run-tests.php index 6f10e4090bdbf..1bcc6aa7b22d9 100755 --- a/run-tests.php +++ b/run-tests.php @@ -683,8 +683,8 @@ function main(): void $environment['TEST_PHP_EXECUTABLE_ESCAPED'] = escapeshellarg($php); putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi"); $environment['TEST_PHP_CGI_EXECUTABLE'] = $php_cgi; - putenv("TEST_PHP_CGI_EXECUTABLE_ESCAPED=" . escapeshellarg($php_cgi)); - $environment['TEST_PHP_CGI_EXECUTABLE_ESCAPED'] = escapeshellarg($php_cgi); + putenv("TEST_PHP_CGI_EXECUTABLE_ESCAPED=" . escapeshellarg($php_cgi ?? '')); + $environment['TEST_PHP_CGI_EXECUTABLE_ESCAPED'] = escapeshellarg($php_cgi ?? ''); putenv("TEST_PHPDBG_EXECUTABLE=$phpdbg"); $environment['TEST_PHPDBG_EXECUTABLE'] = $phpdbg; putenv("TEST_PHPDBG_EXECUTABLE_ESCAPED=" . escapeshellarg($phpdbg ?? '')); diff --git a/sapi/cgi/tests/008.phpt b/sapi/cgi/tests/008.phpt index 05d9d8c190e87..5ba21028b3327 100644 --- a/sapi/cgi/tests/008.phpt +++ b/sapi/cgi/tests/008.phpt @@ -41,10 +41,22 @@ echo "Done\n"; string(%d) "X-Powered-By: PHP/%s Content-type: text/html%r; charset=.*|%r - -
<?php
$test 
"var"//var
/* test class */
class test {
    private 
$var = array();

    public static function 
foo(Test $arg) {
        echo 
"hello";
        
var_dump($this);
    }
}

$o = new test;
?>
-
-
" +

+<?php
+$test = "var"; //var
+/* test class */
+class test {
+    private $var = array();
+
+    public static function foo(Test $arg) {
+        echo "hello";
+        var_dump($this);
+    }
+}
+
+$o = new test;
+?>
+
" string(%d) "Status: 404 Not Found X-Powered-By: PHP/%s Content-type: text/html%r; charset=.*|%r diff --git a/sapi/cli/tests/014.phpt b/sapi/cli/tests/014.phpt index 734eef0c2ce95..8a13433d643bc 100644 --- a/sapi/cli/tests/014.phpt +++ b/sapi/cli/tests/014.phpt @@ -36,10 +36,22 @@ var_dump(`$php -n -s unknown`); echo "Done\n"; ?> --EXPECT-- -string(1478) " -
<?php
$test 
"var"//var
/* test class */
class test {
    private 
$var = array();

    public static function 
foo(Test $arg) {
        echo 
"hello";
        
var_dump($this);
    }
}

$o = new test;
?>
-
-
" +string(1158) "

+<?php
+$test = "var"; //var
+/* test class */
+class test {
+    private $var = array();
+
+    public static function foo(Test $arg) {
+        echo "hello";
+        var_dump($this);
+    }
+}
+
+$o = new test;
+?>
+
" Could not open input file: unknown NULL Done diff --git a/sapi/cli/tests/ext_loading.phpt b/sapi/cli/tests/ext_loading.phpt index 220302da629df..1769f1f657555 100644 --- a/sapi/cli/tests/ext_loading.phpt +++ b/sapi/cli/tests/ext_loading.phpt @@ -10,7 +10,6 @@ if (!file_exists($extDir . '/opcache.so') && !file_exists($extDir . '/php_opcach --FILE-- --EXPECTF-- Only extension name: -Output: Done. +#####OUTPUT_BEGIN#### +Done. +######OUTPUT_END##### Name with file extension: -Output: Done. +#####OUTPUT_BEGIN#### +Done. +######OUTPUT_END##### Absolute path: -Output: Done. +#####OUTPUT_BEGIN#### +Done. +######OUTPUT_END##### Unknown extension name (unknown): -Output: +#####OUTPUT_BEGIN#### + Warning: Failed loading Zend extension 'unknown_ext' (tried: %s) in Unknown on line 0 Done. +######OUTPUT_END##### Name with file extension (unknown): -Output: +#####OUTPUT_BEGIN#### + Warning: Failed loading Zend extension '%Sunknown_ext%S' (tried: %s) in Unknown on line 0 Done. +######OUTPUT_END##### Absolute path (unknown): -Output: Failed loading %s +#####OUTPUT_BEGIN#### +Failed loading %s Done. +######OUTPUT_END##### diff --git a/sapi/cli/tests/php_cli_server_pdeathsig.phpt b/sapi/cli/tests/php_cli_server_pdeathsig.phpt index db4b99af61a43..8b70bbcad4927 100644 --- a/sapi/cli/tests/php_cli_server_pdeathsig.phpt +++ b/sapi/cli/tests/php_cli_server_pdeathsig.phpt @@ -8,8 +8,7 @@ include "skipif.inc"; if (!(str_contains(PHP_OS, 'Linux') || str_contains(PHP_OS, 'FreeBSD'))) { die('skip PDEATHSIG is only supported on Linux and FreeBSD'); } -// This fails on 32-bit GitHub actions (probably due to Docker rather than 32-bit) -if (PHP_INT_SIZE != 8) die("skip 64-bit only"); +if (@file_exists('/.dockerenv')) die("skip Broken in Docker"); ?> --FILE--
", TRUE); echo "\n[$var]\n"; ?> --EXPECT-- - -<br /><?php echo "foo"?><br /> - -[ -<br /><?php echo "bar"?><br /> -] +
<br /><?php echo "foo"; ?><br />
+[
<br /><?php echo "bar"; ?><br />
] diff --git a/tests/strings/bug26703.phpt b/tests/strings/bug26703.phpt index 4e48845fdf0a1..aaa7833f01660 100644 --- a/tests/strings/bug26703.phpt +++ b/tests/strings/bug26703.phpt @@ -11,7 +11,4 @@ highlight.html=#000000 highlight_string(''); ?> --EXPECT-- - -<?php echo "foo[] $a \n"?> - - +
<?php echo "foo[] $a \n"; ?>