summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorPeter Kokot <peterkokot@gmail.com>2019-03-30 19:39:32 +0100
committerPeter Kokot <peterkokot@gmail.com>2019-03-30 19:39:32 +0100
commit7915d8bbca2f388e95dd1cae831f3297053d907a (patch)
treee9f46fae9827d14600fa655dadcc66a2b521fd24 /docs
parentc6eac0d5be24e90faa5206e38cddf2c685712aaa (diff)
parent8346b4c9f149c1a3d4e0631007e71bbbebd0b87d (diff)
downloadphp-git-7915d8bbca2f388e95dd1cae831f3297053d907a.tar.gz
Merge branch 'PHP-7.4'
* PHP-7.4: Move README files to a dedicated docs directory
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.md398
-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, 1709 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..fdc2440748
--- /dev/null
+++ b/docs/release-process.md
@@ -0,0 +1,398 @@
+=======================
+ 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_Y=major_minor version number)
+
+ a. ``$PHP_X_Y_RC`` = "5.4.0RC1" (should be set to "false" before)
+
+ b. ``$PHP_X_Y_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 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. Update ``phpweb/include/version.inc`` (X_Y=major_minor release number):
+
+ a. ``$PHP_X_Y_VERSION`` to the correct version
+
+ b. ``$PHP_X_Y_DATE`` to the release date
+
+ c. ``$PHP_X_Y_SHA256`` array and update all the SHA256 sums
+
+ d. set ``$PHP_X_Y_RC`` to false!
+
+ e. Make sure there are no outdated "notes" or edited "date" keys in the
+ ``$RELEASES[X][$PHP_X_VERSION]["source"]`` array
+
+ f. Only for the first revision of a major or minor release bump
+ ``$PHP_X_VERSION``, ``$PHP_X_DATE`` and ``$PHP_X_RC_DATE``.
+
+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. Commit and push all the changes to their respective git repos
+
+8. **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)
+
+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. Update ``phpweb/include/version.inc`` (X_Y=major_minor release number):
+
+ a. If only releasing for one OS, make sure you edit only those variables
+
+ b. ``$PHP_X_Y_VERSION`` to the correct version
+
+ c. ``$PHP_X_Y_DATE`` to the release date
+
+ d. ``$PHP_X_Y_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 php-announce@lists.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..8db9bcde2f
--- /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_php.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.