From 1c94aac89e0d7dfbd5efc15ec1862214b22603d1 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Sun, 21 Apr 2019 15:33:20 +0200 Subject: [ci skip] Fix CS in Markdown files Checked and quickfixed with Markdown linter - 80 columns line width (~) - code highlighting - ... Some most obvious outdated content updated a bit more. --- docs/input-filter.md | 43 ++--- docs/mailinglist-rules.md | 11 +- docs/output-api.md | 265 +++++++++++++-------------- docs/parameter-parsing-api.md | 210 ++++++++++----------- docs/self-contained-extensions.md | 212 +++++++++++----------- docs/streams.md | 373 ++++++++++++++++++++------------------ docs/unix-build-system.md | 166 +++++++++-------- 7 files changed, 658 insertions(+), 622 deletions(-) (limited to 'docs') diff --git a/docs/input-filter.md b/docs/input-filter.md index c5307a2155..29de4380fd 100644 --- a/docs/input-filter.md +++ b/docs/input-filter.md @@ -1,26 +1,23 @@ -# Input Filter Support in PHP 5 - -XSS (Cross Site Scripting) hacks are becoming more and more prevalent, -and can be quite difficult to prevent. Whenever you accept user data -and somehow display this data back to users, you are likely vulnerable -to XSS hacks. - -The Input Filter support in PHP 5 is aimed at providing the framework -through which a company-wide or site-wide security policy can be -enforced. It is implemented as a SAPI hook and is called from the -treat_data and post handler functions. To implement your own security -policy you will need to write a standard PHP extension. There is also -a powerful standard implementation in ext/filter that should suit most -peoples' needs. However, if you want to implement your own security -policy, read on. - -A simple implementation might look like the following. This stores the -original raw user data and adds a my_get_raw() function while the normal -$_POST, $_GET and $_COOKIE arrays are only populated with stripped -data. In this simple example all I am doing is calling strip_tags() on -the data. - -``` +# Input filter support in PHP + +XSS (Cross Site Scripting) hacks are becoming more and more prevalent, and can +be quite difficult to prevent. Whenever you accept user data and somehow display +this data back to users, you are likely vulnerable to XSS hacks. + +The Input Filter support in PHP is aimed at providing the framework through +which a company-wide or site-wide security policy can be enforced. It is +implemented as a SAPI hook and is called from the `treat_data` and post handler +functions. To implement your own security policy you will need to write a +standard PHP extension. There is also a powerful standard implementation in +`ext/filter` that should suit most peoples' needs. However, if you want to +implement your own security policy, read on. + +A simple implementation might look like the following. This stores the original +raw user data and adds a `my_get_raw()` function while the normal `$_POST`, +`$_GET` and `$_COOKIE` arrays are only populated with stripped data. In this +simple example all I am doing is calling `strip_tags()` on the data. + +```c ZEND_BEGIN_MODULE_GLOBALS(my_input_filter) zval *post_array; zval *get_array; diff --git a/docs/mailinglist-rules.md b/docs/mailinglist-rules.md index c76dc7862a..8bdf9752d0 100644 --- a/docs/mailinglist-rules.md +++ b/docs/mailinglist-rules.md @@ -1,4 +1,4 @@ -# Mailinglist Rules +# Mailinglist rules This is the first file you should be reading before doing any posts on PHP mailinglists. Following these rules is considered imperative to the success of @@ -19,7 +19,6 @@ following some basic rules with regards to mailinglist usage will: d. Increase the general level of good will on planet Earth. - Having said that, here are the organizational rules: 1. Respect other people working on the project. @@ -28,9 +27,9 @@ Having said that, here are the organizational rules: your post after a good breather or a good nights sleep. 3. Make sure you pick the right mailinglist for your posting. Please review - the descriptions on the mailinglist overview page - (http://www.php.net/mailing-lists.php). When in doubt ask a friend or - someone you trust on IRC. + the descriptions on the + [mailinglist overview page](https://www.php.net/mailing-lists.php). When + in doubt ask a friend or someone you trust on IRC. 4. Make sure you know what you are talking about. PHP is a very large project that strives to be very open. The flip side is that the core developers @@ -70,7 +69,7 @@ The next few rules are more some general hints: new thread. Finally, additional hints on how to behave inside the virtual community can be -found in RFC 1855 (http://www.faqs.org/rfcs/rfc1855.html). +found in [RFC 1855](http://www.faqs.org/rfcs/rfc1855.html). Happy hacking, diff --git a/docs/output-api.md b/docs/output-api.md index 3c23c8e8de..73876c4732 100644 --- a/docs/output-api.md +++ b/docs/output-api.md @@ -1,139 +1,136 @@ -API adjustment to the old output control code: +# API adjustment to the old output control code - Everything now resides beneath the php_output namespace, - and there's an API call for every output handler op. +Everything now resides beneath the php_output namespace, and there's an API call +for every output handler op. - Checking output control layers status: - // Using OG() - php_output_get_status(); + Checking output control layers status: + // Using OG() + php_output_get_status(); - Starting the default output handler: - // php_start_ob_buffer(NULL, 0, 1); - php_output_start_default(); + Starting the default output handler: + // php_start_ob_buffer(NULL, 0, 1); + php_output_start_default(); - Starting an user handler by zval: - // php_start_ob_buffer(zhandler, chunk_size, erase); - php_output_start_user(zhandler, chunk_size, flags); + Starting an user handler by zval: + // php_start_ob_buffer(zhandler, chunk_size, erase); + php_output_start_user(zhandler, chunk_size, flags); - Starting an internal handler without context: - // php_ob_set_internal_handler(my_php_output_handler_func_t, buffer_size, "output handler name", erase); - php_output_start_internal(handler_name, handler_name_len, my_php_output_handler_func_t, chunk_size, flags); - - Starting an internal handler with context: - // not possible with old API - php_output_handler *h; - h = php_output_handler_create_internal(handler_name, handler_name_len, my_php_output_handler_context_func_t, chunk_size, flags); - php_output_handler_set_context(h, my_context, my_context_dtor); - php_output_handler_start(h); - - Testing whether a certain output handler has already been started: - // php_ob_handler_used("output handler name"); - php_output_handler_started(handler_name, handler_name_len); - - Flushing one output buffer: - // php_end_ob_buffer(1, 1); - php_output_flush(); - - Flushing all output buffers: - // not possible with old API - php_output_flush_all(); - - Cleaning one output buffer: - // php_ob_end_buffer(0, 1); - php_output_clean(); - - Cleaning all output buffers: - // not possible with old API - php_output_clean_all(); - - Discarding one output buffer: - // php_ob_end_buffer(0, 0); - php_output_discard(); - - Discarding all output buffers: - // php_ob_end_buffers(0); - php_output_discard_all(); - - Stopping (and dropping) one output buffer: - // php_ob_end_buffer(1, 0) - php_output_end(); - - Stopping (and dropping) all output buffers: - // php_ob_end_buffers(1, 0); - php_output_end_all(); - - Retrieving output buffers contents: - // php_ob_get_buffer(zstring); - php_output_get_contents(zstring); - - Retrieving output buffers length: - // php_ob_get_length(zlength); - php_output_get_length(zlength); - - Retrieving output buffering level: - // OG(nesting_level); - php_output_get_level(); - - Issue a warning because of an output handler conflict: - // php_ob_init_conflict("to be started handler name", "to be tested if already started handler name"); - php_output_handler_conflict(new_handler_name, new_handler_name_len, set_handler_name, set_handler_name_len); - - Registering a conflict checking function, which will be checked prior starting the handler: - // not possible with old API, unless hardcoding into output.c - php_output_handler_conflict_register(handler_name, handler_name_len, my_php_output_handler_conflict_check_t); - - Registering a reverse conflict checking function, which will be checked prior starting the specified foreign handler: - // not possible with old API - php_output_handler_reverse_conflict_register(foreign_handler_name, foreign_handler_name_len, my_php_output_handler_conflict_check_t); - - Facilitating a context from within an output handler callable with ob_start(): - // not possible with old API - php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ, (void *) &custom_ctx_ptr_ptr); - - Disabling of the output handler by itself: - //not possible with old API - php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_DISABLE, NULL); - - Marking an output handler immutable by itself because of irreversibility of its operation: - // not possible with old API - php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL); - - Restarting the output handler because of a CLEAN operation: - // not possible with old API - if (flags & PHP_OUTPUT_HANDLER_CLEAN) { ... } - - Recognizing by the output handler itself if it gets discarded: - // not possible with old API - if ((flags & PHP_OUTPUT_HANDLER_CLEAN) && (flags & PHP_OUTPUT_HANDLER_FINAL)) { ... } - - -Output handler hooks - - The output handler can change its abilities at runtime. Eg. the gz handler can - remove the CLEANABLE and REMOVABLE bits when the first output has passed through it; - or handlers implemented in C to be used with ob_start() can contain a non-global - context: - PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ - pass a void*** pointer as second arg to receive the address of a pointer - pointer to the opaque field of the output handler context - PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS - pass a int* pointer as second arg to receive the flags set for the output handler - PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL - pass a int* pointer as second arg to receive the level of this output handler - (starts with 0) - PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE - the second arg is ignored; marks the output handler to be neither cleanable - nor removable - PHP_OUTPUT_HANDLER_HOOK_DISABLE - the second arg is ignored; marks the output handler as disabled - - -Open questions - - Should the userland API be adjusted and unified? - - Many bits of the manual (and very first implementation) do not comply - with the behaviour of the current (to be obsoleted) code, thus should - the manual or the behaviour be adjusted? - -END + Starting an internal handler without context: + // php_ob_set_internal_handler(my_php_output_handler_func_t, buffer_size, "output handler name", erase); + php_output_start_internal(handler_name, handler_name_len, my_php_output_handler_func_t, chunk_size, flags); + + Starting an internal handler with context: + // not possible with old API + php_output_handler *h; + h = php_output_handler_create_internal(handler_name, handler_name_len, my_php_output_handler_context_func_t, chunk_size, flags); + php_output_handler_set_context(h, my_context, my_context_dtor); + php_output_handler_start(h); + + Testing whether a certain output handler has already been started: + // php_ob_handler_used("output handler name"); + php_output_handler_started(handler_name, handler_name_len); + + Flushing one output buffer: + // php_end_ob_buffer(1, 1); + php_output_flush(); + + Flushing all output buffers: + // not possible with old API + php_output_flush_all(); + + Cleaning one output buffer: + // php_ob_end_buffer(0, 1); + php_output_clean(); + + Cleaning all output buffers: + // not possible with old API + php_output_clean_all(); + + Discarding one output buffer: + // php_ob_end_buffer(0, 0); + php_output_discard(); + + Discarding all output buffers: + // php_ob_end_buffers(0); + php_output_discard_all(); + + Stopping (and dropping) one output buffer: + // php_ob_end_buffer(1, 0) + php_output_end(); + + Stopping (and dropping) all output buffers: + // php_ob_end_buffers(1, 0); + php_output_end_all(); + + Retrieving output buffers contents: + // php_ob_get_buffer(zstring); + php_output_get_contents(zstring); + + Retrieving output buffers length: + // php_ob_get_length(zlength); + php_output_get_length(zlength); + + Retrieving output buffering level: + // OG(nesting_level); + php_output_get_level(); + + Issue a warning because of an output handler conflict: + // php_ob_init_conflict("to be started handler name", "to be tested if already started handler name"); + php_output_handler_conflict(new_handler_name, new_handler_name_len, set_handler_name, set_handler_name_len); + + Registering a conflict checking function, which will be checked prior starting the handler: + // not possible with old API, unless hardcoding into output.c + php_output_handler_conflict_register(handler_name, handler_name_len, my_php_output_handler_conflict_check_t); + + Registering a reverse conflict checking function, which will be checked prior starting the specified foreign handler: + // not possible with old API + php_output_handler_reverse_conflict_register(foreign_handler_name, foreign_handler_name_len, my_php_output_handler_conflict_check_t); + + Facilitating a context from within an output handler callable with ob_start(): + // not possible with old API + php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ, (void *) &custom_ctx_ptr_ptr); + + Disabling of the output handler by itself: + //not possible with old API + php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_DISABLE, NULL); + + Marking an output handler immutable by itself because of irreversibility of its operation: + // not possible with old API + php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL); + + Restarting the output handler because of a CLEAN operation: + // not possible with old API + if (flags & PHP_OUTPUT_HANDLER_CLEAN) { ... } + + Recognizing by the output handler itself if it gets discarded: + // not possible with old API + if ((flags & PHP_OUTPUT_HANDLER_CLEAN) && (flags & PHP_OUTPUT_HANDLER_FINAL)) { ... } + +## Output handler hooks + +The output handler can change its abilities at runtime. Eg. the gz handler can +remove the CLEANABLE and REMOVABLE bits when the first output has passed through it; +or handlers implemented in C to be used with ob_start() can contain a non-global +context: + + PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ + pass a void*** pointer as second arg to receive the address of a pointer + pointer to the opaque field of the output handler context + PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS + pass a int* pointer as second arg to receive the flags set for the output handler + PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL + pass a int* pointer as second arg to receive the level of this output handler + (starts with 0) + PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE + the second arg is ignored; marks the output handler to be neither cleanable + nor removable + PHP_OUTPUT_HANDLER_HOOK_DISABLE + the second arg is ignored; marks the output handler as disabled + +## Open questions + +* Should the userland API be adjusted and unified? + +Many bits of the manual (and very first implementation) do not comply with the +behaviour of the current (to be obsoleted) code, thus should the manual or the +behaviour be adjusted? diff --git a/docs/parameter-parsing-api.md b/docs/parameter-parsing-api.md index f65c19a723..d4d24b1dbf 100644 --- a/docs/parameter-parsing-api.md +++ b/docs/parameter-parsing-api.md @@ -1,133 +1,140 @@ -Fast Parameter Parsing API -========================== +# Fast Parameter Parsing API -In PHP 7, a "Fast Parameter Parsing API" was introduced. See +In PHP 7, a "Fast Parameter Parsing API" was introduced. See +[RFC](https://wiki.php.net/rfc/fast_zpp). - https://wiki.php.net/rfc/fast_zpp +This API uses inlining to improve applications performance compared with the +`zend_parse_parameters()` function described below. -This API uses inlining to improve applications performance compared -with the zend_parse_parameters() function described below. +## Parameter parsing functions +Borrowing from Python's example, there is a set of functions that given the +string of type specifiers, can parse the input parameters and store the results +in the user specified variables. This avoids using `IS_*` checks and +`convert_to_*` conversions. The functions also check for the appropriate number +of parameters, and try to output meaningful error messages. -Parameter parsing functions -=========================== +## Prototypes -Borrowing from Python's example, there is a set of functions that -given the string of type specifiers, can parse the input parameters -and store the results in the user specified variables. This avoids -using IS_* checks and convert_to_* conversions. The functions also -check for the appropriate number of parameters, and try to output -meaningful error messages. - - -Prototypes ----------- +```c /* Implemented. */ int zend_parse_parameters(int num_args, char *type_spec, ...); int zend_parse_parameters_ex(int flags, int num_args, char *type_spec, ...); +``` -The zend_parse_parameters() function takes the number of parameters -passed to the extension function, the type specifier string, and the -list of pointers to variables to store the results in. The _ex() version -also takes 'flags' argument -- current only ZEND_PARSE_PARAMS_QUIET can -be used as 'flags' to specify that the function should operate quietly -and not output any error messages. +The `zend_parse_parameters()` function takes the number of parameters passed to +the extension function, the type specifier string, and the list of pointers to +variables to store the results in. The _ex() version also takes 'flags' argument +-- current only `ZEND_PARSE_PARAMS_QUIET` can be used as 'flags' to specify that +the function should operate quietly and not output any error messages. -Both functions return SUCCESS or FAILURE depending on the result. +Both functions return `SUCCESS` or `FAILURE` depending on the result. -The auto-conversions are performed as necessary. Arrays, objects, and -resources cannot be auto-converted. +The auto-conversions are performed as necessary. Arrays, objects, and resources +cannot be auto-converted. PHP 5.3 includes a new function (actually implemented as macro): +```c int zend_parse_parameters_none(); +``` -This returns SUCCESS if no argument has been passed to the function, -FAILURE otherwise. +This returns `SUCCESS` if no argument has been passed to the function, `FAILURE` +otherwise. PHP 5.5 includes a new function: +```c int zend_parse_parameter(int flags, int arg_num, zval **arg, const char *spec, ...); +``` -This function behaves like zend_parse_parameters_ex() except that instead of +This function behaves like `zend_parse_parameters_ex()` except that instead of reading the arguments from the stack, it receives a single zval to convert (passed with double indirection). The passed zval may be changed in place as part of the conversion process. -See also https://wiki.php.net/rfc/zpp_improv#expose_zend_parse_arg_as_zend_parse_parameter - - -Type specifiers ---------------- - The following list shows the type specifier, its meaning and the parameter - types that need to be passed by address. All passed parameters are set - if the PHP parameter is non optional and untouched if optional and the - parameter is not present. The only exception is O where the zend_class_entry* - has to be provided on input and is used to verify the PHP parameter is an - instance of that class. - - a - array (zval*) - A - array or object (zval*) - b - boolean (zend_bool) - C - class (zend_class_entry*) - d - double (double) - f - function or array containing php method call info (returned as - zend_fcall_info and zend_fcall_info_cache) - h - array (returned as HashTable*) - H - array or HASH_OF(object) (returned as HashTable*) - l - long (zend_long) - L - long, limits out-of-range numbers to LONG_MAX/LONG_MIN (zend_long, ZEND_LONG_MAX/ZEND_LONG_MIN) - o - object of any type (zval*) - O - object of specific type given by class entry (zval*, zend_class_entry) - p - valid path (string without null bytes in the middle) and its length (char*, size_t) - P - valid path (string without null bytes in the middle) as zend_string (zend_string*) - r - resource (zval*) - s - string (with possible null bytes) and its length (char*, size_t) - S - string (with possible null bytes) as zend_string (zend_string*) - z - the actual zval (zval*) - * - variable arguments list (0 or more) - + - variable arguments list (1 or more) - - The following characters also have a meaning in the specifier string: - | - indicates that the remaining parameters are optional, they - should be initialized to default values by the extension since they - will not be touched by the parsing function if they are not - passed to it. - / - use SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows - ! - the parameter it follows can be of specified type or NULL. If NULL is - passed and the output for such type is a pointer, then the output - pointer is set to a native NULL pointer. - For 'b', 'l' and 'd', an extra argument of type zend_bool* must be - passed after the corresponding bool*, zend_long* or double* arguments, - respectively. A non-zero value will be written to the zend_bool if a - PHP NULL is passed. - - -Note on 64bit compatibility ---------------------------- -Please note that since version 7 PHP uses zend_long as integer type and -zend_string with size_t as length, so make sure you pass zend_longs to "l" -and size_t to strings length (i.e. for "s" you need to pass char * and size_t), -not the other way round! +See also +[Expose zend_parse_arg() as zend_parse_parameter()](https://wiki.php.net/rfc/zpp_improv#expose_zend_parse_arg_as_zend_parse_parameter). + +## Type specifiers + +The following list shows the type specifier, its meaning and the parameter types +that need to be passed by address. All passed parameters are set if the PHP +parameter is non optional and untouched if optional and the parameter is not +present. The only exception is O where the zend_class_entry* has to be provided +on input and is used to verify the PHP parameter is an instance of that class. + +```txt +a - array (zval*) +A - array or object (zval*) +b - boolean (zend_bool) +C - class (zend_class_entry*) +d - double (double) +f - function or array containing php method call info (returned as + zend_fcall_info and zend_fcall_info_cache) +h - array (returned as HashTable*) +H - array or HASH_OF(object) (returned as HashTable*) +l - long (zend_long) +L - long, limits out-of-range numbers to LONG_MAX/LONG_MIN (zend_long, ZEND_LONG_MAX/ZEND_LONG_MIN) +o - object of any type (zval*) +O - object of specific type given by class entry (zval*, zend_class_entry) +p - valid path (string without null bytes in the middle) and its length (char*, size_t) +P - valid path (string without null bytes in the middle) as zend_string (zend_string*) +r - resource (zval*) +s - string (with possible null bytes) and its length (char*, size_t) +S - string (with possible null bytes) as zend_string (zend_string*) +z - the actual zval (zval*) +* - variable arguments list (0 or more) ++ - variable arguments list (1 or more) +``` + +The following characters also have a meaning in the specifier string: + +* `|` - indicates that the remaining parameters are optional, they should be + initialized to default values by the extension since they will not be touched + by the parsing function if they are not passed to it. +* `/` - use SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows +* `!` - the parameter it follows can be of specified type or NULL. If NULL is + passed and the output for such type is a pointer, then the output pointer is + set to a native NULL pointer. For 'b', 'l' and 'd', an extra argument of type + zend_bool* must be passed after the corresponding bool*, zend_long* or + double* arguments, respectively. A non-zero value will be written to the + zend_bool if a PHP NULL is passed. + +## Note on 64bit compatibility + +Please note that since version 7 PHP uses `zend_long` as integer type and +`zend_string` with `size_t` as length, so make sure you pass `zend_long`s to "l" +and `size_t` to strings length (i.e. for "s" you need to pass char `*` and +`size_t`), not the other way round! Both mistakes might cause memory corruptions and segfaults: -1) - char *str; - long str_len; /* XXX THIS IS WRONG!! Use size_t instead. */ - zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len) -2) - int num; /* XXX THIS IS WRONG!! Use zend_long instead. */ - zend_parse_parameters(ZEND_NUM_ARGS(), "l", &num) +* 1 + +```c +char *str; +long str_len; /* XXX THIS IS WRONG!! Use size_t instead. */ +zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len) +``` + +* 2 + +```c +int num; /* XXX THIS IS WRONG!! Use zend_long instead. */ +zend_parse_parameters(ZEND_NUM_ARGS(), "l", &num) +``` -If you're in doubt, use check_parameters.php script to the parameters -and their types (it can be found in ./scripts/dev/ directory of PHP sources): +If you're in doubt, use check_parameters.php script to the parameters and their +types (it can be found in `./scripts/dev/` directory of PHP sources): -# php ./scripts/dev/check_parameters.php /path/to/your/sources/ +```bash +php ./scripts/dev/check_parameters.php /path/to/your/sources/ +``` +## Examples -Examples --------- +```c /* Gets a long, a string and its length, and a zval */ zend_long l; char *s; @@ -138,7 +145,6 @@ if (zend_parse_parameters(ZEND_NUM_ARGS(), "lsz", return; } - /* Gets an object of class specified by my_ce, and an optional double. */ zval *obj; double d = 0.5; @@ -148,7 +154,6 @@ if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|d", return; } - /* Gets an object or null, and an array. If null is passed for object, obj will be set to NULL. */ zval *obj; @@ -158,7 +163,6 @@ if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!a", return; } - /* Gets a separated array which can also be null. */ zval *arr; if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/!", @@ -171,7 +175,7 @@ zend_long l1, l2, l3; char *s; /* * The function expects a pointer to a size_t in this case, not a long - * or any other type. If you specify a type which is larger + * or any other type. If you specify a type which is larger * than a 'size_t', the upper bits might not be initialized * properly, leading to random crashes on platforms like * Tru64 or Linux/Alpha. @@ -190,13 +194,11 @@ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), return; } - /* Function that accepts only varargs (0 or more) */ int i, num_varargs; zval *varargs = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &varargs, &num_varargs) == FAILURE) { return; } @@ -209,7 +211,6 @@ if (varargs) { efree(varargs); } - /* Function that accepts a string, followed by varargs (1 or more) */ char *str; @@ -243,3 +244,4 @@ for (i = 0; i < num_varargs; i++) { if (zend_parse_parameters_none() == FAILURE) { return; } +``` diff --git a/docs/self-contained-extensions.md b/docs/self-contained-extensions.md index 84d6aaa685..47f4c636ba 100644 --- a/docs/self-contained-extensions.md +++ b/docs/self-contained-extensions.md @@ -1,84 +1,83 @@ -# HOW TO CREATE A SELF-CONTAINED PHP EXTENSION +# How to create a self-contained PHP extension - A self-contained extension can be distributed independently of - the PHP source. To create such an extension, two things are - required: +A self-contained extension can be distributed independently of the PHP source. +To create such an extension, two things are required: - - Configuration file (config.m4) - - Source code for your module +* Configuration file (config.m4) +* Source code for your module - We will describe now how to create these and how to put things - together. +We will describe now how to create these and how to put things together. -## PREPARING YOUR SYSTEM +## Prepairing your system - While the result will run on any system, a developer's setup needs these - tools: +While the result will run on any system, a developer's setup needs these tools: - GNU autoconf - GNU libtool - GNU m4 +* GNU autoconf +* GNU libtool +* GNU m4 - All of these are available from +All of these are available from ftp://ftp.gnu.org/pub/gnu/ -## CONVERTING AN EXISTING EXTENSION +## Converting an existing extension - Just to show you how easy it is to create a self-contained - extension, we will convert an embedded extension into a - self-contained one. Install PHP and execute the following - commands. +Just to show you how easy it is to create a self-contained extension, we will +convert an embedded extension into a self-contained one. Install PHP and execute +the following commands. - $ mkdir /tmp/newext - $ cd /tmp/newext - - You now have an empty directory. We will copy the files from - the mysql extension: - - $ cp -rp php-4.0.X/ext/mysql/* . +```bash +mkdir /tmp/newext +cd /tmp/newext +``` - It is time to finish the module. Run: +You now have an empty directory. We will copy the files from the mysqli +extension: - $ phpize +```bash +cp -rp php-src/ext/mysqli/* . +``` - You can now ship the contents of the directory - the extension - can live completely on its own. +It is time to finish the module. Run: - The user instructions boil down to +```bash +phpize +``` - $ ./configure \ - [--with-php-config=/path/to/php-config] \ - [--with-mysql=MYSQL-DIR] - $ make install +You can now ship the contents of the directory - the extension can live +completely on its own. - The MySQL module will either use the embedded MySQL client - library or the MySQL installation in MYSQL-DIR. +The user instructions boil down to +```bash +./configure \ + [--with-php-config=/path/to/php-config] \ + [--with-mysqli=MYSQL-DIR] +make install +``` -## DEFINING THE NEW EXTENSION +The MySQL module will either use the embedded MySQL client library or the MySQL +installation in MYSQL-DIR. - Our demo extension is called "foobar". +## Defining the new extension - It consists of two source files "foo.c" and "bar.c" - (and any arbitrary amount of header files, but that is not - important here). +Our demo extension is called "foobar". - The demo extension does not reference any external - libraries (that is important, because the user does not - need to specify anything). +It consists of two source files `foo.c` and `bar.c` (and any arbitrary amount of +header files, but that is not important here). +The demo extension does not reference any external libraries (that is important, +because the user does not need to specify anything). - LTLIBRARY_SOURCES specifies the names of the sources files. You can - name an arbitrary number of source files here. +`LTLIBRARY_SOURCES` specifies the names of the sources files. You can name an +arbitrary number of source files here. -## CREATING THE M4 CONFIGURATION FILE +## Creating the M4 configuration file - The m4 configuration can perform additional checks. For a - self-contained extension, you do not need more than a few - macro calls. +The m4 configuration can perform additional checks. For a self-contained +extension, you do not need more than a few macro calls. -``` +```m4 PHP_ARG_ENABLE([foobar], [whether to enable foobar], [AS_HELP_STRING([--enable-foobar], @@ -89,81 +88,86 @@ if test "$PHP_FOOBAR" != "no"; then fi ``` - PHP_ARG_ENABLE will automatically set the correct variables, so - that the extension will be enabled by PHP_NEW_EXTENSION in shared mode. - - The first argument of PHP_NEW_EXTENSION describes the name of the - extension. The second names the source-code files. The third passes - $ext_shared which is set by PHP_ARG_ENABLE/WITH to PHP_NEW_EXTENSION. +`PHP_ARG_ENABLE` will automatically set the correct variables, so that the +extension will be enabled by `PHP_NEW_EXTENSION` in shared mode. - Please use always PHP_ARG_ENABLE or PHP_ARG_WITH. Even if you do not - plan to distribute your module with PHP, these facilities allow you - to integrate your module easily into the main PHP module framework. +The first argument of `PHP_NEW_EXTENSION` describes the name of the extension. +The second names the source-code files. The third passes `$ext_shared` which is +set by `PHP_ARG_ENABLE/WITH` to `PHP_NEW_EXTENSION`. -## CREATING SOURCE FILES +Please use always `PHP_ARG_ENABLE` or `PHP_ARG_WITH`. Even if you do not plan to +distribute your module with PHP, these facilities allow you to integrate your +module easily into the main PHP module framework. - ext_skel can be of great help when creating the common code for all modules - in PHP for you and also writing basic function definitions and C code for - handling arguments passed to your functions. See `./ext/ext_skel.php --help` - for further information. +## Create source files - As for the rest, you are currently alone here. There are a lot of existing - modules, use a simple module as a starting point and add your own code. +`ext_skel.php` can be of great help when creating the common code for all +modules in PHP for you and also writing basic function definitions and C code +for handling arguments passed to your functions. See `./ext/ext_skel.php --help` +for further information. +As for the rest, you are currently alone here. There are a lot of existing +modules, use a simple module as a starting point and add your own code. -## CREATING THE SELF-CONTAINED EXTENSION +## Creating the self-contained extension - Put config.m4 and the source files into one directory. Then, run phpize - (this is installed during make install by PHP 4.0). +Put `config.m4` and the source files into one directory. Then, run `phpize` +(this is installed during `make install` by PHP). - For example, if you configured PHP with --prefix=/php, you would run +For example, if you configured PHP with `--prefix=/php`, you would run - $ /php/bin/phpize +```bash +/php/bin/phpize +``` - This will automatically copy the necessary build files and create - configure from your config.m4. +This will automatically copy the necessary build files and create configure from +your `config.m4`. - And that's it. You now have a self-contained extension. +And that's it. You now have a self-contained extension. -## INSTALLING A SELF-CONTAINED EXTENSION +## Installing a self-contained extension - An extension can be installed by running: +An extension can be installed by running: - $ ./configure \ - [--with-php-config=/path/to/php-config] - $ make install +```bash +./configure \ + [--with-php-config=/path/to/php-config] +make install +``` -## ADDING SHARED MODULE SUPPORT TO A MODULE +## Adding shared module support to a module - In order to be useful, a self-contained extension must be loadable - as a shared module. I will explain now how you can add shared module - support to an existing module called foo. +In order to be useful, a self-contained extension must be loadable as a shared +module. The following will explain now how you can add shared module support to +an existing module called `foo`. - 1. In config.m4, use PHP_ARG_WITH/PHP_ARG_ENABLE. Then you will - automatically be able to use --with-foo=shared[,..] or - --enable-foo=shared[,..]. +1. In `config.m4`, use `PHP_ARG_WITH/PHP_ARG_ENABLE`. Then you will + automatically be able to use `--with-foo=shared[,..]` or + `--enable-foo=shared[,..]`. - 2. In config.m4, use PHP_NEW_EXTENSION(foo,.., $ext_shared) to enable - building the extension. +2. In `config.m4`, use `PHP_NEW_EXTENSION(foo,.., $ext_shared)` to enable + building the extension. - 3. Add the following lines to your C source file: +3. Add the following lines to your C source file: -``` - #ifdef COMPILE_DL_FOO - ZEND_GET_MODULE(foo) - #endif +```c +#ifdef COMPILE_DL_FOO + ZEND_GET_MODULE(foo) +#endif ``` -## PECL SITE CONFORMITY +## PECL site conformity - If you plan to release an extension to the PECL website, there are several - points to be regarded. +If you plan to release an extension to the PECL website, there are several +points to be regarded. - 1. Add LICENSE or COPYING to the package.xml +1. Add `LICENSE` or `COPYING` to the `package.xml` - 2. The following should be defined in one of the extension header files +2. The following should be defined in one of the extension header files - #define PHP_FOO_VERSION "1.2.3" +```c +#define PHP_FOO_VERSION "1.2.3" +``` - This macros has to be used within your foo_module_entry to indicate the - extension version. +This macros has to be used within your foo_module_entry to indicate the +extension version. diff --git a/docs/streams.md b/docs/streams.md index 6ef69c733a..0ec3846d68 100644 --- a/docs/streams.md +++ b/docs/streams.md @@ -1,29 +1,26 @@ -An Overview of the PHP Streams abstraction -========================================== +# An overview of the PHP streams abstraction WARNING: some prototypes in this file are out of date. -The information contained here is being integrated into -the PHP manual - stay tuned... -Please send comments to: Wez Furlong +## Why streams? -Why Streams? -============ You may have noticed a shed-load of issock parameters flying around the PHP -code; we don't want them - they are ugly and cumbersome and force you to -special case sockets and files every time you need to work with a "user-level" -PHP file pointer. +code; we don't want them - they are ugly and cumbersome and force you to special +case sockets and files every time you need to work with a "user-level" PHP file +pointer. + Streams take care of that and present the PHP extension coder with an ANSI stdio-alike API that looks much nicer and can be extended to support non file based data sources. -Using Streams -============= -Streams use a php_stream* parameter just as ANSI stdio (fread etc.) use a -FILE* parameter. +## Using streams + +Streams use a `php_stream*` parameter just as ANSI stdio (fread etc.) use a +`FILE*` parameter. The main functions are: +```c PHPAPI size_t php_stream_read(php_stream * stream, char * buf, size_t count); PHPAPI size_t php_stream_write(php_stream * stream, const char * buf, size_t count); @@ -37,210 +34,234 @@ PHPAPI int php_stream_flush(php_stream * stream); PHPAPI int php_stream_seek(php_stream * stream, off_t offset, int whence); PHPAPI off_t php_stream_tell(php_stream * stream); PHPAPI int php_stream_lock(php_stream * stream, int mode); +``` These (should) behave in the same way as the ANSI stdio functions with similar -names: fread, fwrite, fprintf, feof, fgetc, fgets, fclose, fflush, fseek, ftell, flock. +names: fread, fwrite, fprintf, feof, fgetc, fgets, fclose, fflush, fseek, ftell, +flock. + +## Opening streams -Opening Streams -=============== In most cases, you should use this API: +```c PHPAPI php_stream *php_stream_open_wrapper(const char *path, const char *mode, int options, char **opened_path); +``` Where: - path is the file or resource to open. - mode is the stdio compatible mode eg: "wb", "rb" etc. - options is a combination of the following values: - IGNORE_PATH (default) - don't use include path to search for the file - USE_PATH - use include path to search for the file - IGNORE_URL - do not use plugin wrappers - REPORT_ERRORS - show errors in a standard format if something - goes wrong. - STREAM_MUST_SEEK - If you really need to be able to seek the stream - and don't need to be able to write to the original - file/URL, use this option to arrange for the stream - to be copied (if needed) into a stream that can - be seek()ed. - - opened_path is used to return the path of the actual file opened, - but if you used STREAM_MUST_SEEK, may not be valid. You are - responsible for efree()ing opened_path. opened_path may be (and usually - is) NULL. + +* `path` is the file or resource to open. +* `mode` is the stdio compatible mode eg: "wb", "rb" etc. +* `options` is a combination of the following values: + * `IGNORE_PATH` (default) - don't use include path to search for the file + * `USE_PATH` - use include path to search for the file + * `IGNORE_URL` - do not use plugin wrappers + * `REPORT_ERRORS` - show errors in a standard format if something goes wrong. + * `STREAM_MUST_SEEK` - If you really need to be able to seek the stream and + don't need to be able to write to the original file/URL, use this option to + arrange for the stream to be copied (if needed) into a stream that can be + seek()ed. +* `opened_path` is used to return the path of the actual file opened, but if you + used `STREAM_MUST_SEEK`, may not be valid. You are responsible for + `efree()ing` `opened_path`. +* `opened_path` may be (and usually is) `NULL`. If you need to open a specific stream, or convert standard resources into -streams there are a range of functions to do this defined in php_streams.h. -A brief list of the most commonly used functions: +streams there are a range of functions to do this defined in `php_streams.h`. A +brief list of the most commonly used functions: +```c PHPAPI php_stream *php_stream_fopen_from_file(FILE *file, const char *mode); - Convert a FILE * into a stream. + /* Convert a FILE * into a stream. */ PHPAPI php_stream *php_stream_fopen_tmpfile(void); - Open a FILE * with tmpfile() and convert into a stream. + /* Open a FILE * with tmpfile() and convert into a stream. */ PHPAPI php_stream *php_stream_fopen_temporary_file(const char *dir, const char *pfx, char **opened_path); - Generate a temporary file name and open it. + /* Generate a temporary file name and open it. */ +``` -There are some network enabled relatives in php_network.h: +There are some network enabled relatives in `php_network.h`: +```c PHPAPI php_stream *php_stream_sock_open_from_socket(int socket, int persistent); - Convert a socket into a stream. + /* Convert a socket into a stream. */ PHPAPI php_stream *php_stream_sock_open_host(const char *host, unsigned short port, - int socktype, int timeout, int persistent); - Open a connection to a host and return a stream. + int socktype, int timeout, int persistent); + /* Open a connection to a host and return a stream. */ PHPAPI php_stream *php_stream_sock_open_unix(const char *path, int persistent, struct timeval *timeout); - Open a UNIX domain socket. - + /* Open a UNIX domain socket. */ +``` -Stream Utilities -================ +## Stream utilities -If you need to copy some data from one stream to another, you will be please -to know that the streams API provides a standard way to do this: +If you need to copy some data from one stream to another, you will be please to +know that the streams API provides a standard way to do this: +```c PHPAPI size_t php_stream_copy_to_stream(php_stream *src, php_stream *dest, size_t maxlen); +``` If you want to copy all remaining data from the src stream, pass -PHP_STREAM_COPY_ALL as the maxlen parameter, otherwise maxlen indicates the -number of bytes to copy. -This function will try to use mmap where available to make the copying more -efficient. +`PHP_STREAM_COPY_ALL` as the maxlen parameter, otherwise maxlen indicates the +number of bytes to copy. This function will try to use mmap where available to +make the copying more efficient. If you want to read the contents of a stream into an allocated memory buffer, you should use: +```c PHPAPI size_t php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen, int persistent); +``` -This function will set buf to the address of the buffer that it allocated, -which will be maxlen bytes in length, or will be the entire length of the -data remaining on the stream if you set maxlen to PHP_STREAM_COPY_ALL. -The buffer is allocated using pemalloc(); you need to call pefree() to -release the memory when you are done. -As with copy_to_stream, this function will try use mmap where it can. +This function will set buf to the address of the buffer that it allocated, which +will be maxlen bytes in length, or will be the entire length of the data +remaining on the stream if you set maxlen to `PHP_STREAM_COPY_ALL`. The buffer +is allocated using `pemalloc()`. You need to call `pefree()` to release the +memory when you are done. As with `copy_to_stream`, this function will try use +mmap where it can. -If you have an existing stream and need to be able to seek() it, you -can use this function to copy the contents into a new stream that can -be seek()ed: +If you have an existing stream and need to be able to `seek()` it, you can use +this function to copy the contents into a new stream that can be `seek()ed`: +```c PHPAPI int php_stream_make_seekable(php_stream *origstream, php_stream **newstream); +``` It returns one of the following values: -#define PHP_STREAM_UNCHANGED 0 /* orig stream was seekable anyway */ -#define PHP_STREAM_RELEASED 1 /* newstream should be used; origstream is no longer valid */ -#define PHP_STREAM_FAILED 2 /* an error occurred while attempting conversion */ -#define PHP_STREAM_CRITICAL 3 /* an error occurred; origstream is in an unknown state; you should close origstream */ -make_seekable will always set newstream to be the stream that is valid -if the function succeeds. -When you have finished, remember to close the stream. +```c +#define PHP_STREAM_UNCHANGED 0 /* orig stream was seekable anyway */ +#define PHP_STREAM_RELEASED 1 /* newstream should be used; origstream is no longer valid */ +#define PHP_STREAM_FAILED 2 /* an error occurred while attempting conversion */ +#define PHP_STREAM_CRITICAL 3 /* an error occurred; origstream is in an unknown state; you should close origstream */ +``` + +`make_seekable` will always set newstream to be the stream that is valid if the +function succeeds. When you have finished, remember to close the stream. -NOTE: If you only need to seek forward, there is no need to call this -function, as the php_stream_seek can emulate forward seeking when the -whence parameter is SEEK_CUR. +NOTE: If you only need to seek forward, there is no need to call this function, +as the `php_stream_seek` can emulate forward seeking when the whence parameter +is `SEEK_CUR`. -NOTE: Writing to the stream may not affect the original source, so it -only makes sense to use this for read-only use. +NOTE: Writing to the stream may not affect the original source, so it only makes +sense to use this for read-only use. -NOTE: If the origstream is network based, this function will block -until the whole contents have been downloaded. +NOTE: If the origstream is network based, this function will block until the +whole contents have been downloaded. -NOTE: Never call this function with an origstream that is referenced -as a resource! It will close the origstream on success, and this -can lead to a crash when the resource is later used/released. +NOTE: Never call this function with an origstream that is referenced as a +resource! It will close the origstream on success, and this can lead to a crash +when the resource is later used/released. NOTE: If you are opening a stream and need it to be seekable, use the -STREAM_MUST_SEEK option to php_stream_open_wrapper(); +`STREAM_MUST_SEEK` option to php_stream_open_wrapper(); +```c PHPAPI int php_stream_supports_lock(php_stream * stream); +``` -This function will return either 1 (success) or 0 (failure) indicating whether or -not a lock can be set on this stream. Typically you can only set locks on stdio streams. +This function will return either 1 (success) or 0 (failure) indicating whether +or not a lock can be set on this stream. Typically you can only set locks on +stdio streams. -Casting Streams -=============== -What if your extension needs to access the FILE* of a user level file pointer? -You need to "cast" the stream into a FILE*, and this is how you do it: +## Casting streams +What if your extension needs to access the `FILE*` of a user level file pointer? +You need to "cast" the stream into a `FILE*`, and this is how you do it: + +```c FILE * fp; php_stream * stream; /* already opened */ if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void*)&fp, REPORT_ERRORS) == FAILURE) { RETURN_FALSE; } +``` The prototype is: -PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int - show_err); +```c +PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int show_err); +``` + +The `show_err` parameter, if non-zero, will cause the function to display an +appropriate error message of type `E_WARNING` if the cast fails. -The show_err parameter, if non-zero, will cause the function to display an -appropriate error message of type E_WARNING if the cast fails. +`castas` can be one of the following values: -castas can be one of the following values: +```txt PHP_STREAM_AS_STDIO - a stdio FILE* PHP_STREAM_AS_FD - a generic file descriptor PHP_STREAM_AS_SOCKETD - a socket descriptor +``` -If you ask a socket stream for a FILE*, the abstraction will use fdopen to -create it for you. Be warned that doing so may cause buffered data to be lost +If you ask a socket stream for a `FILE*`, the abstraction will use fdopen to +create it for you. Be warned that doing so may cause buffered data to be lost if you mix ANSI stdio calls on the FILE* with php stream calls on the stream. If your system has the fopencookie function, php streams can synthesize a -FILE* on top of any stream, which is useful for SSL sockets, memory based +`FILE*` on top of any stream, which is useful for SSL sockets, memory based streams, data base streams etc. etc. -In situations where this is not desirable, you should query the stream -to see if it naturally supports FILE *. You can use this code snippet -for this purpose: +In situations where this is not desirable, you should query the stream to see if +it naturally supports `FILE *`. You can use this code snippet for this purpose: - if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) { - /* can safely cast to FILE* with no adverse side effects */ - } +```c +if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) { + /* can safely cast to FILE* with no adverse side effects */ +} +``` You can use: +```c PHPAPI int php_stream_can_cast(php_stream * stream, int castas) +``` -to find out if a stream can be cast, without actually performing the cast, so -to check if a stream is a socket you might use: +to find out if a stream can be cast, without actually performing the cast, so to +check if a stream is a socket you might use: +```c if (php_stream_can_cast(stream, PHP_STREAM_AS_SOCKETD) == SUCCESS) { /* it can be a socket */ } +``` -Please note the difference between php_stream_is and php_stream_can_cast; -stream_is tells you if the stream is a particular type of stream, whereas -can_cast tells you if the stream can be forced into the form you request. -The former doesn't change anything, while the later *might* change some -state in the stream. +Please note the difference between `php_stream_is` and `php_stream_can_cast`; +`stream_is` tells you if the stream is a particular type of stream, whereas +`can_cast` tells you if the stream can be forced into the form you request. The +former doesn't change anything, while the later *might* change some state in the +stream. -Stream Internals -================ +## Stream internals -There are two main structures associated with a stream - the php_stream +There are two main structures associated with a stream - the `php_stream` itself, which holds some state information (and possibly a buffer) and a -php_stream_ops structure, which holds the "virtual method table" for the +`php_stream_ops` structure, which holds the "virtual method table" for the underlying implementation. -The php_streams ops struct consists of pointers to methods that implement -read, write, close, flush, seek, gets and cast operations. Of these, an -implementation need only implement write, read, close and flush. The gets -method is intended to be used for streams if there is an underlying method -that can efficiently behave as fgets. The ops struct also contains a label -for the implementation that will be used when printing error messages - the -stdio implementation has a label of "STDIO" for example. +The `php_streams` ops struct consists of pointers to methods that implement +read, write, close, flush, seek, gets and cast operations. Of these, an +implementation need only implement write, read, close and flush. The gets method +is intended to be used for streams if there is an underlying method that can +efficiently behave as fgets. The ops struct also contains a label for the +implementation that will be used when printing error messages - the stdio +implementation has a label of `STDIO` for example. -The idea is that a stream implementation defines a php_stream_ops struct, and -associates it with a php_stream using php_stream_alloc. +The idea is that a stream implementation defines a `php_stream_ops` struct, and +associates it with a `php_stream` using `php_stream_alloc`. -As an example, the php_stream_fopen() function looks like this: +As an example, the `php_stream_fopen()` function looks like this: +```c PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode) { FILE * fp = fopen(filename, mode); @@ -255,62 +276,64 @@ PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode) } return NULL; } +``` -php_stream_stdio_ops is a php_stream_ops structure that can be used to handle -FILE* based streams. +`php_stream_stdio_ops` is a `php_stream_ops` structure that can be used to +handle `FILE*` based streams. -A socket based stream would use code similar to that above to create a stream -to be passed back to fopen_wrapper (or it's yet to be implemented successor). +A socket based stream would use code similar to that above to create a stream to +be passed back to fopen_wrapper (or it's yet to be implemented successor). The prototype for php_stream_alloc is this: +```c PHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract, size_t bufsize, int persistent, const char * mode) - -ops is a pointer to the implementation, -abstract holds implementation specific data that is relevant to this instance -of the stream, -bufsize is the size of the buffer to use - if 0, then buffering at the stream -level will be disabled (recommended for underlying sources that implement -their own buffering - such a FILE*), -persistent controls how the memory is to be allocated - persistently so that -it lasts across requests, or non-persistently so that it is freed at the end -of a request (it uses pemalloc), -mode is the stdio-like mode of operation - php streams places no real meaning -in the mode parameter, except that it checks for a 'w' in the string when -attempting to write (this may change). - -The mode parameter is passed on to fdopen/fopencookie when the stream is cast -into a FILE*, so it should be compatible with the mode parameter of fopen(). - -Writing your own stream implementation -====================================== - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -RULE #1: when writing your own streams: make sure you have configured PHP with ---enable-debug. -I've taken some great pains to hook into the Zend memory manager to help track -down allocation problems. It will also help you spot incorrect use of the -STREAMS_DC, STREAMS_CC and the semi-private STREAMS_REL_CC macros for function -definitions. -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -RULE #2: Please use the stdio stream as a reference; it will help you -understand the semantics of the stream operations, and it will always -be more up to date than these docs :-) +``` + +* `ops` is a pointer to the implementation, +* `abstract` holds implementation specific data that is relevant to this + instance of the stream, +* `bufsize` is the size of the buffer to use - if 0, then buffering at the + stream +* `level` will be disabled (recommended for underlying sources that implement + their own buffering - such a `FILE*`) +* `persistent` controls how the memory is to be allocated - persistently so that + it lasts across requests, or non-persistently so that it is freed at the end + of a request (it uses pemalloc), +* `mode` is the stdio-like mode of operation - php streams places no real + meaning in the mode parameter, except that it checks for a `w` in the string + when attempting to write (this may change). + +The mode parameter is passed on to `fdopen/fopencookie` when the stream is cast +into a `FILE*`, so it should be compatible with the mode parameter of `fopen()`. + +## Writing your own stream implementation + +* **RULE #1**: when writing your own streams: make sure you have configured PHP + with `--enable-debug`. + Some great great pains have been taken to hook into the Zend memory manager to + help track down allocation problems. It will also help you spot incorrect use + of the STREAMS_DC, STREAMS_CC and the semi-private STREAMS_REL_CC macros for + function definitions. + +* RULE #2: Please use the stdio stream as a reference; it will help you + understand the semantics of the stream operations, and it will always be more + up to date than these docs :-) First, you need to figure out what data you need to associate with the -php_stream. For example, you might need a pointer to some memory for memory +`php_stream`. For example, you might need a pointer to some memory for memory based streams, or if you were making a stream to read data from an RDBMS like MySQL, you might want to store the connection and rowset handles. -The stream has a field called abstract that you can use to hold this data. -If you need to store more than a single field of data, define a structure to -hold it, allocate it (use pemalloc with the persistent flag set -appropriately), and use the abstract pointer to refer to it. +The stream has a field called abstract that you can use to hold this data. If +you need to store more than a single field of data, define a structure to hold +it, allocate it (use pemalloc with the persistent flag set appropriately), and +use the abstract pointer to refer to it. For structured state you might have this: +```c struct my_state { MYSQL conn; MYSQL_RES * result; @@ -327,6 +350,7 @@ state->result = mysql_use_result(&state->conn); stream = php_stream_alloc(&my_ops, state, 0, persistent, "r"); /* now stream->abstract == state */ +``` Once you have that part figured out, you can write your implementation and define the your own php_stream_ops struct (we called it my_ops in the above @@ -334,6 +358,7 @@ example). For example, for reading from this weird MySQL stream: +```c static size_t php_mysqlop_read(php_stream * stream, char * buf, size_t count) { struct my_state * state = (struct my_state*)stream->abstract; @@ -354,23 +379,27 @@ static size_t php_mysqlop_read(php_stream * stream, char * buf, size_t count) such as coping with a buffer size too small to hold the data, so I won't even go in to how to do that here */ } +``` -Implement the other operations - remember that write, read, close and flush -are all mandatory. The rest are optional. Declare your stream ops struct: +Implement the other operations - remember that write, read, close and flush are +all mandatory. The rest are optional. Declare your stream ops struct: +```c php_stream_ops my_ops = { php_mysqlop_write, php_mysqlop_read, php_mysqlop_close, php_mysqlop_flush, NULL, NULL, NULL, "Strange MySQL example" } +``` That's it! -Take a look at the STDIO implementation in streams.c for more information -about how these operations work. +Take a look at the STDIO implementation in streams.c for more information about +how these operations work. + The main thing to remember is that in your close operation you need to release -and free the resources you allocated for the abstract field. In the case of -the example above, you need to use mysql_free_result on the rowset, close the -connection and then use pefree to dispose of the struct you allocated. -You may read the stream->persistent field to determine if your struct was -allocated in persistent mode or not. +and free the resources you allocated for the abstract field. In the case of the +example above, you need to use mysql_free_result on the rowset, close the +connection and then use pefree to dispose of the struct you allocated. You may +read the stream->persistent field to determine if your struct was allocated in +persistent mode or not. diff --git a/docs/unix-build-system.md b/docs/unix-build-system.md index e13053e39e..bdb8d4d146 100644 --- a/docs/unix-build-system.md +++ b/docs/unix-build-system.md @@ -1,113 +1,121 @@ -# PHP Build System V5 Overview - -- supports Makefile.ins during transition phase -- not-really-portable Makefile includes have been eliminated -- supports separate build directories without VPATH by using - explicit rules only -- does not waste disk-space/CPU-time for building temporary libraries - => especially noticeable on slower systems -- slow recursive make replaced with one global Makefile -- eases integration of proper dependencies -- adds PHP_DEFINE(what[, value]) which creates a single include-file - per what. This will allow more fine-grained dependencies. -- abandoning the "one library per directory" concept -- improved integration of the CLI -- several new targets - build-modules: builds and copies dynamic modules into modules/ - install-cli: installs the CLI only, so that the install-sapi - target does only what its name says -- finally abandoned automake -- changed some configure-time constructs to run at buildconf-time -- upgraded shtool to 1.5.4 -- removed $(moduledir) (use EXTENSION_DIR) - -## The Reason For a New System - -It became more and more apparent that there is a severe need -for addressing the portability concerns and improving the chance -that your build is correct (how often have you been told to -"make clean"? When this is done, you won't need to anymore). - -## If You Build PHP on a Unix System - -You, as a user of PHP, will notice no changes. Of course, the build -system will be faster, look better and work smarter. - -## If You Are Developing PHP - -### Extension developers: - -Makefile.ins are abandoned. The files which are to be compiled -are specified in the config.m4 now using the following macro: - +# PHP build system V5 overview + +* supports Makefile.ins during transition phase +* not-really-portable Makefile includes have been eliminated +* supports separate build directories without VPATH by using explicit rules only +* does not waste disk-space/CPU-time for building temporary libraries => + especially noticeable on slower systems +* slow recursive make replaced with one global Makefile +* eases integration of proper dependencies +* adds PHP_DEFINE(what[, value]) which creates a single include-file per what. + This will allow more fine-grained dependencies. +* abandoning the "one library per directory" concept +* improved integration of the CLI +* several new targets: + * `build-modules`: builds and copies dynamic modules into `modules/` + * `install-cli`: installs the CLI only, so that the install-sapi target does + only what its name says +* finally abandoned automake +* changed some configure-time constructs to run at buildconf-time +* upgraded shtool to 1.5.4 +* removed `$(moduledir)` (use `EXTENSION_DIR`) + +## The reason for a new system + +It became more and more apparent that there is a severe need for addressing the +portability concerns and improving the chance that your build is correct (how +often have you been told to `make clean`? When this is done, you won't need to +anymore). + +## If you build PHP on a Unix system + +You, as a user of PHP, will notice no changes. Of course, the build system will +be faster, look better and work smarter. + +## If you are developing PHP + +### Extension developers + +Makefile.ins are abandoned. The files which are to be compiled are specified in +the `config.m4` now using the following macro: + +```m4 PHP_NEW_EXTENSION(foo, foo.c bar.c baz.cpp, $ext_shared) +``` -E.g. this enables the extension foo which consists of three source-code -modules, two in C and one in C++. And, depending on the user's wishes, -the extension will even be built as a dynamic module. +E.g. this enables the extension foo which consists of three source-code modules, +two in C and one in C++. And, depending on the user's wishes, the extension will +even be built as a dynamic module. The full syntax: +```m4 PHP_NEW_EXTENSION(extname, sources [, shared [,sapi_class[, extra-cflags]]]) +``` -Please have a look at acinclude.m4 for the gory details and meanings -of the other parameters. +Please have a look at `acinclude.m4` for the gory details and meanings of the +other parameters. And that's basically it for the extension side. -If you previously built sub-libraries for this module, add -the source-code files here as well. If you need to specify -separate include directories, do it this way: +If you previously built sub-libraries for this module, add the source-code files +here as well. If you need to specify separate include directories, do it this +way: +```m4 PHP_NEW_EXTENSION(foo, foo.c mylib/bar.c mylib/gregor.c,,,-I@ext_srcdir@/lib) +``` -E.g. this builds the three files which are located relative to the -extension source directory and compiles all three files with the -special include directive (@ext_srcdir@ is automatically replaced). +E.g. this builds the three files which are located relative to the extension +source directory and compiles all three files with the special include directive +(`@ext_srcdir@` is automatically replaced). -Now, you need to tell the build system that you want to build files -in a directory called $ext_builddir/lib: +Now, you need to tell the build system that you want to build files in a +directory called `$ext_builddir/lib`: +```m4 PHP_ADD_BUILD_DIR($ext_builddir/lib) +``` -Make sure to call this after PHP_NEW_EXTENSION, because $ext_builddir -is only set by the latter. +Make sure to call this after `PHP_NEW_EXTENSION`, because `$ext_builddir` is +only set by the latter. -If you have a complex extension, you might to need add special -Make rules. You can do this by calling PHP_ADD_MAKEFILE_FRAGMENT -in your config.m4 after PHP_NEW_EXTENSION. +If you have a complex extension, you might to need add special Make rules. You +can do this by calling `PHP_ADD_MAKEFILE_FRAGMENT` in your `config.m4` after +`PHP_NEW_EXTENSION`. This will read a file in the source-dir of your extension called -Makefile.frag. In this file, $(builddir) and $(srcdir) will be -replaced by the values which are correct for your extension -and which are again determined by the PHP_NEW_EXTENSION macro. +`Makefile.frag`. In this file, `$(builddir)` and `$(srcdir)` will be replaced by +the values which are correct for your extension and which are again determined +by the `PHP_NEW_EXTENSION` macro. -Make sure to prefix *all* relative paths correctly with either -$(builddir) or $(srcdir). Because the build system does not -change the working directory anymore, we must use either -absolute paths or relative ones to the top build-directory. -Correct prefixing ensures that. +Make sure to prefix *all* relative paths correctly with either `$(builddir)` or +`$(srcdir)`. Because the build system does not change the working directory +anymore, we must use either absolute paths or relative ones to the top +build-directory. Correct prefixing ensures that. -### SAPI developers: +### SAPI developers -Instead of using PHP_SAPI=foo/PHP_BUILD_XYZ, you will need to type +Instead of using `PHP_SAPI=foo/PHP_BUILD_XYZ`, you will need to type +```m4 PHP_SELECT_SAPI(name, type, sources.c) +``` -I.e. specify the source-code files as above and also pass the -information regarding how PHP is supposed to be built (shared -module, program, etc). +I.e. specify the source-code files as above and also pass the information +regarding how PHP is supposed to be built (shared module, program, etc). For example for APXS: +```m4 PHP_SELECT_SAPI(apache, shared, sapi_apache.c mod_php7.c php_apache.c) +``` ## General info -The foundation for the new system is the flexible handling of -sources and their contexts. With the help of macros you -can define special flags for each source-file, where it is -located, in which target context it can work, etc. +The foundation for the new system is the flexible handling of sources and their +contexts. With the help of macros you can define special flags for each +source-file, where it is located, in which target context it can work, etc. -Have a look at the well documented macros -PHP_ADD_SOURCES(_X) in acinclude.m4. +Have a look at the well documented macros `PHP_ADD_SOURCES(_X)` in +`acinclude.m4`. -- cgit v1.2.1