Skip to content

Commit eac0cc6

Browse files
committed
docs(guide): add guide for IniBuilder
1 parent 03a7f2a commit eac0cc6

File tree

6 files changed

+255
-54
lines changed

6 files changed

+255
-54
lines changed

build.rs

Lines changed: 102 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,10 @@ use std::{
1616
str::FromStr,
1717
};
1818

19-
use anyhow::{anyhow, bail, Context, Result};
19+
use anyhow::{anyhow, bail, Context, Error, Result};
2020
use bindgen::RustTarget;
2121
use impl_::Provider;
2222

23-
const MIN_PHP_API_VER: u32 = 2020_09_30;
24-
const MAX_PHP_API_VER: u32 = 2024_09_24;
25-
2623
/// Provides information about the PHP installation.
2724
pub trait PHPProvider<'a>: Sized {
2825
/// Create a new PHP provider.
@@ -170,6 +167,20 @@ impl PHPInfo {
170167
}
171168
}
172169

170+
fn add_php_version_defines(
171+
defines: &mut Vec<(&'static str, &'static str)>,
172+
info: &PHPInfo,
173+
) -> Result<()> {
174+
let version = info.zend_version()?;
175+
let supported_version: ApiVersion = version.try_into()?;
176+
177+
for supported_api in supported_version.supported_apis() {
178+
defines.push((supported_api.define_name(), "1"));
179+
}
180+
181+
Ok(())
182+
}
183+
173184
/// Builds the wrapper library.
174185
fn build_wrapper(defines: &[(&str, &str)], includes: &[PathBuf]) -> Result<()> {
175186
let mut build = cc::Build::new();
@@ -249,19 +260,90 @@ fn generate_bindings(defines: &[(&str, &str)], includes: &[PathBuf]) -> Result<S
249260
Ok(bindings)
250261
}
251262

