summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorPeter Kokot <peterkokot@gmail.com>2019-03-27 20:51:45 +0100
committerPeter Kokot <peterkokot@gmail.com>2019-03-30 19:38:34 +0100
commit8346b4c9f149c1a3d4e0631007e71bbbebd0b87d (patch)
tree1a9248515aa422aae2368a61531b42c2f50fcb40 /docs
parent1ce4ab1ecc48012c2359b4ddd6db5150aeb4ae01 (diff)
downloadphp-git-8346b4c9f149c1a3d4e0631007e71bbbebd0b87d.tar.gz
Move README files to a dedicated docs directory
The new dedicated docs directory has been introduced after a discussion on GitHub[1]. Main issue it is addressing is the reduction of too many README files in the project root directory. The new directory is dedicated for notes and quick documentation files that either can't be put in the manual or wiki pages or that relate to the php-src repository specifically and need to live together with the source code. Also the `docs` directory is by GitHub used for some repository configuration files such as pull request templates, and contributing documentation helper files that are integrated in the interface. [1]: https://github.com/php/php-src/pull/3988
Diffstat (limited to 'docs')
-rw-r--r--docs/input-filter.md182
-rw-r--r--docs/mailinglist-rules.md79
-rw-r--r--docs/output-api.md139
-rw-r--r--docs/parameter-parsing-api.md245
-rw-r--r--docs/release-process.md395
-rw-r--r--docs/self-contained-extensions.md167
-rw-r--r--docs/streams.md376
-rw-r--r--docs/unix-build-system.md123
8 files changed, 1706 insertions, 0 deletions
diff --git a/docs/input-filter.md b/docs/input-filter.md
new file mode 100644
index 0000000000..bca7f29ad2
--- /dev/null
+++ b/docs/input-filter.md
@@ -0,0 +1,182 @@
+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.
+
+ZEND_BEGIN_MODULE_GLOBALS(my_input_filter)
+ zval *post_array;
+ zval *get_array;
+ zval *cookie_array;
+ZEND_END_MODULE_GLOBALS(my_input_filter)
+
+#ifdef ZTS
+#define IF_G(v) TSRMG(my_input_filter_globals_id, zend_my_input_filter_globals *, v)
+#else
+#define IF_G(v) (my_input_filter_globals.v)
+#endif
+
+ZEND_DECLARE_MODULE_GLOBALS(my_input_filter)
+
+zend_function_entry my_input_filter_functions[] = {
+ PHP_FE(my_get_raw, NULL)
+ {NULL, NULL, NULL}
+};
+
+zend_module_entry my_input_filter_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "my_input_filter",
+ my_input_filter_functions,
+ PHP_MINIT(my_input_filter),
+ PHP_MSHUTDOWN(my_input_filter),
+ NULL,
+ PHP_RSHUTDOWN(my_input_filter),
+ PHP_MINFO(my_input_filter),
+ "0.1",
+ STANDARD_MODULE_PROPERTIES
+};
+
+PHP_MINIT_FUNCTION(my_input_filter)
+{
+ ZEND_INIT_MODULE_GLOBALS(my_input_filter, php_my_input_filter_init_globals, NULL);
+
+ REGISTER_LONG_CONSTANT("POST", PARSE_POST, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("GET", PARSE_GET, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("COOKIE", PARSE_COOKIE, CONST_CS | CONST_PERSISTENT);
+
+ sapi_register_input_filter(my_sapi_input_filter);
+ return SUCCESS;
+}
+
+PHP_RSHUTDOWN_FUNCTION(my_input_filter)
+{
+ if(IF_G(get_array)) {
+ zval_ptr_dtor(&IF_G(get_array));
+ IF_G(get_array) = NULL;
+ }
+ if(IF_G(post_array)) {
+ zval_ptr_dtor(&IF_G(post_array));
+ IF_G(post_array) = NULL;
+ }
+ if(IF_G(cookie_array)) {
+ zval_ptr_dtor(&IF_G(cookie_array));
+ IF_G(cookie_array) = NULL;
+ }
+ return SUCCESS;
+}
+
+PHP_MINFO_FUNCTION(my_input_filter)
+{
+ php_info_print_table_start();
+ php_info_print_table_row( 2, "My Input Filter Support", "enabled" );
+ php_info_print_table_end();
+}
+
+/* The filter handler. If you return 1 from it, then PHP also registers the
+ * (modified) variable. Returning 0 prevents PHP from registering the variable;
+ * you can use this if your filter already registers the variable under a
+ * different name, or if you just don't want the variable registered at all. */
+SAPI_INPUT_FILTER_FUNC(my_sapi_input_filter)
+{
+ zval new_var;
+ zval *array_ptr = NULL;
+ char *raw_var;
+ int var_len;
+
+ assert(*val != NULL);
+
+ switch(arg) {
+ case PARSE_GET:
+ if(!IF_G(get_array)) {
+ ALLOC_ZVAL(array_ptr);
+ array_init(array_ptr);
+ INIT_PZVAL(array_ptr);
+ }
+ IF_G(get_array) = array_ptr;
+ break;
+ case PARSE_POST:
+ if(!IF_G(post_array)) {
+ ALLOC_ZVAL(array_ptr);
+ array_init(array_ptr);
+ INIT_PZVAL(array_ptr);
+ }
+ IF_G(post_array) = array_ptr;
+ break;
+ case PARSE_COOKIE:
+ if(!IF_G(cookie_array)) {
+ ALLOC_ZVAL(array_ptr);
+ array_init(array_ptr);
+ INIT_PZVAL(array_ptr);
+ }
+ IF_G(cookie_array) = array_ptr;
+ break;
+ }
+ Z_STRLEN(new_var) = val_len;
+ Z_STRVAL(new_var) = estrndup(*val, val_len);
+ Z_TYPE(new_var) = IS_STRING;
+
+ var_len = strlen(var);
+ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */
+ strcpy(raw_var, "RAW_");
+ strlcat(raw_var,var,var_len+5);
+
+ php_register_variable_ex(raw_var, &new_var, array_ptr);
+
+ php_strip_tags(*val, val_len, NULL, NULL, 0);
+
+ *new_val_len = strlen(*val);
+ return 1;
+}
+
+PHP_FUNCTION(my_get_raw)
+{
+ long arg;
+ char *var;
+ int var_len;
+ zval **tmp;
+ zval *array_ptr = NULL;
+
+ if(zend_parse_parameters(2, "ls", &arg, &var, &var_len) == FAILURE) {
+ return;
+ }
+
+ switch(arg) {
+ case PARSE_GET:
+ array_ptr = IF_G(get_array);
+ break;
+ case PARSE_POST:
+ array_ptr = IF_G(post_array);
+ break;
+ case PARSE_COOKIE:
+ array_ptr = IF_G(post_array);
+ break;
+ }
+
+ if(!array_ptr) {
+ RETURN_FALSE;
+ }
+
+ if(zend_hash_find(HASH_OF(array_ptr), var, var_len+5, (void **)&tmp) == SUCCESS) {
+ *return_value = **tmp;
+ zval_copy_ctor(return_value);
+ } else {
+ RETVAL_FALSE;
+ }
+}
diff --git a/docs/mailinglist-rules.md b/docs/mailinglist-rules.md
new file mode 100644
index 0000000000..8fafbd717d
--- /dev/null
+++ b/docs/mailinglist-rules.md
@@ -0,0 +1,79 @@
+====================
+ 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
+the PHP project. Therefore expect your contributions to be of much less positive
+impact if you do not follow these rules. More importantly you can actually
+assume that not following these rules will hurt the PHP project.
+
+PHP is developed through the efforts of a large number of people.
+Collaboration is a Good Thing(tm), and mailinglists lets us do this. Thus,
+following some basic rules with regards to mailinglist usage will:
+
+ a. Make everybody happier, especially those responsible for developing PHP
+ itself.
+
+ b. Help in making sure we all use our time more efficiently.
+
+ c. Prevent you from making a fool of yourself in public.
+
+ 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.
+
+ 2. Do not post when you are angry. Any post can wait a few hours. Review
+ 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.
+
+ 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
+ are faced with a lot of requests. Make sure that you have done your
+ research before posting to the entire developer community.
+
+ 5. Patches have a much greater chance of acceptance than just asking the
+ PHP developers to implement a feature for you. For one it makes the
+ discussion more concrete and it shows that the poster put thought and time
+ into the request.
+
+ 6. If you are posting to an existing thread, make sure that you know what
+ previous posters have said. This is even more important the longer the
+ thread is already.
+
+ 7. Please configure your email client to use a real name and keep message
+ signatures to a maximum of 2 lines if at all necessary.
+
+The next few rules are more some general hints:
+
+ 1. If you notice that your posting ratio is much higher than that of other
+ people, double check the above rules. Try to wait a bit longer before
+ sending your replies to give other people more time to digest your answers
+ and more importantly give you the opportunity to make sure that you
+ aggregate your current position into a single mail instead of multiple
+ ones.
+
+ 2. Consider taking a step back from a very active thread now and then. Maybe
+ talking to some friends and fellow developers will help in understanding
+ the other opinions better.
+
+ 3. Do not top post. Place your answer underneath anyone you wish to quote
+ and remove any previous comment that is not relevant to your post.
+
+ 4. Do not high-jack threads, by bringing up entirely new topics. Please
+ create an entirely new thread copying anything you wish to quote into the
+ 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).
+
+Happy hacking,
+
+PHP Team
diff --git a/docs/output-api.md b/docs/output-api.md
new file mode 100644
index 0000000000..3c23c8e8de
--- /dev/null
+++ b/docs/output-api.md
@@ -0,0 +1,139 @@
+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.
+
+ 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 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
diff --git a/docs/parameter-parsing-api.md b/docs/parameter-parsing-api.md
new file mode 100644
index 0000000000..f65c19a723
--- /dev/null
+++ b/docs/parameter-parsing-api.md
@@ -0,0 +1,245 @@
+Fast Parameter Parsing API
+==========================
+
+In PHP 7, a "Fast Parameter Parsing API" was introduced. See
+
+ https://wiki.php.net/rfc/fast_zpp
+
+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.
+
+
+Prototypes
+----------
+/* 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.
+
+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.
+
+PHP 5.3 includes a new function (actually implemented as macro):
+
+int zend_parse_parameters_none();
+
+This returns SUCCESS if no argument has been passed to the function,
+FAILURE otherwise.
+
+PHP 5.5 includes a new function:
+
+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
+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!
+
+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)
+
+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/
+
+
+Examples
+--------
+/* Gets a long, a string and its length, and a zval */
+zend_long l;
+char *s;
+size_t s_len;
+zval *param;
+if (zend_parse_parameters(ZEND_NUM_ARGS(), "lsz",
+ &l, &s, &s_len, &param) == FAILURE) {
+ return;
+}
+
+
+/* Gets an object of class specified by my_ce, and an optional double. */
+zval *obj;
+double d = 0.5;
+zend_class_entry *my_ce;
+if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|d",
+ &obj, my_ce, &d) == FAILURE) {
+ return;
+}
+
+
+/* Gets an object or null, and an array.
+ If null is passed for object, obj will be set to NULL. */
+zval *obj;
+zval *arr;
+if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!a",
+ &obj, &arr) == FAILURE) {
+ return;
+}
+
+
+/* Gets a separated array which can also be null. */
+zval *arr;
+if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/!",
+ &arr) == FAILURE) {
+ return;
+}
+
+/* Get either a set of 3 longs or a string. */
+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
+ * than a 'size_t', the upper bits might not be initialized
+ * properly, leading to random crashes on platforms like
+ * Tru64 or Linux/Alpha.
+ */
+size_t length;
+
+if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
+ "lll", &l1, &l2, &l3) == SUCCESS) {
+ /* manipulate longs */
+} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
+ "s", &s, &length) == SUCCESS) {
+ /* manipulate string */
+} else {
+ /* output error */
+
+ 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;
+}
+
+for (i = 0; i < num_varargs; i++) {
+ /* do something with varargs[i] */
+}
+
+if (varargs) {
+ efree(varargs);
+}
+
+
+/* Function that accepts a string, followed by varargs (1 or more) */
+
+char *str;
+size_t str_len;
+int i, num_varargs;
+zval *varargs = NULL;
+
+if (zend_parse_parameters(ZEND_NUM_ARGS(), "s+", &str, &str_len, &varargs, &num_varargs) == FAILURE) {
+ return;
+}
+
+for (i = 0; i < num_varargs; i++) {
+ /* do something with varargs[i] */
+}
+
+/* Function that takes an array, followed by varargs, and ending with a long */
+zend_long num;
+zval *array;
+int i, num_varargs;
+zval *varargs = NULL;
+
+if (zend_parse_parameters(ZEND_NUM_ARGS(), "a*l", &array, &varargs, &num_varargs, &num) == FAILURE) {
+ return;
+}
+
+for (i = 0; i < num_varargs; i++) {
+ /* do something with varargs[i] */
+}
+
+/* Function that doesn't accept any arguments */
+if (zend_parse_parameters_none() == FAILURE) {
+ return;
+}
diff --git a/docs/release-process.md b/docs/release-process.md
new file mode 100644
index 0000000000..211d68d5e0
--- /dev/null
+++ b/docs/release-process.md
@@ -0,0 +1,395 @@
+=======================
+ PHP Release Process
+=======================
+
+General notes and tips
+----------------------
+
+1. Do not release on Fridays, Saturdays or Sundays
+because the sysadmins can not upgrade stuff then.
+
+2. Package two days before a release. So if the release is to be on Thursday,
+package on Tuesday. Think about timezones as well.
+
+3. Ensure that the tests on Travis CI are green.
+See: https://travis-ci.org/php/php-src/builds
+It is recommended to do so a couple of days before the packaging day, to
+have enough time to investigate failures, communicate with the authors and
+commit the fixes.
+The RM for the branch is also responsible for keeping the CI green on
+ongoing basis between the releases. Check the CI status for your branch
+periodically and resolve the failures ASAP. See more in:
+https://wiki.php.net/rfc/travis_ci
+
+4. Ensure that Windows builds will work before packaging
+
+5. Follow all steps to the letter. When unclear ask previous RM's (David/Julien/
+Johannes/Stas/Derick/Ilia) before proceeding. Ideally make sure that for the
+first releases one of the previous RM's is around to answer questions. For the
+steps related to the php/QA/bug websites try to have someone from the webmaster
+team (Bjori) on hand.
+
+6. Verify the tags to be extra sure everything was tagged properly.
+
+7. Moving extensions from/to PECL requires write access to the destination.
+Most developers should have this.
+
+Moving extensions from php-src to PECL
+- Checkout the pecl directory, most likely you want a sparse-root checkout
+ svn co --depth=empty https://svn.php.net/repository/pecl
+- Create a directory for the extension incl. branch and tag structure,
+ no trunk at this point and commit this to svn
+ cd pecl; mkdir foo foo/tags foo/branches; svn add foo; svn commit
+- Move the extension from php-src to the new location
+ svn mv https://svn.php.net/repository/php/php-src/trunk/ext/foo \
+ https://svn.php.net/repository/pecl/foo/trunk
+
+If the extension is still usable or not dead, in cooperation with the extension
+maintainers if any:
+- create the pecl.php.net/foo package and its content, license, maintainer
+- create the package.xml, commit
+- release the package
+
+For Moving extensions from PECL to php-src the svn mv has to be done the other
+way round.
+
+Rolling a non stable release (alpha/beta/RC)
+--------------------------------------------
+
+1. Check windows snapshot builder logs (http://windows.php.net/downloads/snaps/ the last revision)
+
+2. Check the tests at https://travis-ci.org/php/php-src/builds
+
+3. run the "scripts/dev/credits" script in php-src and commit the changes in the
+credits files in ext/standard.
+
+4. Checkout the release branch for this release (e.g., PHP-5.4.2) from the main branch.
+
+5. Bump the version numbers in ``main/php_version.h``, ``Zend/zend.h``, ``configure.ac`` and possibly ``NEWS``.
+Do not use abbreviations for alpha and beta. Do not use dashes, you should
+``#define PHP_VERSION "5.4.22RC1"`` and not ``#define PHP_VERSION "5.4.22-RC1"``
+
+6. Compile and make test, with and without ZTS, using the right Bison version
+(for example, for 5.5, Bison 2.4.1 is used)
+
+7. Check ./sapi/cli/php -v output for version matching.
+
+8. If all is right, commit the changes to the release branch with ``git commit -a``.
+
+9. Tag the repository release branch with the version, e.g.:
+``git tag -u YOURKEYID php-5.4.2RC2``
+
+10. Bump the version numbers in ``main/php_version.h``, ``Zend/zend.h``, ``configure.ac`` and ``NEWS``
+in the *main* branch (PHP-5.4 for example) to prepare for the **next** version.
+F.e. if the RC is "5.4.1RC1" then the new one should be "5.4.2-dev" - regardless if we get
+a new RC or not. This is to make sure ``version_compare()`` can correctly work.
+Commit the changes to the main branch.
+
+11. Push the changes to the main repo, the tag, the main branch and the release branch :
+``git push --tags origin HEAD``
+``git push origin {main branch}``
+``git push origin {release branch}``
+
+12. run: ``PHPROOT=. ./scripts/dev/makedist 5.4.2RC2``, this will export the tree, create configure
+and build three tarballs (gz, bz2 and xz).
+
+13. run ``scripts/dev/gen_verify_stub <version> [identity]``, this will sign the tarballs
+and output verification information to be included in announcement email
+
+14. Copy those tarballs (scp, rsync) to downloads.php.net, in your homedir there should be a
+directory "public_html/". Copy them into there. If you do not have this directory, create it.
+
+15. Now the RC can be found on http://downloads.php.net/~yourname,
+f.e. http://downloads.php.net/~derick/
+
+16. Once the release has been tagged, contact the release-managers@ distribution list
+so that Windows binaries can be created. Once those are made, they can be found at
+http://windows.php.net/download
+
+Getting the non stable release (alpha/beta/RC) announced
+--------------------------------------------------------
+
+1. Update ``qa.git/include/release-qa.php`` with the appropriate information.
+ See the documentation within release-qa.php for more information, but all releases
+ and RCs are configured here. Only $QA_RELEASES needs to be edited.
+
+ Example: When rolling an RC, set the 'rc' with appropriate information for the
+ given version.
+
+ Note: Remember to update the sha256 checksum information.
+
+2. Update ``web/php.git/include/version.inc`` (x=major version number)
+
+ a. ``$PHP_x_RC`` = "5.4.0RC1" (should be set to "false" before)
+
+ b. ``$PHP_x_RC_DATE`` = "06 September 2007"
+
+3. Skip this step for non stable releases after GA of minor or major versions
+ (e.g. announce 7.3.0RC1, but not 7.3.1RC1):
+
+ Add a short notice to phpweb stating that there is a new release, and
+ highlight the major important things (security fixes) and when it is
+ important to upgrade.
+
+ a. Call php bin/createNewsEntry in your local phpweb checkout
+ Use category "frontpage" *and* "releases" for all stable releases.
+ Use category "frontpage" for X.Y.0 non-stable releases only (news only).
+
+ b. Add the content for the news entry. Be sure to include the text:
+ "THIS IS A DEVELOPMENT PREVIEW - DO NOT USE IT IN PRODUCTION!"
+
+4. Commit and push changes to qa and web
+
+*Wait for web and qa sites to update with new information before sending announce*
+
+5. Send **separate** emails **To** ``internals@lists.php.net`` and ``php-general@lists.php.net``
+lists pointing out "the location of the release" and "the possible release date of
+either the next RC, or the final release". Include in this information the verification
+information output by ``gen_verify_stub``.
+
+6. Send **separate** emails (see example here http://news.php.net/php.pear.qa/5201) **To**
+``php-qa@lists.php.net`` and ``primary-qa-tester@lists.php.net``.
+These emails are to notify the selected projects about a new release so that they
+can make sure their projects keep working. Make sure that you have been setup
+as a moderator for ``primary-qa-tester@lists.php.net`` by having someone (Hannes, Dan,
+Derick) run the following commands for you:
+
+``ssh lists.php.net``
+
+``sudo -u ezmlm ezmlm-sub ~ezmlm/primary-qa-tester/mod moderator-email-address``
+
+Rolling a stable release
+------------------------
+
+1. Checkout your release branch, you should have created when releasing previous RC
+and bump the version numbers in ``main/php_version.h``, ``Zend/zend.h``, ``configure.ac`` and possibly ``NEWS``.
+
+2. If a CVE commit needs to be merged to the release, then have it committed to
+the base branches and merged upwards as usual (f.e commit the CVE fix to 5.3,
+merge to 5.4, 5.5 etc...). Then you can cherry-pick it in your release branch.
+Don't forget to update NEWS manually in an extra commit then.
+
+3. Commit those changes. Ensure the tests at https://travis-ci.org/php/php-src/builds are
+still passing.
+
+4. run the "scripts/dev/credits" script in php-src and commit the changes in the
+credits files in ext/standard.
+
+5. Compile and make test, with and without ZTS, using the right Bison version
+(for example, for 5.5, Bison 2.4.1 is used)
+
+6. Check ./sapi/cli/php -v output for version matching.
+
+7. tag the repository with the version f.e. "``git tag -u YOURKEYID php-5.4.1``"
+
+8. Push the tag f.e. "``git push origin php-5.4.1``"
+
+9. run: ``PHPROOT=. ./scripts/dev/makedist php 5.4.1``, this will export the tag, create configure
+and build three tarballs (gz, bz2 and xz).
+ Check if the pear files are updated (phar).
+ On some systems the behavior of GNU tar can default to produce POSIX compliant archives
+with PAX headers. As not every application is compatible with that format, creation of
+archives with PAX headers should be avoided. When packaging on such a system, the GNU tar
+can be influenced by defining the environment variable TAR_OPTIONS='--format=gnu'.
+
+10. run ``scripts/dev/gen_verify_stub <version> [identity]``, this will sign the tarballs
+ and output verification information to be included in announcement email
+
+11. Commit and push all the tarballs and signature files to web/php-distributions.git,
+ then update the git submodule reference in web/php.git:
+ ``git submodule init;
+ git submodule update;
+ cd distributions;
+ git fetch;
+ git pull --rebase origin master;
+ cd ..;
+ git commit distributions;
+ git push;``
+This is to fetch the last commit id from php-distributions.git and commit this
+last commit id to web/php.git, then, mirrors will now sync
+
+12. Once the release has been tagged, contact release managers, windows builders, and package maintainers
+so that they can build releases. Do not send this announcement to any public lists.
+
+Getting the stable release announced
+------------------------------------
+
+1. Update phpweb/include/releases.inc with the old release info
+ (updates the download archives)
+
+ a. You can run ``php bin/bumpRelease 7 2`` where the first number is
+ the major version, and the second number is the minor version
+ (7.2 in this example).
+
+ b. If that fails for any non-trivially fixable reason, you can
+ manually copy the old information to include/releases.inc
+
+2. Edit ``phpweb/include/version.inc`` and change (X=major release number):
+
+ a. ``$PHP_X_VERSION`` to the correct version
+
+ b. ``$PHP_X_DATE`` to the release date
+
+ c. ``$PHP_X_SHA256`` array and update all the SHA256 sums
+
+ d. set ``$PHP_X_RC`` to false!
+
+ e. Make sure there are no outdated "notes" or edited "date" keys in the
+ ``$RELEASES[X][$PHP_X_VERSION]["source"]`` array
+
+3. Create the release file (releases/x_y_z.php)
+ Usually we use the same content as for point 6, but included in php template
+ instead of the release xml.
+
+4. Update php-qa/include/release-qa.php and add the next version as an QARELEASE
+ (prepare for next RC)
+
+5. Update the ChangeLog file for the given major version
+f.e. ``ChangeLog-5.php`` from the NEWS file
+
+ a. go over the list and put every element on one line
+
+ b. check for &, < and > and escape them if necessary
+
+ c. remove all the names at the ends of lines
+
+ d. for marking up, you can do the following (with VI):
+
+ I. ``s/^- /<li>/``
+
+ II. ``s/$/<\/li>/``
+
+ III. ``s/Fixed bug #\([0-9]\+\)/<?php bugfix(\1); ?>/``
+
+ IV. ``s/Fixed PECL bug #\([0-9]\+\)/<?php peclbugfix(\1); ?>/``
+
+ V. ``s/FR #\([0-9]\+\)/FR <?php bugl(\1); ?>/``
+
+ e. You may want to try php-web/bin/news2html to automate this task
+
+6. Add a short notice to phpweb stating that there is a new release, and
+highlight the major important things (security fixes) and when it is important
+to upgrade.
+
+ a. Call php bin/createNewsEntry in your local phpweb checkout
+
+ b. Add the content for the news entry
+
+7. **Check mirrors have been synced before announcing or pushing news**
+ Try, f.e. http://www.php.net/get/php-5.5.1.tar.bz2/from/a/mirror
+ Try several mirrors, mirrors may update slowly (may take an hour)
+
+8. Commit all the changes to their respective git repos
+
+9. Please note down the sha256 and the PGP signature (.asc). These *must* be
+ included in the release mail.
+10. Wait an hour or two, then send a mail to php-announce@lists.php.net,
+php-general@lists.php.net and internals@lists.php.net with a text similar to
+http://news.php.net/php.internals/17222.
+Please make sure that the mail to php-announce@ is its own completely separate email.
+This is to make sure that replies to the announcement on php-general@ or internals@
+will not accidentally hit the php-announce@ mailinglist.
+
+Re-releasing the same version (or -pl)
+--------------------------------------
+
+1. Commit the new binaries to ``phpweb/distributions/``
+
+2. Edit ``phpweb/include/version.inc`` and change (X=major release number):
+
+ a. If only releasing for one OS, make sure you edit only those variables
+
+ b. ``$PHP_X_VERSION`` to the correct version
+
+ c. ``$PHP_X_DATE`` to the release date
+
+ d. ``$PHP_X_SHA256`` array and update all the SHA256 sums
+
+ e. Make sure there are no outdated "notes" or edited "date" keys in the
+ ``$RELEASES[X][$PHP_X_VERSION]["source"]`` array
+
+3. Add a short notice to phpweb stating that there is a new release, and
+highlight the major important things (security fixes) and when it is important
+to upgrade.
+
+ a. Call php bin/createNewsEntry in your local phpweb checkout
+
+ b. Add the content for the news entry
+
+4. Commit all the changes (``include/version.inc``, ``archive/archive.xml``,
+``archive/entries/YYYY-MM-DD-N.xml``)
+
+5. Wait an hour or two, then send a mail to php-announce@lists.php.net,
+php-general@lists.php.net and internals@lists.php.net with a text similar to
+the news entry.
+Please make sure that the mail to php-announce@ is its own completely separate email.
+This is to make sure that replies to the announcement on php-general@ or internals@
+will not accidentally hit the php-announce@ mailinglist.
+
+Forking a new release branch
+----------------------------
+
+1. One week prior to cutting X.Y.0beta1, warn internals@ that your version's branch
+ is about to be cut, and that PHP-X.Y will be moving into feature freeze.
+ Try to be specific about when the branch will be cut.
+ Example: http://news.php.net/php.internals/99864
+
+2. Just prior to cutting X.Y.0beta1, create the new branch locally.
+ Add a commit on master after the branch point clearing the NEWS, UPGRADING
+ and UPGRADING.INTERNALS files, updating the version in configure.ac (run
+ ./configure to automatically update main/php_versions.h, too) and Zend/zend.h.
+ Also list the new branch in CONTRIBUTING.md.
+ Example: http://git.php.net/?p=php-src.git;a=commit;h=a63c99b
+ Push the new branch and the commit just added to master.
+
+3. Immediately notify internals@ of the branch cut and advise the new merging order:
+ Example: http://news.php.net/php.internals/99903
+
+4. Update php-web:git.php and wiki.php.net/vcs/gitworkflow to reflect the new branch:
+ Example: https://github.com/php/web-php/commit/74bcad4c770d95f21b7fbeeedbd76d943bb83f23
+
+5. Notify nlopess@ to add PHP_X_Y tag to gcov.php.net
+
+Preparing for the initial stable version (PHP X.Y.0)
+----------------------------------------------------
+
+1. About the time you release the first RC, remind the documentation team
+ (phpdoc@lists.php.net) to write the migration guide. See to it that they
+ have done it before you release the initial stable version, since you want
+ to link to it in the release announcements.
+
+2. Timely get used to the differences in preparing and announcing a stable
+ release.
+
+Prime the selection of the Release Managers of the next version
+---------------------------------------------------------------
+
+1. About three months before the scheduled release of the first alpha of the
+ next minor or major release, issue a call for volunteers on
+ internals@lists.php.net (cf. http://news.php.net/php.internals/98652).
+
+2. Make sure that there are two or more volunteers, and hold a vote if necessary
+ (see https://wiki.php.net/rfc/releaseprocess#release_managers_selection).
+
+3. Help the new release managers with their first steps.
+
+New Release Manager Checklist
+-----------------------------
+
+1. Email systems@ to get setup for access to downloads.php.net and to be added to the
+ release-managers@ distribution list.
+
+2. Create a GPG key for your @php.net address and publish it by editing `include/gpg-keys.inc`
+ in the `web-php` repository, adding the output of `gpg --fingerprint "$USER@php.net"`. Let
+ one or more of the previous RMs sign your key. Publish your public key to pgp.mit.edu with:
+ `gpg --keyserver pgp.mit.edu --send-keys $KEYID`
+
+3. Request karma to edit main/php_version.h and Zend/zend.h. Possibly karma for other restricted parts of
+ php-src might come in question. To edit main/php_version.h in a release branch,
+ you need release manager karma in global_avail.
+
+4. Request karma for web/qa.git and web/php.git for publishing release announcements.
+
+5. Request moderation access to announce@php.net and primary-qa-tester@lists.php.net lists, to
+ be able to moderate your release announcements. All the announcements should be sent from
+ the @php.net alias.
diff --git a/docs/self-contained-extensions.md b/docs/self-contained-extensions.md
new file mode 100644
index 0000000000..1aaec6d6c4
--- /dev/null
+++ b/docs/self-contained-extensions.md
@@ -0,0 +1,167 @@
+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:
+
+ - Configuration file (config.m4)
+ - Source code for your module
+
+ We will describe now how to create these and how to put things
+ together.
+
+PREPARING YOUR SYSTEM
+
+ While the result will run on any system, a developer's setup needs these
+ tools:
+
+ GNU autoconf
+ GNU libtool
+ GNU m4
+
+ All of these are available from
+
+ ftp://ftp.gnu.org/pub/gnu/
+
+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.
+
+ $ 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/* .
+
+ It is time to finish the module. Run:
+
+ $ phpize
+
+ You can now ship the contents of the directory - the extension
+ can live completely on its own.
+
+ The user instructions boil down to
+
+ $ ./configure \
+ [--with-php-config=/path/to/php-config] \
+ [--with-mysql=MYSQL-DIR]
+ $ make install
+
+ The MySQL module will either use the embedded MySQL client
+ library or the MySQL installation in MYSQL-DIR.
+
+
+DEFINING THE NEW EXTENSION
+
+ Our demo extension is called "foobar".
+
+ 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.
+
+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.
+
+------------------------------------------------------------------------------
+PHP_ARG_ENABLE([foobar],
+ [whether to enable foobar],
+ [AS_HELP_STRING([--enable-foobar],
+ [Enable foobar])])
+
+if test "$PHP_FOOBAR" != "no"; then
+ PHP_NEW_EXTENSION(foobar, foo.c bar.c, $ext_shared)
+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.
+
+ 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.
+
+CREATING SOURCE FILES
+
+ 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.
+
+ 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
+
+ Put config.m4 and the source files into one directory. Then, run phpize
+ (this is installed during make install by PHP 4.0).
+
+ For example, if you configured PHP with --prefix=/php, you would run
+
+ $ /php/bin/phpize
+
+ 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.
+
+INSTALLING A SELF-CONTAINED EXTENSION
+
+ An extension can be installed by running:
+
+ $ ./configure \
+ [--with-php-config=/path/to/php-config]
+ $ make install
+
+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.
+
+ 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.
+
+ 3. Add the following lines to your C source file:
+
+ #ifdef COMPILE_DL_FOO
+ ZEND_GET_MODULE(foo)
+ #endif
+
+PECL SITE CONFORMITY
+
+ 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
+
+ 2. The following should be defined in one of the extension header files
+
+ #define PHP_FOO_VERSION "1.2.3"
+
+ 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
new file mode 100644
index 0000000000..6ef69c733a
--- /dev/null
+++ b/docs/streams.md
@@ -0,0 +1,376 @@
+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 <wez@thebrainroom.com>
+
+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.
+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.
+
+The main functions are:
+
+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);
+PHPAPI size_t php_stream_printf(php_stream * stream,
+ const char * fmt, ...);
+PHPAPI int php_stream_eof(php_stream * stream);
+PHPAPI int php_stream_getc(php_stream * stream);
+PHPAPI char *php_stream_gets(php_stream * stream, char *buf, size_t maxlen);
+PHPAPI int php_stream_close(php_stream * stream);
+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.
+
+Opening Streams
+===============
+In most cases, you should use this API:
+
+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.
+
+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:
+
+PHPAPI php_stream *php_stream_fopen_from_file(FILE *file, const char *mode);
+ Convert a FILE * into a stream.
+
+PHPAPI php_stream *php_stream_fopen_tmpfile(void);
+ 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.
+
+There are some network enabled relatives in php_network.h:
+
+PHPAPI php_stream *php_stream_sock_open_from_socket(int socket, int persistent);
+ 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.
+
+PHPAPI php_stream *php_stream_sock_open_unix(const char *path, int persistent,
+ struct timeval *timeout);
+ Open a UNIX domain socket.
+
+
+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:
+
+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.
+
+If you want to read the contents of a stream into an allocated memory buffer,
+you should use:
+
+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.
+
+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:
+
+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.
+
+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: 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: If you are opening a stream and need it to be seekable, use the
+STREAM_MUST_SEEK option to php_stream_open_wrapper();
+
+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.
+
+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:
+
+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);
+
+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:
+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 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
+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:
+
+ if (php_stream_is(stream, PHP_STREAM_IS_STDIO)) {
+ /* can safely cast to FILE* with no adverse side effects */
+ }
+
+You can use:
+
+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:
+
+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.
+
+Stream Internals
+================
+
+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
+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 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:
+
+PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode)
+{
+ FILE * fp = fopen(filename, mode);
+ php_stream * ret;
+
+ if (fp) {
+ ret = php_stream_alloc(&php_stream_stdio_ops, fp, 0, 0, mode);
+ if (ret)
+ return ret;
+
+ fclose(fp);
+ }
+ return NULL;
+}
+
+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).
+
+The prototype for php_stream_alloc is this:
+
+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 :-)
+
+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
+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.
+
+For structured state you might have this:
+
+struct my_state {
+ MYSQL conn;
+ MYSQL_RES * result;
+};
+
+struct my_state * state = pemalloc(sizeof(struct my_state), persistent);
+
+/* initialize the connection, and run a query, using the fields in state to
+ * hold the results */
+
+state->result = mysql_use_result(&state->conn);
+
+/* now allocate the stream itself */
+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
+example).
+
+For example, for reading from this weird MySQL stream:
+
+static size_t php_mysqlop_read(php_stream * stream, char * buf, size_t count)
+{
+ struct my_state * state = (struct my_state*)stream->abstract;
+
+ if (buf == NULL && count == 0) {
+ /* in this special case, php_streams is asking if we have reached the
+ * end of file */
+ if (... at end of file ...)
+ return EOF;
+ else
+ return 0;
+ }
+
+ /* pull out some data from the stream and put it in buf */
+ ... mysql_fetch_row(state->result) ...
+ /* we could do something strange, like format the data as XML here,
+ and place that in the buf, but that brings in some complexities,
+ 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:
+
+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.
+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.
diff --git a/docs/unix-build-system.md b/docs/unix-build-system.md
new file mode 100644
index 0000000000..a184b909ba
--- /dev/null
+++ b/docs/unix-build-system.md
@@ -0,0 +1,123 @@
+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_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.
+
+The full syntax:
+
+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.
+
+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:
+
+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).
+
+Now, you need to tell the build system that you want to build files
+in a directory called $ext_builddir/lib:
+
+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.
+
+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.
+
+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:
+
+Instead of using PHP_SAPI=foo/PHP_BUILD_XYZ, you will need to type
+
+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).
+
+For example for APXS:
+
+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.
+
+Have a look at the well documented macros
+PHP_ADD_SOURCES(_X) in acinclude.m4.