From 2dbf4b3fb6582f8b2f54f68a4b55a0b0702564b8 Mon Sep 17 00:00:00 2001 From: Pierre Tondereau Date: Thu, 20 Nov 2025 21:05:58 +0100 Subject: [PATCH] feat(php): Add PHP 8.5 support --- .github/action/musl/Dockerfile | 2 +- .github/workflows/build.yml | 4 +- Dockerfile | 2 +- allowed_bindings.rs | 1 + build.rs | 30 +++- docsrs_bindings.rs | 302 +++++++++++++++++++-------------- src/builders/sapi.rs | 40 +++++ src/constant.rs | 86 +++++++--- src/types/array/iterators.rs | 33 +++- src/wrapper.h | 1 + tools/update_bindings.sh | 2 +- windows_build.rs | 39 +++++ 12 files changed, 374 insertions(+), 168 deletions(-) diff --git a/.github/action/musl/Dockerfile b/.github/action/musl/Dockerfile index 4a4fdff94e..8fd52c4a9b 100644 --- a/.github/action/musl/Dockerfile +++ b/.github/action/musl/Dockerfile @@ -1,4 +1,4 @@ -ARG PHP_VERSION=8.4 +ARG PHP_VERSION=8.5 ARG TS=-zts FROM php:${PHP_VERSION}${TS}-alpine diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index afded66fbe..c7e5dd17ce 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,7 +87,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - php: ["8.1", "8.2", "8.3", "8.4"] + php: ["8.1", "8.2", "8.3", "8.4", "8.5"] rust: [stable, nightly] clang: ["15", "17"] phpts: [ts, nts] @@ -231,7 +231,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: ["8.1", "8.2", "8.3", "8.4"] + php: ["8.1", "8.2", "8.3", "8.4", "8.5"] phpts: [["-zts", "TS"], ["", "NTS"]] env: CARGO_TERM_COLOR: always diff --git a/Dockerfile b/Dockerfile index 40467e9adc..c0bb4c7f51 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM rust:latest AS base -ARG PHP_VERSION=8.4 +ARG PHP_VERSION=8.5 WORKDIR /tmp RUN <: Sized { #[allow(clippy::missing_errors_doc)] fn get_defines(&self) -> Result>; + /// Retrieve extra clang arguments for bindgen (e.g., system include paths). + #[allow(clippy::missing_errors_doc)] + fn get_extra_clang_args(&self) -> Result> { + Ok(Vec::new()) + } + /// Writes the bindings to a file. #[allow(clippy::missing_errors_doc)] fn write_bindings(&self, bindings: String, writer: &mut impl Write) -> Result<()> { @@ -211,7 +217,11 @@ fn build_embed(defines: &[(&str, &str)], includes: &[PathBuf]) -> Result<()> { } /// Generates bindings to the Zend API. -fn generate_bindings(defines: &[(&str, &str)], includes: &[PathBuf]) -> Result { +fn generate_bindings( + defines: &[(&str, &str)], + includes: &[PathBuf], + extra_clang_args: &[String], +) -> Result { let mut bindgen = bindgen::Builder::default(); #[cfg(feature = "embed")] @@ -227,6 +237,7 @@ fn generate_bindings(defines: &[(&str, &str)], includes: &[PathBuf]) -> Result Self { - ApiVersion::Php84 + ApiVersion::Php85 } pub fn versions() -> Vec { @@ -295,6 +307,7 @@ impl ApiVersion { ApiVersion::Php82, ApiVersion::Php83, ApiVersion::Php84, + ApiVersion::Php85, ] } @@ -313,6 +326,7 @@ impl ApiVersion { ApiVersion::Php82 => "php82", ApiVersion::Php83 => "php83", ApiVersion::Php84 => "php84", + ApiVersion::Php85 => "php85", } } @@ -323,6 +337,7 @@ impl ApiVersion { ApiVersion::Php82 => "EXT_PHP_RS_PHP_82", ApiVersion::Php83 => "EXT_PHP_RS_PHP_83", ApiVersion::Php84 => "EXT_PHP_RS_PHP_84", + ApiVersion::Php85 => "EXT_PHP_RS_PHP_85", } } } @@ -344,7 +359,10 @@ impl TryFrom for ApiVersion { x if ((ApiVersion::Php83 as u32)..(ApiVersion::Php84 as u32)).contains(&x) => { Ok(ApiVersion::Php83) } - x if (ApiVersion::Php84 as u32) == x => Ok(ApiVersion::Php84), + x if ((ApiVersion::Php84 as u32)..(ApiVersion::Php85 as u32)).contains(&x) => { + Ok(ApiVersion::Php84) + } + x if (ApiVersion::Php85 as u32) == x => Ok(ApiVersion::Php85), version => Err(anyhow!( "The current version of PHP is not supported. Current PHP API version: {}, requires a version between {} and {}", version, @@ -371,7 +389,7 @@ fn check_php_version(info: &PHPInfo) -> Result<()> { // The PHP version cfg flags should also stack - if you compile on PHP 8.2 you // should get both the `php81` and `php82` flags. println!( - "cargo::rustc-check-cfg=cfg(php80, php81, php82, php83, php84, php_zts, php_debug, docs)" + "cargo::rustc-check-cfg=cfg(php80, php81, php82, php83, php84, php85, php_zts, php_debug, docs)" ); if version == ApiVersion::Php80 { @@ -416,6 +434,7 @@ fn main() -> Result<()> { println!("cargo:rustc-cfg=php82"); println!("cargo:rustc-cfg=php83"); println!("cargo:rustc-cfg=php84"); + println!("cargo:rustc-cfg=php85"); std::fs::copy("docsrs_bindings.rs", out_path) .expect("failed to copy docs.rs stub bindings to out directory"); return Ok(()); @@ -428,6 +447,7 @@ fn main() -> Result<()> { let includes = provider.get_includes()?; let mut defines = provider.get_defines()?; add_php_version_defines(&mut defines, &info)?; + let extra_clang_args = provider.get_extra_clang_args()?; check_php_version(&info)?; build_wrapper(&defines, &includes)?; @@ -435,7 +455,7 @@ fn main() -> Result<()> { #[cfg(feature = "embed")] build_embed(&defines, &includes)?; - let bindings = generate_bindings(&defines, &includes)?; + let bindings = generate_bindings(&defines, &includes, &extra_clang_args)?; let out_file = File::create(&out_path).context("Failed to open output bindings file for writing")?; diff --git a/docsrs_bindings.rs b/docsrs_bindings.rs index 73a514b4cd..4502111707 100644 --- a/docsrs_bindings.rs +++ b/docsrs_bindings.rs @@ -172,7 +172,7 @@ pub const IS_STRING_EX: u32 = 262; pub const IS_ARRAY_EX: u32 = 775; pub const IS_OBJECT_EX: u32 = 776; pub const IS_RESOURCE_EX: u32 = 265; -pub const IS_REFERENCE_EX: u32 = 266; +pub const IS_REFERENCE_EX: u32 = 778; pub const IS_CONSTANT_AST_EX: u32 = 267; pub const E_ERROR: u32 = 1; pub const E_WARNING: u32 = 2; @@ -202,6 +202,7 @@ pub const ZEND_ACC_IMMUTABLE: u32 = 128; pub const ZEND_ACC_HAS_TYPE_HINTS: u32 = 256; pub const ZEND_ACC_TOP_LEVEL: u32 = 512; pub const ZEND_ACC_PRELOADED: u32 = 1024; +pub const ZEND_ACC_DEPRECATED: u32 = 2048; pub const ZEND_ACC_PROMOTED: u32 = 256; pub const ZEND_ACC_INTERFACE: u32 = 1; pub const ZEND_ACC_TRAIT: u32 = 2; @@ -209,7 +210,7 @@ pub const ZEND_ACC_ANON_CLASS: u32 = 4; pub const ZEND_ACC_ENUM: u32 = 268435456; pub const ZEND_ACC_LINKED: u32 = 8; pub const ZEND_ACC_IMPLICIT_ABSTRACT_CLASS: u32 = 16; -pub const ZEND_ACC_USE_GUARDS: u32 = 2048; +pub const ZEND_ACC_USE_GUARDS: u32 = 1073741824; pub const ZEND_ACC_CONSTANTS_UPDATED: u32 = 4096; pub const ZEND_ACC_NO_DYNAMIC_PROPERTIES: u32 = 8192; pub const ZEND_HAS_STATIC_IN_METHODS: u32 = 16384; @@ -218,7 +219,6 @@ pub const ZEND_ACC_RESOLVED_INTERFACES: u32 = 262144; pub const ZEND_ACC_UNRESOLVED_VARIANCE: u32 = 524288; pub const ZEND_ACC_NEARLY_LINKED: u32 = 1048576; pub const ZEND_ACC_NOT_SERIALIZABLE: u32 = 536870912; -pub const ZEND_ACC_DEPRECATED: u32 = 2048; pub const ZEND_ACC_RETURN_REFERENCE: u32 = 4096; pub const ZEND_ACC_HAS_RETURN_TYPE: u32 = 8192; pub const ZEND_ACC_VARIADIC: u32 = 16384; @@ -241,8 +241,12 @@ pub const ZEND_EVAL_CODE: u32 = 4; pub const ZEND_ISEMPTY: u32 = 1; pub const _ZEND_SEND_MODE_SHIFT: u32 = 25; pub const _ZEND_IS_VARIADIC_BIT: u32 = 134217728; -pub const ZEND_MODULE_API_NO: u32 = 20240924; +pub const ZEND_MODULE_API_NO: u32 = 20250925; pub const USING_ZTS: u32 = 0; +pub const CONST_CS: u32 = 0; +pub const CONST_PERSISTENT: u32 = 1; +pub const CONST_NO_FILE_CACHE: u32 = 2; +pub const CONST_DEPRECATED: u32 = 4; pub const MAY_BE_BOOL: u32 = 12; pub const MAY_BE_ANY: u32 = 1022; pub const TRACK_VARS_POST: u32 = 0; @@ -256,10 +260,6 @@ pub const PHP_INI_USER: u32 = 1; pub const PHP_INI_PERDIR: u32 = 2; pub const PHP_INI_SYSTEM: u32 = 4; pub const PHP_INI_ALL: u32 = 7; -pub const CONST_CS: u32 = 0; -pub const CONST_PERSISTENT: u32 = 1; -pub const CONST_NO_FILE_CACHE: u32 = 2; -pub const CONST_DEPRECATED: u32 = 4; pub type __dev_t = ::std::os::raw::c_ulong; pub type __uid_t = ::std::os::raw::c_uint; pub type __gid_t = ::std::os::raw::c_uint; @@ -687,73 +687,88 @@ pub const _zend_known_string_id_ZEND_STR_ARGS: _zend_known_string_id = 8; pub const _zend_known_string_id_ZEND_STR_UNKNOWN: _zend_known_string_id = 9; pub const _zend_known_string_id_ZEND_STR_UNKNOWN_CAPITALIZED: _zend_known_string_id = 10; pub const _zend_known_string_id_ZEND_STR_EXIT: _zend_known_string_id = 11; -pub const _zend_known_string_id_ZEND_STR_EVAL: _zend_known_string_id = 12; -pub const _zend_known_string_id_ZEND_STR_INCLUDE: _zend_known_string_id = 13; -pub const _zend_known_string_id_ZEND_STR_REQUIRE: _zend_known_string_id = 14; -pub const _zend_known_string_id_ZEND_STR_INCLUDE_ONCE: _zend_known_string_id = 15; -pub const _zend_known_string_id_ZEND_STR_REQUIRE_ONCE: _zend_known_string_id = 16; -pub const _zend_known_string_id_ZEND_STR_SCALAR: _zend_known_string_id = 17; -pub const _zend_known_string_id_ZEND_STR_ERROR_REPORTING: _zend_known_string_id = 18; -pub const _zend_known_string_id_ZEND_STR_STATIC: _zend_known_string_id = 19; -pub const _zend_known_string_id_ZEND_STR_THIS: _zend_known_string_id = 20; -pub const _zend_known_string_id_ZEND_STR_VALUE: _zend_known_string_id = 21; -pub const _zend_known_string_id_ZEND_STR_KEY: _zend_known_string_id = 22; -pub const _zend_known_string_id_ZEND_STR_MAGIC_INVOKE: _zend_known_string_id = 23; -pub const _zend_known_string_id_ZEND_STR_PREVIOUS: _zend_known_string_id = 24; -pub const _zend_known_string_id_ZEND_STR_CODE: _zend_known_string_id = 25; -pub const _zend_known_string_id_ZEND_STR_MESSAGE: _zend_known_string_id = 26; -pub const _zend_known_string_id_ZEND_STR_SEVERITY: _zend_known_string_id = 27; -pub const _zend_known_string_id_ZEND_STR_STRING: _zend_known_string_id = 28; -pub const _zend_known_string_id_ZEND_STR_TRACE: _zend_known_string_id = 29; -pub const _zend_known_string_id_ZEND_STR_SCHEME: _zend_known_string_id = 30; -pub const _zend_known_string_id_ZEND_STR_HOST: _zend_known_string_id = 31; -pub const _zend_known_string_id_ZEND_STR_PORT: _zend_known_string_id = 32; -pub const _zend_known_string_id_ZEND_STR_USER: _zend_known_string_id = 33; -pub const _zend_known_string_id_ZEND_STR_PASS: _zend_known_string_id = 34; -pub const _zend_known_string_id_ZEND_STR_PATH: _zend_known_string_id = 35; -pub const _zend_known_string_id_ZEND_STR_QUERY: _zend_known_string_id = 36; -pub const _zend_known_string_id_ZEND_STR_FRAGMENT: _zend_known_string_id = 37; -pub const _zend_known_string_id_ZEND_STR_NULL: _zend_known_string_id = 38; -pub const _zend_known_string_id_ZEND_STR_BOOLEAN: _zend_known_string_id = 39; -pub const _zend_known_string_id_ZEND_STR_INTEGER: _zend_known_string_id = 40; -pub const _zend_known_string_id_ZEND_STR_DOUBLE: _zend_known_string_id = 41; -pub const _zend_known_string_id_ZEND_STR_ARRAY: _zend_known_string_id = 42; -pub const _zend_known_string_id_ZEND_STR_RESOURCE: _zend_known_string_id = 43; -pub const _zend_known_string_id_ZEND_STR_CLOSED_RESOURCE: _zend_known_string_id = 44; -pub const _zend_known_string_id_ZEND_STR_NAME: _zend_known_string_id = 45; -pub const _zend_known_string_id_ZEND_STR_ARGV: _zend_known_string_id = 46; -pub const _zend_known_string_id_ZEND_STR_ARGC: _zend_known_string_id = 47; -pub const _zend_known_string_id_ZEND_STR_ARRAY_CAPITALIZED: _zend_known_string_id = 48; -pub const _zend_known_string_id_ZEND_STR_BOOL: _zend_known_string_id = 49; -pub const _zend_known_string_id_ZEND_STR_INT: _zend_known_string_id = 50; -pub const _zend_known_string_id_ZEND_STR_FLOAT: _zend_known_string_id = 51; -pub const _zend_known_string_id_ZEND_STR_CALLABLE: _zend_known_string_id = 52; -pub const _zend_known_string_id_ZEND_STR_ITERABLE: _zend_known_string_id = 53; -pub const _zend_known_string_id_ZEND_STR_VOID: _zend_known_string_id = 54; -pub const _zend_known_string_id_ZEND_STR_NEVER: _zend_known_string_id = 55; -pub const _zend_known_string_id_ZEND_STR_FALSE: _zend_known_string_id = 56; -pub const _zend_known_string_id_ZEND_STR_TRUE: _zend_known_string_id = 57; -pub const _zend_known_string_id_ZEND_STR_NULL_LOWERCASE: _zend_known_string_id = 58; -pub const _zend_known_string_id_ZEND_STR_MIXED: _zend_known_string_id = 59; -pub const _zend_known_string_id_ZEND_STR_TRAVERSABLE: _zend_known_string_id = 60; -pub const _zend_known_string_id_ZEND_STR_SLEEP: _zend_known_string_id = 61; -pub const _zend_known_string_id_ZEND_STR_WAKEUP: _zend_known_string_id = 62; -pub const _zend_known_string_id_ZEND_STR_CASES: _zend_known_string_id = 63; -pub const _zend_known_string_id_ZEND_STR_FROM: _zend_known_string_id = 64; -pub const _zend_known_string_id_ZEND_STR_TRYFROM: _zend_known_string_id = 65; -pub const _zend_known_string_id_ZEND_STR_TRYFROM_LOWERCASE: _zend_known_string_id = 66; -pub const _zend_known_string_id_ZEND_STR_AUTOGLOBAL_SERVER: _zend_known_string_id = 67; -pub const _zend_known_string_id_ZEND_STR_AUTOGLOBAL_ENV: _zend_known_string_id = 68; -pub const _zend_known_string_id_ZEND_STR_AUTOGLOBAL_REQUEST: _zend_known_string_id = 69; -pub const _zend_known_string_id_ZEND_STR_COUNT: _zend_known_string_id = 70; -pub const _zend_known_string_id_ZEND_STR_SENSITIVEPARAMETER: _zend_known_string_id = 71; -pub const _zend_known_string_id_ZEND_STR_CONST_EXPR_PLACEHOLDER: _zend_known_string_id = 72; -pub const _zend_known_string_id_ZEND_STR_DEPRECATED_CAPITALIZED: _zend_known_string_id = 73; -pub const _zend_known_string_id_ZEND_STR_SINCE: _zend_known_string_id = 74; -pub const _zend_known_string_id_ZEND_STR_GET: _zend_known_string_id = 75; -pub const _zend_known_string_id_ZEND_STR_SET: _zend_known_string_id = 76; -pub const _zend_known_string_id_ZEND_STR_LAST_KNOWN: _zend_known_string_id = 77; +pub const _zend_known_string_id_ZEND_STR_CLONE: _zend_known_string_id = 12; +pub const _zend_known_string_id_ZEND_STR_EVAL: _zend_known_string_id = 13; +pub const _zend_known_string_id_ZEND_STR_INCLUDE: _zend_known_string_id = 14; +pub const _zend_known_string_id_ZEND_STR_REQUIRE: _zend_known_string_id = 15; +pub const _zend_known_string_id_ZEND_STR_INCLUDE_ONCE: _zend_known_string_id = 16; +pub const _zend_known_string_id_ZEND_STR_REQUIRE_ONCE: _zend_known_string_id = 17; +pub const _zend_known_string_id_ZEND_STR_SCALAR: _zend_known_string_id = 18; +pub const _zend_known_string_id_ZEND_STR_ERROR_REPORTING: _zend_known_string_id = 19; +pub const _zend_known_string_id_ZEND_STR_STATIC: _zend_known_string_id = 20; +pub const _zend_known_string_id_ZEND_STR_THIS: _zend_known_string_id = 21; +pub const _zend_known_string_id_ZEND_STR_VALUE: _zend_known_string_id = 22; +pub const _zend_known_string_id_ZEND_STR_KEY: _zend_known_string_id = 23; +pub const _zend_known_string_id_ZEND_STR_MAGIC_INVOKE: _zend_known_string_id = 24; +pub const _zend_known_string_id_ZEND_STR_PREVIOUS: _zend_known_string_id = 25; +pub const _zend_known_string_id_ZEND_STR_CODE: _zend_known_string_id = 26; +pub const _zend_known_string_id_ZEND_STR_MESSAGE: _zend_known_string_id = 27; +pub const _zend_known_string_id_ZEND_STR_SEVERITY: _zend_known_string_id = 28; +pub const _zend_known_string_id_ZEND_STR_STRING: _zend_known_string_id = 29; +pub const _zend_known_string_id_ZEND_STR_TRACE: _zend_known_string_id = 30; +pub const _zend_known_string_id_ZEND_STR_SCHEME: _zend_known_string_id = 31; +pub const _zend_known_string_id_ZEND_STR_HOST: _zend_known_string_id = 32; +pub const _zend_known_string_id_ZEND_STR_PORT: _zend_known_string_id = 33; +pub const _zend_known_string_id_ZEND_STR_USER: _zend_known_string_id = 34; +pub const _zend_known_string_id_ZEND_STR_USERNAME: _zend_known_string_id = 35; +pub const _zend_known_string_id_ZEND_STR_PASS: _zend_known_string_id = 36; +pub const _zend_known_string_id_ZEND_STR_PASSWORD: _zend_known_string_id = 37; +pub const _zend_known_string_id_ZEND_STR_PATH: _zend_known_string_id = 38; +pub const _zend_known_string_id_ZEND_STR_QUERY: _zend_known_string_id = 39; +pub const _zend_known_string_id_ZEND_STR_FRAGMENT: _zend_known_string_id = 40; +pub const _zend_known_string_id_ZEND_STR_NULL: _zend_known_string_id = 41; +pub const _zend_known_string_id_ZEND_STR_BOOLEAN: _zend_known_string_id = 42; +pub const _zend_known_string_id_ZEND_STR_INTEGER: _zend_known_string_id = 43; +pub const _zend_known_string_id_ZEND_STR_DOUBLE: _zend_known_string_id = 44; +pub const _zend_known_string_id_ZEND_STR_ARRAY: _zend_known_string_id = 45; +pub const _zend_known_string_id_ZEND_STR_RESOURCE: _zend_known_string_id = 46; +pub const _zend_known_string_id_ZEND_STR_CLOSED_RESOURCE: _zend_known_string_id = 47; +pub const _zend_known_string_id_ZEND_STR_NAME: _zend_known_string_id = 48; +pub const _zend_known_string_id_ZEND_STR_ARGV: _zend_known_string_id = 49; +pub const _zend_known_string_id_ZEND_STR_ARGC: _zend_known_string_id = 50; +pub const _zend_known_string_id_ZEND_STR_ARRAY_CAPITALIZED: _zend_known_string_id = 51; +pub const _zend_known_string_id_ZEND_STR_BOOL: _zend_known_string_id = 52; +pub const _zend_known_string_id_ZEND_STR_INT: _zend_known_string_id = 53; +pub const _zend_known_string_id_ZEND_STR_FLOAT: _zend_known_string_id = 54; +pub const _zend_known_string_id_ZEND_STR_CALLABLE: _zend_known_string_id = 55; +pub const _zend_known_string_id_ZEND_STR_ITERABLE: _zend_known_string_id = 56; +pub const _zend_known_string_id_ZEND_STR_VOID: _zend_known_string_id = 57; +pub const _zend_known_string_id_ZEND_STR_NEVER: _zend_known_string_id = 58; +pub const _zend_known_string_id_ZEND_STR_FALSE: _zend_known_string_id = 59; +pub const _zend_known_string_id_ZEND_STR_TRUE: _zend_known_string_id = 60; +pub const _zend_known_string_id_ZEND_STR_NULL_LOWERCASE: _zend_known_string_id = 61; +pub const _zend_known_string_id_ZEND_STR_MIXED: _zend_known_string_id = 62; +pub const _zend_known_string_id_ZEND_STR_TRAVERSABLE: _zend_known_string_id = 63; +pub const _zend_known_string_id_ZEND_STR_SELF: _zend_known_string_id = 64; +pub const _zend_known_string_id_ZEND_STR_PARENT: _zend_known_string_id = 65; +pub const _zend_known_string_id_ZEND_STR_SLEEP: _zend_known_string_id = 66; +pub const _zend_known_string_id_ZEND_STR_WAKEUP: _zend_known_string_id = 67; +pub const _zend_known_string_id_ZEND_STR_CASES: _zend_known_string_id = 68; +pub const _zend_known_string_id_ZEND_STR_FROM: _zend_known_string_id = 69; +pub const _zend_known_string_id_ZEND_STR_TRYFROM: _zend_known_string_id = 70; +pub const _zend_known_string_id_ZEND_STR_TRYFROM_LOWERCASE: _zend_known_string_id = 71; +pub const _zend_known_string_id_ZEND_STR_AUTOGLOBAL_SERVER: _zend_known_string_id = 72; +pub const _zend_known_string_id_ZEND_STR_AUTOGLOBAL_ENV: _zend_known_string_id = 73; +pub const _zend_known_string_id_ZEND_STR_AUTOGLOBAL_REQUEST: _zend_known_string_id = 74; +pub const _zend_known_string_id_ZEND_STR_COUNT: _zend_known_string_id = 75; +pub const _zend_known_string_id_ZEND_STR_SENSITIVEPARAMETER: _zend_known_string_id = 76; +pub const _zend_known_string_id_ZEND_STR_CONST_EXPR_PLACEHOLDER: _zend_known_string_id = 77; +pub const _zend_known_string_id_ZEND_STR_DEPRECATED_CAPITALIZED: _zend_known_string_id = 78; +pub const _zend_known_string_id_ZEND_STR_SINCE: _zend_known_string_id = 79; +pub const _zend_known_string_id_ZEND_STR_GET: _zend_known_string_id = 80; +pub const _zend_known_string_id_ZEND_STR_SET: _zend_known_string_id = 81; +pub const _zend_known_string_id_ZEND_STR_8_DOT_0: _zend_known_string_id = 82; +pub const _zend_known_string_id_ZEND_STR_8_DOT_1: _zend_known_string_id = 83; +pub const _zend_known_string_id_ZEND_STR_8_DOT_2: _zend_known_string_id = 84; +pub const _zend_known_string_id_ZEND_STR_8_DOT_3: _zend_known_string_id = 85; +pub const _zend_known_string_id_ZEND_STR_8_DOT_4: _zend_known_string_id = 86; +pub const _zend_known_string_id_ZEND_STR_8_DOT_5: _zend_known_string_id = 87; +pub const _zend_known_string_id_ZEND_STR_LAST_KNOWN: _zend_known_string_id = 88; pub type _zend_known_string_id = ::std::os::raw::c_uint; +pub const zend_hash_key_type_HASH_KEY_IS_STRING: zend_hash_key_type = 1; +pub const zend_hash_key_type_HASH_KEY_IS_LONG: zend_hash_key_type = 2; +pub const zend_hash_key_type_HASH_KEY_NON_EXISTENT: zend_hash_key_type = 3; +pub type zend_hash_key_type = ::std::os::raw::c_uint; unsafe extern "C" { pub fn zend_hash_clean(ht: *mut HashTable); } @@ -796,10 +811,11 @@ unsafe extern "C" { pub fn zend_hash_find_known_hash(ht: *const HashTable, key: *const zend_string) -> *mut zval; } unsafe extern "C" { - pub fn zend_hash_move_forward_ex(ht: *mut HashTable, pos: *mut HashPosition) -> zend_result; + pub fn zend_hash_move_forward_ex(ht: *const HashTable, pos: *mut HashPosition) -> zend_result; } unsafe extern "C" { - pub fn zend_hash_move_backwards_ex(ht: *mut HashTable, pos: *mut HashPosition) -> zend_result; + pub fn zend_hash_move_backwards_ex(ht: *const HashTable, pos: *mut HashPosition) + -> zend_result; } unsafe extern "C" { pub fn zend_hash_get_current_key_zval_ex( @@ -810,12 +826,15 @@ unsafe extern "C" { } unsafe extern "C" { pub fn zend_hash_get_current_key_type_ex( - ht: *mut HashTable, - pos: *mut HashPosition, - ) -> ::std::os::raw::c_int; + ht: *const HashTable, + pos: *const HashPosition, + ) -> zend_hash_key_type; } unsafe extern "C" { - pub fn zend_hash_get_current_data_ex(ht: *mut HashTable, pos: *mut HashPosition) -> *mut zval; + pub fn zend_hash_get_current_data_ex( + ht: *const HashTable, + pos: *const HashPosition, + ) -> *mut zval; } unsafe extern "C" { pub fn _zend_new_array(size: u32) -> *mut HashTable; @@ -824,7 +843,7 @@ unsafe extern "C" { pub fn zend_array_count(ht: *mut HashTable) -> u32; } unsafe extern "C" { - pub fn zend_array_dup(source: *mut HashTable) -> *mut HashTable; + pub fn zend_array_dup(source: *const HashTable) -> *mut HashTable; } unsafe extern "C" { pub fn zend_array_destroy(ht: *mut HashTable); @@ -846,6 +865,7 @@ pub struct _zend_ast { pub lineno: u32, pub child: [*mut zend_ast; 1usize], } +pub type zend_op_array = _zend_op_array; unsafe extern "C" { pub fn zval_ptr_dtor(zval_ptr: *mut zval); } @@ -1293,6 +1313,13 @@ pub type zend_object_dtor_obj_t = ::std::option::Option; pub type zend_object_clone_obj_t = ::std::option::Option *mut zend_object>; +pub type zend_object_clone_obj_with_t = ::std::option::Option< + unsafe extern "C" fn( + object: *mut zend_object, + scope: *const zend_class_entry, + properties: *const HashTable, + ) -> *mut zend_object, +>; pub type zend_object_get_class_name_t = ::std::option::Option *mut zend_string>; pub type zend_object_compare_t = ::std::option::Option< @@ -1339,6 +1366,7 @@ pub struct _zend_object_handlers { pub free_obj: zend_object_free_obj_t, pub dtor_obj: zend_object_dtor_obj_t, pub clone_obj: zend_object_clone_obj_t, + pub clone_obj_with: zend_object_clone_obj_with_t, pub read_property: zend_object_read_property_t, pub write_property: zend_object_write_property_t, pub read_dimension: zend_object_read_dimension_t, @@ -1418,6 +1446,7 @@ unsafe extern "C" { unsafe extern "C" { pub fn zend_is_true(op: *const zval) -> bool; } +pub type zend_vm_opcode_handler_t = *const ::std::os::raw::c_void; pub type zend_op = _zend_op; #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -1425,7 +1454,6 @@ pub struct zend_frameless_function_info { pub handler: *mut ::std::os::raw::c_void, pub num_args: u32, } -pub type zend_op_array = _zend_op_array; #[repr(C)] #[derive(Copy, Clone)] pub union _znode_op { @@ -1457,7 +1485,7 @@ pub type zend_file_context = _zend_file_context; #[repr(C)] #[derive(Copy, Clone)] pub struct _zend_op { - pub handler: *const ::std::os::raw::c_void, + pub handler: zend_vm_opcode_handler_t, pub op1: znode_op, pub op2: znode_op, pub result: znode_op, @@ -1509,9 +1537,10 @@ pub struct _zend_oparray_context { pub last_brk_cont: ::std::os::raw::c_int, pub brk_cont_array: *mut zend_brk_cont_element, pub labels: *mut HashTable, - pub active_property_info: *const zend_property_info, + pub active_property_info_name: *mut zend_string, pub active_property_hook_kind: zend_property_hook_kind, pub in_jmp_frameless_branch: bool, + pub has_assigned_to_http_response_header: bool, } pub type zend_oparray_context = _zend_oparray_context; #[repr(C)] @@ -1806,6 +1835,8 @@ pub struct _zend_executor_globals { pub included_files: HashTable, pub bailout: *mut sigjmp_buf, pub error_reporting: ::std::os::raw::c_int, + pub fatal_error_backtrace_on: bool, + pub last_fatal_error_backtrace: zval, pub exit_status: ::std::os::raw::c_int, pub function_table: *mut HashTable, pub class_table: *mut HashTable, @@ -1815,7 +1846,7 @@ pub struct _zend_executor_globals { pub vm_stack: zend_vm_stack, pub vm_stack_page_size: usize, pub current_execute_data: *mut _zend_execute_data, - pub fake_scope: *mut zend_class_entry, + pub fake_scope: *const zend_class_entry, pub jit_trace_num: u32, pub current_observed_frame: *mut zend_execute_data, pub ticks_count: ::std::os::raw::c_int, @@ -1944,6 +1975,50 @@ pub struct _zend_module_dep { pub version: *const ::std::os::raw::c_char, pub type_: ::std::os::raw::c_uchar, } +#[repr(C)] +pub struct _zend_constant { + pub value: zval, + pub name: *mut zend_string, + pub filename: *mut zend_string, + pub attributes: *mut HashTable, +} +pub type zend_constant = _zend_constant; +unsafe extern "C" { + pub fn zend_register_bool_constant( + name: *const ::std::os::raw::c_char, + name_len: usize, + bval: bool, + flags: ::std::os::raw::c_int, + module_number: ::std::os::raw::c_int, + ) -> *mut zend_constant; +} +unsafe extern "C" { + pub fn zend_register_long_constant( + name: *const ::std::os::raw::c_char, + name_len: usize, + lval: zend_long, + flags: ::std::os::raw::c_int, + module_number: ::std::os::raw::c_int, + ) -> *mut zend_constant; +} +unsafe extern "C" { + pub fn zend_register_double_constant( + name: *const ::std::os::raw::c_char, + name_len: usize, + dval: f64, + flags: ::std::os::raw::c_int, + module_number: ::std::os::raw::c_int, + ) -> *mut zend_constant; +} +unsafe extern "C" { + pub fn zend_register_string_constant( + name: *const ::std::os::raw::c_char, + name_len: usize, + strval: *const ::std::os::raw::c_char, + flags: ::std::os::raw::c_int, + module_number: ::std::os::raw::c_int, + ) -> *mut zend_constant; +} unsafe extern "C" { pub fn zend_lookup_class_ex( name: *mut zend_string, @@ -2128,10 +2203,11 @@ pub type php_stream_notification_func = ::std::option::Option< >; pub type php_stream_notifier = _php_stream_notifier; #[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct _php_stream_notifier { pub func: php_stream_notification_func, pub dtor: ::std::option::Option, - pub ptr: zval, + pub ptr: *mut ::std::os::raw::c_void, pub mask: ::std::os::raw::c_int, pub progress: usize, pub progress_max: usize, @@ -2152,8 +2228,8 @@ pub struct _php_stream_bucket { pub brigade: *mut php_stream_bucket_brigade, pub buf: *mut ::std::os::raw::c_char, pub buflen: usize, - pub own_buf: u8, - pub is_persistent: u8, + pub own_buf: bool, + pub is_persistent: bool, pub refcount: ::std::os::raw::c_int, } #[repr(C)] @@ -2760,6 +2836,7 @@ pub struct _php_core_globals { pub unserialize_callback_func: *mut ::std::os::raw::c_char, pub serialize_precision: zend_long, pub memory_limit: zend_long, + pub max_memory_limit: zend_long, pub max_input_time: zend_long, pub error_log: *mut ::std::os::raw::c_char, pub doc_root: *mut ::std::os::raw::c_char, @@ -2807,13 +2884,13 @@ pub struct _php_core_globals { pub last_error_message: *mut zend_string, pub last_error_file: *mut zend_string, pub php_sys_temp_dir: *mut ::std::os::raw::c_char, - pub disable_classes: *mut ::std::os::raw::c_char, pub max_input_nesting_level: zend_long, pub max_input_vars: zend_long, pub user_ini_filename: *mut ::std::os::raw::c_char, pub user_ini_cache_ttl: zend_long, pub request_order: *mut ::std::os::raw::c_char, pub mail_log: *mut ::std::os::raw::c_char, + pub mail_cr_lf_mode: *mut zend_string, pub mail_x_header: bool, pub mail_mixed_lf_and_crlf: bool, pub in_error_log: bool, @@ -2831,8 +2908,8 @@ unsafe extern "C" { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _arg_separators { - pub output: *mut ::std::os::raw::c_char, - pub input: *mut ::std::os::raw::c_char, + pub output: *mut zend_string, + pub input: *mut zend_string, } pub type arg_separators = _arg_separators; #[repr(C)] @@ -2887,6 +2964,7 @@ pub struct _zend_ini_entry { pub modifiable: u8, pub orig_modifiable: u8, pub modified: u8, + pub def: *const zend_ini_entry_def, } unsafe extern "C" { pub fn zend_register_ini_entries( @@ -2909,42 +2987,6 @@ pub struct _zend_ini_parser_param { pub ini_parser_cb: zend_ini_parser_cb_t, pub arg: *mut ::std::os::raw::c_void, } -unsafe extern "C" { - pub fn zend_register_bool_constant( - name: *const ::std::os::raw::c_char, - name_len: usize, - bval: bool, - flags: ::std::os::raw::c_int, - module_number: ::std::os::raw::c_int, - ); -} -unsafe extern "C" { - pub fn zend_register_long_constant( - name: *const ::std::os::raw::c_char, - name_len: usize, - lval: zend_long, - flags: ::std::os::raw::c_int, - module_number: ::std::os::raw::c_int, - ); -} -unsafe extern "C" { - pub fn zend_register_double_constant( - name: *const ::std::os::raw::c_char, - name_len: usize, - dval: f64, - flags: ::std::os::raw::c_int, - module_number: ::std::os::raw::c_int, - ); -} -unsafe extern "C" { - pub fn zend_register_string_constant( - name: *const ::std::os::raw::c_char, - name_len: usize, - strval: *const ::std::os::raw::c_char, - flags: ::std::os::raw::c_int, - module_number: ::std::os::raw::c_int, - ); -} unsafe extern "C" { pub fn php_info_print_table_header(num_cols: ::std::os::raw::c_int, ...); } @@ -3176,8 +3218,9 @@ unsafe extern "C" { pub const sapi_header_op_enum_SAPI_HEADER_REPLACE: sapi_header_op_enum = 0; pub const sapi_header_op_enum_SAPI_HEADER_ADD: sapi_header_op_enum = 1; pub const sapi_header_op_enum_SAPI_HEADER_DELETE: sapi_header_op_enum = 2; -pub const sapi_header_op_enum_SAPI_HEADER_DELETE_ALL: sapi_header_op_enum = 3; -pub const sapi_header_op_enum_SAPI_HEADER_SET_STATUS: sapi_header_op_enum = 4; +pub const sapi_header_op_enum_SAPI_HEADER_DELETE_PREFIX: sapi_header_op_enum = 3; +pub const sapi_header_op_enum_SAPI_HEADER_DELETE_ALL: sapi_header_op_enum = 4; +pub const sapi_header_op_enum_SAPI_HEADER_SET_STATUS: sapi_header_op_enum = 5; pub type sapi_header_op_enum = ::std::os::raw::c_uint; #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -3277,6 +3320,7 @@ pub struct _sapi_module_struct { pub ini_entries: *const ::std::os::raw::c_char, pub additional_functions: *const zend_function_entry, pub input_filter_init: ::std::option::Option ::std::os::raw::c_uint>, + pub pre_request_init: ::std::option::Option ::std::os::raw::c_int>, } #[repr(C)] #[derive(Debug, Copy, Clone)] diff --git a/src/builders/sapi.rs b/src/builders/sapi.rs index fd5ab3f13d..1de957209c 100644 --- a/src/builders/sapi.rs +++ b/src/builders/sapi.rs @@ -95,6 +95,8 @@ impl SapiBuilder { ini_entries: ptr::null_mut(), additional_functions: ptr::null(), input_filter_init: None, + #[cfg(php85)] + pre_request_init: None, }, executable_location: None, php_ini_path_override: None, @@ -287,6 +289,20 @@ impl SapiBuilder { self } + /// Sets the pre-request init function for this SAPI + /// + /// This function is called before request activation and before POST data is read. + /// It is typically used for .user.ini processing. + /// + /// # Parameters + /// + /// * `func` - The function to be called before request initialization. + #[cfg(php85)] + pub fn pre_request_init_function(mut self, func: SapiPreRequestInitFunc) -> Self { + self.module.pre_request_init = Some(func); + self + } + /// Set the `ini_entries` for this SAPI /// /// # Parameters @@ -439,6 +455,10 @@ pub type SapiGetUidFunc = extern "C" fn(uid: *mut uid_t) -> c_int; /// A function to be called when PHP gets the gid pub type SapiGetGidFunc = extern "C" fn(gid: *mut gid_t) -> c_int; +/// A function to be called before request activation (used for .user.ini processing) +#[cfg(php85)] +pub type SapiPreRequestInitFunc = extern "C" fn() -> c_int; + extern "C" fn dummy_send_header(_header: *mut sapi_header_struct, _server_context: *mut c_void) {} #[cfg(test)] @@ -490,6 +510,10 @@ mod test { extern "C" fn test_get_target_gid(_gid: *mut gid_t) -> c_int { 0 } + #[cfg(php85)] + extern "C" fn test_pre_request_init() -> c_int { + 0 + } #[test] fn test_basic_sapi_builder() { @@ -760,6 +784,22 @@ mod test { ); } + #[cfg(php85)] + #[test] + fn test_pre_request_init_function() { + let sapi = SapiBuilder::new("test", "Test") + .pre_request_init_function(test_pre_request_init) + .build() + .expect("should build sapi module"); + + assert!(sapi.pre_request_init.is_some()); + assert_eq!( + sapi.pre_request_init + .expect("should have pre_request_init function") as usize, + test_pre_request_init as usize + ); + } + #[cfg(php82)] #[test] fn test_sapi_ini_entries() { diff --git a/src/constant.rs b/src/constant.rs index 7e2aac1fcd..9e8e52c316 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -107,13 +107,26 @@ impl IntoConst for &str { flags: GlobalConstantFlags, ) -> Result<()> { unsafe { - zend_register_string_constant( - CString::new(name)?.as_ptr(), - name.len() as _, - CString::new(*self)?.as_ptr(), - flags.bits().try_into()?, - module_number, - ); + #[cfg(php85)] + { + let _ = zend_register_string_constant( + CString::new(name)?.as_ptr(), + name.len() as _, + CString::new(*self)?.as_ptr(), + flags.bits().try_into()?, + module_number, + ); + } + #[cfg(not(php85))] + { + zend_register_string_constant( + CString::new(name)?.as_ptr(), + name.len() as _, + CString::new(*self)?.as_ptr(), + flags.bits().try_into()?, + module_number, + ); + } }; Ok(()) } @@ -127,13 +140,26 @@ impl IntoConst for bool { flags: GlobalConstantFlags, ) -> Result<()> { unsafe { - zend_register_bool_constant( - CString::new(name)?.as_ptr(), - name.len() as _, - *self, - flags.bits().try_into()?, - module_number, - ); + #[cfg(php85)] + { + let _ = zend_register_bool_constant( + CString::new(name)?.as_ptr(), + name.len() as _, + *self, + flags.bits().try_into()?, + module_number, + ); + } + #[cfg(not(php85))] + { + zend_register_bool_constant( + CString::new(name)?.as_ptr(), + name.len() as _, + *self, + flags.bits().try_into()?, + module_number, + ); + } }; Ok(()) } @@ -150,15 +176,29 @@ macro_rules! into_const_num { module_number: i32, flags: GlobalConstantFlags, ) -> Result<()> { - Ok(unsafe { - $fn( - CString::new(name)?.as_ptr(), - name.len() as _, - (*self).into(), - flags.bits().try_into()?, - module_number, - ) - }) + unsafe { + #[cfg(php85)] + { + let _ = $fn( + CString::new(name)?.as_ptr(), + name.len() as _, + (*self).into(), + flags.bits().try_into()?, + module_number, + ); + } + #[cfg(not(php85))] + { + $fn( + CString::new(name)?.as_ptr(), + name.len() as _, + (*self).into(), + flags.bits().try_into()?, + module_number, + ); + } + }; + Ok(()) } } }; diff --git a/src/types/array/iterators.rs b/src/types/array/iterators.rs index 4a53fce720..fcd90db9e3 100644 --- a/src/types/array/iterators.rs +++ b/src/types/array/iterators.rs @@ -15,6 +15,9 @@ use crate::{ types::Zval, }; +#[cfg(php85)] +use crate::ffi::zend_hash_key_type_HASH_KEY_NON_EXISTENT; + /// Immutable iterator upon a reference to a hashtable. pub struct Iter<'a> { ht: &'a ZendHashTable, @@ -59,13 +62,22 @@ impl<'a> Iter<'a> { zend_hash_get_current_key_type_ex(ptr::from_ref(self.ht).cast_mut(), &raw mut self.pos) }; - // Key type `-1` is ??? - // Key type `1` is string - // Key type `2` is long - // Key type `3` is null meaning the end of the array - if key_type == -1 || key_type == 3 { + // Key type `1` is string (HASH_KEY_IS_STRING) + // Key type `2` is long (HASH_KEY_IS_LONG) + // Key type `3` is null/non-existent (HASH_KEY_NON_EXISTENT) + // Pre-PHP 8.5 returns int, PHP 8.5+ returns enum u32 + #[cfg(php85)] + if key_type == zend_hash_key_type_HASH_KEY_NON_EXISTENT { return None; } + #[cfg(not(php85))] + { + // Pre-PHP 8.5: function returns signed int (i32) + // Check for -1 (defensive) and 3 (HASH_KEY_NON_EXISTENT) + if key_type == -1 || key_type == 3 { + return None; + } + } let mut key = Zval::new(); @@ -157,9 +169,18 @@ impl DoubleEndedIterator for Iter<'_> { zend_hash_get_current_key_type_ex(ptr::from_ref(self.ht).cast_mut(), &raw mut self.pos) }; - if key_type == -1 { + #[cfg(php85)] + if key_type == zend_hash_key_type_HASH_KEY_NON_EXISTENT { return None; } + #[cfg(not(php85))] + { + // Pre-PHP 8.5: function returns signed int (i32) + // Check for -1 (defensive) and 3 (HASH_KEY_NON_EXISTENT) + if key_type == -1 || key_type == 3 { + return None; + } + } let key = Zval::new(); diff --git a/src/wrapper.h b/src/wrapper.h index 5ae9098c89..ac58cd9286 100644 --- a/src/wrapper.h +++ b/src/wrapper.h @@ -8,6 +8,7 @@ // generate bindings. To work around this, we include the header file containing // the `ZEND_FASTCALL` macro but not before undefining `__clang__` to pretend we // are compiling on MSVC. + #if defined(_MSC_VER) && defined(__clang__) #undef __clang__ #include "zend_portability.h" diff --git a/tools/update_bindings.sh b/tools/update_bindings.sh index 85b1cf3708..644b6ed144 100755 --- a/tools/update_bindings.sh +++ b/tools/update_bindings.sh @@ -9,5 +9,5 @@ docker buildx build \ --platform linux/amd64 \ --target docsrs_bindings \ -o type=local,dest=. \ - --build-arg PHP_VERSION=8.4 \ + --build-arg PHP_VERSION=8.5 \ . diff --git a/windows_build.rs b/windows_build.rs index 5c27e39bf7..57d0a3ae6b 100644 --- a/windows_build.rs +++ b/windows_build.rs @@ -28,6 +28,35 @@ impl<'a> Provider<'a> { .to_string_lossy() .to_string()) } + + /// Returns Windows SDK include paths for bindgen's clang. + /// PHP 8.5+ requires intsafe.h from the Windows SDK. + pub fn get_windows_sdk_includes(&self) -> Vec { + // Use cc crate's Windows registry detection to find SDK paths + let target = + std::env::var("TARGET").unwrap_or_else(|_| "x86_64-pc-windows-msvc".to_string()); + + if let Ok(tool) = cc::windows_registry::find_tool(&target, "cl.exe") { + // Extract include paths from the MSVC tool environment + tool.env() + .iter() + .filter(|(key, _)| key == &"INCLUDE") + .flat_map(|(_, value)| { + value + .to_str() + .map(|s| { + s.split(';') + .filter(|p| !p.is_empty()) + .map(PathBuf::from) + .collect::>() + }) + .unwrap_or_default() + }) + .collect() + } else { + Vec::new() + } + } } impl<'a> PHPProvider<'a> for Provider<'a> { @@ -65,6 +94,16 @@ impl<'a> PHPProvider<'a> for Provider<'a> { Ok(defines) } + fn get_extra_clang_args(&self) -> Result> { + // PHP 8.5+ on Windows requires intsafe.h from the Windows SDK + // Add Windows SDK include paths so bindgen's clang can find system headers + let sdk_includes = self.get_windows_sdk_includes(); + Ok(sdk_includes + .iter() + .map(|path| format!("-I{}", path.display())) + .collect()) + } + fn write_bindings(&self, bindings: String, writer: &mut impl Write) -> Result<()> { // For some reason some symbols don't link without a `#[link(name = "php8")]` // attribute on each extern block. Bindgen doesn't give us the option to add