263+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
264+
enum ApiVersion {
265+
Php80 = 2020_09_30,
266+
Php81 = 2021_09_02,
267+
Php82 = 2022_08_29,
268+
Php83 = 2023_08_31,
269+
Php84 = 2024_09_24,
270+
}
271+
272+
impl ApiVersion {
273+
/// Returns the minimum API version supported by ext-php-rs.
274+
pub const fn min() -> Self {
275+
ApiVersion::Php80
276+
}
277+
278+
/// Returns the maximum API version supported by ext-php-rs.
279+
pub const fn max() -> Self {
280+
ApiVersion::Php84
281+
}
282+
283+
pub fn versions() -> Vec<Self> {
284+
vec![
285+
ApiVersion::Php80,
286+
ApiVersion::Php81,
287+
ApiVersion::Php82,
288+
ApiVersion::Php83,
289+
ApiVersion::Php84,
290+
]
291+
}
292+
293+
/// Returns the API versions that are supported by this version.
294+
pub fn supported_apis(self) -> Vec<ApiVersion> {
295+
ApiVersion::versions()
296+
.into_iter()
297+
.filter(|&v| v <= self)
298+
.collect()
299+
}
300+
301+
pub fn cfg_name(self) -> &'static str {
302+
match self {
303+
ApiVersion::Php80 => "php80",
304+
ApiVersion::Php81 => "php81",
305+
ApiVersion::Php82 => "php82",
306+
ApiVersion::Php83 => "php83",
307+
ApiVersion::Php84 => "php84",
308+
}
309+
}
310+
311+
pub fn define_name(self) -> &'static str {
312+
match self {
313+
ApiVersion::Php80 => "EXT_PHP_RS_PHP_80",
314+
ApiVersion::Php81 => "EXT_PHP_RS_PHP_81",
315+
ApiVersion::Php82 => "EXT_PHP_RS_PHP_82",
316+
ApiVersion::Php83 => "EXT_PHP_RS_PHP_83",
317+
ApiVersion::Php84 => "EXT_PHP_RS_PHP_84",
318+
}
319+
}
320+
}
321+
322+
impl TryFrom<u32> for ApiVersion {
323+
type Error = Error;
324+
325+
fn try_from(version: u32) -> Result<Self, Self::Error> {
326+
match version {
327+
x if (2020_09_30..2021_09_02).contains(&x) => Ok(ApiVersion::Php80),
328+
x if (2021_09_02..2022_08_29).contains(&x) => Ok(ApiVersion::Php81),
329+
x if (2022_08_29..2023_08_31).contains(&x) => Ok(ApiVersion::Php82),
330+
x if (2023_08_31..2024_09_24).contains(&x) => Ok(ApiVersion::Php83),
331+
2024_09_24 => Ok(ApiVersion::Php84),
332+
version => Err(anyhow!(
333+
"The current version of PHP is not supported. Current PHP API version: {}, requires a version between {} and {}",
334+
version,
335+
ApiVersion::min() as u32,
336+
ApiVersion::max() as u32
337+
))
338+
}
339+
}
340+
}
341+
252342
/// Checks the PHP Zend API version for compatibility with ext-php-rs, setting
253343
/// any configuration flags required.
254344
fn check_php_version(info: &PHPInfo) -> Result<()> {
255-
const PHP_81_API_VER: u32 = 2021_09_02;
256-
const PHP_82_API_VER: u32 = 2022_08_29;
257-
const PHP_83_API_VER: u32 = 2023_08_31;
258-
const PHP_84_API_VER: u32 = 2024_09_24;
259-
260345
let version = info.zend_version()?;
261-
262-
if !(MIN_PHP_API_VER..=MAX_PHP_API_VER).contains(&version) {
263-
bail!("The current version of PHP is not supported. Current PHP API version: {}, requires a version between {} and {}", version, MIN_PHP_API_VER, MAX_PHP_API_VER);
264-
}
346+
let version: ApiVersion = version.try_into()?;
265347

266348
// Infra cfg flags - use these for things that change in the Zend API that don't
267349
// rely on a feature and the crate user won't care about (e.g. struct field
@@ -275,26 +357,14 @@ fn check_php_version(info: &PHPInfo) -> Result<()> {
275357
println!(
276358
"cargo::rustc-check-cfg=cfg(php80, php81, php82, php83, php84, php_zts, php_debug, docs)"
277359
);
278-
println!("cargo:rustc-cfg=php80");
279-
280-
if (MIN_PHP_API_VER..PHP_81_API_VER).contains(&version) {
281-
println!("cargo:warning=PHP version 8.0 is EOL and will no longer be supported in a future release. Please upgrade to a supported version of PHP. See https://www.php.net/supported-versions.php for information on version support timelines.");
282-
}
283-
284-
if version >= PHP_81_API_VER {
285-
println!("cargo:rustc-cfg=php81");
286-
}
287-
288-
if version >= PHP_82_API_VER {
289-
println!("cargo:rustc-cfg=php82");
290-
}
291360

292-
if version >= PHP_83_API_VER {
293-
println!("cargo:rustc-cfg=php83");
361+
if version == ApiVersion::Php80 {
362+
println!("cargo:warning=PHP 8.0 is EOL and will no longer be supported in a future release. Please upgrade to a supported version of PHP. See https://www.php.net/supported-versions.php for information on version support timelines.");
294363
}
295364

296-
if version >= PHP_84_API_VER {
297-
println!("cargo:rustc-cfg=php84");
365+
let supported_versions = version.supported_apis();
366+
for supported_version in supported_versions {
367+
println!("cargo:rustc-cfg={}", supported_version.cfg_name());
298368
}
299369

300370
Ok(())
@@ -337,7 +407,8 @@ fn main() -> Result<()> {
337407
let provider = Provider::new(&info)?;
338408

339409
let includes = provider.get_includes()?;
340-
let defines = provider.get_defines()?;
410+
let mut defines = provider.get_defines()?;
411+
add_php_version_defines(&mut defines, &info)?;
341412

342413
check_php_version(&info)?;
343414
build_wrapper(&defines, &includes)?;

docsrs_bindings.rs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,11 @@ pub type __uid_t = ::std::os::raw::c_uint;
204204
pub type __gid_t = ::std::os::raw::c_uint;
205205
pub type __ino_t = ::std::os::raw::c_ulong;
206206
pub type __mode_t = ::std::os::raw::c_uint;
207-
pub type __nlink_t = ::std::os::raw::c_ulong;
207+
pub type __nlink_t = ::std::os::raw::c_uint;
208208
pub type __off_t = ::std::os::raw::c_long;
209209
pub type __off64_t = ::std::os::raw::c_long;
210210
pub type __time_t = ::std::os::raw::c_long;
211-
pub type __blksize_t = ::std::os::raw::c_long;
211+
pub type __blksize_t = ::std::os::raw::c_int;
212212
pub type __blkcnt_t = ::std::os::raw::c_long;
213213
pub type __syscall_slong_t = ::std::os::raw::c_long;
214214
pub type gid_t = __gid_t;
@@ -768,19 +768,20 @@ pub type zend_class_arrayaccess_funcs = _zend_class_arrayaccess_funcs;
768768
pub struct stat {
769769
pub st_dev: __dev_t,
770770
pub st_ino: __ino_t,
771-
pub st_nlink: __nlink_t,
772771
pub st_mode: __mode_t,
772+
pub st_nlink: __nlink_t,
773773
pub st_uid: __uid_t,
774774
pub st_gid: __gid_t,
775-
pub __pad0: ::std::os::raw::c_int,
776775
pub st_rdev: __dev_t,
776+
pub __pad1: __dev_t,
777777
pub st_size: __off_t,
778778
pub st_blksize: __blksize_t,
779+
pub __pad2: ::std::os::raw::c_int,
779780
pub st_blocks: __blkcnt_t,
780781
pub st_atim: timespec,
781782
pub st_mtim: timespec,
782783
pub st_ctim: timespec,
783-
pub __glibc_reserved: [__syscall_slong_t; 3usize],
784+
pub __glibc_reserved: [::std::os::raw::c_int; 2usize],
784785
}
785786
pub type zend_stream_fsizer_t =
786787
::std::option::Option<unsafe extern "C" fn(handle: *mut ::std::os::raw::c_void) -> usize>;
@@ -1420,7 +1421,7 @@ pub struct _zend_execute_data {
14201421
pub run_time_cache: *mut *mut ::std::os::raw::c_void,
14211422
pub extra_named_params: *mut zend_array,
14221423
}
1423-
pub type __jmp_buf = [::std::os::raw::c_long; 8usize];
1424+
pub type __jmp_buf = [::std::os::raw::c_ulonglong; 22usize];
14241425
#[repr(C)]
14251426
#[derive(Debug, Copy, Clone)]
14261427
pub struct __jmp_buf_tag {
@@ -2732,3 +2733,42 @@ pub struct _sapi_post_entry {
27322733
),
27332734
>,
27342735
}
2736+
#[doc = " A class which helps with constructing INI entries from the command\n line."]
2737+
#[repr(C)]
2738+
#[derive(Debug, Copy, Clone)]
2739+
pub struct php_ini_builder {
2740+
pub value: *mut ::std::os::raw::c_char,
2741+
pub length: usize,
2742+
}
2743+
extern "C" {
2744+
#[doc = " Prepend a string.\n\n @param src the source string\n @param length the size of the source string"]
2745+
pub fn php_ini_builder_prepend(
2746+
b: *mut php_ini_builder,
2747+
src: *const ::std::os::raw::c_char,
2748+
length: usize,
2749+
);
2750+
}
2751+
extern "C" {
2752+
#[doc = " Append an unquoted name/value pair."]
2753+
pub fn php_ini_builder_unquoted(
2754+
b: *mut php_ini_builder,
2755+
name: *const ::std::os::raw::c_char,
2756+
name_length: usize,
2757+
value: *const ::std::os::raw::c_char,
2758+
value_length: usize,
2759+
);
2760+
}
2761+
extern "C" {
2762+
#[doc = " Append a quoted name/value pair."]
2763+
pub fn php_ini_builder_quoted(
2764+
b: *mut php_ini_builder,
2765+
name: *const ::std::os::raw::c_char,
2766+
name_length: usize,
2767+
value: *const ::std::os::raw::c_char,
2768+
value_length: usize,
2769+
);
2770+
}
2771+
extern "C" {
2772+
#[doc = " Parse an INI entry from the command-line option \"--define\"."]
2773+
pub fn php_ini_builder_define(b: *mut php_ini_builder, arg: *const ::std::os::raw::c_char);
2774+
}

guide/src/ini-builder.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# INI Builder
2+
3+
When configuring a SAPI you may use `IniBuilder` to load INI settings as text.
4+
This is useful for setting up configurations required by the SAPI capabilities.
5+
6+
INI settings applied to a SAPI through `sapi.ini_entries` will be immutable,
7+
meaning they cannot be changed at runtime. This is useful for applying settings
8+
to match hard requirements of the way your SAPI works.
9+
10+
To apply _configurable_ defaults it is recommended to use a `sapi.ini_defaults`
11+
callback instead, which will allow settings to be changed at runtime.
12+
13+
```rust,no_run
14+
use ext_php_rs::builder::{IniBuilder, SapiBuilder};
15+
16+
# fn main() {
17+
// Create a new IniBuilder instance.
18+
let mut builder = IniBuilder::new();
19+
20+
// Append a single key/value pair to the INIT buffer with an unquoted value.
21+
builder.unquoted("log_errors", "1");
22+
23+
// Append a single key/value pair to the INI buffer with a quoted value.
24+
builder.quoted("default_mimetype", "text/html");
25+
26+
// Append INI line text as-is. A line break will be automatically appended.
27+
builder.define("memory_limit=128MB");
28+
29+
// Prepend INI line text as-is. No line break insertion will occur.
30+
builder.prepend("error_reporting=0\ndisplay_errors=1\n");
31+
32+
// Construct a SAPI.
33+
let mut sapi = SapiBuilder::new("name", "pretty_name").build()
34+
.expect("should build SAPI");
35+
36+
// Dump INI entries from the builder into the SAPI.
37+
sapi.ini_entries = builder.finish();
38+
# }
39+
# main();
40+
```

0 commit comments

Comments
 (0)