Skip to content

Commit ac03a9a

Browse files
committed
Add ini_bytes to translate ini directive byte shorthand to a count
With WordPress we have seen a variety of bugs that stem from the fact that we don't reliably parse the memory size values from php.ini directives. We want to know those values in order to communicate to site users what the file upload limits are. In this patch I'm adding a new function `ini_bytes( $shorthand )` to return whatever PHP evaluates that value to be internally, thus exposing the actual byte size to the outside world. This eliminates the need for WordPress and other projects to port the config value parser since they could directly call it. Additionally it will reliably reproduce any quirks due to the platform build and overflow behaviors when handling the `g`, `m`, and `k` suffixes on `post_max_size` and `upload_max_filesize` (and others). This function is a shallow wrapper around `zend_atoi()` and could become out of sync with the actual ini directive parsing. I considered a variation of this function which would take a directive's name and return the stored internal value directly, keeping it in sync. ```php switch ( param_name ) { case 'post_max_size': RETVAL_LONG(SG(post_max_size)); } ``` After looking briefly at this option I dismissed it for being a bit too coupled to those options, too demanding to add all the possible config options to a big switch statement, and too complicated for returning all of the possible return types stored in the SAPI globals. This is my first attempt at patching PHP and I don't know what I'm doing :) I'm not thrilled at the function name but I needed something. I'm not aware of what I need to write for testing, documentation, etc... but I'm happy to add whatever is required. The expecation is to use it in situations roughly like this: ```php function max_upload_size() { $u_bytes = ini_bytes( ini_get( 'upload_max_filesize' ) || 0 ); $p_bytes = ini_bytes( ini_get( 'post_max_size' ) || 0 ); return min( $u_bytes, $p_bytes ); } ``` This patch also makes it easier to perform mathematic comparisons and operations on the config values, which again previously required duplicating the parsing outside of PHP and likely will fail for a variety of config values. ```php function validate_upload_size() { $u_bytes = ini_bytes( ini_get( 'upload_max_filesize' ) || 0 ); $p_bytes = ini_bytes( ini_get( 'post_max_size' ) || 0 ); return $u_bytes <= $p_bytes ? [ true ] : [ false, 'upload_max_filesize must be smaller than post_max_size' ]; } ```
1 parent 84c160d commit ac03a9a

File tree

3 files changed

+22
-0
lines changed

3 files changed

+22
-0
lines changed

ext/standard/basic_functions.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,20 @@ PHP_FUNCTION(highlight_string)
19711971
}
19721972
/* }}} */
19731973

1974+
/* {{{ Get a byte size from the ini byte size shorthand */
1975+
PHP_FUNCTION(ini_bytes)
1976+
{
1977+
char *shorthand;
1978+
size_t shorthand_len;
1979+
1980+
ZEND_PARSE_PARAMETERS_START(1, 1)
1981+
Z_PARAM_STRING(shorthand, shorthand_len)
1982+
ZEND_PARSE_PARAMETERS_END();
1983+
1984+
RETVAL_LONG(zend_atol(shorthand, shorthand_len));
1985+
}
1986+
/* }}} */
1987+
19741988
/* {{{ Get a configuration option */
19751989
PHP_FUNCTION(ini_get)
19761990
{

ext/standard/basic_functions.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@ function ini_alter(string $option, string|int|float|bool|null $value): string|fa
488488

489489
function ini_restore(string $option): void {}
490490

491+
function ini_bytes(string $option): int {}
492+
491493
/** @refcount 1 */
492494
function set_include_path(string $include_path): string|false {}
493495

ext/standard/basic_functions_arginfo.h

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)