From d258417afbed101feba6f5869a43043716f0b61a Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Mon, 3 Jun 2024 23:16:15 +0800 Subject: [PATCH] Fix several patches & newer phpmicro support (#470) * use upstream phpmicro * move src/global/tests to src/global/ext-tests * move src/global/tests to src/global/ext-tests * prevent file_get_contents memory insufficience * update README * fix libxml >= 2.12 with older PHP (<=8.1) build bug * cleanup code, support newer phpmicro * add --no-strip and --with-upx-pack tests * fix windows sanity check for newer phpmicro * fix windows sanity check for newer phpmicro * test * test * test * update deps for ci --- .github/workflows/tests.yml | 24 +- README-zh.md | 4 +- README.md | 4 +- config/source.json | 2 +- phpstan.neon | 4 +- src/SPC/builder/BuilderBase.php | 41 ++ src/SPC/builder/BuilderProvider.php | 2 + src/SPC/builder/Extension.php | 12 +- src/SPC/builder/freebsd/BSDBuilder.php | 4 +- src/SPC/builder/linux/LinuxBuilder.php | 38 +- src/SPC/builder/macos/MacOSBuilder.php | 4 +- src/SPC/builder/unix/UnixBuilderBase.php | 30 +- src/SPC/builder/windows/WindowsBuilder.php | 62 +-- src/SPC/command/BaseCommand.php | 2 + src/SPC/store/FileSystem.php | 15 + src/SPC/store/SourcePatcher.php | 54 +++ .../micro_zend_mm_heap_corrupted.txt | 361 ++++++++++++++++++ src/globals/{tests => ext-tests}/bcmath.php | 0 src/globals/{tests => ext-tests}/bz2.php | 0 src/globals/{tests => ext-tests}/calendar.php | 0 src/globals/{tests => ext-tests}/curl.php | 0 src/globals/{tests => ext-tests}/dom.php | 0 src/globals/{tests => ext-tests}/filter.php | 0 src/globals/{tests => ext-tests}/gd.php | 0 src/globals/{tests => ext-tests}/gettext.php | 0 src/globals/{tests => ext-tests}/intl.php | 0 src/globals/{tests => ext-tests}/openssl.php | 0 src/globals/{tests => ext-tests}/parallel.php | 0 src/globals/{tests => ext-tests}/redis.php | 0 src/globals/{tests => ext-tests}/swoole.php | 0 src/globals/{tests => ext-tests}/uuid.php | 0 src/globals/{tests => ext-tests}/zip.php | 0 src/globals/{tests => ext-tests}/zlib.php | 0 .../patch/spc_fix_libxml2_12_php80.patch | 89 +++++ .../patch/spc_fix_libxml2_12_php81.patch | 55 +++ src/globals/test-extensions.php | 6 + 36 files changed, 742 insertions(+), 71 deletions(-) create mode 100644 src/globals/common-tests/micro_zend_mm_heap_corrupted.txt rename src/globals/{tests => ext-tests}/bcmath.php (100%) rename src/globals/{tests => ext-tests}/bz2.php (100%) rename src/globals/{tests => ext-tests}/calendar.php (100%) rename src/globals/{tests => ext-tests}/curl.php (100%) rename src/globals/{tests => ext-tests}/dom.php (100%) rename src/globals/{tests => ext-tests}/filter.php (100%) rename src/globals/{tests => ext-tests}/gd.php (100%) rename src/globals/{tests => ext-tests}/gettext.php (100%) rename src/globals/{tests => ext-tests}/intl.php (100%) rename src/globals/{tests => ext-tests}/openssl.php (100%) rename src/globals/{tests => ext-tests}/parallel.php (100%) rename src/globals/{tests => ext-tests}/redis.php (100%) rename src/globals/{tests => ext-tests}/swoole.php (100%) rename src/globals/{tests => ext-tests}/uuid.php (100%) rename src/globals/{tests => ext-tests}/zip.php (100%) rename src/globals/{tests => ext-tests}/zlib.php (100%) create mode 100644 src/globals/patch/spc_fix_libxml2_12_php80.patch create mode 100644 src/globals/patch/spc_fix_libxml2_12_php81.patch diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d3f688d8..ab5aa4a2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -147,7 +147,7 @@ jobs: # Cache downloaded source - id: cache-download - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: downloads key: php-${{ matrix.php }}-dependencies @@ -158,6 +158,19 @@ jobs: - name: "Run Build Tests (doctor)" run: bin/spc doctor --auto-fix + - name: "Prepare UPX for Windows" + if: matrix.os == 'windows-latest' + run: | + bin/spc install-pkg upx + echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $env:GITHUB_ENV + + - name: "Prepare UPX for Linux" + if: matrix.os == 'ubunut-latest' + run: | + bin/spc install-pkg upx + echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $GITHUB_ENV + + - name: "Run Build Tests (download)" uses: nick-fields/retry@v3 with: @@ -167,5 +180,10 @@ jobs: command: | bin/spc download --for-extensions="$(php src/globals/test-extensions.php extensions)" --for-libs="$(php src/globals/test-extensions.php libs)" --with-php=${{ matrix.php }} --ignore-cache-sources=php-src --debug --retry=3 - - name: "Run Build Tests (build)" - run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php zts) --with-libs="$(php src/globals/test-extensions.php libs)" --build-cli --build-micro --build-fpm --debug + - name: "Run Build Tests (build, *nix)" + if: matrix.os != 'windows-latest' + run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php zts) $(php src/globals/test-extensions.php no_strip) $UPX_CMD --with-libs="$(php src/globals/test-extensions.php libs)" --build-cli --build-micro --build-fpm --debug + + - name: "Run Build Tests (build, windows)" + if: matrix.os == 'windows-latest' + run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php zts) $(php src/globals/test-extensions.php no_strip) $env:UPX_CMD --with-libs="$(php src/globals/test-extensions.php libs)" --build-cli --build-micro --build-fpm --debug \ No newline at end of file diff --git a/README-zh.md b/README-zh.md index 11fbe4e6..8b64a65c 100755 --- a/README-zh.md +++ b/README-zh.md @@ -74,7 +74,7 @@ static-php-cli(简称 `spc`)有许多特性: 当前支持编译的 PHP 版本: -> :warning: 支持,但可能不再提供修复 +> :warning: 支持,但 static-php-cli 作者可能不再提供补丁修复 > > :heavy_check_mark: 支持 > @@ -86,7 +86,7 @@ static-php-cli(简称 `spc`)有许多特性: | 7.3 | :warning: | phpmicro 和许多扩展不支持 7.3、7.4 版本 | | 7.4 | :warning: | phpmicro 和许多扩展不支持 7.3、7.4 版本 | | 8.0 | :heavy_check_mark: | PHP 官方已停止 8.0 的维护 | -| 8.1 | :heavy_check_mark: | | +| 8.1 | :heavy_check_mark: | PHP 官方仅对 8.1 提供安全更新 | | 8.2 | :heavy_check_mark: | | | 8.3 | :heavy_check_mark: | | diff --git a/README.md b/README.md index 91e8953c..c61cb7d7 100755 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ Here is the supported OS and arch, where :octocat: represents support for GitHub Currently supported PHP versions for compilation: -> :warning: supported but not maintained +> :warning: supported but not maintained by static-php-cli authors > > :heavy_check_mark: supported > @@ -94,7 +94,7 @@ Currently supported PHP versions for compilation: | 7.3 | :warning: | phpmicro and some extensions not supported on 7.x | | 7.4 | :warning: | phpmicro and some extensions not supported on 7.x | | 8.0 | :heavy_check_mark: | PHP official has stopped maintenance of 8.0 | -| 8.1 | :heavy_check_mark: | | +| 8.1 | :heavy_check_mark: | PHP official has security fixes only | | 8.2 | :heavy_check_mark: | | | 8.3 | :heavy_check_mark: | | diff --git a/config/source.json b/config/source.json index b666ca6c..789f4e31 100644 --- a/config/source.json +++ b/config/source.json @@ -463,7 +463,7 @@ "type": "git", "path": "php-src/sapi/micro", "rev": "master", - "url": "https://github.com/static-php/phpmicro", + "url": "https://github.com/easysoft/phpmicro", "license": { "type": "file", "path": "LICENSE" diff --git a/phpstan.neon b/phpstan.neon index 56d8183c..241a8dbb 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -13,6 +13,6 @@ parameters: - PHP_OS_FAMILY excludePaths: analyseAndScan: - - ./src/globals/tests/swoole.php - - ./src/globals/tests/swoole.phpt + - ./src/globals/ext-tests/swoole.php + - ./src/globals/ext-tests/swoole.phpt - ./src/globals/test-extensions.php \ No newline at end of file diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index fb3fd70f..f2ab2dd8 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -9,6 +9,7 @@ use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; use SPC\store\Config; +use SPC\store\FileSystem; use SPC\store\SourceManager; use SPC\util\CustomExt; @@ -275,6 +276,24 @@ abstract class BuilderBase return false; } + public function getMicroVersion(): false|string + { + $file = FileSystem::convertPath(SOURCE_PATH . '/php-src/sapi/micro/php_micro.h'); + if (!file_exists($file)) { + return false; + } + + $content = file_get_contents($file); + $ver = ''; + preg_match('/#define PHP_MICRO_VER_MAJ (\d)/m', $content, $match); + $ver .= $match[1] . '.'; + preg_match('/#define PHP_MICRO_VER_MIN (\d)/m', $content, $match); + $ver .= $match[1] . '.'; + preg_match('/#define PHP_MICRO_VER_PAT (\d)/m', $content, $match); + $ver .= $match[1]; + return $ver; + } + /** * Get build type name string to display. * @@ -434,4 +453,26 @@ abstract class BuilderBase $php .= "echo '[micro-test-end]';\n"; return $php; } + + protected function getMicroTestTasks(): array + { + return [ + 'micro_ext_test' => [ + 'content' => ($this->getOption('without-micro-ext-test') ? 'generateMicroExtTests()), + 'conditions' => [ + function ($ret) { return $ret === 0; }, + function ($ret, $out) { + $raw_out = trim(implode('', $out)); + return str_starts_with($raw_out, '[micro-test-start]') && str_ends_with($raw_out, '[micro-test-end]'); + }, + ], + ], + 'micro_zend_bug_test' => [ + 'content' => ($this->getOption('without-micro-ext-test') ? ' [ + function ($ret) { return $ret === 0; }, + ], + ], + ]; + } } diff --git a/src/SPC/builder/BuilderProvider.php b/src/SPC/builder/BuilderProvider.php index fb6d3cef..fd52a217 100644 --- a/src/SPC/builder/BuilderProvider.php +++ b/src/SPC/builder/BuilderProvider.php @@ -27,6 +27,8 @@ class BuilderProvider */ public static function makeBuilderByInput(InputInterface $input): BuilderBase { + ini_set('memory_limit', '2G'); + self::$builder = match (PHP_OS_FAMILY) { 'Windows' => new WindowsBuilder($input->getOptions()), 'Darwin' => new MacOSBuilder($input->getOptions()), diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 5a317184..562db372 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -170,19 +170,19 @@ class Extension public function runCliCheckUnix(): void { // Run compile check if build target is cli - // If you need to run some check, overwrite this or add your assert in src/globals/tests/{extension_name}.php + // If you need to run some check, overwrite this or add your assert in src/globals/ext-tests/{extension_name}.php // If check failed, throw RuntimeException [$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "' . $this->getDistName() . '"', false); if ($ret !== 0) { throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret); } - if (file_exists(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php')) { + if (file_exists(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php')) { // Trim additional content & escape special characters to allow inline usage $test = str_replace( ['getName() . '.php') + file_get_contents(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php') ); [$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -r "' . trim($test) . '"'); @@ -201,19 +201,19 @@ class Extension public function runCliCheckWindows(): void { // Run compile check if build target is cli - // If you need to run some check, overwrite this or add your assert in src/globals/tests/{extension_name}.php + // If you need to run some check, overwrite this or add your assert in src/globals/ext-tests/{extension_name}.php // If check failed, throw RuntimeException [$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe --ri "' . $this->getDistName() . '"', false); if ($ret !== 0) { throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret); } - if (file_exists(FileSystem::convertPath(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php'))) { + if (file_exists(FileSystem::convertPath(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php'))) { // Trim additional content & escape special characters to allow inline usage $test = str_replace( ['getName() . '.php')) + file_get_contents(FileSystem::convertPath(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php')) ); [$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe -r "' . trim($test) . '"'); diff --git a/src/SPC/builder/freebsd/BSDBuilder.php b/src/SPC/builder/freebsd/BSDBuilder.php index ffb44316..fad4a830 100644 --- a/src/SPC/builder/freebsd/BSDBuilder.php +++ b/src/SPC/builder/freebsd/BSDBuilder.php @@ -181,7 +181,7 @@ class BSDBuilder extends UnixBuilderBase } if ($this->getExt('phar')) { $this->phar_patched = true; - SourcePatcher::patchMicro(['phar']); + SourcePatcher::patchMicroPhar($this->getPHPVersionID()); } $enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : ''; @@ -202,7 +202,7 @@ class BSDBuilder extends UnixBuilderBase $this->deployBinary(BUILD_TARGET_MICRO); if ($this->phar_patched) { - SourcePatcher::patchMicro(['phar'], true); + SourcePatcher::unpatchMicroPhar(); } } diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index c921ff69..14a1b987 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -149,7 +149,11 @@ class LinuxBuilder extends UnixBuilderBase // process micro upx patch if micro sapi enabled if ($enable_micro) { - $this->processMicroUPX(); + if (version_compare($this->getMicroVersion(), '0.2.0') < 0) { + // for phpmicro 0.1.x + $this->processMicroUPXLegacy(); + } + // micro latest needs do strip and upx pack later (strip, upx, cut binary manually supported) } shell()->cd(SOURCE_PATH . '/php-src') @@ -236,7 +240,7 @@ class LinuxBuilder extends UnixBuilderBase } if ($this->getExt('phar')) { $this->phar_patched = true; - SourcePatcher::patchMicro(['phar']); + SourcePatcher::patchMicroPhar($this->getPHPVersionID()); } $enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : ''; @@ -250,10 +254,12 @@ class LinuxBuilder extends UnixBuilderBase ->exec('sed -i "s|//lib|/lib|g" Makefile') ->exec("\$SPC_CMD_PREFIX_PHP_MAKE {$vars} micro"); + $this->processMicroUPX(); + $this->deployBinary(BUILD_TARGET_MICRO); if ($this->phar_patched) { - SourcePatcher::patchMicro(['phar'], true); + SourcePatcher::unpatchMicroPhar(); } } @@ -304,11 +310,11 @@ class LinuxBuilder extends UnixBuilderBase } /** - * Apply option --no-strip and --with-upx-pack for micro sapi. + * Apply option --no-strip and --with-upx-pack for micro sapi (only for phpmicro 0.1.x) * * @throws FileSystemException */ - private function processMicroUPX(): void + private function processMicroUPXLegacy(): void { // upx pack and strip for micro // but always restore Makefile.frag.bak first @@ -346,4 +352,26 @@ class LinuxBuilder extends UnixBuilderBase ); } } + + private function processMicroUPX(): void + { + if (version_compare($this->getMicroVersion(), '0.2.0') >= 0 && !$this->getOption('no-strip', false)) { + shell()->exec('strip --strip-all ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx'); + + if ($this->getOption('with-upx-pack')) { + // strip first + shell()->exec(getenv('UPX_EXEC') . ' --best ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx'); + // cut binary with readelf + [$ret, $out] = shell()->execWithResult('readelf -l ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx | awk \'/LOAD|GNU_STACK/ {getline; print $1, $2, $3, $4, $6, $7}\''); + $out[1] = explode(' ', $out[1]); + $offset = $out[1][0]; + if ($ret !== 0 || !str_starts_with($offset, '0x')) { + throw new RuntimeException('Cannot find offset in readelf output'); + } + $offset = hexdec($offset); + // remove upx extra wastes + file_put_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx', substr(file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx'), 0, $offset)); + } + } + } } diff --git a/src/SPC/builder/macos/MacOSBuilder.php b/src/SPC/builder/macos/MacOSBuilder.php index a6769cee..ddcfcb64 100644 --- a/src/SPC/builder/macos/MacOSBuilder.php +++ b/src/SPC/builder/macos/MacOSBuilder.php @@ -233,7 +233,7 @@ class MacOSBuilder extends UnixBuilderBase } if ($this->getExt('phar')) { $this->phar_patched = true; - SourcePatcher::patchMicro(['phar']); + SourcePatcher::patchMicroPhar($this->getPHPVersionID()); } $enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : ''; @@ -251,7 +251,7 @@ class MacOSBuilder extends UnixBuilderBase $this->deployBinary(BUILD_TARGET_MICRO); if ($this->phar_patched) { - SourcePatcher::patchMicro(['phar'], true); + SourcePatcher::unpatchMicroPhar(); } } diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 7b17698a..76d6768a 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -162,22 +162,20 @@ abstract class UnixBuilderBase extends BuilderBase // sanity check for phpmicro if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) { - if (file_exists(SOURCE_PATH . '/hello.exe')) { - @unlink(SOURCE_PATH . '/hello.exe'); - } - file_put_contents( - SOURCE_PATH . '/hello.exe', - file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx') . - ($this->getOption('without-micro-ext-test') ? 'generateMicroExtTests()) - ); - chmod(SOURCE_PATH . '/hello.exe', 0755); - [$ret, $output2] = shell()->execWithResult(SOURCE_PATH . '/hello.exe'); - $raw_out = trim(implode('', $output2)); - $condition[0] = $ret === 0; - $condition[1] = str_starts_with($raw_out, '[micro-test-start]') && str_ends_with($raw_out, '[micro-test-end]'); - foreach ($condition as $k => $v) { - if (!$v) { - throw new RuntimeException("micro failed sanity check with condition[{$k}], ret[{$ret}], out[{$raw_out}]"); + $test_task = $this->getMicroTestTasks(); + foreach ($test_task as $task_name => $task) { + $test_file = SOURCE_PATH . '/' . $task_name . '.exe'; + if (file_exists($test_file)) { + @unlink($test_file); + } + file_put_contents($test_file, file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx') . $task['content']); + chmod($test_file, 0755); + [$ret, $out] = shell()->execWithResult($test_file); + foreach ($task['conditions'] as $condition => $closure) { + if (!$closure($ret, $out)) { + $raw_out = trim(implode('', $out)); + throw new RuntimeException("micro failed sanity check: {$task_name}, condition [{$condition}], ret[{$ret}], out[{$raw_out}]"); + } } } } diff --git a/src/SPC/builder/windows/WindowsBuilder.php b/src/SPC/builder/windows/WindowsBuilder.php index 6da09257..7c1f9ff7 100644 --- a/src/SPC/builder/windows/WindowsBuilder.php +++ b/src/SPC/builder/windows/WindowsBuilder.php @@ -80,16 +80,18 @@ class WindowsBuilder extends BuilderBase $zts = $this->zts ? '--enable-zts=yes ' : '--enable-zts=no '; // with-upx-pack for phpmicro - $makefile = FileSystem::convertPath(SOURCE_PATH . '/php-src/sapi/micro/Makefile.frag.w32'); - if ($this->getOption('with-upx-pack', false)) { - if (!file_exists($makefile . '.originfile')) { - copy($makefile, $makefile . '.originfile'); - FileSystem::replaceFileStr($makefile, '$(MICRO_SFX):', '_MICRO_UPX = ' . getenv('UPX_EXEC') . " --best $(MICRO_SFX)\n$(MICRO_SFX):"); - FileSystem::replaceFileStr($makefile, '@$(_MICRO_MT)', "@$(_MICRO_MT)\n\t@$(_MICRO_UPX)"); + if ($enableMicro && version_compare($this->getMicroVersion(), '0.2.0') < 0) { + $makefile = FileSystem::convertPath(SOURCE_PATH . '/php-src/sapi/micro/Makefile.frag.w32'); + if ($this->getOption('with-upx-pack', false)) { + if (!file_exists($makefile . '.originfile')) { + copy($makefile, $makefile . '.originfile'); + FileSystem::replaceFileStr($makefile, '$(MICRO_SFX):', '_MICRO_UPX = ' . getenv('UPX_EXEC') . " --best $(MICRO_SFX)\n$(MICRO_SFX):"); + FileSystem::replaceFileStr($makefile, '@$(_MICRO_MT)', "@$(_MICRO_MT)\n\t@$(_MICRO_UPX)"); + } + } elseif (file_exists($makefile . '.originfile')) { + copy($makefile . '.originfile', $makefile); + unlink($makefile . '.originfile'); } - } elseif (file_exists($makefile . '.originfile')) { - copy($makefile . '.originfile', $makefile); - unlink($makefile . '.originfile'); } if (($logo = $this->getOption('with-micro-logo')) !== null) { @@ -191,14 +193,14 @@ class WindowsBuilder extends BuilderBase // phar patch for micro if ($this->getExt('phar')) { $this->phar_patched = true; - SourcePatcher::patchMicro(['phar']); + SourcePatcher::patchMicroPhar($this->getPHPVersionID()); } try { cmd()->cd(SOURCE_PATH . '\php-src')->exec("{$this->sdk_prefix} nmake_micro_wrapper.bat --task-args micro"); } finally { if ($this->phar_patched) { - SourcePatcher::patchMicro(['phar'], true); + SourcePatcher::unpatchMicroPhar(); } } @@ -283,22 +285,20 @@ class WindowsBuilder extends BuilderBase // sanity check for phpmicro if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) { - if (file_exists(SOURCE_PATH . '\hello.exe')) { - @unlink(SOURCE_PATH . '\hello.exe'); - } - file_put_contents( - SOURCE_PATH . '\hello.exe', - file_get_contents(BUILD_ROOT_PATH . '\bin\micro.sfx') . - ($this->getOption('without-micro-ext-test') ? 'generateMicroExtTests()) - ); - chmod(SOURCE_PATH . '\hello.exe', 0755); - [$ret, $output2] = cmd()->execWithResult(SOURCE_PATH . '\hello.exe'); - $raw_out = trim(implode('', $output2)); - $condition[0] = $ret === 0; - $condition[1] = str_starts_with($raw_out, '[micro-test-start]') && str_ends_with($raw_out, '[micro-test-end]'); - foreach ($condition as $k => $v) { - if (!$v) { - throw new RuntimeException("micro failed sanity check with condition[{$k}], ret[{$ret}], out[{$raw_out}]"); + $test_task = $this->getMicroTestTasks(); + foreach ($test_task as $task_name => $task) { + $test_file = SOURCE_PATH . '/' . $task_name . '.exe'; + if (file_exists($test_file)) { + @unlink($test_file); + } + file_put_contents($test_file, file_get_contents(BUILD_ROOT_PATH . '\bin\micro.sfx') . $task['content']); + chmod($test_file, 0755); + [$ret, $out] = cmd()->execWithResult($test_file); + foreach ($task['conditions'] as $condition => $closure) { + if (!$closure($ret, $out)) { + $raw_out = trim(implode('', $out)); + throw new RuntimeException("micro failed sanity check: {$task_name}, condition [{$condition}], ret[{$ret}], out[{$raw_out}]"); + } } } } @@ -320,9 +320,11 @@ class WindowsBuilder extends BuilderBase default => throw new RuntimeException('Deployment does not accept type ' . $type), }; - // with-upx-pack for cli - if ($this->getOption('with-upx-pack', false) && $type === BUILD_TARGET_CLI) { - cmd()->exec(getenv('UPX_EXEC') . ' --best ' . escapeshellarg($src)); + // with-upx-pack for cli and micro + if ($this->getOption('with-upx-pack', false)) { + if ($type === BUILD_TARGET_CLI || ($type === BUILD_TARGET_MICRO && version_compare($this->getMicroVersion(), '0.2.0') >= 0)) { + cmd()->exec(getenv('UPX_EXEC') . ' --best ' . escapeshellarg($src)); + } } logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file'); diff --git a/src/SPC/command/BaseCommand.php b/src/SPC/command/BaseCommand.php index 96ccc784..041b53a5 100644 --- a/src/SPC/command/BaseCommand.php +++ b/src/SPC/command/BaseCommand.php @@ -96,6 +96,8 @@ abstract class BaseCommand extends Command }); if ($this->shouldExecute()) { try { + // show raw argv list for logger()->debug + logger()->debug('argv: ' . implode(' ', $_SERVER['argv'])); return $this->handle(); } catch (WrongUsageException $e) { $msg = explode("\n", $e->getMessage()); diff --git a/src/SPC/store/FileSystem.php b/src/SPC/store/FileSystem.php index 732c5b3c..6295a889 100644 --- a/src/SPC/store/FileSystem.php +++ b/src/SPC/store/FileSystem.php @@ -436,6 +436,21 @@ class FileSystem return str_replace(array_keys($replacement), array_values($replacement), $path); } + public static function backupFile(string $path): string + { + copy($path, $path . '.bak'); + return $path . '.bak'; + } + + public static function restoreBackupFile(string $path): void + { + if (!file_exists($path . '.bak')) { + throw new RuntimeException('Cannot find bak file for ' . $path); + } + copy($path . '.bak', $path); + unlink($path . '.bak'); + } + /** * @throws RuntimeException * @throws FileSystemException diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index 53f74ddc..4bae1f5a 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -18,6 +18,7 @@ class SourcePatcher FileSystem::addSourceExtractHook('micro', [SourcePatcher::class, 'patchMicro']); FileSystem::addSourceExtractHook('openssl', [SourcePatcher::class, 'patchOpenssl11Darwin']); FileSystem::addSourceExtractHook('swoole', [SourcePatcher::class, 'patchSwoole']); + FileSystem::addSourceExtractHook('php-src', [SourcePatcher::class, 'patchPhpLibxml212']); } /** @@ -200,6 +201,11 @@ class SourcePatcher FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'install-micro', ''); } + // no asan + // if (strpos(file_get_contents(SOURCE_PATH . '/php-src/Makefile'), 'CFLAGS_CLEAN = -g') === false) { + // FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'CFLAGS_CLEAN = ', 'CFLAGS_CLEAN = -g -fsanitize=address '); + // } + // call extension patch before make foreach ($builder->getExts() as $ext) { if ($ext->patchBeforeMake() === true) { @@ -268,6 +274,36 @@ class SourcePatcher return $result; } + public static function patchMicroPhar(int $version_id): void + { + FileSystem::backupFile(SOURCE_PATH . '/php-src/ext/phar/phar.c'); + FileSystem::replaceFileStr( + SOURCE_PATH . '/php-src/ext/phar/phar.c', + 'static zend_op_array *phar_compile_file', + "char *micro_get_filename(void);\n\nstatic zend_op_array *phar_compile_file" + ); + if ($version_id < 80100) { + // PHP 8.0.x + FileSystem::replaceFileStr( + SOURCE_PATH . '/php-src/ext/phar/phar.c', + 'if (strstr(file_handle->filename, ".phar") && !strstr(file_handle->filename, "://")) {', + 'if ((strstr(file_handle->filename, micro_get_filename()) || strstr(file_handle->filename, ".phar")) && !strstr(file_handle->filename, "://")) {' + ); + } else { + // PHP >= 8.1 + FileSystem::replaceFileStr( + SOURCE_PATH . '/php-src/ext/phar/phar.c', + 'if (strstr(ZSTR_VAL(file_handle->filename), ".phar") && !strstr(ZSTR_VAL(file_handle->filename), "://")) {', + 'if ((strstr(ZSTR_VAL(file_handle->filename), micro_get_filename()) || strstr(ZSTR_VAL(file_handle->filename), ".phar")) && !strstr(ZSTR_VAL(file_handle->filename), "://")) {' + ); + } + } + + public static function unpatchMicroPhar(): void + { + FileSystem::restoreBackupFile(SOURCE_PATH . '/php-src/ext/phar/phar.c'); + } + /** * Patch cli SAPI Makefile for Windows. * @@ -296,6 +332,24 @@ class SourcePatcher FileSystem::writeFile(SOURCE_PATH . '/php-src/Makefile', implode("\r\n", $lines)); } + public static function patchPhpLibxml212(): bool + { + $file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h'); + if (preg_match('/PHP_VERSION_ID (\d+)/', $file, $match) !== 0) { + $ver_id = intval($match[1]); + if ($ver_id < 80100) { + self::patchFile('spc_fix_libxml2_12_php80.patch', SOURCE_PATH . '/php-src'); + return true; + } + if ($ver_id < 80200) { + self::patchFile('spc_fix_libxml2_12_php81.patch', SOURCE_PATH . '/php-src'); + return true; + } + return false; + } + return false; + } + /** * Add additional `static-php-cli.version` ini value for PHP source. * diff --git a/src/globals/common-tests/micro_zend_mm_heap_corrupted.txt b/src/globals/common-tests/micro_zend_mm_heap_corrupted.txt new file mode 100644 index 00000000..cd0272a2 --- /dev/null +++ b/src/globals/common-tests/micro_zend_mm_heap_corrupted.txt @@ -0,0 +1,361 @@ +'); +define('K_question', '?'); +define('K_at', '@'); +define('K_A', 'A'); +define('K_B', 'B'); +define('K_C', 'C'); +define('K_D', 'D'); +define('K_E', 'E'); +define('K_F', 'F'); +define('K_G', 'G'); +define('K_H', 'H'); +define('K_I', 'I'); +define('K_J', 'J'); +define('K_K', 'K'); +define('K_L', 'L'); +define('K_M', 'M'); +define('K_N', 'N'); +define('K_O', 'O'); +define('K_P', 'P'); +define('K_Q', 'Q'); +define('K_R', 'R'); +define('K_S', 'S'); +define('K_T', 'T'); +define('K_U', 'U'); +define('K_V', 'V'); +define('K_W', 'W'); +define('K_X', 'X'); +define('K_Y', 'Y'); +define('K_Z', 'Z'); +define('K_bracketleft', '['); +define('K_bracketright', ']'); +define('K_circum', '^'); +define('K_underscore', '_'); +define('K_grave', '`'); +define('K_a', 'a'); +define('K_b', 'b'); +define('K_c', 'c'); +define('K_d', 'd'); +define('K_e', 'e'); +define('K_f', 'f'); +define('K_g', 'g'); +define('K_h', 'h'); +define('K_i', 'i'); +define('K_j', 'j'); +define('K_k', 'k'); +define('K_l', 'l'); +define('K_m', 'm'); +define('K_n', 'n'); +define('K_o', 'o'); +define('K_p', 'p'); +define('K_q', 'q'); +define('K_r', 'r'); +define('K_s', 's'); +define('K_t', 't'); +define('K_u', 'u'); +define('K_v', 'v'); +define('K_w', 'w'); +define('K_x', 'x'); +define('K_y', 'y'); +define('K_z', 'z'); +define('K_braceleft', '{'); +define('K_bar', '|'); +define('K_braceright', '}'); +define('K_tilde', '~'); +define('K_BS', '\\b'); +define('K_TAB', "\t"); +define('K_LF', "\n"); +define('K_CR', "\r"); +define('K_quoteleft', '`'); +define('K_quoteright', "'"); +define('K_PAUSE', 65299); +define('K_ESC', 65307); +define('K_HOME', 65360); +define('K_LEFT', 65361); +define('K_UP', 65362); +define('K_RIGHT', 65363); +define('K_DOWN', 65364); +define('K_PGUP', 65365); +define('K_PGDN', 65366); +define('K_END', 65367); +define('K_MIDDLE', 65291); +define('K_Print', 65377); +define('K_INS', 65379); +define('K_Menu', 65383); +define('K_DEL', 65535); +define('K_F1', 65470); +define('K_F2', 65471); +define('K_F3', 65472); +define('K_F4', 65473); +define('K_F5', 65474); +define('K_F6', 65475); +define('K_F7', 65476); +define('K_F8', 65477); +define('K_F9', 65478); +define('K_F10', 65479); +define('K_F11', 65480); +define('K_F12', 65481); +define('K_F13', 65482); +define('K_F14', 65483); +define('K_F15', 65484); +define('K_F16', 65485); +define('K_F17', 65486); +define('K_F18', 65487); +define('K_F19', 65488); +define('K_F20', 65489); +define('K_LSHIFT', 65505); +define('K_RSHIFT', 65506); +define('K_LCTRL', 65507); +define('K_RCTRL', 65508); +define('K_LALT', 65513); +define('K_RALT', 65514); +define('K_NUM', 65407); +define('K_SCROLL', 65300); +define('K_CAPS', 65509); +define('K_CLEAR', 65490); +define('K_HELP', 65491); +define('K_ccedilla', 231); +define('K_Ccedilla', 199); +define('K_acute', 180); +define('K_diaeresis', 168); +define('IUP_RUN', 'RUN'); +define('IUP_ENGLISH', 'ENGLISH'); +define('IUP_PORTUGUESE', 'PORTUGUESE'); +define('IUP_SBH', 'SBH'); +define('IUP_SBV', 'SBV'); +define('IUP_IDLE_ACTION', 'IDLE_ACTION'); +define('IUP_ACTION', 'ACTION'); +define('IUP_GETFOCUS_CB', 'GETFOCUS_CB'); +define('IUP_KILLFOCUS_CB', 'KILLFOCUS_CB'); +define('IUP_K_ANY', 'K_ANY'); +define('IUP_KEYPRESS_CB', 'KEYPRESS_CB'); +define('IUP_HELP_CB', 'HELP_CB'); +define('IUP_SCROLL_CB', 'SCROLL_CB'); +define('IUP_RESIZE_CB', 'RESIZE_CB'); +define('IUP_MOTION_CB', 'MOTION_CB'); +define('IUP_BUTTON_CB', 'BUTTON_CB'); +define('IUP_ENTERWINDOW_CB', 'ENTERWINDOW_CB'); +define('IUP_LEAVEWINDOW_CB', 'LEAVEWINDOW_CB'); +define('IUP_WHEEL_CB', 'WHEEL_CB'); +define('IUP_MASK_CB', 'MASK_CB'); +define('IUP_OPEN_CB', 'OPEN_CB'); +define('IUP_HIGHLIGHT_CB', 'HIGHLIGHT_CB'); +define('IUP_MENUCLOSE_CB', 'MENUCLOSE_CB'); +define('IUP_MAP_CB', 'MAP_CB'); +define('IUP_CLOSE_CB', 'CLOSE_CB'); +define('IUP_SHOW_CB', 'SHOW_CB'); +define('IUP_DROPFILES_CB', 'DROPFILES_CB'); +define('IUP_WOM_CB', 'WOM_CB'); +define('IUP_DIRECTION', 'DIRECTION'); +define('IUP_ACTIVE', 'ACTIVE'); +define('IUP_BGCOLOR', 'BGCOLOR'); +define('IUP_FRAMECOLOR', 'FRAMECOLOR'); +define('IUP_FGCOLOR', 'FGCOLOR'); +define('IUP_COLOR', 'COLOR'); +define('IUP_WID', 'WID'); +define('IUP_SIZE', 'SIZE'); +define('IUP_RASTERSIZE', 'RASTERSIZE'); +define('IUP_TITLE', 'TITLE'); +define('IUP_VALUE', 'VALUE'); +define('IUP_VISIBLE', 'VISIBLE'); +define('IUP_FONT', 'FONT'); +define('IUP_TIP', 'TIP'); +define('IUP_EXPAND', 'EXPAND'); +define('IUP_SEPARATOR', 'SEPARATOR'); +define('IUP_HOTSPOT', 'HOTSPOT'); +define('IUP_HEIGHT', 'HEIGHT'); +define('IUP_WIDTH', 'WIDTH'); +define('IUP_KEY', 'KEY'); +define('IUP_MULTIPLE', 'MULTIPLE'); +define('IUP_DROPDOWN', 'DROPDOWN'); +define('IUP_VISIBLE_ITEMS', 'VISIBLE_ITEMS'); +define('IUP_MARGIN', 'MARGIN'); +define('IUP_GAP', 'GAP'); +define('IUP_ALIGNMENT', 'ALIGNMENT'); +define('IUP_IMAGE', 'IMAGE'); +define('IUP_IMINACTIVE', 'IMINACTIVE'); +define('IUP_IMPRESS', 'IMPRESS'); +define('IUP_WIN_SAVEBITS', 'WIN_SAVEBITS'); +define('IUP_NC', 'NC'); +define('IUP_MASK', 'MASK'); +define('IUP_APPEND', 'APPEND'); +define('IUP_BORDER', 'BORDER'); +define('IUP_CARET', 'CARET'); +define('IUP_SELECTION', 'SELECTION'); +define('IUP_SELECTEDTEXT', 'SELECTEDTEXT'); +define('IUP_INSERT', 'INSERT'); +define('IUP_CONID', 'CONID'); +define('IUP_CURSOR', 'CURSOR'); +define('IUP_ICON', 'ICON'); +define('IUP_MENUBOX', 'MENUBOX'); +define('IUP_MINBOX', 'MINBOX'); +define('IUP_MAXBOX', 'MAXBOX'); +define('IUP_RESIZE', 'RESIZE'); +define('IUP_MENU', 'MENU'); +define('IUP_STARTFOCUS', 'STARTFOCUS'); +define('IUP_PARENTDIALOG', 'PARENTDIALOG'); +define('IUP_SHRINK', 'SHRINK'); +define('IUP_DEFAULTENTER', 'DEFAULTENTER'); +define('IUP_DEFAULTESC', 'DEFAULTESC'); +define('IUP_X', 'X'); +define('IUP_Y', 'Y'); +define('IUP_TOOLBOX', 'TOOLBOX'); +define('IUP_CONTROL', 'CONTROL'); +define('IUP_READONLY', 'READONLY'); +define('IUP_SCROLLBAR', 'SCROLLBAR'); +define('IUP_POSY', 'POSY'); +define('IUP_POSX', 'POSX'); +define('IUP_DX', 'DX'); +define('IUP_DY', 'DY'); +define('IUP_XMAX', 'XMAX'); +define('IUP_XMIN', 'XMIN'); +define('IUP_YMAX', 'YMAX'); +define('IUP_YMIN', 'YMIN'); +define('IUP_RED', '255 0 0'); +define('IUP_GREEN', '0 255 0'); +define('IUP_BLUE', '0 0 255'); +define('IUP_MIN', 'MIN'); +define('IUP_MAX', 'MAX'); +define('IUP_TIME', 'TIME'); +define('IUP_DRAG', 'DRAG'); +define('IUP_DROP', 'DROP'); +define('IUP_REPAINT', 'REPAINT'); +define('IUP_TOPMOST', 'TOPMOST'); +define('IUP_CLIPCHILDREN', 'CLIPCHILDREN'); +define('IUP_DIALOGTYPE', 'DIALOGTYPE'); +define('IUP_FILE', 'FILE'); +define('IUP_MULTIPLEFILES', 'MULTIPLEFILES'); +define('IUP_FILTER', 'FILTER'); +define('IUP_FILTERUSED', 'FILTERUSED'); +define('IUP_FILTERINFO', 'FILTERINFO'); +define('IUP_EXTFILTER', 'EXTFILTER'); +define('IUP_DIRECTORY', 'DIRECTORY'); +define('IUP_ALLOWNEW', 'ALLOWNEW'); +define('IUP_NOOVERWRITEPROMPT', 'NOOVERWRITEPROMPT'); +define('IUP_NOCHANGEDIR', 'NOCHANGEDIR'); +define('IUP_FILEEXIST', 'FILEEXIST'); +define('IUP_STATUS', 'STATUS'); +define('IUP_LOCKLOOP', 'LOCKLOOP'); +define('IUP_SYSTEM', 'SYSTEM'); +define('IUP_DRIVER', 'DRIVER'); +define('IUP_SCREENSIZE', 'SCREENSIZE'); +define('IUP_SYSTEMLANGUAGE', 'SYSTEMLANGUAGE'); +define('IUP_COMPUTERNAME', 'COMPUTERNAME'); +define('IUP_USERNAME', 'USERNAME'); +define('IUP_OPEN', 'OPEN'); +define('IUP_SAVE', 'SAVE'); +define('IUP_DIR', 'DIR'); +define('IUP_HORIZONTAL', 'HORIZONTAL'); +define('IUP_VERTICAL', 'VERTICAL'); +define('IUP_YES', 'YES'); +define('IUP_NO', 'NO'); +define('IUP_ON', 'ON'); +define('IUP_OFF', 'OFF'); +define('IUP_ACENTER', 'ACENTER'); +define('IUP_ALEFT', 'ALEFT'); +define('IUP_ARIGHT', 'ARIGHT'); +define('IUP_ATOP', 'ATOP'); +define('IUP_ABOTTOM', 'ABOTTOM'); +define('IUP_NORTH', 'NORTH'); +define('IUP_SOUTH', 'SOUTH'); +define('IUP_WEST', 'WEST'); +define('IUP_EAST', 'EAST'); +define('IUP_NE', 'NE'); +define('IUP_SE', 'SE'); +define('IUP_NW', 'NW'); +define('IUP_SW', 'SW'); +define('IUP_FULLSCREEN', 'FULLSCREEN'); +define('IUP_FULL', 'FULL'); +define('IUP_HALF', 'HALF'); +define('IUP_THIRD', 'THIRD'); +define('IUP_QUARTER', 'QUARTER'); +define('IUP_EIGHTH', 'EIGHTH'); +define('IUP_ARROW', 'ARROW'); +define('IUP_BUSY', 'BUSY'); +define('IUP_RESIZE_N', 'RESIZE_N'); +define('IUP_RESIZE_S', 'RESIZE_S'); +define('IUP_RESIZE_E', 'RESIZE_E'); +define('IUP_RESIZE_W', 'RESIZE_W'); +define('IUP_RESIZE_NE', 'RESIZE_NE'); +define('IUP_RESIZE_NW', 'RESIZE_NW'); +define('IUP_RESIZE_SE', 'RESIZE_SE'); +define('IUP_RESIZE_SW', 'RESIZE_SW'); +define('IUP_MOVE', 'MOVE'); +define('IUP_HAND', 'HAND'); +define('IUP_NONE', 'NONE'); +define('IUP_IUP', 'IUP'); +define('IUP_CROSS', 'CROSS'); +define('IUP_PEN', 'PEN'); +define('IUP_TEXT', 'TEXT'); +define('IUP_RESIZE_C', 'RESIZE_C'); +define('IUP_OPENHAND', 'OPENHAND'); +define('IUP_K_exclam', 'K_exclam'); +define('IUP_K_quotedbl', 'K_quotedbl'); +define('IUP_K_numbersign', 'K_numbersign'); +define('IUP_K_dollar', 'K_dollar'); +define('IUP_K_percent', 'K_percent'); +define('IUP_K_ampersand', 'K_ampersand'); +define('IUP_K_quoteright', 'K_quoteright'); +define('IUP_K_parentleft', 'K_parentleft'); +define('IUP_K_parentright', 'K_parentright'); +define('IUP_K_asterisk', 'K_asterisk'); +define('IUP_K_plus', 'K_plus'); +define('IUP_K_comma', 'K_comma'); +define('IUP_K_minus', 'K_minus'); +define('IUP_K_period', 'K_period'); +define('IUP_K_slash', 'K_slash'); +define('IUP_K_0', 'K_0'); +define('IUP_K_1', 'K_1'); +define('IUP_K_2', 'K_2'); +define('IUP_K_3', 'K_3'); +define('IUP_K_4', 'K_4'); +define('IUP_K_5', 'K_5'); +define('IUP_K_6', 'K_6'); +define('IUP_K_7', 'K_7'); +define('IUP_K_8', 'K_8'); +define('IUP_K_9', 'K_9'); +define('IUP_K_colon', 'K_colon'); +define('IUP_K_semicolon', 'K_semicolon '); +define('IUP_K_less', 'K_less'); +define('IUP_K_equal', 'K_equal'); +define('IUP_K_greater', 'K_greater'); +define('IUP_K_question', 'K_question'); +define('IUP_K_at', 'K_at'); +define('IUP_K_A', 'K_A'); +define('IUP_K_B', 'K_B'); +define('IUP_K_C', 'K_C'); +define('IUP_K_D', 'K_D'); +define('IUP_K_E', 'K_E'); +define('IUP_K_F', 'K_F'); +define('IUP_K_G', 'K_G'); \ No newline at end of file diff --git a/src/globals/tests/bcmath.php b/src/globals/ext-tests/bcmath.php similarity index 100% rename from src/globals/tests/bcmath.php rename to src/globals/ext-tests/bcmath.php diff --git a/src/globals/tests/bz2.php b/src/globals/ext-tests/bz2.php similarity index 100% rename from src/globals/tests/bz2.php rename to src/globals/ext-tests/bz2.php diff --git a/src/globals/tests/calendar.php b/src/globals/ext-tests/calendar.php similarity index 100% rename from src/globals/tests/calendar.php rename to src/globals/ext-tests/calendar.php diff --git a/src/globals/tests/curl.php b/src/globals/ext-tests/curl.php similarity index 100% rename from src/globals/tests/curl.php rename to src/globals/ext-tests/curl.php diff --git a/src/globals/tests/dom.php b/src/globals/ext-tests/dom.php similarity index 100% rename from src/globals/tests/dom.php rename to src/globals/ext-tests/dom.php diff --git a/src/globals/tests/filter.php b/src/globals/ext-tests/filter.php similarity index 100% rename from src/globals/tests/filter.php rename to src/globals/ext-tests/filter.php diff --git a/src/globals/tests/gd.php b/src/globals/ext-tests/gd.php similarity index 100% rename from src/globals/tests/gd.php rename to src/globals/ext-tests/gd.php diff --git a/src/globals/tests/gettext.php b/src/globals/ext-tests/gettext.php similarity index 100% rename from src/globals/tests/gettext.php rename to src/globals/ext-tests/gettext.php diff --git a/src/globals/tests/intl.php b/src/globals/ext-tests/intl.php similarity index 100% rename from src/globals/tests/intl.php rename to src/globals/ext-tests/intl.php diff --git a/src/globals/tests/openssl.php b/src/globals/ext-tests/openssl.php similarity index 100% rename from src/globals/tests/openssl.php rename to src/globals/ext-tests/openssl.php diff --git a/src/globals/tests/parallel.php b/src/globals/ext-tests/parallel.php similarity index 100% rename from src/globals/tests/parallel.php rename to src/globals/ext-tests/parallel.php diff --git a/src/globals/tests/redis.php b/src/globals/ext-tests/redis.php similarity index 100% rename from src/globals/tests/redis.php rename to src/globals/ext-tests/redis.php diff --git a/src/globals/tests/swoole.php b/src/globals/ext-tests/swoole.php similarity index 100% rename from src/globals/tests/swoole.php rename to src/globals/ext-tests/swoole.php diff --git a/src/globals/tests/uuid.php b/src/globals/ext-tests/uuid.php similarity index 100% rename from src/globals/tests/uuid.php rename to src/globals/ext-tests/uuid.php diff --git a/src/globals/tests/zip.php b/src/globals/ext-tests/zip.php similarity index 100% rename from src/globals/tests/zip.php rename to src/globals/ext-tests/zip.php diff --git a/src/globals/tests/zlib.php b/src/globals/ext-tests/zlib.php similarity index 100% rename from src/globals/tests/zlib.php rename to src/globals/ext-tests/zlib.php diff --git a/src/globals/patch/spc_fix_libxml2_12_php80.patch b/src/globals/patch/spc_fix_libxml2_12_php80.patch new file mode 100644 index 00000000..608c1ec0 --- /dev/null +++ b/src/globals/patch/spc_fix_libxml2_12_php80.patch @@ -0,0 +1,89 @@ +diff --git a/ext/dom/document.c b/ext/dom/document.c +index 02522b50..6d1b0740 100644 +--- a/ext/dom/document.c ++++ b/ext/dom/document.c +@@ -23,6 +23,7 @@ + #if defined(HAVE_LIBXML) && defined(HAVE_DOM) + #include "php_dom.h" + #include ++#include + #ifdef LIBXML_SCHEMAS_ENABLED + #include + #include +diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c +index 73486ae2..59bd3d20 100644 +--- a/ext/libxml/libxml.c ++++ b/ext/libxml/libxml.c +@@ -382,7 +382,7 @@ php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc) + + if (encoding) { + char *end; +- ++ + encoding += sizeof("charset=")-1; + if (*encoding == '"') { + encoding++; +@@ -481,7 +481,11 @@ static void _php_libxml_free_error(void *ptr) + xmlResetError((xmlErrorPtr) ptr); + } + +-static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg) ++#if LIBXML_VERSION >= 21200 ++static void _php_list_set_error_structure(const xmlError *error, const char *msg) ++#else ++static void _php_list_set_error_structure(xmlError *error, const char *msg) ++#endif + { + xmlError error_copy; + int ret; +@@ -732,7 +736,11 @@ PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...) + va_end(args); + } + ++#if LIBXML_VERSION >= 21200 ++PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, const xmlError *error) ++#else + PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error) ++#endif + { + _php_list_set_error_structure(error, NULL); + +@@ -1035,11 +1043,9 @@ PHP_FUNCTION(libxml_use_internal_errors) + /* {{{ Retrieve last error from libxml */ + PHP_FUNCTION(libxml_get_last_error) + { +- xmlErrorPtr error; +- + ZEND_PARSE_PARAMETERS_NONE(); + +- error = xmlGetLastError(); ++ const xmlError *error = xmlGetLastError(); + + if (error) { + object_init_ex(return_value, libxmlerror_class_entry); +diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h +index d0ce7cec..02717417 100644 +--- a/ext/libxml/php_libxml.h ++++ b/ext/libxml/php_libxml.h +@@ -35,6 +35,7 @@ extern zend_module_entry libxml_module_entry; + + #include "zend_smart_str.h" + #include ++#include + + #define LIBXML_SAVE_NOEMPTYTAG 1<<2 + +diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c +index e5e7f2f9..00b58b87 100644 +--- a/ext/soap/php_sdl.c ++++ b/ext/soap/php_sdl.c +@@ -331,8 +331,7 @@ static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include) + sdl_restore_uri_credentials(ctx); + + if (!wsdl) { +- xmlErrorPtr xmlErrorPtr = xmlGetLastError(); +- ++ const xmlError *xmlErrorPtr = xmlGetLastError(); + if (xmlErrorPtr) { + soap_error2(E_ERROR, "Parsing WSDL: Couldn't load from '%s' : %s", struri, xmlErrorPtr->message); + } else { diff --git a/src/globals/patch/spc_fix_libxml2_12_php81.patch b/src/globals/patch/spc_fix_libxml2_12_php81.patch new file mode 100644 index 00000000..bd9a616c --- /dev/null +++ b/src/globals/patch/spc_fix_libxml2_12_php81.patch @@ -0,0 +1,55 @@ +diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c +index 3959b362..6cdfbd39 100644 +--- a/ext/libxml/libxml.c ++++ b/ext/libxml/libxml.c +@@ -483,7 +483,11 @@ static void _php_libxml_free_error(void *ptr) + xmlResetError((xmlErrorPtr) ptr); + } + +-static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg) ++#if LIBXML_VERSION >= 21200 ++static void _php_list_set_error_structure(const xmlError *error, const char *msg) ++#else ++static void _php_list_set_error_structure(xmlError *error, const char *msg) ++#endif + { + xmlError error_copy; + int ret; +@@ -736,7 +740,11 @@ PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...) + va_end(args); + } + ++#if LIBXML_VERSION >= 21200 ++PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, const xmlError *error) ++#else + PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error) ++#endif + { + _php_list_set_error_structure(error, NULL); + +@@ -1009,11 +1017,9 @@ PHP_FUNCTION(libxml_use_internal_errors) + /* {{{ Retrieve last error from libxml */ + PHP_FUNCTION(libxml_get_last_error) + { +- xmlErrorPtr error; +- + ZEND_PARSE_PARAMETERS_NONE(); + +- error = xmlGetLastError(); ++ const xmlError *error = xmlGetLastError(); + + if (error) { + object_init_ex(return_value, libxmlerror_class_entry); +diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c +index 651eab23..7a7ce304 100644 +--- a/ext/soap/php_sdl.c ++++ b/ext/soap/php_sdl.c +@@ -332,7 +332,7 @@ static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include) + sdl_restore_uri_credentials(ctx); + + if (!wsdl) { +- xmlErrorPtr xmlErrorPtr = xmlGetLastError(); ++ const xmlError *xmlErrorPtr = xmlGetLastError(); + + if (xmlErrorPtr) { + soap_error2(E_ERROR, "Parsing WSDL: Couldn't load from '%s' : %s", struri, xmlErrorPtr->message); diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index f2ccda99..22a42e07 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -13,6 +13,10 @@ declare(strict_types=1); $zts = false; +$no_strip = false; + +$upx = true; + // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { 'Linux', 'Darwin' => 'libxml', @@ -74,5 +78,7 @@ echo match ($argv[1]) { 'libs_cmd' => ($final_libs === '' ? '' : (' --with-libs=' . $final_libs)), 'cmd' => $final_extensions_cmd . ($final_libs === '' ? '' : (' --with-libs=' . $final_libs)), 'zts' => $zts ? '--enable-zts' : '', + 'no_strip' => $no_strip ? '--no-strip' : '', + 'upx' => $upx ? '--with-upx-pack' : '', default => '', };