Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/action/musl/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG PHP_VERSION=8.4
ARG PHP_VERSION=8.5
ARG TS=-zts

FROM php:${PHP_VERSION}${TS}-alpine
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -173,7 +173,7 @@ jobs:
runs-on: ubuntu-latest
env:
clang: "17"
php_version: "8.4"
php_version: "8.5"
steps:
- name: Checkout code
uses: actions/checkout@v5
Expand All @@ -185,15 +185,15 @@ jobs:
env:
debug: true

- name: Install libphp-embed
run: sudo apt update -y && sudo apt install -y libphp8.4-embed

- name: Setup Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: rustfmt, clippy

- name: Install libphp-embed
run: sudo apt update -y && sudo apt install -y libphp${{ env.php_version }}-embed-dbgsym

- name: Install cargo-expand
uses: dtolnay/install@cargo-expand

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
FROM rust:latest AS base
ARG PHP_VERSION=8.4
ARG PHP_VERSION=8.5
WORKDIR /tmp
RUN <<EOF
set -e
Expand Down
1 change: 1 addition & 0 deletions allowed_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ bind! {
zend_hash_get_current_key_zval_ex,
zend_hash_get_current_data_ex,
zend_hash_move_backwards_ex,
zend_hash_key_type,
zend_array_count,
gc_possible_root,
ZEND_ACC_NOT_SERIALIZABLE,
Expand Down
14 changes: 11 additions & 3 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ enum ApiVersion {
Php82 = 2022_08_29,
Php83 = 2023_08_31,
Php84 = 2024_09_24,
Php85 = 2025_09_25,
}

impl ApiVersion {
Expand All @@ -285,7 +286,7 @@ impl ApiVersion {

/// Returns the maximum API version supported by ext-php-rs.
pub const fn max() -> Self {
ApiVersion::Php84
ApiVersion::Php85
}

pub fn versions() -> Vec<Self> {
Expand All @@ -295,6 +296,7 @@ impl ApiVersion {
ApiVersion::Php82,
ApiVersion::Php83,
ApiVersion::Php84,
ApiVersion::Php85,
]
}

Expand All @@ -313,6 +315,7 @@ impl ApiVersion {
ApiVersion::Php82 => "php82",
ApiVersion::Php83 => "php83",
ApiVersion::Php84 => "php84",
ApiVersion::Php85 => "php85",
}
}

Expand All @@ -323,6 +326,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",
}
}
}
Expand All @@ -344,7 +348,10 @@ impl TryFrom<u32> 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,
Expand All @@ -371,7 +378,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 {
Expand Down Expand Up @@ -416,6 +423,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(());
Expand Down
302 changes: 173 additions & 129 deletions docsrs_bindings.rs

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions src/builders/sapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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() {
Expand Down
84 changes: 61 additions & 23 deletions src/constant.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Types and traits for registering constants in PHP.

use cfg_if::cfg_if;
use std::ffi::CString;
use std::fmt::Debug;

Expand Down Expand Up @@ -107,13 +108,25 @@ 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_if! {
if #[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,
);
} else {
zend_register_string_constant(
CString::new(name)?.as_ptr(),
name.len() as _,
CString::new(*self)?.as_ptr(),
flags.bits().try_into()?,
module_number,
);
}
}
};
Ok(())
}
Expand All @@ -127,13 +140,25 @@ 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_if! {
if #[cfg(php85)] {
let _ = zend_register_bool_constant(
CString::new(name)?.as_ptr(),
name.len() as _,
*self,
flags.bits().try_into()?,
module_number,
);
} else {
zend_register_bool_constant(
CString::new(name)?.as_ptr(),
name.len() as _,
*self,
flags.bits().try_into()?,
module_number,
);
}
}
};
Ok(())
}
Expand All @@ -150,15 +175,28 @@ 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_if! {
if #[cfg(php85)] {
let _ = $fn(
CString::new(name)?.as_ptr(),
name.len() as _,
(*self).into(),
flags.bits().try_into()?,
module_number,
);
} else {
$fn(
CString::new(name)?.as_ptr(),
name.len() as _,
(*self).into(),
flags.bits().try_into()?,
module_number,
);
}
}
};
Ok(())
}
}
};
Expand Down
40 changes: 32 additions & 8 deletions src/types/array/iterators.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cfg_if::cfg_if;
use std::{
convert::TryInto,
iter::{DoubleEndedIterator, ExactSizeIterator, Iterator},
Expand All @@ -15,6 +16,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,
Expand Down Expand Up @@ -59,12 +63,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 {
return None;
// 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_if! {
if #[cfg(php85)] {
if key_type == zend_hash_key_type_HASH_KEY_NON_EXISTENT {
return None;
}
} else {
// 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();
Expand Down Expand Up @@ -157,8 +171,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 {
return None;
cfg_if! {
if #[cfg(php85)] {
if key_type == zend_hash_key_type_HASH_KEY_NON_EXISTENT {
return None;
}
} else {
// 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();
Expand Down
Loading