summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2013-03-14 05:42:27 +0000
committer <>2013-04-03 16:25:08 +0000
commitc4dd7a1a684490673e25aaf4fabec5df138854c4 (patch)
tree4d57c44caae4480efff02b90b9be86f44bf25409 /main
downloadphp2-c4dd7a1a684490673e25aaf4fabec5df138854c4.tar.gz
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'main')
-rw-r--r--main/SAPI.c1094
-rw-r--r--main/SAPI.h317
-rw-r--r--main/alloca.c501
-rw-r--r--main/build-defs.h.in91
-rw-r--r--main/fopen_wrappers.c817
-rw-r--r--main/fopen_wrappers.h64
-rw-r--r--main/getopt.c199
-rw-r--r--main/internal_functions.c.in48
-rw-r--r--main/internal_functions_nw.c100
-rw-r--r--main/internal_functions_win32.c208
-rw-r--r--main/logos.h1080
-rw-r--r--main/main.c2645
-rw-r--r--main/mergesort.c358
-rw-r--r--main/network.c1202
-rw-r--r--main/output.c1578
-rw-r--r--main/php.h457
-rw-r--r--main/php_compat.h378
-rw-r--r--main/php_config.h.in2480
-rw-r--r--main/php_content_types.c100
-rw-r--r--main/php_content_types.h31
-rw-r--r--main/php_getopt.h57
-rw-r--r--main/php_globals.h175
-rw-r--r--main/php_ini.c916
-rw-r--r--main/php_ini.h90
-rw-r--r--main/php_logos.c99
-rw-r--r--main/php_logos.h34
-rw-r--r--main/php_main.h61
-rw-r--r--main/php_memory_streams.h68
-rw-r--r--main/php_network.h321
-rw-r--r--main/php_open_temporary_file.c314
-rw-r--r--main/php_open_temporary_file.h32
-rw-r--r--main/php_output.h279
-rw-r--r--main/php_reentrancy.h133
-rw-r--r--main/php_scandir.c136
-rw-r--r--main/php_scandir.h54
-rw-r--r--main/php_sprintf.c50
-rw-r--r--main/php_streams.h611
-rw-r--r--main/php_syslog.h52
-rw-r--r--main/php_ticks.c86
-rw-r--r--main/php_ticks.h41
-rw-r--r--main/php_variables.c865
-rw-r--r--main/php_variables.h49
-rw-r--r--main/php_version.h8
-rw-r--r--main/reentrancy.c450
-rw-r--r--main/rfc1867.c1299
-rw-r--r--main/rfc1867.h91
-rw-r--r--main/snprintf.c1316
-rw-r--r--main/snprintf.h179
-rw-r--r--main/spprintf.c831
-rw-r--r--main/spprintf.h52
-rw-r--r--main/streams/cast.c418
-rw-r--r--main/streams/filter.c544
-rw-r--r--main/streams/glob_wrapper.c291
-rw-r--r--main/streams/memory.c758
-rw-r--r--main/streams/mmap.c75
-rw-r--r--main/streams/php_stream_context.h136
-rw-r--r--main/streams/php_stream_filter_api.h162
-rw-r--r--main/streams/php_stream_glob_wrapper.h44
-rw-r--r--main/streams/php_stream_mmap.h88
-rw-r--r--main/streams/php_stream_plain_wrapper.h66
-rw-r--r--main/streams/php_stream_transport.h211
-rw-r--r--main/streams/php_stream_userspace.h35
-rw-r--r--main/streams/php_streams_int.h71
-rw-r--r--main/streams/plain_wrapper.c1505
-rw-r--r--main/streams/streams.c2397
-rw-r--r--main/streams/transports.c532
-rw-r--r--main/streams/userspace.c1676
-rw-r--r--main/streams/xp_socket.c838
-rw-r--r--main/strlcat.c106
-rw-r--r--main/strlcpy.c103
-rw-r--r--main/win32_internal_function_disabled.h34
-rw-r--r--main/win95nt.h89
72 files changed, 32676 insertions, 0 deletions
diff --git a/main/SAPI.c b/main/SAPI.c
new file mode 100644
index 0000000..dcb2da6
--- /dev/null
+++ b/main/SAPI.c
@@ -0,0 +1,1094 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Original design: Shane Caraveo <shane@caraveo.com> |
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include <ctype.h>
+#include <sys/stat.h>
+
+#include "php.h"
+#include "SAPI.h"
+#include "php_variables.h"
+#include "php_ini.h"
+#include "ext/standard/php_string.h"
+#include "ext/standard/pageinfo.h"
+#if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)
+#include "ext/pcre/php_pcre.h"
+#endif
+#ifdef ZTS
+#include "TSRM.h"
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#elif defined(PHP_WIN32)
+#include "win32/time.h"
+#endif
+
+#include "rfc1867.h"
+
+#ifdef PHP_WIN32
+#define STRCASECMP stricmp
+#else
+#define STRCASECMP strcasecmp
+#endif
+
+#include "php_content_types.h"
+
+#ifdef ZTS
+SAPI_API int sapi_globals_id;
+#else
+sapi_globals_struct sapi_globals;
+#endif
+
+static void sapi_globals_ctor(sapi_globals_struct *sapi_globals TSRMLS_DC)
+{
+ memset(sapi_globals, 0, sizeof(*sapi_globals));
+ zend_hash_init_ex(&sapi_globals->known_post_content_types, 5, NULL, NULL, 1, 0);
+ php_setup_sapi_content_types(TSRMLS_C);
+}
+
+static void sapi_globals_dtor(sapi_globals_struct *sapi_globals TSRMLS_DC)
+{
+ zend_hash_destroy(&sapi_globals->known_post_content_types);
+}
+
+/* True globals (no need for thread safety) */
+SAPI_API sapi_module_struct sapi_module;
+
+
+SAPI_API void sapi_startup(sapi_module_struct *sf)
+{
+#ifdef ZEND_SIGNALS
+ zend_signal_startup();
+#endif
+
+ sf->ini_entries = NULL;
+ sapi_module = *sf;
+
+#ifdef ZTS
+ ts_allocate_id(&sapi_globals_id, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor);
+# ifdef PHP_WIN32
+ _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
+# endif
+#else
+ sapi_globals_ctor(&sapi_globals);
+#endif
+
+ virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */
+
+#ifdef PHP_WIN32
+ tsrm_win32_startup();
+#endif
+
+ reentrancy_startup();
+}
+
+SAPI_API void sapi_shutdown(void)
+{
+#ifdef ZTS
+ ts_free_id(sapi_globals_id);
+#else
+ sapi_globals_dtor(&sapi_globals);
+#endif
+
+ reentrancy_shutdown();
+
+ virtual_cwd_shutdown();
+
+#ifdef PHP_WIN32
+ tsrm_win32_shutdown();
+#endif
+}
+
+
+SAPI_API void sapi_free_header(sapi_header_struct *sapi_header)
+{
+ efree(sapi_header->header);
+}
+
+/* {{{ proto bool header_register_callback(mixed callback)
+ call a header function */
+PHP_FUNCTION(header_register_callback)
+{
+ zval *callback_func;
+ char *callback_name;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &callback_func) == FAILURE) {
+ return;
+ }
+
+ if (!zend_is_callable(callback_func, 0, &callback_name TSRMLS_CC)) {
+ efree(callback_name);
+ RETURN_FALSE;
+ }
+ efree(callback_name);
+
+ if (SG(callback_func)) {
+ zval_ptr_dtor(&SG(callback_func));
+ SG(fci_cache) = empty_fcall_info_cache;
+ }
+
+ Z_ADDREF_P(callback_func);
+
+ SG(callback_func) = callback_func;
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+static void sapi_run_header_callback(TSRMLS_D)
+{
+ int error;
+ zend_fcall_info fci;
+ zval *retval_ptr = NULL;
+
+ fci.size = sizeof(fci);
+ fci.function_table = EG(function_table);
+ fci.object_ptr = NULL;
+ fci.function_name = SG(callback_func);
+ fci.retval_ptr_ptr = &retval_ptr;
+ fci.param_count = 0;
+ fci.params = NULL;
+ fci.no_separation = 0;
+ fci.symbol_table = NULL;
+
+ error = zend_call_function(&fci, &SG(fci_cache) TSRMLS_CC);
+ if (error == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the sapi_header_callback");
+ } else if (retval_ptr) {
+ zval_ptr_dtor(&retval_ptr);
+ }
+}
+
+SAPI_API void sapi_handle_post(void *arg TSRMLS_DC)
+{
+ if (SG(request_info).post_entry && SG(request_info).content_type_dup) {
+ SG(request_info).post_entry->post_handler(SG(request_info).content_type_dup, arg TSRMLS_CC);
+ if (SG(request_info).post_data) {
+ efree(SG(request_info).post_data);
+ SG(request_info).post_data = NULL;
+ }
+ efree(SG(request_info).content_type_dup);
+ SG(request_info).content_type_dup = NULL;
+ }
+}
+
+static void sapi_read_post_data(TSRMLS_D)
+{
+ sapi_post_entry *post_entry;
+ uint content_type_length = strlen(SG(request_info).content_type);
+ char *content_type = estrndup(SG(request_info).content_type, content_type_length);
+ char *p;
+ char oldchar=0;
+ void (*post_reader_func)(TSRMLS_D) = NULL;
+
+
+ /* dedicated implementation for increased performance:
+ * - Make the content type lowercase
+ * - Trim descriptive data, stay with the content-type only
+ */
+ for (p=content_type; p<content_type+content_type_length; p++) {
+ switch (*p) {
+ case ';':
+ case ',':
+ case ' ':
+ content_type_length = p-content_type;
+ oldchar = *p;
+ *p = 0;
+ break;
+ default:
+ *p = tolower(*p);
+ break;
+ }
+ }
+
+ /* now try to find an appropriate POST content handler */
+ if (zend_hash_find(&SG(known_post_content_types), content_type,
+ content_type_length+1, (void **) &post_entry) == SUCCESS) {
+ /* found one, register it for use */
+ SG(request_info).post_entry = post_entry;
+ post_reader_func = post_entry->post_reader;
+ } else {
+ /* fallback */
+ SG(request_info).post_entry = NULL;
+ if (!sapi_module.default_post_reader) {
+ /* no default reader ? */
+ SG(request_info).content_type_dup = NULL;
+ sapi_module.sapi_error(E_WARNING, "Unsupported content type: '%s'", content_type);
+ return;
+ }
+ }
+ if (oldchar) {
+ *(p-1) = oldchar;
+ }
+
+ SG(request_info).content_type_dup = content_type;
+
+ if(post_reader_func) {
+ post_reader_func(TSRMLS_C);
+ }
+
+ if(sapi_module.default_post_reader) {
+ sapi_module.default_post_reader(TSRMLS_C);
+ }
+}
+
+
+SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data)
+{
+ int read_bytes;
+ int allocated_bytes=SAPI_POST_BLOCK_SIZE+1;
+
+ if ((SG(post_max_size) > 0) && (SG(request_info).content_length > SG(post_max_size))) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes",
+ SG(request_info).content_length, SG(post_max_size));
+ return;
+ }
+ SG(request_info).post_data = emalloc(allocated_bytes);
+
+ for (;;) {
+ read_bytes = sapi_module.read_post(SG(request_info).post_data+SG(read_post_bytes), SAPI_POST_BLOCK_SIZE TSRMLS_CC);
+ if (read_bytes<=0) {
+ break;
+ }
+ SG(read_post_bytes) += read_bytes;
+ if ((SG(post_max_size) > 0) && (SG(read_post_bytes) > SG(post_max_size))) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Actual POST length does not match Content-Length, and exceeds %ld bytes", SG(post_max_size));
+ break;
+ }
+ if (read_bytes < SAPI_POST_BLOCK_SIZE) {
+ break;
+ }
+ if (SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE >= allocated_bytes) {
+ allocated_bytes = SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE+1;
+ SG(request_info).post_data = erealloc(SG(request_info).post_data, allocated_bytes);
+ }
+ }
+ SG(request_info).post_data[SG(read_post_bytes)] = 0; /* terminating NULL */
+ SG(request_info).post_data_length = SG(read_post_bytes);
+}
+
+
+static inline char *get_default_content_type(uint prefix_len, uint *len TSRMLS_DC)
+{
+ char *mimetype, *charset, *content_type;
+ uint mimetype_len, charset_len;
+
+ if (SG(default_mimetype)) {
+ mimetype = SG(default_mimetype);
+ mimetype_len = strlen(SG(default_mimetype));
+ } else {
+ mimetype = SAPI_DEFAULT_MIMETYPE;
+ mimetype_len = sizeof(SAPI_DEFAULT_MIMETYPE) - 1;
+ }
+ if (SG(default_charset)) {
+ charset = SG(default_charset);
+ charset_len = strlen(SG(default_charset));
+ } else {
+ charset = SAPI_DEFAULT_CHARSET;
+ charset_len = sizeof(SAPI_DEFAULT_CHARSET) - 1;
+ }
+
+ if (*charset && strncasecmp(mimetype, "text/", 5) == 0) {
+ char *p;
+
+ *len = prefix_len + mimetype_len + sizeof("; charset=") - 1 + charset_len;
+ content_type = (char*)emalloc(*len + 1);
+ p = content_type + prefix_len;
+ memcpy(p, mimetype, mimetype_len);
+ p += mimetype_len;
+ memcpy(p, "; charset=", sizeof("; charset=") - 1);
+ p += sizeof("; charset=") - 1;
+ memcpy(p, charset, charset_len + 1);
+ } else {
+ *len = prefix_len + mimetype_len;
+ content_type = (char*)emalloc(*len + 1);
+ memcpy(content_type + prefix_len, mimetype, mimetype_len + 1);
+ }
+ return content_type;
+}
+
+
+SAPI_API char *sapi_get_default_content_type(TSRMLS_D)
+{
+ uint len;
+
+ return get_default_content_type(0, &len TSRMLS_CC);
+}
+
+
+SAPI_API void sapi_get_default_content_type_header(sapi_header_struct *default_header TSRMLS_DC)
+{
+ uint len;
+
+ default_header->header = get_default_content_type(sizeof("Content-type: ")-1, &len TSRMLS_CC);
+ default_header->header_len = len;
+ memcpy(default_header->header, "Content-type: ", sizeof("Content-type: ") - 1);
+}
+
+/*
+ * Add charset on content-type header if the MIME type starts with
+ * "text/", the default_charset directive is not empty and
+ * there is not already a charset option in there.
+ *
+ * If "mimetype" is non-NULL, it should point to a pointer allocated
+ * with emalloc(). If a charset is added, the string will be
+ * re-allocated and the new length is returned. If mimetype is
+ * unchanged, 0 is returned.
+ *
+ */
+SAPI_API size_t sapi_apply_default_charset(char **mimetype, size_t len TSRMLS_DC)
+{
+ char *charset, *newtype;
+ size_t newlen;
+ charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
+
+ if (*mimetype != NULL) {
+ if (*charset && strncmp(*mimetype, "text/", 5) == 0 && strstr(*mimetype, "charset=") == NULL) {
+ newlen = len + (sizeof(";charset=")-1) + strlen(charset);
+ newtype = emalloc(newlen + 1);
+ PHP_STRLCPY(newtype, *mimetype, newlen + 1, len);
+ strlcat(newtype, ";charset=", newlen + 1);
+ strlcat(newtype, charset, newlen + 1);
+ efree(*mimetype);
+ *mimetype = newtype;
+ return newlen;
+ }
+ }
+ return 0;
+}
+
+SAPI_API void sapi_activate_headers_only(TSRMLS_D)
+{
+ if (SG(request_info).headers_read == 1)
+ return;
+ SG(request_info).headers_read = 1;
+ zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct),
+ (void (*)(void *)) sapi_free_header, 0);
+ SG(sapi_headers).send_default_content_type = 1;
+
+ /* SG(sapi_headers).http_response_code = 200; */
+ SG(sapi_headers).http_status_line = NULL;
+ SG(sapi_headers).mimetype = NULL;
+ SG(read_post_bytes) = 0;
+ SG(request_info).post_data = NULL;
+ SG(request_info).raw_post_data = NULL;
+ SG(request_info).current_user = NULL;
+ SG(request_info).current_user_length = 0;
+ SG(request_info).no_headers = 0;
+ SG(request_info).post_entry = NULL;
+ SG(global_request_time) = 0;
+
+ /*
+ * It's possible to override this general case in the activate() callback,
+ * if necessary.
+ */
+ if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
+ SG(request_info).headers_only = 1;
+ } else {
+ SG(request_info).headers_only = 0;
+ }
+ if (SG(server_context)) {
+ SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
+ if (sapi_module.activate) {
+ sapi_module.activate(TSRMLS_C);
+ }
+ }
+ if (sapi_module.input_filter_init ) {
+ sapi_module.input_filter_init(TSRMLS_C);
+ }
+}
+
+/*
+ * Called from php_request_startup() for every request.
+ */
+
+SAPI_API void sapi_activate(TSRMLS_D)
+{
+ zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0);
+ SG(sapi_headers).send_default_content_type = 1;
+
+ /*
+ SG(sapi_headers).http_response_code = 200;
+ */
+ SG(sapi_headers).http_status_line = NULL;
+ SG(sapi_headers).mimetype = NULL;
+ SG(headers_sent) = 0;
+ SG(callback_run) = 0;
+ SG(callback_func) = NULL;
+ SG(read_post_bytes) = 0;
+ SG(request_info).post_data = NULL;
+ SG(request_info).raw_post_data = NULL;
+ SG(request_info).current_user = NULL;
+ SG(request_info).current_user_length = 0;
+ SG(request_info).no_headers = 0;
+ SG(request_info).post_entry = NULL;
+ SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
+ SG(global_request_time) = 0;
+
+ /* It's possible to override this general case in the activate() callback, if necessary. */
+ if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
+ SG(request_info).headers_only = 1;
+ } else {
+ SG(request_info).headers_only = 0;
+ }
+ SG(rfc1867_uploaded_files) = NULL;
+
+ /* Handle request method */
+ if (SG(server_context)) {
+ if (PG(enable_post_data_reading) && SG(request_info).request_method) {
+ if (SG(request_info).content_type && !strcmp(SG(request_info).request_method, "POST")) {
+ /* HTTP POST may contain form data to be processed into variables
+ * depending on given content type */
+ sapi_read_post_data(TSRMLS_C);
+ } else {
+ /* Any other method with content payload will fill $HTTP_RAW_POST_DATA
+ * if it is enabled by always_populate_raw_post_data.
+ * It's up to the webserver to decide whether to allow a method or not. */
+ SG(request_info).content_type_dup = NULL;
+ if (sapi_module.default_post_reader) {
+ sapi_module.default_post_reader(TSRMLS_C);
+ }
+ }
+ } else {
+ SG(request_info).content_type_dup = NULL;
+ }
+
+ /* Cookies */
+ SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
+
+ if (sapi_module.activate) {
+ sapi_module.activate(TSRMLS_C);
+ }
+ }
+ if (sapi_module.input_filter_init) {
+ sapi_module.input_filter_init(TSRMLS_C);
+ }
+}
+
+
+static void sapi_send_headers_free(TSRMLS_D)
+{
+ if (SG(sapi_headers).http_status_line) {
+ efree(SG(sapi_headers).http_status_line);
+ SG(sapi_headers).http_status_line = NULL;
+ }
+}
+
+SAPI_API void sapi_deactivate(TSRMLS_D)
+{
+ zend_llist_destroy(&SG(sapi_headers).headers);
+ if (SG(request_info).post_data) {
+ efree(SG(request_info).post_data);
+ } else if (SG(server_context)) {
+ if(sapi_module.read_post) {
+ /* make sure we've consumed all request input data */
+ char dummy[SAPI_POST_BLOCK_SIZE];
+ int read_bytes;
+
+ while((read_bytes = sapi_module.read_post(dummy, sizeof(dummy)-1 TSRMLS_CC)) > 0) {
+ SG(read_post_bytes) += read_bytes;
+ }
+ }
+ }
+ if (SG(request_info).raw_post_data) {
+ efree(SG(request_info).raw_post_data);
+ }
+ if (SG(request_info).auth_user) {
+ efree(SG(request_info).auth_user);
+ }
+ if (SG(request_info).auth_password) {
+ efree(SG(request_info).auth_password);
+ }
+ if (SG(request_info).auth_digest) {
+ efree(SG(request_info).auth_digest);
+ }
+ if (SG(request_info).content_type_dup) {
+ efree(SG(request_info).content_type_dup);
+ }
+ if (SG(request_info).current_user) {
+ efree(SG(request_info).current_user);
+ }
+ if (sapi_module.deactivate) {
+ sapi_module.deactivate(TSRMLS_C);
+ }
+ if (SG(rfc1867_uploaded_files)) {
+ destroy_uploaded_files_hash(TSRMLS_C);
+ }
+ if (SG(sapi_headers).mimetype) {
+ efree(SG(sapi_headers).mimetype);
+ SG(sapi_headers).mimetype = NULL;
+ }
+ sapi_send_headers_free(TSRMLS_C);
+ SG(sapi_started) = 0;
+ SG(headers_sent) = 0;
+ SG(callback_run) = 0;
+ if (SG(callback_func)) {
+ zval_ptr_dtor(&SG(callback_func));
+ }
+ SG(request_info).headers_read = 0;
+ SG(global_request_time) = 0;
+}
+
+
+SAPI_API void sapi_initialize_empty_request(TSRMLS_D)
+{
+ SG(server_context) = NULL;
+ SG(request_info).request_method = NULL;
+ SG(request_info).auth_digest = SG(request_info).auth_user = SG(request_info).auth_password = NULL;
+ SG(request_info).content_type_dup = NULL;
+}
+
+
+static int sapi_extract_response_code(const char *header_line)
+{
+ int code = 200;
+ const char *ptr;
+
+ for (ptr = header_line; *ptr; ptr++) {
+ if (*ptr == ' ' && *(ptr + 1) != ' ') {
+ code = atoi(ptr + 1);
+ break;
+ }
+ }
+
+ return code;
+}
+
+
+static void sapi_update_response_code(int ncode TSRMLS_DC)
+{
+ /* if the status code did not change, we do not want
+ to change the status line, and no need to change the code */
+ if (SG(sapi_headers).http_response_code == ncode) {
+ return;
+ }
+
+ if (SG(sapi_headers).http_status_line) {
+ efree(SG(sapi_headers).http_status_line);
+ SG(sapi_headers).http_status_line = NULL;
+ }
+ SG(sapi_headers).http_response_code = ncode;
+}
+
+/*
+ * since zend_llist_del_element only remove one matched item once,
+ * we should remove them by ourself
+ */
+static void sapi_remove_header(zend_llist *l, char *name, uint len) {
+ sapi_header_struct *header;
+ zend_llist_element *next;
+ zend_llist_element *current=l->head;
+
+ while (current) {
+ header = (sapi_header_struct *)(current->data);
+ next = current->next;
+ if (header->header_len > len && header->header[len] == ':'
+ && !strncasecmp(header->header, name, len)) {
+ if (current->prev) {
+ current->prev->next = next;
+ } else {
+ l->head = next;
+ }
+ if (next) {
+ next->prev = current->prev;
+ } else {
+ l->tail = current->prev;
+ }
+ sapi_free_header(header);
+ efree(current);
+ --l->count;
+ }
+ current = next;
+ }
+}
+
+SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace TSRMLS_DC)
+{
+ sapi_header_line ctr = {0};
+ int r;
+
+ ctr.line = header_line;
+ ctr.line_len = header_line_len;
+
+ r = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD,
+ &ctr TSRMLS_CC);
+
+ if (!duplicate)
+ efree(header_line);
+
+ return r;
+}
+
+static void sapi_header_add_op(sapi_header_op_enum op, sapi_header_struct *sapi_header TSRMLS_DC)
+{
+ if (!sapi_module.header_handler ||
+ (SAPI_HEADER_ADD & sapi_module.header_handler(sapi_header, op, &SG(sapi_headers) TSRMLS_CC))) {
+ if (op == SAPI_HEADER_REPLACE) {
+ char *colon_offset = strchr(sapi_header->header, ':');
+
+ if (colon_offset) {
+ char sav = *colon_offset;
+
+ *colon_offset = 0;
+ sapi_remove_header(&SG(sapi_headers).headers, sapi_header->header, strlen(sapi_header->header));
+ *colon_offset = sav;
+ }
+ }
+ zend_llist_add_element(&SG(sapi_headers).headers, (void *) sapi_header);
+ } else {
+ sapi_free_header(sapi_header);
+ }
+}
+
+SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
+{
+ sapi_header_struct sapi_header;
+ char *colon_offset;
+ char *header_line;
+ uint header_line_len;
+ int http_response_code;
+
+ if (SG(headers_sent) && !SG(request_info).no_headers) {
+ const char *output_start_filename = php_output_get_start_filename(TSRMLS_C);
+ int output_start_lineno = php_output_get_start_lineno(TSRMLS_C);
+
+ if (output_start_filename) {
+ sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)",
+ output_start_filename, output_start_lineno);
+ } else {
+ sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent");
+ }
+ return FAILURE;
+ }
+
+ switch (op) {
+ case SAPI_HEADER_SET_STATUS:
+ sapi_update_response_code((int)(zend_intptr_t) arg TSRMLS_CC);
+ return SUCCESS;
+
+ case SAPI_HEADER_ADD:
+ case SAPI_HEADER_REPLACE:
+ case SAPI_HEADER_DELETE: {
+ sapi_header_line *p = arg;
+
+ if (!p->line || !p->line_len) {
+ return FAILURE;
+ }
+ header_line = p->line;
+ header_line_len = p->line_len;
+ http_response_code = p->response_code;
+ break;
+ }
+
+ case SAPI_HEADER_DELETE_ALL:
+ if (sapi_module.header_handler) {
+ sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
+ }
+ zend_llist_clean(&SG(sapi_headers).headers);
+ return SUCCESS;
+
+ default:
+ return FAILURE;
+ }
+
+ header_line = estrndup(header_line, header_line_len);
+
+ /* cut of trailing spaces, linefeeds and carriage-returns */
+ if (header_line_len && isspace(header_line[header_line_len-1])) {
+ do {
+ header_line_len--;
+ } while(header_line_len && isspace(header_line[header_line_len-1]));
+ header_line[header_line_len]='\0';
+ }
+
+ if (op == SAPI_HEADER_DELETE) {
+ if (strchr(header_line, ':')) {
+ efree(header_line);
+ sapi_module.sapi_error(E_WARNING, "Header to delete may not contain colon.");
+ return FAILURE;
+ }
+ if (sapi_module.header_handler) {
+ sapi_header.header = header_line;
+ sapi_header.header_len = header_line_len;
+ sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
+ }
+ sapi_remove_header(&SG(sapi_headers).headers, header_line, header_line_len);
+ efree(header_line);
+ return SUCCESS;
+ } else {
+ /* new line/NUL character safety check */
+ int i;
+ for (i = 0; i < header_line_len; i++) {
+ /* RFC 2616 allows new lines if followed by SP or HT */
+ int illegal_break =
+ (header_line[i+1] != ' ' && header_line[i+1] != '\t')
+ && (
+ header_line[i] == '\n'
+ || (header_line[i] == '\r' && header_line[i+1] != '\n'));
+ if (illegal_break) {
+ efree(header_line);
+ sapi_module.sapi_error(E_WARNING, "Header may not contain "
+ "more than a single header, new line detected");
+ return FAILURE;
+ }
+ if (header_line[i] == '\0') {
+ efree(header_line);
+ sapi_module.sapi_error(E_WARNING, "Header may not contain NUL bytes");
+ return FAILURE;
+ }
+ }
+ }
+
+ sapi_header.header = header_line;
+ sapi_header.header_len = header_line_len;
+
+ /* Check the header for a few cases that we have special support for in SAPI */
+ if (header_line_len>=5
+ && !strncasecmp(header_line, "HTTP/", 5)) {
+ /* filter out the response code */
+ sapi_update_response_code(sapi_extract_response_code(header_line) TSRMLS_CC);
+ /* sapi_update_response_code doesn't free the status line if the code didn't change */
+ if (SG(sapi_headers).http_status_line) {
+ efree(SG(sapi_headers).http_status_line);
+ }
+ SG(sapi_headers).http_status_line = header_line;
+ return SUCCESS;
+ } else {
+ colon_offset = strchr(header_line, ':');
+ if (colon_offset) {
+ *colon_offset = 0;
+ if (!STRCASECMP(header_line, "Content-Type")) {
+ char *ptr = colon_offset+1, *mimetype = NULL, *newheader;
+ size_t len = header_line_len - (ptr - header_line), newlen;
+ while (*ptr == ' ') {
+ ptr++;
+ len--;
+ }
+
+ /* Disable possible output compression for images */
+ if (!strncmp(ptr, "image/", sizeof("image/")-1)) {
+ zend_alter_ini_entry("zlib.output_compression", sizeof("zlib.output_compression"), "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ }
+
+ mimetype = estrdup(ptr);
+ newlen = sapi_apply_default_charset(&mimetype, len TSRMLS_CC);
+ if (!SG(sapi_headers).mimetype){
+ SG(sapi_headers).mimetype = estrdup(mimetype);
+ }
+
+ if (newlen != 0) {
+ newlen += sizeof("Content-type: ");
+ newheader = emalloc(newlen);
+ PHP_STRLCPY(newheader, "Content-type: ", newlen, sizeof("Content-type: ")-1);
+ strlcat(newheader, mimetype, newlen);
+ sapi_header.header = newheader;
+ sapi_header.header_len = newlen - 1;
+ efree(header_line);
+ }
+ efree(mimetype);
+ SG(sapi_headers).send_default_content_type = 0;
+ } else if (!STRCASECMP(header_line, "Content-Length")) {
+ /* Script is setting Content-length. The script cannot reasonably
+ * know the size of the message body after compression, so it's best
+ * do disable compression altogether. This contributes to making scripts
+ * portable between setups that have and don't have zlib compression
+ * enabled globally. See req #44164 */
+ zend_alter_ini_entry("zlib.output_compression", sizeof("zlib.output_compression"),
+ "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ } else if (!STRCASECMP(header_line, "Location")) {
+ if ((SG(sapi_headers).http_response_code < 300 ||
+ SG(sapi_headers).http_response_code > 307) &&
+ SG(sapi_headers).http_response_code != 201) {
+ /* Return a Found Redirect if one is not already specified */
+ if (http_response_code) { /* user specified redirect code */
+ sapi_update_response_code(http_response_code TSRMLS_CC);
+ } else if (SG(request_info).proto_num > 1000 &&
+ SG(request_info).request_method &&
+ strcmp(SG(request_info).request_method, "HEAD") &&
+ strcmp(SG(request_info).request_method, "GET")) {
+ sapi_update_response_code(303 TSRMLS_CC);
+ } else {
+ sapi_update_response_code(302 TSRMLS_CC);
+ }
+ }
+ } else if (!STRCASECMP(header_line, "WWW-Authenticate")) { /* HTTP Authentication */
+ sapi_update_response_code(401 TSRMLS_CC); /* authentication-required */
+ }
+ if (sapi_header.header==header_line) {
+ *colon_offset = ':';
+ }
+ }
+ }
+ if (http_response_code) {
+ sapi_update_response_code(http_response_code TSRMLS_CC);
+ }
+ sapi_header_add_op(op, &sapi_header TSRMLS_CC);
+ return SUCCESS;
+}
+
+
+SAPI_API int sapi_send_headers(TSRMLS_D)
+{
+ int retval;
+ int ret = FAILURE;
+
+ if (SG(headers_sent) || SG(request_info).no_headers || SG(callback_run)) {
+ return SUCCESS;
+ }
+
+ /* Success-oriented. We set headers_sent to 1 here to avoid an infinite loop
+ * in case of an error situation.
+ */
+ if (SG(sapi_headers).send_default_content_type && sapi_module.send_headers) {
+ sapi_header_struct default_header;
+ uint len;
+
+ SG(sapi_headers).mimetype = get_default_content_type(0, &len TSRMLS_CC);
+ default_header.header_len = sizeof("Content-type: ") - 1 + len;
+ default_header.header = emalloc(default_header.header_len + 1);
+ memcpy(default_header.header, "Content-type: ", sizeof("Content-type: ") - 1);
+ memcpy(default_header.header + sizeof("Content-type: ") - 1, SG(sapi_headers).mimetype, len + 1);
+ sapi_header_add_op(SAPI_HEADER_ADD, &default_header TSRMLS_CC);
+ SG(sapi_headers).send_default_content_type = 0;
+ }
+
+ if (SG(callback_func) && !SG(callback_run)) {
+ SG(callback_run) = 1;
+ sapi_run_header_callback(TSRMLS_C);
+ }
+
+ SG(headers_sent) = 1;
+
+ if (sapi_module.send_headers) {
+ retval = sapi_module.send_headers(&SG(sapi_headers) TSRMLS_CC);
+ } else {
+ retval = SAPI_HEADER_DO_SEND;
+ }
+
+ switch (retval) {
+ case SAPI_HEADER_SENT_SUCCESSFULLY:
+ ret = SUCCESS;
+ break;
+ case SAPI_HEADER_DO_SEND: {
+ sapi_header_struct http_status_line;
+ char buf[255];
+
+ if (SG(sapi_headers).http_status_line) {
+ http_status_line.header = SG(sapi_headers).http_status_line;
+ http_status_line.header_len = strlen(SG(sapi_headers).http_status_line);
+ } else {
+ http_status_line.header = buf;
+ http_status_line.header_len = slprintf(buf, sizeof(buf), "HTTP/1.0 %d X", SG(sapi_headers).http_response_code);
+ }
+ sapi_module.send_header(&http_status_line, SG(server_context) TSRMLS_CC);
+ }
+ zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context) TSRMLS_CC);
+ if(SG(sapi_headers).send_default_content_type) {
+ sapi_header_struct default_header;
+
+ sapi_get_default_content_type_header(&default_header TSRMLS_CC);
+ sapi_module.send_header(&default_header, SG(server_context) TSRMLS_CC);
+ sapi_free_header(&default_header);
+ }
+ sapi_module.send_header(NULL, SG(server_context) TSRMLS_CC);
+ ret = SUCCESS;
+ break;
+ case SAPI_HEADER_SEND_FAILED:
+ SG(headers_sent) = 0;
+ ret = FAILURE;
+ break;
+ }
+
+ sapi_send_headers_free(TSRMLS_C);
+
+ return ret;
+}
+
+
+SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entries TSRMLS_DC)
+{
+ sapi_post_entry *p=post_entries;
+
+ while (p->content_type) {
+ if (sapi_register_post_entry(p TSRMLS_CC) == FAILURE) {
+ return FAILURE;
+ }
+ p++;
+ }
+ return SUCCESS;
+}
+
+
+SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
+{
+ if (SG(sapi_started) && EG(in_execution)) {
+ return FAILURE;
+ }
+ return zend_hash_add(&SG(known_post_content_types),
+ post_entry->content_type, post_entry->content_type_len+1,
+ (void *) post_entry, sizeof(sapi_post_entry), NULL);
+}
+
+SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
+{
+ if (SG(sapi_started) && EG(in_execution)) {
+ return;
+ }
+ zend_hash_del(&SG(known_post_content_types), post_entry->content_type,
+ post_entry->content_type_len+1);
+}
+
+
+SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D) TSRMLS_DC)
+{
+ if (SG(sapi_started) && EG(in_execution)) {
+ return FAILURE;
+ }
+ sapi_module.default_post_reader = default_post_reader;
+ return SUCCESS;
+}
+
+
+SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC) TSRMLS_DC)
+{
+ if (SG(sapi_started) && EG(in_execution)) {
+ return FAILURE;
+ }
+ sapi_module.treat_data = treat_data;
+ return SUCCESS;
+}
+
+SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC), unsigned int (*input_filter_init)(TSRMLS_D) TSRMLS_DC)
+{
+ if (SG(sapi_started) && EG(in_execution)) {
+ return FAILURE;
+ }
+ sapi_module.input_filter = input_filter;
+ sapi_module.input_filter_init = input_filter_init;
+ return SUCCESS;
+}
+
+SAPI_API int sapi_flush(TSRMLS_D)
+{
+ if (sapi_module.flush) {
+ sapi_module.flush(SG(server_context));
+ return SUCCESS;
+ } else {
+ return FAILURE;
+ }
+}
+
+SAPI_API struct stat *sapi_get_stat(TSRMLS_D)
+{
+ if (sapi_module.get_stat) {
+ return sapi_module.get_stat(TSRMLS_C);
+ } else {
+ if (!SG(request_info).path_translated || (VCWD_STAT(SG(request_info).path_translated, &SG(global_stat)) == -1)) {
+ return NULL;
+ }
+ return &SG(global_stat);
+ }
+}
+
+SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC)
+{
+ if (sapi_module.getenv) {
+ char *value, *tmp = sapi_module.getenv(name, name_len TSRMLS_CC);
+ if (tmp) {
+ value = estrdup(tmp);
+ } else {
+ return NULL;
+ }
+ if (sapi_module.input_filter) {
+ sapi_module.input_filter(PARSE_STRING, name, &value, strlen(value), NULL TSRMLS_CC);
+ }
+ return value;
+ }
+ return NULL;
+}
+
+SAPI_API int sapi_get_fd(int *fd TSRMLS_DC)
+{
+ if (sapi_module.get_fd) {
+ return sapi_module.get_fd(fd TSRMLS_CC);
+ } else {
+ return FAILURE;
+ }
+}
+
+SAPI_API int sapi_force_http_10(TSRMLS_D)
+{
+ if (sapi_module.force_http_10) {
+ return sapi_module.force_http_10(TSRMLS_C);
+ } else {
+ return FAILURE;
+ }
+}
+
+
+SAPI_API int sapi_get_target_uid(uid_t *obj TSRMLS_DC)
+{
+ if (sapi_module.get_target_uid) {
+ return sapi_module.get_target_uid(obj TSRMLS_CC);
+ } else {
+ return FAILURE;
+ }
+}
+
+SAPI_API int sapi_get_target_gid(gid_t *obj TSRMLS_DC)
+{
+ if (sapi_module.get_target_gid) {
+ return sapi_module.get_target_gid(obj TSRMLS_CC);
+ } else {
+ return FAILURE;
+ }
+}
+
+SAPI_API double sapi_get_request_time(TSRMLS_D)
+{
+ if(SG(global_request_time)) return SG(global_request_time);
+
+ if (sapi_module.get_request_time && SG(server_context)) {
+ SG(global_request_time) = sapi_module.get_request_time(TSRMLS_C);
+ } else {
+ struct timeval tp = {0};
+ if (!gettimeofday(&tp, NULL)) {
+ SG(global_request_time) = (double)(tp.tv_sec + tp.tv_usec / 1000000.00);
+ } else {
+ SG(global_request_time) = (double)time(0);
+ }
+ }
+ return SG(global_request_time);
+}
+
+SAPI_API void sapi_terminate_process(TSRMLS_D) {
+ if (sapi_module.terminate_process) {
+ sapi_module.terminate_process(TSRMLS_C);
+ }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/SAPI.h b/main/SAPI.h
new file mode 100644
index 0000000..92b7329
--- /dev/null
+++ b/main/SAPI.h
@@ -0,0 +1,317 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef SAPI_H
+#define SAPI_H
+
+#include "zend.h"
+#include "zend_API.h"
+#include "zend_llist.h"
+#include "zend_operators.h"
+#ifdef PHP_WIN32
+#include "win95nt.h"
+#endif
+#include <sys/stat.h>
+
+#define SAPI_OPTION_NO_CHDIR 1
+
+#define SAPI_POST_BLOCK_SIZE 4000
+
+#ifdef PHP_WIN32
+# ifdef SAPI_EXPORTS
+# define SAPI_API __declspec(dllexport)
+# else
+# define SAPI_API __declspec(dllimport)
+# endif
+#elif defined(__GNUC__) && __GNUC__ >= 4
+# define SAPI_API __attribute__ ((visibility("default")))
+#else
+# define SAPI_API
+#endif
+
+#undef shutdown
+
+typedef struct {
+ char *header;
+ uint header_len;
+} sapi_header_struct;
+
+
+typedef struct {
+ zend_llist headers;
+ int http_response_code;
+ unsigned char send_default_content_type;
+ char *mimetype;
+ char *http_status_line;
+} sapi_headers_struct;
+
+
+typedef struct _sapi_post_entry sapi_post_entry;
+typedef struct _sapi_module_struct sapi_module_struct;
+
+BEGIN_EXTERN_C()
+extern SAPI_API sapi_module_struct sapi_module; /* true global */
+END_EXTERN_C()
+
+/* Some values in this structure needs to be filled in before
+ * calling sapi_activate(). We WILL change the `char *' entries,
+ * so make sure that you allocate a separate buffer for them
+ * and that you free them after sapi_deactivate().
+ */
+
+typedef struct {
+ const char *request_method;
+ char *query_string;
+ char *post_data, *raw_post_data;
+ char *cookie_data;
+ long content_length;
+ uint post_data_length, raw_post_data_length;
+
+ char *path_translated;
+ char *request_uri;
+
+ const char *content_type;
+
+ zend_bool headers_only;
+ zend_bool no_headers;
+ zend_bool headers_read;
+
+ sapi_post_entry *post_entry;
+
+ char *content_type_dup;
+
+ /* for HTTP authentication */
+ char *auth_user;
+ char *auth_password;
+ char *auth_digest;
+
+ /* this is necessary for the CGI SAPI module */
+ char *argv0;
+
+ char *current_user;
+ int current_user_length;
+
+ /* this is necessary for CLI module */
+ int argc;
+ char **argv;
+ int proto_num;
+} sapi_request_info;
+
+
+typedef struct _sapi_globals_struct {
+ void *server_context;
+ sapi_request_info request_info;
+ sapi_headers_struct sapi_headers;
+ int read_post_bytes;
+ unsigned char headers_sent;
+ struct stat global_stat;
+ char *default_mimetype;
+ char *default_charset;
+ HashTable *rfc1867_uploaded_files;
+ long post_max_size;
+ int options;
+ zend_bool sapi_started;
+ double global_request_time;
+ HashTable known_post_content_types;
+ zval *callback_func;
+ zend_fcall_info_cache fci_cache;
+ zend_bool callback_run;
+} sapi_globals_struct;
+
+
+BEGIN_EXTERN_C()
+#ifdef ZTS
+# define SG(v) TSRMG(sapi_globals_id, sapi_globals_struct *, v)
+SAPI_API extern int sapi_globals_id;
+#else
+# define SG(v) (sapi_globals.v)
+extern SAPI_API sapi_globals_struct sapi_globals;
+#endif
+
+SAPI_API void sapi_startup(sapi_module_struct *sf);
+SAPI_API void sapi_shutdown(void);
+SAPI_API void sapi_activate(TSRMLS_D);
+SAPI_API void sapi_deactivate(TSRMLS_D);
+SAPI_API void sapi_initialize_empty_request(TSRMLS_D);
+END_EXTERN_C()
+
+/*
+ * This is the preferred and maintained API for
+ * operating on HTTP headers.
+ */
+
+/*
+ * Always specify a sapi_header_line this way:
+ *
+ * sapi_header_line ctr = {0};
+ */
+
+typedef struct {
+ char *line; /* If you allocated this, you need to free it yourself */
+ uint line_len;
+ long response_code; /* long due to zend_parse_parameters compatibility */
+} sapi_header_line;
+
+typedef enum { /* Parameter: */
+ SAPI_HEADER_REPLACE, /* sapi_header_line* */
+ SAPI_HEADER_ADD, /* sapi_header_line* */
+ SAPI_HEADER_DELETE, /* sapi_header_line* */
+ SAPI_HEADER_DELETE_ALL, /* void */
+ SAPI_HEADER_SET_STATUS /* int */
+} sapi_header_op_enum;
+
+BEGIN_EXTERN_C()
+SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC);
+
+/* Deprecated functions. Use sapi_header_op instead. */
+SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace TSRMLS_DC);
+#define sapi_add_header(a, b, c) sapi_add_header_ex((a),(b),(c),1 TSRMLS_CC)
+
+
+SAPI_API int sapi_send_headers(TSRMLS_D);
+SAPI_API void sapi_free_header(sapi_header_struct *sapi_header);
+SAPI_API void sapi_handle_post(void *arg TSRMLS_DC);
+
+SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entry TSRMLS_DC);
+SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry TSRMLS_DC);
+SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry TSRMLS_DC);
+SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D) TSRMLS_DC);
+SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC) TSRMLS_DC);
+SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC), unsigned int (*input_filter_init)(TSRMLS_D) TSRMLS_DC);
+
+SAPI_API int sapi_flush(TSRMLS_D);
+SAPI_API struct stat *sapi_get_stat(TSRMLS_D);
+SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC);
+
+SAPI_API char *sapi_get_default_content_type(TSRMLS_D);
+SAPI_API void sapi_get_default_content_type_header(sapi_header_struct *default_header TSRMLS_DC);
+SAPI_API size_t sapi_apply_default_charset(char **mimetype, size_t len TSRMLS_DC);
+SAPI_API void sapi_activate_headers_only(TSRMLS_D);
+
+SAPI_API int sapi_get_fd(int *fd TSRMLS_DC);
+SAPI_API int sapi_force_http_10(TSRMLS_D);
+
+SAPI_API int sapi_get_target_uid(uid_t * TSRMLS_DC);
+SAPI_API int sapi_get_target_gid(gid_t * TSRMLS_DC);
+SAPI_API double sapi_get_request_time(TSRMLS_D);
+SAPI_API void sapi_terminate_process(TSRMLS_D);
+END_EXTERN_C()
+
+struct _sapi_module_struct {
+ char *name;
+ char *pretty_name;
+
+ int (*startup)(struct _sapi_module_struct *sapi_module);
+ int (*shutdown)(struct _sapi_module_struct *sapi_module);
+
+ int (*activate)(TSRMLS_D);
+ int (*deactivate)(TSRMLS_D);
+
+ int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC);
+ void (*flush)(void *server_context);
+ struct stat *(*get_stat)(TSRMLS_D);
+ char *(*getenv)(char *name, size_t name_len TSRMLS_DC);
+
+ void (*sapi_error)(int type, const char *error_msg, ...);
+
+ int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC);
+ int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC);
+ void (*send_header)(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC);
+
+ int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC);
+ char *(*read_cookies)(TSRMLS_D);
+
+ void (*register_server_variables)(zval *track_vars_array TSRMLS_DC);
+ void (*log_message)(char *message TSRMLS_DC);
+ double (*get_request_time)(TSRMLS_D);
+ void (*terminate_process)(TSRMLS_D);
+
+ char *php_ini_path_override;
+
+ void (*block_interruptions)(void);
+ void (*unblock_interruptions)(void);
+
+ void (*default_post_reader)(TSRMLS_D);
+ void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC);
+ char *executable_location;
+
+ int php_ini_ignore;
+ int php_ini_ignore_cwd; /* don't look for php.ini in the current directory */
+
+ int (*get_fd)(int *fd TSRMLS_DC);
+
+ int (*force_http_10)(TSRMLS_D);
+
+ int (*get_target_uid)(uid_t * TSRMLS_DC);
+ int (*get_target_gid)(gid_t * TSRMLS_DC);
+
+ unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC);
+
+ void (*ini_defaults)(HashTable *configuration_hash);
+ int phpinfo_as_text;
+
+ char *ini_entries;
+ const zend_function_entry *additional_functions;
+ unsigned int (*input_filter_init)(TSRMLS_D);
+};
+
+
+struct _sapi_post_entry {
+ char *content_type;
+ uint content_type_len;
+ void (*post_reader)(TSRMLS_D);
+ void (*post_handler)(char *content_type_dup, void *arg TSRMLS_DC);
+};
+
+/* header_handler() constants */
+#define SAPI_HEADER_ADD (1<<0)
+
+
+#define SAPI_HEADER_SENT_SUCCESSFULLY 1
+#define SAPI_HEADER_DO_SEND 2
+#define SAPI_HEADER_SEND_FAILED 3
+
+#define SAPI_DEFAULT_MIMETYPE "text/html"
+#define SAPI_DEFAULT_CHARSET ""
+#define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION
+
+#define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D)
+#define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC)
+
+#define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC)
+#define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)
+
+BEGIN_EXTERN_C()
+SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data);
+SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader);
+SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data);
+SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter);
+END_EXTERN_C()
+
+#define STANDARD_SAPI_MODULE_PROPERTIES
+
+#endif /* SAPI_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/main/alloca.c b/main/alloca.c
new file mode 100644
index 0000000..401649c
--- /dev/null
+++ b/main/alloca.c
@@ -0,0 +1,501 @@
+/* alloca.c -- allocate automatically reclaimed memory
+ (Mostly) portable public-domain implementation -- D A Gwyn
+
+ This implementation of the PWB library alloca function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+ J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+ There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection. */
+
+/* $Id$ */
+
+#include <php_config.h>
+
+#if !HAVE_ALLOCA
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef emacs
+#include "blockinput.h"
+#endif
+
+/* If compiling with GCC 2, this file's not needed. */
+#if !defined (__GNUC__) || __GNUC__ < 2
+
+/* If someone has defined alloca as a macro,
+ there must be some other way alloca is supposed to work. */
+#ifndef alloca
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+ provide an "address metric" ADDRESS_FUNCTION macro. */
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+
+#ifndef STACK_DIRECTION
+#define STACK_DIRECTION 0 /* Direction unknown. */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
+
+#else /* STACK_DIRECTION == 0; need run-time code. */
+
+static int stack_dir; /* 1 or -1 once known. */
+#define STACK_DIR stack_dir
+
+static void
+find_stack_direction ()
+{
+ static char *addr = NULL; /* Address of first `dummy', once known. */
+ auto char dummy; /* To get stack address. */
+
+ if (addr == NULL)
+ { /* Initial entry. */
+ addr = ADDRESS_FUNCTION (dummy);
+
+ find_stack_direction (); /* Recurse once. */
+ }
+ else
+ {
+ /* Second entry. */
+ if (ADDRESS_FUNCTION (dummy) > addr)
+ stack_dir = 1; /* Stack grew upward. */
+ else
+ stack_dir = -1; /* Stack grew downward. */
+ }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+ (a) chain together all alloca'ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc
+ alignment chunk size. The following default should work okay. */
+
+#ifndef ALIGN_SIZE
+#define ALIGN_SIZE sizeof(double)
+#endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* To force sizeof(header). */
+ struct
+ {
+ union hdr *next; /* For chaining headers. */
+ char *deep; /* For stack depth measure. */
+ } h;
+} header;
+
+static header *last_alloca_header = NULL; /* -> last alloca header. */
+
+/* Return a pointer to at least SIZE bytes of storage,
+ which will be automatically reclaimed upon exit from
+ the procedure that called alloca. Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32. */
+
+pointer
+alloca (size)
+ size_t size;
+{
+ auto char probe; /* Probes stack depth: */
+ register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* Unknown growth direction. */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca'd storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* Traverses linked list. */
+
+#ifdef emacs
+ BLOCK_INPUT;
+#endif
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if ((STACK_DIR > 0 && hp->h.deep > depth)
+ || (STACK_DIR < 0 && hp->h.deep < depth))
+ {
+ register header *np = hp->h.next;
+
+ free ((pointer) hp); /* Collect garbage. */
+
+ hp = np; /* -> next header. */
+ }
+ else
+ break; /* Rest are not deeper. */
+
+ last_alloca_header = hp; /* -> last valid storage. */
+
+#ifdef emacs
+ UNBLOCK_INPUT;
+#endif
+ }
+
+ if (size == 0)
+ return NULL; /* No allocation required. */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ register pointer new = malloc (sizeof (header) + size);
+ /* Address of header. */
+
+ if (new == 0)
+ abort();
+
+ ((header *) new)->h.next = last_alloca_header;
+ ((header *) new)->h.deep = depth;
+
+ last_alloca_header = (header *) new;
+
+ /* User storage begins just after header. */
+
+ return (pointer) ((char *) new + sizeof (header));
+ }
+}
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+ {
+ long shgrow:32; /* Number of times stack has grown. */
+ long shaseg:32; /* Size of increments to stack. */
+ long shhwm:32; /* High water mark of stack. */
+ long shsize:32; /* Current size of stack (all segments). */
+ };
+
+/* The stack segment linkage control information occurs at
+ the high-address end of a stack segment. (The stack
+ grows from low addresses to high addresses.) The initial
+ part of the stack segment linkage control information is
+ 0200 (octal) words. This provides for register storage
+ for the routine which overflows the stack. */
+
+struct stack_segment_linkage
+ {
+ long ss[0200]; /* 0200 overflow words. */
+ long sssize:32; /* Number of words in this segment. */
+ long ssbase:32; /* Offset to stack base. */
+ long:32;
+ long sspseg:32; /* Offset to linkage control of previous
+ segment of stack. */
+ long:32;
+ long sstcpt:32; /* Pointer to task common address block. */
+ long sscsnm; /* Private control structure number for
+ microtasking. */
+ long ssusr1; /* Reserved for user. */
+ long ssusr2; /* Reserved for user. */
+ long sstpid; /* Process ID for pid based multi-tasking. */
+ long ssgvup; /* Pointer to multitasking thread giveup. */
+ long sscray[7]; /* Reserved for Cray Research. */
+ long ssa0;
+ long ssa1;
+ long ssa2;
+ long ssa3;
+ long ssa4;
+ long ssa5;
+ long ssa6;
+ long ssa7;
+ long sss0;
+ long sss1;
+ long sss2;
+ long sss3;
+ long sss4;
+ long sss5;
+ long sss6;
+ long sss7;
+ };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+ returned by the STKSTAT library routine. */
+struct stk_stat
+ {
+ long now; /* Current total stack size. */
+ long maxc; /* Amount of contiguous space which would
+ be required to satisfy the maximum
+ stack demand to date. */
+ long high_water; /* Stack high-water mark. */
+ long overflows; /* Number of stack overflow ($STKOFEN) calls. */
+ long hits; /* Number of internal buffer hits. */
+ long extends; /* Number of block extensions. */
+ long stko_mallocs; /* Block allocations by $STKOFEN. */
+ long underflows; /* Number of stack underflow calls ($STKRETN). */
+ long stko_free; /* Number of deallocations by $STKRETN. */
+ long stkm_free; /* Number of deallocations by $STKMRET. */
+ long segments; /* Current number of stack segments. */
+ long maxs; /* Maximum number of stack segments so far. */
+ long pad_size; /* Stack pad size. */
+ long current_address; /* Current stack segment address. */
+ long current_size; /* Current stack segment size. This
+ number is actually corrupted by STKSTAT to
+ include the fifteen word trailer area. */
+ long initial_address; /* Address of initial segment. */
+ long initial_size; /* Size of initial segment. */
+ };
+
+/* The following structure describes the data structure which trails
+ any stack segment. I think that the description in 'asdef' is
+ out of date. I only describe the parts that I am sure about. */
+
+struct stk_trailer
+ {
+ long this_address; /* Address of this block. */
+ long this_size; /* Size of this block (does not include
+ this trailer). */
+ long unknown2;
+ long unknown3;
+ long link; /* Address of trailer block of previous
+ segment. */
+ long unknown5;
+ long unknown6;
+ long unknown7;
+ long unknown8;
+ long unknown9;
+ long unknown10;
+ long unknown11;
+ long unknown12;
+ long unknown13;
+ long unknown14;
+ };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+ I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+ struct stk_stat status;
+ struct stk_trailer *trailer;
+ long *block, size;
+ long result = 0;
+
+ /* We want to iterate through all of the segments. The first
+ step is to get the stack status structure. We could do this
+ more quickly and more directly, perhaps, by referencing the
+ $LM00 common block, but I know that this works. */
+
+ STKSTAT (&status);
+
+ /* Set up the iteration. */
+
+ trailer = (struct stk_trailer *) (status.current_address
+ + status.current_size
+ - 15);
+
+ /* There must be at least one stack segment. Therefore it is
+ a fatal error if "trailer" is null. */
+
+ if (trailer == 0)
+ abort ();
+
+ /* Discard segments that do not contain our argument address. */
+
+ while (trailer != 0)
+ {
+ block = (long *) trailer->this_address;
+ size = trailer->this_size;
+ if (block == 0 || size == 0)
+ abort ();
+ trailer = (struct stk_trailer *) trailer->link;
+ if ((block <= address) && (address < (block + size)))
+ break;
+ }
+
+ /* Set the result to the offset in this segment and add the sizes
+ of all predecessor segments. */
+
+ result = address - block;
+
+ if (trailer == 0)
+ {
+ return result;
+ }
+
+ do
+ {
+ if (trailer->this_size <= 0)
+ abort ();
+ result += trailer->this_size;
+ trailer = (struct stk_trailer *) trailer->link;
+ }
+ while (trailer != 0);
+
+ /* We are done. Note that if you present a bogus address (one
+ not in any segment), you will get a different number back, formed
+ from subtracting the address of the first block. This is probably
+ not what you want. */
+
+ return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+ Determine the number of the cell within the stack,
+ given the address of the cell. The purpose of this
+ routine is to linearize, in some sense, stack addresses
+ for alloca. */
+
+static long
+i00afunc (long address)
+{
+ long stkl = 0;
+
+ long size, pseg, this_segment, stack;
+ long result = 0;
+
+ struct stack_segment_linkage *ssptr;
+
+ /* Register B67 contains the address of the end of the
+ current stack segment. If you (as a subprogram) store
+ your registers on the stack and find that you are past
+ the contents of B67, you have overflowed the segment.
+
+ B67 also points to the stack segment linkage control
+ area, which is what we are really interested in. */
+
+ stkl = CRAY_STACKSEG_END ();
+ ssptr = (struct stack_segment_linkage *) stkl;
+
+ /* If one subtracts 'size' from the end of the segment,
+ one has the address of the first word of the segment.
+
+ If this is not the first segment, 'pseg' will be
+ nonzero. */
+
+ pseg = ssptr->sspseg;
+ size = ssptr->sssize;
+
+ this_segment = stkl - size;
+
+ /* It is possible that calling this routine itself caused
+ a stack overflow. Discard stack segments which do not
+ contain the target address. */
+
+ while (!(this_segment <= address && address <= stkl))
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+ if (pseg == 0)
+ break;
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ this_segment = stkl - size;
+ }
+
+ result = address - this_segment;
+
+ /* If you subtract pseg from the current end of the stack,
+ you get the address of the previous stack segment's end.
+ This seems a little convoluted to me, but I'll bet you save
+ a cycle somewhere. */
+
+ while (pseg != 0)
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ result += size;
+ }
+ return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
+#endif /* not GCC version 2 */
+#endif /* HAVE_ALLOCA */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/build-defs.h.in b/main/build-defs.h.in
new file mode 100644
index 0000000..aa1fbf0
--- /dev/null
+++ b/main/build-defs.h.in
@@ -0,0 +1,91 @@
+/* -*- C -*-
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Stig Sæther Bakken <ssb@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#define CONFIGURE_COMMAND "@CONFIGURE_COMMAND@"
+#define PHP_ADA_INCLUDE ""
+#define PHP_ADA_LFLAGS ""
+#define PHP_ADA_LIBS ""
+#define PHP_APACHE_INCLUDE ""
+#define PHP_APACHE_TARGET ""
+#define PHP_FHTTPD_INCLUDE ""
+#define PHP_FHTTPD_LIB ""
+#define PHP_FHTTPD_TARGET ""
+#define PHP_CFLAGS "@CFLAGS@"
+#define PHP_DBASE_LIB ""
+#define PHP_BUILD_DEBUG "@DEBUG_CFLAGS@"
+#define PHP_GDBM_INCLUDE ""
+#define PHP_IBASE_INCLUDE ""
+#define PHP_IBASE_LFLAGS ""
+#define PHP_IBASE_LIBS ""
+#define PHP_IFX_INCLUDE ""
+#define PHP_IFX_LFLAGS ""
+#define PHP_IFX_LIBS ""
+#define PHP_INSTALL_IT "@INSTALL_IT@"
+#define PHP_IODBC_INCLUDE ""
+#define PHP_IODBC_LFLAGS ""
+#define PHP_IODBC_LIBS ""
+#define PHP_MSQL_INCLUDE ""
+#define PHP_MSQL_LFLAGS ""
+#define PHP_MSQL_LIBS ""
+#define PHP_MYSQL_INCLUDE "@MYSQL_INCLUDE@"
+#define PHP_MYSQL_LIBS "@MYSQL_LIBS@"
+#define PHP_MYSQL_TYPE "@MYSQL_MODULE_TYPE@"
+#define PHP_ODBC_INCLUDE "@ODBC_INCLUDE@"
+#define PHP_ODBC_LFLAGS "@ODBC_LFLAGS@"
+#define PHP_ODBC_LIBS "@ODBC_LIBS@"
+#define PHP_ODBC_TYPE "@ODBC_TYPE@"
+#define PHP_OCI8_SHARED_LIBADD "@OCI8_SHARED_LIBADD@"
+#define PHP_OCI8_DIR "@OCI8_DIR@"
+#define PHP_OCI8_ORACLE_VERSION "@OCI8_ORACLE_VERSION@"
+#define PHP_ORACLE_SHARED_LIBADD "@ORACLE_SHARED_LIBADD@"
+#define PHP_ORACLE_DIR "@ORACLE_DIR@"
+#define PHP_ORACLE_VERSION "@ORACLE_VERSION@"
+#define PHP_PGSQL_INCLUDE ""
+#define PHP_PGSQL_LFLAGS ""
+#define PHP_PGSQL_LIBS ""
+#define PHP_PROG_SENDMAIL "@PROG_SENDMAIL@"
+#define PHP_SOLID_INCLUDE ""
+#define PHP_SOLID_LIBS ""
+#define PHP_EMPRESS_INCLUDE ""
+#define PHP_EMPRESS_LIBS ""
+#define PHP_SYBASE_INCLUDE ""
+#define PHP_SYBASE_LFLAGS ""
+#define PHP_SYBASE_LIBS ""
+#define PHP_DBM_TYPE ""
+#define PHP_DBM_LIB ""
+#define PHP_LDAP_LFLAGS ""
+#define PHP_LDAP_INCLUDE ""
+#define PHP_LDAP_LIBS ""
+#define PHP_BIRDSTEP_INCLUDE ""
+#define PHP_BIRDSTEP_LIBS ""
+#define PEAR_INSTALLDIR "@EXPANDED_PEAR_INSTALLDIR@"
+#define PHP_INCLUDE_PATH "@INCLUDE_PATH@"
+#define PHP_EXTENSION_DIR "@EXPANDED_EXTENSION_DIR@"
+#define PHP_PREFIX "@prefix@"
+#define PHP_BINDIR "@EXPANDED_BINDIR@"
+#define PHP_SBINDIR "@EXPANDED_SBINDIR@"
+#define PHP_MANDIR "@EXPANDED_MANDIR@"
+#define PHP_LIBDIR "@EXPANDED_LIBDIR@"
+#define PHP_DATADIR "@EXPANDED_DATADIR@"
+#define PHP_SYSCONFDIR "@EXPANDED_SYSCONFDIR@"
+#define PHP_LOCALSTATEDIR "@EXPANDED_LOCALSTATEDIR@"
+#define PHP_CONFIG_FILE_PATH "@EXPANDED_PHP_CONFIG_FILE_PATH@"
+#define PHP_CONFIG_FILE_SCAN_DIR "@EXPANDED_PHP_CONFIG_FILE_SCAN_DIR@"
+#define PHP_SHLIB_SUFFIX "@SHLIB_DL_SUFFIX_NAME@"
diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c
new file mode 100644
index 0000000..6f11cf3
--- /dev/null
+++ b/main/fopen_wrappers.c
@@ -0,0 +1,817 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
+ | Jim Winstead <jimw@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/* {{{ includes
+ */
+#include "php.h"
+#include "php_globals.h"
+#include "SAPI.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef PHP_WIN32
+#define O_RDONLY _O_RDONLY
+#include "win32/param.h"
+#else
+#include <sys/param.h>
+#endif
+
+#include "ext/standard/head.h"
+#include "ext/standard/php_standard.h"
+#include "zend_compile.h"
+#include "php_network.h"
+
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#include <sys/types.h>
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+
+#ifdef PHP_WIN32
+#include <winsock2.h>
+#elif defined(NETWARE) && defined(USE_WINSOCK)
+#include <novsock2.h>
+#else
+#include <netinet/in.h>
+#include <netdb.h>
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#endif
+
+#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE)
+#undef AF_UNIX
+#endif
+
+#if defined(AF_UNIX)
+#include <sys/un.h>
+#endif
+/* }}} */
+
+/* {{{ OnUpdateBaseDir
+Allows any change to open_basedir setting in during Startup and Shutdown events,
+or a tightening during activation/runtime/deactivation */
+PHPAPI ZEND_INI_MH(OnUpdateBaseDir)
+{
+ char **p, *pathbuf, *ptr, *end;
+#ifndef ZTS
+ char *base = (char *) mh_arg2;
+#else
+ char *base = (char *) ts_resource(*((int *) mh_arg2));
+#endif
+
+ p = (char **) (base + (size_t) mh_arg1);
+
+ if (stage == PHP_INI_STAGE_STARTUP || stage == PHP_INI_STAGE_SHUTDOWN || stage == PHP_INI_STAGE_ACTIVATE || stage == PHP_INI_STAGE_DEACTIVATE) {
+ /* We're in a PHP_INI_SYSTEM context, no restrictions */
+ *p = new_value;
+ return SUCCESS;
+ }
+
+ /* Otherwise we're in runtime */
+ if (!*p || !**p) {
+ /* open_basedir not set yet, go ahead and give it a value */
+ *p = new_value;
+ return SUCCESS;
+ }
+
+ /* Shortcut: When we have a open_basedir and someone tries to unset, we know it'll fail */
+ if (!new_value || !*new_value) {
+ return FAILURE;
+ }
+
+ /* Is the proposed open_basedir at least as restrictive as the current setting? */
+ ptr = pathbuf = estrdup(new_value);
+ while (ptr && *ptr) {
+ end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
+ if (end != NULL) {
+ *end = '\0';
+ end++;
+ }
+ if (php_check_open_basedir_ex(ptr, 0 TSRMLS_CC) != 0) {
+ /* At least one portion of this open_basedir is less restrictive than the prior one, FAIL */
+ efree(pathbuf);
+ return FAILURE;
+ }
+ ptr = end;
+ }
+ efree(pathbuf);
+
+ /* Everything checks out, set it */
+ *p = new_value;
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ php_check_specific_open_basedir
+ When open_basedir is not NULL, check if the given filename is located in
+ open_basedir. Returns -1 if error or not in the open_basedir, else 0.
+ When open_basedir is NULL, always return 0.
+*/
+PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path TSRMLS_DC)
+{
+ char resolved_name[MAXPATHLEN];
+ char resolved_basedir[MAXPATHLEN];
+ char local_open_basedir[MAXPATHLEN];
+ char path_tmp[MAXPATHLEN];
+ char *path_file;
+ int resolved_basedir_len;
+ int resolved_name_len;
+ int path_len;
+ int nesting_level = 0;
+
+ /* Special case basedir==".": Use script-directory */
+ if (strcmp(basedir, ".") || !VCWD_GETCWD(local_open_basedir, MAXPATHLEN)) {
+ /* Else use the unmodified path */
+ strlcpy(local_open_basedir, basedir, sizeof(local_open_basedir));
+ }
+
+ path_len = strlen(path);
+ if (path_len > (MAXPATHLEN - 1)) {
+ /* empty and too long paths are invalid */
+ return -1;
+ }
+
+ /* normalize and expand path */
+ if (expand_filepath(path, resolved_name TSRMLS_CC) == NULL) {
+ return -1;
+ }
+
+ path_len = strlen(resolved_name);
+ memcpy(path_tmp, resolved_name, path_len + 1); /* safe */
+
+ while (VCWD_REALPATH(path_tmp, resolved_name) == NULL) {
+#if defined(PHP_WIN32) || defined(HAVE_SYMLINK)
+#if defined(PHP_WIN32)
+ if (EG(windows_version_info).dwMajorVersion > 5) {
+#endif
+ if (nesting_level == 0) {
+ int ret;
+ char buf[MAXPATHLEN];
+
+ ret = php_sys_readlink(path_tmp, buf, MAXPATHLEN - 1);
+ if (ret < 0) {
+ /* not a broken symlink, move along.. */
+ } else {
+ /* put the real path into the path buffer */
+ memcpy(path_tmp, buf, ret);
+ path_tmp[ret] = '\0';
+ }
+ }
+#if defined(PHP_WIN32)
+ }
+#endif
+#endif
+
+#if defined(PHP_WIN32) || defined(NETWARE)
+ path_file = strrchr(path_tmp, DEFAULT_SLASH);
+ if (!path_file) {
+ path_file = strrchr(path_tmp, '/');
+ }
+#else
+ path_file = strrchr(path_tmp, DEFAULT_SLASH);
+#endif
+ if (!path_file) {
+ /* none of the path components exist. definitely not in open_basedir.. */
+ return -1;
+ } else {
+ path_len = path_file - path_tmp + 1;
+#if defined(PHP_WIN32) || defined(NETWARE)
+ if (path_len > 1 && path_tmp[path_len - 2] == ':') {
+ if (path_len != 3) {
+ return -1;
+ }
+ /* this is c:\ */
+ path_tmp[path_len] = '\0';
+ } else {
+ path_tmp[path_len - 1] = '\0';
+ }
+#else
+ path_tmp[path_len - 1] = '\0';
+#endif
+ }
+ nesting_level++;
+ }
+
+ /* Resolve open_basedir to resolved_basedir */
+ if (expand_filepath(local_open_basedir, resolved_basedir TSRMLS_CC) != NULL) {
+ /* Handler for basedirs that end with a / */
+ resolved_basedir_len = strlen(resolved_basedir);
+#if defined(PHP_WIN32) || defined(NETWARE)
+ if (basedir[strlen(basedir) - 1] == PHP_DIR_SEPARATOR || basedir[strlen(basedir) - 1] == '/') {
+#else
+ if (basedir[strlen(basedir) - 1] == PHP_DIR_SEPARATOR) {
+#endif
+ if (resolved_basedir[resolved_basedir_len - 1] != PHP_DIR_SEPARATOR) {
+ resolved_basedir[resolved_basedir_len] = PHP_DIR_SEPARATOR;
+ resolved_basedir[++resolved_basedir_len] = '\0';
+ }
+ } else {
+ resolved_basedir[resolved_basedir_len++] = PHP_DIR_SEPARATOR;
+ resolved_basedir[resolved_basedir_len] = '\0';
+ }
+
+ resolved_name_len = strlen(resolved_name);
+ if (path_tmp[path_len - 1] == PHP_DIR_SEPARATOR) {
+ if (resolved_name[resolved_name_len - 1] != PHP_DIR_SEPARATOR) {
+ resolved_name[resolved_name_len] = PHP_DIR_SEPARATOR;
+ resolved_name[++resolved_name_len] = '\0';
+ }
+ }
+
+ /* Check the path */
+#if defined(PHP_WIN32) || defined(NETWARE)
+ if (strncasecmp(resolved_basedir, resolved_name, resolved_basedir_len) == 0) {
+#else
+ if (strncmp(resolved_basedir, resolved_name, resolved_basedir_len) == 0) {
+#endif
+ if (resolved_name_len > resolved_basedir_len &&
+ resolved_name[resolved_basedir_len - 1] != PHP_DIR_SEPARATOR) {
+ return -1;
+ } else {
+ /* File is in the right directory */
+ return 0;
+ }
+ } else {
+ /* /openbasedir/ and /openbasedir are the same directory */
+ if (resolved_basedir_len == (resolved_name_len + 1) && resolved_basedir[resolved_basedir_len - 1] == PHP_DIR_SEPARATOR) {
+#if defined(PHP_WIN32) || defined(NETWARE)
+ if (strncasecmp(resolved_basedir, resolved_name, resolved_name_len) == 0) {
+#else
+ if (strncmp(resolved_basedir, resolved_name, resolved_name_len) == 0) {
+#endif
+ return 0;
+ }
+ }
+ return -1;
+ }
+ } else {
+ /* Unable to resolve the real path, return -1 */
+ return -1;
+ }
+}
+/* }}} */
+
+PHPAPI int php_check_open_basedir(const char *path TSRMLS_DC)
+{
+ return php_check_open_basedir_ex(path, 1 TSRMLS_CC);
+}
+
+/* {{{ php_check_open_basedir
+ */
+PHPAPI int php_check_open_basedir_ex(const char *path, int warn TSRMLS_DC)
+{
+ /* Only check when open_basedir is available */
+ if (PG(open_basedir) && *PG(open_basedir)) {
+ char *pathbuf;
+ char *ptr;
+ char *end;
+
+ /* Check if the path is too long so we can give a more useful error
+ * message. */
+ if (strlen(path) > (MAXPATHLEN - 1)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "File name is longer than the maximum allowed path length on this platform (%d): %s", MAXPATHLEN, path);
+ errno = EINVAL;
+ return -1;
+ }
+
+ pathbuf = estrdup(PG(open_basedir));
+
+ ptr = pathbuf;
+
+ while (ptr && *ptr) {
+ end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
+ if (end != NULL) {
+ *end = '\0';
+ end++;
+ }
+
+ if (php_check_specific_open_basedir(ptr, path TSRMLS_CC) == 0) {
+ efree(pathbuf);
+ return 0;
+ }
+
+ ptr = end;
+ }
+ if (warn) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "open_basedir restriction in effect. File(%s) is not within the allowed path(s): (%s)", path, PG(open_basedir));
+ }
+ efree(pathbuf);
+ errno = EPERM; /* we deny permission to open it */
+ return -1;
+ }
+
+ /* Nothing to check... */
+ return 0;
+}
+/* }}} */
+
+/* {{{ php_fopen_and_set_opened_path
+ */
+static FILE *php_fopen_and_set_opened_path(const char *path, const char *mode, char **opened_path TSRMLS_DC)
+{
+ FILE *fp;
+
+ if (php_check_open_basedir((char *)path TSRMLS_CC)) {
+ return NULL;
+ }
+ fp = VCWD_FOPEN(path, mode);
+ if (fp && opened_path) {
+ *opened_path = expand_filepath_with_mode(path, NULL, NULL, 0, CWD_EXPAND TSRMLS_CC);
+ }
+ return fp;
+}
+/* }}} */
+
+/* {{{ php_fopen_primary_script
+ */
+PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC)
+{
+ char *path_info;
+ char *filename = NULL;
+ char *resolved_path = NULL;
+ int length;
+ zend_bool orig_display_errors;
+
+ path_info = SG(request_info).request_uri;
+#if HAVE_PWD_H
+ if (PG(user_dir) && *PG(user_dir) && path_info && '/' == path_info[0] && '~' == path_info[1]) {
+ char *s = strchr(path_info + 2, '/');
+
+ if (s) { /* if there is no path name after the file, do not bother */
+ char user[32]; /* to try open the directory */
+ struct passwd *pw;
+#if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
+ struct passwd pwstruc;
+ long pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+ char *pwbuf;
+
+ if (pwbuflen < 1) {
+ return FAILURE;
+ }
+
+ pwbuf = emalloc(pwbuflen);
+#endif
+ length = s - (path_info + 2);
+ if (length > (int)sizeof(user) - 1) {
+ length = sizeof(user) - 1;
+ }
+ memcpy(user, path_info + 2, length);
+ user[length] = '\0';
+#if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
+ if (getpwnam_r(user, &pwstruc, pwbuf, pwbuflen, &pw)) {
+ efree(pwbuf);
+ return FAILURE;
+ }
+#else
+ pw = getpwnam(user);
+#endif
+ if (pw && pw->pw_dir) {
+ spprintf(&filename, 0, "%s%c%s%c%s", pw->pw_dir, PHP_DIR_SEPARATOR, PG(user_dir), PHP_DIR_SEPARATOR, s + 1); /* Safe */
+ } else {
+ filename = SG(request_info).path_translated;
+ }
+#if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
+ efree(pwbuf);
+#endif
+ }
+ } else
+#endif
+ if (PG(doc_root) && path_info && (length = strlen(PG(doc_root))) &&
+ IS_ABSOLUTE_PATH(PG(doc_root), length)) {
+ int path_len = strlen(path_info);
+ filename = emalloc(length + path_len + 2);
+ if (filename) {
+ memcpy(filename, PG(doc_root), length);
+ if (!IS_SLASH(filename[length - 1])) { /* length is never 0 */
+ filename[length++] = PHP_DIR_SEPARATOR;
+ }
+ if (IS_SLASH(path_info[0])) {
+ length--;
+ }
+ strncpy(filename + length, path_info, path_len + 1);
+ }
+ } else {
+ filename = SG(request_info).path_translated;
+ }
+
+
+ if (filename) {
+ resolved_path = zend_resolve_path(filename, strlen(filename) TSRMLS_CC);
+ }
+
+ if (!resolved_path) {
+ if (SG(request_info).path_translated != filename) {
+ STR_FREE(filename);
+ }
+ /* we have to free SG(request_info).path_translated here because
+ * php_destroy_request_info assumes that it will get
+ * freed when the include_names hash is emptied, but
+ * we're not adding it in this case */
+ STR_FREE(SG(request_info).path_translated);
+ SG(request_info).path_translated = NULL;
+ return FAILURE;
+ }
+ efree(resolved_path);
+
+ orig_display_errors = PG(display_errors);
+ PG(display_errors) = 0;
+ if (zend_stream_open(filename, file_handle TSRMLS_CC) == FAILURE) {
+ PG(display_errors) = orig_display_errors;
+ if (SG(request_info).path_translated != filename) {
+ STR_FREE(filename);
+ }
+ STR_FREE(SG(request_info).path_translated); /* for same reason as above */
+ SG(request_info).path_translated = NULL;
+ return FAILURE;
+ }
+ PG(display_errors) = orig_display_errors;
+
+ if (SG(request_info).path_translated != filename) {
+ STR_FREE(SG(request_info).path_translated); /* for same reason as above */
+ SG(request_info).path_translated = filename;
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ php_resolve_path
+ * Returns the realpath for given filename according to include path
+ */
+PHPAPI char *php_resolve_path(const char *filename, int filename_length, const char *path TSRMLS_DC)
+{
+ char resolved_path[MAXPATHLEN];
+ char trypath[MAXPATHLEN];
+ const char *ptr, *end, *p;
+ char *actual_path;
+ php_stream_wrapper *wrapper;
+
+ if (!filename || CHECK_NULL_PATH(filename, filename_length)) {
+ return NULL;
+ }
+
+ /* Don't resolve paths which contain protocol (except of file://) */
+ for (p = filename; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
+ if ((*p == ':') && (p - filename > 1) && (p[1] == '/') && (p[2] == '/')) {
+ wrapper = php_stream_locate_url_wrapper(filename, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+ if (wrapper == &php_plain_files_wrapper) {
+ if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
+ return estrdup(resolved_path);
+ }
+ }
+ return NULL;
+ }
+
+ if ((*filename == '.' &&
+ (IS_SLASH(filename[1]) ||
+ ((filename[1] == '.') && IS_SLASH(filename[2])))) ||
+ IS_ABSOLUTE_PATH(filename, filename_length) ||
+ !path ||
+ !*path) {
+ if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
+ return estrdup(resolved_path);
+ } else {
+ return NULL;
+ }
+ }
+
+ ptr = path;
+ while (ptr && *ptr) {
+ /* Check for stream wrapper */
+ int is_stream_wrapper = 0;
+
+ for (p = ptr; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
+ if ((*p == ':') && (p - ptr > 1) && (p[1] == '/') && (p[2] == '/')) {
+ /* .:// or ..:// is not a stream wrapper */
+ if (p[-1] != '.' || p[-2] != '.' || p - 2 != ptr) {
+ p += 3;
+ is_stream_wrapper = 1;
+ }
+ }
+ end = strchr(p, DEFAULT_DIR_SEPARATOR);
+ if (end) {
+ if ((end-ptr) + 1 + filename_length + 1 >= MAXPATHLEN) {
+ ptr = end + 1;
+ continue;
+ }
+ memcpy(trypath, ptr, end-ptr);
+ trypath[end-ptr] = '/';
+ memcpy(trypath+(end-ptr)+1, filename, filename_length+1);
+ ptr = end+1;
+ } else {
+ int len = strlen(ptr);
+
+ if (len + 1 + filename_length + 1 >= MAXPATHLEN) {
+ break;
+ }
+ memcpy(trypath, ptr, len);
+ trypath[len] = '/';
+ memcpy(trypath+len+1, filename, filename_length+1);
+ ptr = NULL;
+ }
+ actual_path = trypath;
+ if (is_stream_wrapper) {
+ wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+ if (!wrapper) {
+ continue;
+ } else if (wrapper != &php_plain_files_wrapper) {
+ if (wrapper->wops->url_stat) {
+ php_stream_statbuf ssb;
+
+ if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
+ return estrdup(trypath);
+ }
+ }
+ continue;
+ }
+ }
+ if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
+ return estrdup(resolved_path);
+ }
+ } /* end provided path */
+
+ /* check in calling scripts' current working directory as a fall back case
+ */
+ if (zend_is_executing(TSRMLS_C)) {
+ const char *exec_fname = zend_get_executed_filename(TSRMLS_C);
+ int exec_fname_length = strlen(exec_fname);
+
+ while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
+ if (exec_fname && exec_fname[0] != '[' &&
+ exec_fname_length > 0 &&
+ exec_fname_length + 1 + filename_length + 1 < MAXPATHLEN) {
+ memcpy(trypath, exec_fname, exec_fname_length + 1);
+ memcpy(trypath+exec_fname_length + 1, filename, filename_length+1);
+ actual_path = trypath;
+
+ /* Check for stream wrapper */
+ for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
+ if ((*p == ':') && (p - trypath > 1) && (p[1] == '/') && (p[2] == '/')) {
+ wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+ if (!wrapper) {
+ return NULL;
+ } else if (wrapper != &php_plain_files_wrapper) {
+ if (wrapper->wops->url_stat) {
+ php_stream_statbuf ssb;
+
+ if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
+ return estrdup(trypath);
+ }
+ }
+ return NULL;
+ }
+ }
+
+ if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
+ return estrdup(resolved_path);
+ }
+ }
+ }
+
+ return NULL;
+}
+/* }}} */
+
+/* {{{ php_fopen_with_path
+ * Tries to open a file with a PATH-style list of directories.
+ * If the filename starts with "." or "/", the path is ignored.
+ */
+PHPAPI FILE *php_fopen_with_path(const char *filename, const char *mode, const char *path, char **opened_path TSRMLS_DC)
+{
+ char *pathbuf, *ptr, *end;
+ const char *exec_fname;
+ char trypath[MAXPATHLEN];
+ FILE *fp;
+ int path_length;
+ int filename_length;
+ int exec_fname_length;
+
+ if (opened_path) {
+ *opened_path = NULL;
+ }
+
+ if (!filename) {
+ return NULL;
+ }
+
+ filename_length = strlen(filename);
+
+ /* Relative path open */
+ if ((*filename == '.')
+ /* Absolute path open */
+ || IS_ABSOLUTE_PATH(filename, filename_length)
+ || (!path || (path && !*path))
+ ) {
+ return php_fopen_and_set_opened_path(filename, mode, opened_path TSRMLS_CC);
+ }
+
+ /* check in provided path */
+ /* append the calling scripts' current working directory
+ * as a fall back case
+ */
+ if (zend_is_executing(TSRMLS_C)) {
+ exec_fname = zend_get_executed_filename(TSRMLS_C);
+ exec_fname_length = strlen(exec_fname);
+ path_length = strlen(path);
+
+ while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
+ if ((exec_fname && exec_fname[0] == '[') || exec_fname_length <= 0) {
+ /* [no active file] or no path */
+ pathbuf = estrdup(path);
+ } else {
+ pathbuf = (char *) emalloc(exec_fname_length + path_length + 1 + 1);
+ memcpy(pathbuf, path, path_length);
+ pathbuf[path_length] = DEFAULT_DIR_SEPARATOR;
+ memcpy(pathbuf + path_length + 1, exec_fname, exec_fname_length);
+ pathbuf[path_length + exec_fname_length + 1] = '\0';
+ }
+ } else {
+ pathbuf = estrdup(path);
+ }
+
+ ptr = pathbuf;
+
+ while (ptr && *ptr) {
+ end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
+ if (end != NULL) {
+ *end = '\0';
+ end++;
+ }
+ if (snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename) >= MAXPATHLEN) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN);
+ }
+ fp = php_fopen_and_set_opened_path(trypath, mode, opened_path TSRMLS_CC);
+ if (fp) {
+ efree(pathbuf);
+ return fp;
+ }
+ ptr = end;
+ } /* end provided path */
+
+ efree(pathbuf);
+ return NULL;
+}
+/* }}} */
+
+/* {{{ php_strip_url_passwd
+ */
+PHPAPI char *php_strip_url_passwd(char *url)
+{
+ register char *p, *url_start;
+
+ if (url == NULL) {
+ return "";
+ }
+
+ p = url;
+
+ while (*p) {
+ if (*p == ':' && *(p + 1) == '/' && *(p + 2) == '/') {
+ /* found protocol */
+ url_start = p = p + 3;
+
+ while (*p) {
+ if (*p == '@') {
+ int i;
+
+ for (i = 0; i < 3 && url_start < p; i++, url_start++) {
+ *url_start = '.';
+ }
+ for (; *p; p++) {
+ *url_start++ = *p;
+ }
+ *url_start=0;
+ break;
+ }
+ p++;
+ }
+ return url;
+ }
+ p++;
+ }
+ return url;
+}
+/* }}} */
+
+/* {{{ expand_filepath
+ */
+PHPAPI char *expand_filepath(const char *filepath, char *real_path TSRMLS_DC)
+{
+ return expand_filepath_ex(filepath, real_path, NULL, 0 TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ expand_filepath_ex
+ */
+PHPAPI char *expand_filepath_ex(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len TSRMLS_DC)
+{
+ return expand_filepath_with_mode(filepath, real_path, relative_to, relative_to_len, CWD_FILEPATH TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ expand_filepath_use_realpath
+ */
+PHPAPI char *expand_filepath_with_mode(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len, int realpath_mode TSRMLS_DC)
+{
+ cwd_state new_state;
+ char cwd[MAXPATHLEN];
+ int copy_len;
+
+ if (!filepath[0]) {
+ return NULL;
+ } else if (IS_ABSOLUTE_PATH(filepath, strlen(filepath))) {
+ cwd[0] = '\0';
+ } else {
+ const char *iam = SG(request_info).path_translated;
+ const char *result;
+ if (relative_to) {
+ if (relative_to_len > MAXPATHLEN-1U) {
+ return NULL;
+ }
+ result = relative_to;
+ memcpy(cwd, relative_to, relative_to_len+1U);
+ } else {
+ result = VCWD_GETCWD(cwd, MAXPATHLEN);
+ }
+
+ if (!result && (iam != filepath)) {
+ int fdtest = -1;
+
+ fdtest = VCWD_OPEN(filepath, O_RDONLY);
+ if (fdtest != -1) {
+ /* return a relative file path if for any reason
+ * we cannot cannot getcwd() and the requested,
+ * relatively referenced file is accessible */
+ copy_len = strlen(filepath) > MAXPATHLEN - 1 ? MAXPATHLEN - 1 : strlen(filepath);
+ real_path = estrndup(filepath, copy_len);
+ close(fdtest);
+ return real_path;
+ } else {
+ cwd[0] = '\0';
+ }
+ } else if (!result) {
+ cwd[0] = '\0';
+ }
+ }
+
+ new_state.cwd = strdup(cwd);
+ new_state.cwd_length = strlen(cwd);
+
+ if (virtual_file_ex(&new_state, filepath, NULL, realpath_mode TSRMLS_CC)) {
+ free(new_state.cwd);
+ return NULL;
+ }
+
+ if (real_path) {
+ copy_len = new_state.cwd_length > MAXPATHLEN - 1 ? MAXPATHLEN - 1 : new_state.cwd_length;
+ memcpy(real_path, new_state.cwd, copy_len);
+ real_path[copy_len] = '\0';
+ } else {
+ real_path = estrndup(new_state.cwd, new_state.cwd_length);
+ }
+ free(new_state.cwd);
+
+ return real_path;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/fopen_wrappers.h b/main/fopen_wrappers.h
new file mode 100644
index 0000000..ae0001f
--- /dev/null
+++ b/main/fopen_wrappers.h
@@ -0,0 +1,64 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Jim Winstead <jimw@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef FOPEN_WRAPPERS_H
+#define FOPEN_WRAPPERS_H
+
+BEGIN_EXTERN_C()
+#include "php_globals.h"
+#include "php_ini.h"
+
+PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC);
+PHPAPI char *expand_filepath(const char *filepath, char *real_path TSRMLS_DC);
+PHPAPI char *expand_filepath_ex(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len TSRMLS_DC);
+PHPAPI char *expand_filepath_with_mode(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len, int realpath_mode TSRMLS_DC);
+
+PHPAPI int php_check_open_basedir(const char *path TSRMLS_DC);
+PHPAPI int php_check_open_basedir_ex(const char *path, int warn TSRMLS_DC);
+PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path TSRMLS_DC);
+
+/* {{{ OPENBASEDIR_CHECKPATH(filename) to ease merge between 6.x and 5.x */
+#if PHP_API_VERSION < 20100412
+# define OPENBASEDIR_CHECKPATH(filename) \
+ (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)
+#else
+#define OPENBASEDIR_CHECKPATH(filename) \
+ php_check_open_basedir(filename TSRMLS_CC)
+#endif
+/* }}} */
+
+PHPAPI int php_check_safe_mode_include_dir(const char *path TSRMLS_DC);
+
+PHPAPI char *php_resolve_path(const char *filename, int filename_len, const char *path TSRMLS_DC);
+
+PHPAPI FILE *php_fopen_with_path(const char *filename, const char *mode, const char *path, char **opened_path TSRMLS_DC);
+
+PHPAPI char *php_strip_url_passwd(char *path);
+
+PHPAPI ZEND_INI_MH(OnUpdateBaseDir);
+END_EXTERN_C()
+
+#endif
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/main/getopt.c b/main/getopt.c
new file mode 100644
index 0000000..591c8c7
--- /dev/null
+++ b/main/getopt.c
@@ -0,0 +1,199 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include "php_getopt.h"
+
+#define OPTERRCOLON (1)
+#define OPTERRNF (2)
+#define OPTERRARG (3)
+
+static int php_opt_error(int argc, char * const *argv, int oint, int optchr, int err, int show_err) /* {{{ */
+{
+ if (show_err)
+ {
+ fprintf(stderr, "Error in argument %d, char %d: ", oint, optchr+1);
+ switch(err)
+ {
+ case OPTERRCOLON:
+ fprintf(stderr, ": in flags\n");
+ break;
+ case OPTERRNF:
+ fprintf(stderr, "option not found %c\n", argv[oint][optchr]);
+ break;
+ case OPTERRARG:
+ fprintf(stderr, "no argument for option %c\n", argv[oint][optchr]);
+ break;
+ default:
+ fprintf(stderr, "unknown\n");
+ break;
+ }
+ }
+ return('?');
+}
+/* }}} */
+
+PHPAPI int php_optidx = -1;
+
+PHPAPI int php_getopt(int argc, char* const *argv, const opt_struct opts[], char **optarg, int *optind, int show_err, int arg_start) /* {{{ */
+{
+ static int optchr = 0;
+ static int dash = 0; /* have already seen the - */
+
+ php_optidx = -1;
+
+ if (*optind >= argc) {
+ return(EOF);
+ }
+ if (!dash) {
+ if ((argv[*optind][0] != '-')) {
+ return(EOF);
+ } else {
+ if (!argv[*optind][1])
+ {
+ /*
+ * use to specify stdin. Need to let pgm process this and
+ * the following args
+ */
+ return(EOF);
+ }
+ }
+ }
+ if ((argv[*optind][0] == '-') && (argv[*optind][1] == '-')) {
+ char *pos;
+ int arg_end = strlen(argv[*optind])-1;
+
+ /* '--' indicates end of args if not followed by a known long option name */
+ if (argv[*optind][2] == '\0') {
+ (*optind)++;
+ return(EOF);
+ }
+
+ arg_start = 2;
+
+ /* Check for <arg>=<val> */
+ if ((pos = php_memnstr(&argv[*optind][arg_start], "=", 1, argv[*optind]+arg_end)) != NULL) {
+ arg_end = pos-&argv[*optind][arg_start];
+ arg_start++;
+ } else {
+ arg_end--;
+ }
+
+ while (1) {
+ php_optidx++;
+ if (opts[php_optidx].opt_char == '-') {
+ (*optind)++;
+ return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
+ } else if (opts[php_optidx].opt_name && !strncmp(&argv[*optind][2], opts[php_optidx].opt_name, arg_end) && arg_end == strlen(opts[php_optidx].opt_name)) {
+ break;
+ }
+ }
+
+ optchr = 0;
+ dash = 0;
+ arg_start += strlen(opts[php_optidx].opt_name);
+ } else {
+ if (!dash) {
+ dash = 1;
+ optchr = 1;
+ }
+ /* Check if the guy tries to do a -: kind of flag */
+ if (argv[*optind][optchr] == ':') {
+ dash = 0;
+ (*optind)++;
+ return (php_opt_error(argc, argv, *optind-1, optchr, OPTERRCOLON, show_err));
+ }
+ arg_start = 1 + optchr;
+ }
+ if (php_optidx < 0) {
+ while (1) {
+ php_optidx++;
+ if (opts[php_optidx].opt_char == '-') {
+ int errind = *optind;
+ int errchr = optchr;
+
+ if (!argv[*optind][optchr+1]) {
+ dash = 0;
+ (*optind)++;
+ } else {
+ optchr++;
+ arg_start++;
+ }
+ return(php_opt_error(argc, argv, errind, errchr, OPTERRNF, show_err));
+ } else if (argv[*optind][optchr] == opts[php_optidx].opt_char) {
+ break;
+ }
+ }
+ }
+ if (opts[php_optidx].need_param) {
+ /* Check for cases where the value of the argument
+ is in the form -<arg> <val>, -<arg>=<varl> or -<arg><val> */
+ dash = 0;
+ if (!argv[*optind][arg_start]) {
+ (*optind)++;
+ if (*optind == argc) {
+ /* Was the value required or is it optional? */
+ if (opts[php_optidx].need_param == 1) {
+ return(php_opt_error(argc, argv, *optind-1, optchr, OPTERRARG, show_err));
+ }
+ /* Optional value is not supported with -<arg> <val> style */
+ } else if (opts[php_optidx].need_param == 1) {
+ *optarg = argv[(*optind)++];
+ }
+ } else if (argv[*optind][arg_start] == '=') {
+ arg_start++;
+ *optarg = &argv[*optind][arg_start];
+ (*optind)++;
+ } else {
+ *optarg = &argv[*optind][arg_start];
+ (*optind)++;
+ }
+ return opts[php_optidx].opt_char;
+ } else {
+ /* multiple options specified as one (exclude long opts) */
+ if (arg_start >= 2 && !((argv[*optind][0] == '-') && (argv[*optind][1] == '-'))) {
+ if (!argv[*optind][optchr+1])
+ {
+ dash = 0;
+ (*optind)++;
+ } else {
+ optchr++;
+ }
+ } else {
+ (*optind)++;
+ }
+ return opts[php_optidx].opt_char;
+ }
+ assert(0);
+ return(0); /* never reached */
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/internal_functions.c.in b/main/internal_functions.c.in
new file mode 100644
index 0000000..f1e66b1
--- /dev/null
+++ b/main/internal_functions.c.in
@@ -0,0 +1,48 @@
+/* -*- C -*-
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "php.h"
+#include "php_main.h"
+#include "zend_modules.h"
+#include "zend_compile.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+@EXT_INCLUDE_CODE@
+
+static zend_module_entry *php_builtin_extensions[] = {
+@EXT_MODULE_PTRS@
+};
+
+#define EXTCOUNT (sizeof(php_builtin_extensions)/sizeof(zend_module_entry *))
+
+PHPAPI int php_register_internal_extensions(TSRMLS_D)
+{
+ return php_register_extensions(php_builtin_extensions, EXTCOUNT TSRMLS_CC);
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/main/internal_functions_nw.c b/main/internal_functions_nw.c
new file mode 100644
index 0000000..07aec9a
--- /dev/null
+++ b/main/internal_functions_nw.c
@@ -0,0 +1,100 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ | Modified for NetWare: Novell, Inc. |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/* {{{ includes
+ */
+#include "php.h"
+#include "php_main.h"
+#include "zend_modules.h"
+#include "zend_compile.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "ext/bcmath/php_bcmath.h"
+#include "ext/gd/php_gd.h"
+#include "ext/standard/dl.h"
+#include "ext/standard/file.h"
+#include "ext/standard/fsock.h"
+#include "ext/standard/head.h"
+#include "ext/standard/pack.h"
+#include "ext/standard/php_browscap.h"
+/*#include "ext/standard/php_crypt.h"*/
+#include "ext/standard/php_dir.h"
+#include "ext/standard/php_filestat.h"
+#include "ext/standard/php_mail.h"
+/*#include "ext/standard/php_ext_syslog.h"*/
+#include "ext/standard/php_standard.h"
+#include "ext/standard/php_lcg.h"
+#include "ext/standard/php_array.h"
+#include "ext/standard/php_assert.h"
+#include "ext/calendar/php_calendar.h"
+/*#include "ext/com/php_COM.h"
+#include "ext/com/php_VARIANT.h"*/
+#include "ext/ftp/php_ftp.h"
+#include "ext/standard/reg.h"
+#include "ext/pcre/php_pcre.h"
+/*#include "ext/odbc/php_odbc.h"*/ /* Commented out for now */
+#include "ext/session/php_session.h"
+/*#include "ext/xml/php_xml.h"
+#include "ext/wddx/php_wddx.h"
+#include "ext/mysql/php_mysql.h"*/ /* Commented out for now */
+/* }}} */
+
+/* {{{ php_builtin_extensions[]
+ */
+static zend_module_entry *php_builtin_extensions[] = {
+ phpext_standard_ptr,
+#if HAVE_BCMATH
+ phpext_bcmath_ptr,
+#endif
+ phpext_calendar_ptr,
+/* COM_module_ptr,*/
+ phpext_ftp_ptr,
+#if defined(MBSTR_ENC_TRANS)
+ phpext_mbstring_ptr,
+#endif
+/* phpext_mysql_ptr,*/ /* Commented out for now */
+/* phpext_odbc_ptr, */ /* Commented out for now */
+ phpext_pcre_ptr,
+ phpext_session_ptr,
+/* phpext_xml_ptr,
+ phpext_wddx_ptr */ /* Commented out for now */
+};
+/* }}} */
+
+#define EXTCOUNT (sizeof(php_builtin_extensions)/sizeof(zend_module_entry *))
+
+PHPAPI int php_register_internal_extensions(TSRMLS_D)
+{
+ return php_register_extensions(php_builtin_extensions, EXTCOUNT TSRMLS_CC);
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/internal_functions_win32.c b/main/internal_functions_win32.c
new file mode 100644
index 0000000..06cd5b2
--- /dev/null
+++ b/main/internal_functions_win32.c
@@ -0,0 +1,208 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/* {{{ includes
+ */
+#include "php.h"
+#include "php_main.h"
+#include "zend_modules.h"
+#include "zend_compile.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifndef ZEND_ENGINE_2
+#error HEAD does not work with ZendEngine1 anymore
+#endif
+
+#include "ext/standard/dl.h"
+#include "ext/standard/file.h"
+#include "ext/standard/fsock.h"
+#include "ext/standard/head.h"
+#include "ext/standard/pack.h"
+#include "ext/standard/php_browscap.h"
+#include "ext/standard/php_crypt.h"
+#include "ext/standard/php_dir.h"
+#include "ext/standard/php_filestat.h"
+#include "ext/standard/php_mail.h"
+#include "ext/standard/php_ext_syslog.h"
+#include "ext/standard/php_standard.h"
+#include "ext/standard/php_lcg.h"
+#include "ext/standard/php_array.h"
+#include "ext/standard/php_assert.h"
+#include "ext/reflection/php_reflection.h"
+#if HAVE_BCMATH
+#include "ext/bcmath/php_bcmath.h"
+#endif
+#if HAVE_CALENDAR
+#include "ext/calendar/php_calendar.h"
+#endif
+#if HAVE_CTYPE
+#include "ext/ctype/php_ctype.h"
+#endif
+#if HAVE_DATE
+#include "ext/date/php_date.h"
+#endif
+#if HAVE_FTP
+#include "ext/ftp/php_ftp.h"
+#endif
+#if HAVE_ICONV
+#include "ext/iconv/php_iconv.h"
+#endif
+#include "ext/standard/reg.h"
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+#include "ext/pcre/php_pcre.h"
+#endif
+#if HAVE_UODBC
+#include "ext/odbc/php_odbc.h"
+#endif
+#if HAVE_PHP_SESSION
+#include "ext/session/php_session.h"
+#endif
+#if HAVE_MBSTRING
+#include "ext/mbstring/mbstring.h"
+#endif
+#if HAVE_TOKENIZER
+#include "ext/tokenizer/php_tokenizer.h"
+#endif
+#if HAVE_ZLIB
+#include "ext/zlib/php_zlib.h"
+#endif
+#if HAVE_LIBXML
+#include "ext/libxml/php_libxml.h"
+#if HAVE_DOM
+#include "ext/dom/php_dom.h"
+#endif
+#if HAVE_SIMPLEXML
+#include "ext/simplexml/php_simplexml.h"
+#endif
+#endif
+#if HAVE_XML
+#include "ext/xml/php_xml.h"
+#endif
+#if HAVE_XML && HAVE_WDDX
+#include "ext/wddx/php_wddx.h"
+#endif
+#ifdef HAVE_SQLITE
+#include "ext/sqlite/php_sqlite.h"
+#endif
+#include "ext/com_dotnet/php_com_dotnet.h"
+#ifdef HAVE_SPL
+#include "ext/spl/php_spl.h"
+#endif
+#if HAVE_XML && HAVE_XMLREADER
+#include "ext/xmlreader/php_xmlreader.h"
+#endif
+#if HAVE_XML && HAVE_XMLWRITER
+#include "ext/xmlwriter/php_xmlwriter.h"
+#endif
+/* }}} */
+
+/* {{{ php_builtin_extensions[]
+ */
+static zend_module_entry *php_builtin_extensions[] = {
+ phpext_standard_ptr
+#if HAVE_BCMATH
+ ,phpext_bcmath_ptr
+#endif
+#if HAVE_CALENDAR
+ ,phpext_calendar_ptr
+#endif
+ ,phpext_com_dotnet_ptr
+#if HAVE_CTYPE
+ ,phpext_ctype_ptr
+#endif
+#if HAVE_DATE
+ ,phpext_date_ptr
+#endif
+#if HAVE_FTP
+ ,phpext_ftp_ptr
+#endif
+#if HAVE_HASH
+ ,phpext_hash_ptr
+#endif
+#if HAVE_ICONV
+ ,phpext_iconv_ptr
+#endif
+#if HAVE_MBSTRING
+ ,phpext_mbstring_ptr
+#endif
+#if HAVE_UODBC
+ ,phpext_odbc_ptr
+#endif
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ ,phpext_pcre_ptr
+#endif
+ ,phpext_reflection_ptr
+#if HAVE_PHP_SESSION
+ ,phpext_session_ptr
+#endif
+#if HAVE_TOKENIZER
+ ,phpext_tokenizer_ptr
+#endif
+#if HAVE_ZLIB
+ ,phpext_zlib_ptr
+#endif
+#if HAVE_LIBXML
+ ,phpext_libxml_ptr
+#if HAVE_DOM
+ ,phpext_dom_ptr
+#endif
+#if HAVE_SIMPLEXML
+ ,phpext_simplexml_ptr
+#endif
+#endif
+#if HAVE_XML
+ ,phpext_xml_ptr
+#endif
+#if HAVE_XML && HAVE_WDDX
+ ,phpext_wddx_ptr
+#endif
+#if HAVE_SQLITE
+ ,phpext_sqlite_ptr
+#endif
+#if HAVE_SPL
+ ,phpext_spl_ptr
+#endif
+#if HAVE_XML && HAVE_XMLREADER
+ ,phpext_xmlreader_ptr
+#endif
+#if HAVE_XML && HAVE_XMLWRITER
+ ,phpext_xmlwriter_ptr
+#endif
+};
+/* }}} */
+
+#define EXTCOUNT (sizeof(php_builtin_extensions)/sizeof(zend_module_entry *))
+
+PHPAPI int php_register_internal_extensions(TSRMLS_D)
+{
+ return php_register_extensions(php_builtin_extensions, EXTCOUNT TSRMLS_CC);
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/logos.h b/main/logos.h
new file mode 100644
index 0000000..eb28107
--- /dev/null
+++ b/main/logos.h
@@ -0,0 +1,1080 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#define CONTEXT_TYPE_IMAGE_GIF "Content-Type: image/gif"
+
+static const unsigned char zend_logo[] = {
+ 71, 73, 70, 56, 57, 97, 113, 0, 72, 0,
+ 213, 0, 0, 13, 13, 14, 1, 3, 6, 2,
+ 5, 9, 46, 68, 94, 21, 29, 39, 5, 15,
+ 26, 4, 10, 17, 29, 43, 58, 0, 1, 2,
+ 9, 25, 42, 38, 105, 171, 24, 67, 109, 13,
+ 36, 59, 10, 27, 45, 9, 25, 41, 35, 96,
+ 157, 32, 87, 142, 29, 79, 130, 26, 70, 114,
+ 20, 54, 87, 29, 77, 124, 10, 26, 42, 34,
+ 88, 141, 10, 24, 38, 11, 26, 41, 1, 2,
+ 3, 55, 80, 105, 45, 63, 81, 49, 53, 57,
+ 5, 15, 24, 9, 26, 42, 30, 85, 138, 33,
+ 92, 149, 26, 73, 117, 10, 28, 45, 32, 89,
+ 142, 30, 84, 134, 26, 72, 115, 15, 42, 67,
+ 23, 62, 99, 12, 32, 51, 7, 21, 33, 9,
+ 26, 41, 8, 23, 35, 7, 25, 37, 51, 58,
+ 63, 2, 4, 5, 25, 26, 26, 49, 50, 50,
+ 255, 102, 0, 255, 255, 255, 204, 204, 204, 199,
+ 199, 199, 191, 191, 191, 171, 171, 171, 146, 146,
+ 146, 115, 115, 115, 85, 85, 85, 60, 60, 60,
+ 55, 55, 55, 38, 38, 38, 7, 7, 7, 3,
+ 3, 3, 0, 0, 0, 44, 0, 0, 0, 0,
+ 113, 0, 72, 0, 0, 6, 255, 192, 153, 112,
+ 72, 44, 26, 143, 200, 164, 114, 121, 252, 49,
+ 159, 208, 168, 148, 248, 171, 58, 167, 210, 171,
+ 208, 170, 197, 122, 191, 70, 109, 23, 140, 236,
+ 138, 201, 232, 239, 121, 102, 221, 186, 217, 219,
+ 171, 83, 46, 110, 15, 207, 235, 180, 190, 124,
+ 135, 187, 229, 127, 127, 128, 112, 121, 108, 118,
+ 132, 123, 137, 77, 118, 120, 136, 115, 109, 117,
+ 85, 126, 147, 147, 128, 99, 138, 137, 99, 107,
+ 146, 146, 148, 133, 159, 125, 136, 152, 163, 151,
+ 135, 121, 144, 84, 157, 92, 169, 157, 111, 163,
+ 175, 176, 83, 151, 177, 180, 181, 161, 182, 184,
+ 185, 186, 187, 188, 189, 67, 54, 56, 58, 56,
+ 53, 190, 197, 88, 55, 57, 60, 63, 2, 43,
+ 2, 56, 198, 208, 74, 192, 58, 0, 63, 5,
+ 12, 11, 35, 35, 12, 47, 209, 222, 67, 53,
+ 201, 203, 34, 19, 20, 218, 231, 37, 63, 54,
+ 223, 222, 60, 2, 216, 231, 241, 231, 206, 76,
+ 193, 55, 236, 176, 63, 39, 242, 252, 35, 40,
+ 58, 75, 114, 8, 40, 240, 227, 25, 62, 76,
+ 60, 24, 244, 147, 55, 161, 202, 11, 24, 57,
+ 134, 17, 201, 241, 99, 130, 191, 130, 7, 21,
+ 225, 48, 176, 48, 30, 137, 5, 11, 38, 48,
+ 88, 81, 5, 198, 51, 138, 22, 181, 53, 52,
+ 152, 49, 141, 141, 31, 230, 58, 46, 60, 129,
+ 194, 74, 202, 115, 43, 91, 234, 1, 112, 83,
+ 102, 63, 255, 18, 38, 122, 226, 252, 145, 67,
+ 39, 153, 26, 47, 68, 248, 92, 186, 176, 97,
+ 81, 163, 88, 108, 188, 48, 80, 130, 169, 85,
+ 134, 68, 161, 74, 177, 1, 160, 0, 137, 171,
+ 96, 135, 62, 213, 186, 132, 171, 215, 176, 104,
+ 71, 52, 188, 71, 54, 9, 210, 179, 105, 195,
+ 166, 99, 219, 214, 198, 58, 34, 48, 12, 124,
+ 213, 38, 163, 175, 223, 191, 50, 22, 132, 216,
+ 139, 182, 132, 0, 30, 196, 250, 218, 37, 70,
+ 198, 198, 141, 199, 144, 31, 223, 253, 114, 163,
+ 10, 0, 97, 192, 126, 100, 59, 7, 24, 176,
+ 10, 20, 229, 210, 146, 48, 128, 88, 72, 223,
+ 28, 57, 38, 111, 197, 17, 163, 181, 235, 215,
+ 58, 116, 68, 100, 60, 5, 134, 136, 18, 19,
+ 80, 24, 168, 162, 48, 94, 95, 21, 6, 82,
+ 168, 80, 209, 215, 128, 1, 20, 39, 8, 95,
+ 37, 81, 160, 180, 105, 25, 177, 233, 62, 1,
+ 246, 186, 186, 245, 24, 209, 177, 84, 140, 71,
+ 97, 130, 114, 109, 33, 76, 48, 152, 176, 192,
+ 111, 135, 20, 222, 211, 54, 167, 61, 163, 111,
+ 246, 39, 55, 174, 203, 175, 254, 30, 74, 229,
+ 152, 62, 73, 132, 24, 60, 162, 47, 131, 14,
+ 12, 132, 224, 155, 95, 130, 145, 208, 89, 129,
+ 40, 116, 211, 25, 12, 58, 72, 135, 68, 124,
+ 214, 197, 38, 161, 14, 243, 73, 200, 222, 18,
+ 27, 161, 213, 215, 4, 159, 37, 199, 255, 25,
+ 96, 12, 116, 230, 223, 9, 11, 252, 32, 226,
+ 11, 13, 74, 35, 223, 132, 19, 174, 24, 27,
+ 75, 76, 192, 128, 66, 88, 126, 161, 160, 66,
+ 122, 124, 201, 112, 2, 3, 195, 125, 54, 65,
+ 95, 29, 4, 87, 227, 9, 126, 233, 192, 3,
+ 12, 125, 161, 232, 160, 93, 207, 184, 200, 98,
+ 139, 17, 74, 24, 197, 118, 96, 249, 7, 160,
+ 128, 31, 242, 72, 30, 72, 33, 244, 149, 2,
+ 122, 229, 201, 0, 224, 105, 60, 52, 216, 23,
+ 131, 14, 226, 96, 194, 1, 78, 74, 152, 195,
+ 13, 196, 208, 192, 90, 148, 177, 217, 7, 83,
+ 149, 50, 112, 136, 220, 94, 34, 22, 216, 159,
+ 12, 195, 101, 227, 37, 113, 50, 192, 0, 3,
+ 156, 238, 165, 72, 196, 11, 21, 178, 184, 228,
+ 117, 19, 66, 145, 225, 85, 53, 222, 72, 152,
+ 136, 42, 152, 32, 224, 111, 42, 8, 10, 40,
+ 161, 101, 222, 96, 67, 95, 61, 40, 58, 3,
+ 13, 55, 24, 112, 221, 101, 19, 226, 64, 131,
+ 17, 54, 64, 42, 229, 19, 50, 226, 249, 95,
+ 128, 127, 238, 23, 166, 113, 194, 105, 250, 103,
+ 160, 191, 18, 90, 232, 13, 59, 0, 249, 130,
+ 168, 56, 160, 198, 195, 10, 214, 161, 144, 1,
+ 131, 245, 21, 1, 33, 125, 177, 141, 181, 4,
+ 149, 76, 137, 232, 23, 3, 38, 132, 9, 216,
+ 9, 93, 126, 234, 105, 160, 34, 94, 208, 129,
+ 14, 7, 152, 112, 255, 2, 4, 40, 84, 80,
+ 157, 8, 30, 176, 154, 195, 133, 68, 200, 250,
+ 34, 124, 119, 102, 171, 109, 113, 157, 142, 16,
+ 238, 111, 160, 113, 58, 110, 167, 38, 252, 213,
+ 192, 193, 12, 72, 32, 193, 3, 15, 128, 192,
+ 128, 7, 175, 121, 32, 66, 7, 101, 230, 240,
+ 42, 18, 53, 216, 171, 131, 106, 73, 224, 32,
+ 0, 88, 221, 217, 216, 227, 200, 190, 234, 39,
+ 210, 112, 12, 36, 23, 158, 175, 254, 154, 160,
+ 105, 9, 5, 236, 88, 129, 7, 41, 83, 240,
+ 65, 195, 32, 56, 236, 128, 107, 14, 36, 208,
+ 64, 10, 24, 41, 161, 177, 181, 74, 84, 182,
+ 194, 4, 85, 45, 181, 239, 134, 11, 236, 165,
+ 31, 151, 95, 233, 199, 223, 8, 82, 27, 40,
+ 3, 9, 39, 144, 56, 24, 4, 92, 119, 61,
+ 129, 3, 96, 135, 221, 128, 8, 12, 0, 64,
+ 239, 47, 26, 59, 88, 52, 53, 227, 132, 182,
+ 208, 210, 128, 178, 76, 163, 12, 46, 135, 208,
+ 245, 221, 92, 3, 21, 54, 216, 9, 152, 208,
+ 48, 64, 72, 12, 237, 197, 52, 0, 152, 208,
+ 209, 111, 193, 141, 204, 239, 102, 104, 45, 96,
+ 128, 9, 20, 224, 45, 249, 215, 97, 51, 240,
+ 1, 8, 10, 152, 80, 20, 14, 56, 208, 213,
+ 38, 199, 181, 245, 214, 207, 111, 96, 130, 4,
+ 146, 72, 114, 135, 69, 194, 10, 38, 64, 0,
+ 130, 228, 120, 71, 240, 181, 8, 145, 67, 240,
+ 255, 128, 2, 44, 164, 0, 26, 2, 66, 180,
+ 9, 163, 23, 56, 20, 112, 184, 184, 242, 232,
+ 119, 224, 212, 127, 18, 56, 152, 95, 14, 252,
+ 8, 88, 129, 120, 255, 37, 216, 205, 17, 68,
+ 160, 192, 3, 24, 212, 64, 131, 198, 58, 92,
+ 12, 70, 101, 223, 125, 8, 172, 60, 218, 166,
+ 252, 149, 136, 41, 251, 21, 64, 249, 201, 117,
+ 221, 89, 202, 151, 131, 112, 251, 9, 211, 194,
+ 54, 161, 218, 88, 212, 128, 237, 128, 207, 35,
+ 15, 164, 144, 125, 65, 78, 141, 206, 3, 164,
+ 0, 245, 69, 0, 34, 248, 95, 10, 134, 68,
+ 2, 8, 244, 101, 71, 97, 3, 77, 237, 70,
+ 240, 0, 18, 248, 110, 15, 58, 80, 10, 63,
+ 48, 37, 55, 47, 129, 169, 128, 86, 10, 152,
+ 12, 132, 19, 166, 2, 36, 112, 132, 31, 20,
+ 83, 128, 28, 40, 3, 6, 52, 207, 116, 91,
+ 227, 218, 3, 218, 68, 52, 50, 224, 32, 95,
+ 228, 147, 1, 175, 134, 211, 65, 226, 13, 138,
+ 116, 222, 249, 77, 1, 10, 38, 3, 7, 52,
+ 160, 47, 96, 91, 0, 11, 83, 224, 128, 62,
+ 197, 176, 107, 32, 224, 222, 217, 192, 240, 130,
+ 25, 109, 16, 133, 91, 242, 159, 15, 63, 37,
+ 176, 63, 25, 64, 0, 68, 108, 128, 7, 144,
+ 232, 0, 37, 146, 81, 68, 14, 208, 20, 20,
+ 163, 72, 167, 216, 128, 14, 85, 201, 66, 205,
+ 155, 110, 224, 61, 37, 220, 255, 16, 63, 226,
+ 235, 215, 135, 194, 5, 44, 78, 249, 5, 61,
+ 86, 251, 65, 5, 36, 208, 23, 15, 52, 177,
+ 136, 101, 100, 97, 18, 195, 197, 171, 52, 218,
+ 205, 117, 51, 108, 163, 169, 132, 16, 171, 54,
+ 118, 174, 142, 69, 48, 75, 248, 224, 22, 162,
+ 45, 146, 171, 51, 8, 160, 221, 25, 17, 105,
+ 70, 82, 90, 237, 91, 131, 137, 164, 37, 137,
+ 80, 73, 238, 221, 11, 86, 93, 9, 95, 242,
+ 180, 101, 128, 46, 10, 236, 148, 126, 177, 6,
+ 5, 70, 153, 68, 69, 38, 18, 2, 255, 42,
+ 34, 104, 34, 160, 74, 106, 9, 99, 8, 245,
+ 51, 230, 147, 126, 55, 131, 26, 196, 178, 35,
+ 225, 25, 153, 52, 131, 82, 55, 240, 84, 19,
+ 107, 60, 234, 11, 0, 12, 16, 1, 16, 148,
+ 160, 110, 43, 123, 100, 56, 243, 22, 2, 145,
+ 128, 45, 101, 16, 152, 15, 118, 44, 54, 131,
+ 100, 218, 239, 73, 111, 58, 66, 13, 120, 0,
+ 151, 133, 60, 205, 116, 248, 20, 12, 5, 246,
+ 227, 52, 126, 106, 195, 120, 50, 56, 146, 1,
+ 46, 247, 1, 126, 86, 141, 156, 79, 132, 192,
+ 61, 67, 240, 1, 117, 182, 6, 85, 141, 90,
+ 38, 232, 134, 176, 17, 89, 198, 165, 35, 134,
+ 17, 70, 14, 92, 32, 63, 134, 141, 224, 117,
+ 176, 11, 105, 215, 44, 232, 208, 136, 178, 72,
+ 34, 118, 212, 203, 69, 173, 226, 148, 26, 216,
+ 133, 7, 255, 39, 80, 192, 4, 102, 42, 191,
+ 17, 136, 52, 164, 37, 109, 211, 253, 48, 137,
+ 49, 122, 90, 116, 165, 255, 100, 64, 86, 40,
+ 74, 128, 22, 0, 224, 6, 48, 152, 128, 2,
+ 64, 122, 211, 187, 229, 84, 153, 142, 226, 169,
+ 18, 230, 41, 128, 164, 1, 149, 31, 37, 98,
+ 166, 93, 134, 192, 129, 133, 49, 181, 169, 36,
+ 125, 234, 147, 36, 68, 71, 47, 80, 213, 170,
+ 252, 32, 79, 92, 232, 177, 4, 14, 80, 32,
+ 103, 77, 229, 218, 83, 177, 51, 214, 6, 73,
+ 53, 10, 103, 237, 71, 67, 126, 96, 0, 164,
+ 133, 69, 4, 128, 147, 134, 15, 72, 240, 85,
+ 174, 229, 236, 176, 175, 203, 105, 93, 223, 116,
+ 215, 41, 228, 53, 30, 43, 177, 65, 14, 94,
+ 80, 133, 21, 160, 64, 93, 75, 153, 0, 0,
+ 158, 224, 130, 19, 60, 224, 110, 57, 99, 216,
+ 237, 74, 0, 130, 8, 120, 192, 3, 99, 243,
+ 192, 97, 234, 58, 161, 120, 42, 226, 177, 106,
+ 9, 26, 37, 57, 167, 131, 23, 8, 207, 39,
+ 20, 248, 1, 254, 136, 80, 3, 20, 44, 21,
+ 180, 32, 32, 79, 4, 80, 16, 128, 11, 64,
+ 64, 4, 34, 80, 65, 7, 94, 80, 38, 214,
+ 202, 102, 183, 105, 168, 1, 12, 170, 26, 219,
+ 26, 34, 19, 135, 29, 41, 128, 117, 137, 128,
+ 3, 9, 252, 214, 176, 15, 24, 64, 15, 56,
+ 247, 12, 24, 168, 75, 4, 6, 0, 135, 192,
+ 14, 156, 139, 82, 90, 8, 164, 38, 219, 29,
+ 2, 79, 150, 194, 0, 24, 44, 97, 7, 22,
+ 184, 29, 195, 58, 106, 223, 58, 230, 160, 156,
+ 68, 89, 108, 89, 115, 145, 3, 147, 48, 33,
+ 131, 50, 89, 0, 3, 4, 16, 95, 33, 220,
+ 224, 5, 26, 64, 193, 91, 111, 167, 57, 35,
+ 132, 35, 53, 148, 116, 12, 100, 166, 248, 13,
+ 143, 241, 163, 59, 34, 16, 192, 15, 120, 208,
+ 222, 36, 208, 192, 49, 63, 216, 192, 9, 36,
+ 192, 128, 137, 114, 152, 44, 47, 217, 140, 130,
+ 9, 114, 25, 28, 76, 148, 9, 162, 2, 128,
+ 141, 219, 50, 5, 122, 134, 120, 196, 174, 141,
+ 46, 143, 167, 96, 131, 23, 221, 120, 200, 72,
+ 214, 74, 16, 0, 0, 59 };
+
+static const unsigned char php_logo[] = {
+ 71, 73, 70, 56, 57, 97, 120, 0, 67, 0,
+ 230, 106, 0, 127, 130, 184, 57, 55, 71, 40,
+ 37, 42, 204, 205, 226, 161, 164, 203, 211, 213,
+ 231, 178, 180, 212, 67, 66, 88, 131, 134, 185,
+ 130, 131, 179, 82, 82, 114, 144, 146, 194, 194,
+ 196, 222, 170, 172, 208, 76, 75, 99, 91, 92,
+ 131, 221, 222, 236, 59, 56, 60, 110, 113, 165,
+ 106, 109, 157, 97, 99, 141, 117, 121, 177, 123,
+ 126, 181, 229, 230, 240, 153, 156, 198, 140, 141,
+ 193, 185, 186, 217, 107, 107, 146, 78, 78, 107,
+ 113, 116, 169, 122, 122, 163, 136, 139, 189, 114,
+ 116, 163, 116, 115, 152, 142, 144, 193, 90, 91,
+ 126, 226, 227, 239, 123, 125, 173, 164, 165, 208,
+ 109, 112, 162, 114, 118, 172, 149, 150, 200, 187,
+ 189, 217, 116, 120, 174, 133, 136, 187, 146, 149,
+ 195, 216, 217, 234, 146, 146, 196, 100, 102, 146,
+ 107, 110, 159, 165, 168, 206, 148, 150, 197, 46,
+ 43, 47, 83, 81, 104, 179, 180, 215, 108, 106,
+ 140, 92, 91, 118, 138, 141, 191, 102, 104, 150,
+ 104, 106, 154, 156, 159, 200, 49, 46, 57, 174,
+ 176, 211, 156, 156, 205, 85, 86, 120, 158, 161,
+ 202, 150, 153, 197, 129, 130, 175, 103, 105, 151,
+ 63, 61, 80, 188, 190, 218, 94, 96, 137, 152,
+ 153, 200, 140, 142, 191, 137, 138, 186, 87, 88,
+ 124, 182, 183, 215, 213, 215, 232, 34, 30, 32,
+ 108, 111, 158, 206, 208, 228, 191, 192, 220, 119,
+ 123, 180, 118, 120, 167, 95, 94, 125, 153, 153,
+ 204, 110, 111, 152, 115, 119, 174, 34, 30, 31,
+ 255, 255, 255, 144, 142, 143, 89, 86, 87, 199,
+ 198, 199, 238, 238, 245, 213, 212, 213, 246, 246,
+ 250, 130, 128, 129, 172, 170, 171, 116, 114, 115,
+ 241, 240, 241, 158, 156, 157, 227, 226, 227, 75,
+ 72, 73, 185, 184, 185, 103, 100, 101, 137, 137,
+ 182, 0, 255, 0, 71, 70, 95, 223, 224, 237,
+ 155, 156, 204, 105, 107, 156, 111, 115, 167, 140,
+ 140, 186, 184, 185, 217, 184, 186, 215, 154, 155,
+ 204, 167, 170, 207, 219, 220, 235, 154, 156, 201,
+ 102, 100, 132, 104, 103, 137, 167, 168, 210, 110,
+ 112, 160, 139, 139, 185, 198, 199, 224, 199, 201,
+ 225, 105, 108, 156, 151, 152, 203, 33, 249, 4,
+ 1, 0, 0, 106, 0, 44, 0, 0, 0, 0,
+ 120, 0, 67, 0, 0, 7, 255, 128, 106, 130,
+ 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
+ 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,
+ 151, 150, 109, 63, 109, 115, 152, 158, 159, 160,
+ 63, 121, 121, 54, 62, 26, 113, 76, 26, 26,
+ 76, 6, 62, 62, 13, 50, 4, 65, 60, 24,
+ 66, 45, 11, 73, 34, 57, 31, 25, 57, 34,
+ 47, 41, 160, 194, 161, 13, 26, 12, 125, 77,
+ 5, 80, 80, 3, 125, 124, 12, 81, 81, 42,
+ 114, 172, 175, 116, 177, 179, 66, 51, 45, 186,
+ 31, 8, 0, 22, 22, 21, 87, 40, 37, 22,
+ 9, 25, 193, 195, 235, 140, 38, 113, 124, 46,
+ 108, 108, 16, 16, 117, 46, 201, 3, 212, 50,
+ 179, 34, 31, 254, 44, 0, 17, 8, 4, 64,
+ 176, 224, 55, 130, 225, 164, 172, 64, 241, 70,
+ 194, 9, 63, 59, 158, 76, 25, 146, 132, 157,
+ 69, 53, 65, 108, 12, 96, 67, 226, 130, 71,
+ 18, 36, 242, 53, 16, 178, 64, 138, 201, 147,
+ 40, 83, 170, 92, 121, 114, 92, 7, 9, 19,
+ 118, 232, 128, 65, 225, 8, 5, 43, 67, 68,
+ 92, 196, 20, 132, 9, 20, 142, 30, 47, 184,
+ 48, 66, 167, 5, 203, 163, 72, 147, 162, 188,
+ 242, 38, 6, 140, 35, 71, 30, 140, 88, 114,
+ 196, 131, 206, 157, 144, 126, 104, 116, 1, 129,
+ 35, 4, 35, 4, 88, 40, 29, 75, 54, 233,
+ 149, 19, 58, 30, 44, 1, 162, 64, 193, 136,
+ 41, 51, 255, 176, 46, 50, 161, 161, 64, 19,
+ 23, 117, 10, 24, 72, 82, 182, 175, 95, 164,
+ 29, 96, 44, 81, 192, 129, 131, 3, 60, 9,
+ 228, 26, 202, 19, 101, 0, 148, 2, 3, 124,
+ 228, 248, 187, 114, 1, 134, 203, 152, 49, 124,
+ 160, 156, 244, 13, 5, 5, 14, 214, 172, 81,
+ 224, 65, 177, 154, 60, 70, 248, 244, 25, 192,
+ 100, 6, 231, 149, 31, 178, 112, 153, 77, 155,
+ 75, 151, 215, 74, 221, 44, 89, 115, 224, 128,
+ 131, 16, 59, 221, 69, 97, 192, 160, 1, 2,
+ 220, 43, 49, 112, 193, 194, 188, 185, 153, 219,
+ 200, 147, 118, 216, 93, 164, 200, 154, 210, 195,
+ 126, 248, 144, 99, 68, 5, 15, 11, 209, 87,
+ 170, 32, 211, 188, 185, 152, 2, 225, 149, 94,
+ 121, 112, 32, 64, 0, 14, 112, 64, 153, 48,
+ 192, 68, 14, 1, 0, 233, 87, 22, 16, 83,
+ 158, 57, 25, 21, 249, 41, 245, 134, 2, 238,
+ 245, 112, 7, 38, 115, 208, 225, 131, 1, 50,
+ 28, 23, 160, 74, 93, 152, 209, 31, 22, 92,
+ 16, 240, 160, 82, 49, 172, 209, 67, 15, 7,
+ 236, 81, 201, 15, 50, 52, 208, 64, 73, 23,
+ 166, 4, 64, 22, 19, 98, 145, 197, 102, 37,
+ 38, 245, 64, 0, 27, 2, 39, 73, 27, 4,
+ 236, 227, 96, 139, 39, 41, 55, 161, 25, 95,
+ 224, 168, 148, 31, 69, 208, 64, 3, 21, 145,
+ 216, 17, 4, 1, 51, 128, 135, 212, 255, 7,
+ 153, 53, 217, 36, 139, 71, 169, 16, 198, 132,
+ 98, 92, 208, 36, 137, 44, 49, 233, 228, 150,
+ 248, 141, 133, 130, 3, 52, 8, 80, 195, 35,
+ 72, 96, 16, 4, 148, 71, 125, 240, 69, 22,
+ 108, 182, 233, 230, 155, 89, 116, 81, 64, 3,
+ 93, 162, 84, 0, 24, 19, 146, 1, 103, 155,
+ 23, 12, 96, 225, 73, 11, 236, 41, 40, 155,
+ 93, 12, 208, 128, 82, 64, 8, 32, 128, 3,
+ 141, 204, 32, 4, 6, 98, 41, 69, 192, 114,
+ 41, 86, 106, 6, 24, 92, 124, 1, 32, 74,
+ 93, 108, 81, 105, 138, 52, 108, 161, 69, 25,
+ 93, 144, 104, 192, 148, 159, 78, 184, 5, 24,
+ 94, 116, 113, 40, 82, 35, 8, 224, 4, 163,
+ 138, 108, 35, 196, 141, 73, 141, 151, 234, 167,
+ 91, 120, 1, 65, 151, 39, 238, 250, 41, 24,
+ 99, 96, 32, 197, 0, 120, 10, 171, 106, 25,
+ 3, 36, 53, 130, 19, 78, 224, 144, 72, 10,
+ 34, 180, 128, 102, 82, 16, 240, 167, 108, 138,
+ 97, 64, 96, 18, 6, 94, 108, 155, 34, 26,
+ 183, 93, 224, 169, 184, 229, 209, 224, 69, 179,
+ 72, 173, 1, 45, 118, 133, 252, 225, 203, 100,
+ 101, 125, 33, 33, 186, 253, 121, 1, 160, 148,
+ 248, 230, 219, 0, 138, 253, 54, 71, 67, 25,
+ 127, 30, 21, 128, 19, 2, 44, 96, 72, 63,
+ 244, 146, 21, 91, 192, 229, 109, 209, 227, 157,
+ 16, 51, 167, 197, 255, 5, 225, 86, 140, 133,
+ 24, 208, 29, 213, 129, 172, 99, 18, 146, 2,
+ 2, 31, 212, 57, 214, 164, 59, 194, 57, 198,
+ 25, 218, 78, 232, 5, 1, 157, 78, 200, 197,
+ 155, 99, 112, 129, 70, 138, 90, 100, 129, 106,
+ 196, 112, 150, 113, 198, 185, 19, 150, 129, 37,
+ 75, 10, 64, 155, 6, 33, 222, 224, 58, 150,
+ 174, 253, 137, 225, 45, 74, 11, 52, 208, 5,
+ 121, 19, 106, 193, 0, 192, 253, 173, 136, 18,
+ 6, 13, 124, 17, 65, 213, 89, 104, 81, 53,
+ 187, 128, 26, 240, 69, 178, 253, 133, 97, 128,
+ 82, 52, 204, 58, 200, 31, 0, 32, 160, 100,
+ 89, 217, 230, 185, 169, 137, 89, 124, 221, 116,
+ 22, 25, 151, 199, 227, 74, 16, 0, 221, 92,
+ 206, 130, 51, 119, 198, 218, 42, 125, 48, 6,
+ 206, 119, 31, 181, 4, 180, 10, 171, 33, 130,
+ 5, 38, 147, 101, 175, 204, 5, 167, 20, 184,
+ 170, 58, 83, 249, 116, 74, 49, 247, 119, 70,
+ 22, 52, 4, 109, 236, 74, 161, 151, 167, 69,
+ 227, 44, 117, 0, 237, 13, 130, 176, 144, 80,
+ 95, 15, 79, 56, 198, 181, 39, 109, 222, 31,
+ 26, 89, 160, 221, 220, 127, 42, 5, 27, 116,
+ 25, 19, 210, 144, 197, 81, 169, 15, 206, 58,
+ 75, 69, 184, 173, 70, 56, 115, 147, 133, 114,
+ 127, 17, 244, 200, 210, 229, 253, 17, 142, 185,
+ 74, 224, 22, 159, 197, 25, 170, 94, 112, 20,
+ 255, 214, 229, 1, 175, 20, 7, 78, 244, 32,
+ 72, 5, 148, 49, 93, 30, 26, 159, 167, 84,
+ 123, 218, 228, 55, 119, 187, 74, 252, 246, 183,
+ 69, 216, 99, 179, 132, 1, 241, 219, 83, 10,
+ 5, 160, 37, 136, 21, 80, 166, 110, 217, 91,
+ 158, 73, 12, 0, 190, 160, 245, 173, 57, 213,
+ 211, 143, 239, 152, 3, 134, 44, 20, 14, 11,
+ 135, 99, 9, 3, 168, 214, 159, 251, 9, 144,
+ 128, 41, 184, 2, 251, 252, 130, 189, 242, 84,
+ 136, 37, 201, 99, 78, 4, 58, 183, 187, 248,
+ 157, 36, 133, 88, 8, 3, 233, 76, 183, 18,
+ 0, 120, 109, 66, 228, 34, 203, 0, 157, 32,
+ 8, 20, 24, 176, 47, 194, 235, 32, 238, 142,
+ 69, 169, 236, 245, 174, 106, 203, 11, 98, 121,
+ 188, 0, 192, 116, 29, 79, 63, 28, 44, 79,
+ 24, 20, 184, 146, 29, 10, 162, 3, 40, 24,
+ 33, 89, 116, 68, 189, 39, 162, 228, 3, 5,
+ 240, 66, 233, 250, 67, 131, 49, 124, 225, 130,
+ 39, 76, 73, 247, 38, 244, 189, 240, 113, 15,
+ 2, 98, 156, 80, 245, 42, 119, 20, 43, 170,
+ 97, 33, 90, 92, 90, 20, 153, 67, 46, 21,
+ 248, 81, 5, 16, 232, 194, 24, 180, 48, 70,
+ 209, 13, 160, 126, 204, 241, 32, 74, 242, 199,
+ 51, 177, 101, 175, 11, 127, 4, 100, 23, 202,
+ 224, 72, 153, 81, 113, 37, 232, 83, 223, 243,
+ 58, 112, 133, 190, 236, 71, 255, 85, 90, 8,
+ 101, 40, 197, 112, 175, 20, 137, 225, 11, 4,
+ 120, 160, 10, 189, 104, 167, 9, 98, 161, 130,
+ 23, 20, 149, 40, 181, 64, 202, 97, 137, 175,
+ 44, 205, 163, 213, 7, 222, 208, 129, 190, 68,
+ 72, 99, 104, 248, 194, 2, 78, 133, 67, 23,
+ 154, 196, 92, 19, 146, 97, 33, 3, 118, 202,
+ 161, 73, 231, 117, 130, 72, 129, 4, 222, 240,
+ 67, 165, 40, 177, 95, 205, 60, 150, 43, 173,
+ 182, 18, 68, 98, 129, 137, 26, 3, 131, 48,
+ 251, 242, 56, 39, 68, 238, 121, 18, 232, 229,
+ 88, 214, 216, 47, 26, 156, 97, 156, 82, 64,
+ 102, 127, 184, 240, 170, 173, 169, 146, 57, 109,
+ 12, 88, 4, 206, 112, 1, 103, 178, 205, 121,
+ 130, 120, 193, 9, 36, 208, 73, 165, 48, 82,
+ 92, 102, 32, 195, 24, 6, 80, 167, 25, 118,
+ 208, 159, 196, 212, 31, 255, 240, 101, 6, 25,
+ 50, 128, 142, 73, 41, 154, 19, 142, 70, 136,
+ 33, 156, 224, 13, 99, 161, 152, 254, 102, 57,
+ 75, 50, 112, 97, 12, 133, 66, 83, 160, 72,
+ 26, 74, 86, 158, 68, 5, 92, 96, 233, 232,
+ 46, 40, 6, 150, 134, 210, 164, 40, 101, 192,
+ 16, 165, 3, 50, 67, 164, 224, 4, 39, 80,
+ 39, 82, 96, 200, 133, 11, 208, 131, 30, 5,
+ 248, 35, 1, 252, 105, 18, 64, 30, 245, 168,
+ 153, 3, 212, 0, 158, 74, 143, 67, 46, 147,
+ 57, 94, 255, 48, 234, 81, 147, 234, 71, 2,
+ 236, 116, 44, 7, 75, 216, 33, 146, 16, 131,
+ 19, 160, 0, 41, 215, 76, 36, 83, 125, 36,
+ 133, 5, 52, 177, 60, 89, 192, 40, 114, 220,
+ 229, 4, 120, 25, 34, 1, 101, 45, 104, 114,
+ 238, 185, 66, 182, 178, 164, 1, 13, 140, 88,
+ 199, 242, 83, 78, 105, 41, 162, 4, 121, 101,
+ 201, 65, 249, 104, 76, 191, 74, 129, 1, 149,
+ 108, 14, 24, 208, 19, 160, 114, 210, 106, 17,
+ 136, 53, 171, 4, 171, 198, 0, 199, 170, 68,
+ 119, 82, 188, 36, 101, 52, 122, 89, 70, 148,
+ 96, 2, 49, 232, 64, 30, 165, 64, 212, 122,
+ 122, 214, 36, 121, 115, 217, 233, 162, 211, 129,
+ 3, 64, 171, 180, 141, 72, 0, 106, 37, 160,
+ 197, 180, 98, 97, 12, 107, 245, 209, 2, 22,
+ 199, 70, 185, 250, 133, 8, 61, 128, 150, 97,
+ 35, 161, 132, 39, 76, 64, 179, 82, 248, 223,
+ 22, 166, 75, 93, 222, 189, 214, 158, 212, 165,
+ 46, 24, 6, 251, 26, 5, 200, 74, 0, 50,
+ 154, 196, 11, 64, 224, 135, 24, 240, 22, 0,
+ 5, 160, 42, 61, 16, 119, 93, 41, 160, 87,
+ 189, 16, 112, 45, 101, 136, 112, 48, 39, 68,
+ 128, 163, 150, 72, 128, 27, 80, 251, 134, 213,
+ 182, 215, 175, 39, 176, 173, 114, 65, 241, 130,
+ 41, 248, 1, 181, 170, 253, 175, 95, 81, 192,
+ 1, 89, 57, 161, 8, 248, 5, 133, 255, 18,
+ 244, 224, 134, 3, 247, 87, 193, 37, 58, 193,
+ 26, 28, 220, 131, 240, 178, 131, 5, 20, 62,
+ 176, 4, 206, 138, 225, 240, 28, 225, 0, 138,
+ 18, 64, 15, 96, 167, 24, 22, 128, 96, 7,
+ 110, 112, 67, 12, 168, 89, 98, 202, 248, 129,
+ 3, 1, 8, 147, 0, 2, 192, 98, 211, 8,
+ 34, 9, 37, 32, 194, 14, 96, 60, 1, 26,
+ 215, 56, 41, 19, 32, 80, 15, 132, 36, 38,
+ 187, 250, 120, 16, 41, 72, 128, 30, 116, 64,
+ 4, 33, 187, 33, 168, 254, 197, 240, 27, 142,
+ 128, 227, 13, 45, 185, 8, 120, 120, 193, 147,
+ 23, 241, 2, 41, 235, 224, 204, 103, 222, 193,
+ 71, 73, 124, 221, 29, 28, 65, 1, 237, 129,
+ 209, 134, 14, 112, 3, 15, 141, 249, 17, 47,
+ 64, 192, 20, 136, 0, 131, 62, 251, 153, 8,
+ 126, 248, 168, 80, 243, 51, 1, 34, 60, 0,
+ 52, 213, 113, 143, 162, 113, 16, 2, 59, 223,
+ 153, 18, 34, 24, 194, 158, 41, 64, 233, 74,
+ 83, 250, 8, 125, 174, 112, 160, 223, 192, 105,
+ 78, 75, 224, 211, 159, 6, 42, 80, 137, 112,
+ 105, 182, 136, 166, 55, 7, 168, 78, 17, 2,
+ 112, 0, 28, 108, 32, 49, 143, 22, 70, 10,
+ 62, 80, 2, 16, 88, 1, 42, 80, 121, 128,
+ 174, 119, 61, 149, 37, 172, 5, 8, 108, 105,
+ 11, 97, 10, 99, 152, 208, 156, 186, 55, 69,
+ 80, 0, 21, 110, 56, 48, 4, 49, 199, 90,
+ 49, 41, 80, 2, 2, 60, 224, 129, 13, 108,
+ 32, 45, 190, 6, 118, 176, 219, 66, 108, 195,
+ 112, 128, 10, 35, 24, 129, 21, 172, 80, 130,
+ 102, 63, 251, 220, 139, 16, 65, 26, 16, 112,
+ 21, 116, 187, 251, 221, 240, 142, 119, 188, 3,
+ 1, 0, 59, 0 };
+
+static const unsigned char php_egg_logo[] = {
+ 71, 73, 70, 56, 57, 97, 120, 0, 67, 0,
+ 231, 255, 0, 18, 25, 33, 32, 30, 34, 28,
+ 33, 44, 15, 35, 71, 6, 37, 85, 37, 40,
+ 47, 34, 41, 53, 41, 40, 43, 9, 47, 109,
+ 30, 45, 68, 21, 48, 84, 51, 46, 55, 43,
+ 49, 59, 31, 59, 98, 15, 61, 128, 58, 55,
+ 69, 50, 57, 74, 0, 66, 144, 56, 58, 60,
+ 54, 59, 71, 32, 66, 113, 60, 65, 67, 63,
+ 65, 84, 63, 68, 79, 28, 79, 145, 15, 82,
+ 162, 75, 72, 98, 68, 78, 86, 74, 77, 88,
+ 50, 82, 122, 41, 85, 134, 76, 78, 108, 70,
+ 83, 101, 5, 94, 190, 0, 95, 197, 86, 80,
+ 101, 28, 92, 159, 80, 84, 96, 83, 83, 115,
+ 81, 87, 89, 22, 97, 183, 86, 88, 85, 0,
+ 102, 210, 8, 101, 204, 24, 100, 177, 85, 90,
+ 127, 35, 101, 169, 42, 100, 159, 88, 92, 103,
+ 0, 107, 216, 69, 95, 132, 0, 108, 210, 84,
+ 93, 112, 94, 90, 117, 18, 105, 201, 96, 92,
+ 105, 89, 96, 98, 94, 93, 135, 94, 94, 126,
+ 30, 106, 210, 7, 112, 222, 33, 108, 198, 16,
+ 114, 217, 27, 113, 198, 24, 113, 209, 59, 108,
+ 159, 96, 100, 138, 0, 120, 229, 44, 112, 180,
+ 49, 112, 171, 71, 108, 148, 99, 104, 115, 90,
+ 106, 125, 27, 115, 232, 100, 102, 147, 42, 115,
+ 192, 86, 110, 137, 9, 123, 239, 106, 108, 105,
+ 105, 105, 138, 33, 118, 228, 12, 125, 227, 48,
+ 117, 208, 16, 126, 222, 37, 120, 224, 20, 125,
+ 235, 35, 123, 213, 50, 121, 190, 43, 123, 206,
+ 40, 123, 220, 105, 110, 160, 59, 122, 182, 78,
+ 119, 158, 44, 122, 233, 3, 134, 250, 112, 112,
+ 151, 73, 123, 175, 113, 118, 114, 51, 128, 205,
+ 34, 129, 246, 11, 136, 245, 34, 130, 240, 113,
+ 117, 149, 111, 116, 166, 111, 119, 141, 48, 130,
+ 221, 38, 132, 235, 53, 130, 215, 97, 124, 146,
+ 116, 122, 124, 117, 121, 131, 54, 130, 229, 41,
+ 135, 232, 68, 130, 223, 46, 135, 246, 65, 134,
+ 202, 42, 137, 241, 75, 131, 205, 124, 121, 161,
+ 101, 125, 191, 86, 128, 210, 121, 122, 169, 105,
+ 128, 157, 121, 122, 180, 114, 124, 181, 94, 128,
+ 201, 81, 134, 185, 46, 138, 252, 76, 135, 195,
+ 34, 142, 252, 62, 137, 229, 63, 138, 217, 33,
+ 144, 247, 58, 139, 223, 56, 141, 246, 54, 143,
+ 234, 57, 143, 241, 102, 135, 193, 129, 130, 176,
+ 122, 136, 144, 46, 148, 252, 45, 149, 246, 118,
+ 133, 191, 65, 146, 231, 73, 146, 216, 129, 133,
+ 185, 135, 135, 156, 69, 148, 226, 44, 153, 255,
+ 94, 143, 216, 132, 136, 175, 88, 146, 207, 137,
+ 139, 136, 93, 146, 197, 95, 147, 188, 137, 139,
+ 150, 104, 146, 178, 122, 143, 172, 135, 139, 191,
+ 57, 156, 254, 67, 154, 245, 70, 154, 239, 134,
+ 141, 180, 117, 145, 201, 120, 146, 190, 79, 154,
+ 233, 140, 141, 188, 129, 144, 194, 142, 142, 176,
+ 137, 147, 156, 88, 155, 222, 82, 157, 230, 93,
+ 157, 218, 66, 162, 253, 100, 157, 210, 77, 161,
+ 247, 55, 168, 255, 81, 162, 241, 148, 148, 195,
+ 145, 149, 202, 127, 156, 204, 77, 166, 255, 142,
+ 155, 177, 141, 153, 200, 123, 160, 193, 73, 171,
+ 255, 93, 167, 240, 96, 167, 234, 152, 158, 160,
+ 101, 167, 228, 119, 164, 206, 155, 158, 171, 110,
+ 167, 219, 156, 155, 203, 89, 172, 252, 128, 164,
+ 219, 151, 163, 174, 81, 178, 255, 158, 162, 202,
+ 102, 175, 249, 93, 178, 251, 108, 175, 237, 103,
+ 177, 244, 166, 168, 165, 97, 182, 255, 87, 185,
+ 255, 149, 174, 216, 125, 181, 235, 110, 185, 252,
+ 117, 183, 254, 171, 172, 209, 166, 175, 197, 103,
+ 190, 255, 174, 176, 189, 140, 183, 221, 128, 184,
+ 248, 120, 187, 249, 179, 180, 184, 115, 193, 253,
+ 170, 183, 193, 174, 181, 215, 107, 197, 255, 135,
+ 191, 246, 151, 192, 219, 187, 183, 213, 128, 197,
+ 253, 121, 202, 255, 147, 198, 239, 188, 191, 219,
+ 148, 200, 252, 192, 193, 197, 134, 205, 254, 171,
+ 199, 236, 183, 199, 218, 163, 207, 251, 142, 213,
+ 255, 158, 211, 253, 195, 205, 217, 166, 211, 245,
+ 205, 204, 228, 153, 218, 255, 190, 210, 236, 186,
+ 212, 231, 177, 213, 248, 162, 224, 255, 188, 221,
+ 250, 214, 219, 221, 214, 219, 233, 174, 229, 254,
+ 198, 225, 247, 209, 226, 248, 186, 233, 251, 227,
+ 230, 239, 225, 241, 252, 253, 255, 252, 255, 255,
+ 255, 33, 249, 4, 1, 10, 0, 255, 0, 44,
+ 0, 0, 0, 0, 120, 0, 67, 0, 0, 8,
+ 254, 0, 255, 9, 28, 72, 176, 160, 193, 131,
+ 8, 19, 42, 92, 200, 176, 161, 195, 135, 16,
+ 35, 74, 156, 72, 177, 162, 197, 139, 22, 131,
+ 105, 12, 134, 177, 163, 199, 143, 193, 164, 73,
+ 227, 38, 141, 28, 56, 112, 228, 76, 146, 20,
+ 41, 205, 152, 75, 99, 183, 100, 201, 50, 101,
+ 202, 147, 77, 79, 166, 102, 205, 250, 200, 19,
+ 100, 73, 114, 239, 238, 221, 123, 71, 148, 104,
+ 202, 163, 224, 86, 138, 124, 25, 115, 166, 205,
+ 72, 145, 246, 72, 221, 195, 39, 207, 30, 69,
+ 158, 118, 246, 220, 202, 208, 24, 184, 160, 252,
+ 248, 9, 29, 59, 212, 100, 75, 99, 53, 159,
+ 66, 93, 203, 182, 109, 84, 169, 124, 248, 156,
+ 57, 163, 165, 174, 150, 60, 138, 76, 113, 221,
+ 251, 207, 24, 183, 119, 97, 3, 135, 125, 71,
+ 78, 90, 76, 62, 142, 70, 141, 18, 53, 109,
+ 170, 227, 199, 144, 35, 75, 157, 91, 87, 137,
+ 229, 28, 74, 190, 228, 229, 139, 209, 43, 96,
+ 193, 247, 10, 203, 114, 212, 167, 82, 47, 93,
+ 197, 138, 81, 163, 166, 173, 19, 47, 201, 176,
+ 99, 59, 166, 171, 36, 135, 237, 22, 45, 114,
+ 216, 209, 203, 25, 98, 176, 191, 66, 195, 134,
+ 54, 230, 233, 150, 179, 100, 197, 106, 181, 90,
+ 158, 171, 57, 179, 110, 231, 124, 185, 145, 77,
+ 157, 186, 150, 218, 45, 76, 104, 111, 145, 71,
+ 86, 239, 133, 198, 200, 254, 145, 189, 199, 205,
+ 212, 212, 115, 244, 232, 157, 107, 86, 172, 185,
+ 234, 92, 197, 154, 137, 11, 231, 11, 77, 245,
+ 251, 178, 207, 40, 201, 254, 225, 131, 134, 39,
+ 138, 124, 103, 80, 73, 68, 13, 37, 141, 39,
+ 144, 213, 115, 14, 60, 235, 116, 211, 12, 123,
+ 197, 136, 67, 141, 106, 226, 156, 51, 78, 16,
+ 92, 208, 194, 7, 126, 28, 70, 166, 159, 9,
+ 26, 132, 104, 130, 29, 2, 254, 67, 32, 81,
+ 224, 200, 18, 91, 56, 240, 208, 35, 78, 51,
+ 238, 49, 40, 223, 58, 240, 88, 99, 132, 31,
+ 207, 168, 131, 14, 55, 206, 56, 115, 203, 41,
+ 167, 172, 229, 73, 36, 158, 196, 133, 216, 83,
+ 29, 58, 166, 69, 11, 26, 88, 96, 129, 6,
+ 95, 112, 230, 213, 81, 210, 188, 21, 27, 59,
+ 208, 208, 179, 14, 123, 205, 81, 227, 96, 55,
+ 235, 208, 227, 14, 23, 126, 244, 162, 204, 49,
+ 200, 64, 3, 13, 51, 194, 232, 162, 139, 50,
+ 105, 106, 131, 13, 54, 225, 132, 227, 205, 157,
+ 207, 96, 243, 204, 48, 195, 244, 72, 28, 126,
+ 103, 48, 233, 164, 6, 36, 246, 20, 210, 81,
+ 198, 224, 87, 143, 48, 12, 78, 8, 75, 43,
+ 242, 21, 3, 38, 60, 227, 116, 224, 2, 22,
+ 135, 32, 162, 41, 33, 112, 208, 129, 72, 35,
+ 135, 8, 242, 72, 40, 163, 150, 82, 202, 42,
+ 186, 172, 178, 203, 46, 169, 170, 154, 76, 50,
+ 254, 123, 158, 194, 97, 14, 22, 60, 240, 192,
+ 7, 188, 117, 228, 23, 74, 198, 88, 41, 219,
+ 56, 189, 36, 19, 203, 57, 235, 80, 147, 11,
+ 44, 176, 20, 211, 96, 51, 240, 192, 195, 14,
+ 5, 36, 88, 129, 8, 33, 116, 200, 81, 198,
+ 181, 101, 208, 1, 199, 27, 220, 110, 59, 69,
+ 22, 130, 20, 82, 200, 35, 165, 76, 34, 110,
+ 33, 147, 64, 162, 174, 42, 192, 200, 122, 223,
+ 25, 38, 216, 186, 192, 19, 24, 133, 52, 82,
+ 149, 247, 161, 179, 203, 35, 136, 8, 243, 72,
+ 57, 244, 80, 179, 220, 39, 185, 192, 163, 77,
+ 55, 244, 236, 227, 14, 5, 17, 0, 65, 7,
+ 25, 101, 120, 81, 197, 196, 216, 82, 97, 49,
+ 21, 81, 68, 145, 69, 22, 105, 116, 236, 113,
+ 26, 161, 148, 59, 136, 24, 98, 64, 210, 203,
+ 40, 28, 106, 161, 193, 2, 11, 88, 144, 171,
+ 68, 246, 74, 163, 226, 125, 207, 156, 105, 8,
+ 25, 212, 54, 218, 202, 39, 4, 227, 115, 142,
+ 54, 233, 177, 211, 65, 4, 51, 84, 113, 109,
+ 21, 77, 52, 1, 69, 23, 19, 15, 1, 197,
+ 16, 84, 12, 17, 197, 182, 112, 8, 146, 198,
+ 20, 86, 147, 139, 204, 49, 169, 78, 50, 200,
+ 32, 144, 56, 210, 97, 14, 15, 176, 28, 37,
+ 204, 198, 180, 228, 107, 108, 158, 60, 19, 202,
+ 43, 159, 200, 225, 133, 28, 175, 224, 3, 15,
+ 50, 176, 80, 2, 75, 254, 51, 94, 34, 140,
+ 143, 208, 68, 119, 129, 45, 210, 93, 48, 13,
+ 197, 210, 60, 240, 0, 133, 15, 111, 104, 138,
+ 8, 28, 27, 79, 1, 199, 35, 163, 234, 18,
+ 139, 155, 233, 206, 177, 97, 202, 22, 28, 112,
+ 128, 14, 17, 5, 227, 210, 204, 213, 69, 178,
+ 11, 40, 160, 16, 194, 8, 33, 134, 52, 17,
+ 142, 122, 197, 236, 156, 11, 51, 185, 52, 3,
+ 244, 62, 128, 207, 16, 49, 182, 93, 36, 125,
+ 120, 23, 135, 67, 193, 131, 15, 112, 148, 147,
+ 143, 58, 216, 8, 3, 249, 198, 89, 192, 1,
+ 199, 33, 143, 196, 18, 203, 42, 144, 104, 222,
+ 33, 31, 26, 120, 62, 194, 67, 162, 255, 121,
+ 159, 35, 149, 104, 58, 135, 21, 100, 64, 92,
+ 69, 139, 198, 238, 156, 236, 222, 226, 208, 131,
+ 207, 56, 13, 56, 80, 116, 19, 215, 54, 81,
+ 197, 24, 73, 23, 126, 248, 16, 62, 248, 144,
+ 133, 62, 110, 112, 194, 50, 202, 113, 8, 231,
+ 101, 193, 7, 64, 152, 220, 184, 30, 129, 42,
+ 93, 168, 66, 108, 29, 50, 129, 231, 52, 208,
+ 16, 89, 220, 162, 87, 248, 137, 68, 29, 178,
+ 160, 6, 53, 188, 225, 5, 85, 176, 86, 21,
+ 232, 1, 15, 113, 228, 98, 57, 173, 104, 143,
+ 151, 224, 241, 190, 248, 249, 160, 126, 114, 136,
+ 161, 181, 202, 16, 53, 167, 13, 97, 120, 105,
+ 184, 7, 7, 12, 224, 4, 111, 192, 65, 114,
+ 254, 144, 3, 66, 26, 14, 145, 6, 43, 88,
+ 1, 11, 107, 128, 196, 42, 86, 1, 65, 14,
+ 181, 224, 0, 1, 160, 160, 66, 100, 114, 139,
+ 181, 197, 230, 22, 117, 152, 194, 20, 162, 160,
+ 134, 42, 144, 64, 10, 248, 163, 67, 122, 214,
+ 17, 187, 79, 232, 45, 23, 226, 16, 7, 62,
+ 240, 97, 13, 5, 16, 109, 12, 215, 98, 4,
+ 207, 64, 193, 51, 77, 53, 66, 83, 84, 240,
+ 65, 26, 218, 113, 1, 3, 180, 1, 27, 144,
+ 19, 196, 183, 128, 128, 196, 66, 132, 98, 13,
+ 63, 72, 228, 15, 176, 32, 134, 68, 52, 241,
+ 62, 45, 8, 64, 0, 106, 144, 144, 89, 152,
+ 66, 22, 8, 186, 207, 40, 214, 32, 8, 107,
+ 216, 194, 5, 67, 144, 218, 15, 134, 208, 5,
+ 68, 184, 15, 30, 205, 120, 148, 25, 97, 1,
+ 157, 125, 208, 227, 25, 3, 136, 64, 12, 232,
+ 215, 136, 121, 200, 35, 31, 249, 168, 71, 61,
+ 242, 33, 143, 118, 108, 67, 30, 208, 128, 195,
+ 32, 218, 49, 1, 1, 180, 1, 121, 199, 120,
+ 197, 35, 136, 184, 134, 102, 146, 11, 137, 88,
+ 80, 228, 37, 104, 145, 36, 13, 72, 178, 80,
+ 5, 153, 5, 78, 50, 73, 157, 72, 92, 98,
+ 13, 135, 208, 135, 63, 252, 129, 132, 40, 116,
+ 193, 105, 192, 11, 5, 62, 92, 217, 140, 157,
+ 49, 162, 21, 104, 60, 199, 62, 224, 225, 10,
+ 2, 68, 128, 10, 114, 254, 32, 196, 49, 178,
+ 113, 129, 11, 112, 224, 159, 37, 224, 192, 6,
+ 46, 176, 129, 108, 148, 99, 21, 213, 40, 230,
+ 1, 78, 128, 3, 55, 240, 34, 29, 216, 8,
+ 197, 36, 122, 81, 10, 114, 61, 2, 93, 107,
+ 136, 230, 28, 230, 96, 13, 43, 202, 230, 1,
+ 1, 56, 128, 119, 10, 146, 150, 251, 240, 65,
+ 21, 88, 200, 194, 60, 198, 233, 143, 84, 164,
+ 193, 104, 72, 43, 195, 49, 214, 8, 143, 216,
+ 49, 226, 157, 197, 208, 70, 251, 216, 193, 5,
+ 2, 100, 160, 10, 129, 64, 4, 54, 54, 81,
+ 2, 24, 148, 128, 6, 48, 160, 193, 81, 3,
+ 202, 0, 115, 120, 99, 19, 19, 40, 128, 1,
+ 74, 208, 79, 6, 20, 32, 12, 222, 8, 133,
+ 45, 136, 241, 141, 103, 232, 194, 84, 143, 72,
+ 195, 15, 196, 112, 9, 87, 248, 226, 22, 28,
+ 58, 3, 20, 183, 71, 144, 89, 16, 201, 163,
+ 145, 185, 68, 74, 7, 145, 130, 106, 140, 83,
+ 15, 136, 40, 131, 181, 154, 48, 6, 111, 140,
+ 145, 61, 173, 72, 214, 131, 210, 83, 41, 2,
+ 160, 128, 12, 140, 104, 68, 57, 220, 80, 212,
+ 106, 224, 50, 151, 250, 248, 69, 9, 24, 208,
+ 6, 126, 28, 225, 2, 1, 32, 70, 53, 126,
+ 193, 88, 1, 0, 96, 17, 165, 96, 2, 65,
+ 113, 16, 6, 76, 96, 98, 27, 202, 16, 43,
+ 89, 51, 193, 10, 82, 108, 174, 58, 38, 144,
+ 254, 228, 203, 134, 4, 87, 200, 220, 1, 11,
+ 64, 160, 66, 16, 12, 80, 128, 118, 216, 195,
+ 5, 141, 40, 31, 182, 216, 145, 30, 23, 181,
+ 135, 149, 212, 8, 19, 60, 188, 145, 0, 4,
+ 100, 225, 19, 59, 155, 7, 13, 78, 80, 130,
+ 109, 60, 67, 24, 141, 128, 67, 33, 204, 81,
+ 130, 2, 84, 224, 30, 37, 152, 128, 4, 242,
+ 113, 167, 121, 216, 162, 152, 39, 120, 6, 8,
+ 4, 192, 128, 13, 112, 160, 159, 6, 192, 68,
+ 41, 122, 240, 131, 65, 0, 2, 16, 115, 48,
+ 171, 51, 238, 3, 69, 41, 254, 195, 173, 181,
+ 125, 12, 31, 122, 0, 132, 25, 248, 192, 3,
+ 211, 56, 0, 13, 54, 145, 5, 50, 236, 149,
+ 126, 236, 104, 17, 60, 186, 113, 44, 73, 73,
+ 120, 29, 174, 136, 37, 28, 102, 215, 10, 121,
+ 208, 192, 13, 71, 72, 135, 50, 38, 22, 133,
+ 66, 164, 163, 187, 12, 216, 6, 7, 24, 112,
+ 132, 114, 192, 33, 13, 144, 248, 69, 1, 0,
+ 112, 2, 98, 126, 54, 30, 211, 32, 6, 26,
+ 120, 11, 12, 32, 244, 64, 12, 115, 240, 195,
+ 18, 174, 0, 8, 87, 144, 226, 20, 164, 147,
+ 76, 36, 3, 48, 82, 243, 4, 120, 42, 3,
+ 182, 193, 10, 86, 48, 3, 18, 20, 32, 0,
+ 2, 32, 129, 26, 200, 80, 133, 194, 53, 129,
+ 12, 236, 160, 17, 60, 210, 7, 11, 113, 172,
+ 227, 204, 225, 144, 129, 254, 97, 65, 33, 12,
+ 129, 165, 131, 3, 55, 112, 131, 45, 142, 81,
+ 5, 42, 188, 225, 17, 237, 88, 241, 2, 36,
+ 107, 128, 69, 196, 66, 13, 130, 120, 6, 26,
+ 60, 187, 136, 106, 120, 22, 23, 186, 224, 90,
+ 60, 12, 0, 0, 78, 76, 161, 7, 88, 152,
+ 67, 16, 92, 176, 4, 34, 92, 97, 11, 91,
+ 200, 132, 53, 204, 35, 153, 51, 72, 146, 94,
+ 255, 120, 242, 84, 60, 177, 4, 41, 171, 64,
+ 5, 59, 0, 2, 5, 18, 128, 1, 56, 220,
+ 236, 90, 189, 83, 3, 59, 206, 97, 230, 102,
+ 64, 55, 23, 201, 61, 179, 55, 26, 128, 128,
+ 52, 188, 162, 24, 204, 128, 196, 52, 56, 0,
+ 131, 77, 88, 67, 24, 132, 64, 196, 33, 212,
+ 241, 139, 11, 20, 224, 8, 104, 184, 128, 0,
+ 170, 129, 8, 53, 100, 193, 25, 16, 0, 0,
+ 0, 182, 49, 104, 6, 36, 67, 153, 143, 184,
+ 68, 2, 0, 192, 133, 52, 160, 0, 11, 87,
+ 120, 129, 11, 88, 192, 110, 18, 144, 128, 8,
+ 153, 118, 70, 162, 34, 99, 129, 40, 10, 196,
+ 164, 128, 232, 193, 10, 98, 16, 131, 29, 248,
+ 27, 8, 133, 224, 32, 33, 132, 123, 173, 70,
+ 172, 35, 141, 235, 64, 6, 116, 97, 65, 172,
+ 51, 103, 98, 0, 25, 120, 133, 48, 218, 163,
+ 138, 84, 252, 51, 27, 232, 160, 6, 51, 160,
+ 193, 142, 108, 28, 97, 2, 12, 176, 7, 18,
+ 254, 250, 136, 142, 14, 102, 161, 19, 140, 102,
+ 64, 59, 178, 189, 1, 109, 188, 34, 20, 133,
+ 240, 131, 103, 57, 113, 136, 31, 44, 97, 14,
+ 91, 32, 1, 187, 89, 224, 110, 23, 144, 160,
+ 8, 96, 240, 3, 46, 146, 44, 149, 15, 4,
+ 96, 1, 247, 174, 206, 41, 176, 96, 131, 29,
+ 240, 32, 6, 42, 224, 247, 14, 124, 16, 5,
+ 58, 88, 221, 193, 85, 240, 2, 51, 194, 113,
+ 142, 110, 72, 40, 23, 202, 233, 70, 179, 202,
+ 209, 1, 2, 212, 129, 25, 108, 202, 133, 55,
+ 208, 192, 129, 18, 152, 227, 30, 230, 216, 6,
+ 49, 156, 64, 108, 8, 164, 226, 30, 48, 152,
+ 192, 6, 158, 65, 7, 53, 88, 1, 9, 158,
+ 61, 194, 52, 102, 76, 12, 109, 8, 35, 22,
+ 144, 232, 196, 161, 225, 32, 134, 43, 92, 161,
+ 8, 47, 120, 1, 17, 212, 237, 110, 12, 252,
+ 28, 211, 156, 128, 140, 18, 36, 41, 144, 215,
+ 194, 198, 19, 115, 0, 194, 10, 84, 192, 131,
+ 33, 240, 187, 223, 62, 160, 66, 178, 7, 14,
+ 49, 50, 208, 233, 96, 231, 152, 16, 123, 230,
+ 83, 142, 12, 59, 32, 22, 26, 103, 70, 43,
+ 230, 1, 130, 182, 95, 128, 6, 19, 184, 64,
+ 240, 139, 234, 134, 120, 84, 99, 197, 109, 240,
+ 134, 26, 232, 80, 7, 11, 104, 123, 27, 72,
+ 0, 192, 6, 228, 49, 14, 61, 165, 131, 6,
+ 0, 144, 0, 43, 4, 254, 49, 136, 43, 16,
+ 33, 8, 30, 136, 60, 188, 225, 237, 238, 23,
+ 20, 97, 11, 153, 127, 204, 230, 3, 240, 223,
+ 234, 140, 2, 11, 83, 142, 58, 15, 202, 80,
+ 133, 167, 199, 96, 8, 141, 128, 155, 33, 62,
+ 65, 6, 67, 112, 29, 26, 21, 114, 14, 204,
+ 144, 83, 212, 112, 14, 222, 80, 118, 98, 128,
+ 12, 180, 35, 12, 185, 32, 15, 16, 0, 103,
+ 71, 0, 98, 71, 0, 3, 48, 224, 6, 219,
+ 48, 15, 143, 32, 9, 28, 48, 1, 188, 80,
+ 14, 84, 160, 6, 137, 192, 104, 23, 144, 14,
+ 217, 38, 1, 188, 112, 130, 188, 0, 3, 152,
+ 149, 10, 230, 50, 8, 150, 22, 4, 50, 0,
+ 6, 91, 64, 4, 46, 224, 2, 145, 7, 126,
+ 65, 16, 4, 91, 128, 11, 234, 199, 121, 255,
+ 16, 23, 178, 81, 7, 82, 32, 2, 168, 22,
+ 3, 62, 48, 4, 100, 160, 6, 79, 23, 5,
+ 135, 240, 10, 173, 48, 45, 251, 7, 13, 231,
+ 160, 38, 102, 118, 14, 117, 82, 39, 126, 0,
+ 113, 186, 128, 12, 12, 88, 11, 185, 176, 13,
+ 19, 112, 3, 37, 192, 15, 185, 84, 15, 243,
+ 16, 15, 234, 112, 12, 136, 80, 10, 237, 64,
+ 12, 196, 112, 15, 215, 64, 5, 112, 128, 11,
+ 22, 208, 103, 182, 32, 1, 0, 192, 0, 239,
+ 5, 80, 23, 208, 6, 207, 80, 8, 96, 3,
+ 111, 70, 128, 6, 118, 192, 4, 96, 0, 121,
+ 254, 36, 240, 2, 96, 176, 33, 150, 192, 5,
+ 92, 224, 43, 235, 39, 16, 103, 224, 121, 144,
+ 49, 10, 63, 48, 3, 163, 23, 3, 195, 243,
+ 129, 101, 160, 6, 169, 247, 10, 200, 0, 10,
+ 204, 209, 10, 194, 16, 14, 201, 195, 34, 7,
+ 151, 12, 225, 0, 12, 10, 224, 0, 147, 160,
+ 13, 180, 227, 133, 208, 240, 11, 196, 230, 6,
+ 253, 112, 12, 159, 208, 119, 86, 103, 8, 214,
+ 246, 10, 209, 80, 14, 209, 0, 10, 67, 0,
+ 7, 227, 16, 15, 247, 192, 15, 72, 192, 91,
+ 246, 176, 13, 169, 176, 8, 110, 144, 10, 214,
+ 5, 61, 35, 227, 2, 91, 32, 3, 86, 33,
+ 21, 92, 0, 6, 47, 224, 1, 50, 32, 10,
+ 176, 17, 137, 63, 72, 137, 142, 113, 10, 98,
+ 208, 116, 81, 199, 111, 60, 64, 5, 143, 83,
+ 6, 67, 160, 6, 177, 16, 14, 208, 160, 13,
+ 106, 194, 12, 200, 160, 12, 218, 112, 12, 82,
+ 152, 12, 187, 160, 10, 151, 64, 1, 8, 240,
+ 3, 10, 184, 51, 148, 208, 10, 139, 85, 2,
+ 37, 176, 9, 253, 32, 12, 134, 80, 6, 251,
+ 83, 62, 84, 144, 45, 141, 64, 8, 84, 192,
+ 3, 158, 8, 4, 86, 64, 10, 28, 32, 0,
+ 56, 224, 13, 194, 176, 11, 222, 80, 14, 202,
+ 16, 10, 135, 32, 46, 141, 7, 111, 45, 224,
+ 24, 145, 144, 9, 91, 0, 6, 70, 0, 6,
+ 112, 101, 116, 72, 247, 254, 15, 123, 112, 6,
+ 176, 65, 11, 63, 176, 111, 59, 208, 111, 154,
+ 216, 142, 135, 0, 10, 136, 16, 10, 194, 160,
+ 13, 201, 160, 13, 117, 34, 14, 208, 128, 12,
+ 186, 208, 11, 187, 112, 9, 128, 224, 1, 20,
+ 64, 0, 8, 96, 3, 203, 1, 11, 159, 112,
+ 83, 175, 80, 15, 52, 208, 118, 196, 144, 15,
+ 185, 32, 66, 67, 80, 5, 100, 64, 7, 81,
+ 83, 56, 85, 48, 3, 20, 233, 3, 54, 208,
+ 3, 157, 192, 0, 0, 64, 12, 208, 0, 10,
+ 63, 4, 7, 202, 54, 146, 133, 48, 7, 151,
+ 64, 4, 96, 112, 146, 144, 225, 7, 96, 192,
+ 5, 226, 40, 21, 245, 38, 69, 158, 48, 23,
+ 145, 97, 10, 115, 96, 3, 34, 48, 122, 231,
+ 88, 122, 112, 160, 6, 165, 16, 11, 161, 112,
+ 12, 202, 112, 9, 151, 16, 14, 226, 32, 143,
+ 244, 40, 6, 24, 224, 0, 8, 128, 0, 17,
+ 128, 2, 135, 128, 66, 173, 64, 9, 140, 64,
+ 9, 185, 208, 15, 196, 144, 10, 191, 192, 15,
+ 236, 0, 10, 114, 96, 56, 93, 32, 7, 73,
+ 120, 67, 80, 64, 5, 59, 128, 132, 84, 0,
+ 4, 107, 48, 104, 5, 240, 13, 194, 0, 10,
+ 111, 0, 4, 64, 32, 57, 105, 128, 46, 171,
+ 48, 7, 223, 39, 4, 145, 1, 132, 157, 246,
+ 105, 2, 49, 11, 115, 33, 142, 167, 240, 3,
+ 54, 224, 3, 153, 152, 56, 80, 243, 6, 112,
+ 254, 0, 138, 177, 32, 12, 208, 160, 10, 106,
+ 130, 13, 0, 24, 14, 197, 128, 148, 107, 208,
+ 3, 86, 32, 138, 202, 193, 51, 85, 121, 83,
+ 173, 112, 14, 229, 192, 14, 234, 80, 14, 173,
+ 160, 87, 101, 0, 60, 33, 148, 132, 112, 32,
+ 60, 60, 48, 3, 184, 233, 3, 170, 224, 75,
+ 237, 128, 13, 79, 72, 5, 84, 246, 45, 83,
+ 0, 136, 221, 71, 4, 50, 64, 147, 29, 178,
+ 100, 35, 37, 147, 132, 249, 24, 137, 128, 152,
+ 43, 224, 111, 57, 121, 132, 92, 4, 7, 161,
+ 160, 12, 111, 162, 11, 115, 32, 153, 199, 176,
+ 117, 63, 83, 158, 244, 8, 10, 148, 48, 144,
+ 237, 25, 8, 44, 26, 8, 114, 16, 8, 169,
+ 193, 8, 11, 41, 56, 133, 195, 3, 244, 99,
+ 117, 84, 80, 5, 80, 192, 111, 244, 195, 63,
+ 64, 16, 10, 186, 32, 12, 5, 234, 3, 49,
+ 48, 3, 195, 153, 6, 88, 48, 50, 240, 246,
+ 1, 73, 178, 7, 253, 213, 86, 90, 224, 160,
+ 142, 33, 6, 33, 48, 101, 254, 118, 67, 169,
+ 39, 8, 175, 208, 132, 210, 179, 11, 189, 176,
+ 5, 202, 160, 12, 107, 194, 117, 83, 216, 10,
+ 180, 83, 149, 44, 234, 5, 99, 224, 5, 127,
+ 224, 5, 110, 58, 6, 178, 89, 6, 74, 51,
+ 49, 80, 192, 144, 246, 83, 6, 159, 210, 119,
+ 166, 55, 75, 12, 57, 3, 213, 201, 132, 160,
+ 160, 6, 81, 48, 4, 254, 51, 48, 3, 89,
+ 96, 68, 73, 234, 125, 65, 96, 2, 73, 18,
+ 91, 1, 240, 50, 255, 160, 8, 81, 234, 24,
+ 142, 176, 4, 33, 32, 2, 137, 57, 3, 84,
+ 0, 5, 29, 84, 53, 64, 154, 42, 170, 144,
+ 9, 92, 112, 9, 165, 16, 143, 196, 98, 133,
+ 12, 184, 51, 104, 170, 166, 99, 176, 166, 115,
+ 227, 162, 173, 154, 52, 247, 217, 101, 89, 87,
+ 6, 132, 208, 8, 62, 89, 5, 67, 144, 147,
+ 19, 195, 3, 43, 96, 3, 81, 240, 10, 141,
+ 160, 6, 95, 217, 159, 126, 106, 3, 71, 36,
+ 6, 68, 80, 4, 50, 144, 36, 106, 21, 0,
+ 108, 5, 165, 147, 42, 21, 166, 96, 169, 83,
+ 214, 111, 137, 83, 5, 206, 3, 10, 161, 48,
+ 61, 170, 224, 7, 32, 0, 1, 50, 0, 9,
+ 186, 64, 39, 86, 104, 120, 202, 161, 170, 140,
+ 224, 166, 106, 250, 7, 109, 234, 166, 49, 228,
+ 5, 134, 224, 5, 73, 67, 63, 114, 80, 5,
+ 183, 154, 58, 55, 164, 2, 177, 73, 6, 80,
+ 96, 164, 108, 214, 10, 92, 198, 63, 51, 16,
+ 2, 6, 75, 95, 138, 42, 165, 248, 1, 82,
+ 34, 117, 16, 166, 80, 23, 155, 115, 11, 87,
+ 96, 161, 51, 192, 111, 156, 170, 108, 160, 32,
+ 61, 171, 192, 10, 32, 16, 124, 48, 208, 9,
+ 189, 128, 148, 208, 16, 14, 176, 72, 59, 55,
+ 69, 154, 129, 192, 166, 127, 176, 166, 114, 163,
+ 254, 166, 94, 0, 49, 77, 192, 3, 73, 208,
+ 4, 115, 67, 6, 160, 128, 171, 132, 160, 6,
+ 60, 10, 49, 60, 96, 3, 112, 112, 179, 100,
+ 16, 8, 236, 8, 4, 54, 96, 176, 33, 128,
+ 2, 40, 192, 2, 68, 160, 4, 213, 116, 77,
+ 9, 33, 169, 90, 48, 21, 115, 160, 111, 153,
+ 184, 3, 114, 136, 58, 135, 208, 173, 171, 224,
+ 10, 253, 132, 6, 81, 113, 10, 172, 240, 38,
+ 216, 160, 13, 242, 40, 164, 104, 250, 7, 129,
+ 224, 174, 129, 192, 8, 114, 208, 166, 134, 128,
+ 63, 17, 147, 56, 77, 32, 155, 132, 32, 138,
+ 136, 80, 5, 58, 11, 5, 47, 219, 5, 253,
+ 9, 7, 46, 74, 8, 236, 232, 3, 244, 133,
+ 2, 71, 139, 180, 44, 16, 4, 73, 178, 100,
+ 148, 164, 16, 121, 80, 23, 82, 225, 10, 55,
+ 153, 137, 70, 168, 6, 136, 32, 8, 47, 86,
+ 8, 165, 160, 9, 19, 96, 6, 142, 193, 7,
+ 163, 176, 11, 202, 192, 117, 242, 232, 78, 108,
+ 235, 174, 238, 58, 6, 104, 203, 170, 73, 227,
+ 5, 73, 48, 179, 65, 139, 171, 175, 80, 109,
+ 84, 80, 52, 178, 217, 4, 187, 58, 4, 217,
+ 82, 5, 83, 99, 5, 61, 128, 180, 190, 203,
+ 2, 46, 192, 180, 78, 36, 73, 254, 197, 184,
+ 117, 145, 7, 180, 192, 116, 138, 201, 111, 133,
+ 74, 117, 89, 112, 8, 186, 160, 9, 23, 16,
+ 25, 159, 171, 83, 240, 254, 120, 66, 104, 58,
+ 6, 129, 176, 166, 174, 10, 167, 100, 80, 175,
+ 245, 138, 51, 160, 144, 11, 112, 153, 71, 47,
+ 84, 62, 49, 91, 122, 116, 0, 60, 81, 0,
+ 4, 152, 122, 180, 75, 144, 1, 25, 112, 184,
+ 17, 68, 188, 15, 209, 184, 90, 80, 173, 54,
+ 80, 168, 167, 39, 60, 22, 243, 6, 208, 43,
+ 189, 146, 49, 10, 218, 112, 174, 19, 119, 44,
+ 60, 67, 186, 45, 234, 162, 114, 80, 175, 93,
+ 86, 6, 159, 0, 10, 177, 11, 7, 81, 112,
+ 132, 47, 75, 175, 78, 99, 52, 60, 160, 2,
+ 86, 90, 168, 54, 176, 4, 46, 144, 1, 87,
+ 112, 141, 213, 113, 6, 245, 102, 111, 16, 33,
+ 169, 138, 48, 177, 152, 184, 147, 19, 153, 122,
+ 28, 154, 12, 156, 48, 189, 146, 241, 12, 87,
+ 8, 13, 26, 215, 30, 237, 89, 11, 200, 128,
+ 12, 178, 3, 93, 235, 234, 5, 101, 144, 132,
+ 208, 149, 41, 21, 252, 144, 220, 27, 60, 117,
+ 250, 116, 161, 228, 163, 132, 116, 5, 46, 144,
+ 8, 248, 161, 4, 11, 32, 73, 139, 27, 17,
+ 166, 240, 5, 144, 208, 3, 251, 187, 111, 165,
+ 39, 135, 136, 240, 10, 146, 41, 192, 146, 113,
+ 10, 231, 96, 133, 212, 32, 12, 112, 195, 162,
+ 104, 27, 8, 173, 0, 55, 183, 214, 10, 55,
+ 85, 149, 79, 200, 173, 144, 99, 96, 170, 35,
+ 92, 192, 51, 4, 116, 64, 127, 161, 244, 129,
+ 254, 83, 80, 156, 147, 16, 100, 222, 8, 91,
+ 80, 116, 0, 103, 51, 17, 193, 192, 10, 145,
+ 123, 161, 6, 118, 181, 175, 240, 38, 153, 64,
+ 195, 53, 76, 178, 218, 128, 12, 185, 80, 149,
+ 109, 251, 7, 132, 32, 7, 134, 240, 7, 49,
+ 180, 182, 107, 11, 187, 91, 122, 8, 82, 96,
+ 3, 89, 128, 8, 173, 208, 8, 154, 92, 6,
+ 141, 208, 8, 129, 96, 8, 3, 103, 117, 207,
+ 35, 81, 27, 203, 131, 212, 161, 4, 32, 21,
+ 0, 18, 0, 169, 18, 49, 14, 107, 128, 137,
+ 251, 150, 122, 87, 43, 12, 245, 8, 12, 27,
+ 240, 151, 82, 241, 12, 218, 64, 13, 56, 44,
+ 12, 181, 192, 8, 105, 123, 83, 210, 44, 55,
+ 160, 204, 162, 148, 64, 48, 185, 16, 10, 161,
+ 80, 68, 105, 48, 190, 114, 76, 205, 55, 149,
+ 79, 172, 71, 45, 112, 208, 8, 163, 178, 10,
+ 201, 128, 203, 176, 161, 5, 39, 60, 73, 30,
+ 49, 8, 82, 230, 197, 95, 169, 202, 109, 162,
+ 12, 192, 64, 3, 150, 0, 27, 201, 35, 12,
+ 108, 34, 12, 210, 220, 162, 55, 229, 162, 110,
+ 26, 203, 238, 249, 198, 177, 160, 12, 144, 48,
+ 8, 177, 112, 12, 194, 0, 148, 205, 1, 55,
+ 210, 44, 205, 229, 67, 7, 201, 6, 42, 12,
+ 148, 12, 190, 0, 27, 124, 240, 1, 80, 20,
+ 0, 46, 243, 17, 170, 96, 5, 133, 122, 155,
+ 31, 168, 202, 14, 141, 254, 12, 189, 128, 4,
+ 146, 32, 25, 124, 160, 13, 171, 44, 144, 45,
+ 106, 8, 134, 240, 162, 11, 188, 182, 208, 149,
+ 66, 229, 169, 13, 151, 160, 10, 247, 88, 10,
+ 68, 89, 182, 85, 233, 96, 194, 101, 209, 81,
+ 160, 108, 151, 211, 11, 192, 240, 24, 168, 192,
+ 7, 42, 243, 209, 11, 144, 200, 30, 145, 12,
+ 105, 80, 168, 205, 171, 6, 231, 252, 10, 151,
+ 179, 11, 156, 112, 4, 252, 188, 198, 100, 112,
+ 205, 46, 26, 208, 114, 243, 162, 238, 233, 133,
+ 104, 87, 143, 47, 192, 10, 202, 80, 10, 200,
+ 64, 148, 225, 160, 198, 104, 26, 8, 179, 137,
+ 183, 114, 120, 8, 166, 162, 212, 190, 66, 43,
+ 158, 115, 0, 243, 194, 21, 127, 232, 167, 51,
+ 224, 111, 84, 87, 203, 165, 176, 11, 154, 0,
+ 3, 220, 244, 24, 189, 16, 206, 14, 214, 182,
+ 11, 108, 8, 105, 107, 211, 239, 36, 12, 150,
+ 29, 39, 30, 176, 5, 172, 208, 11, 14, 205,
+ 12, 218, 80, 11, 235, 73, 9, 44, 42, 155,
+ 134, 128, 49, 181, 60, 9, 170, 48, 10, 230,
+ 161, 5, 31, 240, 0, 125, 253, 0, 160, 182,
+ 23, 147, 64, 180, 23, 58, 117, 84, 23, 5,
+ 130, 112, 42, 174, 0, 3, 150, 240, 151, 171,
+ 144, 58, 1, 205, 174, 114, 80, 205, 160, 108,
+ 214, 3, 25, 209, 185, 160, 13, 202, 208, 0,
+ 3, 224, 1, 151, 32, 166, 152, 57, 48, 134,
+ 254, 112, 83, 16, 115, 45, 114, 184, 6, 125,
+ 112, 7, 123, 160, 5, 241, 178, 0, 125, 61,
+ 2, 216, 196, 23, 144, 80, 96, 21, 91, 177,
+ 253, 19, 5, 83, 112, 216, 192, 80, 2, 95,
+ 96, 23, 82, 234, 9, 165, 128, 8, 65, 27,
+ 180, 110, 74, 8, 163, 221, 182, 54, 157, 205,
+ 181, 192, 128, 185, 240, 10, 208, 160, 11, 13,
+ 160, 0, 24, 0, 6, 208, 32, 158, 208, 208,
+ 30, 234, 42, 223, 85, 144, 5, 216, 45, 23,
+ 57, 208, 218, 44, 227, 221, 22, 240, 4, 90,
+ 241, 29, 170, 64, 157, 215, 170, 147, 196, 147,
+ 208, 201, 128, 4, 102, 96, 25, 32, 94, 23,
+ 147, 120, 7, 125, 176, 6, 113, 160, 6, 214,
+ 60, 55, 106, 122, 223, 114, 4, 79, 39, 148,
+ 11, 255, 77, 1, 20, 112, 5, 170, 48, 182,
+ 205, 12, 205, 159, 64, 57, 120, 144, 221, 219,
+ 157, 3, 38, 80, 43, 101, 195, 50, 19, 238,
+ 203, 189, 1, 185, 243, 188, 188, 62, 48, 5,
+ 202, 128, 13, 201, 192, 6, 110, 224, 86, 121,
+ 0, 226, 82, 174, 4, 34, 126, 6, 36, 222,
+ 7, 120, 96, 226, 220, 226, 56, 17, 44, 154,
+ 151, 227, 148, 118, 201, 10, 124, 50, 10, 142,
+ 176, 33, 215, 225, 227, 77, 2, 228, 182, 242,
+ 0, 53, 240, 5, 68, 94, 34, 229, 120, 169,
+ 137, 169, 2, 6, 150, 5, 229, 186, 206, 48,
+ 64, 16, 166, 160, 8, 192, 81, 62, 229, 32,
+ 142, 25, 84, 238, 222, 115, 49, 232, 132, 110,
+ 23, 215, 113, 25, 218, 17, 34, 78, 178, 232,
+ 181, 98, 1, 109, 30, 32, 37, 162, 16, 151,
+ 64, 184, 152, 26, 127, 73, 94, 10, 73, 9,
+ 12, 56, 128, 16, 218, 148, 7, 121, 240, 5,
+ 182, 17, 234, 162, 158, 3, 184, 129, 27, 218,
+ 113, 234, 218, 209, 31, 253, 17, 34, 172, 206,
+ 232, 38, 160, 3, 0, 82, 225, 145, 206, 16,
+ 148, 142, 169, 116, 126, 164, 186, 144, 12, 187,
+ 237, 16, 150, 20, 9, 118, 96, 7, 95, 240,
+ 5, 216, 145, 29, 168, 158, 234, 170, 174, 1,
+ 31, 160, 3, 184, 17, 236, 120, 33, 235, 179,
+ 254, 16, 144, 75, 184, 136, 153, 106, 22, 185,
+ 6, 147, 192, 10, 174, 176, 1, 60, 65, 19,
+ 145, 240, 230, 207, 222, 17, 128, 64, 184, 33,
+ 96, 164, 86, 144, 6, 225, 226, 165, 154, 32,
+ 1, 223, 190, 238, 21, 225, 10, 75, 128, 2,
+ 54, 240, 3, 66, 148, 6, 228, 178, 11, 192,
+ 192, 4, 236, 158, 239, 2, 17, 16, 0, 59};
+
diff --git a/main/main.c b/main/main.c
new file mode 100644
index 0000000..be289c8
--- /dev/null
+++ b/main/main.c
@@ -0,0 +1,2645 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/* {{{ includes
+ */
+
+#define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
+
+#include "php.h"
+#include <stdio.h>
+#include <fcntl.h>
+#ifdef PHP_WIN32
+#include "win32/time.h"
+#include "win32/signal.h"
+#include "win32/php_win32_globals.h"
+#include "win32/winutil.h"
+#include <process.h>
+#elif defined(NETWARE)
+#include <sys/timeval.h>
+#ifdef USE_WINSOCK
+#include <novsock2.h>
+#endif
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#if HAVE_SETLOCALE
+#include <locale.h>
+#endif
+#include "zend.h"
+#include "zend_extensions.h"
+#include "php_ini.h"
+#include "php_globals.h"
+#include "php_main.h"
+#include "fopen_wrappers.h"
+#include "ext/standard/php_standard.h"
+#include "ext/standard/php_string.h"
+#include "ext/date/php_date.h"
+#include "php_variables.h"
+#include "ext/standard/credits.h"
+#ifdef PHP_WIN32
+#include <io.h>
+#include "win32/php_registry.h"
+#include "ext/standard/flock_compat.h"
+#endif
+#include "php_syslog.h"
+#include "Zend/zend_exceptions.h"
+
+#if PHP_SIGCHILD
+#include <sys/types.h>
+#include <sys/wait.h>
+#endif
+
+#include "zend_compile.h"
+#include "zend_execute.h"
+#include "zend_highlight.h"
+#include "zend_indent.h"
+#include "zend_extensions.h"
+#include "zend_ini.h"
+#include "zend_dtrace.h"
+
+#include "php_content_types.h"
+#include "php_ticks.h"
+#include "php_logos.h"
+#include "php_streams.h"
+#include "php_open_temporary_file.h"
+
+#include "SAPI.h"
+#include "rfc1867.h"
+
+#if HAVE_MMAP || defined(PHP_WIN32)
+# if HAVE_UNISTD_H
+# include <unistd.h>
+# if defined(_SC_PAGESIZE)
+# define REAL_PAGE_SIZE sysconf(_SC_PAGESIZE);
+# elif defined(_SC_PAGE_SIZE)
+# define REAL_PAGE_SIZE sysconf(_SC_PAGE_SIZE);
+# endif
+# endif
+# if HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+# endif
+# ifndef REAL_PAGE_SIZE
+# ifdef PAGE_SIZE
+# define REAL_PAGE_SIZE PAGE_SIZE
+# else
+# define REAL_PAGE_SIZE 4096
+# endif
+# endif
+#endif
+/* }}} */
+
+PHPAPI int (*php_register_internal_extensions_func)(TSRMLS_D) = php_register_internal_extensions;
+
+#ifndef ZTS
+php_core_globals core_globals;
+#else
+PHPAPI int core_globals_id;
+#endif
+
+#ifdef PHP_WIN32
+#include "win32_internal_function_disabled.h"
+
+static php_win32_disable_functions(TSRMLS_D)
+{
+ int i;
+
+ if (EG(windows_version_info).dwMajorVersion < 5) {
+ for (i = 0; i < function_name_cnt_5; i++) {
+ if (zend_hash_del(CG(function_table), function_name_5[i], strlen(function_name_5[i]) + 1)==FAILURE) {
+ php_printf("Unable to disable function '%s'\n", function_name_5[i]);
+ return FAILURE;
+ }
+ }
+ }
+
+ if (EG(windows_version_info).dwMajorVersion < 6) {
+ for (i = 0; i < function_name_cnt_6; i++) {
+ if (zend_hash_del(CG(function_table), function_name_6[i], strlen(function_name_6[i]) + 1)==FAILURE) {
+ php_printf("Unable to disable function '%s'\n", function_name_6[i]);
+ return FAILURE;
+ }
+ }
+ }
+ return SUCCESS;
+}
+#endif
+
+#define SAFE_FILENAME(f) ((f)?(f):"-")
+
+/* {{{ PHP_INI_MH
+ */
+static PHP_INI_MH(OnSetPrecision)
+{
+ int i = atoi(new_value);
+ if (i >= 0) {
+ EG(precision) = i;
+ return SUCCESS;
+ } else {
+ return FAILURE;
+ }
+}
+/* }}} */
+
+/* {{{ PHP_INI_MH
+ */
+static PHP_INI_MH(OnChangeMemoryLimit)
+{
+ if (new_value) {
+ PG(memory_limit) = zend_atol(new_value, new_value_length);
+ } else {
+ PG(memory_limit) = 1<<30; /* effectively, no limit */
+ }
+ return zend_set_memory_limit(PG(memory_limit));
+}
+/* }}} */
+
+
+/* {{{ php_disable_functions
+ */
+static void php_disable_functions(TSRMLS_D)
+{
+ char *s = NULL, *e;
+
+ if (!*(INI_STR("disable_functions"))) {
+ return;
+ }
+
+ e = PG(disable_functions) = strdup(INI_STR("disable_functions"));
+ if (e == NULL) {
+ return;
+ }
+ while (*e) {
+ switch (*e) {
+ case ' ':
+ case ',':
+ if (s) {
+ *e = '\0';
+ zend_disable_function(s, e-s TSRMLS_CC);
+ s = NULL;
+ }
+ break;
+ default:
+ if (!s) {
+ s = e;
+ }
+ break;
+ }
+ e++;
+ }
+ if (s) {
+ zend_disable_function(s, e-s TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ php_disable_classes
+ */
+static void php_disable_classes(TSRMLS_D)
+{
+ char *s = NULL, *e;
+
+ if (!*(INI_STR("disable_classes"))) {
+ return;
+ }
+
+ e = PG(disable_classes) = strdup(INI_STR("disable_classes"));
+
+ while (*e) {
+ switch (*e) {
+ case ' ':
+ case ',':
+ if (s) {
+ *e = '\0';
+ zend_disable_class(s, e-s TSRMLS_CC);
+ s = NULL;
+ }
+ break;
+ default:
+ if (!s) {
+ s = e;
+ }
+ break;
+ }
+ e++;
+ }
+ if (s) {
+ zend_disable_class(s, e-s TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ php_binary_init
+ */
+static void php_binary_init(TSRMLS_D)
+{
+ char *binary_location;
+#ifdef PHP_WIN32
+ binary_location = (char *)malloc(MAXPATHLEN);
+ if (GetModuleFileName(0, binary_location, MAXPATHLEN) == 0) {
+ free(binary_location);
+ PG(php_binary) = NULL;
+ }
+#else
+ if (sapi_module.executable_location) {
+ binary_location = (char *)malloc(MAXPATHLEN);
+ if (!strchr(sapi_module.executable_location, '/')) {
+ char *envpath, *path;
+ int found = 0;
+
+ if ((envpath = getenv("PATH")) != NULL) {
+ char *search_dir, search_path[MAXPATHLEN];
+ char *last = NULL;
+
+ path = estrdup(envpath);
+ search_dir = php_strtok_r(path, ":", &last);
+
+ while (search_dir) {
+ snprintf(search_path, MAXPATHLEN, "%s/%s", search_dir, sapi_module.executable_location);
+ if (VCWD_REALPATH(search_path, binary_location) && !VCWD_ACCESS(binary_location, X_OK)) {
+ found = 1;
+ break;
+ }
+ search_dir = php_strtok_r(NULL, ":", &last);
+ }
+ efree(path);
+ }
+ if (!found) {
+ free(binary_location);
+ binary_location = NULL;
+ }
+ } else if (!VCWD_REALPATH(sapi_module.executable_location, binary_location) || VCWD_ACCESS(binary_location, X_OK)) {
+ free(binary_location);
+ binary_location = NULL;
+ }
+ } else {
+ binary_location = NULL;
+ }
+#endif
+ PG(php_binary) = binary_location;
+}
+/* }}} */
+
+/* {{{ PHP_INI_MH
+ */
+static PHP_INI_MH(OnUpdateTimeout)
+{
+ if (stage==PHP_INI_STAGE_STARTUP) {
+ /* Don't set a timeout on startup, only per-request */
+ EG(timeout_seconds) = atoi(new_value);
+ return SUCCESS;
+ }
+ zend_unset_timeout(TSRMLS_C);
+ EG(timeout_seconds) = atoi(new_value);
+ zend_set_timeout(EG(timeout_seconds), 0);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ php_get_display_errors_mode() helper function
+ */
+static int php_get_display_errors_mode(char *value, int value_length)
+{
+ int mode;
+
+ if (!value) {
+ return PHP_DISPLAY_ERRORS_STDOUT;
+ }
+
+ if (value_length == 2 && !strcasecmp("on", value)) {
+ mode = PHP_DISPLAY_ERRORS_STDOUT;
+ } else if (value_length == 3 && !strcasecmp("yes", value)) {
+ mode = PHP_DISPLAY_ERRORS_STDOUT;
+ } else if (value_length == 4 && !strcasecmp("true", value)) {
+ mode = PHP_DISPLAY_ERRORS_STDOUT;
+ } else if (value_length == 6 && !strcasecmp(value, "stderr")) {
+ mode = PHP_DISPLAY_ERRORS_STDERR;
+ } else if (value_length == 6 && !strcasecmp(value, "stdout")) {
+ mode = PHP_DISPLAY_ERRORS_STDOUT;
+ } else {
+ mode = atoi(value);
+ if (mode && mode != PHP_DISPLAY_ERRORS_STDOUT && mode != PHP_DISPLAY_ERRORS_STDERR) {
+ mode = PHP_DISPLAY_ERRORS_STDOUT;
+ }
+ }
+
+ return mode;
+}
+/* }}} */
+
+/* {{{ PHP_INI_MH
+ */
+static PHP_INI_MH(OnUpdateDisplayErrors)
+{
+ PG(display_errors) = (zend_bool) php_get_display_errors_mode(new_value, new_value_length);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_INI_DISP
+ */
+static PHP_INI_DISP(display_errors_mode)
+{
+ int mode, tmp_value_length, cgi_or_cli;
+ char *tmp_value;
+ TSRMLS_FETCH();
+
+ if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
+ tmp_value = (ini_entry->orig_value ? ini_entry->orig_value : NULL );
+ tmp_value_length = ini_entry->orig_value_length;
+ } else if (ini_entry->value) {
+ tmp_value = ini_entry->value;
+ tmp_value_length = ini_entry->value_length;
+ } else {
+ tmp_value = NULL;
+ tmp_value_length = 0;
+ }
+
+ mode = php_get_display_errors_mode(tmp_value, tmp_value_length);
+
+ /* Display 'On' for other SAPIs instead of STDOUT or STDERR */
+ cgi_or_cli = (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "cgi"));
+
+ switch (mode) {
+ case PHP_DISPLAY_ERRORS_STDERR:
+ if (cgi_or_cli ) {
+ PUTS("STDERR");
+ } else {
+ PUTS("On");
+ }
+ break;
+
+ case PHP_DISPLAY_ERRORS_STDOUT:
+ if (cgi_or_cli ) {
+ PUTS("STDOUT");
+ } else {
+ PUTS("On");
+ }
+ break;
+
+ default:
+ PUTS("Off");
+ break;
+ }
+}
+/* }}} */
+
+/* {{{ PHP_INI_MH
+ */
+static PHP_INI_MH(OnUpdateErrorLog)
+{
+ /* Only do the safemode/open_basedir check at runtime */
+ if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) && new_value && strcmp(new_value, "syslog")) {
+ if (PG(open_basedir) && php_check_open_basedir(new_value TSRMLS_CC)) {
+ return FAILURE;
+ }
+ }
+ OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_INI_MH
+ */
+static PHP_INI_MH(OnUpdateMailLog)
+{
+ /* Only do the safemode/open_basedir check at runtime */
+ if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) && new_value) {
+ if (PG(open_basedir) && php_check_open_basedir(new_value TSRMLS_CC)) {
+ return FAILURE;
+ }
+ }
+ OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_INI_MH
+ */
+static PHP_INI_MH(OnChangeMailForceExtra)
+{
+ /* Don't allow changing it in htaccess */
+ if (stage == PHP_INI_STAGE_HTACCESS) {
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/* defined in browscap.c */
+PHP_INI_MH(OnChangeBrowscap);
+
+
+/* Need to be read from the environment (?):
+ * PHP_AUTO_PREPEND_FILE
+ * PHP_AUTO_APPEND_FILE
+ * PHP_DOCUMENT_ROOT
+ * PHP_USER_DIR
+ * PHP_INCLUDE_PATH
+ */
+
+ /* Windows and Netware use the internal mail */
+#if defined(PHP_WIN32) || defined(NETWARE)
+# define DEFAULT_SENDMAIL_PATH NULL
+#elif defined(PHP_PROG_SENDMAIL)
+# define DEFAULT_SENDMAIL_PATH PHP_PROG_SENDMAIL " -t -i "
+#else
+# define DEFAULT_SENDMAIL_PATH "/usr/sbin/sendmail -t -i"
+#endif
+
+/* {{{ PHP_INI
+ */
+PHP_INI_BEGIN()
+ PHP_INI_ENTRY_EX("highlight.comment", HL_COMMENT_COLOR, PHP_INI_ALL, NULL, php_ini_color_displayer_cb)
+ PHP_INI_ENTRY_EX("highlight.default", HL_DEFAULT_COLOR, PHP_INI_ALL, NULL, php_ini_color_displayer_cb)
+ PHP_INI_ENTRY_EX("highlight.html", HL_HTML_COLOR, PHP_INI_ALL, NULL, php_ini_color_displayer_cb)
+ PHP_INI_ENTRY_EX("highlight.keyword", HL_KEYWORD_COLOR, PHP_INI_ALL, NULL, php_ini_color_displayer_cb)
+ PHP_INI_ENTRY_EX("highlight.string", HL_STRING_COLOR, PHP_INI_ALL, NULL, php_ini_color_displayer_cb)
+
+ STD_PHP_INI_BOOLEAN("asp_tags", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, asp_tags, zend_compiler_globals, compiler_globals)
+ STD_PHP_INI_ENTRY_EX("display_errors", "1", PHP_INI_ALL, OnUpdateDisplayErrors, display_errors, php_core_globals, core_globals, display_errors_mode)
+ STD_PHP_INI_BOOLEAN("display_startup_errors", "0", PHP_INI_ALL, OnUpdateBool, display_startup_errors, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("enable_dl", "1", PHP_INI_SYSTEM, OnUpdateBool, enable_dl, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("expose_php", "1", PHP_INI_SYSTEM, OnUpdateBool, expose_php, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("docref_root", "", PHP_INI_ALL, OnUpdateString, docref_root, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("docref_ext", "", PHP_INI_ALL, OnUpdateString, docref_ext, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("html_errors", "1", PHP_INI_ALL, OnUpdateBool, html_errors, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("xmlrpc_errors", "0", PHP_INI_SYSTEM, OnUpdateBool, xmlrpc_errors, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("xmlrpc_error_number", "0", PHP_INI_ALL, OnUpdateLong, xmlrpc_error_number, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("max_input_time", "-1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, max_input_time, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("ignore_user_abort", "0", PHP_INI_ALL, OnUpdateBool, ignore_user_abort, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("implicit_flush", "0", PHP_INI_ALL, OnUpdateBool, implicit_flush, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("log_errors", "0", PHP_INI_ALL, OnUpdateBool, log_errors, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("log_errors_max_len", "1024", PHP_INI_ALL, OnUpdateLong, log_errors_max_len, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("ignore_repeated_errors", "0", PHP_INI_ALL, OnUpdateBool, ignore_repeated_errors, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("ignore_repeated_source", "0", PHP_INI_ALL, OnUpdateBool, ignore_repeated_source, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("report_memleaks", "1", PHP_INI_ALL, OnUpdateBool, report_memleaks, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("report_zend_debug", "1", PHP_INI_ALL, OnUpdateBool, report_zend_debug, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("output_buffering", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateLong, output_buffering, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("output_handler", NULL, PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateString, output_handler, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("register_argc_argv", "1", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, register_argc_argv, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("auto_globals_jit", "1", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, auto_globals_jit, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("short_open_tag", DEFAULT_SHORT_OPEN_TAG, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, short_tags, zend_compiler_globals, compiler_globals)
+ STD_PHP_INI_BOOLEAN("sql.safe_mode", "0", PHP_INI_SYSTEM, OnUpdateBool, sql_safe_mode, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("track_errors", "0", PHP_INI_ALL, OnUpdateBool, track_errors, php_core_globals, core_globals)
+
+ STD_PHP_INI_ENTRY("unserialize_callback_func", NULL, PHP_INI_ALL, OnUpdateString, unserialize_callback_func, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("serialize_precision", "17", PHP_INI_ALL, OnUpdateLongGEZero, serialize_precision, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("arg_separator.output", "&", PHP_INI_ALL, OnUpdateStringUnempty, arg_separator.output, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("arg_separator.input", "&", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateStringUnempty, arg_separator.input, php_core_globals, core_globals)
+
+ STD_PHP_INI_ENTRY("auto_append_file", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, auto_append_file, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("auto_prepend_file", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, auto_prepend_file, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("doc_root", NULL, PHP_INI_SYSTEM, OnUpdateStringUnempty, doc_root, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("default_charset", SAPI_DEFAULT_CHARSET, PHP_INI_ALL, OnUpdateString, default_charset, sapi_globals_struct,sapi_globals)
+ STD_PHP_INI_ENTRY("default_mimetype", SAPI_DEFAULT_MIMETYPE, PHP_INI_ALL, OnUpdateString, default_mimetype, sapi_globals_struct,sapi_globals)
+ STD_PHP_INI_ENTRY("error_log", NULL, PHP_INI_ALL, OnUpdateErrorLog, error_log, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("extension_dir", PHP_EXTENSION_DIR, PHP_INI_SYSTEM, OnUpdateStringUnempty, extension_dir, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("include_path", PHP_INCLUDE_PATH, PHP_INI_ALL, OnUpdateStringUnempty, include_path, php_core_globals, core_globals)
+ PHP_INI_ENTRY("max_execution_time", "30", PHP_INI_ALL, OnUpdateTimeout)
+ STD_PHP_INI_ENTRY("open_basedir", NULL, PHP_INI_ALL, OnUpdateBaseDir, open_basedir, php_core_globals, core_globals)
+
+ STD_PHP_INI_BOOLEAN("file_uploads", "1", PHP_INI_SYSTEM, OnUpdateBool, file_uploads, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("upload_max_filesize", "2M", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, upload_max_filesize, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("post_max_size", "8M", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, post_max_size, sapi_globals_struct,sapi_globals)
+ STD_PHP_INI_ENTRY("upload_tmp_dir", NULL, PHP_INI_SYSTEM, OnUpdateStringUnempty, upload_tmp_dir, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("max_input_nesting_level", "64", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLongGEZero, max_input_nesting_level, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("max_input_vars", "1000", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLongGEZero, max_input_vars, php_core_globals, core_globals)
+
+ STD_PHP_INI_ENTRY("user_dir", NULL, PHP_INI_SYSTEM, OnUpdateString, user_dir, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("variables_order", "EGPCS", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateStringUnempty, variables_order, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("request_order", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, request_order, php_core_globals, core_globals)
+
+ STD_PHP_INI_ENTRY("error_append_string", NULL, PHP_INI_ALL, OnUpdateString, error_append_string, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("error_prepend_string", NULL, PHP_INI_ALL, OnUpdateString, error_prepend_string, php_core_globals, core_globals)
+
+ PHP_INI_ENTRY("SMTP", "localhost",PHP_INI_ALL, NULL)
+ PHP_INI_ENTRY("smtp_port", "25", PHP_INI_ALL, NULL)
+ STD_PHP_INI_BOOLEAN("mail.add_x_header", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, mail_x_header, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("mail.log", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateMailLog, mail_log, php_core_globals, core_globals)
+ PHP_INI_ENTRY("browscap", NULL, PHP_INI_SYSTEM, OnChangeBrowscap)
+ PHP_INI_ENTRY("memory_limit", "128M", PHP_INI_ALL, OnChangeMemoryLimit)
+ PHP_INI_ENTRY("precision", "14", PHP_INI_ALL, OnSetPrecision)
+ PHP_INI_ENTRY("sendmail_from", NULL, PHP_INI_ALL, NULL)
+ PHP_INI_ENTRY("sendmail_path", DEFAULT_SENDMAIL_PATH, PHP_INI_SYSTEM, NULL)
+ PHP_INI_ENTRY("mail.force_extra_parameters",NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnChangeMailForceExtra)
+ PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL)
+ PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL)
+ PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL)
+
+ STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("enable_post_data_reading", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, enable_post_data_reading, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("always_populate_raw_post_data", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, always_populate_raw_post_data, php_core_globals, core_globals)
+
+ STD_PHP_INI_ENTRY("realpath_cache_size", "16K", PHP_INI_SYSTEM, OnUpdateLong, realpath_cache_size_limit, virtual_cwd_globals, cwd_globals)
+ STD_PHP_INI_ENTRY("realpath_cache_ttl", "120", PHP_INI_SYSTEM, OnUpdateLong, realpath_cache_ttl, virtual_cwd_globals, cwd_globals)
+
+ STD_PHP_INI_ENTRY("user_ini.filename", ".user.ini", PHP_INI_SYSTEM, OnUpdateString, user_ini_filename, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("user_ini.cache_ttl", "300", PHP_INI_SYSTEM, OnUpdateLong, user_ini_cache_ttl, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("exit_on_timeout", "0", PHP_INI_ALL, OnUpdateBool, exit_on_timeout, php_core_globals, core_globals)
+#ifdef PHP_WIN32
+ STD_PHP_INI_BOOLEAN("windows.show_crt_warning", "0", PHP_INI_ALL, OnUpdateBool, windows_show_crt_warning, php_core_globals, core_globals)
+#endif
+PHP_INI_END()
+/* }}} */
+
+/* True globals (no need for thread safety */
+/* But don't make them a single int bitfield */
+static int module_initialized = 0;
+static int module_startup = 1;
+static int module_shutdown = 0;
+
+/* {{{ php_during_module_startup */
+static int php_during_module_startup(void)
+{
+ return module_startup;
+}
+/* }}} */
+
+/* {{{ php_during_module_shutdown */
+static int php_during_module_shutdown(void)
+{
+ return module_shutdown;
+}
+/* }}} */
+
+/* {{{ php_get_module_initialized
+ */
+PHPAPI int php_get_module_initialized(void)
+{
+ return module_initialized;
+}
+/* }}} */
+
+/* {{{ php_log_err
+ */
+PHPAPI void php_log_err(char *log_message TSRMLS_DC)
+{
+ int fd = -1;
+ time_t error_time;
+
+ if (PG(in_error_log)) {
+ /* prevent recursive invocation */
+ return;
+ }
+ PG(in_error_log) = 1;
+
+ /* Try to use the specified logging location. */
+ if (PG(error_log) != NULL) {
+#ifdef HAVE_SYSLOG_H
+ if (!strcmp(PG(error_log), "syslog")) {
+ php_syslog(LOG_NOTICE, "%s", log_message);
+ PG(in_error_log) = 0;
+ return;
+ }
+#endif
+ fd = VCWD_OPEN_MODE(PG(error_log), O_CREAT | O_APPEND | O_WRONLY, 0644);
+ if (fd != -1) {
+ char *tmp;
+ int len;
+ char *error_time_str;
+
+ time(&error_time);
+#ifdef ZTS
+ if (!php_during_module_startup()) {
+ error_time_str = php_format_date("d-M-Y H:i:s e", 13, error_time, 1 TSRMLS_CC);
+ } else {
+ error_time_str = php_format_date("d-M-Y H:i:s e", 13, error_time, 0 TSRMLS_CC);
+ }
+#else
+ error_time_str = php_format_date("d-M-Y H:i:s e", 13, error_time, 1 TSRMLS_CC);
+#endif
+ len = spprintf(&tmp, 0, "[%s] %s%s", error_time_str, log_message, PHP_EOL);
+#ifdef PHP_WIN32
+ php_flock(fd, 2);
+#endif
+ php_ignore_value(write(fd, tmp, len));
+ efree(tmp);
+ efree(error_time_str);
+ close(fd);
+ PG(in_error_log) = 0;
+ return;
+ }
+ }
+
+ /* Otherwise fall back to the default logging location, if we have one */
+
+ if (sapi_module.log_message) {
+ sapi_module.log_message(log_message TSRMLS_CC);
+ }
+ PG(in_error_log) = 0;
+}
+/* }}} */
+
+/* {{{ php_write
+ wrapper for modules to use PHPWRITE */
+PHPAPI int php_write(void *buf, uint size TSRMLS_DC)
+{
+ return PHPWRITE(buf, size);
+}
+/* }}} */
+
+/* {{{ php_printf
+ */
+PHPAPI int php_printf(const char *format, ...)
+{
+ va_list args;
+ int ret;
+ char *buffer;
+ int size;
+ TSRMLS_FETCH();
+
+ va_start(args, format);
+ size = vspprintf(&buffer, 0, format, args);
+ ret = PHPWRITE(buffer, size);
+ efree(buffer);
+ va_end(args);
+
+ return ret;
+}
+/* }}} */
+
+/* {{{ php_verror */
+/* php_verror is called from php_error_docref<n> functions.
+ * Its purpose is to unify error messages and automatically generate clickable
+ * html error messages if correcponding ini setting (html_errors) is activated.
+ * See: CODING_STANDARDS for details.
+ */
+PHPAPI void php_verror(const char *docref, const char *params, int type, const char *format, va_list args TSRMLS_DC)
+{
+ char *buffer = NULL, *docref_buf = NULL, *target = NULL;
+ char *docref_target = "", *docref_root = "";
+ char *p;
+ int buffer_len = 0;
+ const char *space = "";
+ const char *class_name = "";
+ const char *function;
+ int origin_len;
+ char *origin;
+ char *message;
+ int is_function = 0;
+
+ /* get error text into buffer and escape for html if necessary */
+ buffer_len = vspprintf(&buffer, 0, format, args);
+
+ if (PG(html_errors)) {
+ size_t len;
+ char *replace = php_escape_html_entities(buffer, buffer_len, &len, 0, ENT_COMPAT, NULL TSRMLS_CC);
+ efree(buffer);
+ buffer = replace;
+ buffer_len = len;
+ }
+
+ /* which function caused the problem if any at all */
+ if (php_during_module_startup()) {
+ function = "PHP Startup";
+ } else if (php_during_module_shutdown()) {
+ function = "PHP Shutdown";
+ } else if (EG(current_execute_data) &&
+ EG(current_execute_data)->opline &&
+ EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL
+ ) {
+ switch (EG(current_execute_data)->opline->extended_value) {
+ case ZEND_EVAL:
+ function = "eval";
+ is_function = 1;
+ break;
+ case ZEND_INCLUDE:
+ function = "include";
+ is_function = 1;
+ break;
+ case ZEND_INCLUDE_ONCE:
+ function = "include_once";
+ is_function = 1;
+ break;
+ case ZEND_REQUIRE:
+ function = "require";
+ is_function = 1;
+ break;
+ case ZEND_REQUIRE_ONCE:
+ function = "require_once";
+ is_function = 1;
+ break;
+ default:
+ function = "Unknown";
+ }
+ } else {
+ function = get_active_function_name(TSRMLS_C);
+ if (!function || !strlen(function)) {
+ function = "Unknown";
+ } else {
+ is_function = 1;
+ class_name = get_active_class_name(&space TSRMLS_CC);
+ }
+ }
+
+ /* if we still have memory then format the origin */
+ if (is_function) {
+ origin_len = spprintf(&origin, 0, "%s%s%s(%s)", class_name, space, function, params);
+ } else {
+ origin_len = spprintf(&origin, 0, "%s", function);
+ }
+
+ if (PG(html_errors)) {
+ size_t len;
+ char *replace = php_escape_html_entities(origin, origin_len, &len, 0, ENT_COMPAT, NULL TSRMLS_CC);
+ efree(origin);
+ origin = replace;
+ }
+
+ /* origin and buffer available, so lets come up with the error message */
+ if (docref && docref[0] == '#') {
+ docref_target = strchr(docref, '#');
+ docref = NULL;
+ }
+
+ /* no docref given but function is known (the default) */
+ if (!docref && is_function) {
+ int doclen;
+ if (space[0] == '\0') {
+ doclen = spprintf(&docref_buf, 0, "function.%s", function);
+ } else {
+ doclen = spprintf(&docref_buf, 0, "%s.%s", class_name, function);
+ }
+ while((p = strchr(docref_buf, '_')) != NULL) {
+ *p = '-';
+ }
+ docref = php_strtolower(docref_buf, doclen);
+ }
+
+ /* we have a docref for a function AND
+ * - we show errors in html mode AND
+ * - the user wants to see the links
+ */
+ if (docref && is_function && PG(html_errors) && strlen(PG(docref_root))) {
+ if (strncmp(docref, "http://", 7)) {
+ /* We don't have 'http://' so we use docref_root */
+
+ char *ref; /* temp copy for duplicated docref */
+
+ docref_root = PG(docref_root);
+
+ ref = estrdup(docref);
+ if (docref_buf) {
+ efree(docref_buf);
+ }
+ docref_buf = ref;
+ /* strip of the target if any */
+ p = strrchr(ref, '#');
+ if (p) {
+ target = estrdup(p);
+ if (target) {
+ docref_target = target;
+ *p = '\0';
+ }
+ }
+ /* add the extension if it is set in ini */
+ if (PG(docref_ext) && strlen(PG(docref_ext))) {
+ spprintf(&docref_buf, 0, "%s%s", ref, PG(docref_ext));
+ efree(ref);
+ }
+ docref = docref_buf;
+ }
+ /* display html formatted or only show the additional links */
+ if (PG(html_errors)) {
+ spprintf(&message, 0, "%s [<a href='%s%s%s'>%s</a>]: %s", origin, docref_root, docref, docref_target, docref, buffer);
+ } else {
+ spprintf(&message, 0, "%s [%s%s%s]: %s", origin, docref_root, docref, docref_target, buffer);
+ }
+ if (target) {
+ efree(target);
+ }
+ } else {
+ spprintf(&message, 0, "%s: %s", origin, buffer);
+ }
+ efree(origin);
+ if (docref_buf) {
+ efree(docref_buf);
+ }
+
+ if (PG(track_errors) && module_initialized &&
+ (!EG(user_error_handler) || !(EG(user_error_handler_error_reporting) & type))) {
+ if (!EG(active_symbol_table)) {
+ zend_rebuild_symbol_table(TSRMLS_C);
+ }
+ if (EG(active_symbol_table)) {
+ zval *tmp;
+ ALLOC_INIT_ZVAL(tmp);
+ ZVAL_STRINGL(tmp, buffer, buffer_len, 1);
+ zend_hash_update(EG(active_symbol_table), "php_errormsg", sizeof("php_errormsg"), (void **) &tmp, sizeof(zval *), NULL);
+ }
+ }
+ efree(buffer);
+
+ php_error(type, "%s", message);
+ efree(message);
+}
+/* }}} */
+
+/* {{{ php_error_docref0 */
+/* See: CODING_STANDARDS for details. */
+PHPAPI void php_error_docref0(const char *docref TSRMLS_DC, int type, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ php_verror(docref, "", type, format, args TSRMLS_CC);
+ va_end(args);
+}
+/* }}} */
+
+/* {{{ php_error_docref1 */
+/* See: CODING_STANDARDS for details. */
+PHPAPI void php_error_docref1(const char *docref TSRMLS_DC, const char *param1, int type, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ php_verror(docref, param1, type, format, args TSRMLS_CC);
+ va_end(args);
+}
+/* }}} */
+
+/* {{{ php_error_docref2 */
+/* See: CODING_STANDARDS for details. */
+PHPAPI void php_error_docref2(const char *docref TSRMLS_DC, const char *param1, const char *param2, int type, const char *format, ...)
+{
+ char *params;
+ va_list args;
+
+ spprintf(&params, 0, "%s,%s", param1, param2);
+ va_start(args, format);
+ php_verror(docref, params ? params : "...", type, format, args TSRMLS_CC);
+ va_end(args);
+ if (params) {
+ efree(params);
+ }
+}
+/* }}} */
+
+#ifdef PHP_WIN32
+#define PHP_WIN32_ERROR_MSG_BUFFER_SIZE 512
+PHPAPI void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2 TSRMLS_DC) {
+ if (error == 0) {
+ php_error_docref2(NULL TSRMLS_CC, param1, param2, E_WARNING, "%s", strerror(errno));
+ } else {
+ char buf[PHP_WIN32_ERROR_MSG_BUFFER_SIZE + 1];
+ int buf_len;
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buf, PHP_WIN32_ERROR_MSG_BUFFER_SIZE, NULL);
+ buf_len = strlen(buf);
+ if (buf_len >= 2) {
+ buf[buf_len - 1] = '\0';
+ buf[buf_len - 2] = '\0';
+ }
+ php_error_docref2(NULL TSRMLS_CC, param1, param2, E_WARNING, "%s (code: %lu)", (char *)buf, error);
+ }
+}
+#undef PHP_WIN32_ERROR_MSG_BUFFER_SIZE
+#endif
+
+/* {{{ php_html_puts */
+PHPAPI void php_html_puts(const char *str, uint size TSRMLS_DC)
+{
+ zend_html_puts(str, size TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ php_error_cb
+ extended error handling function */
+static void php_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args)
+{
+ char *buffer;
+ int buffer_len, display;
+ TSRMLS_FETCH();
+
+ buffer_len = vspprintf(&buffer, PG(log_errors_max_len), format, args);
+
+ /* check for repeated errors to be ignored */
+ if (PG(ignore_repeated_errors) && PG(last_error_message)) {
+ /* no check for PG(last_error_file) is needed since it cannot
+ * be NULL if PG(last_error_message) is not NULL */
+ if (strcmp(PG(last_error_message), buffer)
+ || (!PG(ignore_repeated_source)
+ && ((PG(last_error_lineno) != (int)error_lineno)
+ || strcmp(PG(last_error_file), error_filename)))) {
+ display = 1;
+ } else {
+ display = 0;
+ }
+ } else {
+ display = 1;
+ }
+
+ /* store the error if it has changed */
+ if (display) {
+#ifdef ZEND_SIGNALS
+ HANDLE_BLOCK_INTERRUPTIONS();
+#endif
+ if (PG(last_error_message)) {
+ free(PG(last_error_message));
+ PG(last_error_message) = NULL;
+ }
+ if (PG(last_error_file)) {
+ free(PG(last_error_file));
+ PG(last_error_file) = NULL;
+ }
+#ifdef ZEND_SIGNALS
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+#endif
+ if (!error_filename) {
+ error_filename = "Unknown";
+ }
+ PG(last_error_type) = type;
+ PG(last_error_message) = strdup(buffer);
+ PG(last_error_file) = strdup(error_filename);
+ PG(last_error_lineno) = error_lineno;
+ }
+
+ /* according to error handling mode, suppress error, throw exception or show it */
+ if (EG(error_handling) != EH_NORMAL) {
+ switch (type) {
+ case E_ERROR:
+ case E_CORE_ERROR:
+ case E_COMPILE_ERROR:
+ case E_USER_ERROR:
+ case E_PARSE:
+ /* fatal errors are real errors and cannot be made exceptions */
+ break;
+ case E_STRICT:
+ case E_DEPRECATED:
+ case E_USER_DEPRECATED:
+ /* for the sake of BC to old damaged code */
+ break;
+ case E_NOTICE:
+ case E_USER_NOTICE:
+ /* notices are no errors and are not treated as such like E_WARNINGS */
+ break;
+ default:
+ /* throw an exception if we are in EH_THROW mode
+ * but DO NOT overwrite a pending exception
+ */
+ if (EG(error_handling) == EH_THROW && !EG(exception)) {
+ zend_throw_error_exception(EG(exception_class), buffer, 0, type TSRMLS_CC);
+ }
+ efree(buffer);
+ return;
+ }
+ }
+
+ /* display/log the error if necessary */
+ if (display && (EG(error_reporting) & type || (type & E_CORE))
+ && (PG(log_errors) || PG(display_errors) || (!module_initialized))) {
+ char *error_type_str;
+
+ switch (type) {
+ case E_ERROR:
+ case E_CORE_ERROR:
+ case E_COMPILE_ERROR:
+ case E_USER_ERROR:
+ error_type_str = "Fatal error";
+ break;
+ case E_RECOVERABLE_ERROR:
+ error_type_str = "Catchable fatal error";
+ break;
+ case E_WARNING:
+ case E_CORE_WARNING:
+ case E_COMPILE_WARNING:
+ case E_USER_WARNING:
+ error_type_str = "Warning";
+ break;
+ case E_PARSE:
+ error_type_str = "Parse error";
+ break;
+ case E_NOTICE:
+ case E_USER_NOTICE:
+ error_type_str = "Notice";
+ break;
+ case E_STRICT:
+ error_type_str = "Strict Standards";
+ break;
+ case E_DEPRECATED:
+ case E_USER_DEPRECATED:
+ error_type_str = "Deprecated";
+ break;
+ default:
+ error_type_str = "Unknown error";
+ break;
+ }
+
+ if (!module_initialized || PG(log_errors)) {
+ char *log_buffer;
+#ifdef PHP_WIN32
+ if ((type == E_CORE_ERROR || type == E_CORE_WARNING) && PG(display_startup_errors)) {
+ MessageBox(NULL, buffer, error_type_str, MB_OK|ZEND_SERVICE_MB_STYLE);
+ }
+#endif
+ spprintf(&log_buffer, 0, "PHP %s: %s in %s on line %d", error_type_str, buffer, error_filename, error_lineno);
+ php_log_err(log_buffer TSRMLS_CC);
+ efree(log_buffer);
+ }
+
+ if (PG(display_errors) && ((module_initialized && !PG(during_request_startup)) || (PG(display_startup_errors)))) {
+ if (PG(xmlrpc_errors)) {
+ php_printf("<?xml version=\"1.0\"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><int>%ld</int></value></member><member><name>faultString</name><value><string>%s:%s in %s on line %d</string></value></member></struct></value></fault></methodResponse>", PG(xmlrpc_error_number), error_type_str, buffer, error_filename, error_lineno);
+ } else {
+ char *prepend_string = INI_STR("error_prepend_string");
+ char *append_string = INI_STR("error_append_string");
+
+ if (PG(html_errors)) {
+ if (type == E_ERROR || type == E_PARSE) {
+ size_t len;
+ char *buf = php_escape_html_entities(buffer, buffer_len, &len, 0, ENT_COMPAT, NULL TSRMLS_CC);
+ php_printf("%s<br />\n<b>%s</b>: %s in <b>%s</b> on line <b>%d</b><br />\n%s", STR_PRINT(prepend_string), error_type_str, buf, error_filename, error_lineno, STR_PRINT(append_string));
+ efree(buf);
+ } else {
+ php_printf("%s<br />\n<b>%s</b>: %s in <b>%s</b> on line <b>%d</b><br />\n%s", STR_PRINT(prepend_string), error_type_str, buffer, error_filename, error_lineno, STR_PRINT(append_string));
+ }
+ } else {
+ /* Write CLI/CGI errors to stderr if display_errors = "stderr" */
+ if ((!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "cgi")) &&
+ PG(display_errors) == PHP_DISPLAY_ERRORS_STDERR
+ ) {
+#ifdef PHP_WIN32
+ fprintf(stderr, "%s: %s in %s on line %d\n", error_type_str, buffer, error_filename, error_lineno);
+ fflush(stderr);
+#else
+ fprintf(stderr, "%s: %s in %s on line %d\n", error_type_str, buffer, error_filename, error_lineno);
+#endif
+ } else {
+ php_printf("%s\n%s: %s in %s on line %d\n%s", STR_PRINT(prepend_string), error_type_str, buffer, error_filename, error_lineno, STR_PRINT(append_string));
+ }
+ }
+ }
+ }
+#if ZEND_DEBUG
+ if (PG(report_zend_debug)) {
+ zend_bool trigger_break;
+
+ switch (type) {
+ case E_ERROR:
+ case E_CORE_ERROR:
+ case E_COMPILE_ERROR:
+ case E_USER_ERROR:
+ trigger_break=1;
+ break;
+ default:
+ trigger_break=0;
+ break;
+ }
+ zend_output_debug_string(trigger_break, "%s(%d) : %s - %s", error_filename, error_lineno, error_type_str, buffer);
+ }
+#endif
+ }
+
+ /* Bail out if we can't recover */
+ switch (type) {
+ case E_CORE_ERROR:
+ if(!module_initialized) {
+ /* bad error in module startup - no way we can live with this */
+ exit(-2);
+ }
+ /* no break - intentionally */
+ case E_ERROR:
+ case E_RECOVERABLE_ERROR:
+ case E_PARSE:
+ case E_COMPILE_ERROR:
+ case E_USER_ERROR:
+ { /* new block to allow variable definition */
+ /* eval() errors do not affect exit_status or response code */
+ zend_bool during_eval = (type == E_PARSE) && (EG(current_execute_data) &&
+ EG(current_execute_data)->opline &&
+ EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
+ EG(current_execute_data)->opline->extended_value == ZEND_EVAL);
+ if (!during_eval) {
+ EG(exit_status) = 255;
+ }
+ if (module_initialized) {
+ if (!PG(display_errors) &&
+ !SG(headers_sent) &&
+ SG(sapi_headers).http_response_code == 200 &&
+ !during_eval
+ ) {
+ sapi_header_line ctr = {0};
+
+ ctr.line = "HTTP/1.0 500 Internal Server Error";
+ ctr.line_len = sizeof("HTTP/1.0 500 Internal Server Error") - 1;
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+ }
+ /* the parser would return 1 (failure), we can bail out nicely */
+ if (type == E_PARSE) {
+ CG(parse_error) = 0;
+ } else {
+ /* restore memory limit */
+ zend_set_memory_limit(PG(memory_limit));
+ efree(buffer);
+ zend_objects_store_mark_destructed(&EG(objects_store) TSRMLS_CC);
+ zend_bailout();
+ return;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Log if necessary */
+ if (!display) {
+ efree(buffer);
+ return;
+ }
+
+ if (PG(track_errors) && module_initialized) {
+ if (!EG(active_symbol_table)) {
+ zend_rebuild_symbol_table(TSRMLS_C);
+ }
+ if (EG(active_symbol_table)) {
+ zval *tmp;
+ ALLOC_INIT_ZVAL(tmp);
+ ZVAL_STRINGL(tmp, buffer, buffer_len, 1);
+ zend_hash_update(EG(active_symbol_table), "php_errormsg", sizeof("php_errormsg"), (void **) & tmp, sizeof(zval *), NULL);
+ }
+ }
+
+ efree(buffer);
+}
+/* }}} */
+
+/* {{{ php_get_current_user
+ */
+PHPAPI char *php_get_current_user(TSRMLS_D)
+{
+ struct stat *pstat;
+
+ if (SG(request_info).current_user) {
+ return SG(request_info).current_user;
+ }
+
+ /* FIXME: I need to have this somehow handled if
+ USE_SAPI is defined, because cgi will also be
+ interfaced in USE_SAPI */
+
+ pstat = sapi_get_stat(TSRMLS_C);
+
+ if (!pstat) {
+ return "";
+ } else {
+#ifdef PHP_WIN32
+ char name[256];
+ DWORD len = sizeof(name)-1;
+
+ if (!GetUserName(name, &len)) {
+ return "";
+ }
+ name[len] = '\0';
+ SG(request_info).current_user_length = len;
+ SG(request_info).current_user = estrndup(name, len);
+ return SG(request_info).current_user;
+#else
+ struct passwd *pwd;
+#if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
+ struct passwd _pw;
+ struct passwd *retpwptr = NULL;
+ int pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+ char *pwbuf;
+
+ if (pwbuflen < 1) {
+ return "";
+ }
+ pwbuf = emalloc(pwbuflen);
+ if (getpwuid_r(pstat->st_uid, &_pw, pwbuf, pwbuflen, &retpwptr) != 0) {
+ efree(pwbuf);
+ return "";
+ }
+ pwd = &_pw;
+#else
+ if ((pwd=getpwuid(pstat->st_uid))==NULL) {
+ return "";
+ }
+#endif
+ SG(request_info).current_user_length = strlen(pwd->pw_name);
+ SG(request_info).current_user = estrndup(pwd->pw_name, SG(request_info).current_user_length);
+#if defined(ZTS) && defined(HAVE_GETPWUID_R) && defined(_SC_GETPW_R_SIZE_MAX)
+ efree(pwbuf);
+#endif
+ return SG(request_info).current_user;
+#endif
+ }
+}
+/* }}} */
+
+/* {{{ proto bool set_time_limit(int seconds)
+ Sets the maximum time a script can run */
+PHP_FUNCTION(set_time_limit)
+{
+ long new_timeout;
+ char *new_timeout_str;
+ int new_timeout_strlen;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &new_timeout) == FAILURE) {
+ return;
+ }
+
+ new_timeout_strlen = zend_spprintf(&new_timeout_str, 0, "%ld", new_timeout);
+
+ if (zend_alter_ini_entry_ex("max_execution_time", sizeof("max_execution_time"), new_timeout_str, new_timeout_strlen, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC) == SUCCESS) {
+ RETVAL_TRUE;
+ } else {
+ RETVAL_FALSE;
+ }
+ efree(new_timeout_str);
+}
+/* }}} */
+
+/* {{{ php_fopen_wrapper_for_zend
+ */
+static FILE *php_fopen_wrapper_for_zend(const char *filename, char **opened_path TSRMLS_DC)
+{
+ return php_stream_open_wrapper_as_file((char *)filename, "rb", USE_PATH|IGNORE_URL_WIN|REPORT_ERRORS|STREAM_OPEN_FOR_INCLUDE, opened_path);
+}
+/* }}} */
+
+static void php_zend_stream_closer(void *handle TSRMLS_DC) /* {{{ */
+{
+ php_stream_close((php_stream*)handle);
+}
+/* }}} */
+
+static void php_zend_stream_mmap_closer(void *handle TSRMLS_DC) /* {{{ */
+{
+ php_stream_mmap_unmap((php_stream*)handle);
+ php_zend_stream_closer(handle TSRMLS_CC);
+}
+/* }}} */
+
+static size_t php_zend_stream_fsizer(void *handle TSRMLS_DC) /* {{{ */
+{
+ php_stream_statbuf ssb;
+ if (php_stream_stat((php_stream*)handle, &ssb) == 0) {
+ return ssb.sb.st_size;
+ }
+ return 0;
+}
+/* }}} */
+
+static int php_stream_open_for_zend(const char *filename, zend_file_handle *handle TSRMLS_DC) /* {{{ */
+{
+ return php_stream_open_for_zend_ex(filename, handle, USE_PATH|REPORT_ERRORS|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
+}
+/* }}} */
+
+PHPAPI int php_stream_open_for_zend_ex(const char *filename, zend_file_handle *handle, int mode TSRMLS_DC) /* {{{ */
+{
+ char *p;
+ size_t len, mapped_len;
+ php_stream *stream = php_stream_open_wrapper((char *)filename, "rb", mode, &handle->opened_path);
+
+ if (stream) {
+#if HAVE_MMAP || defined(PHP_WIN32)
+ size_t page_size = REAL_PAGE_SIZE;
+#endif
+
+ handle->filename = (char*)filename;
+ handle->free_filename = 0;
+ handle->handle.stream.handle = stream;
+ handle->handle.stream.reader = (zend_stream_reader_t)_php_stream_read;
+ handle->handle.stream.fsizer = php_zend_stream_fsizer;
+ handle->handle.stream.isatty = 0;
+ /* can we mmap immeadiately? */
+ memset(&handle->handle.stream.mmap, 0, sizeof(handle->handle.stream.mmap));
+ len = php_zend_stream_fsizer(stream TSRMLS_CC);
+ if (len != 0
+#if HAVE_MMAP || defined(PHP_WIN32)
+ && ((len - 1) % page_size) <= page_size - ZEND_MMAP_AHEAD
+#endif
+ && php_stream_mmap_possible(stream)
+ && (p = php_stream_mmap_range(stream, 0, len, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped_len)) != NULL) {
+ handle->handle.stream.closer = php_zend_stream_mmap_closer;
+ handle->handle.stream.mmap.buf = p;
+ handle->handle.stream.mmap.len = mapped_len;
+ handle->type = ZEND_HANDLE_MAPPED;
+ } else {
+ handle->handle.stream.closer = php_zend_stream_closer;
+ handle->type = ZEND_HANDLE_STREAM;
+ }
+ /* suppress warning if this stream is not explicitly closed */
+ php_stream_auto_cleanup(stream);
+
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+/* }}} */
+
+static char *php_resolve_path_for_zend(const char *filename, int filename_len TSRMLS_DC) /* {{{ */
+{
+ return php_resolve_path(filename, filename_len, PG(include_path) TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ php_get_configuration_directive_for_zend
+ */
+static int php_get_configuration_directive_for_zend(const char *name, uint name_length, zval *contents)
+{
+ zval *retval = cfg_get_entry(name, name_length);
+
+ if (retval) {
+ *contents = *retval;
+ return SUCCESS;
+ } else {
+ return FAILURE;
+ }
+}
+/* }}} */
+
+/* {{{ php_message_handler_for_zend
+ */
+static void php_message_handler_for_zend(long message, const void *data TSRMLS_DC)
+{
+ switch (message) {
+ case ZMSG_FAILED_INCLUDE_FOPEN:
+ php_error_docref("function.include" TSRMLS_CC, E_WARNING, "Failed opening '%s' for inclusion (include_path='%s')", php_strip_url_passwd((char *) data), STR_PRINT(PG(include_path)));
+ break;
+ case ZMSG_FAILED_REQUIRE_FOPEN:
+ php_error_docref("function.require" TSRMLS_CC, E_COMPILE_ERROR, "Failed opening required '%s' (include_path='%s')", php_strip_url_passwd((char *) data), STR_PRINT(PG(include_path)));
+ break;
+ case ZMSG_FAILED_HIGHLIGHT_FOPEN:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed opening '%s' for highlighting", php_strip_url_passwd((char *) data));
+ break;
+ case ZMSG_MEMORY_LEAK_DETECTED:
+ case ZMSG_MEMORY_LEAK_REPEATED:
+#if ZEND_DEBUG
+ if (EG(error_reporting) & E_WARNING) {
+ char memory_leak_buf[1024];
+
+ if (message==ZMSG_MEMORY_LEAK_DETECTED) {
+ zend_leak_info *t = (zend_leak_info *) data;
+
+ snprintf(memory_leak_buf, 512, "%s(%d) : Freeing 0x%.8lX (%zu bytes), script=%s\n", t->filename, t->lineno, (zend_uintptr_t)t->addr, t->size, SAFE_FILENAME(SG(request_info).path_translated));
+ if (t->orig_filename) {
+ char relay_buf[512];
+
+ snprintf(relay_buf, 512, "%s(%d) : Actual location (location was relayed)\n", t->orig_filename, t->orig_lineno);
+ strlcat(memory_leak_buf, relay_buf, sizeof(memory_leak_buf));
+ }
+ } else {
+ unsigned long leak_count = (zend_uintptr_t) data;
+
+ snprintf(memory_leak_buf, 512, "Last leak repeated %ld time%s\n", leak_count, (leak_count>1?"s":""));
+ }
+# if defined(PHP_WIN32)
+ OutputDebugString(memory_leak_buf);
+# else
+ fprintf(stderr, "%s", memory_leak_buf);
+# endif
+ }
+#endif
+ break;
+ case ZMSG_MEMORY_LEAKS_GRAND_TOTAL:
+#if ZEND_DEBUG
+ if (EG(error_reporting) & E_WARNING) {
+ char memory_leak_buf[512];
+
+ snprintf(memory_leak_buf, 512, "=== Total %d memory leaks detected ===\n", *((zend_uint *) data));
+# if defined(PHP_WIN32)
+ OutputDebugString(memory_leak_buf);
+# else
+ fprintf(stderr, "%s", memory_leak_buf);
+# endif
+ }
+#endif
+ break;
+ case ZMSG_LOG_SCRIPT_NAME: {
+ struct tm *ta, tmbuf;
+ time_t curtime;
+ char *datetime_str, asctimebuf[52];
+ char memory_leak_buf[4096];
+
+ time(&curtime);
+ ta = php_localtime_r(&curtime, &tmbuf);
+ datetime_str = php_asctime_r(ta, asctimebuf);
+ if (datetime_str) {
+ datetime_str[strlen(datetime_str)-1]=0; /* get rid of the trailing newline */
+ snprintf(memory_leak_buf, sizeof(memory_leak_buf), "[%s] Script: '%s'\n", datetime_str, SAFE_FILENAME(SG(request_info).path_translated));
+ } else {
+ snprintf(memory_leak_buf, sizeof(memory_leak_buf), "[null] Script: '%s'\n", SAFE_FILENAME(SG(request_info).path_translated));
+ }
+# if defined(PHP_WIN32)
+ OutputDebugString(memory_leak_buf);
+# else
+ fprintf(stderr, "%s", memory_leak_buf);
+# endif
+ }
+ break;
+ }
+}
+/* }}} */
+
+
+void php_on_timeout(int seconds TSRMLS_DC)
+{
+ PG(connection_status) |= PHP_CONNECTION_TIMEOUT;
+ zend_set_timeout(EG(timeout_seconds), 1);
+ if(PG(exit_on_timeout)) sapi_terminate_process(TSRMLS_C);
+}
+
+#if PHP_SIGCHILD
+/* {{{ sigchld_handler
+ */
+static void sigchld_handler(int apar)
+{
+ int errno_save = errno;
+
+ while (waitpid(-1, NULL, WNOHANG) > 0);
+ signal(SIGCHLD, sigchld_handler);
+
+ errno = errno_save;
+}
+/* }}} */
+#endif
+
+/* {{{ php_start_sapi()
+ */
+static int php_start_sapi(TSRMLS_D)
+{
+ int retval = SUCCESS;
+
+ if(!SG(sapi_started)) {
+ zend_try {
+ PG(during_request_startup) = 1;
+
+ /* initialize global variables */
+ PG(modules_activated) = 0;
+ PG(header_is_being_sent) = 0;
+ PG(connection_status) = PHP_CONNECTION_NORMAL;
+
+ zend_activate(TSRMLS_C);
+ zend_set_timeout(EG(timeout_seconds), 1);
+ zend_activate_modules(TSRMLS_C);
+ PG(modules_activated)=1;
+ } zend_catch {
+ retval = FAILURE;
+ } zend_end_try();
+
+ SG(sapi_started) = 1;
+ }
+ return retval;
+}
+
+/* }}} */
+
+/* {{{ php_request_startup
+ */
+#ifndef APACHE_HOOKS
+int php_request_startup(TSRMLS_D)
+{
+ int retval = SUCCESS;
+
+#ifdef HAVE_DTRACE
+ DTRACE_REQUEST_STARTUP(SAFE_FILENAME(SG(request_info).path_translated), SAFE_FILENAME(SG(request_info).request_uri), SAFE_FILENAME(SG(request_info).request_method));
+#endif /* HAVE_DTRACE */
+
+#ifdef PHP_WIN32
+ PG(com_initialized) = 0;
+#endif
+
+#if PHP_SIGCHILD
+ signal(SIGCHLD, sigchld_handler);
+#endif
+
+ zend_try {
+ PG(in_error_log) = 0;
+ PG(during_request_startup) = 1;
+
+ php_output_activate(TSRMLS_C);
+
+ /* initialize global variables */
+ PG(modules_activated) = 0;
+ PG(header_is_being_sent) = 0;
+ PG(connection_status) = PHP_CONNECTION_NORMAL;
+ PG(in_user_include) = 0;
+
+ zend_activate(TSRMLS_C);
+ sapi_activate(TSRMLS_C);
+
+#ifdef ZEND_SIGNALS
+ zend_signal_activate(TSRMLS_C);
+#endif
+
+ if (PG(max_input_time) == -1) {
+ zend_set_timeout(EG(timeout_seconds), 1);
+ } else {
+ zend_set_timeout(PG(max_input_time), 1);
+ }
+
+ /* Disable realpath cache if an open_basedir is set */
+ if (PG(open_basedir) && *PG(open_basedir)) {
+ CWDG(realpath_cache_size_limit) = 0;
+ }
+
+ if (PG(expose_php)) {
+ sapi_add_header(SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1, 1);
+ }
+
+ if (PG(output_handler) && PG(output_handler)[0]) {
+ zval *oh;
+
+ MAKE_STD_ZVAL(oh);
+ ZVAL_STRING(oh, PG(output_handler), 1);
+ php_output_start_user(oh, 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC);
+ zval_ptr_dtor(&oh);
+ } else if (PG(output_buffering)) {
+ php_output_start_user(NULL, PG(output_buffering) > 1 ? PG(output_buffering) : 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC);
+ } else if (PG(implicit_flush)) {
+ php_output_set_implicit_flush(1 TSRMLS_CC);
+ }
+
+ /* We turn this off in php_execute_script() */
+ /* PG(during_request_startup) = 0; */
+
+ php_hash_environment(TSRMLS_C);
+ zend_activate_modules(TSRMLS_C);
+ PG(modules_activated)=1;
+ } zend_catch {
+ retval = FAILURE;
+ } zend_end_try();
+
+ SG(sapi_started) = 1;
+
+ return retval;
+}
+# else
+int php_request_startup(TSRMLS_D)
+{
+ int retval = SUCCESS;
+
+#if PHP_SIGCHILD
+ signal(SIGCHLD, sigchld_handler);
+#endif
+
+ if (php_start_sapi() == FAILURE) {
+ return FAILURE;
+ }
+
+ php_output_activate(TSRMLS_C);
+ sapi_activate(TSRMLS_C);
+ php_hash_environment(TSRMLS_C);
+
+ zend_try {
+ PG(during_request_startup) = 1;
+ if (PG(expose_php)) {
+ sapi_add_header(SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1, 1);
+ }
+ } zend_catch {
+ retval = FAILURE;
+ } zend_end_try();
+
+ return retval;
+}
+# endif
+/* }}} */
+
+/* {{{ php_request_startup_for_hook
+ */
+int php_request_startup_for_hook(TSRMLS_D)
+{
+ int retval = SUCCESS;
+
+#if PHP_SIGCHLD
+ signal(SIGCHLD, sigchld_handler);
+#endif
+
+ if (php_start_sapi(TSRMLS_C) == FAILURE) {
+ return FAILURE;
+ }
+
+ php_output_activate(TSRMLS_C);
+ sapi_activate_headers_only(TSRMLS_C);
+ php_hash_environment(TSRMLS_C);
+
+ return retval;
+}
+/* }}} */
+
+/* {{{ php_request_shutdown_for_exec
+ */
+void php_request_shutdown_for_exec(void *dummy)
+{
+ TSRMLS_FETCH();
+
+ /* used to close fd's in the 3..255 range here, but it's problematic
+ */
+ shutdown_memory_manager(1, 1 TSRMLS_CC);
+ zend_interned_strings_restore(TSRMLS_C);
+}
+/* }}} */
+
+/* {{{ php_request_shutdown_for_hook
+ */
+void php_request_shutdown_for_hook(void *dummy)
+{
+ TSRMLS_FETCH();
+
+ if (PG(modules_activated)) zend_try {
+ php_call_shutdown_functions(TSRMLS_C);
+ } zend_end_try();
+
+ if (PG(modules_activated)) {
+ zend_deactivate_modules(TSRMLS_C);
+ php_free_shutdown_functions(TSRMLS_C);
+ }
+
+ zend_try {
+ zend_unset_timeout(TSRMLS_C);
+ } zend_end_try();
+
+ zend_try {
+ int i;
+
+ for (i = 0; i < NUM_TRACK_VARS; i++) {
+ if (PG(http_globals)[i]) {
+ zval_ptr_dtor(&PG(http_globals)[i]);
+ }
+ }
+ } zend_end_try();
+
+ zend_deactivate(TSRMLS_C);
+
+ zend_try {
+ sapi_deactivate(TSRMLS_C);
+ } zend_end_try();
+
+ zend_try {
+ php_shutdown_stream_hashes(TSRMLS_C);
+ } zend_end_try();
+
+ zend_try {
+ shutdown_memory_manager(CG(unclean_shutdown), 0 TSRMLS_CC);
+ } zend_end_try();
+
+ zend_interned_strings_restore(TSRMLS_C);
+
+#ifdef ZEND_SIGNALS
+ zend_try {
+ zend_signal_deactivate(TSRMLS_C);
+ } zend_end_try();
+#endif
+}
+
+/* }}} */
+
+/* {{{ php_request_shutdown
+ */
+void php_request_shutdown(void *dummy)
+{
+ zend_bool report_memleaks;
+ TSRMLS_FETCH();
+
+ report_memleaks = PG(report_memleaks);
+
+ /* EG(opline_ptr) points into nirvana and therefore cannot be safely accessed
+ * inside zend_executor callback functions.
+ */
+ EG(opline_ptr) = NULL;
+ EG(active_op_array) = NULL;
+
+ php_deactivate_ticks(TSRMLS_C);
+
+ /* 1. Call all possible shutdown functions registered with register_shutdown_function() */
+ if (PG(modules_activated)) zend_try {
+ php_call_shutdown_functions(TSRMLS_C);
+ } zend_end_try();
+
+ /* 2. Call all possible __destruct() functions */
+ zend_try {
+ zend_call_destructors(TSRMLS_C);
+ } zend_end_try();
+
+ /* 3. Flush all output buffers */
+ zend_try {
+ zend_bool send_buffer = SG(request_info).headers_only ? 0 : 1;
+
+ if (CG(unclean_shutdown) && PG(last_error_type) == E_ERROR &&
+ (size_t)PG(memory_limit) < zend_memory_usage(1 TSRMLS_CC)
+ ) {
+ send_buffer = 0;
+ }
+
+ if (!send_buffer) {
+ php_output_discard_all(TSRMLS_C);
+ } else {
+ php_output_end_all(TSRMLS_C);
+ }
+ } zend_end_try();
+
+ /* 4. Reset max_execution_time (no longer executing php code after response sent) */
+ zend_try {
+ zend_unset_timeout(TSRMLS_C);
+ } zend_end_try();
+
+ /* 5. Call all extensions RSHUTDOWN functions */
+ if (PG(modules_activated)) {
+ zend_deactivate_modules(TSRMLS_C);
+ php_free_shutdown_functions(TSRMLS_C);
+ }
+
+ /* 6. Shutdown output layer (send the set HTTP headers, cleanup output handlers, etc.) */
+ zend_try {
+ php_output_deactivate(TSRMLS_C);
+ } zend_end_try();
+
+ /* 7. Destroy super-globals */
+ zend_try {
+ int i;
+
+ for (i=0; i<NUM_TRACK_VARS; i++) {
+ if (PG(http_globals)[i]) {
+ zval_ptr_dtor(&PG(http_globals)[i]);
+ }
+ }
+ } zend_end_try();
+
+ /* 7.5 free last error information */
+ if (PG(last_error_message)) {
+ free(PG(last_error_message));
+ PG(last_error_message) = NULL;
+ }
+ if (PG(last_error_file)) {
+ free(PG(last_error_file));
+ PG(last_error_file) = NULL;
+ }
+
+ /* 7. Shutdown scanner/executor/compiler and restore ini entries */
+ zend_deactivate(TSRMLS_C);
+
+ /* 8. Call all extensions post-RSHUTDOWN functions */
+ zend_try {
+ zend_post_deactivate_modules(TSRMLS_C);
+ } zend_end_try();
+
+ /* 9. SAPI related shutdown (free stuff) */
+ zend_try {
+ sapi_deactivate(TSRMLS_C);
+ } zend_end_try();
+
+ /* 10. Destroy stream hashes */
+ zend_try {
+ php_shutdown_stream_hashes(TSRMLS_C);
+ } zend_end_try();
+
+ /* 11. Free Willy (here be crashes) */
+ zend_try {
+ shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0 TSRMLS_CC);
+ } zend_end_try();
+ zend_interned_strings_restore(TSRMLS_C);
+
+ /* 12. Reset max_execution_time */
+ zend_try {
+ zend_unset_timeout(TSRMLS_C);
+ } zend_end_try();
+
+#ifdef PHP_WIN32
+ if (PG(com_initialized)) {
+ CoUninitialize();
+ PG(com_initialized) = 0;
+ }
+#endif
+
+#ifdef HAVE_DTRACE
+ DTRACE_REQUEST_SHUTDOWN(SAFE_FILENAME(SG(request_info).path_translated), SAFE_FILENAME(SG(request_info).request_uri), SAFE_FILENAME(SG(request_info).request_method));
+#endif /* HAVE_DTRACE */
+}
+/* }}} */
+
+/* {{{ php_com_initialize
+ */
+PHPAPI void php_com_initialize(TSRMLS_D)
+{
+#ifdef PHP_WIN32
+ if (!PG(com_initialized)) {
+ if (CoInitialize(NULL) == S_OK) {
+ PG(com_initialized) = 1;
+ }
+ }
+#endif
+}
+/* }}} */
+
+/* {{{ php_output_wrapper
+ */
+static int php_output_wrapper(const char *str, uint str_length)
+{
+ TSRMLS_FETCH();
+ return php_output_write(str, str_length TSRMLS_CC);
+}
+/* }}} */
+
+#ifdef ZTS
+/* {{{ core_globals_ctor
+ */
+static void core_globals_ctor(php_core_globals *core_globals TSRMLS_DC)
+{
+ memset(core_globals, 0, sizeof(*core_globals));
+
+ php_startup_ticks(TSRMLS_C);
+}
+/* }}} */
+#endif
+
+/* {{{ core_globals_dtor
+ */
+static void core_globals_dtor(php_core_globals *core_globals TSRMLS_DC)
+{
+ if (core_globals->last_error_message) {
+ free(core_globals->last_error_message);
+ }
+ if (core_globals->last_error_file) {
+ free(core_globals->last_error_file);
+ }
+ if (core_globals->disable_functions) {
+ free(core_globals->disable_functions);
+ }
+ if (core_globals->disable_classes) {
+ free(core_globals->disable_classes);
+ }
+ if (core_globals->php_binary) {
+ free(core_globals->php_binary);
+ }
+
+ php_shutdown_ticks(TSRMLS_C);
+}
+/* }}} */
+
+PHP_MINFO_FUNCTION(php_core) { /* {{{ */
+ php_info_print_table_start();
+ php_info_print_table_row(2, "PHP Version", PHP_VERSION);
+ php_info_print_table_end();
+ DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+
+/* {{{ php_register_extensions
+ */
+int php_register_extensions(zend_module_entry **ptr, int count TSRMLS_DC)
+{
+ zend_module_entry **end = ptr + count;
+
+ while (ptr < end) {
+ if (*ptr) {
+ if (zend_register_internal_module(*ptr TSRMLS_CC)==NULL) {
+ return FAILURE;
+ }
+ }
+ ptr++;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+#if defined(PHP_WIN32) && _MSC_VER >= 1400
+static _invalid_parameter_handler old_invalid_parameter_handler;
+
+void dummy_invalid_parameter_handler(
+ const wchar_t *expression,
+ const wchar_t *function,
+ const wchar_t *file,
+ unsigned int line,
+ uintptr_t pEwserved)
+{
+ static int called = 0;
+ char buf[1024];
+ int len;
+
+ if (!called) {
+ TSRMLS_FETCH();
+ if(PG(windows_show_crt_warning)) {
+ called = 1;
+ if (function) {
+ if (file) {
+ len = _snprintf(buf, sizeof(buf)-1, "Invalid parameter detected in CRT function '%ws' (%ws:%d)", function, file, line);
+ } else {
+ len = _snprintf(buf, sizeof(buf)-1, "Invalid parameter detected in CRT function '%ws'", function);
+ }
+ } else {
+ len = _snprintf(buf, sizeof(buf)-1, "Invalid CRT parameter detected (function not known)");
+ }
+ zend_error(E_WARNING, "%s", buf);
+ called = 0;
+ }
+ }
+}
+#endif
+
+/* {{{ php_module_startup
+ */
+int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules)
+{
+ zend_utility_functions zuf;
+ zend_utility_values zuv;
+ int retval = SUCCESS, module_number=0; /* for REGISTER_INI_ENTRIES() */
+ char *php_os;
+ zend_module_entry *module;
+#ifdef ZTS
+ zend_executor_globals *executor_globals;
+ void ***tsrm_ls;
+ php_core_globals *core_globals;
+#endif
+
+#if defined(PHP_WIN32) || (defined(NETWARE) && defined(USE_WINSOCK))
+ WORD wVersionRequested = MAKEWORD(2, 0);
+ WSADATA wsaData;
+#endif
+#ifdef PHP_WIN32
+ php_os = "WINNT";
+#if _MSC_VER >= 1400
+ old_invalid_parameter_handler =
+ _set_invalid_parameter_handler(dummy_invalid_parameter_handler);
+ if (old_invalid_parameter_handler != NULL) {
+ _set_invalid_parameter_handler(old_invalid_parameter_handler);
+ }
+
+ /* Disable the message box for assertions.*/
+ _CrtSetReportMode(_CRT_ASSERT, 0);
+#endif
+#else
+ php_os=PHP_OS;
+#endif
+
+#ifdef ZTS
+ tsrm_ls = ts_resource(0);
+#endif
+
+#ifdef PHP_WIN32
+ php_win32_init_rng_lock();
+#endif
+
+ module_shutdown = 0;
+ module_startup = 1;
+ sapi_initialize_empty_request(TSRMLS_C);
+ sapi_activate(TSRMLS_C);
+
+ if (module_initialized) {
+ return SUCCESS;
+ }
+
+ sapi_module = *sf;
+
+ php_output_startup();
+
+ zuf.error_function = php_error_cb;
+ zuf.printf_function = php_printf;
+ zuf.write_function = php_output_wrapper;
+ zuf.fopen_function = php_fopen_wrapper_for_zend;
+ zuf.message_handler = php_message_handler_for_zend;
+ zuf.block_interruptions = sapi_module.block_interruptions;
+ zuf.unblock_interruptions = sapi_module.unblock_interruptions;
+ zuf.get_configuration_directive = php_get_configuration_directive_for_zend;
+ zuf.ticks_function = php_run_ticks;
+ zuf.on_timeout = php_on_timeout;
+ zuf.stream_open_function = php_stream_open_for_zend;
+ zuf.vspprintf_function = vspprintf;
+ zuf.getenv_function = sapi_getenv;
+ zuf.resolve_path_function = php_resolve_path_for_zend;
+ zend_startup(&zuf, NULL TSRMLS_CC);
+
+#ifdef ZTS
+ executor_globals = ts_resource(executor_globals_id);
+ ts_allocate_id(&core_globals_id, sizeof(php_core_globals), (ts_allocate_ctor) core_globals_ctor, (ts_allocate_dtor) core_globals_dtor);
+ core_globals = ts_resource(core_globals_id);
+#ifdef PHP_WIN32
+ ts_allocate_id(&php_win32_core_globals_id, sizeof(php_win32_core_globals), (ts_allocate_ctor) php_win32_core_globals_ctor, (ts_allocate_dtor) php_win32_core_globals_dtor);
+#endif
+#else
+ php_startup_ticks(TSRMLS_C);
+#endif
+ gc_globals_ctor(TSRMLS_C);
+
+#ifdef PHP_WIN32
+ {
+ OSVERSIONINFOEX *osvi = &EG(windows_version_info);
+
+ ZeroMemory(osvi, sizeof(OSVERSIONINFOEX));
+ osvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ if( !GetVersionEx((OSVERSIONINFO *) osvi)) {
+ php_printf("\nGetVersionEx unusable. %d\n", GetLastError());
+ return FAILURE;
+ }
+ }
+#endif
+ EG(bailout) = NULL;
+ EG(error_reporting) = E_ALL & ~E_NOTICE;
+ EG(active_symbol_table) = NULL;
+ PG(header_is_being_sent) = 0;
+ SG(request_info).headers_only = 0;
+ SG(request_info).argv0 = NULL;
+ SG(request_info).argc=0;
+ SG(request_info).argv=(char **)NULL;
+ PG(connection_status) = PHP_CONNECTION_NORMAL;
+ PG(during_request_startup) = 0;
+ PG(last_error_message) = NULL;
+ PG(last_error_file) = NULL;
+ PG(last_error_lineno) = 0;
+ EG(error_handling) = EH_NORMAL;
+ EG(exception_class) = NULL;
+ PG(disable_functions) = NULL;
+ PG(disable_classes) = NULL;
+
+#if HAVE_SETLOCALE
+ setlocale(LC_CTYPE, "");
+ zend_update_current_locale();
+#endif
+
+#if HAVE_TZSET
+ tzset();
+#endif
+
+#if defined(PHP_WIN32) || (defined(NETWARE) && defined(USE_WINSOCK))
+ /* start up winsock services */
+ if (WSAStartup(wVersionRequested, &wsaData) != 0) {
+ php_printf("\nwinsock.dll unusable. %d\n", WSAGetLastError());
+ return FAILURE;
+ }
+#endif
+
+ le_index_ptr = zend_register_list_destructors_ex(NULL, NULL, "index pointer", 0);
+
+ /* Register constants */
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_VERSION", PHP_VERSION, sizeof(PHP_VERSION)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_MAJOR_VERSION", PHP_MAJOR_VERSION, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_MINOR_VERSION", PHP_MINOR_VERSION, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_RELEASE_VERSION", PHP_RELEASE_VERSION, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_EXTRA_VERSION", PHP_EXTRA_VERSION, sizeof(PHP_EXTRA_VERSION) - 1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_VERSION_ID", PHP_VERSION_ID, CONST_PERSISTENT | CONST_CS);
+#ifdef ZTS
+ REGISTER_MAIN_LONG_CONSTANT("PHP_ZTS", 1, CONST_PERSISTENT | CONST_CS);
+#else
+ REGISTER_MAIN_LONG_CONSTANT("PHP_ZTS", 0, CONST_PERSISTENT | CONST_CS);
+#endif
+ REGISTER_MAIN_LONG_CONSTANT("PHP_DEBUG", PHP_DEBUG, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_OS", php_os, strlen(php_os), CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_SAPI", sapi_module.name, strlen(sapi_module.name), CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("DEFAULT_INCLUDE_PATH", PHP_INCLUDE_PATH, sizeof(PHP_INCLUDE_PATH)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PEAR_INSTALL_DIR", PEAR_INSTALLDIR, sizeof(PEAR_INSTALLDIR)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PEAR_EXTENSION_DIR", PHP_EXTENSION_DIR, sizeof(PHP_EXTENSION_DIR)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_EXTENSION_DIR", PHP_EXTENSION_DIR, sizeof(PHP_EXTENSION_DIR)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_PREFIX", PHP_PREFIX, sizeof(PHP_PREFIX)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_BINDIR", PHP_BINDIR, sizeof(PHP_BINDIR)-1, CONST_PERSISTENT | CONST_CS);
+#ifndef PHP_WIN32
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_MANDIR", PHP_MANDIR, sizeof(PHP_MANDIR)-1, CONST_PERSISTENT | CONST_CS);
+#endif
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_LIBDIR", PHP_LIBDIR, sizeof(PHP_LIBDIR)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_DATADIR", PHP_DATADIR, sizeof(PHP_DATADIR)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_SYSCONFDIR", PHP_SYSCONFDIR, sizeof(PHP_SYSCONFDIR)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_LOCALSTATEDIR", PHP_LOCALSTATEDIR, sizeof(PHP_LOCALSTATEDIR)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, strlen(PHP_CONFIG_FILE_PATH), CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_MAXPATHLEN", MAXPATHLEN, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_INT_MAX", LONG_MAX, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS);
+
+#ifdef PHP_WIN32
+ REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_MAJOR", EG(windows_version_info).dwMajorVersion, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_MINOR", EG(windows_version_info).dwMinorVersion, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_BUILD", EG(windows_version_info).dwBuildNumber, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_PLATFORM", EG(windows_version_info).dwPlatformId, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_SP_MAJOR", EG(windows_version_info).wServicePackMajor, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_SP_MINOR", EG(windows_version_info).wServicePackMinor, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_SUITEMASK", EG(windows_version_info).wSuiteMask, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_PRODUCTTYPE", EG(windows_version_info).wProductType, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_NT_DOMAIN_CONTROLLER", VER_NT_DOMAIN_CONTROLLER, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_NT_SERVER", VER_NT_SERVER, CONST_PERSISTENT | CONST_CS);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_NT_WORKSTATION", VER_NT_WORKSTATION, CONST_PERSISTENT | CONST_CS);
+#endif
+
+ php_binary_init(TSRMLS_C);
+ if (PG(php_binary)) {
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_BINARY", PG(php_binary), strlen(PG(php_binary)), CONST_PERSISTENT | CONST_CS);
+ } else {
+ REGISTER_MAIN_STRINGL_CONSTANT("PHP_BINARY", "", 0, CONST_PERSISTENT | CONST_CS);
+ }
+
+ php_output_register_constants(TSRMLS_C);
+ php_rfc1867_register_constants(TSRMLS_C);
+
+ /* this will read in php.ini, set up the configuration parameters,
+ load zend extensions and register php function extensions
+ to be loaded later */
+ if (php_init_config(TSRMLS_C) == FAILURE) {
+ return FAILURE;
+ }
+
+ /* Register PHP core ini entries */
+ REGISTER_INI_ENTRIES();
+
+ /* Register Zend ini entries */
+ zend_register_standard_ini_entries(TSRMLS_C);
+
+ /* Disable realpath cache if an open_basedir is set */
+ if (PG(open_basedir) && *PG(open_basedir)) {
+ CWDG(realpath_cache_size_limit) = 0;
+ }
+
+ /* initialize stream wrappers registry
+ * (this uses configuration parameters from php.ini)
+ */
+ if (php_init_stream_wrappers(module_number TSRMLS_CC) == FAILURE) {
+ php_printf("PHP: Unable to initialize stream url wrappers.\n");
+ return FAILURE;
+ }
+
+ /* initialize registry for images to be used in phpinfo()
+ (this uses configuration parameters from php.ini)
+ */
+ if (php_init_info_logos() == FAILURE) {
+ php_printf("PHP: Unable to initialize info phpinfo logos.\n");
+ return FAILURE;
+ }
+
+ zuv.html_errors = 1;
+ zuv.import_use_extension = ".php";
+ php_startup_auto_globals(TSRMLS_C);
+ zend_set_utility_values(&zuv);
+ php_startup_sapi_content_types(TSRMLS_C);
+
+ /* startup extensions staticly compiled in */
+ if (php_register_internal_extensions_func(TSRMLS_C) == FAILURE) {
+ php_printf("Unable to start builtin modules\n");
+ return FAILURE;
+ }
+
+ /* start additional PHP extensions */
+ php_register_extensions(&additional_modules, num_additional_modules TSRMLS_CC);
+
+ /* load and startup extensions compiled as shared objects (aka DLLs)
+ as requested by php.ini entries
+ theese are loaded after initialization of internal extensions
+ as extensions *might* rely on things from ext/standard
+ which is always an internal extension and to be initialized
+ ahead of all other internals
+ */
+ php_ini_register_extensions(TSRMLS_C);
+ zend_startup_modules(TSRMLS_C);
+
+ /* start Zend extensions */
+ zend_startup_extensions();
+
+ zend_collect_module_handlers(TSRMLS_C);
+
+ /* register additional functions */
+ if (sapi_module.additional_functions) {
+ if (zend_hash_find(&module_registry, "standard", sizeof("standard"), (void**)&module)==SUCCESS) {
+ EG(current_module) = module;
+ zend_register_functions(NULL, sapi_module.additional_functions, NULL, MODULE_PERSISTENT TSRMLS_CC);
+ EG(current_module) = NULL;
+ }
+ }
+
+ /* disable certain classes and functions as requested by php.ini */
+ php_disable_functions(TSRMLS_C);
+ php_disable_classes(TSRMLS_C);
+
+ /* make core report what it should */
+ if (zend_hash_find(&module_registry, "core", sizeof("core"), (void**)&module)==SUCCESS) {
+ module->version = PHP_VERSION;
+ module->info_func = PHP_MINFO(php_core);
+ }
+
+
+#ifdef PHP_WIN32
+ /* Disable incompatible functions for the running platform */
+ if (php_win32_disable_functions(TSRMLS_C) == FAILURE) {
+ php_printf("Unable to disable unsupported functions\n");
+ return FAILURE;
+ }
+#endif
+
+#ifdef ZTS
+ zend_post_startup(TSRMLS_C);
+#endif
+
+ module_initialized = 1;
+
+ /* Check for deprecated directives */
+ /* NOTE: If you add anything here, remember to add it to Makefile.global! */
+ {
+ struct {
+ const long error_level;
+ const char *phrase;
+ const char *directives[16]; /* Remember to change this if the number of directives change */
+ } directives[2] = {
+ {
+ E_DEPRECATED,
+ "Directive '%s' is deprecated in PHP 5.3 and greater",
+ {
+ NULL
+ }
+ },
+ {
+ E_CORE_ERROR,
+ "Directive '%s' is no longer available in PHP",
+ {
+ "allow_call_time_pass_reference",
+ "define_syslog_variables",
+ "highlight.bg",
+ "magic_quotes_gpc",
+ "magic_quotes_runtime",
+ "magic_quotes_sybase",
+ "register_globals",
+ "register_long_arrays",
+ "safe_mode",
+ "safe_mode_gid",
+ "safe_mode_include_dir",
+ "safe_mode_exec_dir",
+ "safe_mode_allowed_env_vars",
+ "safe_mode_protected_env_vars",
+ "zend.ze1_compatibility_mode",
+ NULL
+ }
+ }
+ };
+
+ unsigned int i;
+
+ zend_try {
+ /* 2 = Count of deprecation structs */
+ for (i = 0; i < 2; i++) {
+ const char **p = directives[i].directives;
+
+ while(*p) {
+ long value;
+
+ if (cfg_get_long((char*)*p, &value) == SUCCESS && value) {
+ zend_error(directives[i].error_level, directives[i].phrase, *p);
+ }
+
+ ++p;
+ }
+ }
+ } zend_catch {
+ retval = FAILURE;
+ } zend_end_try();
+ }
+
+ sapi_deactivate(TSRMLS_C);
+ module_startup = 0;
+
+ shutdown_memory_manager(1, 0 TSRMLS_CC);
+ zend_interned_strings_snapshot(TSRMLS_C);
+
+ /* we're done */
+ return retval;
+}
+/* }}} */
+
+void php_module_shutdown_for_exec(void)
+{
+ /* used to close fd's in the range 3.255 here, but it's problematic */
+}
+
+/* {{{ php_module_shutdown_wrapper
+ */
+int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals)
+{
+ TSRMLS_FETCH();
+ php_module_shutdown(TSRMLS_C);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ php_module_shutdown
+ */
+void php_module_shutdown(TSRMLS_D)
+{
+ int module_number=0; /* for UNREGISTER_INI_ENTRIES() */
+
+ module_shutdown = 1;
+
+ if (!module_initialized) {
+ return;
+ }
+
+#ifdef ZTS
+ ts_free_worker_threads();
+#endif
+
+#if defined(PHP_WIN32) || (defined(NETWARE) && defined(USE_WINSOCK))
+ /*close winsock */
+ WSACleanup();
+#endif
+
+#ifdef PHP_WIN32
+ php_win32_free_rng_lock();
+#endif
+
+ sapi_flush(TSRMLS_C);
+
+ zend_shutdown(TSRMLS_C);
+
+ /* Destroys filter & transport registries too */
+ php_shutdown_stream_wrappers(module_number TSRMLS_CC);
+
+ php_shutdown_info_logos();
+ UNREGISTER_INI_ENTRIES();
+
+ /* close down the ini config */
+ php_shutdown_config();
+
+#ifndef ZTS
+ zend_ini_shutdown(TSRMLS_C);
+ shutdown_memory_manager(CG(unclean_shutdown), 1 TSRMLS_CC);
+#else
+ zend_ini_global_shutdown(TSRMLS_C);
+#endif
+
+ php_output_shutdown();
+ php_shutdown_temporary_directory();
+
+ module_initialized = 0;
+
+#ifndef ZTS
+ core_globals_dtor(&core_globals TSRMLS_CC);
+ gc_globals_dtor(TSRMLS_C);
+#else
+ ts_free_id(core_globals_id);
+#endif
+
+#if defined(PHP_WIN32) && defined(_MSC_VER) && (_MSC_VER >= 1400)
+ if (old_invalid_parameter_handler == NULL) {
+ _set_invalid_parameter_handler(old_invalid_parameter_handler);
+ }
+#endif
+}
+/* }}} */
+
+/* {{{ php_execute_script
+ */
+PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC)
+{
+ zend_file_handle *prepend_file_p, *append_file_p;
+ zend_file_handle prepend_file = {0}, append_file = {0};
+#if HAVE_BROKEN_GETCWD
+ int old_cwd_fd = -1;
+#else
+ char *old_cwd;
+ ALLOCA_FLAG(use_heap)
+#endif
+ int retval = 0;
+
+ EG(exit_status) = 0;
+ if (php_handle_special_queries(TSRMLS_C)) {
+ zend_file_handle_dtor(primary_file TSRMLS_CC);
+ return 0;
+ }
+#ifndef HAVE_BROKEN_GETCWD
+# define OLD_CWD_SIZE 4096
+ old_cwd = do_alloca(OLD_CWD_SIZE, use_heap);
+ old_cwd[0] = '\0';
+#endif
+
+ zend_try {
+ char realfile[MAXPATHLEN];
+
+#ifdef PHP_WIN32
+ if(primary_file->filename) {
+ UpdateIniFromRegistry(primary_file->filename TSRMLS_CC);
+ }
+#endif
+
+ PG(during_request_startup) = 0;
+
+ if (primary_file->filename && !(SG(options) & SAPI_OPTION_NO_CHDIR)) {
+#if HAVE_BROKEN_GETCWD
+ /* this looks nasty to me */
+ old_cwd_fd = open(".", 0);
+#else
+ php_ignore_value(VCWD_GETCWD(old_cwd, OLD_CWD_SIZE-1));
+#endif
+ VCWD_CHDIR_FILE(primary_file->filename);
+ }
+
+ /* Only lookup the real file path and add it to the included_files list if already opened
+ * otherwise it will get opened and added to the included_files list in zend_execute_scripts
+ */
+ if (primary_file->filename &&
+ (primary_file->filename[0] != '-' || primary_file->filename[1] != 0) &&
+ primary_file->opened_path == NULL &&
+ primary_file->type != ZEND_HANDLE_FILENAME
+ ) {
+ int realfile_len;
+ int dummy = 1;
+
+ if (expand_filepath(primary_file->filename, realfile TSRMLS_CC)) {
+ realfile_len = strlen(realfile);
+ zend_hash_add(&EG(included_files), realfile, realfile_len+1, (void *)&dummy, sizeof(int), NULL);
+ primary_file->opened_path = estrndup(realfile, realfile_len);
+ }
+ }
+
+ if (PG(auto_prepend_file) && PG(auto_prepend_file)[0]) {
+ prepend_file.filename = PG(auto_prepend_file);
+ prepend_file.opened_path = NULL;
+ prepend_file.free_filename = 0;
+ prepend_file.type = ZEND_HANDLE_FILENAME;
+ prepend_file_p = &prepend_file;
+ } else {
+ prepend_file_p = NULL;
+ }
+
+ if (PG(auto_append_file) && PG(auto_append_file)[0]) {
+ append_file.filename = PG(auto_append_file);
+ append_file.opened_path = NULL;
+ append_file.free_filename = 0;
+ append_file.type = ZEND_HANDLE_FILENAME;
+ append_file_p = &append_file;
+ } else {
+ append_file_p = NULL;
+ }
+ if (PG(max_input_time) != -1) {
+#ifdef PHP_WIN32
+ zend_unset_timeout(TSRMLS_C);
+#endif
+ zend_set_timeout(INI_INT("max_execution_time"), 0);
+ }
+ retval = (zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 3, prepend_file_p, primary_file, append_file_p) == SUCCESS);
+
+ } zend_end_try();
+
+#if HAVE_BROKEN_GETCWD
+ if (old_cwd_fd != -1) {
+ fchdir(old_cwd_fd);
+ close(old_cwd_fd);
+ }
+#else
+ if (old_cwd[0] != '\0') {
+ php_ignore_value(VCWD_CHDIR(old_cwd));
+ }
+ free_alloca(old_cwd, use_heap);
+#endif
+ return retval;
+}
+/* }}} */
+
+/* {{{ php_execute_simple_script
+ */
+PHPAPI int php_execute_simple_script(zend_file_handle *primary_file, zval **ret TSRMLS_DC)
+{
+ char *old_cwd;
+ ALLOCA_FLAG(use_heap)
+
+ EG(exit_status) = 0;
+#define OLD_CWD_SIZE 4096
+ old_cwd = do_alloca(OLD_CWD_SIZE, use_heap);
+ old_cwd[0] = '\0';
+
+ zend_try {
+#ifdef PHP_WIN32
+ if(primary_file->filename) {
+ UpdateIniFromRegistry(primary_file->filename TSRMLS_CC);
+ }
+#endif
+
+ PG(during_request_startup) = 0;
+
+ if (primary_file->filename && !(SG(options) & SAPI_OPTION_NO_CHDIR)) {
+ php_ignore_value(VCWD_GETCWD(old_cwd, OLD_CWD_SIZE-1));
+ VCWD_CHDIR_FILE(primary_file->filename);
+ }
+ zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, ret, 1, primary_file);
+ } zend_end_try();
+
+ if (old_cwd[0] != '\0') {
+ php_ignore_value(VCWD_CHDIR(old_cwd));
+ }
+
+ free_alloca(old_cwd, use_heap);
+ return EG(exit_status);
+}
+/* }}} */
+
+/* {{{ php_handle_aborted_connection
+ */
+PHPAPI void php_handle_aborted_connection(void)
+{
+ TSRMLS_FETCH();
+
+ PG(connection_status) = PHP_CONNECTION_ABORTED;
+ php_output_set_status(PHP_OUTPUT_DISABLED TSRMLS_CC);
+
+ if (!PG(ignore_user_abort)) {
+ zend_bailout();
+ }
+}
+/* }}} */
+
+/* {{{ php_handle_auth_data
+ */
+PHPAPI int php_handle_auth_data(const char *auth TSRMLS_DC)
+{
+ int ret = -1;
+
+ if (auth && auth[0] != '\0' && strncmp(auth, "Basic ", 6) == 0) {
+ char *pass;
+ char *user;
+
+ user = php_base64_decode(auth + 6, strlen(auth) - 6, NULL);
+ if (user) {
+ pass = strchr(user, ':');
+ if (pass) {
+ *pass++ = '\0';
+ SG(request_info).auth_user = user;
+ SG(request_info).auth_password = estrdup(pass);
+ ret = 0;
+ } else {
+ efree(user);
+ }
+ }
+ }
+
+ if (ret == -1) {
+ SG(request_info).auth_user = SG(request_info).auth_password = NULL;
+ } else {
+ SG(request_info).auth_digest = NULL;
+ }
+
+ if (ret == -1 && auth && auth[0] != '\0' && strncmp(auth, "Digest ", 7) == 0) {
+ SG(request_info).auth_digest = estrdup(auth + 7);
+ ret = 0;
+ }
+
+ if (ret == -1) {
+ SG(request_info).auth_digest = NULL;
+ }
+
+ return ret;
+}
+/* }}} */
+
+/* {{{ php_lint_script
+ */
+PHPAPI int php_lint_script(zend_file_handle *file TSRMLS_DC)
+{
+ zend_op_array *op_array;
+ int retval = FAILURE;
+
+ zend_try {
+ op_array = zend_compile_file(file, ZEND_INCLUDE TSRMLS_CC);
+ zend_destroy_file_handle(file TSRMLS_CC);
+
+ if (op_array) {
+ destroy_op_array(op_array TSRMLS_CC);
+ efree(op_array);
+ retval = SUCCESS;
+ }
+ } zend_end_try();
+
+ return retval;
+}
+/* }}} */
+
+#ifdef PHP_WIN32
+/* {{{ dummy_indent
+ just so that this symbol gets exported... */
+PHPAPI void dummy_indent(void)
+{
+ zend_indent();
+}
+/* }}} */
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/mergesort.c b/main/mergesort.c
new file mode 100644
index 0000000..4555e1b
--- /dev/null
+++ b/main/mergesort.c
@@ -0,0 +1,358 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Peter McIlroy.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)merge.c 8.2 (Berkeley) 2/14/94";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Hybrid exponential search/linear search merge sort with hybrid
+ * natural/pairwise first pass. Requires about .3% more comparisons
+ * for random data than LSMS with pairwise first pass alone.
+ * It works for objects as small as two bytes.
+ */
+
+#define NATURAL
+#define THRESHOLD 16 /* Best choice for natural merge cut-off. */
+
+/* #define NATURAL to get hybrid natural merge.
+ * (The default is pairwise merging.)
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "php.h"
+
+#ifdef PHP_WIN32
+#include <winsock2.h> /* Includes definition for u_char */
+#endif
+
+static void setup(u_char *list1, u_char *list2, size_t n, size_t size, int (*cmp)(const void *, const void * TSRMLS_DC) TSRMLS_DC);
+static void insertionsort(u_char *a, size_t n, size_t size, int (*cmp)(const void *, const void * TSRMLS_DC) TSRMLS_DC);
+
+#define ISIZE sizeof(int)
+#define PSIZE sizeof(u_char *)
+#define ICOPY_LIST(src, dst, last) \
+ do \
+ *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \
+ while(src < last)
+#define ICOPY_ELT(src, dst, i) \
+ do \
+ *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \
+ while (i -= ISIZE)
+
+#define CCOPY_LIST(src, dst, last) \
+ do \
+ *dst++ = *src++; \
+ while (src < last)
+#define CCOPY_ELT(src, dst, i) \
+ do \
+ *dst++ = *src++; \
+ while (i -= 1)
+
+/*
+ * Find the next possible pointer head. (Trickery for forcing an array
+ * to do double duty as a linked list when objects do not align with word
+ * boundaries.
+ */
+/* Assumption: PSIZE is a power of 2. */
+#define EVAL(p) (u_char **) \
+ ((u_char *)0 + \
+ (((u_char *)p + PSIZE - 1 - (u_char *) 0) & ~(PSIZE - 1)))
+
+/* {{{ php_mergesort
+ * Arguments are as for qsort.
+ */
+PHPAPI int php_mergesort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *, const void * TSRMLS_DC) TSRMLS_DC)
+{
+ register unsigned int i;
+ register int sense;
+ int big, iflag;
+ register u_char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2;
+ u_char *list2, *list1, *p2, *p, *last, **p1;
+
+ if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (nmemb == 0)
+ return (0);
+
+ /*
+ * XXX
+ * Stupid subtraction for the Cray.
+ */
+ iflag = 0;
+ if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE))
+ iflag = 1;
+
+ if ((list2 = malloc(nmemb * size + PSIZE)) == NULL)
+ return (-1);
+
+ list1 = base;
+ setup(list1, list2, nmemb, size, cmp TSRMLS_CC);
+ last = list2 + nmemb * size;
+ i = big = 0;
+ while (*EVAL(list2) != last) {
+ l2 = list1;
+ p1 = EVAL(list1);
+ for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) {
+ p2 = *EVAL(p2);
+ f1 = l2;
+ f2 = l1 = list1 + (p2 - list2);
+ if (p2 != last)
+ p2 = *EVAL(p2);
+ l2 = list1 + (p2 - list2);
+ while (f1 < l1 && f2 < l2) {
+ if ((*cmp)(f1, f2 TSRMLS_CC) <= 0) {
+ q = f2;
+ b = f1, t = l1;
+ sense = -1;
+ } else {
+ q = f1;
+ b = f2, t = l2;
+ sense = 0;
+ }
+ if (!big) { /* here i = 0 */
+ while ((b += size) < t && cmp(q, b TSRMLS_CC) >sense)
+ if (++i == 6) {
+ big = 1;
+ goto EXPONENTIAL;
+ }
+ } else {
+EXPONENTIAL: for (i = size; ; i <<= 1)
+ if ((p = (b + i)) >= t) {
+ if ((p = t - size) > b &&
+ (*cmp)(q, p TSRMLS_CC) <= sense)
+ t = p;
+ else
+ b = p;
+ break;
+ } else if ((*cmp)(q, p TSRMLS_CC) <= sense) {
+ t = p;
+ if (i == size)
+ big = 0;
+ goto FASTCASE;
+ } else
+ b = p;
+ while (t > b+size) {
+ i = (((t - b) / size) >> 1) * size;
+ if ((*cmp)(q, p = b + i TSRMLS_CC) <= sense)
+ t = p;
+ else
+ b = p;
+ }
+ goto COPY;
+FASTCASE: while (i > size)
+ if ((*cmp)(q,
+ p = b + (i >>= 1) TSRMLS_CC) <= sense)
+ t = p;
+ else
+ b = p;
+COPY: b = t;
+ }
+ i = size;
+ if (q == f1) {
+ if (iflag) {
+ ICOPY_LIST(f2, tp2, b);
+ ICOPY_ELT(f1, tp2, i);
+ } else {
+ CCOPY_LIST(f2, tp2, b);
+ CCOPY_ELT(f1, tp2, i);
+ }
+ } else {
+ if (iflag) {
+ ICOPY_LIST(f1, tp2, b);
+ ICOPY_ELT(f2, tp2, i);
+ } else {
+ CCOPY_LIST(f1, tp2, b);
+ CCOPY_ELT(f2, tp2, i);
+ }
+ }
+ }
+ if (f2 < l2) {
+ if (iflag)
+ ICOPY_LIST(f2, tp2, l2);
+ else
+ CCOPY_LIST(f2, tp2, l2);
+ } else if (f1 < l1) {
+ if (iflag)
+ ICOPY_LIST(f1, tp2, l1);
+ else
+ CCOPY_LIST(f1, tp2, l1);
+ }
+ *p1 = l2;
+ }
+ tp2 = list1; /* swap list1, list2 */
+ list1 = list2;
+ list2 = tp2;
+ last = list2 + nmemb*size;
+ }
+ if (base == list2) {
+ memmove(list2, list1, nmemb*size);
+ list2 = list1;
+ }
+ free(list2);
+ return (0);
+}
+/* }}} */
+
+#define swap(a, b) { \
+ s = b; \
+ i = size; \
+ do { \
+ tmp = *a; *a++ = *s; *s++ = tmp; \
+ } while (--i); \
+ a -= size; \
+ }
+#define reverse(bot, top) { \
+ s = top; \
+ do { \
+ i = size; \
+ do { \
+ tmp = *bot; *bot++ = *s; *s++ = tmp; \
+ } while (--i); \
+ s -= size2; \
+ } while(bot < s); \
+}
+
+/* {{{ setup
+ * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of
+ * increasing order, list2 in a corresponding linked list. Checks for runs
+ * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL
+ * is defined. Otherwise simple pairwise merging is used.)
+ */
+static void setup(u_char *list1, u_char *list2, size_t n, size_t size, int (*cmp)(const void *, const void * TSRMLS_DC) TSRMLS_DC)
+{
+ int i, length, size2, tmp, sense;
+ u_char *f1, *f2, *s, *l2, *last, *p2;
+
+ size2 = size*2;
+ if (n <= 5) {
+ insertionsort(list1, n, size, cmp TSRMLS_CC);
+ *EVAL(list2) = (u_char*) list2 + n*size;
+ return;
+ }
+ /*
+ * Avoid running pointers out of bounds; limit n to evens
+ * for simplicity.
+ */
+ i = 4 + (n & 1);
+ insertionsort(list1 + (n - i) * size, i, size, cmp TSRMLS_CC);
+ last = list1 + size * (n - i);
+ *EVAL(list2 + (last - list1)) = list2 + n * size;
+
+#ifdef NATURAL
+ p2 = list2;
+ f1 = list1;
+ sense = (cmp(f1, f1 + size TSRMLS_CC) > 0);
+ for (; f1 < last; sense = !sense) {
+ length = 2;
+ /* Find pairs with same sense. */
+ for (f2 = f1 + size2; f2 < last; f2 += size2) {
+ if ((cmp(f2, f2+ size TSRMLS_CC) > 0) != sense)
+ break;
+ length += 2;
+ }
+ if (length < THRESHOLD) { /* Pairwise merge */
+ do {
+ p2 = *EVAL(p2) = f1 + size2 - list1 + list2;
+ if (sense > 0)
+ swap (f1, f1 + size);
+ } while ((f1 += size2) < f2);
+ } else { /* Natural merge */
+ l2 = f2;
+ for (f2 = f1 + size2; f2 < l2; f2 += size2) {
+ if ((cmp(f2-size, f2 TSRMLS_CC) > 0) != sense) {
+ p2 = *EVAL(p2) = f2 - list1 + list2;
+ if (sense > 0)
+ reverse(f1, f2-size);
+ f1 = f2;
+ }
+ }
+ if (sense > 0)
+ reverse (f1, f2-size);
+ f1 = f2;
+ if (f2 < last || cmp(f2 - size, f2 TSRMLS_CC) > 0)
+ p2 = *EVAL(p2) = f2 - list1 + list2;
+ else
+ p2 = *EVAL(p2) = list2 + n*size;
+ }
+ }
+#else /* pairwise merge only. */
+ for (f1 = list1, p2 = list2; f1 < last; f1 += size2) {
+ p2 = *EVAL(p2) = p2 + size2;
+ if (cmp (f1, f1 + size TSRMLS_CC) > 0)
+ swap(f1, f1 + size);
+ }
+#endif /* NATURAL */
+}
+/* }}} */
+
+/* {{{ insertionsort
+ * This is to avoid out-of-bounds addresses in sorting the
+ * last 4 elements.
+ */
+static void insertionsort(u_char *a, size_t n, size_t size, int (*cmp)(const void *, const void * TSRMLS_DC) TSRMLS_DC)
+{
+ u_char *ai, *s, *t, *u, tmp;
+ int i;
+
+ for (ai = a+size; --n >= 1; ai += size)
+ for (t = ai; t > a; t -= size) {
+ u = t - size;
+ if (cmp(u, t TSRMLS_CC) <= 0)
+ break;
+ swap(u, t);
+ }
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
diff --git a/main/network.c b/main/network.c
new file mode 100644
index 0000000..ba2ee1c
--- /dev/null
+++ b/main/network.c
@@ -0,0 +1,1202 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Stig Venaas <venaas@uninett.no> |
+ | Streams work by Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/*#define DEBUG_MAIN_NETWORK 1*/
+
+#include "php.h"
+
+#include <stddef.h>
+
+#ifdef PHP_WIN32
+# include "win32/inet.h"
+# define O_RDONLY _O_RDONLY
+# include "win32/param.h"
+#elif defined(NETWARE)
+#include <sys/timeval.h>
+#include <sys/param.h>
+#else
+#include <sys/param.h>
+#endif
+
+#include <sys/types.h>
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifndef _FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#if HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+
+#if defined(NETWARE)
+#ifdef USE_WINSOCK
+#include <novsock2.h>
+#else
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#endif
+#elif !defined(PHP_WIN32)
+#include <netinet/in.h>
+#include <netdb.h>
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#endif
+
+#ifndef HAVE_INET_ATON
+int inet_aton(const char *, struct in_addr *);
+#endif
+
+#include "php_network.h"
+
+#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE)
+#undef AF_UNIX
+#endif
+
+#if defined(AF_UNIX)
+#include <sys/un.h>
+#endif
+
+#include "ext/standard/file.h"
+
+#ifdef PHP_WIN32
+# include "win32/time.h"
+# define SOCK_ERR INVALID_SOCKET
+# define SOCK_CONN_ERR SOCKET_ERROR
+# define PHP_TIMEOUT_ERROR_VALUE WSAETIMEDOUT
+
+#if HAVE_IPV6
+const struct in6_addr in6addr_any = {0}; /* IN6ADDR_ANY_INIT; */
+#endif
+
+#else
+# define SOCK_ERR -1
+# define SOCK_CONN_ERR -1
+# define PHP_TIMEOUT_ERROR_VALUE ETIMEDOUT
+#endif
+
+#if HAVE_GETADDRINFO
+#ifdef HAVE_GAI_STRERROR
+# define PHP_GAI_STRERROR(x) (gai_strerror(x))
+#else
+# define PHP_GAI_STRERROR(x) (php_gai_strerror(x))
+/* {{{ php_gai_strerror
+ */
+static const char *php_gai_strerror(int code)
+{
+ static struct {
+ int code;
+ const char *msg;
+ } values[] = {
+# ifdef EAI_ADDRFAMILY
+ {EAI_ADDRFAMILY, "Address family for hostname not supported"},
+# endif
+ {EAI_AGAIN, "Temporary failure in name resolution"},
+ {EAI_BADFLAGS, "Bad value for ai_flags"},
+ {EAI_FAIL, "Non-recoverable failure in name resolution"},
+ {EAI_FAMILY, "ai_family not supported"},
+ {EAI_MEMORY, "Memory allocation failure"},
+# ifdef EAI_NODATA
+ {EAI_NODATA, "No address associated with hostname"},
+# endif
+ {EAI_NONAME, "Name or service not known"},
+ {EAI_SERVICE, "Servname not supported for ai_socktype"},
+ {EAI_SOCKTYPE, "ai_socktype not supported"},
+ {EAI_SYSTEM, "System error"},
+ {0, NULL}
+ };
+ int i;
+
+ for (i = 0; values[i].msg != NULL; i++) {
+ if (values[i].code == code) {
+ return (char *)values[i].msg;
+ }
+ }
+
+ return "Unknown error";
+}
+/* }}} */
+#endif
+#endif
+
+/* {{{ php_network_freeaddresses
+ */
+PHPAPI void php_network_freeaddresses(struct sockaddr **sal)
+{
+ struct sockaddr **sap;
+
+ if (sal == NULL)
+ return;
+ for (sap = sal; *sap != NULL; sap++)
+ efree(*sap);
+ efree(sal);
+}
+/* }}} */
+
+/* {{{ php_network_getaddresses
+ * Returns number of addresses, 0 for none/error
+ */
+PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, char **error_string TSRMLS_DC)
+{
+ struct sockaddr **sap;
+ int n;
+#if HAVE_GETADDRINFO
+# if HAVE_IPV6
+ static int ipv6_borked = -1; /* the way this is used *is* thread safe */
+# endif
+ struct addrinfo hints, *res, *sai;
+#else
+ struct hostent *host_info;
+ struct in_addr in;
+#endif
+
+ if (host == NULL) {
+ return 0;
+ }
+#if HAVE_GETADDRINFO
+ memset(&hints, '\0', sizeof(hints));
+
+ hints.ai_family = AF_INET; /* default to regular inet (see below) */
+ hints.ai_socktype = socktype;
+
+# if HAVE_IPV6
+ /* probe for a working IPv6 stack; even if detected as having v6 at compile
+ * time, at runtime some stacks are slow to resolve or have other issues
+ * if they are not correctly configured.
+ * static variable use is safe here since simple store or fetch operations
+ * are atomic and because the actual probe process is not in danger of
+ * collisions or race conditions. */
+ if (ipv6_borked == -1) {
+ int s;
+
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s == SOCK_ERR) {
+ ipv6_borked = 1;
+ } else {
+ ipv6_borked = 0;
+ closesocket(s);
+ }
+ }
+ hints.ai_family = ipv6_borked ? AF_INET : AF_UNSPEC;
+# endif
+
+ if ((n = getaddrinfo(host, NULL, &hints, &res))) {
+ if (error_string) {
+ spprintf(error_string, 0, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
+ }
+ return 0;
+ } else if (res == NULL) {
+ if (error_string) {
+ spprintf(error_string, 0, "php_network_getaddresses: getaddrinfo failed (null result pointer) errno=%d", errno);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_network_getaddresses: getaddrinfo failed (null result pointer)");
+ }
+ return 0;
+ }
+
+ sai = res;
+ for (n = 1; (sai = sai->ai_next) != NULL; n++)
+ ;
+
+ *sal = safe_emalloc((n + 1), sizeof(*sal), 0);
+ sai = res;
+ sap = *sal;
+
+ do {
+ *sap = emalloc(sai->ai_addrlen);
+ memcpy(*sap, sai->ai_addr, sai->ai_addrlen);
+ sap++;
+ } while ((sai = sai->ai_next) != NULL);
+
+ freeaddrinfo(res);
+#else
+ if (!inet_aton(host, &in)) {
+ /* XXX NOT THREAD SAFE (is safe under win32) */
+ host_info = gethostbyname(host);
+ if (host_info == NULL) {
+ if (error_string) {
+ spprintf(error_string, 0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_network_getaddresses: gethostbyname failed");
+ }
+ return 0;
+ }
+ in = *((struct in_addr *) host_info->h_addr);
+ }
+
+ *sal = safe_emalloc(2, sizeof(*sal), 0);
+ sap = *sal;
+ *sap = emalloc(sizeof(struct sockaddr_in));
+ (*sap)->sa_family = AF_INET;
+ ((struct sockaddr_in *)*sap)->sin_addr = in;
+ sap++;
+ n = 1;
+#endif
+
+ *sap = NULL;
+ return n;
+}
+/* }}} */
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK O_NDELAY
+#endif
+
+#if !defined(__BEOS__)
+# define HAVE_NON_BLOCKING_CONNECT 1
+# ifdef PHP_WIN32
+typedef u_long php_non_blocking_flags_t;
+# define SET_SOCKET_BLOCKING_MODE(sock, save) \
+ save = TRUE; ioctlsocket(sock, FIONBIO, &save)
+# define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
+ ioctlsocket(sock, FIONBIO, &save)
+# else
+typedef int php_non_blocking_flags_t;
+# define SET_SOCKET_BLOCKING_MODE(sock, save) \
+ save = fcntl(sock, F_GETFL, 0); \
+ fcntl(sock, F_SETFL, save | O_NONBLOCK)
+# define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
+ fcntl(sock, F_SETFL, save)
+# endif
+#endif
+
+/* Connect to a socket using an interruptible connect with optional timeout.
+ * Optionally, the connect can be made asynchronously, which will implicitly
+ * enable non-blocking mode on the socket.
+ * */
+/* {{{ php_network_connect_socket */
+PHPAPI int php_network_connect_socket(php_socket_t sockfd,
+ const struct sockaddr *addr,
+ socklen_t addrlen,
+ int asynchronous,
+ struct timeval *timeout,
+ char **error_string,
+ int *error_code)
+{
+#if HAVE_NON_BLOCKING_CONNECT
+ php_non_blocking_flags_t orig_flags;
+ int n;
+ int error = 0;
+ socklen_t len;
+ int ret = 0;
+
+ SET_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
+
+ if ((n = connect(sockfd, addr, addrlen)) != 0) {
+ error = php_socket_errno();
+
+ if (error_code) {
+ *error_code = error;
+ }
+
+ if (error != EINPROGRESS) {
+ if (error_string) {
+ *error_string = php_socket_strerror(error, NULL, 0);
+ }
+
+ return -1;
+ }
+ if (asynchronous && error == EINPROGRESS) {
+ /* this is fine by us */
+ return 0;
+ }
+ }
+
+ if (n == 0) {
+ goto ok;
+ }
+# ifdef PHP_WIN32
+ /* The documentation for connect() says in case of non-blocking connections
+ * the select function reports success in the writefds set and failure in
+ * the exceptfds set. Indeed, using PHP_POLLREADABLE results in select
+ * failing only due to the timeout and not immediately as would be
+ * expected when a connection is actively refused. This way,
+ * php_pollfd_for will return a mask with POLLOUT if the connection
+ * is successful and with POLLPRI otherwise. */
+ if ((n = php_pollfd_for(sockfd, POLLOUT|POLLPRI, timeout)) == 0) {
+#else
+ if ((n = php_pollfd_for(sockfd, PHP_POLLREADABLE|POLLOUT, timeout)) == 0) {
+#endif
+ error = PHP_TIMEOUT_ERROR_VALUE;
+ }
+
+ if (n > 0) {
+ len = sizeof(error);
+ /*
+ BSD-derived systems set errno correctly
+ Solaris returns -1 from getsockopt in case of error
+ */
+ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&error, &len) != 0) {
+ ret = -1;
+ }
+ } else {
+ /* whoops: sockfd has disappeared */
+ ret = -1;
+ }
+
+ok:
+ if (!asynchronous) {
+ /* back to blocking mode */
+ RESTORE_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
+ }
+
+ if (error_code) {
+ *error_code = error;
+ }
+
+ if (error) {
+ ret = -1;
+ if (error_string) {
+ *error_string = php_socket_strerror(error, NULL, 0);
+ }
+ }
+ return ret;
+#else
+ if (asynchronous) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Asynchronous connect() not supported on this platform");
+ }
+ return (connect(sockfd, addr, addrlen) == 0) ? 0 : -1;
+#endif
+}
+/* }}} */
+
+/* {{{ sub_times */
+static inline void sub_times(struct timeval a, struct timeval b, struct timeval *result)
+{
+ result->tv_usec = a.tv_usec - b.tv_usec;
+ if (result->tv_usec < 0L) {
+ a.tv_sec--;
+ result->tv_usec += 1000000L;
+ }
+ result->tv_sec = a.tv_sec - b.tv_sec;
+ if (result->tv_sec < 0L) {
+ result->tv_sec++;
+ result->tv_usec -= 1000000L;
+ }
+}
+/* }}} */
+
+/* Bind to a local IP address.
+ * Returns the bound socket, or -1 on failure.
+ * */
+/* {{{ php_network_bind_socket_to_local_addr */
+php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port,
+ int socktype, char **error_string, int *error_code
+ TSRMLS_DC)
+{
+ int num_addrs, n, err = 0;
+ php_socket_t sock;
+ struct sockaddr **sal, **psal, *sa;
+ socklen_t socklen;
+
+ num_addrs = php_network_getaddresses(host, socktype, &psal, error_string TSRMLS_CC);
+
+ if (num_addrs == 0) {
+ /* could not resolve address(es) */
+ return -1;
+ }
+
+ for (sal = psal; *sal != NULL; sal++) {
+ sa = *sal;
+
+ /* create a socket for this address */
+ sock = socket(sa->sa_family, socktype, 0);
+
+ if (sock == SOCK_ERR) {
+ continue;
+ }
+
+ switch (sa->sa_family) {
+#if HAVE_GETADDRINFO && HAVE_IPV6
+ case AF_INET6:
+ ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
+ ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
+ socklen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ case AF_INET:
+ ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
+ ((struct sockaddr_in *)sa)->sin_port = htons(port);
+ socklen = sizeof(struct sockaddr_in);
+ break;
+ default:
+ /* Unknown family */
+ socklen = 0;
+ sa = NULL;
+ }
+
+ if (sa) {
+ /* attempt to bind */
+
+#ifdef SO_REUSEADDR
+ {
+ int val = 1;
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val));
+ }
+#endif
+
+ n = bind(sock, sa, socklen);
+
+ if (n != SOCK_CONN_ERR) {
+ goto bound;
+ }
+
+ err = php_socket_errno();
+ }
+
+ closesocket(sock);
+ }
+ sock = -1;
+
+ if (error_code) {
+ *error_code = err;
+ }
+ if (error_string) {
+ *error_string = php_socket_strerror(err, NULL, 0);
+ }
+
+bound:
+
+ php_network_freeaddresses(psal);
+
+ return sock;
+
+}
+/* }}} */
+
+PHPAPI int php_network_parse_network_address_with_port(const char *addr, long addrlen, struct sockaddr *sa, socklen_t *sl TSRMLS_DC)
+{
+ char *colon;
+ char *tmp;
+ int ret = FAILURE;
+ short port;
+ struct sockaddr_in *in4 = (struct sockaddr_in*)sa;
+ struct sockaddr **psal;
+ int n;
+ char *errstr = NULL;
+#if HAVE_IPV6
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6*)sa;
+#endif
+
+ if (*addr == '[') {
+ colon = memchr(addr + 1, ']', addrlen-1);
+ if (!colon || colon[1] != ':') {
+ return FAILURE;
+ }
+ port = atoi(colon + 2);
+ addr++;
+ } else {
+ colon = memchr(addr, ':', addrlen);
+ if (!colon) {
+ return FAILURE;
+ }
+ port = atoi(colon + 1);
+ }
+
+ tmp = estrndup(addr, colon - addr);
+
+ /* first, try interpreting the address as a numeric address */
+
+#if HAVE_IPV6 && HAVE_INET_PTON
+ if (inet_pton(AF_INET6, tmp, &in6->sin6_addr) > 0) {
+ in6->sin6_port = htons(port);
+ in6->sin6_family = AF_INET6;
+ *sl = sizeof(struct sockaddr_in6);
+ ret = SUCCESS;
+ goto out;
+ }
+#endif
+ if (inet_aton(tmp, &in4->sin_addr) > 0) {
+ in4->sin_port = htons(port);
+ in4->sin_family = AF_INET;
+ *sl = sizeof(struct sockaddr_in);
+ ret = SUCCESS;
+ goto out;
+ }
+
+ /* looks like we'll need to resolve it */
+ n = php_network_getaddresses(tmp, SOCK_DGRAM, &psal, &errstr TSRMLS_CC);
+
+ if (n == 0) {
+ if (errstr) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to resolve `%s': %s", tmp, errstr);
+ STR_FREE(errstr);
+ }
+ goto out;
+ }
+
+ /* copy the details from the first item */
+ switch ((*psal)->sa_family) {
+#if HAVE_GETADDRINFO && HAVE_IPV6
+ case AF_INET6:
+ *in6 = **(struct sockaddr_in6**)psal;
+ in6->sin6_port = htons(port);
+ *sl = sizeof(struct sockaddr_in6);
+ ret = SUCCESS;
+ break;
+#endif
+ case AF_INET:
+ *in4 = **(struct sockaddr_in**)psal;
+ in4->sin_port = htons(port);
+ *sl = sizeof(struct sockaddr_in);
+ ret = SUCCESS;
+ break;
+ }
+
+ php_network_freeaddresses(psal);
+
+out:
+ STR_FREE(tmp);
+ return ret;
+}
+
+
+PHPAPI void php_network_populate_name_from_sockaddr(
+ /* input address */
+ struct sockaddr *sa, socklen_t sl,
+ /* output readable address */
+ char **textaddr, long *textaddrlen,
+ /* output address */
+ struct sockaddr **addr,
+ socklen_t *addrlen
+ TSRMLS_DC)
+{
+ if (addr) {
+ *addr = emalloc(sl);
+ memcpy(*addr, sa, sl);
+ *addrlen = sl;
+ }
+
+ if (textaddr) {
+#if HAVE_IPV6 && HAVE_INET_NTOP
+ char abuf[256];
+#endif
+ char *buf = NULL;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ /* generally not thread safe, but it *is* thread safe under win32 */
+ buf = inet_ntoa(((struct sockaddr_in*)sa)->sin_addr);
+ if (buf) {
+ *textaddrlen = spprintf(textaddr, 0, "%s:%d",
+ buf, ntohs(((struct sockaddr_in*)sa)->sin_port));
+ }
+
+ break;
+
+#if HAVE_IPV6 && HAVE_INET_NTOP
+ case AF_INET6:
+ buf = (char*)inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, (char *)&abuf, sizeof(abuf));
+ if (buf) {
+ *textaddrlen = spprintf(textaddr, 0, "%s:%d",
+ buf, ntohs(((struct sockaddr_in6*)sa)->sin6_port));
+ }
+
+ break;
+#endif
+#ifdef AF_UNIX
+ case AF_UNIX:
+ {
+ struct sockaddr_un *ua = (struct sockaddr_un*)sa;
+
+ if (ua->sun_path[0] == '\0') {
+ /* abstract name */
+ int len = strlen(ua->sun_path + 1) + 1;
+ *textaddrlen = len;
+ *textaddr = emalloc(len + 1);
+ memcpy(*textaddr, ua->sun_path, len);
+ (*textaddr)[len] = '\0';
+ } else {
+ *textaddrlen = strlen(ua->sun_path);
+ *textaddr = estrndup(ua->sun_path, *textaddrlen);
+ }
+ }
+ break;
+#endif
+
+ }
+
+ }
+}
+
+PHPAPI int php_network_get_peer_name(php_socket_t sock,
+ char **textaddr, long *textaddrlen,
+ struct sockaddr **addr,
+ socklen_t *addrlen
+ TSRMLS_DC)
+{
+ php_sockaddr_storage sa;
+ socklen_t sl = sizeof(sa);
+ memset(&sa, 0, sizeof(sa));
+
+ if (getpeername(sock, (struct sockaddr*)&sa, &sl) == 0) {
+ php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
+ textaddr, textaddrlen,
+ addr, addrlen
+ TSRMLS_CC);
+ return 0;
+ }
+ return -1;
+}
+
+PHPAPI int php_network_get_sock_name(php_socket_t sock,
+ char **textaddr, long *textaddrlen,
+ struct sockaddr **addr,
+ socklen_t *addrlen
+ TSRMLS_DC)
+{
+ php_sockaddr_storage sa;
+ socklen_t sl = sizeof(sa);
+ memset(&sa, 0, sizeof(sa));
+
+ if (getsockname(sock, (struct sockaddr*)&sa, &sl) == 0) {
+ php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
+ textaddr, textaddrlen,
+ addr, addrlen
+ TSRMLS_CC);
+ return 0;
+ }
+ return -1;
+
+}
+
+
+/* Accept a client connection from a server socket,
+ * using an optional timeout.
+ * Returns the peer address in addr/addrlen (it will emalloc
+ * these, so be sure to efree the result).
+ * If you specify textaddr/textaddrlen, a text-printable
+ * version of the address will be emalloc'd and returned.
+ * */
+
+/* {{{ php_network_accept_incoming */
+PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
+ char **textaddr, long *textaddrlen,
+ struct sockaddr **addr,
+ socklen_t *addrlen,
+ struct timeval *timeout,
+ char **error_string,
+ int *error_code
+ TSRMLS_DC)
+{
+ php_socket_t clisock = -1;
+ int error = 0, n;
+ php_sockaddr_storage sa;
+ socklen_t sl;
+
+ n = php_pollfd_for(srvsock, PHP_POLLREADABLE, timeout);
+
+ if (n == 0) {
+ error = PHP_TIMEOUT_ERROR_VALUE;
+ } else if (n == -1) {
+ error = php_socket_errno();
+ } else {
+ sl = sizeof(sa);
+
+ clisock = accept(srvsock, (struct sockaddr*)&sa, &sl);
+
+ if (clisock != SOCK_ERR) {
+ php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
+ textaddr, textaddrlen,
+ addr, addrlen
+ TSRMLS_CC);
+ } else {
+ error = php_socket_errno();
+ }
+ }
+
+ if (error_code) {
+ *error_code = error;
+ }
+ if (error_string) {
+ *error_string = php_socket_strerror(error, NULL, 0);
+ }
+
+ return clisock;
+}
+/* }}} */
+
+
+
+/* Connect to a remote host using an interruptible connect with optional timeout.
+ * Optionally, the connect can be made asynchronously, which will implicitly
+ * enable non-blocking mode on the socket.
+ * Returns the connected (or connecting) socket, or -1 on failure.
+ * */
+
+/* {{{ php_network_connect_socket_to_host */
+php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
+ int socktype, int asynchronous, struct timeval *timeout, char **error_string,
+ int *error_code, char *bindto, unsigned short bindport
+ TSRMLS_DC)
+{
+ int num_addrs, n, fatal = 0;
+ php_socket_t sock;
+ struct sockaddr **sal, **psal, *sa;
+ struct timeval working_timeout;
+ socklen_t socklen;
+#if HAVE_GETTIMEOFDAY
+ struct timeval limit_time, time_now;
+#endif
+
+ num_addrs = php_network_getaddresses(host, socktype, &psal, error_string TSRMLS_CC);
+
+ if (num_addrs == 0) {
+ /* could not resolve address(es) */
+ return -1;
+ }
+
+ if (timeout) {
+ memcpy(&working_timeout, timeout, sizeof(working_timeout));
+#if HAVE_GETTIMEOFDAY
+ gettimeofday(&limit_time, NULL);
+ limit_time.tv_sec += working_timeout.tv_sec;
+ limit_time.tv_usec += working_timeout.tv_usec;
+ if (limit_time.tv_usec >= 1000000) {
+ limit_time.tv_usec -= 1000000;
+ limit_time.tv_sec++;
+ }
+#endif
+ }
+
+ for (sal = psal; !fatal && *sal != NULL; sal++) {
+ sa = *sal;
+
+ /* create a socket for this address */
+ sock = socket(sa->sa_family, socktype, 0);
+
+ if (sock == SOCK_ERR) {
+ continue;
+ }
+
+ switch (sa->sa_family) {
+#if HAVE_GETADDRINFO && HAVE_IPV6
+ case AF_INET6:
+ if (!bindto || strchr(bindto, ':')) {
+ ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
+ ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
+ socklen = sizeof(struct sockaddr_in6);
+ } else {
+ socklen = 0;
+ sa = NULL;
+ }
+ break;
+#endif
+ case AF_INET:
+ ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
+ ((struct sockaddr_in *)sa)->sin_port = htons(port);
+ socklen = sizeof(struct sockaddr_in);
+ break;
+ default:
+ /* Unknown family */
+ socklen = 0;
+ sa = NULL;
+ }
+
+ if (sa) {
+ /* make a connection attempt */
+
+ if (bindto) {
+ struct sockaddr *local_address = NULL;
+ int local_address_len = 0;
+
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *in4 = emalloc(sizeof(struct sockaddr_in));
+
+ local_address = (struct sockaddr*)in4;
+ local_address_len = sizeof(struct sockaddr_in);
+
+ in4->sin_family = sa->sa_family;
+ in4->sin_port = htons(bindport);
+ if (!inet_aton(bindto, &in4->sin_addr)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid IP Address: %s", bindto);
+ goto skip_bind;
+ }
+ memset(&(in4->sin_zero), 0, sizeof(in4->sin_zero));
+ }
+#if HAVE_IPV6 && HAVE_INET_PTON
+ else { /* IPV6 */
+ struct sockaddr_in6 *in6 = emalloc(sizeof(struct sockaddr_in6));
+
+ local_address = (struct sockaddr*)in6;
+ local_address_len = sizeof(struct sockaddr_in6);
+
+ in6->sin6_family = sa->sa_family;
+ in6->sin6_port = htons(bindport);
+ if (inet_pton(AF_INET6, bindto, &in6->sin6_addr) < 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid IP Address: %s", bindto);
+ goto skip_bind;
+ }
+ }
+#endif
+ if (!local_address || bind(sock, local_address, local_address_len)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno));
+ }
+skip_bind:
+ if (local_address) {
+ efree(local_address);
+ }
+ }
+ /* free error string recieved during previous iteration (if any) */
+ if (error_string && *error_string) {
+ efree(*error_string);
+ *error_string = NULL;
+ }
+
+ n = php_network_connect_socket(sock, sa, socklen, asynchronous,
+ timeout ? &working_timeout : NULL,
+ error_string, error_code);
+
+ if (n != -1) {
+ goto connected;
+ }
+
+ /* adjust timeout for next attempt */
+#if HAVE_GETTIMEOFDAY
+ if (timeout) {
+ gettimeofday(&time_now, NULL);
+
+ if (timercmp(&time_now, &limit_time, >=)) {
+ /* time limit expired; don't attempt any further connections */
+ fatal = 1;
+ } else {
+ /* work out remaining time */
+ sub_times(limit_time, time_now, &working_timeout);
+ }
+ }
+#else
+ if (error_code && *error_code == PHP_TIMEOUT_ERROR_VALUE) {
+ /* Don't even bother trying to connect to the next alternative;
+ * we have no way to determine how long we have already taken
+ * and it is quite likely that the next attempt will fail too. */
+ fatal = 1;
+ } else {
+ /* re-use the same initial timeout.
+ * Not the best thing, but in practice it should be good-enough */
+ if (timeout) {
+ memcpy(&working_timeout, timeout, sizeof(working_timeout));
+ }
+ }
+#endif
+ }
+
+ closesocket(sock);
+ }
+ sock = -1;
+
+connected:
+
+ php_network_freeaddresses(psal);
+
+ return sock;
+}
+/* }}} */
+
+/* {{{ php_any_addr
+ * Fills the any (wildcard) address into php_sockaddr_storage
+ */
+PHPAPI void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port)
+{
+ memset(addr, 0, sizeof(php_sockaddr_storage));
+ switch (family) {
+#if HAVE_IPV6
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons(port);
+ sin6->sin6_addr = in6addr_any;
+ break;
+ }
+#endif
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *) addr;
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(port);
+ sin->sin_addr.s_addr = htonl(INADDR_ANY);
+ break;
+ }
+ }
+}
+/* }}} */
+
+/* {{{ php_sockaddr_size
+ * Returns the size of struct sockaddr_xx for the family
+ */
+PHPAPI int php_sockaddr_size(php_sockaddr_storage *addr)
+{
+ switch (((struct sockaddr *)addr)->sa_family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+#if HAVE_IPV6
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+#endif
+#ifdef AF_UNIX
+ case AF_UNIX:
+ return sizeof(struct sockaddr_un);
+#endif
+ default:
+ return 0;
+ }
+}
+/* }}} */
+
+/* Given a socket error code, if buf == NULL:
+ * emallocs storage for the error message and returns
+ * else
+ * sprintf message into provided buffer and returns buf
+ */
+/* {{{ php_socket_strerror */
+PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
+{
+#ifndef PHP_WIN32
+ char *errstr;
+
+ errstr = strerror(err);
+ if (buf == NULL) {
+ buf = estrdup(errstr);
+ } else {
+ strncpy(buf, errstr, bufsize);
+ }
+ return buf;
+#else
+ char *sysbuf;
+ int free_it = 1;
+
+ if (!FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)&sysbuf,
+ 0,
+ NULL)) {
+ free_it = 0;
+ sysbuf = "Unknown Error";
+ }
+
+ if (buf == NULL) {
+ buf = estrdup(sysbuf);
+ } else {
+ strncpy(buf, sysbuf, bufsize);
+ }
+
+ if (free_it) {
+ LocalFree(sysbuf);
+ }
+
+ return buf;
+#endif
+}
+/* }}} */
+
+/* deprecated */
+PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const char *persistent_id STREAMS_DC TSRMLS_DC)
+{
+ php_stream *stream;
+ php_netstream_data_t *sock;
+
+ sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
+ memset(sock, 0, sizeof(php_netstream_data_t));
+
+ sock->is_blocked = 1;
+ sock->timeout.tv_sec = FG(default_socket_timeout);
+ sock->timeout.tv_usec = 0;
+ sock->socket = socket;
+
+ stream = php_stream_alloc_rel(&php_stream_generic_socket_ops, sock, persistent_id, "r+");
+
+ if (stream == NULL) {
+ pefree(sock, persistent_id ? 1 : 0);
+ } else {
+ stream->flags |= PHP_STREAM_FLAG_AVOID_BLOCKING;
+ }
+
+ return stream;
+}
+
+PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short port,
+ int socktype, struct timeval *timeout, const char *persistent_id STREAMS_DC TSRMLS_DC)
+{
+ char *res;
+ long reslen;
+ php_stream *stream;
+
+ reslen = spprintf(&res, 0, "tcp://%s:%d", host, port);
+
+ stream = php_stream_xport_create(res, reslen, REPORT_ERRORS,
+ STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, persistent_id, timeout, NULL, NULL, NULL);
+
+ efree(res);
+
+ return stream;
+}
+
+PHPAPI int php_set_sock_blocking(int socketd, int block TSRMLS_DC)
+{
+ int ret = SUCCESS;
+ int flags;
+ int myflag = 0;
+
+#ifdef PHP_WIN32
+ /* with ioctlsocket, a non-zero sets nonblocking, a zero sets blocking */
+ flags = !block;
+ if (ioctlsocket(socketd, FIONBIO, &flags) == SOCKET_ERROR) {
+ ret = FAILURE;
+ }
+#else
+ flags = fcntl(socketd, F_GETFL);
+#ifdef O_NONBLOCK
+ myflag = O_NONBLOCK; /* POSIX version */
+#elif defined(O_NDELAY)
+ myflag = O_NDELAY; /* old non-POSIX version */
+#endif
+ if (!block) {
+ flags |= myflag;
+ } else {
+ flags &= ~myflag;
+ }
+ if (fcntl(socketd, F_SETFL, flags) == -1) {
+ ret = FAILURE;
+ }
+#endif
+ return ret;
+}
+
+PHPAPI void _php_emit_fd_setsize_warning(int max_fd)
+{
+ TSRMLS_FETCH();
+
+#ifdef PHP_WIN32
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "PHP needs to be recompiled with a larger value of FD_SETSIZE.\n"
+ "If this binary is from an official www.php.net package, file a bug report\n"
+ "at http://bugs.php.net, including the following information:\n"
+ "FD_SETSIZE=%d, but you are using %d.\n"
+ " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
+ "to match to maximum number of sockets each script will work with at\n"
+ "one time, in order to avoid seeing this error again at a later date.",
+ FD_SETSIZE, max_fd, (max_fd + 128) & ~127);
+#else
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "You MUST recompile PHP with a larger value of FD_SETSIZE.\n"
+ "It is set to %d, but you have descriptors numbered at least as high as %d.\n"
+ " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
+ "to equal the maximum number of open files supported by your system,\n"
+ "in order to avoid seeing this error again at a later date.",
+ FD_SETSIZE, max_fd, (max_fd + 1024) & ~1023);
+#endif
+}
+
+#if defined(PHP_USE_POLL_2_EMULATION)
+
+/* emulate poll(2) using select(2), safely. */
+
+PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout)
+{
+ fd_set rset, wset, eset;
+ php_socket_t max_fd = SOCK_ERR;
+ unsigned int i;
+ int n;
+ struct timeval tv;
+
+ /* check the highest numbered descriptor */
+ for (i = 0; i < nfds; i++) {
+ if (ufds[i].fd > max_fd)
+ max_fd = ufds[i].fd;
+ }
+
+ PHP_SAFE_MAX_FD(max_fd, nfds + 1);
+
+ FD_ZERO(&rset);
+ FD_ZERO(&wset);
+ FD_ZERO(&eset);
+
+ for (i = 0; i < nfds; i++) {
+ if (ufds[i].events & PHP_POLLREADABLE) {
+ PHP_SAFE_FD_SET(ufds[i].fd, &rset);
+ }
+ if (ufds[i].events & POLLOUT) {
+ PHP_SAFE_FD_SET(ufds[i].fd, &wset);
+ }
+ if (ufds[i].events & POLLPRI) {
+ PHP_SAFE_FD_SET(ufds[i].fd, &eset);
+ }
+ }
+
+ if (timeout >= 0) {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
+ }
+/* Reseting/initializing */
+#ifdef PHP_WIN32
+ WSASetLastError(0);
+#else
+ errno = 0;
+#endif
+ n = select(max_fd + 1, &rset, &wset, &eset, timeout >= 0 ? &tv : NULL);
+
+ if (n >= 0) {
+ for (i = 0; i < nfds; i++) {
+ ufds[i].revents = 0;
+
+ if (PHP_SAFE_FD_ISSET(ufds[i].fd, &rset)) {
+ /* could be POLLERR or POLLHUP but can't tell without probing */
+ ufds[i].revents |= POLLIN;
+ }
+ if (PHP_SAFE_FD_ISSET(ufds[i].fd, &wset)) {
+ ufds[i].revents |= POLLOUT;
+ }
+ if (PHP_SAFE_FD_ISSET(ufds[i].fd, &eset)) {
+ ufds[i].revents |= POLLPRI;
+ }
+ }
+ }
+ return n;
+}
+
+#endif
+
+
+/*
+ * Local variables:
+ * tab-width: 8
+ * c-basic-offset: 8
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/output.c b/main/output.c
new file mode 100644
index 0000000..004b066
--- /dev/null
+++ b/main/output.c
@@ -0,0 +1,1578 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Zeev Suraski <zeev@zend.com> |
+ | Thies C. Arntzen <thies@thieso.net> |
+ | Marcus Boerger <helly@php.net> |
+ | New API: Michael Wallner <mike@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_OUTPUT_DEBUG
+# define PHP_OUTPUT_DEBUG 0
+#endif
+#ifndef PHP_OUTPUT_NOINLINE
+# define PHP_OUTPUT_NOINLINE 0
+#endif
+
+#include "php.h"
+#include "ext/standard/head.h"
+#include "ext/standard/url_scanner_ex.h"
+#include "SAPI.h"
+#include "zend_stack.h"
+#include "php_output.h"
+
+ZEND_DECLARE_MODULE_GLOBALS(output);
+
+const char php_output_default_handler_name[sizeof("default output handler")] = "default output handler";
+const char php_output_devnull_handler_name[sizeof("null output handler")] = "null output handler";
+
+#if PHP_OUTPUT_NOINLINE || PHP_OUTPUT_DEBUG
+# undef inline
+# define inline
+#endif
+
+/* {{{ aliases, conflict and reverse conflict hash tables */
+static HashTable php_output_handler_aliases;
+static HashTable php_output_handler_conflicts;
+static HashTable php_output_handler_reverse_conflicts;
+/* }}} */
+
+/* {{{ forward declarations */
+static inline int php_output_lock_error(int op TSRMLS_DC);
+static inline void php_output_op(int op, const char *str, size_t len TSRMLS_DC);
+
+static inline php_output_handler *php_output_handler_init(const char *name, size_t name_len, size_t chunk_size, int flags TSRMLS_DC);
+static inline php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context);
+static inline int php_output_handler_append(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC);
+static inline zval *php_output_handler_status(php_output_handler *handler, zval *entry);
+
+static inline php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC);
+static inline void php_output_context_reset(php_output_context *context);
+static inline void php_output_context_swap(php_output_context *context);
+static inline void php_output_context_dtor(php_output_context *context);
+
+static inline int php_output_stack_pop(int flags TSRMLS_DC);
+
+static int php_output_stack_apply_op(void *h, void *c);
+static int php_output_stack_apply_clean(void *h, void *c);
+static int php_output_stack_apply_list(void *h, void *z);
+static int php_output_stack_apply_status(void *h, void *z);
+
+static int php_output_handler_compat_func(void **handler_context, php_output_context *output_context);
+static int php_output_handler_default_func(void **handler_context, php_output_context *output_context);
+static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context);
+/* }}} */
+
+/* {{{ static void php_output_init_globals(zend_output_globals *G)
+ * Initialize the module globals on MINIT */
+static inline void php_output_init_globals(zend_output_globals *G)
+{
+ memset(G, 0, sizeof(*G));
+}
+/* }}} */
+
+/* {{{ stderr/stdout writer if not PHP_OUTPUT_ACTIVATED */
+static int php_output_stdout(const char *str, size_t str_len)
+{
+ fwrite(str, 1, str_len, stdout);
+ return str_len;
+}
+static int php_output_stderr(const char *str, size_t str_len)
+{
+ fwrite(str, 1, str_len, stderr);
+/* See http://support.microsoft.com/kb/190351 */
+#ifdef PHP_WIN32
+ fflush(stderr);
+#endif
+ return str_len;
+}
+static int (*php_output_direct)(const char *str, size_t str_len) = php_output_stderr;
+/* }}} */
+
+/* {{{ void php_output_header(TSRMLS_D) */
+static void php_output_header(TSRMLS_D)
+{
+ if (!SG(headers_sent)) {
+ if (!OG(output_start_filename)) {
+ if (zend_is_compiling(TSRMLS_C)) {
+ OG(output_start_filename) = zend_get_compiled_filename(TSRMLS_C);
+ OG(output_start_lineno) = zend_get_compiled_lineno(TSRMLS_C);
+ } else if (zend_is_executing(TSRMLS_C)) {
+ OG(output_start_filename) = zend_get_executed_filename(TSRMLS_C);
+ OG(output_start_lineno) = zend_get_executed_lineno(TSRMLS_C);
+ }
+#if PHP_OUTPUT_DEBUG
+ fprintf(stderr, "!!! output started at: %s (%d)\n", OG(output_start_filename), OG(output_start_lineno));
+#endif
+ }
+ if (!php_header(TSRMLS_C)) {
+ OG(flags) |= PHP_OUTPUT_DISABLED;
+ }
+ }
+}
+/* }}} */
+
+/* {{{ void php_output_startup(void)
+ * Set up module globals and initalize the conflict and reverse conflict hash tables */
+PHPAPI void php_output_startup(void)
+{
+ ZEND_INIT_MODULE_GLOBALS(output, php_output_init_globals, NULL);
+ zend_hash_init(&php_output_handler_aliases, 0, NULL, NULL, 1);
+ zend_hash_init(&php_output_handler_conflicts, 0, NULL, NULL, 1);
+ zend_hash_init(&php_output_handler_reverse_conflicts, 0, NULL, (void (*)(void *)) zend_hash_destroy, 1);
+ php_output_direct = php_output_stdout;
+}
+/* }}} */
+
+/* {{{ void php_output_shutdown(void)
+ * Destroy module globals and the conflict and reverse conflict hash tables */
+PHPAPI void php_output_shutdown(void)
+{
+ php_output_direct = php_output_stderr;
+ zend_hash_destroy(&php_output_handler_aliases);
+ zend_hash_destroy(&php_output_handler_conflicts);
+ zend_hash_destroy(&php_output_handler_reverse_conflicts);
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_activate(TSRMLS_D)
+ * Reset output globals and setup the output handler stack */
+PHPAPI int php_output_activate(TSRMLS_D)
+{
+#ifdef ZTS
+ memset((*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(output_globals_id)], 0, sizeof(zend_output_globals));
+#else
+ memset(&output_globals, 0, sizeof(zend_output_globals));
+#endif
+
+ zend_stack_init(&OG(handlers));
+ OG(flags) |= PHP_OUTPUT_ACTIVATED;
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ void php_output_deactivate(TSRMLS_D)
+ * Destroy the output handler stack */
+PHPAPI void php_output_deactivate(TSRMLS_D)
+{
+ php_output_handler **handler = NULL;
+
+ php_output_header(TSRMLS_C);
+
+ OG(flags) ^= PHP_OUTPUT_ACTIVATED;
+ OG(active) = NULL;
+ OG(running) = NULL;
+
+ /* release all output handlers */
+ if (OG(handlers).elements) {
+ while (SUCCESS == zend_stack_top(&OG(handlers), (void *) &handler)) {
+ php_output_handler_free(handler TSRMLS_CC);
+ zend_stack_del_top(&OG(handlers));
+ }
+ zend_stack_destroy(&OG(handlers));
+ }
+
+}
+/* }}} */
+
+/* {{{ void php_output_register_constants() */
+PHPAPI void php_output_register_constants(TSRMLS_D)
+{
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_START", PHP_OUTPUT_HANDLER_START, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_WRITE", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FLUSH", PHP_OUTPUT_HANDLER_FLUSH, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEAN", PHP_OUTPUT_HANDLER_CLEAN, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FINAL", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CONT", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_END", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT);
+
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEANABLE", PHP_OUTPUT_HANDLER_CLEANABLE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FLUSHABLE", PHP_OUTPUT_HANDLER_FLUSHABLE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_REMOVABLE", PHP_OUTPUT_HANDLER_REMOVABLE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STDFLAGS", PHP_OUTPUT_HANDLER_STDFLAGS, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STARTED", PHP_OUTPUT_HANDLER_STARTED, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_DISABLED", PHP_OUTPUT_HANDLER_DISABLED, CONST_CS | CONST_PERSISTENT);
+}
+/* }}} */
+
+/* {{{ void php_output_set_status(int status TSRMLS_DC)
+ * Used by SAPIs to disable output */
+PHPAPI void php_output_set_status(int status TSRMLS_DC)
+{
+ OG(flags) = (OG(flags) & ~0xf) | (status & 0xf);
+}
+/* }}} */
+
+/* {{{ int php_output_get_status(TSRMLS_C)
+ * Get output control status */
+PHPAPI int php_output_get_status(TSRMLS_D)
+{
+ return (
+ OG(flags)
+ | (OG(active) ? PHP_OUTPUT_ACTIVE : 0)
+ | (OG(running)? PHP_OUTPUT_LOCKED : 0)
+ ) & 0xff;
+}
+/* }}} */
+
+/* {{{ int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC)
+ * Unbuffered write */
+PHPAPI int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC)
+{
+ if (OG(flags) & PHP_OUTPUT_DISABLED) {
+ return 0;
+ }
+ if (OG(flags) & PHP_OUTPUT_ACTIVATED) {
+ return sapi_module.ub_write(str, len TSRMLS_CC);
+ }
+ return php_output_direct(str, len);
+}
+/* }}} */
+
+/* {{{ int php_output_write(const char *str, size_t len TSRMLS_DC)
+ * Buffered write */
+PHPAPI int php_output_write(const char *str, size_t len TSRMLS_DC)
+{
+ if (OG(flags) & PHP_OUTPUT_DISABLED) {
+ return 0;
+ }
+ if (OG(flags) & PHP_OUTPUT_ACTIVATED) {
+ php_output_op(PHP_OUTPUT_HANDLER_WRITE, str, len TSRMLS_CC);
+ return (int) len;
+ }
+ return php_output_direct(str, len);
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_flush(TSRMLS_D)
+ * Flush the most recent output handlers buffer */
+PHPAPI int php_output_flush(TSRMLS_D)
+{
+ php_output_context context;
+
+ if (OG(active) && (OG(active)->flags & PHP_OUTPUT_HANDLER_FLUSHABLE)) {
+ php_output_context_init(&context, PHP_OUTPUT_HANDLER_FLUSH TSRMLS_CC);
+ php_output_handler_op(OG(active), &context);
+ if (context.out.data && context.out.used) {
+ zend_stack_del_top(&OG(handlers));
+ php_output_write(context.out.data, context.out.used TSRMLS_CC);
+ zend_stack_push(&OG(handlers), &OG(active), sizeof(php_output_handler *));
+ }
+ php_output_context_dtor(&context);
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ void php_output_flush_all(TSRMLS_C)
+ * Flush all output buffers subsequently */
+PHPAPI void php_output_flush_all(TSRMLS_D)
+{
+ if (OG(active)) {
+ php_output_op(PHP_OUTPUT_HANDLER_FLUSH, NULL, 0 TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_clean(TSRMLS_D)
+ * Cleans the most recent output handlers buffer if the handler is cleanable */
+PHPAPI int php_output_clean(TSRMLS_D)
+{
+ php_output_context context;
+
+ if (OG(active) && (OG(active)->flags & PHP_OUTPUT_HANDLER_CLEANABLE)) {
+ php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC);
+ php_output_handler_op(OG(active), &context);
+ php_output_context_dtor(&context);
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ void php_output_clean_all(TSRMLS_D)
+ * Cleans all output handler buffers, without regard whether the handler is cleanable */
+PHPAPI void php_output_clean_all(TSRMLS_D)
+{
+ php_output_context context;
+
+ if (OG(active)) {
+ php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC);
+ zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_clean, &context);
+ }
+}
+
+/* {{{ SUCCESS|FAILURE php_output_end(TSRMLS_D)
+ * Finalizes the most recent output handler at pops it off the stack if the handler is removable */
+PHPAPI int php_output_end(TSRMLS_D)
+{
+ if (php_output_stack_pop(PHP_OUTPUT_POP_TRY TSRMLS_CC)) {
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ void php_output_end_all(TSRMLS_D)
+ * Finalizes all output handlers and ends output buffering without regard whether a handler is removable */
+PHPAPI void php_output_end_all(TSRMLS_D)
+{
+ while (OG(active) && php_output_stack_pop(PHP_OUTPUT_POP_FORCE TSRMLS_CC));
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_discard(TSRMLS_D)
+ * Discards the most recent output handlers buffer and pops it off the stack if the handler is removable */
+PHPAPI int php_output_discard(TSRMLS_D)
+{
+ if (php_output_stack_pop(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_TRY TSRMLS_CC)) {
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ void php_output_discard_all(TSRMLS_D)
+ * Discard all output handlers and buffers without regard whether a handler is removable */
+PHPAPI void php_output_discard_all(TSRMLS_D)
+{
+ while (OG(active)) {
+ php_output_stack_pop(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_FORCE TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ int php_output_get_level(TSRMLS_D)
+ * Get output buffering level, ie. how many output handlers the stack contains */
+PHPAPI int php_output_get_level(TSRMLS_D)
+{
+ return OG(active) ? zend_stack_count(&OG(handlers)) : 0;
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_get_contents(zval *z TSRMLS_DC)
+ * Get the contents of the active output handlers buffer */
+PHPAPI int php_output_get_contents(zval *p TSRMLS_DC)
+{
+ if (OG(active)) {
+ ZVAL_STRINGL(p, OG(active)->buffer.data, OG(active)->buffer.used, 1);
+ return SUCCESS;
+ } else {
+ ZVAL_NULL(p);
+ return FAILURE;
+ }
+}
+
+/* {{{ SUCCESS|FAILURE php_output_get_length(zval *z TSRMLS_DC)
+ * Get the length of the active output handlers buffer */
+PHPAPI int php_output_get_length(zval *p TSRMLS_DC)
+{
+ if (OG(active)) {
+ ZVAL_LONG(p, OG(active)->buffer.used);
+ return SUCCESS;
+ } else {
+ ZVAL_NULL(p);
+ return FAILURE;
+ }
+}
+/* }}} */
+
+/* {{{ php_output_handler* php_output_get_active_handler(TSRMLS_D)
+ * Get active output handler */
+PHPAPI php_output_handler* php_output_get_active_handler(TSRMLS_D)
+{
+ return OG(active);
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_handler_start_default(TSRMLS_D)
+ * Start a "default output handler" */
+PHPAPI int php_output_start_default(TSRMLS_D)
+{
+ php_output_handler *handler;
+
+ handler = php_output_handler_create_internal(ZEND_STRL(php_output_default_handler_name), php_output_handler_default_func, 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC);
+ if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
+ return SUCCESS;
+ }
+ php_output_handler_free(&handler TSRMLS_CC);
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_handler_start_devnull(TSRMLS_D)
+ * Start a "null output handler" */
+PHPAPI int php_output_start_devnull(TSRMLS_D)
+{
+ php_output_handler *handler;
+
+ handler = php_output_handler_create_internal(ZEND_STRL(php_output_devnull_handler_name), php_output_handler_devnull_func, PHP_OUTPUT_HANDLER_DEFAULT_SIZE, 0 TSRMLS_CC);
+ if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
+ return SUCCESS;
+ }
+ php_output_handler_free(&handler TSRMLS_CC);
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_start_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC)
+ * Start a user level output handler */
+PHPAPI int php_output_start_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC)
+{
+ php_output_handler *handler;
+
+ if (output_handler) {
+ handler = php_output_handler_create_user(output_handler, chunk_size, flags TSRMLS_CC);
+ } else {
+ handler = php_output_handler_create_internal(ZEND_STRL(php_output_default_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC);
+ }
+ if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
+ return SUCCESS;
+ }
+ php_output_handler_free(&handler TSRMLS_CC);
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_start_internal(zval *name, php_output_handler_func_t handler, size_t chunk_size, int flags TSRMLS_DC)
+ * Start an internal output handler that does not have to maintain a non-global state */
+PHPAPI int php_output_start_internal(const char *name, size_t name_len, php_output_handler_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC)
+{
+ php_output_handler *handler;
+
+ handler = php_output_handler_create_internal(name, name_len, php_output_handler_compat_func, chunk_size, flags TSRMLS_CC);
+ php_output_handler_set_context(handler, output_handler, NULL TSRMLS_CC);
+ if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
+ return SUCCESS;
+ }
+ php_output_handler_free(&handler TSRMLS_CC);
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ php_output_handler *php_output_handler_create_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC)
+ * Create a user level output handler */
+PHPAPI php_output_handler *php_output_handler_create_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC)
+{
+ char *handler_name = NULL, *error = NULL;
+ php_output_handler *handler = NULL;
+ php_output_handler_alias_ctor_t *alias = NULL;
+ php_output_handler_user_func_t *user = NULL;
+
+ switch (Z_TYPE_P(output_handler)) {
+ case IS_NULL:
+ handler = php_output_handler_create_internal(ZEND_STRL(php_output_default_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC);
+ break;
+ case IS_STRING:
+ if (Z_STRLEN_P(output_handler) && (alias = php_output_handler_alias(Z_STRVAL_P(output_handler), Z_STRLEN_P(output_handler) TSRMLS_CC))) {
+ handler = (*alias)(Z_STRVAL_P(output_handler), Z_STRLEN_P(output_handler), chunk_size, flags TSRMLS_CC);
+ break;
+ }
+ default:
+ user = ecalloc(1, sizeof(php_output_handler_user_func_t));
+ if (SUCCESS == zend_fcall_info_init(output_handler, 0, &user->fci, &user->fcc, &handler_name, &error TSRMLS_CC)) {
+ handler = php_output_handler_init(handler_name, strlen(handler_name), chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_USER TSRMLS_CC);
+ Z_ADDREF_P(output_handler);
+ user->zoh = output_handler;
+ handler->func.user = user;
+ } else {
+ efree(user);
+ }
+ if (error) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "%s", error);
+ efree(error);
+ }
+ if (handler_name) {
+ efree(handler_name);
+ }
+ }
+
+ return handler;
+}
+/* }}} */
+
+/* {{{ php_output_handler *php_output_handler_create_internal(zval *name, php_output_handler_context_func_t handler, size_t chunk_size, int flags TSRMLS_DC)
+ * Create an internal output handler that can maintain a non-global state */
+PHPAPI php_output_handler *php_output_handler_create_internal(const char *name, size_t name_len, php_output_handler_context_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC)
+{
+ php_output_handler *handler;
+
+ handler = php_output_handler_init(name, name_len, chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_INTERNAL TSRMLS_CC);
+ handler->func.internal = output_handler;
+
+ return handler;
+}
+/* }}} */
+
+/* {{{ void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC)
+ * Set the context/state of an output handler. Calls the dtor of the previous context if there is one */
+PHPAPI void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC)
+{
+ if (handler->dtor && handler->opaq) {
+ handler->dtor(handler->opaq TSRMLS_CC);
+ }
+ handler->dtor = dtor;
+ handler->opaq = opaq;
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_handler_start(php_output_handler *handler TSRMLS_DC)
+ * Starts the set up output handler and pushes it on top of the stack. Checks for any conflicts regarding the output handler to start */
+PHPAPI int php_output_handler_start(php_output_handler *handler TSRMLS_DC)
+{
+ HashPosition pos;
+ HashTable *rconflicts;
+ php_output_handler_conflict_check_t *conflict;
+
+ if (php_output_lock_error(PHP_OUTPUT_HANDLER_START TSRMLS_CC) || !handler) {
+ return FAILURE;
+ }
+ if (SUCCESS == zend_hash_find(&php_output_handler_conflicts, handler->name, handler->name_len+1, (void *) &conflict)) {
+ if (SUCCESS != (*conflict)(handler->name, handler->name_len TSRMLS_CC)) {
+ return FAILURE;
+ }
+ }
+ if (SUCCESS == zend_hash_find(&php_output_handler_reverse_conflicts, handler->name, handler->name_len+1, (void *) &rconflicts)) {
+ for (zend_hash_internal_pointer_reset_ex(rconflicts, &pos);
+ zend_hash_get_current_data_ex(rconflicts, (void *) &conflict, &pos) == SUCCESS;
+ zend_hash_move_forward_ex(rconflicts, &pos)
+ ) {
+ if (SUCCESS != (*conflict)(handler->name, handler->name_len TSRMLS_CC)) {
+ return FAILURE;
+ }
+ }
+ }
+ /* zend_stack_push never returns SUCCESS but FAILURE or stack level */
+ if (FAILURE == (handler->level = zend_stack_push(&OG(handlers), &handler, sizeof(php_output_handler *)))) {
+ return FAILURE;
+ }
+ OG(active) = handler;
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ int php_output_handler_started(zval *name TSRMLS_DC)
+ * Check whether a certain output handler is in use */
+PHPAPI int php_output_handler_started(const char *name, size_t name_len TSRMLS_DC)
+{
+ php_output_handler ***handlers;
+ int i, count = php_output_get_level(TSRMLS_C);
+
+ if (count) {
+ handlers = (php_output_handler ***) zend_stack_base(&OG(handlers));
+
+ for (i = 0; i < count; ++i) {
+ if (name_len == (*(handlers[i]))->name_len && !memcmp((*(handlers[i]))->name, name, name_len)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ int php_output_handler_conflict(zval *handler_new, zval *handler_old TSRMLS_DC)
+ * Check whether a certain handler is in use and issue a warning that the new handler would conflict with the already used one */
+PHPAPI int php_output_handler_conflict(const char *handler_new, size_t handler_new_len, const char *handler_set, size_t handler_set_len TSRMLS_DC)
+{
+ if (php_output_handler_started(handler_set, handler_set_len TSRMLS_CC)) {
+ if (handler_new_len != handler_set_len || memcmp(handler_new, handler_set, handler_set_len)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' conflicts with '%s'", handler_new, handler_set);
+ } else {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' cannot be used twice", handler_new);
+ }
+ return 1;
+ }
+ return 0;
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_handler_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
+ * Register a conflict checking function on MINIT */
+PHPAPI int php_output_handler_conflict_register(const char *name, size_t name_len, php_output_handler_conflict_check_t check_func TSRMLS_DC)
+{
+ if (!EG(current_module)) {
+ zend_error(E_ERROR, "Cannot register an output handler conflict outside of MINIT");
+ return FAILURE;
+ }
+ return zend_hash_update(&php_output_handler_conflicts, name, name_len+1, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_handler_reverse_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
+ * Register a reverse conflict checking function on MINIT */
+PHPAPI int php_output_handler_reverse_conflict_register(const char *name, size_t name_len, php_output_handler_conflict_check_t check_func TSRMLS_DC)
+{
+ HashTable rev, *rev_ptr = NULL;
+
+ if (!EG(current_module)) {
+ zend_error(E_ERROR, "Cannot register a reverse output handler conflict outside of MINIT");
+ return FAILURE;
+ }
+
+ if (SUCCESS == zend_hash_find(&php_output_handler_reverse_conflicts, name, name_len+1, (void *) &rev_ptr)) {
+ return zend_hash_next_index_insert(rev_ptr, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
+ } else {
+ zend_hash_init(&rev, 1, NULL, NULL, 1);
+ if (SUCCESS != zend_hash_next_index_insert(&rev, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL)) {
+ zend_hash_destroy(&rev);
+ return FAILURE;
+ }
+ if (SUCCESS != zend_hash_update(&php_output_handler_reverse_conflicts, name, name_len+1, &rev, sizeof(HashTable), NULL)) {
+ zend_hash_destroy(&rev);
+ return FAILURE;
+ }
+ return SUCCESS;
+ }
+}
+/* }}} */
+
+/* {{{ php_output_handler_alias_ctor_t php_output_handler_alias(zval *name TSRMLS_DC)
+ * Get an internal output handler for a user handler if it exists */
+PHPAPI php_output_handler_alias_ctor_t *php_output_handler_alias(const char *name, size_t name_len TSRMLS_DC)
+{
+ php_output_handler_alias_ctor_t *func = NULL;
+
+ zend_hash_find(&php_output_handler_aliases, name, name_len+1, (void *) &func);
+ return func;
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_handler_alias_register(zval *name, php_output_handler_alias_ctor_t func TSRMLS_DC)
+ * Registers an internal output handler as alias for a user handler */
+PHPAPI int php_output_handler_alias_register(const char *name, size_t name_len, php_output_handler_alias_ctor_t func TSRMLS_DC)
+{
+ if (!EG(current_module)) {
+ zend_error(E_ERROR, "Cannot register an output handler alias outside of MINIT");
+ return FAILURE;
+ }
+ return zend_hash_update(&php_output_handler_aliases, name, name_len+1, &func, sizeof(php_output_handler_alias_ctor_t *), NULL);
+}
+/* }}} */
+
+/* {{{ SUCCESS|FAILURE php_output_handler_hook(php_output_handler_hook_t type, void *arg TSMRLS_DC)
+ * Output handler hook for output handler functions to check/modify the current handlers abilities */
+PHPAPI int php_output_handler_hook(php_output_handler_hook_t type, void *arg TSRMLS_DC)
+{
+ if (OG(running)) {
+ switch (type) {
+ case PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ:
+ *(void ***) arg = &OG(running)->opaq;
+ return SUCCESS;
+ case PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS:
+ *(int *) arg = OG(running)->flags;
+ return SUCCESS;
+ case PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL:
+ *(int *) arg = OG(running)->level;
+ return SUCCESS;
+ case PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE:
+ OG(running)->flags &= ~(PHP_OUTPUT_HANDLER_REMOVABLE|PHP_OUTPUT_HANDLER_CLEANABLE);
+ return SUCCESS;
+ case PHP_OUTPUT_HANDLER_HOOK_DISABLE:
+ OG(running)->flags |= PHP_OUTPUT_HANDLER_DISABLED;
+ return SUCCESS;
+ default:
+ break;
+ }
+ }
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
+ * Destroy an output handler */
+PHPAPI void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
+{
+ STR_FREE(handler->name);
+ STR_FREE(handler->buffer.data);
+ if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
+ zval_ptr_dtor(&handler->func.user->zoh);
+ efree(handler->func.user);
+ }
+ if (handler->dtor && handler->opaq) {
+ handler->dtor(handler->opaq TSRMLS_CC);
+ }
+ memset(handler, 0, sizeof(*handler));
+}
+/* }}} */
+
+/* {{{ void php_output_handler_free(php_output_handler **handler TSMRLS_DC)
+ * Destroy and free an output handler */
+PHPAPI void php_output_handler_free(php_output_handler **h TSRMLS_DC)
+{
+ if (*h) {
+ php_output_handler_dtor(*h TSRMLS_CC);
+ efree(*h);
+ *h = NULL;
+ }
+}
+/* }}} */
+
+/* void php_output_set_implicit_flush(int enabled TSRMLS_DC)
+ * Enable or disable implicit flush */
+PHPAPI void php_output_set_implicit_flush(int flush TSRMLS_DC)
+{
+ if (flush) {
+ OG(flags) |= PHP_OUTPUT_IMPLICITFLUSH;
+ } else {
+ OG(flags) &= ~PHP_OUTPUT_IMPLICITFLUSH;
+ }
+}
+/* }}} */
+
+/* {{{ char *php_output_get_start_filename(TSRMLS_D)
+ * Get the file name where output has started */
+PHPAPI const char *php_output_get_start_filename(TSRMLS_D)
+{
+ return OG(output_start_filename);
+}
+/* }}} */
+
+/* {{{ int php_output_get_start_lineno(TSRMLS_D)
+ * Get the line number where output has started */
+PHPAPI int php_output_get_start_lineno(TSRMLS_D)
+{
+ return OG(output_start_lineno);
+}
+/* }}} */
+
+/* {{{ static int php_output_lock_error(int op TSRMLS_DC)
+ * Checks whether an unallowed operation is attempted from within the output handler and issues a fatal error */
+static inline int php_output_lock_error(int op TSRMLS_DC)
+{
+ /* if there's no ob active, ob has been stopped */
+ if (op && OG(active) && OG(running)) {
+ /* fatal error */
+ php_output_deactivate(TSRMLS_C);
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_ERROR, "Cannot use output buffering in output buffering display handlers");
+ return 1;
+ }
+ return 0;
+}
+/* }}} */
+
+/* {{{ static php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC)
+ * Initialize a new output context */
+static inline php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC)
+{
+ if (!context) {
+ context = emalloc(sizeof(php_output_context));
+ }
+
+ memset(context, 0, sizeof(php_output_context));
+ TSRMLS_SET_CTX(context->tsrm_ls);
+ context->op = op;
+
+ return context;
+}
+/* }}} */
+
+/* {{{ static void php_output_context_reset(php_output_context *context)
+ * Reset an output context */
+static inline void php_output_context_reset(php_output_context *context)
+{
+ int op = context->op;
+ php_output_context_dtor(context);
+ memset(context, 0, sizeof(php_output_context));
+ context->op = op;
+}
+/* }}} */
+
+/* {{{ static void php_output_context_feed(php_output_context *context, char *, size_t, size_t)
+ * Feed output contexts input buffer */
+static inline void php_output_context_feed(php_output_context *context, char *data, size_t size, size_t used, zend_bool free)
+{
+ if (context->in.free && context->in.data) {
+ efree(context->in.data);
+ }
+ context->in.data = data;
+ context->in.used = used;
+ context->in.free = free;
+ context->in.size = size;
+}
+/* }}} */
+
+/* {{{ static void php_output_context_swap(php_output_context *context)
+ * Swap output contexts buffers */
+static inline void php_output_context_swap(php_output_context *context)
+{
+ if (context->in.free && context->in.data) {
+ efree(context->in.data);
+ }
+ context->in.data = context->out.data;
+ context->in.used = context->out.used;
+ context->in.free = context->out.free;
+ context->in.size = context->out.size;
+ context->out.data = NULL;
+ context->out.used = 0;
+ context->out.free = 0;
+ context->out.size = 0;
+}
+/* }}} */
+
+/* {{{ static void php_output_context_pass(php_output_context *context)
+ * Pass input to output buffer */
+static inline void php_output_context_pass(php_output_context *context)
+{
+ context->out.data = context->in.data;
+ context->out.used = context->in.used;
+ context->out.size = context->in.size;
+ context->out.free = context->in.free;
+ context->in.data = NULL;
+ context->in.used = 0;
+ context->in.free = 0;
+ context->in.size = 0;
+}
+/* }}} */
+
+/* {{{ static void php_output_context_dtor(php_output_context *context)
+ * Destroy the contents of an output context */
+static inline void php_output_context_dtor(php_output_context *context)
+{
+ if (context->in.free && context->in.data) {
+ efree(context->in.data);
+ context->in.data = NULL;
+ }
+ if (context->out.free && context->out.data) {
+ efree(context->out.data);
+ context->out.data = NULL;
+ }
+}
+/* }}} */
+
+/* {{{ static php_output_handler *php_output_handler_init(zval *name, size_t chunk_size, int flags TSRMLS_DC)
+ * Allocates and initializes a php_output_handler structure */
+static inline php_output_handler *php_output_handler_init(const char *name, size_t name_len, size_t chunk_size, int flags TSRMLS_DC)
+{
+ php_output_handler *handler;
+
+ handler = ecalloc(1, sizeof(php_output_handler));
+ handler->name = estrndup(name, name_len);
+ handler->name_len = name_len;
+ handler->size = chunk_size;
+ handler->flags = flags;
+ handler->buffer.size = PHP_OUTPUT_HANDLER_INITBUF_SIZE(chunk_size);
+ handler->buffer.data = emalloc(handler->buffer.size);
+
+ return handler;
+}
+/* }}} */
+
+/* {{{ static int php_output_handler_appen(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC)
+ * Appends input to the output handlers buffer and indicates whether the buffer does not have to be processed by the output handler */
+static inline int php_output_handler_append(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC)
+{
+ if (buf->used) {
+ OG(flags) |= PHP_OUTPUT_WRITTEN;
+ /* store it away */
+ if ((handler->buffer.size - handler->buffer.used) <= buf->used) {
+ size_t grow_int = PHP_OUTPUT_HANDLER_INITBUF_SIZE(handler->size);
+ size_t grow_buf = PHP_OUTPUT_HANDLER_INITBUF_SIZE(buf->used - (handler->buffer.size - handler->buffer.used));
+ size_t grow_max = MAX(grow_int, grow_buf);
+
+ handler->buffer.data = erealloc(handler->buffer.data, handler->buffer.size + grow_max);
+ handler->buffer.size += grow_max;
+ }
+ memcpy(handler->buffer.data + handler->buffer.used, buf->data, buf->used);
+ handler->buffer.used += buf->used;
+
+ /* chunked buffering */
+ if (handler->size && (handler->buffer.used >= handler->size)) {
+ /* store away errors and/or any intermediate output */
+ return OG(running) ? 1 : 0;
+ }
+ }
+ return 1;
+}
+/* }}} */
+
+/* {{{ static php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context)
+ * Output handler operation dispatcher, applying context op to the php_output_handler handler */
+static inline php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context)
+{
+ php_output_handler_status_t status;
+ int original_op = context->op;
+ PHP_OUTPUT_TSRMLS(context);
+
+#if PHP_OUTPUT_DEBUG
+ fprintf(stderr, ">>> op(%d, "
+ "handler=%p, "
+ "name=%s, "
+ "flags=%d, "
+ "buffer.data=%s, "
+ "buffer.used=%zu, "
+ "buffer.size=%zu, "
+ "in.data=%s, "
+ "in.used=%zu)\n",
+ context->op,
+ handler,
+ handler->name,
+ handler->flags,
+ handler->buffer.used?handler->buffer.data:"",
+ handler->buffer.used,
+ handler->buffer.size,
+ context->in.used?context->in.data:"",
+ context->in.used
+ );
+#endif
+
+ if (php_output_lock_error(context->op TSRMLS_CC)) {
+ /* fatal error */
+ return PHP_OUTPUT_HANDLER_FAILURE;
+ }
+
+ /* storable? */
+ if (php_output_handler_append(handler, &context->in TSRMLS_CC) && !context->op) {
+ context->op = original_op;
+ return PHP_OUTPUT_HANDLER_NO_DATA;
+ } else {
+ /* need to start? */
+ if (!(handler->flags & PHP_OUTPUT_HANDLER_STARTED)) {
+ context->op |= PHP_OUTPUT_HANDLER_START;
+ }
+
+ OG(running) = handler;
+ if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
+ zval *retval = NULL, *ob_data, *ob_mode;
+
+ MAKE_STD_ZVAL(ob_data);
+ ZVAL_STRINGL(ob_data, handler->buffer.data, handler->buffer.used, 1);
+ MAKE_STD_ZVAL(ob_mode);
+ ZVAL_LONG(ob_mode, (long) context->op);
+ zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 2, &ob_data, &ob_mode);
+
+#define PHP_OUTPUT_USER_SUCCESS(retval) (retval && !(Z_TYPE_P(retval) == IS_BOOL && Z_BVAL_P(retval)==0))
+ if (SUCCESS == zend_fcall_info_call(&handler->func.user->fci, &handler->func.user->fcc, &retval, NULL TSRMLS_CC) && PHP_OUTPUT_USER_SUCCESS(retval)) {
+ /* user handler may have returned TRUE */
+ status = PHP_OUTPUT_HANDLER_NO_DATA;
+ if (Z_TYPE_P(retval) != IS_BOOL) {
+ convert_to_string_ex(&retval);
+ if (Z_STRLEN_P(retval)) {
+ context->out.data = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval));
+ context->out.used = Z_STRLEN_P(retval);
+ context->out.free = 1;
+ status = PHP_OUTPUT_HANDLER_SUCCESS;
+ }
+ }
+ } else {
+ /* call failed, pass internal buffer along */
+ status = PHP_OUTPUT_HANDLER_FAILURE;
+ }
+
+ zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 0);
+ zval_ptr_dtor(&ob_data);
+ zval_ptr_dtor(&ob_mode);
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+
+ } else {
+
+ php_output_context_feed(context, handler->buffer.data, handler->buffer.size, handler->buffer.used, 0);
+
+ if (SUCCESS == handler->func.internal(&handler->opaq, context)) {
+ if (context->out.used) {
+ status = PHP_OUTPUT_HANDLER_SUCCESS;
+ } else {
+ status = PHP_OUTPUT_HANDLER_NO_DATA;
+ }
+ } else {
+ status = PHP_OUTPUT_HANDLER_FAILURE;
+ }
+ }
+ handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
+ OG(running) = NULL;
+ }
+
+ switch (status) {
+ case PHP_OUTPUT_HANDLER_FAILURE:
+ /* disable this handler */
+ handler->flags |= PHP_OUTPUT_HANDLER_DISABLED;
+ /* discard any output */
+ if (context->out.data && context->out.free) {
+ efree(context->out.data);
+ }
+ /* returns handlers buffer */
+ context->out.data = handler->buffer.data;
+ context->out.used = handler->buffer.used;
+ context->out.free = 1;
+ handler->buffer.data = NULL;
+ handler->buffer.used = 0;
+ handler->buffer.size = 0;
+ break;
+ case PHP_OUTPUT_HANDLER_NO_DATA:
+ /* handler ate all */
+ php_output_context_reset(context);
+ /* no break */
+ case PHP_OUTPUT_HANDLER_SUCCESS:
+ /* no more buffered data */
+ handler->buffer.used = 0;
+ handler->flags |= PHP_OUTPUT_HANDLER_PROCESSED;
+ break;
+ }
+
+ context->op = original_op;
+ return status;
+}
+/* }}} */
+
+
+/* {{{ static void php_output_op(int op, const char *str, size_t len TSRMLS_DC)
+ * Output op dispatcher, passes input and output handlers output through the output handler stack until it gets written to the SAPI */
+static inline void php_output_op(int op, const char *str, size_t len TSRMLS_DC)
+{
+ php_output_context context;
+ php_output_handler **active;
+ int obh_cnt;
+
+ if (php_output_lock_error(op TSRMLS_CC)) {
+ return;
+ }
+
+ php_output_context_init(&context, op TSRMLS_CC);
+
+ /*
+ * broken up for better performance:
+ * - apply op to the one active handler; note that OG(active) might be popped off the stack on a flush
+ * - or apply op to the handler stack
+ */
+ if (OG(active) && (obh_cnt = zend_stack_count(&OG(handlers)))) {
+ context.in.data = (char *) str;
+ context.in.used = len;
+
+ if (obh_cnt > 1) {
+ zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_op, &context);
+ } else if ((SUCCESS == zend_stack_top(&OG(handlers), (void *) &active)) && (!((*active)->flags & PHP_OUTPUT_HANDLER_DISABLED))) {
+ php_output_handler_op(*active, &context);
+ } else {
+ php_output_context_pass(&context);
+ }
+ } else {
+ context.out.data = (char *) str;
+ context.out.used = len;
+ }
+
+ if (context.out.data && context.out.used) {
+ php_output_header(TSRMLS_C);
+
+ if (!(OG(flags) & PHP_OUTPUT_DISABLED)) {
+#if PHP_OUTPUT_DEBUG
+ fprintf(stderr, "::: sapi_write('%s', %zu)\n", context.out.data, context.out.used);
+#endif
+ sapi_module.ub_write(context.out.data, context.out.used TSRMLS_CC);
+
+ if (OG(flags) & PHP_OUTPUT_IMPLICITFLUSH) {
+ sapi_flush(TSRMLS_C);
+ }
+
+ OG(flags) |= PHP_OUTPUT_SENT;
+ }
+ }
+ php_output_context_dtor(&context);
+}
+/* }}} */
+
+/* {{{ static int php_output_stack_apply_op(void *h, void *c)
+ * Operation callback for the stack apply function */
+static int php_output_stack_apply_op(void *h, void *c)
+{
+ int was_disabled;
+ php_output_handler_status_t status;
+ php_output_handler *handler = *(php_output_handler **) h;
+ php_output_context *context = (php_output_context *) c;
+
+ if ((was_disabled = (handler->flags & PHP_OUTPUT_HANDLER_DISABLED))) {
+ status = PHP_OUTPUT_HANDLER_FAILURE;
+ } else {
+ status = php_output_handler_op(handler, context);
+ }
+
+ /*
+ * handler ate all => break
+ * handler returned data or failed resp. is disabled => continue
+ */
+ switch (status) {
+ case PHP_OUTPUT_HANDLER_NO_DATA:
+ return 1;
+
+ case PHP_OUTPUT_HANDLER_SUCCESS:
+ /* swap contexts buffers, unless this is the last handler in the stack */
+ if (handler->level) {
+ php_output_context_swap(context);
+ }
+ return 0;
+
+ case PHP_OUTPUT_HANDLER_FAILURE:
+ default:
+ if (was_disabled) {
+ /* pass input along, if it's the last handler in the stack */
+ if (!handler->level) {
+ php_output_context_pass(context);
+ }
+ } else {
+ /* swap buffers, unless this is the last handler */
+ if (handler->level) {
+ php_output_context_swap(context);
+ }
+ }
+ return 0;
+ }
+}
+/* }}} */
+
+/* {{{ static int php_output_stack_apply_clean(void *h, void *c)
+ * Clean callback for the stack apply function */
+static int php_output_stack_apply_clean(void *h, void *c)
+{
+ php_output_handler *handler = *(php_output_handler **) h;
+ php_output_context *context = (php_output_context *) c;
+
+ handler->buffer.used = 0;
+ php_output_handler_op(handler, context);
+ php_output_context_reset(context);
+ return 0;
+}
+/* }}} */
+
+/* {{{ static int php_output_stack_apply_list(void *h, void *z)
+ * List callback for the stack apply function */
+static int php_output_stack_apply_list(void *h, void *z)
+{
+ php_output_handler *handler = *(php_output_handler **) h;
+ zval *array = (zval *) z;
+
+ add_next_index_stringl(array, handler->name, handler->name_len, 1);
+ return 0;
+}
+/* }}} */
+
+/* {{{ static int php_output_stack_apply_status(void *h, void *z)
+ * Status callback for the stack apply function */
+static int php_output_stack_apply_status(void *h, void *z)
+{
+ php_output_handler *handler = *(php_output_handler **) h;
+ zval *array = (zval *) z;
+
+ add_next_index_zval(array, php_output_handler_status(handler, NULL));
+
+ return 0;
+}
+
+/* {{{ static zval *php_output_handler_status(php_output_handler *handler, zval *entry)
+ * Returns an array with the status of the output handler */
+static inline zval *php_output_handler_status(php_output_handler *handler, zval *entry)
+{
+ if (!entry) {
+ MAKE_STD_ZVAL(entry);
+ array_init(entry);
+ }
+
+ add_assoc_stringl(entry, "name", handler->name, handler->name_len, 1);
+ add_assoc_long(entry, "type", (long) (handler->flags & 0xf));
+ add_assoc_long(entry, "flags", (long) handler->flags);
+ add_assoc_long(entry, "level", (long) handler->level);
+ add_assoc_long(entry, "chunk_size", (long) handler->size);
+ add_assoc_long(entry, "buffer_size", (long) handler->buffer.size);
+ add_assoc_long(entry, "buffer_used", (long) handler->buffer.used);
+
+ return entry;
+}
+/* }}} */
+
+/* {{{ static int php_output_stack_pop(int flags TSRMLS_DC)
+ * Pops an output handler off the stack */
+static inline int php_output_stack_pop(int flags TSRMLS_DC)
+{
+ php_output_context context;
+ php_output_handler **current, *orphan = OG(active);
+
+ if (!orphan) {
+ if (!(flags & PHP_OUTPUT_POP_SILENT)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to %s buffer. No buffer to %s", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send");
+ }
+ return 0;
+ } else if (!(flags & PHP_OUTPUT_POP_FORCE) && !(orphan->flags & PHP_OUTPUT_HANDLER_REMOVABLE)) {
+ if (!(flags & PHP_OUTPUT_POP_SILENT)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to %s buffer of %s (%d)", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send", orphan->name, orphan->level);
+ }
+ return 0;
+ } else {
+ php_output_context_init(&context, PHP_OUTPUT_HANDLER_FINAL TSRMLS_CC);
+
+ /* don't run the output handler if it's disabled */
+ if (!(orphan->flags & PHP_OUTPUT_HANDLER_DISABLED)) {
+ /* didn't it start yet? */
+ if (!(orphan->flags & PHP_OUTPUT_HANDLER_STARTED)) {
+ context.op |= PHP_OUTPUT_HANDLER_START;
+ }
+ /* signal that we're cleaning up */
+ if (flags & PHP_OUTPUT_POP_DISCARD) {
+ context.op |= PHP_OUTPUT_HANDLER_CLEAN;
+ }
+ php_output_handler_op(orphan, &context);
+ }
+
+ /* pop it off the stack */
+ zend_stack_del_top(&OG(handlers));
+ if (SUCCESS == zend_stack_top(&OG(handlers), (void *) &current)) {
+ OG(active) = *current;
+ } else {
+ OG(active) = NULL;
+ }
+
+ /* pass output along */
+ if (context.out.data && context.out.used && !(flags & PHP_OUTPUT_POP_DISCARD)) {
+ php_output_write(context.out.data, context.out.used TSRMLS_CC);
+ }
+
+ /* destroy the handler (after write!) */
+ php_output_handler_free(&orphan TSRMLS_CC);
+ php_output_context_dtor(&context);
+
+ return 1;
+ }
+}
+/* }}} */
+
+/* {{{ static SUCCESS|FAILURE php_output_handler_compat_func(void *ctx, php_output_context *)
+ * php_output_handler_context_func_t for php_output_handler_func_t output handlers */
+static int php_output_handler_compat_func(void **handler_context, php_output_context *output_context)
+{
+ php_output_handler_func_t func = *(php_output_handler_func_t *) handler_context;
+ PHP_OUTPUT_TSRMLS(output_context);
+
+ if (func) {
+ char *out_str = NULL;
+ uint out_len = 0;
+
+ func(output_context->in.data, output_context->in.used, &out_str, &out_len, output_context->op TSRMLS_CC);
+
+ if (out_str) {
+ output_context->out.data = out_str;
+ output_context->out.used = out_len;
+ output_context->out.free = 1;
+ } else {
+ php_output_context_pass(output_context);
+ }
+
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ static SUCCESS|FAILURE php_output_handler_default_func(void *ctx, php_output_context *)
+ * Default output handler */
+static int php_output_handler_default_func(void **handler_context, php_output_context *output_context)
+{
+ php_output_context_pass(output_context);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ static SUCCESS|FAILURE php_output_handler_devnull_func(void *ctx, php_output_context *)
+ * Null output handler */
+static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context)
+{
+ return SUCCESS;
+}
+/* }}} */
+
+/*
+ * USERLAND (nearly 1:1 of old output.c)
+ */
+
+/* {{{ proto bool ob_start([string|array user_function [, int chunk_size [, int flags]]])
+ Turn on Output Buffering (specifying an optional output handler). */
+PHP_FUNCTION(ob_start)
+{
+ zval *output_handler = NULL;
+ long chunk_size = 0;
+ long flags = PHP_OUTPUT_HANDLER_STDFLAGS;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/ll", &output_handler, &chunk_size, &flags) == FAILURE) {
+ return;
+ }
+
+ if (chunk_size < 0) {
+ chunk_size = 0;
+ }
+
+ if (php_output_start_user(output_handler, chunk_size, flags TSRMLS_CC) == FAILURE) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to create buffer");
+ RETURN_FALSE;
+ }
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool ob_flush(void)
+ Flush (send) contents of the output buffer. The last buffer content is sent to next buffer */
+PHP_FUNCTION(ob_flush)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (!OG(active)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer. No buffer to flush");
+ RETURN_FALSE;
+ }
+
+ if (SUCCESS != php_output_flush(TSRMLS_C)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer of %s (%d)", OG(active)->name, OG(active)->level);
+ RETURN_FALSE;
+ }
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool ob_clean(void)
+ Clean (delete) the current output buffer */
+PHP_FUNCTION(ob_clean)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (!OG(active)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
+ RETURN_FALSE;
+ }
+
+ if (SUCCESS != php_output_clean(TSRMLS_C)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", OG(active)->name, OG(active)->level);
+ RETURN_FALSE;
+ }
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool ob_end_flush(void)
+ Flush (send) the output buffer, and delete current output buffer */
+PHP_FUNCTION(ob_end_flush)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (!OG(active)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
+ RETURN_FALSE;
+ }
+
+ RETURN_BOOL(SUCCESS == php_output_end(TSRMLS_C));
+}
+/* }}} */
+
+/* {{{ proto bool ob_end_clean(void)
+ Clean the output buffer, and delete current output buffer */
+PHP_FUNCTION(ob_end_clean)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (!OG(active)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
+ RETURN_FALSE;
+ }
+
+ RETURN_BOOL(SUCCESS == php_output_discard(TSRMLS_C));
+}
+/* }}} */
+
+/* {{{ proto bool ob_get_flush(void)
+ Get current buffer contents, flush (send) the output buffer, and delete current output buffer */
+PHP_FUNCTION(ob_get_flush)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
+ RETURN_FALSE;
+ }
+
+ if (SUCCESS != php_output_end(TSRMLS_C)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", OG(active)->name, OG(active)->level);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool ob_get_clean(void)
+ Get current buffer contents and delete current output buffer */
+PHP_FUNCTION(ob_get_clean)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if(!OG(active)) {
+ RETURN_FALSE;
+ }
+
+ if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
+ RETURN_FALSE;
+ }
+
+ if (SUCCESS != php_output_discard(TSRMLS_C)) {
+ php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", OG(active)->name, OG(active)->level);
+ }
+}
+/* }}} */
+
+/* {{{ proto string ob_get_contents(void)
+ Return the contents of the output buffer */
+PHP_FUNCTION(ob_get_contents)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto int ob_get_level(void)
+ Return the nesting level of the output buffer */
+PHP_FUNCTION(ob_get_level)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ RETURN_LONG(php_output_get_level(TSRMLS_C));
+}
+/* }}} */
+
+/* {{{ proto int ob_get_length(void)
+ Return the length of the output buffer */
+PHP_FUNCTION(ob_get_length)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (php_output_get_length(return_value TSRMLS_CC) == FAILURE) {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto false|array ob_list_handlers()
+ List all output_buffers in an array */
+PHP_FUNCTION(ob_list_handlers)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ array_init(return_value);
+
+ if (!OG(active)) {
+ return;
+ }
+
+ zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_list, return_value);
+}
+/* }}} */
+
+/* {{{ proto false|array ob_get_status([bool full_status])
+ Return the status of the active or all output buffers */
+PHP_FUNCTION(ob_get_status)
+{
+ zend_bool full_status = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &full_status) == FAILURE) {
+ return;
+ }
+
+ array_init(return_value);
+
+ if (!OG(active)) {
+ return;
+ }
+
+ if (full_status) {
+ zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_status, return_value);
+ } else {
+ php_output_handler_status(OG(active), return_value);
+ }
+}
+/* }}} */
+
+/* {{{ proto void ob_implicit_flush([int flag])
+ Turn implicit flush on/off and is equivalent to calling flush() after every output call */
+PHP_FUNCTION(ob_implicit_flush)
+{
+ long flag = 1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flag) == FAILURE) {
+ return;
+ }
+
+ php_output_set_implicit_flush(flag TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto bool output_reset_rewrite_vars(void)
+ Reset(clear) URL rewriter values */
+PHP_FUNCTION(output_reset_rewrite_vars)
+{
+ if (php_url_scanner_reset_vars(TSRMLS_C) == SUCCESS) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto bool output_add_rewrite_var(string name, string value)
+ Add URL rewriter values */
+PHP_FUNCTION(output_add_rewrite_var)
+{
+ char *name, *value;
+ int name_len, value_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name, &name_len, &value, &value_len) == FAILURE) {
+ return;
+ }
+
+ if (php_url_scanner_add_var(name, name_len, value, value_len, 1 TSRMLS_CC) == SUCCESS) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php.h b/main/php.h
new file mode 100644
index 0000000..9a7b092
--- /dev/null
+++ b/main/php.h
@@ -0,0 +1,457 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef PHP_H
+#define PHP_H
+
+#ifdef HAVE_DMALLOC
+#include <dmalloc.h>
+#endif
+
+#define PHP_API_VERSION 20100412
+#define PHP_HAVE_STREAMS
+#define YYDEBUG 0
+
+#include "php_version.h"
+#include "zend.h"
+#include "zend_qsort.h"
+#include "php_compat.h"
+
+#include "zend_API.h"
+
+#undef sprintf
+#define sprintf php_sprintf
+
+/* PHP's DEBUG value must match Zend's ZEND_DEBUG value */
+#undef PHP_DEBUG
+#define PHP_DEBUG ZEND_DEBUG
+
+#ifdef PHP_WIN32
+# include "tsrm_win32.h"
+# include "win95nt.h"
+# ifdef PHP_EXPORTS
+# define PHPAPI __declspec(dllexport)
+# else
+# define PHPAPI __declspec(dllimport)
+# endif
+# define PHP_DIR_SEPARATOR '\\'
+# define PHP_EOL "\r\n"
+#else
+# if defined(__GNUC__) && __GNUC__ >= 4
+# define PHPAPI __attribute__ ((visibility("default")))
+# else
+# define PHPAPI
+# endif
+
+# define THREAD_LS
+# define PHP_DIR_SEPARATOR '/'
+# define PHP_EOL "\n"
+#endif
+
+#ifdef NETWARE
+/* For php_get_uname() function */
+#define PHP_UNAME "NetWare"
+#define PHP_OS PHP_UNAME
+#endif
+
+#if HAVE_ASSERT_H
+#if PHP_DEBUG
+#undef NDEBUG
+#else
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+#endif
+#include <assert.h>
+#else /* HAVE_ASSERT_H */
+#define assert(expr) ((void) (0))
+#endif /* HAVE_ASSERT_H */
+
+#define APACHE 0
+
+#if HAVE_UNIX_H
+#include <unix.h>
+#endif
+
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#if HAVE_BUILD_DEFS_H
+#include <build-defs.h>
+#endif
+
+/*
+ * This is a fast version of strlcpy which should be used, if you
+ * know the size of the destination buffer and if you know
+ * the length of the source string.
+ *
+ * size is the allocated number of bytes of dst
+ * src_size is the number of bytes excluding the NUL of src
+ */
+
+#define PHP_STRLCPY(dst, src, size, src_size) \
+ { \
+ size_t php_str_len; \
+ \
+ if (src_size >= size) \
+ php_str_len = size - 1; \
+ else \
+ php_str_len = src_size; \
+ memcpy(dst, src, php_str_len); \
+ dst[php_str_len] = '\0'; \
+ }
+
+#ifndef HAVE_STRLCPY
+BEGIN_EXTERN_C()
+PHPAPI size_t php_strlcpy(char *dst, const char *src, size_t siz);
+END_EXTERN_C()
+#undef strlcpy
+#define strlcpy php_strlcpy
+#endif
+
+#ifndef HAVE_STRLCAT
+BEGIN_EXTERN_C()
+PHPAPI size_t php_strlcat(char *dst, const char *src, size_t siz);
+END_EXTERN_C()
+#undef strlcat
+#define strlcat php_strlcat
+#endif
+
+#ifndef HAVE_STRTOK_R
+BEGIN_EXTERN_C()
+char *strtok_r(char *s, const char *delim, char **last);
+END_EXTERN_C()
+#endif
+
+#ifndef HAVE_SOCKLEN_T
+# if PHP_WIN32
+typedef int socklen_t;
+# else
+typedef unsigned int socklen_t;
+# endif
+#endif
+
+#define CREATE_MUTEX(a, b)
+#define SET_MUTEX(a)
+#define FREE_MUTEX(a)
+
+/*
+ * Then the ODBC support can use both iodbc and Solid,
+ * uncomment this.
+ * #define HAVE_ODBC (HAVE_IODBC|HAVE_SOLID)
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STDARG_H
+#include <stdarg.h>
+#else
+# if HAVE_SYS_VARARGS_H
+# include <sys/varargs.h>
+# endif
+#endif
+
+#ifndef va_copy
+# ifdef __va_copy
+# define va_copy(ap1, ap2) __va_copy((ap1), (ap2))
+# else
+# define va_copy(ap1, ap2) memcpy((&ap1), (&ap2), sizeof(va_list))
+# endif
+#endif
+
+#include "zend_hash.h"
+#include "zend_alloc.h"
+#include "zend_stack.h"
+
+#if STDC_HEADERS
+# include <string.h>
+#else
+# ifndef HAVE_MEMCPY
+# define memcpy(d, s, n) bcopy((s), (d), (n))
+# endif
+# ifndef HAVE_MEMMOVE
+# define memmove(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#ifndef HAVE_STRERROR
+char *strerror(int);
+#endif
+
+#if HAVE_PWD_H
+# ifdef PHP_WIN32
+#include "win32/param.h"
+# else
+#include <pwd.h>
+#include <sys/param.h>
+# endif
+#endif
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647L
+#endif
+
+#ifndef LONG_MIN
+#define LONG_MIN (- LONG_MAX - 1)
+#endif
+
+#ifndef INT_MAX
+#define INT_MAX 2147483647
+#endif
+
+#ifndef INT_MIN
+#define INT_MIN (- INT_MAX - 1)
+#endif
+
+#define PHP_GCC_VERSION ZEND_GCC_VERSION
+#define PHP_ATTRIBUTE_MALLOC ZEND_ATTRIBUTE_MALLOC
+#define PHP_ATTRIBUTE_FORMAT ZEND_ATTRIBUTE_FORMAT
+
+BEGIN_EXTERN_C()
+#include "snprintf.h"
+END_EXTERN_C()
+#include "spprintf.h"
+
+#define EXEC_INPUT_BUF 4096
+
+#define PHP_MIME_TYPE "application/x-httpd-php"
+
+/* macros */
+#define STR_PRINT(str) ((str)?(str):"")
+
+#ifndef MAXPATHLEN
+# ifdef PATH_MAX
+# define MAXPATHLEN PATH_MAX
+# elif defined(MAX_PATH)
+# define MAXPATHLEN MAX_PATH
+# else
+# define MAXPATHLEN 256 /* Should be safe for any weird systems that do not define it */
+# endif
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define php_ignore_value(x) (({ __typeof__ (x) __x = (x); (void) __x; }))
+#else
+# define php_ignore_value(x) ((void) (x))
+#endif
+
+/* global variables */
+#if !defined(PHP_WIN32)
+#define PHP_SLEEP_NON_VOID
+#define php_sleep sleep
+extern char **environ;
+#endif /* !defined(PHP_WIN32) */
+
+#ifdef PHP_PWRITE_64
+ssize_t pwrite(int, void *, size_t, off64_t);
+#endif
+
+#ifdef PHP_PREAD_64
+ssize_t pread(int, void *, size_t, off64_t);
+#endif
+
+BEGIN_EXTERN_C()
+void phperror(char *error);
+PHPAPI int php_write(void *buf, uint size TSRMLS_DC);
+PHPAPI int php_printf(const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 1,
+ 2);
+PHPAPI int php_get_module_initialized(void);
+PHPAPI void php_log_err(char *log_message TSRMLS_DC);
+int Debug(char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 1, 2);
+int cfgparse(void);
+END_EXTERN_C()
+
+#define php_error zend_error
+#define error_handling_t zend_error_handling_t
+
+BEGIN_EXTERN_C()
+static inline ZEND_ATTRIBUTE_DEPRECATED void php_set_error_handling(error_handling_t error_handling, zend_class_entry *exception_class TSRMLS_DC)
+{
+ zend_replace_error_handling(error_handling, exception_class, NULL TSRMLS_CC);
+}
+static inline ZEND_ATTRIBUTE_DEPRECATED void php_std_error_handling() {}
+
+PHPAPI void php_verror(const char *docref, const char *params, int type, const char *format, va_list args TSRMLS_DC) PHP_ATTRIBUTE_FORMAT(printf, 4, 0);
+
+#ifdef ZTS
+#define PHP_ATTR_FMT_OFFSET 1
+#else
+#define PHP_ATTR_FMT_OFFSET 0
+#endif
+
+/* PHPAPI void php_error(int type, const char *format, ...); */
+PHPAPI void php_error_docref0(const char *docref TSRMLS_DC, int type, const char *format, ...)
+ PHP_ATTRIBUTE_FORMAT(printf, PHP_ATTR_FMT_OFFSET + 3, PHP_ATTR_FMT_OFFSET + 4);
+PHPAPI void php_error_docref1(const char *docref TSRMLS_DC, const char *param1, int type, const char *format, ...)
+ PHP_ATTRIBUTE_FORMAT(printf, PHP_ATTR_FMT_OFFSET + 4, PHP_ATTR_FMT_OFFSET + 5);
+PHPAPI void php_error_docref2(const char *docref TSRMLS_DC, const char *param1, const char *param2, int type, const char *format, ...)
+ PHP_ATTRIBUTE_FORMAT(printf, PHP_ATTR_FMT_OFFSET + 5, PHP_ATTR_FMT_OFFSET + 6);
+#ifdef PHP_WIN32
+PHPAPI void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2 TSRMLS_DC);
+#endif
+END_EXTERN_C()
+
+#define php_error_docref php_error_docref0
+
+#define zenderror phperror
+#define zendlex phplex
+
+#define phpparse zendparse
+#define phprestart zendrestart
+#define phpin zendin
+
+#define php_memnstr zend_memnstr
+
+/* functions */
+BEGIN_EXTERN_C()
+PHPAPI extern int (*php_register_internal_extensions_func)(TSRMLS_D);
+PHPAPI int php_register_internal_extensions(TSRMLS_D);
+PHPAPI int php_mergesort(void *base, size_t nmemb, register size_t size, int (*cmp)(const void *, const void * TSRMLS_DC) TSRMLS_DC);
+PHPAPI void php_register_pre_request_shutdown(void (*func)(void *), void *userdata);
+PHPAPI void php_com_initialize(TSRMLS_D);
+PHPAPI char *php_get_current_user(TSRMLS_D);
+END_EXTERN_C()
+
+/* PHP-named Zend macro wrappers */
+#define PHP_FN ZEND_FN
+#define PHP_MN ZEND_MN
+#define PHP_NAMED_FUNCTION ZEND_NAMED_FUNCTION
+#define PHP_FUNCTION ZEND_FUNCTION
+#define PHP_METHOD ZEND_METHOD
+
+#define PHP_RAW_NAMED_FE ZEND_RAW_NAMED_FE
+#define PHP_NAMED_FE ZEND_NAMED_FE
+#define PHP_FE ZEND_FE
+#define PHP_DEP_FE ZEND_DEP_FE
+#define PHP_FALIAS ZEND_FALIAS
+#define PHP_DEP_FALIAS ZEND_DEP_FALIAS
+#define PHP_ME ZEND_ME
+#define PHP_MALIAS ZEND_MALIAS
+#define PHP_ABSTRACT_ME ZEND_ABSTRACT_ME
+#define PHP_ME_MAPPING ZEND_ME_MAPPING
+#define PHP_FE_END ZEND_FE_END
+
+#define PHP_MODULE_STARTUP_N ZEND_MODULE_STARTUP_N
+#define PHP_MODULE_SHUTDOWN_N ZEND_MODULE_SHUTDOWN_N
+#define PHP_MODULE_ACTIVATE_N ZEND_MODULE_ACTIVATE_N
+#define PHP_MODULE_DEACTIVATE_N ZEND_MODULE_DEACTIVATE_N
+#define PHP_MODULE_INFO_N ZEND_MODULE_INFO_N
+
+#define PHP_MODULE_STARTUP_D ZEND_MODULE_STARTUP_D
+#define PHP_MODULE_SHUTDOWN_D ZEND_MODULE_SHUTDOWN_D
+#define PHP_MODULE_ACTIVATE_D ZEND_MODULE_ACTIVATE_D
+#define PHP_MODULE_DEACTIVATE_D ZEND_MODULE_DEACTIVATE_D
+#define PHP_MODULE_INFO_D ZEND_MODULE_INFO_D
+
+/* Compatibility macros */
+#define PHP_MINIT ZEND_MODULE_STARTUP_N
+#define PHP_MSHUTDOWN ZEND_MODULE_SHUTDOWN_N
+#define PHP_RINIT ZEND_MODULE_ACTIVATE_N
+#define PHP_RSHUTDOWN ZEND_MODULE_DEACTIVATE_N
+#define PHP_MINFO ZEND_MODULE_INFO_N
+#define PHP_GINIT ZEND_GINIT
+#define PHP_GSHUTDOWN ZEND_GSHUTDOWN
+
+#define PHP_MINIT_FUNCTION ZEND_MODULE_STARTUP_D
+#define PHP_MSHUTDOWN_FUNCTION ZEND_MODULE_SHUTDOWN_D
+#define PHP_RINIT_FUNCTION ZEND_MODULE_ACTIVATE_D
+#define PHP_RSHUTDOWN_FUNCTION ZEND_MODULE_DEACTIVATE_D
+#define PHP_MINFO_FUNCTION ZEND_MODULE_INFO_D
+#define PHP_GINIT_FUNCTION ZEND_GINIT_FUNCTION
+#define PHP_GSHUTDOWN_FUNCTION ZEND_GSHUTDOWN_FUNCTION
+
+#define PHP_MODULE_GLOBALS ZEND_MODULE_GLOBALS
+
+
+/* Output support */
+#include "main/php_output.h"
+
+
+#include "php_streams.h"
+#include "php_memory_streams.h"
+#include "fopen_wrappers.h"
+
+
+/* Virtual current working directory support */
+#include "tsrm_virtual_cwd.h"
+
+#include "zend_constants.h"
+
+/* connection status states */
+#define PHP_CONNECTION_NORMAL 0
+#define PHP_CONNECTION_ABORTED 1
+#define PHP_CONNECTION_TIMEOUT 2
+
+#include "php_reentrancy.h"
+
+/* Finding offsets of elements within structures.
+ * Taken from the Apache code, which in turn, was taken from X code...
+ */
+
+#ifndef XtOffset
+#if defined(CRAY) || (defined(__arm) && !(defined(LINUX) || defined(__riscos__)))
+#ifdef __STDC__
+#define XtOffset(p_type, field) _Offsetof(p_type, field)
+#else
+#ifdef CRAY2
+#define XtOffset(p_type, field) \
+ (sizeof(int)*((unsigned int)&(((p_type)NULL)->field)))
+
+#else /* !CRAY2 */
+
+#define XtOffset(p_type, field) ((unsigned int)&(((p_type)NULL)->field))
+
+#endif /* !CRAY2 */
+#endif /* __STDC__ */
+#else /* ! (CRAY || __arm) */
+
+#define XtOffset(p_type, field) \
+ ((long) (((char *) (&(((p_type)NULL)->field))) - ((char *) NULL)))
+
+#endif /* !CRAY */
+#endif /* ! XtOffset */
+
+#ifndef XtOffsetOf
+#ifdef offsetof
+#define XtOffsetOf(s_type, field) offsetof(s_type, field)
+#else
+#define XtOffsetOf(s_type, field) XtOffset(s_type*, field)
+#endif
+#endif /* !XtOffsetOf */
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_compat.h b/main/php_compat.h
new file mode 100644
index 0000000..936dd52
--- /dev/null
+++ b/main/php_compat.h
@@ -0,0 +1,378 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_COMPAT_H
+#define PHP_COMPAT_H
+
+#ifdef PHP_WIN32
+#include "config.w32.h"
+#else
+#include <php_config.h>
+#endif
+
+#if defined(HAVE_BUNDLED_PCRE) || !defined(PHP_VERSION)
+#define pcre_compile php_pcre_compile
+#define pcre_compile2 php_pcre_compile2
+#define pcre_copy_substring php_pcre_copy_substring
+#define pcre_exec php_pcre_exec
+#define pcre_get_substring php_pcre_get_substring
+#define pcre_get_substring_list php_pcre_get_substring_list
+#define pcre_maketables php_pcre_maketables
+#define pcre_study php_pcre_study
+#define pcre_version php_pcre_version
+#define pcre_fullinfo php_pcre_fullinfo
+#define pcre_free php_pcre_free
+#define pcre_malloc php_pcre_malloc
+#define pcre_config php_pcre_config
+#define pcre_copy_named_substring php_pcre_copy_named_substring
+#define pcre_free_substring php_pcre_free_substring
+#define pcre_free_substring_list php_pcre_free_substring_list
+#define pcre_get_named_substring php_pcre_get_named_substring
+#define pcre_get_stringnumber php_pcre_get_stringnumber
+#define pcre_refcount php_pcre_refcount
+#define _pcre_ord2utf8 php__pcre_ord2utf8
+#define _pcre_try_flipped php__pcre_try_flipped
+#define _pcre_valid_utf8 php__pcre_valid_utf8
+#define _pcre_xclass php__pcre_xclass
+#define pcre_callout php_pcre_callout
+#define _pcre_OP_lengths php__pcre_OP_lengths
+#define _pcre_utt_names php__pcre_utt_names
+#define _pcre_default_tables php__pcre_default_tables
+#define pcre_get_stringtable_entries php_pcre_get_stringtable_entries
+#define _pcre_is_newline php__pcre_is_newline
+#define pcre_stack_free php_pcre_stack_free
+#define pcre_stack_malloc php_pcre_stack_malloc
+#define _pcre_utf8_table1 php__pcre_utf8_table1
+#define _pcre_utf8_table1_size php__pcre_utf8_table1_size
+#define _pcre_utf8_table2 php__pcre_utf8_table2
+#define _pcre_utf8_table3 php__pcre_utf8_table3
+#define _pcre_utf8_table4 php__pcre_utf8_table4
+#define _pcre_utt php__pcre_utt
+#define _pcre_utt_size php__pcre_utt_size
+#define _pcre_was_newline php__pcre_was_newline
+#define _pcre_ucd_records php__pcre_ucd_records
+#define _pcre_ucd_stage1 php__pcre_ucd_stage1
+#define _pcre_ucd_stage2 php__pcre_ucd_stage2
+#define _pcre_ucp_gentype php__pcre_ucp_gentype
+#endif
+
+#define lookup php_lookup
+#define hashTableInit php_hashTableInit
+#define hashTableDestroy php_hashTableDestroy
+#define hashTableIterInit php_hashTableIterInit
+#define hashTableIterNext php_hashTableIterNext
+
+#if defined(HAVE_LIBXML) && (defined(HAVE_XML) || defined(HAVE_XMLRPC)) && !defined(HAVE_LIBEXPAT)
+#define XML_DefaultCurrent php_XML_DefaultCurrent
+#define XML_ErrorString php_XML_ErrorString
+#define XML_ExpatVersion php_XML_ExpatVersion
+#define XML_ExpatVersionInfo php_XML_ExpatVersionInfo
+#define XML_ExternalEntityParserCreate php_XML_ExternalEntityParserCreate
+#define XML_GetBase php_XML_GetBase
+#define XML_GetBuffer php_XML_GetBuffer
+#define XML_GetCurrentByteCount php_XML_GetCurrentByteCount
+#define XML_GetCurrentByteIndex php_XML_GetCurrentByteIndex
+#define XML_GetCurrentColumnNumber php_XML_GetCurrentColumnNumber
+#define XML_GetCurrentLineNumber php_XML_GetCurrentLineNumber
+#define XML_GetErrorCode php_XML_GetErrorCode
+#define XML_GetIdAttributeIndex php_XML_GetIdAttributeIndex
+#define XML_GetInputContext php_XML_GetInputContext
+#define XML_GetSpecifiedAttributeCount php_XML_GetSpecifiedAttributeCount
+#define XmlGetUtf16InternalEncodingNS php_XmlGetUtf16InternalEncodingNS
+#define XmlGetUtf16InternalEncoding php_XmlGetUtf16InternalEncoding
+#define XmlGetUtf8InternalEncodingNS php_XmlGetUtf8InternalEncodingNS
+#define XmlGetUtf8InternalEncoding php_XmlGetUtf8InternalEncoding
+#define XmlInitEncoding php_XmlInitEncoding
+#define XmlInitEncodingNS php_XmlInitEncodingNS
+#define XmlInitUnknownEncoding php_XmlInitUnknownEncoding
+#define XmlInitUnknownEncodingNS php_XmlInitUnknownEncodingNS
+#define XML_ParseBuffer php_XML_ParseBuffer
+#define XML_Parse php_XML_Parse
+#define XML_ParserCreate_MM php_XML_ParserCreate_MM
+#define XML_ParserCreateNS php_XML_ParserCreateNS
+#define XML_ParserCreate php_XML_ParserCreate
+#define XML_ParserFree php_XML_ParserFree
+#define XmlParseXmlDecl php_XmlParseXmlDecl
+#define XmlParseXmlDeclNS php_XmlParseXmlDeclNS
+#define XmlPrologStateInitExternalEntity php_XmlPrologStateInitExternalEntity
+#define XmlPrologStateInit php_XmlPrologStateInit
+#define XML_SetAttlistDeclHandler php_XML_SetAttlistDeclHandler
+#define XML_SetBase php_XML_SetBase
+#define XML_SetCdataSectionHandler php_XML_SetCdataSectionHandler
+#define XML_SetCharacterDataHandler php_XML_SetCharacterDataHandler
+#define XML_SetCommentHandler php_XML_SetCommentHandler
+#define XML_SetDefaultHandlerExpand php_XML_SetDefaultHandlerExpand
+#define XML_SetDefaultHandler php_XML_SetDefaultHandler
+#define XML_SetDoctypeDeclHandler php_XML_SetDoctypeDeclHandler
+#define XML_SetElementDeclHandler php_XML_SetElementDeclHandler
+#define XML_SetElementHandler php_XML_SetElementHandler
+#define XML_SetEncoding php_XML_SetEncoding
+#define XML_SetEndCdataSectionHandler php_XML_SetEndCdataSectionHandler
+#define XML_SetEndDoctypeDeclHandler php_XML_SetEndDoctypeDeclHandler
+#define XML_SetEndElementHandler php_XML_SetEndElementHandler
+#define XML_SetEndNamespaceDeclHandler php_XML_SetEndNamespaceDeclHandler
+#define XML_SetEntityDeclHandler php_XML_SetEntityDeclHandler
+#define XML_SetExternalEntityRefHandlerArg php_XML_SetExternalEntityRefHandlerArg
+#define XML_SetExternalEntityRefHandler php_XML_SetExternalEntityRefHandler
+#define XML_SetNamespaceDeclHandler php_XML_SetNamespaceDeclHandler
+#define XML_SetNotationDeclHandler php_XML_SetNotationDeclHandler
+#define XML_SetNotStandaloneHandler php_XML_SetNotStandaloneHandler
+#define XML_SetParamEntityParsing php_XML_SetParamEntityParsing
+#define XML_SetProcessingInstructionHandler php_XML_SetProcessingInstructionHandler
+#define XML_SetReturnNSTriplet php_XML_SetReturnNSTriplet
+#define XML_SetStartCdataSectionHandler php_XML_SetStartCdataSectionHandler
+#define XML_SetStartDoctypeDeclHandler php_XML_SetStartDoctypeDeclHandler
+#define XML_SetStartElementHandler php_XML_SetStartElementHandler
+#define XML_SetStartNamespaceDeclHandler php_XML_SetStartNamespaceDeclHandler
+#define XML_SetUnknownEncodingHandler php_XML_SetUnknownEncodingHandler
+#define XML_SetUnparsedEntityDeclHandler php_XML_SetUnparsedEntityDeclHandler
+#define XML_SetUserData php_XML_SetUserData
+#define XML_SetXmlDeclHandler php_XML_SetXmlDeclHandler
+#define XmlSizeOfUnknownEncoding php_XmlSizeOfUnknownEncoding
+#define XML_UseParserAsHandlerArg php_XML_UseParserAsHandlerArg
+#define XmlUtf16Encode php_XmlUtf16Encode
+#define XmlUtf8Encode php_XmlUtf8Encode
+#define XML_FreeContentModel php_XML_FreeContentModel
+#define XML_MemMalloc php_XML_MemMalloc
+#define XML_MemRealloc php_XML_MemRealloc
+#define XML_MemFree php_XML_MemFree
+#define XML_UseForeignDTD php_XML_UseForeignDTD
+#define XML_GetFeatureList php_XML_GetFeatureList
+#define XML_ParserReset php_XML_ParserReset
+
+#ifdef HAVE_GD_BUNDLED
+#define any2eucjp php_gd_any2eucjp
+#define createwbmp php_gd_createwbmp
+#define empty_output_buffer php_gd_empty_output_buffer
+#define fill_input_buffer php_gd_fill_input_buffer
+#define freewbmp php_gd_freewbmp
+#define gdAlphaBlend php_gd_gdAlphaBlend
+#define gdCompareInt php_gd_gdCompareInt
+#define gdCosT php_gd_gdCosT
+#define gdCtxPrintf php_gd_gdCtxPrintf
+#define gdDPExtractData php_gd_gdDPExtractData
+#define gdFontGetGiant php_gd_gdFontGetGiant
+#define gdFontGetLarge php_gd_gdFontGetLarge
+#define gdFontGetMediumBold php_gd_gdFontGetMediumBold
+#define gdFontGetSmall php_gd_gdFontGetSmall
+#define gdFontGetTiny php_gd_gdFontGetTiny
+#define gdFontGiant php_gd_gdFontGiant
+#define gdFontGiantData php_gd_gdFontGiantData
+#define gdFontGiantRep php_gd_gdFontGiantRep
+#define gdFontLarge php_gd_gdFontLarge
+#define gdFontLargeData php_gd_gdFontLargeData
+#define gdFontLargeRep php_gd_gdFontLargeRep
+#define gdFontMediumBold php_gd_gdFontMediumBold
+#define gdFontMediumBoldData php_gd_gdFontMediumBoldData
+#define gdFontMediumBoldRep php_gd_gdFontMediumBoldRep
+#define gdFontSmall php_gd_gdFontSmall
+#define gdFontSmallData php_gd_gdFontSmallData
+#define gdFontSmallRep php_gd_gdFontSmallRep
+#define gdFontTiny php_gd_gdFontTiny
+#define gdFontTinyData php_gd_gdFontTinyData
+#define gdFontTinyRep php_gd_gdFontTinyRep
+#define gdGetBuf php_gd_gdGetBuf
+#define gdGetByte php_gd_gdGetByte
+#define gdGetC php_gd_gdGetC
+#define _gdGetColors php_gd__gdGetColors
+#define gd_getin php_gd_gd_getin
+#define gdGetInt php_gd_gdGetInt
+#define gdGetWord php_gd_gdGetWord
+#define gdImageAABlend php_gd_gdImageAABlend
+#define gdImageAALine php_gd_gdImageAALine
+#define gdImageAlphaBlending php_gd_gdImageAlphaBlending
+#define gdImageAntialias php_gd_gdImageAntialias
+#define gdImageArc php_gd_gdImageArc
+#define gdImageBrightness php_gd_gdImageBrightness
+#define gdImageChar php_gd_gdImageChar
+#define gdImageCharUp php_gd_gdImageCharUp
+#define gdImageColor php_gd_gdImageColor
+#define gdImageColorAllocate php_gd_gdImageColorAllocate
+#define gdImageColorAllocateAlpha php_gd_gdImageColorAllocateAlpha
+#define gdImageColorClosest php_gd_gdImageColorClosest
+#define gdImageColorClosestAlpha php_gd_gdImageColorClosestAlpha
+#define gdImageColorClosestHWB php_gd_gdImageColorClosestHWB
+#define gdImageColorDeallocate php_gd_gdImageColorDeallocate
+#define gdImageColorExact php_gd_gdImageColorExact
+#define gdImageColorExactAlpha php_gd_gdImageColorExactAlpha
+#define gdImageColorMatch php_gd_gdImageColorMatch
+#define gdImageColorResolve php_gd_gdImageColorResolve
+#define gdImageColorResolveAlpha php_gd_gdImageColorResolveAlpha
+#define gdImageColorTransparent php_gd_gdImageColorTransparent
+#define gdImageCompare php_gd_gdImageCompare
+#define gdImageContrast php_gd_gdImageContrast
+#define gdImageConvolution php_gd_gdImageConvolution
+#define gdImageCopy php_gd_gdImageCopy
+#define gdImageCopyMerge php_gd_gdImageCopyMerge
+#define gdImageCopyMergeGray php_gd_gdImageCopyMergeGray
+#define gdImageCopyResampled php_gd_gdImageCopyResampled
+#define gdImageCopyResized php_gd_gdImageCopyResized
+#define gdImageCreate php_gd_gdImageCreate
+#define gdImageCreateFromGd php_gd_gdImageCreateFromGd
+#define gdImageCreateFromGd2 php_gd_gdImageCreateFromGd2
+#define gdImageCreateFromGd2Ctx php_gd_gdImageCreateFromGd2Ctx
+#define gdImageCreateFromGd2Part php_gd_gdImageCreateFromGd2Part
+#define gdImageCreateFromGd2PartCtx php_gd_gdImageCreateFromGd2PartCtx
+#define gdImageCreateFromGd2PartPtr php_gd_gdImageCreateFromGd2PartPtr
+#define gdImageCreateFromGd2Ptr php_gd_gdImageCreateFromGd2Ptr
+#define gdImageCreateFromGdCtx php_gd_gdImageCreateFromGdCtx
+#define gdImageCreateFromGdPtr php_gd_gdImageCreateFromGdPtr
+#define gdImageCreateFromGif php_gd_gdImageCreateFromGif
+#define gdImageCreateFromGifCtx php_gd_gdImageCreateFromGifCtx
+#define gdImageCreateFromGifSource php_gd_gdImageCreateFromGifSource
+#define gdImageCreateFromJpeg php_gd_gdImageCreateFromJpeg
+#define gdImageCreateFromJpegCtx php_gd_gdImageCreateFromJpegCtx
+#define gdImageCreateFromJpegPtr php_gd_gdImageCreateFromJpegPtr
+#define gdImageCreateFromPng php_gd_gdImageCreateFromPng
+#define gdImageCreateFromPngCtx php_gd_gdImageCreateFromPngCtx
+#define gdImageCreateFromPngPtr php_gd_gdImageCreateFromPngPtr
+#define gdImageCreateFromPngSource php_gd_gdImageCreateFromPngSource
+#define gdImageCreateFromWBMP php_gd_gdImageCreateFromWBMP
+#define gdImageCreateFromWBMPCtx php_gd_gdImageCreateFromWBMPCtx
+#define gdImageCreateFromWBMPPtr php_gd_gdImageCreateFromWBMPPtr
+#define gdImageCreateFromXbm php_gd_gdImageCreateFromXbm
+#define gdImageCreatePaletteFromTrueColor php_gd_gdImageCreatePaletteFromTrueColor
+#define gdImageCreateTrueColor php_gd_gdImageCreateTrueColor
+#define gdImageDashedLine php_gd_gdImageDashedLine
+#define gdImageDestroy php_gd_gdImageDestroy
+#define gdImageEdgeDetectQuick php_gd_gdImageEdgeDetectQuick
+#define gdImageEllipse php_gd_gdImageEllipse
+#define gdImageEmboss php_gd_gdImageEmboss
+#define gdImageFill php_gd_gdImageFill
+#define gdImageFilledArc php_gd_gdImageFilledArc
+#define gdImageFilledEllipse php_gd_gdImageFilledEllipse
+#define gdImageFilledPolygon php_gd_gdImageFilledPolygon
+#define gdImageFilledRectangle php_gd_gdImageFilledRectangle
+#define _gdImageFillTiled php_gd__gdImageFillTiled
+#define gdImageFillToBorder php_gd_gdImageFillToBorder
+#define gdImageGaussianBlur php_gd_gdImageGaussianBlur
+#define gdImageGd php_gd_gdImageGd
+#define gdImageGd2 php_gd_gdImageGd2
+#define gdImageGd2Ptr php_gd_gdImageGd2Ptr
+#define gdImageGdPtr php_gd_gdImageGdPtr
+#define gdImageGetClip php_gd_gdImageGetClip
+#define gdImageGetPixel php_gd_gdImageGetPixel
+#define gdImageGetTrueColorPixel php_gd_gdImageGetTrueColorPixel
+#define gdImageGif php_gd_gdImageGif
+#define gdImageGifCtx php_gd_gdImageGifCtx
+#define gdImageGifPtr php_gd_gdImageGifPtr
+#define gdImageGrayScale php_gd_gdImageGrayScale
+#define gdImageInterlace php_gd_gdImageInterlace
+#define gdImageJpeg php_gd_gdImageJpeg
+#define gdImageJpegCtx php_gd_gdImageJpegCtx
+#define gdImageJpegPtr php_gd_gdImageJpegPtr
+#define gdImageLine php_gd_gdImageLine
+#define gdImageMeanRemoval php_gd_gdImageMeanRemoval
+#define gdImageNegate php_gd_gdImageNegate
+#define gdImagePaletteCopy php_gd_gdImagePaletteCopy
+#define gdImagePng php_gd_gdImagePng
+#define gdImagePngCtx php_gd_gdImagePngCtx
+#define gdImagePngCtxEx php_gd_gdImagePngCtxEx
+#define gdImagePngEx php_gd_gdImagePngEx
+#define gdImagePngPtr php_gd_gdImagePngPtr
+#define gdImagePngPtrEx php_gd_gdImagePngPtrEx
+#define gdImagePngToSink php_gd_gdImagePngToSink
+#define gdImagePolygon php_gd_gdImagePolygon
+#define gdImageRectangle php_gd_gdImageRectangle
+#define gdImageRotate php_gd_gdImageRotate
+#define gdImageRotate180 php_gd_gdImageRotate180
+#define gdImageRotate270 php_gd_gdImageRotate270
+#define gdImageRotate45 php_gd_gdImageRotate45
+#define gdImageRotate90 php_gd_gdImageRotate90
+#define gdImageSaveAlpha php_gd_gdImageSaveAlpha
+#define gdImageSelectiveBlur php_gd_gdImageSelectiveBlur
+#define gdImageSetAntiAliased php_gd_gdImageSetAntiAliased
+#define gdImageSetAntiAliasedDontBlend php_gd_gdImageSetAntiAliasedDontBlend
+#define gdImageSetBrush php_gd_gdImageSetBrush
+#define gdImageSetClip php_gd_gdImageSetClip
+#define gdImageSetPixel php_gd_gdImageSetPixel
+#define gdImageSetStyle php_gd_gdImageSetStyle
+#define gdImageSetThickness php_gd_gdImageSetThickness
+#define gdImageSetTile php_gd_gdImageSetTile
+#define gdImageSkewX php_gd_gdImageSkewX
+#define gdImageSkewY php_gd_gdImageSkewY
+#define gdImageSmooth php_gd_gdImageSmooth
+#define gdImageString php_gd_gdImageString
+#define gdImageString16 php_gd_gdImageString16
+#define gdImageStringFT php_gd_gdImageStringFT
+#define gdImageStringFTEx php_gd_gdImageStringFTEx
+#define gdImageStringTTF php_gd_gdImageStringTTF
+#define gdImageStringUp php_gd_gdImageStringUp
+#define gdImageStringUp16 php_gd_gdImageStringUp16
+#define gdImageTrueColorToPalette php_gd_gdImageTrueColorToPalette
+#define gdImageWBMP php_gd_gdImageWBMP
+#define gdImageWBMPCtx php_gd_gdImageWBMPCtx
+#define gdImageWBMPPtr php_gd_gdImageWBMPPtr
+#define gdImageXbmCtx php_gd_gdImageXbmCtx
+#define gdNewDynamicCtx php_gd_gdNewDynamicCtx
+#define gdNewDynamicCtxEx php_gd_gdNewDynamicCtxEx
+#define gdNewFileCtx php_gd_gdNewFileCtx
+#define gdNewSSCtx php_gd_gdNewSSCtx
+#define gdPutBuf php_gd_gdPutBuf
+#define gdPutC php_gd_gdPutC
+#define _gdPutColors php_gd__gdPutColors
+#define gdPutInt php_gd_gdPutInt
+#define gd_putout php_gd_gd_putout
+#define gdPutWord php_gd_gdPutWord
+#define gdSeek php_gd_gdSeek
+#define gdSinT php_gd_gdSinT
+#define gd_strtok_r php_gd_gd_strtok_r
+#define gdTell php_gd_gdTell
+#define getmbi php_gd_getmbi
+#define init_destination php_gd_init_destination
+#define init_source php_gd_init_source
+#define jpeg_gdIOCtx_dest php_gd_jpeg_gdIOCtx_dest
+#define jpeg_gdIOCtx_src php_gd_jpeg_gdIOCtx_src
+#define lsqrt php_gd_lsqrt
+#define printwbmp php_gd_printwbmp
+#define Putchar php_gd_Putchar
+#define putmbi php_gd_putmbi
+#define Putword php_gd_Putword
+#define readwbmp php_gd_readwbmp
+#define skipheader php_gd_skipheader
+#define skip_input_data php_gd_skip_input_data
+#define term_destination php_gd_term_destination
+#define term_source php_gd_term_source
+#define writewbmp php_gd_writewbmp
+#define ZeroDataBlock php_gd_ZeroDataBlock
+#define gdCacheCreate php_gd_gdCacheCreate
+#define gdCacheDelete php_gd_gdCacheDelete
+#define gdCacheGet php_gd_gdCacheGet
+#define gdFontCacheSetup php_gd_gdFontCacheSetup
+#define gdFontCacheShutdown php_gd_gdFontCacheShutdown
+#define gdFreeFontCache php_gd_gdFreeFontCache
+#endif /* HAVE_GD_BUNDLED */
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+#define XML_DTD 1
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS 1
+#endif
+
+#ifdef PHP_EXPORTS
+#define PCRE_STATIC
+#endif
+
+#endif
diff --git a/main/php_config.h.in b/main/php_config.h.in
new file mode 100644
index 0000000..a8f4e9d
--- /dev/null
+++ b/main/php_config.h.in
@@ -0,0 +1,2480 @@
+/* main/php_config.h.in. Generated from configure.in by autoheader. */
+
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define ZEND_API __attribute__ ((visibility("default")))
+# define ZEND_DLEXPORT __attribute__ ((visibility("default")))
+#else
+# define ZEND_API
+# define ZEND_DLEXPORT
+#endif
+
+#define ZEND_DLIMPORT
+
+#undef uint
+#undef ulong
+
+/* Define if you want to enable memory limit support */
+#define MEMORY_LIMIT 0
+
+
+/* */
+#undef AIX
+
+/* Whether to use native BeOS threads */
+#undef BETHREADS
+
+/* */
+#undef BUGGY_SNMPRINT_VALUE
+
+/* */
+#undef CDB_INCLUDE_FILE
+
+/* Define if system uses EBCDIC */
+#undef CHARSET_EBCDIC
+
+/* Whether to build bcmath as dynamic module */
+#undef COMPILE_DL_BCMATH
+
+/* Whether to build bz2 as dynamic module */
+#undef COMPILE_DL_BZ2
+
+/* Whether to build calendar as dynamic module */
+#undef COMPILE_DL_CALENDAR
+
+/* Whether to build ctype as dynamic module */
+#undef COMPILE_DL_CTYPE
+
+/* Whether to build curl as dynamic module */
+#undef COMPILE_DL_CURL
+
+/* Whether to build date as dynamic module */
+#undef COMPILE_DL_DATE
+
+/* Whether to build dba as dynamic module */
+#undef COMPILE_DL_DBA
+
+/* Whether to build dom as dynamic module */
+#undef COMPILE_DL_DOM
+
+/* Whether to build enchant as dynamic module */
+#undef COMPILE_DL_ENCHANT
+
+/* Whether to build ereg as dynamic module */
+#undef COMPILE_DL_EREG
+
+/* Whether to build exif as dynamic module */
+#undef COMPILE_DL_EXIF
+
+/* Whether to build fileinfo as dynamic module */
+#undef COMPILE_DL_FILEINFO
+
+/* Whether to build filter as dynamic module */
+#undef COMPILE_DL_FILTER
+
+/* Whether to build ftp as dynamic module */
+#undef COMPILE_DL_FTP
+
+/* Whether to build gd as dynamic module */
+#undef COMPILE_DL_GD
+
+/* Whether to build gettext as dynamic module */
+#undef COMPILE_DL_GETTEXT
+
+/* Whether to build gmp as dynamic module */
+#undef COMPILE_DL_GMP
+
+/* Whether to build hash as dynamic module */
+#undef COMPILE_DL_HASH
+
+/* Whether to build iconv as dynamic module */
+#undef COMPILE_DL_ICONV
+
+/* Whether to build imap as dynamic module */
+#undef COMPILE_DL_IMAP
+
+/* Whether to build interbase as dynamic module */
+#undef COMPILE_DL_INTERBASE
+
+/* Whether to build intl as dynamic module */
+#undef COMPILE_DL_INTL
+
+/* Whether to build json as dynamic module */
+#undef COMPILE_DL_JSON
+
+/* Whether to build ldap as dynamic module */
+#undef COMPILE_DL_LDAP
+
+/* Whether to build libxml as dynamic module */
+#undef COMPILE_DL_LIBXML
+
+/* Whether to build mbstring as dynamic module */
+#undef COMPILE_DL_MBSTRING
+
+/* Whether to build mcrypt as dynamic module */
+#undef COMPILE_DL_MCRYPT
+
+/* Whether to build mssql as dynamic module */
+#undef COMPILE_DL_MSSQL
+
+/* Whether to build mysql as dynamic module */
+#undef COMPILE_DL_MYSQL
+
+/* Whether to build mysqli as dynamic module */
+#undef COMPILE_DL_MYSQLI
+
+/* Whether to build mysqlnd as dynamic module */
+#undef COMPILE_DL_MYSQLND
+
+/* Whether to build oci8 as dynamic module */
+#undef COMPILE_DL_OCI8
+
+/* Whether to build odbc as dynamic module */
+#undef COMPILE_DL_ODBC
+
+/* Whether to build openssl as dynamic module */
+#undef COMPILE_DL_OPENSSL
+
+/* Whether to build pcntl as dynamic module */
+#undef COMPILE_DL_PCNTL
+
+/* Whether to build pcre as dynamic module */
+#undef COMPILE_DL_PCRE
+
+/* Whether to build pdo as dynamic module */
+#undef COMPILE_DL_PDO
+
+/* Whether to build pdo_dblib as dynamic module */
+#undef COMPILE_DL_PDO_DBLIB
+
+/* Whether to build pdo_firebird as dynamic module */
+#undef COMPILE_DL_PDO_FIREBIRD
+
+/* Whether to build pdo_mysql as dynamic module */
+#undef COMPILE_DL_PDO_MYSQL
+
+/* Whether to build pdo_oci as dynamic module */
+#undef COMPILE_DL_PDO_OCI
+
+/* Whether to build pdo_odbc as dynamic module */
+#undef COMPILE_DL_PDO_ODBC
+
+/* Whether to build pdo_pgsql as dynamic module */
+#undef COMPILE_DL_PDO_PGSQL
+
+/* Whether to build pdo_sqlite as dynamic module */
+#undef COMPILE_DL_PDO_SQLITE
+
+/* Whether to build pgsql as dynamic module */
+#undef COMPILE_DL_PGSQL
+
+/* Whether to build phar as dynamic module */
+#undef COMPILE_DL_PHAR
+
+/* Whether to build posix as dynamic module */
+#undef COMPILE_DL_POSIX
+
+/* Whether to build pspell as dynamic module */
+#undef COMPILE_DL_PSPELL
+
+/* Whether to build readline as dynamic module */
+#undef COMPILE_DL_READLINE
+
+/* Whether to build recode as dynamic module */
+#undef COMPILE_DL_RECODE
+
+/* Whether to build reflection as dynamic module */
+#undef COMPILE_DL_REFLECTION
+
+/* Whether to build session as dynamic module */
+#undef COMPILE_DL_SESSION
+
+/* Whether to build shmop as dynamic module */
+#undef COMPILE_DL_SHMOP
+
+/* Whether to build simplexml as dynamic module */
+#undef COMPILE_DL_SIMPLEXML
+
+/* Whether to build snmp as dynamic module */
+#undef COMPILE_DL_SNMP
+
+/* Whether to build soap as dynamic module */
+#undef COMPILE_DL_SOAP
+
+/* Whether to build sockets as dynamic module */
+#undef COMPILE_DL_SOCKETS
+
+/* Whether to build spl as dynamic module */
+#undef COMPILE_DL_SPL
+
+/* Whether to build sqlite3 as dynamic module */
+#undef COMPILE_DL_SQLITE3
+
+/* Whether to build standard as dynamic module */
+#undef COMPILE_DL_STANDARD
+
+/* Whether to build sybase_ct as dynamic module */
+#undef COMPILE_DL_SYBASE_CT
+
+/* Whether to build sysvmsg as dynamic module */
+#undef COMPILE_DL_SYSVMSG
+
+/* Whether to build sysvsem as dynamic module */
+#undef COMPILE_DL_SYSVSEM
+
+/* Whether to build sysvshm as dynamic module */
+#undef COMPILE_DL_SYSVSHM
+
+/* Whether to build tidy as dynamic module */
+#undef COMPILE_DL_TIDY
+
+/* Whether to build tokenizer as dynamic module */
+#undef COMPILE_DL_TOKENIZER
+
+/* Whether to build wddx as dynamic module */
+#undef COMPILE_DL_WDDX
+
+/* Whether to build xml as dynamic module */
+#undef COMPILE_DL_XML
+
+/* Whether to build xmlreader as dynamic module */
+#undef COMPILE_DL_XMLREADER
+
+/* Whether to build xmlrpc as dynamic module */
+#undef COMPILE_DL_XMLRPC
+
+/* Whether to build xmlwriter as dynamic module */
+#undef COMPILE_DL_XMLWRITER
+
+/* Whether to build xsl as dynamic module */
+#undef COMPILE_DL_XSL
+
+/* Whether to build zip as dynamic module */
+#undef COMPILE_DL_ZIP
+
+/* Whether to build zlib as dynamic module */
+#undef COMPILE_DL_ZLIB
+
+/* */
+#undef COOKIE_IO_FUNCTIONS_T
+
+/* */
+#undef COOKIE_SEEKER_USES_OFF64_T
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+#undef CRAY_STACKSEG_END
+
+/* Define if crypt_r has uses CRYPTD */
+#undef CRYPT_R_CRYPTD
+
+/* Define if struct crypt_data requires _GNU_SOURCE */
+#undef CRYPT_R_GNU_SOURCE
+
+/* Define if crypt_r uses struct crypt_data */
+#undef CRYPT_R_STRUCT_CRYPT_DATA
+
+/* Define to 1 if using `alloca.c'. */
+#undef C_ALLOCA
+
+/* Define if the target system is darwin */
+#undef DARWIN
+
+/* */
+#undef DB1_INCLUDE_FILE
+
+/* */
+#undef DB1_VERSION
+
+/* */
+#undef DB2_INCLUDE_FILE
+
+/* */
+#undef DB3_INCLUDE_FILE
+
+/* */
+#undef DB4_INCLUDE_FILE
+
+/* */
+#undef DBA_CDB
+
+/* */
+#undef DBA_CDB_BUILTIN
+
+/* */
+#undef DBA_CDB_MAKE
+
+/* */
+#undef DBA_DB1
+
+/* */
+#undef DBA_DB2
+
+/* */
+#undef DBA_DB3
+
+/* */
+#undef DBA_DB4
+
+/* */
+#undef DBA_DBM
+
+/* */
+#undef DBA_FLATFILE
+
+/* */
+#undef DBA_GDBM
+
+/* */
+#undef DBA_INIFILE
+
+/* */
+#undef DBA_NDBM
+
+/* */
+#undef DBA_QDBM
+
+/* */
+#undef DBA_TCADB
+
+/* */
+#undef DBM_INCLUDE_FILE
+
+/* */
+#undef DBM_VERSION
+
+/* */
+#undef DEFAULT_SHORT_OPEN_TAG
+
+/* Define if dlsym() requires a leading underscore in symbol names. */
+#undef DLSYM_NEEDS_UNDERSCORE
+
+/* Whether to enable chroot() function */
+#undef ENABLE_CHROOT_FUNC
+
+/* */
+#undef ENABLE_GD_TTF
+
+/* */
+#undef ENCHANT_VERSION_STRING
+
+/* */
+#undef GDBM_INCLUDE_FILE
+
+/* Whether you use GNU Pth */
+#undef GNUPTH
+
+/* Whether 3 arg set_rebind_proc() */
+#undef HAVE_3ARG_SETREBINDPROC
+
+/* Define to 1 if you have the `acosh' function. */
+#undef HAVE_ACOSH
+
+/* */
+#undef HAVE_ADABAS
+
+/* whether the compiler supports __alignof__ */
+#undef HAVE_ALIGNOF
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+ */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if you have the `alphasort' function. */
+#undef HAVE_ALPHASORT
+
+/* Whether you have AOLserver */
+#undef HAVE_AOLSERVER
+
+/* */
+#undef HAVE_APACHE
+
+/* */
+#undef HAVE_APACHE_HOOKS
+
+/* Define to 1 if you have the <ApplicationServices/ApplicationServices.h>
+ header file. */
+#undef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
+
+/* */
+#undef HAVE_AP_COMPAT_H
+
+/* */
+#undef HAVE_AP_CONFIG_H
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the <arpa/nameser.h> header file. */
+#undef HAVE_ARPA_NAMESER_H
+
+/* Define to 1 if you have the `asctime_r' function. */
+#undef HAVE_ASCTIME_R
+
+/* Define to 1 if you have the `asinh' function. */
+#undef HAVE_ASINH
+
+/* Define to 1 if you have the `asprintf' function. */
+#undef HAVE_ASPRINTF
+
+/* Define to 1 if you have the <assert.h> header file. */
+#undef HAVE_ASSERT_H
+
+/* Define to 1 if you have the `atanh' function. */
+#undef HAVE_ATANH
+
+/* whether atof() accepts INF */
+#undef HAVE_ATOF_ACCEPTS_INF
+
+/* whether atof() accepts NAN */
+#undef HAVE_ATOF_ACCEPTS_NAN
+
+/* Define to 1 if you have the `atoll' function. */
+#undef HAVE_ATOLL
+
+/* Define to 1 if you have the <atomic.h> header file. */
+#undef HAVE_ATOMIC_H
+
+/* whether the compiler supports __attribute__ ((__aligned__)) */
+#undef HAVE_ATTRIBUTE_ALIGNED
+
+/* Whether you have bcmath */
+#undef HAVE_BCMATH
+
+/* */
+#undef HAVE_BIND_TEXTDOMAIN_CODESET
+
+/* */
+#undef HAVE_BIRDSTEP
+
+/* Define if system has broken getcwd */
+#undef HAVE_BROKEN_GETCWD
+
+/* Define if your glibc borks on fopen with mode a+ */
+#undef HAVE_BROKEN_GLIBC_FOPEN_APPEND
+
+/* Whether we have librecode 3.5 */
+#undef HAVE_BROKEN_RECODE
+
+/* Konstantin Chuguev's iconv implementation */
+#undef HAVE_BSD_ICONV
+
+/* */
+#undef HAVE_BUILD_DEFS_H
+
+/* Define to 1 if gcc supports __sync_bool_compare_and_swap() a.o. */
+#undef HAVE_BUILTIN_ATOMIC
+
+/* */
+#undef HAVE_BUNDLED_PCRE
+
+/* */
+#undef HAVE_BZ2
+
+/* */
+#undef HAVE_CALENDAR
+
+/* Whether to compile with Caudium support */
+#undef HAVE_CAUDIUM
+
+/* Define to 1 if you have the `chroot' function. */
+#undef HAVE_CHROOT
+
+/* Define to 1 if you have the `clearenv' function. */
+#undef HAVE_CLEARENV
+
+/* */
+#undef HAVE_CLI0CLI_H
+
+/* */
+#undef HAVE_CLI0CORE_H
+
+/* */
+#undef HAVE_CLI0DEFS_H
+
+/* */
+#undef HAVE_CLI0ENV_H
+
+/* */
+#undef HAVE_CLI0EXT_H
+
+/* do we have clock_gettime? */
+#undef HAVE_CLOCK_GETTIME
+
+/* do we have clock_get_time? */
+#undef HAVE_CLOCK_GET_TIME
+
+/* Whether you have struct cmsghdr */
+#undef HAVE_CMSGHDR
+
+/* */
+#undef HAVE_CODBC
+
+/* */
+#undef HAVE_COLORCLOSESTHWB
+
+/* Whether you have a Continuity Server */
+#undef HAVE_CONTINUITY
+
+/* Define to 1 if you have the `CreateProcess' function. */
+#undef HAVE_CREATEPROCESS
+
+/* */
+#undef HAVE_CRYPT
+
+/* Define to 1 if you have the <crypt.h> header file. */
+#undef HAVE_CRYPT_H
+
+/* Define to 1 if you have the `crypt_r' function. */
+#undef HAVE_CRYPT_R
+
+/* Define to 1 if you have the `ctermid' function. */
+#undef HAVE_CTERMID
+
+/* Define to 1 if you have the `ctime_r' function. */
+#undef HAVE_CTIME_R
+
+/* */
+#undef HAVE_CTYPE
+
+/* */
+#undef HAVE_CURL
+
+/* */
+#undef HAVE_CURL_EASY_STRERROR
+
+/* Have cURL with GnuTLS support */
+#undef HAVE_CURL_GNUTLS
+
+/* */
+#undef HAVE_CURL_MULTI_STRERROR
+
+/* Have cURL with OpenSSL support */
+#undef HAVE_CURL_OPENSSL
+
+/* Have cURL with SSL support */
+#undef HAVE_CURL_SSL
+
+/* */
+#undef HAVE_CURL_VERSION_INFO
+
+/* Define to 1 if you have the `cuserid' function. */
+#undef HAVE_CUSERID
+
+/* */
+#undef HAVE_DBA
+
+/* Whether you want DBMaker */
+#undef HAVE_DBMAKER
+
+/* */
+#undef HAVE_DCNGETTEXT
+
+/* Whether system headers declare timezone */
+#undef HAVE_DECLARED_TIMEZONE
+
+/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't.
+ */
+#undef HAVE_DECL_TZNAME
+
+/* do we have /dev/poll? */
+#undef HAVE_DEVPOLL
+
+/* Define if the target system has /dev/arandom device */
+#undef HAVE_DEV_ARANDOM
+
+/* Define if the target system has /dev/urandom device */
+#undef HAVE_DEV_URANDOM
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* */
+#undef HAVE_DLOPEN
+
+/* Whether you have dmalloc */
+#undef HAVE_DMALLOC
+
+/* */
+#undef HAVE_DNGETTEXT
+
+/* Define to 1 if you have the <dns.h> header file. */
+#undef HAVE_DNS_H
+
+/* */
+#undef HAVE_DNS_SEARCH
+
+/* */
+#undef HAVE_DN_EXPAND
+
+/* */
+#undef HAVE_DN_SKIPNAME
+
+/* */
+#undef HAVE_DOM
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+#undef HAVE_DOPRNT
+
+/* OpenSSL 0.9.7 or later */
+#undef HAVE_DSA_DEFAULT_METHOD
+
+/* Whether to enable DTrace support */
+#undef HAVE_DTRACE
+
+/* embedded MySQL support enabled */
+#undef HAVE_EMBEDDED_MYSQLI
+
+/* */
+#undef HAVE_EMPRESS
+
+/* */
+#undef HAVE_ENCHANT
+
+/* */
+#undef HAVE_ENCHANT_BROKER_SET_PARAM
+
+/* do we have epoll? */
+#undef HAVE_EPOLL
+
+/* Define to 1 if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* */
+#undef HAVE_ESOOB
+
+/* Whether you want EXIF (metadata from images) support */
+#undef HAVE_EXIF
+
+/* Define to 1 if you have the `fabsf' function. */
+#undef HAVE_FABSF
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the `finite' function. */
+#undef HAVE_FINITE
+
+/* Define to 1 if you have the `flock' function. */
+#undef HAVE_FLOCK
+
+/* Define to 1 if you have the `floorf' function. */
+#undef HAVE_FLOORF
+
+/* Define if flush should be called explicitly after a buffered io. */
+#undef HAVE_FLUSHIO
+
+/* Define to 1 if your system has a working POSIX `fnmatch' function. */
+#undef HAVE_FNMATCH
+
+/* */
+#undef HAVE_FOPENCOOKIE
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if you have the `fpclass' function. */
+#undef HAVE_FPCLASS
+
+/* whether fpsetprec is present and usable */
+#undef HAVE_FPSETPREC
+
+/* whether FPU control word can be manipulated by inline assembler */
+#undef HAVE_FPU_INLINE_ASM_X86
+
+/* whether floatingpoint.h defines fp_except */
+#undef HAVE_FP_EXCEPT
+
+/* */
+#undef HAVE_FREETDS
+
+/* Define to 1 if you have the `ftok' function. */
+#undef HAVE_FTOK
+
+/* Whether you want FTP support */
+#undef HAVE_FTP
+
+/* Define to 1 if you have the `funopen' function. */
+#undef HAVE_FUNOPEN
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#undef HAVE_GAI_STRERROR
+
+/* Whether you have gcov */
+#undef HAVE_GCOV
+
+/* Define to 1 if you have the `gcvt' function. */
+#undef HAVE_GCVT
+
+/* */
+#undef HAVE_GDIMAGECOLORRESOLVE
+
+/* */
+#undef HAVE_GD_BUNDLED
+
+/* */
+#undef HAVE_GD_CACHE_CREATE
+
+/* */
+#undef HAVE_GD_DYNAMIC_CTX_EX
+
+/* */
+#undef HAVE_GD_FONTCACHESHUTDOWN
+
+/* */
+#undef HAVE_GD_FONTMUTEX
+
+/* */
+#undef HAVE_GD_FREEFONTCACHE
+
+/* */
+#undef HAVE_GD_GD2
+
+/* */
+#undef HAVE_GD_GIF_CREATE
+
+/* */
+#undef HAVE_GD_GIF_CTX
+
+/* */
+#undef HAVE_GD_GIF_READ
+
+/* */
+#undef HAVE_GD_IMAGEELLIPSE
+
+/* */
+#undef HAVE_GD_IMAGESETBRUSH
+
+/* */
+#undef HAVE_GD_IMAGESETTILE
+
+/* */
+#undef HAVE_GD_JPG
+
+/* */
+#undef HAVE_GD_PNG
+
+/* */
+#undef HAVE_GD_STRINGFT
+
+/* */
+#undef HAVE_GD_STRINGFTEX
+
+/* */
+#undef HAVE_GD_STRINGTTF
+
+/* */
+#undef HAVE_GD_WBMP
+
+/* */
+#undef HAVE_GD_WEBP
+
+/* */
+#undef HAVE_GD_XBM
+
+/* */
+#undef HAVE_GD_XPM
+
+/* Define if you have the getaddrinfo function */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getcwd' function. */
+#undef HAVE_GETCWD
+
+/* Define to 1 if you have the `getgrgid_r' function. */
+#undef HAVE_GETGRGID_R
+
+/* Define to 1 if you have the `getgrnam_r' function. */
+#undef HAVE_GETGRNAM_R
+
+/* Define to 1 if you have the `getgroups' function. */
+#undef HAVE_GETGROUPS
+
+/* */
+#undef HAVE_GETHOSTBYADDR
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have the `getloadavg' function. */
+#undef HAVE_GETLOADAVG
+
+/* Define to 1 if you have the `getlogin' function. */
+#undef HAVE_GETLOGIN
+
+/* Define to 1 if you have the `getopt' function. */
+#undef HAVE_GETOPT
+
+/* Define to 1 if you have the `getpgid' function. */
+#undef HAVE_GETPGID
+
+/* Define to 1 if you have the `getpid' function. */
+#undef HAVE_GETPID
+
+/* Define to 1 if you have the `getpriority' function. */
+#undef HAVE_GETPRIORITY
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#undef HAVE_GETPROTOBYNAME
+
+/* Define to 1 if you have the `getprotobynumber' function. */
+#undef HAVE_GETPROTOBYNUMBER
+
+/* Define to 1 if you have the `getpwnam_r' function. */
+#undef HAVE_GETPWNAM_R
+
+/* Define to 1 if you have the `getpwuid_r' function. */
+#undef HAVE_GETPWUID_R
+
+/* Define to 1 if you have the `getrlimit' function. */
+#undef HAVE_GETRLIMIT
+
+/* Define to 1 if you have the `getrusage' function. */
+#undef HAVE_GETRUSAGE
+
+/* Define to 1 if you have the `getservbyname' function. */
+#undef HAVE_GETSERVBYNAME
+
+/* Define to 1 if you have the `getservbyport' function. */
+#undef HAVE_GETSERVBYPORT
+
+/* Define to 1 if you have the `getsid' function. */
+#undef HAVE_GETSID
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the `getwd' function. */
+#undef HAVE_GETWD
+
+/* */
+#undef HAVE_GICONV_H
+
+/* glibc's iconv implementation */
+#undef HAVE_GLIBC_ICONV
+
+/* Define to 1 if you have the `glob' function. */
+#undef HAVE_GLOB
+
+/* */
+#undef HAVE_GMP
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#undef HAVE_GMTIME_R
+
+/* Define to 1 if you have the `grantpt' function. */
+#undef HAVE_GRANTPT
+
+/* Define to 1 if you have the <grp.h> header file. */
+#undef HAVE_GRP_H
+
+/* Have HASH Extension */
+#undef HAVE_HASH_EXT
+
+/* Define to 1 if you have the `hstrerror' function. */
+#undef HAVE_HSTRERROR
+
+/* */
+#undef HAVE_HTONL
+
+/* whether HUGE_VAL == INF */
+#undef HAVE_HUGE_VAL_INF
+
+/* whether HUGE_VAL + -HUGEVAL == NAN */
+#undef HAVE_HUGE_VAL_NAN
+
+/* Define to 1 if you have the `hypot' function. */
+#undef HAVE_HYPOT
+
+/* */
+#undef HAVE_IBASE
+
+/* */
+#undef HAVE_IBMDB2
+
+/* IBM iconv implementation */
+#undef HAVE_IBM_ICONV
+
+/* */
+#undef HAVE_ICONV
+
+/* Define to 1 if you have the <ieeefp.h> header file. */
+#undef HAVE_IEEEFP_H
+
+/* Define to 1 if you have the `if_indextoname' function. */
+#undef HAVE_IF_INDEXTONAME
+
+/* Define to 1 if you have the `if_nametoindex' function. */
+#undef HAVE_IF_NAMETOINDEX
+
+/* */
+#undef HAVE_IMAP
+
+/* */
+#undef HAVE_IMAP2000
+
+/* */
+#undef HAVE_IMAP2001
+
+/* */
+#undef HAVE_IMAP2004
+
+/* */
+#undef HAVE_IMAP_AUTH_GSS
+
+/* */
+#undef HAVE_IMAP_KRB
+
+/* */
+#undef HAVE_IMAP_MUTF7
+
+/* */
+#undef HAVE_IMAP_SSL
+
+/* */
+#undef HAVE_INET_ATON
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#undef HAVE_INET_NTOA
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the `inet_pton' function. */
+#undef HAVE_INET_PTON
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define if int32_t type is present. */
+#undef HAVE_INT32_T
+
+/* Whether intmax_t is available */
+#undef HAVE_INTMAX_T
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* */
+#undef HAVE_IODBC
+
+/* */
+#undef HAVE_IODBC_H
+
+/* Whether to enable IPv6 support */
+#undef HAVE_IPV6
+
+/* Define to 1 if you have the `isascii' function. */
+#undef HAVE_ISASCII
+
+/* Define to 1 if you have the `isfinite' function. */
+#undef HAVE_ISFINITE
+
+/* Define to 1 if you have the `isinf' function. */
+#undef HAVE_ISINF
+
+/* Define to 1 if you have the `isnan' function. */
+#undef HAVE_ISNAN
+
+/* */
+#undef HAVE_ISQLEXT_H
+
+/* */
+#undef HAVE_ISQL_H
+
+/* whether to enable JavaScript Object Serialization support */
+#undef HAVE_JSON
+
+/* Define to 1 if you have the `kill' function. */
+#undef HAVE_KILL
+
+/* do we have kqueue? */
+#undef HAVE_KQUEUE
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+#undef HAVE_LANGINFO_H
+
+/* Define to 1 if you have the `lchown' function. */
+#undef HAVE_LCHOWN
+
+/* */
+#undef HAVE_LDAP
+
+/* Define to 1 if you have the `ldap_parse_reference' function. */
+#undef HAVE_LDAP_PARSE_REFERENCE
+
+/* Define to 1 if you have the `ldap_parse_result' function. */
+#undef HAVE_LDAP_PARSE_RESULT
+
+/* LDAP SASL support */
+#undef HAVE_LDAP_SASL
+
+/* */
+#undef HAVE_LDAP_SASL_H
+
+/* */
+#undef HAVE_LDAP_SASL_SASL_H
+
+/* Define to 1 if you have the `ldap_start_tls_s' function. */
+#undef HAVE_LDAP_START_TLS_S
+
+/* */
+#undef HAVE_LIBBIND
+
+/* */
+#undef HAVE_LIBCRYPT
+
+/* */
+#undef HAVE_LIBDL
+
+/* */
+#undef HAVE_LIBDNET_STUB
+
+/* */
+#undef HAVE_LIBEDIT
+
+/* */
+#undef HAVE_LIBEXPAT
+
+/* */
+#undef HAVE_LIBFREETYPE
+
+/* */
+#undef HAVE_LIBGD
+
+/* */
+#undef HAVE_LIBGD13
+
+/* */
+#undef HAVE_LIBGD15
+
+/* */
+#undef HAVE_LIBGD20
+
+/* */
+#undef HAVE_LIBGD204
+
+/* */
+#undef HAVE_LIBICONV
+
+/* */
+#undef HAVE_LIBINTL
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* */
+#undef HAVE_LIBMCRYPT
+
+/* Whether you have libmm */
+#undef HAVE_LIBMM
+
+/* */
+#undef HAVE_LIBNSL
+
+/* */
+#undef HAVE_LIBPAM
+
+/* */
+#undef HAVE_LIBRARYMANAGER_H
+
+/* */
+#undef HAVE_LIBREADLINE
+
+/* Whether we have librecode 3.5 or higher */
+#undef HAVE_LIBRECODE
+
+/* */
+#undef HAVE_LIBRESOLV
+
+/* */
+#undef HAVE_LIBRT
+
+/* */
+#undef HAVE_LIBSOCKET
+
+/* */
+#undef HAVE_LIBT1
+
+/* */
+#undef HAVE_LIBXML
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the `link' function. */
+#undef HAVE_LINK
+
+/* Define to 1 if you have the `localeconv' function. */
+#undef HAVE_LOCALECONV
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if you have the `localtime_r' function. */
+#undef HAVE_LOCALTIME_R
+
+/* Define to 1 if you have the `lockf' function. */
+#undef HAVE_LOCKF
+
+/* Define to 1 if you have the `log1p' function. */
+#undef HAVE_LOG1P
+
+/* do we have SO_LISTENQxxx? */
+#undef HAVE_LQ_SO_LISTENQ
+
+/* do we have TCP_INFO? */
+#undef HAVE_LQ_TCP_INFO
+
+/* Define to 1 if you have the `lrand48' function. */
+#undef HAVE_LRAND48
+
+/* do we have mach_vm_read? */
+#undef HAVE_MACH_VM_READ
+
+/* Define to 1 if you have the `makedev' function. */
+#undef HAVE_MAKEDEV
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the `mblen' function. */
+#undef HAVE_MBLEN
+
+/* whether to have multibyte regex support */
+#undef HAVE_MBREGEX
+
+/* Define to 1 if you have the `mbrlen' function. */
+#undef HAVE_MBRLEN
+
+/* Define to 1 if you have the `mbsinit' function. */
+#undef HAVE_MBSINIT
+
+/* Define if your system has mbstate_t in wchar.h */
+#undef HAVE_MBSTATE_T
+
+/* whether to have multibyte string support */
+#undef HAVE_MBSTRING
+
+/* Define to 1 if you have the `memcpy' function. */
+#undef HAVE_MEMCPY
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mempcpy' function. */
+#undef HAVE_MEMPCPY
+
+/* Define if the target system has support for memory allocation using
+ mmap(MAP_ANON) */
+#undef HAVE_MEM_MMAP_ANON
+
+/* Define if the target system has support for memory allocation using
+ mmap("/dev/zero") */
+#undef HAVE_MEM_MMAP_ZERO
+
+/* Define to 1 if you have the `mkfifo' function. */
+#undef HAVE_MKFIFO
+
+/* Define to 1 if you have the `mknod' function. */
+#undef HAVE_MKNOD
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the <monetary.h> header file. */
+#undef HAVE_MONETARY_H
+
+/* Define to 1 if you have the `mremap' function. */
+#undef HAVE_MREMAP
+
+/* */
+#undef HAVE_MSSQL
+
+/* Whether you have MySQL */
+#undef HAVE_MYSQL
+
+/* */
+#undef HAVE_MYSQLILIB
+
+/* Define to 1 if you have the `nanosleep' function. */
+#undef HAVE_NANOSLEEP
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#undef HAVE_NDIR_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* Whether utf8_mime2text() has new signature */
+#undef HAVE_NEW_MIME2TEXT
+
+/* */
+#undef HAVE_NGETTEXT
+
+/* Define to 1 if you have the `nice' function. */
+#undef HAVE_NICE
+
+/* Define to 1 if you have the `nl_langinfo' function. */
+#undef HAVE_NL_LANGINFO
+
+/* Whether you have a Netscape/iPlanet/Sun Webserver */
+#undef HAVE_NSAPI
+
+/* */
+#undef HAVE_NSLDAP
+
+/* */
+#undef HAVE_OCI8
+
+/* */
+#undef HAVE_OCICOLLASSIGN
+
+/* */
+#undef HAVE_OCIENVCREATE
+
+/* */
+#undef HAVE_OCIENVNLSCREATE
+
+/* */
+#undef HAVE_OCILOBISTEMPORARY
+
+/* */
+#undef HAVE_OCISTMTFETCH2
+
+/* */
+#undef HAVE_OCI_INSTANT_CLIENT
+
+/* */
+#undef HAVE_OCI_LOB_READ2
+
+/* */
+#undef HAVE_ODBC2
+
+/* */
+#undef HAVE_ODBCSDK_H
+
+/* */
+#undef HAVE_ODBC_H
+
+/* */
+#undef HAVE_ODBC_ROUTER
+
+/* */
+#undef HAVE_OLD_COMPAT_H
+
+/* whether you have old-style readdir_r */
+#undef HAVE_OLD_READDIR_R
+
+/* Define to 1 if the oniguruma library is available */
+#undef HAVE_ONIG
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+#undef HAVE_OPENSSL_CRYPTO_H
+
+/* */
+#undef HAVE_OPENSSL_EXT
+
+/* */
+#undef HAVE_ORALDAP
+
+/* */
+#undef HAVE_ORALDAP_10
+
+/* Whether struct _zend_object_value is packed */
+#undef HAVE_PACKED_OBJECT_VALUE
+
+/* */
+#undef HAVE_PCRE
+
+/* */
+#undef HAVE_PDO_DBLIB
+
+/* */
+#undef HAVE_PDO_FIREBIRD
+
+/* Whether to build PostgreSQL for PDO support or not */
+#undef HAVE_PDO_PGSQL
+
+/* */
+#undef HAVE_PDO_SQLITELIB
+
+/* Define to 1 if you have the `perror' function. */
+#undef HAVE_PERROR
+
+/* Whether to build PostgreSQL support or not */
+#undef HAVE_PGSQL
+
+/* Whether libpq is compiled with --enable-multibyte */
+#undef HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PGTRANSACTIONSTATUS
+
+/* Whether to have pg_config.h */
+#undef HAVE_PG_CONFIG_H
+
+/* PostgreSQL 8.1 or later */
+#undef HAVE_PG_LO_CREATE
+
+/* PostgreSQL 8.4 or later */
+#undef HAVE_PG_LO_IMPORT_WITH_OID
+
+/* */
+#undef HAVE_PHP_SESSION
+
+/* Whether you have phttpd */
+#undef HAVE_PHTTPD
+
+/* Define to 1 if you have the `poll' function. */
+#undef HAVE_POLL
+
+/* do we have port framework? */
+#undef HAVE_PORT
+
+/* whether to include POSIX-like functions */
+#undef HAVE_POSIX
+
+/* whether you have POSIX readdir_r */
+#undef HAVE_POSIX_READDIR_R
+
+/* PostgreSQL 7.0.x or later */
+#undef HAVE_PQCLIENTENCODING
+
+/* Broken libpq under windows */
+#undef HAVE_PQCMDTUPLES
+
+/* PostgreSQL 7.2.0 or later */
+#undef HAVE_PQESCAPE
+
+/* PostgreSQL 9.0 or later */
+#undef HAVE_PQESCAPELITERAL
+
+/* PostgreSQL 8.1.4 or later */
+#undef HAVE_PQESCAPE_BYTEA_CONN
+
+/* PostgreSQL 8.1.4 or later */
+#undef HAVE_PQESCAPE_CONN
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQEXECPARAMS
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQEXECPREPARED
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQFREEMEM
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQFTABLE
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQGETCOPYDATA
+
+/* Older PostgreSQL */
+#undef HAVE_PQOIDVALUE
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQPARAMETERSTATUS
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQPREPARE
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQPROTOCOLVERSION
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQPUTCOPYDATA
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQPUTCOPYEND
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQRESULTERRORFIELD
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQSENDPREPARE
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQSENDQUERYPARAMS
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQSENDQUERYPREPARED
+
+/* PostgreSQL 7.4 or later */
+#undef HAVE_PQSETERRORVERBOSITY
+
+/* PostgreSQL 7.0.x or later */
+#undef HAVE_PQSETNONBLOCKING
+
+/* PostgreSQL 7.3.0 or later */
+#undef HAVE_PQUNESCAPEBYTEA
+
+/* do we have prctl? */
+#undef HAVE_PRCTL
+
+/* */
+#undef HAVE_PREAD
+
+/* */
+#undef HAVE_PSPELL
+
+/* do we have ptrace? */
+#undef HAVE_PTRACE
+
+/* Whether ptrdiff_t is available */
+#undef HAVE_PTRDIFF_T
+
+/* Define to 1 if you have the `ptsname' function. */
+#undef HAVE_PTSNAME
+
+/* Define to 1 if you have the `putenv' function. */
+#undef HAVE_PUTENV
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* */
+#undef HAVE_PWRITE
+
+/* Define to 1 if you have the `random' function. */
+#undef HAVE_RANDOM
+
+/* Define to 1 if you have the `rand_r' function. */
+#undef HAVE_RAND_R
+
+/* Define to 1 if you have the `realpath' function. */
+#undef HAVE_REALPATH
+
+/* Whether Reflection is enabled */
+#undef HAVE_REFLECTION
+
+/* 1 */
+#undef HAVE_REGEX_T_RE_MAGIC
+
+/* Define to 1 if you have the <resolv.h> header file. */
+#undef HAVE_RESOLV_H
+
+/* */
+#undef HAVE_RES_NSEARCH
+
+/* */
+#undef HAVE_RES_SEARCH
+
+/* */
+#undef HAVE_RFC822_OUTPUT_ADDRESS_LIST
+
+/* */
+#undef HAVE_RL_CALLBACK_READ_CHAR
+
+/* Define to 1 if you have the `rl_completion_matches' function. */
+#undef HAVE_RL_COMPLETION_MATCHES
+
+/* */
+#undef HAVE_RL_ON_NEW_LINE
+
+/* Whether you use Roxen */
+#undef HAVE_ROXEN
+
+/* */
+#undef HAVE_SAPDB
+
+/* Whether you have sockaddr_storage.ss_family */
+#undef HAVE_SA_SS_FAMILY
+
+/* Define to 1 if you have the `scandir' function. */
+#undef HAVE_SCANDIR
+
+/* do we have select? */
+#undef HAVE_SELECT
+
+/* */
+#undef HAVE_SEMUN
+
+/* Define to 1 if you have the `setegid' function. */
+#undef HAVE_SETEGID
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Define to 1 if you have the `seteuid' function. */
+#undef HAVE_SETEUID
+
+/* Define to 1 if you have the `setitimer' function. */
+#undef HAVE_SETITIMER
+
+/* Define to 1 if you have the `setlocale' function. */
+#undef HAVE_SETLOCALE
+
+/* Define to 1 if you have the `setpgid' function. */
+#undef HAVE_SETPGID
+
+/* Define to 1 if you have the `setpriority' function. */
+#undef HAVE_SETPRIORITY
+
+/* Define to 1 if you have the `setproctitle' function. */
+#undef HAVE_SETPROCTITLE
+
+/* Define to 1 if you have the `setsid' function. */
+#undef HAVE_SETSID
+
+/* Define to 1 if you have the `setsockopt' function. */
+#undef HAVE_SETSOCKOPT
+
+/* Define to 1 if you have the `setvbuf' function. */
+#undef HAVE_SETVBUF
+
+/* */
+#undef HAVE_SHMOP
+
+/* Define to 1 if you have the `shutdown' function. */
+#undef HAVE_SHUTDOWN
+
+/* */
+#undef HAVE_SHUTDOWN_SNMP_LOGGING
+
+/* Whether sigaction() is available */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the <signal.h> header file. */
+#undef HAVE_SIGNAL_H
+
+/* Define to 1 if you have the `sigprocmask' function. */
+#undef HAVE_SIGPROCMASK
+
+/* Define to 1 if you have the `sigsetjmp' function. */
+#undef HAVE_SIGSETJMP
+
+/* Define to 1 if you have the `sigtimedwait' function. */
+#undef HAVE_SIGTIMEDWAIT
+
+/* Define to 1 if you have the `sigwaitinfo' function. */
+#undef HAVE_SIGWAITINFO
+
+/* */
+#undef HAVE_SIMPLEXML
+
+/* Define to 1 if you have the `sin' function. */
+#undef HAVE_SIN
+
+/* */
+#undef HAVE_SNMP
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* */
+#undef HAVE_SOAP
+
+/* Whether struct sockaddr has field sa_len */
+#undef HAVE_SOCKADDR_SA_LEN
+
+/* Whether you have struct sockaddr_storage */
+#undef HAVE_SOCKADDR_STORAGE
+
+/* Define if sockaddr_un in sys/un.h contains a sun_len component */
+#undef HAVE_SOCKADDR_UN_SUN_LEN
+
+/* */
+#undef HAVE_SOCKET
+
+/* Define to 1 if you have the `socketpair' function. */
+#undef HAVE_SOCKETPAIR
+
+/* */
+#undef HAVE_SOCKETS
+
+/* Whether you have socklen_t */
+#undef HAVE_SOCKLEN_T
+
+/* */
+#undef HAVE_SOLID
+
+/* */
+#undef HAVE_SOLID_30
+
+/* */
+#undef HAVE_SOLID_35
+
+/* Whether you want SPL (Standard PHP Library) support */
+#undef HAVE_SPL
+
+/* */
+#undef HAVE_SQLCLI1_H
+
+/* */
+#undef HAVE_SQLDATASOURCES
+
+/* */
+#undef HAVE_SQLEXT_H
+
+/* */
+#undef HAVE_SQLITE3
+
+/* have commercial sqlite3 with crypto support */
+#undef HAVE_SQLITE3_KEY
+
+/* */
+#undef HAVE_SQLTYPES_H
+
+/* */
+#undef HAVE_SQLUCODE_H
+
+/* */
+#undef HAVE_SQLUNIX_H
+
+/* */
+#undef HAVE_SQL_H
+
+/* Define to 1 if you have the `srand48' function. */
+#undef HAVE_SRAND48
+
+/* Define to 1 if you have the `srandom' function. */
+#undef HAVE_SRANDOM
+
+/* Whether ssize_t is available */
+#undef HAVE_SSIZE_T
+
+/* Define to 1 if you have the `statfs' function. */
+#undef HAVE_STATFS
+
+/* Define to 1 if you have the `statvfs' function. */
+#undef HAVE_STATVFS
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_PROTOTYPES
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `std_syslog' function. */
+#undef HAVE_STD_SYSLOG
+
+/* */
+#undef HAVE_STMT_NEXT_RESULT
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the `strcoll' function. */
+#undef HAVE_STRCOLL
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the `strfmon' function. */
+#undef HAVE_STRFMON
+
+/* Define to 1 if you have the `strftime' function. */
+#undef HAVE_STRFTIME
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strndup' function. */
+#undef HAVE_STRNDUP
+
+/* Define to 1 if you have the `strnlen' function. */
+#undef HAVE_STRNLEN
+
+/* Define to 1 if you have the `strpbrk' function. */
+#undef HAVE_STRPBRK
+
+/* Define to 1 if you have the `strpncpy' function. */
+#undef HAVE_STRPNCPY
+
+/* Define to 1 if you have the `strptime' function. */
+#undef HAVE_STRPTIME
+
+/* whether strptime() declaration fails */
+#undef HAVE_STRPTIME_DECL_FAILS
+
+/* Define to 1 if you have the `strstr' function. */
+#undef HAVE_STRSTR
+
+/* Define to 1 if you have the `strtod' function. */
+#undef HAVE_STRTOD
+
+/* Define to 1 if you have the `strtok_r' function. */
+#undef HAVE_STRTOK_R
+
+/* Define to 1 if you have the `strtol' function. */
+#undef HAVE_STRTOL
+
+/* Define to 1 if you have the `strtoll' function. */
+#undef HAVE_STRTOLL
+
+/* Define to 1 if you have the `strtoul' function. */
+#undef HAVE_STRTOUL
+
+/* Define to 1 if you have the `strtoull' function. */
+#undef HAVE_STRTOULL
+
+/* whether you have struct flock */
+#undef HAVE_STRUCT_FLOCK
+
+/* Define to 1 if `st_blksize' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_BLKSIZE
+
+/* Define to 1 if `st_blocks' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_BLOCKS
+
+/* Define to 1 if `st_rdev' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_RDEV
+
+/* Define to 1 if `tm_zone' is member of `struct tm'. */
+#undef HAVE_STRUCT_TM_TM_ZONE
+
+/* Define to 1 if your `struct stat' has `st_blksize'. Deprecated, use
+ `HAVE_STRUCT_STAT_ST_BLKSIZE' instead. */
+#undef HAVE_ST_BLKSIZE
+
+/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use
+ `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */
+#undef HAVE_ST_BLOCKS
+
+/* Define to 1 if you have the <st.h> header file. */
+#undef HAVE_ST_H
+
+/* Define to 1 if your `struct stat' has `st_rdev'. Deprecated, use
+ `HAVE_STRUCT_STAT_ST_RDEV' instead. */
+#undef HAVE_ST_RDEV
+
+/* */
+#undef HAVE_SYBASE_CT
+
+/* Define to 1 if you have the `symlink' function. */
+#undef HAVE_SYMLINK
+
+/* Define if you have the __sync_fetch_and_add function */
+#undef HAVE_SYNC_FETCH_AND_ADD
+
+/* do we have sysconf? */
+#undef HAVE_SYSCONF
+
+/* Define to 1 if you have the <sysexits.h> header file. */
+#undef HAVE_SYSEXITS_H
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* */
+#undef HAVE_SYSVMSG
+
+/* */
+#undef HAVE_SYSVSEM
+
+/* */
+#undef HAVE_SYSVSHM
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+#undef HAVE_SYS_IPC_H
+
+/* Define to 1 if you have the <sys/loadavg.h> header file. */
+#undef HAVE_SYS_LOADAVG_H
+
+/* Define to 1 if you have the <sys/mkdev.h> header file. */
+#undef HAVE_SYS_MKDEV_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/mount.h> header file. */
+#undef HAVE_SYS_MOUNT_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#undef HAVE_SYS_POLL_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/sdt.h> header file. */
+#undef HAVE_SYS_SDT_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/statfs.h> header file. */
+#undef HAVE_SYS_STATFS_H
+
+/* Define to 1 if you have the <sys/statvfs.h> header file. */
+#undef HAVE_SYS_STATVFS_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/sysexits.h> header file. */
+#undef HAVE_SYS_SYSEXITS_H
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#undef HAVE_SYS_TIMES_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#undef HAVE_SYS_UIO_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#undef HAVE_SYS_UTSNAME_H
+
+/* Define to 1 if you have the <sys/varargs.h> header file. */
+#undef HAVE_SYS_VARARGS_H
+
+/* Define to 1 if you have the <sys/vfs.h> header file. */
+#undef HAVE_SYS_VFS_H
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the `tempnam' function. */
+#undef HAVE_TEMPNAM
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* */
+#undef HAVE_TIDY
+
+/* */
+#undef HAVE_TIDYOPTGETDOC
+
+/* do we have times? */
+#undef HAVE_TIMES
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* whether you have tm_gmtoff in struct tm */
+#undef HAVE_TM_GMTOFF
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+ `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#undef HAVE_TM_ZONE
+
+/* Whether you have a working ttyname_r */
+#undef HAVE_TTYNAME_R
+
+/* Define to 1 if you have the <tuxmodule.h> header file. */
+#undef HAVE_TUXMODULE_H
+
+/* Define to 1 if you don't have `tm_zone' but do have the external array
+ `tzname'. */
+#undef HAVE_TZNAME
+
+/* Define to 1 if you have the `tzset' function. */
+#undef HAVE_TZSET
+
+/* */
+#undef HAVE_UDBCEXT_H
+
+/* Define if uint32_t type is present. */
+#undef HAVE_UINT32_T
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* */
+#undef HAVE_UNIXODBC
+
+/* Define to 1 if you have the <unix.h> header file. */
+#undef HAVE_UNIX_H
+
+/* Define to 1 if you have the `unlockpt' function. */
+#undef HAVE_UNLOCKPT
+
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
+/* */
+#undef HAVE_UODBC
+
+/* Define to 1 if you have the `usleep' function. */
+#undef HAVE_USLEEP
+
+/* Define to 1 if you have the `utime' function. */
+#undef HAVE_UTIME
+
+/* Define to 1 if you have the `utimes' function. */
+#undef HAVE_UTIMES
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
+#undef HAVE_UTIME_NULL
+
+/* Wether struct utsname has domainname */
+#undef HAVE_UTSNAME_DOMAINNAME
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `vprintf' function. */
+#undef HAVE_VPRINTF
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 if you have the `wait3' function. */
+#undef HAVE_WAIT3
+
+/* */
+#undef HAVE_WAITPID
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#undef HAVE_WCHAR_H
+
+/* */
+#undef HAVE_WDDX
+
+/* */
+#undef HAVE_XML
+
+/* Define to 1 if you have the <xmlparse.h> header file. */
+#undef HAVE_XMLPARSE_H
+
+/* */
+#undef HAVE_XMLREADER
+
+/* */
+#undef HAVE_XMLRPC
+
+/* Define to 1 if you have the <xmltok.h> header file. */
+#undef HAVE_XMLTOK_H
+
+/* */
+#undef HAVE_XMLWRITER
+
+/* */
+#undef HAVE_XSL
+
+/* */
+#undef HAVE_XSL_EXSLT
+
+/* */
+#undef HAVE_YP_GET_DEFAULT_DOMAIN
+
+/* */
+#undef HAVE_ZIP
+
+/* */
+#undef HAVE_ZLIB
+
+/* whether _controlfp is present usable */
+#undef HAVE__CONTROLFP
+
+/* whether _controlfp_s is present and usable */
+#undef HAVE__CONTROLFP_S
+
+/* whether _FPU_SETCW is present and usable */
+#undef HAVE__FPU_SETCW
+
+/* */
+#undef HPUX
+
+/* */
+#undef HSREGEX
+
+/* iconv() is aliased to libiconv() in -liconv */
+#undef ICONV_ALIASED_LIBICONV
+
+/* Whether iconv supports error no or not */
+#undef ICONV_SUPPORTS_ERRNO
+
+/* */
+#undef ISOLARIS
+
+/* */
+#undef LINUX
+
+/* Whether asctime_r is declared */
+#undef MISSING_ASCTIME_R_DECL
+
+/* Whether ctime_r is declared */
+#undef MISSING_CTIME_R_DECL
+
+/* */
+#undef MISSING_FCLOSE_DECL
+
+/* Whether gmtime_r is declared */
+#undef MISSING_GMTIME_R_DECL
+
+/* Whether localtime_r is declared */
+#undef MISSING_LOCALTIME_R_DECL
+
+/* */
+#undef MISSING_MSGHDR_MSGFLAGS
+
+/* Whether strtok_r is declared */
+#undef MISSING_STRTOK_R_DECL
+
+/* Whether mysqlnd is enabled */
+#undef MYSQLI_USE_MYSQLND
+
+/* Enable compressed protocol support */
+#undef MYSQLND_COMPRESSION_WANTED
+
+/* Enable SSL support */
+#undef MYSQLND_SSL_SUPPORTED
+
+/* Whether mysqlnd is enabled */
+#undef MYSQL_USE_MYSQLND
+
+/* */
+#undef NDBM_INCLUDE_FILE
+
+/* */
+#undef NEUTRINO
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* */
+#undef PDO_MYSQL_UNIX_ADDR
+
+/* Whether pdo_mysql uses mysqlnd */
+#undef PDO_USE_MYSQLND
+
+/* */
+#undef PHAR_HASH_OK
+
+/* */
+#undef PHAR_HAVE_OPENSSL
+
+/* */
+#undef PHP_APACHE_HAVE_CLIENT_FD
+
+/* Whether the system supports BlowFish salt */
+#undef PHP_BLOWFISH_CRYPT
+
+/* PHP build date */
+#undef PHP_BUILD_DATE
+
+/* Define if your system has fork/vfork/CreateProcess */
+#undef PHP_CAN_SUPPORT_PROC_OPEN
+
+/* */
+#undef PHP_CURL_URL_WRAPPERS
+
+/* Whether the system supports extended DES salt */
+#undef PHP_EXT_DES_CRYPT
+
+/* fpm group name */
+#undef PHP_FPM_GROUP
+
+/* fpm user name */
+#undef PHP_FPM_USER
+
+/* Whether you have HP-UX 10.x */
+#undef PHP_HPUX_TIME_R
+
+/* Path to iconv.h */
+#undef PHP_ICONV_H_PATH
+
+/* Which iconv implementation to use */
+#undef PHP_ICONV_IMPL
+
+/* Whether you have IRIX-style functions */
+#undef PHP_IRIX_TIME_R
+
+/* Whether the system supports MD5 salt */
+#undef PHP_MD5_CRYPT
+
+/* */
+#undef PHP_MHASH_BC
+
+/* */
+#undef PHP_MYSQL_UNIX_SOCK_ADDR
+
+/* */
+#undef PHP_OCI8_DEF_DIR
+
+/* */
+#undef PHP_OCI8_DEF_SHARED_LIBADD
+
+/* define to 1 if oniguruma has an invalid entry for KOI8 encoding */
+#undef PHP_ONIG_BAD_KOI8_ENTRY
+
+/* Define to 1 if the bundled oniguruma is used */
+#undef PHP_ONIG_BUNDLED
+
+/* uname output */
+#undef PHP_OS
+
+/* */
+#undef PHP_PDO_OCI_CLIENT_VERSION
+
+/* whether pread64 is default */
+#undef PHP_PREAD_64
+
+/* whether pwrite64 is default */
+#undef PHP_PWRITE_64
+
+/* Whether the system supports SHA256 salt */
+#undef PHP_SHA256_CRYPT
+
+/* Whether the system supports SHA512 salt */
+#undef PHP_SHA512_CRYPT
+
+/* */
+#undef PHP_SIGCHILD
+
+/* Whether the system supports standard DES salt */
+#undef PHP_STD_DES_CRYPT
+
+/* uname -a output */
+#undef PHP_UNAME
+
+/* Whether PHP has to use its own crypt_r for blowfish, des and ext des */
+#undef PHP_USE_PHP_CRYPT_R
+
+/* whether write(2) works */
+#undef PHP_WRITE_STDOUT
+
+/* /proc/pid/mem interface */
+#undef PROC_MEM_FILE
+
+/* Whether to use Pthreads */
+#undef PTHREADS
+
+/* */
+#undef QDBM_INCLUDE_FILE
+
+/* */
+#undef REGEX
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Whether to use Roxen in ZTS mode */
+#undef ROXEN_USE_ZTS
+
+/* The size of `char', as computed by sizeof. */
+#undef SIZEOF_CHAR
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* Size of intmax_t */
+#undef SIZEOF_INTMAX_T
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `long int', as computed by sizeof. */
+#undef SIZEOF_LONG_INT
+
+/* The size of `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of `long long int', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG_INT
+
+/* Size of ptrdiff_t */
+#undef SIZEOF_PTRDIFF_T
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* Size of ssize_t */
+#undef SIZEOF_SSIZE_T
+
+/* */
+#undef SOLARIS
+
+/* have sqlite3 with column metadata enabled */
+#undef SQLITE_ENABLE_COLUMN_METADATA
+
+/* have sqlite3 with extension support */
+#undef SQLITE_OMIT_LOAD_EXTENSION
+
+/* Needed in sqlunix.h for wchar defs */
+#undef SS_FBX
+
+/* Needed in sqlunix.h */
+#undef SS_LINUX
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at runtime.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+#undef STACK_DIRECTION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* */
+#undef TCADB_INCLUDE_FILE
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* */
+#undef TSRM_ST
+
+/* */
+#undef UNDEF_THREADS_HACK
+
+/* */
+#undef UNIXWARE
+
+/* whether to check multibyte regex backtrack */
+#undef USE_COMBINATION_EXPLOSION_CHECK
+
+/* */
+#undef USE_GD_IMGSTRTTF
+
+/* */
+#undef USE_GD_JISX0208
+
+/* Define if cross-process locking is required by accept() */
+#undef USE_LOCKING
+
+/* */
+#undef USE_TRANSFER_TABLES
+
+/* whether you want Pi3Web support */
+#undef WITH_PI3WEB
+
+/* */
+#undef WITH_ZEUS
+
+/* Define if processor uses big-endian word */
+#undef WORDS_BIGENDIAN
+
+/* Whether sprintf is broken */
+#undef ZEND_BROKEN_SPRINTF
+
+/* */
+#undef ZEND_DEBUG
+
+/* Define if double cast to long preserves least significant bits */
+#undef ZEND_DVAL_TO_LVAL_CAST_OK
+
+/* */
+#undef ZEND_MM_ALIGNMENT
+
+/* */
+#undef ZEND_MM_ALIGNMENT_LOG2
+
+/* Use zend signal handling */
+#undef ZEND_SIGNALS
+
+/* virtual machine dispatch method */
+#undef ZEND_VM_KIND
+
+/* */
+#undef ZTS
+
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* */
+#undef in_addr_t
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to `unsigned int ' if <sys/types.h> does not define. */
+#undef uint
+
+/* Define to `unsigned long ' if <sys/types.h> does not define. */
+#undef ulong
+
+
+#ifndef ZEND_ACCONFIG_H_NO_C_PROTOS
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_IEEEFP_H
+# include <ieeefp.h>
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if ZEND_BROKEN_SPRINTF
+int zend_sprintf(char *buffer, const char *format, ...);
+#else
+# define zend_sprintf sprintf
+#endif
+
+#include <math.h>
+
+/* To enable the is_nan, is_infinite and is_finite PHP functions */
+#ifdef NETWARE
+ #define HAVE_ISNAN 1
+ #define HAVE_ISINF 1
+ #define HAVE_ISFINITE 1
+#endif
+
+#ifndef zend_isnan
+#ifdef HAVE_ISNAN
+#define zend_isnan(a) isnan(a)
+#elif defined(HAVE_FPCLASS)
+#define zend_isnan(a) ((fpclass(a) == FP_SNAN) || (fpclass(a) == FP_QNAN))
+#else
+#define zend_isnan(a) 0
+#endif
+#endif
+
+#ifdef HAVE_ISINF
+#define zend_isinf(a) isinf(a)
+#elif defined(INFINITY)
+/* Might not work, but is required by ISO C99 */
+#define zend_isinf(a) (((a)==INFINITY)?1:0)
+#elif defined(HAVE_FPCLASS)
+#define zend_isinf(a) ((fpclass(a) == FP_PINF) || (fpclass(a) == FP_NINF))
+#else
+#define zend_isinf(a) 0
+#endif
+
+#ifdef HAVE_FINITE
+#define zend_finite(a) finite(a)
+#elif defined(HAVE_ISFINITE) || defined(isfinite)
+#define zend_finite(a) isfinite(a)
+#elif defined(fpclassify)
+#define zend_finite(a) ((fpclassify((a))!=FP_INFINITE&&fpclassify((a))!=FP_NAN)?1:0)
+#else
+#define zend_finite(a) (zend_isnan(a) ? 0 : zend_isinf(a) ? 0 : 1)
+#endif
+
+#endif /* ifndef ZEND_ACCONFIG_H_NO_C_PROTOS */
+
+#ifdef NETWARE
+#ifdef USE_WINSOCK
+#/*This detection against winsock is of no use*/ undef HAVE_SOCKLEN_T
+#/*This detection against winsock is of no use*/ undef HAVE_SYS_SOCKET_H
+#endif
+#endif
+
+#undef PTHREADS
+
diff --git a/main/php_content_types.c b/main/php_content_types.c
new file mode 100644
index 0000000..c443397
--- /dev/null
+++ b/main/php_content_types.c
@@ -0,0 +1,100 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+#include "SAPI.h"
+#include "rfc1867.h"
+
+#include "php_content_types.h"
+
+/* {{{ php_post_entries[]
+ */
+static sapi_post_entry php_post_entries[] = {
+ { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, php_std_post_handler },
+ { MULTIPART_CONTENT_TYPE, sizeof(MULTIPART_CONTENT_TYPE)-1, NULL, rfc1867_post_handler },
+ { NULL, 0, NULL, NULL }
+};
+/* }}} */
+
+/* {{{ SAPI_POST_READER_FUNC
+ */
+SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader)
+{
+ char *data;
+ int length;
+
+ /* $HTTP_RAW_POST_DATA registration */
+ if (!strcmp(SG(request_info).request_method, "POST")) {
+ if (NULL == SG(request_info).post_entry) {
+ /* no post handler registered, so we just swallow the data */
+ sapi_read_standard_form_data(TSRMLS_C);
+ }
+
+ /* For unknown content types we create HTTP_RAW_POST_DATA even if always_populate_raw_post_data off,
+ * this is in-effecient, but we need to keep doing it for BC reasons (for now) */
+ if ((PG(always_populate_raw_post_data) || NULL == SG(request_info).post_entry) && SG(request_info).post_data) {
+ length = SG(request_info).post_data_length;
+ data = estrndup(SG(request_info).post_data, length);
+ SET_VAR_STRINGL("HTTP_RAW_POST_DATA", data, length);
+ }
+ }
+
+ /* for php://input stream:
+ some post handlers modify the content of request_info.post_data
+ so for now we need a copy for the php://input stream
+ in the long run post handlers should be changed to not touch
+ request_info.post_data for memory preservation reasons
+ */
+ if (SG(request_info).post_data) {
+ SG(request_info).raw_post_data = estrndup(SG(request_info).post_data, SG(request_info).post_data_length);
+ SG(request_info).raw_post_data_length = SG(request_info).post_data_length;
+ }
+}
+/* }}} */
+
+/* {{{ php_startup_sapi_content_types
+ */
+int php_startup_sapi_content_types(TSRMLS_D)
+{
+ sapi_register_default_post_reader(php_default_post_reader TSRMLS_CC);
+ sapi_register_treat_data(php_default_treat_data TSRMLS_CC);
+ sapi_register_input_filter(php_default_input_filter, NULL TSRMLS_CC);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ php_setup_sapi_content_types
+ */
+int php_setup_sapi_content_types(TSRMLS_D)
+{
+ sapi_register_post_entries(php_post_entries TSRMLS_CC);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_content_types.h b/main/php_content_types.h
new file mode 100644
index 0000000..7ceffff
--- /dev/null
+++ b/main/php_content_types.h
@@ -0,0 +1,31 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_CONTENT_TYPES_H
+#define PHP_CONTENT_TYPES_H
+
+#define DEFAULT_POST_CONTENT_TYPE "application/x-www-form-urlencoded"
+
+SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader);
+SAPI_API SAPI_POST_HANDLER_FUNC(php_std_post_handler);
+int php_startup_sapi_content_types(TSRMLS_D);
+int php_setup_sapi_content_types(TSRMLS_D);
+
+#endif /* PHP_CONTENT_TYPES_H */
diff --git a/main/php_getopt.h b/main/php_getopt.h
new file mode 100644
index 0000000..a3f4c14
--- /dev/null
+++ b/main/php_getopt.h
@@ -0,0 +1,57 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_GETOPT_H
+#define PHP_GETOPT_H
+
+#include "php.h"
+
+#ifdef NETWARE
+/*
+As NetWare LibC has optind and optarg macros defined in unistd.h our local variables were getting mistakenly preprocessed so undeffing optind and optarg
+*/
+#undef optarg
+#undef optind
+#endif
+
+/* Define structure for one recognized option (both single char and long name).
+ * If short_open is '-' this is the last option. */
+typedef struct _opt_struct {
+ char opt_char;
+ int need_param;
+ char * opt_name;
+} opt_struct;
+
+BEGIN_EXTERN_C()
+/* holds the index of the latest fetched element from the opts array */
+extern PHPAPI int php_optidx;
+PHPAPI int php_getopt(int argc, char* const *argv, const opt_struct opts[], char **optarg, int *optind, int show_err, int arg_start);
+END_EXTERN_C()
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/php_globals.h b/main/php_globals.h
new file mode 100644
index 0000000..170431d
--- /dev/null
+++ b/main/php_globals.h
@@ -0,0 +1,175 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_GLOBALS_H
+#define PHP_GLOBALS_H
+
+#include "zend_globals.h"
+
+typedef struct _php_core_globals php_core_globals;
+
+#ifdef ZTS
+# define PG(v) TSRMG(core_globals_id, php_core_globals *, v)
+extern PHPAPI int core_globals_id;
+#else
+# define PG(v) (core_globals.v)
+extern ZEND_API struct _php_core_globals core_globals;
+#endif
+
+/* Error display modes */
+#define PHP_DISPLAY_ERRORS_STDOUT 1
+#define PHP_DISPLAY_ERRORS_STDERR 2
+
+/* Track vars */
+#define TRACK_VARS_POST 0
+#define TRACK_VARS_GET 1
+#define TRACK_VARS_COOKIE 2
+#define TRACK_VARS_SERVER 3
+#define TRACK_VARS_ENV 4
+#define TRACK_VARS_FILES 5
+#define TRACK_VARS_REQUEST 6
+
+struct _php_tick_function_entry;
+
+typedef struct _arg_separators {
+ char *output;
+ char *input;
+} arg_separators;
+
+struct _php_core_globals {
+ zend_bool implicit_flush;
+
+ long output_buffering;
+
+ zend_bool sql_safe_mode;
+ zend_bool enable_dl;
+
+ char *output_handler;
+
+ char *unserialize_callback_func;
+ long serialize_precision;
+
+ long memory_limit;
+ long max_input_time;
+
+ zend_bool track_errors;
+ zend_bool display_errors;
+ zend_bool display_startup_errors;
+ zend_bool log_errors;
+ long log_errors_max_len;
+ zend_bool ignore_repeated_errors;
+ zend_bool ignore_repeated_source;
+ zend_bool report_memleaks;
+ char *error_log;
+
+ char *doc_root;
+ char *user_dir;
+ char *include_path;
+ char *open_basedir;
+ char *extension_dir;
+ char *php_binary;
+
+ char *upload_tmp_dir;
+ long upload_max_filesize;
+
+ char *error_append_string;
+ char *error_prepend_string;
+
+ char *auto_prepend_file;
+ char *auto_append_file;
+
+ arg_separators arg_separator;
+
+ char *variables_order;
+
+ HashTable rfc1867_protected_variables;
+
+ short connection_status;
+ short ignore_user_abort;
+
+ unsigned char header_is_being_sent;
+
+ zend_llist tick_functions;
+
+ zval *http_globals[6];
+
+ zend_bool expose_php;
+
+ zend_bool register_argc_argv;
+ zend_bool auto_globals_jit;
+
+ char *docref_root;
+ char *docref_ext;
+
+ zend_bool html_errors;
+ zend_bool xmlrpc_errors;
+
+ long xmlrpc_error_number;
+
+ zend_bool activated_auto_globals[8];
+
+ zend_bool modules_activated;
+ zend_bool file_uploads;
+ zend_bool during_request_startup;
+ zend_bool allow_url_fopen;
+ zend_bool enable_post_data_reading;
+ zend_bool always_populate_raw_post_data;
+ zend_bool report_zend_debug;
+
+ int last_error_type;
+ char *last_error_message;
+ char *last_error_file;
+ int last_error_lineno;
+
+ char *disable_functions;
+ char *disable_classes;
+ zend_bool allow_url_include;
+ zend_bool exit_on_timeout;
+#ifdef PHP_WIN32
+ zend_bool com_initialized;
+#endif
+ long max_input_nesting_level;
+ long max_input_vars;
+ zend_bool in_user_include;
+
+ char *user_ini_filename;
+ long user_ini_cache_ttl;
+
+ char *request_order;
+
+ zend_bool mail_x_header;
+ char *mail_log;
+
+ zend_bool in_error_log;
+
+#ifdef PHP_WIN32
+ zend_bool windows_show_crt_warning;
+#endif
+};
+
+
+#endif /* PHP_GLOBALS_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/main/php_ini.c b/main/php_ini.c
new file mode 100644
index 0000000..b15a384
--- /dev/null
+++ b/main/php_ini.c
@@ -0,0 +1,916 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "zend_ini.h"
+#include "zend_ini_scanner.h"
+#include "php_ini.h"
+#include "ext/standard/dl.h"
+#include "zend_extensions.h"
+#include "zend_highlight.h"
+#include "SAPI.h"
+#include "php_main.h"
+#include "php_scandir.h"
+#ifdef PHP_WIN32
+#include "win32/php_registry.h"
+#endif
+
+#if HAVE_SCANDIR && HAVE_ALPHASORT && HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+
+#ifdef PHP_WIN32
+#define TRANSLATE_SLASHES_LOWER(path) \
+ { \
+ char *tmp = path; \
+ while (*tmp) { \
+ if (*tmp == '\\') *tmp = '/'; \
+ else *tmp = tolower(*tmp); \
+ tmp++; \
+ } \
+ }
+#else
+#define TRANSLATE_SLASHES_LOWER(path)
+#endif
+
+
+typedef struct _php_extension_lists {
+ zend_llist engine;
+ zend_llist functions;
+} php_extension_lists;
+
+/* True globals */
+static int is_special_section = 0;
+static HashTable *active_ini_hash;
+static HashTable configuration_hash;
+static int has_per_dir_config = 0;
+static int has_per_host_config = 0;
+PHPAPI char *php_ini_opened_path=NULL;
+static php_extension_lists extension_lists;
+PHPAPI char *php_ini_scanned_path=NULL;
+PHPAPI char *php_ini_scanned_files=NULL;
+
+/* {{{ php_ini_displayer_cb
+ */
+static void php_ini_displayer_cb(zend_ini_entry *ini_entry, int type TSRMLS_DC)
+{
+ if (ini_entry->displayer) {
+ ini_entry->displayer(ini_entry, type);
+ } else {
+ char *display_string;
+ uint display_string_length, esc_html=0;
+
+ if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
+ if (ini_entry->orig_value && ini_entry->orig_value[0]) {
+ display_string = ini_entry->orig_value;
+ display_string_length = ini_entry->orig_value_length;
+ esc_html = !sapi_module.phpinfo_as_text;
+ } else {
+ if (!sapi_module.phpinfo_as_text) {
+ display_string = "<i>no value</i>";
+ display_string_length = sizeof("<i>no value</i>") - 1;
+ } else {
+ display_string = "no value";
+ display_string_length = sizeof("no value") - 1;
+ }
+ }
+ } else if (ini_entry->value && ini_entry->value[0]) {
+ display_string = ini_entry->value;
+ display_string_length = ini_entry->value_length;
+ esc_html = !sapi_module.phpinfo_as_text;
+ } else {
+ if (!sapi_module.phpinfo_as_text) {
+ display_string = "<i>no value</i>";
+ display_string_length = sizeof("<i>no value</i>") - 1;
+ } else {
+ display_string = "no value";
+ display_string_length = sizeof("no value") - 1;
+ }
+ }
+
+ if (esc_html) {
+ php_html_puts(display_string, display_string_length TSRMLS_CC);
+ } else {
+ PHPWRITE(display_string, display_string_length);
+ }
+ }
+}
+/* }}} */
+
+/* {{{ php_ini_displayer
+ */
+static int php_ini_displayer(zend_ini_entry *ini_entry, int module_number TSRMLS_DC)
+{
+ if (ini_entry->module_number != module_number) {
+ return 0;
+ }
+ if (!sapi_module.phpinfo_as_text) {
+ PUTS("<tr>");
+ PUTS("<td class=\"e\">");
+ PHPWRITE(ini_entry->name, ini_entry->name_length - 1);
+ PUTS("</td><td class=\"v\">");
+ php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE TSRMLS_CC);
+ PUTS("</td><td class=\"v\">");
+ php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG TSRMLS_CC);
+ PUTS("</td></tr>\n");
+ } else {
+ PHPWRITE(ini_entry->name, ini_entry->name_length - 1);
+ PUTS(" => ");
+ php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE TSRMLS_CC);
+ PUTS(" => ");
+ php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG TSRMLS_CC);
+ PUTS("\n");
+ }
+ return 0;
+}
+/* }}} */
+
+/* {{{ php_ini_available
+ */
+static int php_ini_available(zend_ini_entry *ini_entry, int *module_number_available TSRMLS_DC)
+{
+ if (ini_entry->module_number == *module_number_available) {
+ *module_number_available = -1;
+ return ZEND_HASH_APPLY_STOP;
+ } else {
+ return ZEND_HASH_APPLY_KEEP;
+ }
+}
+/* }}} */
+
+/* {{{ display_ini_entries
+ */
+PHPAPI void display_ini_entries(zend_module_entry *module)
+{
+ int module_number, module_number_available;
+ TSRMLS_FETCH();
+
+ if (module) {
+ module_number = module->module_number;
+ } else {
+ module_number = 0;
+ }
+ module_number_available = module_number;
+ zend_hash_apply_with_argument(EG(ini_directives), (apply_func_arg_t) php_ini_available, &module_number_available TSRMLS_CC);
+ if (module_number_available == -1) {
+ php_info_print_table_start();
+ php_info_print_table_header(3, "Directive", "Local Value", "Master Value");
+ zend_hash_apply_with_argument(EG(ini_directives), (apply_func_arg_t) php_ini_displayer, (void *) (zend_intptr_t) module_number TSRMLS_CC);
+ php_info_print_table_end();
+ }
+}
+/* }}} */
+
+/* php.ini support */
+#define PHP_EXTENSION_TOKEN "extension"
+#define ZEND_EXTENSION_TOKEN "zend_extension"
+
+/* {{{ config_zval_dtor
+ */
+PHPAPI void config_zval_dtor(zval *zvalue)
+{
+ if (Z_TYPE_P(zvalue) == IS_ARRAY) {
+ zend_hash_destroy(Z_ARRVAL_P(zvalue));
+ free(Z_ARRVAL_P(zvalue));
+ } else if (Z_TYPE_P(zvalue) == IS_STRING) {
+ free(Z_STRVAL_P(zvalue));
+ }
+}
+/* Reset / free active_ini_sectin global */
+#define RESET_ACTIVE_INI_HASH() do { \
+ active_ini_hash = NULL; \
+ is_special_section = 0; \
+} while (0)
+/* }}} */
+
+/* {{{ php_ini_parser_cb
+ */
+static void php_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_type, HashTable *target_hash)
+{
+ zval *entry;
+ HashTable *active_hash;
+ char *extension_name;
+
+ if (active_ini_hash) {
+ active_hash = active_ini_hash;
+ } else {
+ active_hash = target_hash;
+ }
+
+ switch (callback_type) {
+ case ZEND_INI_PARSER_ENTRY: {
+ if (!arg2) {
+ /* bare string - nothing to do */
+ break;
+ }
+
+ /* PHP and Zend extensions are not added into configuration hash! */
+ if (!is_special_section && !strcasecmp(Z_STRVAL_P(arg1), PHP_EXTENSION_TOKEN)) { /* load PHP extension */
+ extension_name = estrndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
+ zend_llist_add_element(&extension_lists.functions, &extension_name);
+ } else if (!is_special_section && !strcasecmp(Z_STRVAL_P(arg1), ZEND_EXTENSION_TOKEN)) { /* load Zend extension */
+ extension_name = estrndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
+ zend_llist_add_element(&extension_lists.engine, &extension_name);
+
+ /* All other entries are added into either configuration_hash or active ini section array */
+ } else {
+ /* Store in active hash */
+ zend_hash_update(active_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, arg2, sizeof(zval), (void **) &entry);
+ Z_STRVAL_P(entry) = zend_strndup(Z_STRVAL_P(entry), Z_STRLEN_P(entry));
+ }
+ }
+ break;
+
+ case ZEND_INI_PARSER_POP_ENTRY: {
+ zval *option_arr;
+ zval *find_arr;
+
+ if (!arg2) {
+ /* bare string - nothing to do */
+ break;
+ }
+
+/* fprintf(stdout, "ZEND_INI_PARSER_POP_ENTRY: %s[%s] = %s\n",Z_STRVAL_P(arg1), Z_STRVAL_P(arg3), Z_STRVAL_P(arg2)); */
+
+ /* If option not found in hash or is not an array -> create array, otherwise add to existing array */
+ if (zend_hash_find(active_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, (void **) &find_arr) == FAILURE || Z_TYPE_P(find_arr) != IS_ARRAY) {
+ option_arr = (zval *) pemalloc(sizeof(zval), 1);
+ INIT_PZVAL(option_arr);
+ Z_TYPE_P(option_arr) = IS_ARRAY;
+ Z_ARRVAL_P(option_arr) = (HashTable *) pemalloc(sizeof(HashTable), 1);
+ zend_hash_init(Z_ARRVAL_P(option_arr), 0, NULL, (dtor_func_t) config_zval_dtor, 1);
+ zend_hash_update(active_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, option_arr, sizeof(zval), (void **) &find_arr);
+ free(option_arr);
+ }
+
+ /* arg3 is possible option offset name */
+ if (arg3 && Z_STRLEN_P(arg3) > 0) {
+ zend_symtable_update(Z_ARRVAL_P(find_arr), Z_STRVAL_P(arg3), Z_STRLEN_P(arg3) + 1, arg2, sizeof(zval), (void **) &entry);
+ } else {
+ zend_hash_next_index_insert(Z_ARRVAL_P(find_arr), arg2, sizeof(zval), (void **) &entry);
+ }
+ Z_STRVAL_P(entry) = zend_strndup(Z_STRVAL_P(entry), Z_STRLEN_P(entry));
+ }
+ break;
+
+ case ZEND_INI_PARSER_SECTION: { /* Create an array of entries of each section */
+
+/* fprintf(stdout, "ZEND_INI_PARSER_SECTION: %s\n",Z_STRVAL_P(arg1)); */
+
+ char *key = NULL;
+ uint key_len;
+
+ /* PATH sections */
+ if (!strncasecmp(Z_STRVAL_P(arg1), "PATH", sizeof("PATH") - 1)) {
+ key = Z_STRVAL_P(arg1);
+ key = key + sizeof("PATH") - 1;
+ key_len = Z_STRLEN_P(arg1) - sizeof("PATH") + 1;
+ is_special_section = 1;
+ has_per_dir_config = 1;
+
+ /* make the path lowercase on Windows, for case insensitivty. Does nothign for other platforms */
+ TRANSLATE_SLASHES_LOWER(key);
+
+ /* HOST sections */
+ } else if (!strncasecmp(Z_STRVAL_P(arg1), "HOST", sizeof("HOST") - 1)) {
+ key = Z_STRVAL_P(arg1);
+ key = key + sizeof("HOST") - 1;
+ key_len = Z_STRLEN_P(arg1) - sizeof("HOST") + 1;
+ is_special_section = 1;
+ has_per_host_config = 1;
+ zend_str_tolower(key, key_len); /* host names are case-insensitive. */
+
+ } else {
+ is_special_section = 0;
+ }
+
+ if (key && key_len > 0) {
+ /* Strip any trailing slashes */
+ while (key_len > 0 && (key[key_len - 1] == '/' || key[key_len - 1] == '\\')) {
+ key_len--;
+ key[key_len] = 0;
+ }
+
+ /* Strip any leading whitespace and '=' */
+ while (*key && (
+ *key == '=' ||
+ *key == ' ' ||
+ *key == '\t'
+ )) {
+ key++;
+ key_len--;
+ }
+
+ /* Search for existing entry and if it does not exist create one */
+ if (zend_hash_find(target_hash, key, key_len + 1, (void **) &entry) == FAILURE) {
+ zval *section_arr;
+
+ section_arr = (zval *) pemalloc(sizeof(zval), 1);
+ INIT_PZVAL(section_arr);
+ Z_TYPE_P(section_arr) = IS_ARRAY;
+ Z_ARRVAL_P(section_arr) = (HashTable *) pemalloc(sizeof(HashTable), 1);
+ zend_hash_init(Z_ARRVAL_P(section_arr), 0, NULL, (dtor_func_t) config_zval_dtor, 1);
+ zend_hash_update(target_hash, key, key_len + 1, section_arr, sizeof(zval), (void **) &entry);
+ free(section_arr);
+ }
+ active_ini_hash = Z_ARRVAL_P(entry);
+ }
+ }
+ break;
+ }
+}
+/* }}} */
+
+/* {{{ php_load_php_extension_cb
+ */
+static void php_load_php_extension_cb(void *arg TSRMLS_DC)
+{
+#ifdef HAVE_LIBDL
+ php_load_extension(*((char **) arg), MODULE_PERSISTENT, 0 TSRMLS_CC);
+#endif
+}
+/* }}} */
+
+/* {{{ php_load_zend_extension_cb
+ */
+static void php_load_zend_extension_cb(void *arg TSRMLS_DC)
+{
+ zend_load_extension(*((char **) arg));
+}
+/* }}} */
+
+/* {{{ php_init_config
+ */
+int php_init_config(TSRMLS_D)
+{
+ char *php_ini_file_name = NULL;
+ char *php_ini_search_path = NULL;
+ int php_ini_scanned_path_len;
+ char *open_basedir;
+ int free_ini_search_path = 0;
+ zend_file_handle fh;
+
+ if (zend_hash_init(&configuration_hash, 0, NULL, (dtor_func_t) config_zval_dtor, 1) == FAILURE) {
+ return FAILURE;
+ }
+
+ if (sapi_module.ini_defaults) {
+ sapi_module.ini_defaults(&configuration_hash);
+ }
+
+ zend_llist_init(&extension_lists.engine, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
+ zend_llist_init(&extension_lists.functions, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
+
+ open_basedir = PG(open_basedir);
+
+ if (sapi_module.php_ini_path_override) {
+ php_ini_file_name = sapi_module.php_ini_path_override;
+ php_ini_search_path = sapi_module.php_ini_path_override;
+ free_ini_search_path = 0;
+ } else if (!sapi_module.php_ini_ignore) {
+ int search_path_size;
+ char *default_location;
+ char *env_location;
+ static const char paths_separator[] = { ZEND_PATHS_SEPARATOR, 0 };
+#ifdef PHP_WIN32
+ char *reg_location;
+ char phprc_path[MAXPATHLEN];
+#endif
+
+ env_location = getenv("PHPRC");
+
+#ifdef PHP_WIN32
+ if (!env_location) {
+ char dummybuf;
+ int size;
+
+ SetLastError(0);
+
+ /*If the given bugger is not large enough to hold the data, the return value is
+ the buffer size, in characters, required to hold the string and its terminating
+ null character. We use this return value to alloc the final buffer. */
+ size = GetEnvironmentVariableA("PHPRC", &dummybuf, 0);
+ if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
+ /* The environment variable doesn't exist. */
+ env_location = "";
+ } else {
+ if (size == 0) {
+ env_location = "";
+ } else {
+ size = GetEnvironmentVariableA("PHPRC", phprc_path, size);
+ if (size == 0) {
+ env_location = "";
+ } else {
+ env_location = phprc_path;
+ }
+ }
+ }
+ }
+#else
+ if (!env_location) {
+ env_location = "";
+ }
+#endif
+ /*
+ * Prepare search path
+ */
+
+ search_path_size = MAXPATHLEN * 4 + strlen(env_location) + 3 + 1;
+ php_ini_search_path = (char *) emalloc(search_path_size);
+ free_ini_search_path = 1;
+ php_ini_search_path[0] = 0;
+
+ /* Add environment location */
+ if (env_location[0]) {
+ if (*php_ini_search_path) {
+ strlcat(php_ini_search_path, paths_separator, search_path_size);
+ }
+ strlcat(php_ini_search_path, env_location, search_path_size);
+ php_ini_file_name = env_location;
+ }
+
+#ifdef PHP_WIN32
+ /* Add registry location */
+ reg_location = GetIniPathFromRegistry();
+ if (reg_location != NULL) {
+ if (*php_ini_search_path) {
+ strlcat(php_ini_search_path, paths_separator, search_path_size);
+ }
+ strlcat(php_ini_search_path, reg_location, search_path_size);
+ efree(reg_location);
+ }
+#endif
+
+ /* Add cwd (not with CLI) */
+ if (!sapi_module.php_ini_ignore_cwd) {
+ if (*php_ini_search_path) {
+ strlcat(php_ini_search_path, paths_separator, search_path_size);
+ }
+ strlcat(php_ini_search_path, ".", search_path_size);
+ }
+
+ if (PG(php_binary)) {
+ char *separator_location, *binary_location;
+
+ binary_location = estrdup(PG(php_binary));
+ separator_location = strrchr(binary_location, DEFAULT_SLASH);
+
+ if (separator_location && separator_location != binary_location) {
+ *(separator_location) = 0;
+ }
+ if (*php_ini_search_path) {
+ strlcat(php_ini_search_path, paths_separator, search_path_size);
+ }
+ strlcat(php_ini_search_path, binary_location, search_path_size);
+ efree(binary_location);
+ }
+
+ /* Add default location */
+#ifdef PHP_WIN32
+ default_location = (char *) emalloc(MAXPATHLEN + 1);
+
+ if (0 < GetWindowsDirectory(default_location, MAXPATHLEN)) {
+ if (*php_ini_search_path) {
+ strlcat(php_ini_search_path, paths_separator, search_path_size);
+ }
+ strlcat(php_ini_search_path, default_location, search_path_size);
+ }
+
+ /* For people running under terminal services, GetWindowsDirectory will
+ * return their personal Windows directory, so lets add the system
+ * windows directory too */
+ if (0 < GetSystemWindowsDirectory(default_location, MAXPATHLEN)) {
+ if (*php_ini_search_path) {
+ strlcat(php_ini_search_path, paths_separator, search_path_size);
+ }
+ strlcat(php_ini_search_path, default_location, search_path_size);
+ }
+ efree(default_location);
+
+#else
+ default_location = PHP_CONFIG_FILE_PATH;
+ if (*php_ini_search_path) {
+ strlcat(php_ini_search_path, paths_separator, search_path_size);
+ }
+ strlcat(php_ini_search_path, default_location, search_path_size);
+#endif
+ }
+
+ PG(open_basedir) = NULL;
+
+ /*
+ * Find and open actual ini file
+ */
+
+ memset(&fh, 0, sizeof(fh));
+
+ /* If SAPI does not want to ignore all ini files OR an overriding file/path is given.
+ * This allows disabling scanning for ini files in the PHP_CONFIG_FILE_SCAN_DIR but still
+ * load an optional ini file. */
+ if (!sapi_module.php_ini_ignore || sapi_module.php_ini_path_override) {
+
+ /* Check if php_ini_file_name is a file and can be opened */
+ if (php_ini_file_name && php_ini_file_name[0]) {
+ struct stat statbuf;
+
+ if (!VCWD_STAT(php_ini_file_name, &statbuf)) {
+ if (!((statbuf.st_mode & S_IFMT) == S_IFDIR)) {
+ fh.handle.fp = VCWD_FOPEN(php_ini_file_name, "r");
+ if (fh.handle.fp) {
+ fh.filename = php_ini_opened_path = expand_filepath(php_ini_file_name, NULL TSRMLS_CC);
+ }
+ }
+ }
+ }
+
+ /* Otherwise search for php-%sapi-module-name%.ini file in search path */
+ if (!fh.handle.fp) {
+ const char *fmt = "php-%s.ini";
+ char *ini_fname;
+ spprintf(&ini_fname, 0, fmt, sapi_module.name);
+ fh.handle.fp = php_fopen_with_path(ini_fname, "r", php_ini_search_path, &php_ini_opened_path TSRMLS_CC);
+ efree(ini_fname);
+ if (fh.handle.fp) {
+ fh.filename = php_ini_opened_path;
+ }
+ }
+
+ /* If still no ini file found, search for php.ini file in search path */
+ if (!fh.handle.fp) {
+ fh.handle.fp = php_fopen_with_path("php.ini", "r", php_ini_search_path, &php_ini_opened_path TSRMLS_CC);
+ if (fh.handle.fp) {
+ fh.filename = php_ini_opened_path;
+ }
+ }
+ }
+
+ if (free_ini_search_path) {
+ efree(php_ini_search_path);
+ }
+
+ PG(open_basedir) = open_basedir;
+
+ if (fh.handle.fp) {
+ fh.type = ZEND_HANDLE_FP;
+ RESET_ACTIVE_INI_HASH();
+
+ zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash TSRMLS_CC);
+
+ {
+ zval tmp;
+
+ Z_STRLEN(tmp) = strlen(fh.filename);
+ Z_STRVAL(tmp) = zend_strndup(fh.filename, Z_STRLEN(tmp));
+ Z_TYPE(tmp) = IS_STRING;
+ Z_SET_REFCOUNT(tmp, 0);
+
+ zend_hash_update(&configuration_hash, "cfg_file_path", sizeof("cfg_file_path"), (void *) &tmp, sizeof(zval), NULL);
+ if (php_ini_opened_path) {
+ efree(php_ini_opened_path);
+ }
+ php_ini_opened_path = zend_strndup(Z_STRVAL(tmp), Z_STRLEN(tmp));
+ }
+ }
+
+ /* Check for PHP_INI_SCAN_DIR environment variable to override/set config file scan directory */
+ php_ini_scanned_path = getenv("PHP_INI_SCAN_DIR");
+ if (!php_ini_scanned_path) {
+ /* Or fall back using possible --with-config-file-scan-dir setting (defaults to empty string!) */
+ php_ini_scanned_path = PHP_CONFIG_FILE_SCAN_DIR;
+ }
+ php_ini_scanned_path_len = strlen(php_ini_scanned_path);
+
+ /* Scan and parse any .ini files found in scan path if path not empty. */
+ if (!sapi_module.php_ini_ignore && php_ini_scanned_path_len) {
+ struct dirent **namelist;
+ int ndir, i;
+ struct stat sb;
+ char ini_file[MAXPATHLEN];
+ char *p;
+ zend_file_handle fh2;
+ zend_llist scanned_ini_list;
+ zend_llist_element *element;
+ int l, total_l = 0;
+
+ if ((ndir = php_scandir(php_ini_scanned_path, &namelist, 0, php_alphasort)) > 0) {
+ zend_llist_init(&scanned_ini_list, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
+ memset(&fh2, 0, sizeof(fh2));
+
+ for (i = 0; i < ndir; i++) {
+
+ /* check for any file with .ini extension */
+ if (!(p = strrchr(namelist[i]->d_name, '.')) || (p && strcmp(p, ".ini"))) {
+ free(namelist[i]);
+ continue;
+ }
+ /* Reset active ini section */
+ RESET_ACTIVE_INI_HASH();
+
+ if (IS_SLASH(php_ini_scanned_path[php_ini_scanned_path_len - 1])) {
+ snprintf(ini_file, MAXPATHLEN, "%s%s", php_ini_scanned_path, namelist[i]->d_name);
+ } else {
+ snprintf(ini_file, MAXPATHLEN, "%s%c%s", php_ini_scanned_path, DEFAULT_SLASH, namelist[i]->d_name);
+ }
+ if (VCWD_STAT(ini_file, &sb) == 0) {
+ if (S_ISREG(sb.st_mode)) {
+ if ((fh2.handle.fp = VCWD_FOPEN(ini_file, "r"))) {
+ fh2.filename = ini_file;
+ fh2.type = ZEND_HANDLE_FP;
+
+ if (zend_parse_ini_file(&fh2, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash TSRMLS_CC) == SUCCESS) {
+ /* Here, add it to the list of ini files read */
+ l = strlen(ini_file);
+ total_l += l + 2;
+ p = estrndup(ini_file, l);
+ zend_llist_add_element(&scanned_ini_list, &p);
+ }
+ }
+ }
+ }
+ free(namelist[i]);
+ }
+ free(namelist);
+
+ if (total_l) {
+ int php_ini_scanned_files_len = (php_ini_scanned_files) ? strlen(php_ini_scanned_files) + 1 : 0;
+ php_ini_scanned_files = (char *) realloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1);
+ if (!php_ini_scanned_files_len) {
+ *php_ini_scanned_files = '\0';
+ }
+ total_l += php_ini_scanned_files_len;
+ for (element = scanned_ini_list.head; element; element = element->next) {
+ if (php_ini_scanned_files_len) {
+ strlcat(php_ini_scanned_files, ",\n", total_l);
+ }
+ strlcat(php_ini_scanned_files, *(char **)element->data, total_l);
+ strlcat(php_ini_scanned_files, element->next ? ",\n" : "\n", total_l);
+ }
+ }
+ zend_llist_destroy(&scanned_ini_list);
+ }
+ } else {
+ /* Make sure an empty php_ini_scanned_path ends up as NULL */
+ php_ini_scanned_path = NULL;
+ }
+
+ if (sapi_module.ini_entries) {
+ /* Reset active ini section */
+ RESET_ACTIVE_INI_HASH();
+ zend_parse_ini_string(sapi_module.ini_entries, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash TSRMLS_CC);
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ php_shutdown_config
+ */
+int php_shutdown_config(void)
+{
+ zend_hash_destroy(&configuration_hash);
+ if (php_ini_opened_path) {
+ free(php_ini_opened_path);
+ php_ini_opened_path = NULL;
+ }
+ if (php_ini_scanned_files) {
+ free(php_ini_scanned_files);
+ php_ini_scanned_files = NULL;
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ php_ini_register_extensions
+ */
+void php_ini_register_extensions(TSRMLS_D)
+{
+ zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb TSRMLS_CC);
+ zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb TSRMLS_CC);
+
+ zend_llist_destroy(&extension_lists.engine);
+ zend_llist_destroy(&extension_lists.functions);
+}
+/* }}} */
+
+/* {{{ php_parse_user_ini_file
+ */
+PHPAPI int php_parse_user_ini_file(const char *dirname, char *ini_filename, HashTable *target_hash TSRMLS_DC)
+{
+ struct stat sb;
+ char ini_file[MAXPATHLEN];
+ zend_file_handle fh;
+
+ snprintf(ini_file, MAXPATHLEN, "%s%c%s", dirname, DEFAULT_SLASH, ini_filename);
+
+ if (VCWD_STAT(ini_file, &sb) == 0) {
+ if (S_ISREG(sb.st_mode)) {
+ memset(&fh, 0, sizeof(fh));
+ if ((fh.handle.fp = VCWD_FOPEN(ini_file, "r"))) {
+ fh.filename = ini_file;
+ fh.type = ZEND_HANDLE_FP;
+
+ /* Reset active ini section */
+ RESET_ACTIVE_INI_HASH();
+
+ if (zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, target_hash TSRMLS_CC) == SUCCESS) {
+ /* FIXME: Add parsed file to the list of user files read? */
+ return SUCCESS;
+ }
+ return FAILURE;
+ }
+ }
+ }
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ php_ini_activate_config
+ */
+PHPAPI void php_ini_activate_config(HashTable *source_hash, int modify_type, int stage TSRMLS_DC)
+{
+ char *str;
+ zval *data;
+ uint str_len;
+ ulong num_index;
+
+ /* Walk through config hash and alter matching ini entries using the values found in the hash */
+ for (zend_hash_internal_pointer_reset(source_hash);
+ zend_hash_get_current_key_ex(source_hash, &str, &str_len, &num_index, 0, NULL) == HASH_KEY_IS_STRING;
+ zend_hash_move_forward(source_hash)
+ ) {
+ zend_hash_get_current_data(source_hash, (void **) &data);
+ zend_alter_ini_entry_ex(str, str_len, Z_STRVAL_P(data), Z_STRLEN_P(data), modify_type, stage, 0 TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ php_ini_has_per_dir_config
+ */
+PHPAPI int php_ini_has_per_dir_config(void)
+{
+ return has_per_dir_config;
+}
+/* }}} */
+
+/* {{{ php_ini_activate_per_dir_config
+ */
+PHPAPI void php_ini_activate_per_dir_config(char *path, uint path_len TSRMLS_DC)
+{
+ zval *tmp2;
+ char *ptr;
+
+#if PHP_WIN32
+ char path_bak[MAXPATHLEN];
+#endif
+
+ if (path_len > MAXPATHLEN) {
+ return;
+ }
+
+#if PHP_WIN32
+ memcpy(path_bak, path, path_len);
+ path_bak[path_len] = 0;
+ TRANSLATE_SLASHES_LOWER(path_bak);
+ path = path_bak;
+#endif
+
+ /* Walk through each directory in path and apply any found per-dir-system-configuration from configuration_hash */
+ if (has_per_dir_config && path && path_len) {
+ ptr = path + 1;
+ while ((ptr = strchr(ptr, '/')) != NULL) {
+ *ptr = 0;
+ /* Search for source array matching the path from configuration_hash */
+ if (zend_hash_find(&configuration_hash, path, strlen(path) + 1, (void **) &tmp2) == SUCCESS) {
+ php_ini_activate_config(Z_ARRVAL_P(tmp2), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE TSRMLS_CC);
+ }
+ *ptr = '/';
+ ptr++;
+ }
+ }
+}
+/* }}} */
+
+/* {{{ php_ini_has_per_host_config
+ */
+PHPAPI int php_ini_has_per_host_config(void)
+{
+ return has_per_host_config;
+}
+/* }}} */
+
+/* {{{ php_ini_activate_per_host_config
+ */
+PHPAPI void php_ini_activate_per_host_config(const char *host, uint host_len TSRMLS_DC)
+{
+ zval *tmp;
+
+ if (has_per_host_config && host && host_len) {
+ /* Search for source array matching the host from configuration_hash */
+ if (zend_hash_find(&configuration_hash, host, host_len, (void **) &tmp) == SUCCESS) {
+ php_ini_activate_config(Z_ARRVAL_P(tmp), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE TSRMLS_CC);
+ }
+ }
+}
+/* }}} */
+
+/* {{{ cfg_get_entry
+ */
+PHPAPI zval *cfg_get_entry(const char *name, uint name_length)
+{
+ zval *tmp;
+
+ if (zend_hash_find(&configuration_hash, name, name_length, (void **) &tmp) == SUCCESS) {
+ return tmp;
+ } else {
+ return NULL;
+ }
+}
+/* }}} */
+
+/* {{{ cfg_get_long
+ */
+PHPAPI int cfg_get_long(const char *varname, long *result)
+{
+ zval *tmp, var;
+
+ if (zend_hash_find(&configuration_hash, varname, strlen(varname) + 1, (void **) &tmp) == FAILURE) {
+ *result = 0;
+ return FAILURE;
+ }
+ var = *tmp;
+ zval_copy_ctor(&var);
+ convert_to_long(&var);
+ *result = Z_LVAL(var);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ cfg_get_double
+ */
+PHPAPI int cfg_get_double(const char *varname, double *result)
+{
+ zval *tmp, var;
+
+ if (zend_hash_find(&configuration_hash, varname, strlen(varname) + 1, (void **) &tmp) == FAILURE) {
+ *result = (double) 0;
+ return FAILURE;
+ }
+ var = *tmp;
+ zval_copy_ctor(&var);
+ convert_to_double(&var);
+ *result = Z_DVAL(var);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ cfg_get_string
+ */
+PHPAPI int cfg_get_string(const char *varname, char **result)
+{
+ zval *tmp;
+
+ if (zend_hash_find(&configuration_hash, varname, strlen(varname)+1, (void **) &tmp) == FAILURE) {
+ *result = NULL;
+ return FAILURE;
+ }
+ *result = Z_STRVAL_P(tmp);
+ return SUCCESS;
+}
+/* }}} */
+
+PHPAPI HashTable* php_ini_get_configuration_hash(void) /* {{{ */
+{
+ return &configuration_hash;
+} /* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_ini.h b/main/php_ini.h
new file mode 100644
index 0000000..65c80f7
--- /dev/null
+++ b/main/php_ini.h
@@ -0,0 +1,90 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_INI_H
+#define PHP_INI_H
+
+#include "zend_ini.h"
+
+BEGIN_EXTERN_C()
+PHPAPI void config_zval_dtor(zval *zvalue);
+int php_init_config(TSRMLS_D);
+int php_shutdown_config(void);
+void php_ini_register_extensions(TSRMLS_D);
+PHPAPI zval *cfg_get_entry(const char *name, uint name_length);
+PHPAPI int cfg_get_long(const char *varname, long *result);
+PHPAPI int cfg_get_double(const char *varname, double *result);
+PHPAPI int cfg_get_string(const char *varname, char **result);
+PHPAPI int php_parse_user_ini_file(const char *dirname, char *ini_filename, HashTable *target_hash TSRMLS_DC);
+PHPAPI void php_ini_activate_config(HashTable *source_hash, int modify_type, int stage TSRMLS_DC);
+PHPAPI int php_ini_has_per_dir_config(void);
+PHPAPI int php_ini_has_per_host_config(void);
+PHPAPI void php_ini_activate_per_dir_config(char *path, uint path_len TSRMLS_DC);
+PHPAPI void php_ini_activate_per_host_config(const char *host, uint host_len TSRMLS_DC);
+PHPAPI HashTable* php_ini_get_configuration_hash(void);
+END_EXTERN_C()
+
+#define PHP_INI_USER ZEND_INI_USER
+#define PHP_INI_PERDIR ZEND_INI_PERDIR
+#define PHP_INI_SYSTEM ZEND_INI_SYSTEM
+
+#define PHP_INI_ALL ZEND_INI_ALL
+
+#define php_ini_entry zend_ini_entry
+
+#define PHP_INI_MH ZEND_INI_MH
+#define PHP_INI_DISP ZEND_INI_DISP
+
+#define PHP_INI_BEGIN ZEND_INI_BEGIN
+#define PHP_INI_END ZEND_INI_END
+
+#define PHP_INI_ENTRY3_EX ZEND_INI_ENTRY3_EX
+#define PHP_INI_ENTRY3 ZEND_INI_ENTRY3
+#define PHP_INI_ENTRY2_EX ZEND_INI_ENTRY2_EX
+#define PHP_INI_ENTRY2 ZEND_INI_ENTRY2
+#define PHP_INI_ENTRY1_EX ZEND_INI_ENTRY1_EX
+#define PHP_INI_ENTRY1 ZEND_INI_ENTRY1
+#define PHP_INI_ENTRY_EX ZEND_INI_ENTRY_EX
+#define PHP_INI_ENTRY ZEND_INI_ENTRY
+
+#define STD_PHP_INI_ENTRY STD_ZEND_INI_ENTRY
+#define STD_PHP_INI_ENTRY_EX STD_ZEND_INI_ENTRY_EX
+#define STD_PHP_INI_BOOLEAN STD_ZEND_INI_BOOLEAN
+
+#define PHP_INI_DISPLAY_ORIG ZEND_INI_DISPLAY_ORIG
+#define PHP_INI_DISPLAY_ACTIVE ZEND_INI_DISPLAY_ACTIVE
+
+#define PHP_INI_STAGE_STARTUP ZEND_INI_STAGE_STARTUP
+#define PHP_INI_STAGE_SHUTDOWN ZEND_INI_STAGE_SHUTDOWN
+#define PHP_INI_STAGE_ACTIVATE ZEND_INI_STAGE_ACTIVATE
+#define PHP_INI_STAGE_DEACTIVATE ZEND_INI_STAGE_DEACTIVATE
+#define PHP_INI_STAGE_RUNTIME ZEND_INI_STAGE_RUNTIME
+#define PHP_INI_STAGE_HTACCESS ZEND_INI_STAGE_HTACCESS
+
+#define php_ini_boolean_displayer_cb zend_ini_boolean_displayer_cb
+#define php_ini_color_displayer_cb zend_ini_color_displayer_cb
+
+#define php_alter_ini_entry zend_alter_ini_entry
+
+#define php_ini_long zend_ini_long
+#define php_ini_double zend_ini_double
+#define php_ini_string zend_ini_string
+
+#endif /* PHP_INI_H */
diff --git a/main/php_logos.c b/main/php_logos.c
new file mode 100644
index 0000000..5162c6c
--- /dev/null
+++ b/main/php_logos.c
@@ -0,0 +1,99 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Hartmut Holzgraefe <hholzgra@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+#include "logos.h"
+#include "php_logos.h"
+#include "ext/standard/info.h"
+#include "SAPI.h"
+
+typedef struct _php_info_logo {
+ const char *mimetype;
+ int mimelen;
+ const unsigned char *data;
+ int size;
+} php_info_logo;
+
+static HashTable phpinfo_logo_hash;
+
+PHPAPI int php_register_info_logo(char *logo_string, const char *mimetype, const unsigned char *data, int size)
+{
+ php_info_logo info_logo;
+
+ info_logo.mimetype = mimetype;
+ info_logo.mimelen = strlen(mimetype);
+ info_logo.data = data;
+ info_logo.size = size;
+
+ return zend_hash_add(&phpinfo_logo_hash, logo_string, strlen(logo_string), &info_logo, sizeof(php_info_logo), NULL);
+}
+
+PHPAPI int php_unregister_info_logo(char *logo_string)
+{
+ return zend_hash_del(&phpinfo_logo_hash, logo_string, strlen(logo_string));
+}
+
+int php_init_info_logos(void)
+{
+ if(zend_hash_init(&phpinfo_logo_hash, 0, NULL, NULL, 1)==FAILURE)
+ return FAILURE;
+
+ php_register_info_logo(PHP_LOGO_GUID , "image/gif", php_logo , sizeof(php_logo));
+ php_register_info_logo(PHP_EGG_LOGO_GUID, "image/gif", php_egg_logo, sizeof(php_egg_logo));
+ php_register_info_logo(ZEND_LOGO_GUID , "image/gif", zend_logo , sizeof(zend_logo));
+
+ return SUCCESS;
+}
+
+int php_shutdown_info_logos(void)
+{
+ zend_hash_destroy(&phpinfo_logo_hash);
+ return SUCCESS;
+}
+
+#define CONTENT_TYPE_HEADER "Content-Type: "
+int php_info_logos(const char *logo_string TSRMLS_DC)
+{
+ php_info_logo *logo_image;
+ char *content_header;
+ int len;
+
+ if(FAILURE==zend_hash_find(&phpinfo_logo_hash, (char *) logo_string, strlen(logo_string), (void **)&logo_image))
+ return 0;
+
+ len = sizeof(CONTENT_TYPE_HEADER) - 1 + logo_image->mimelen;
+ content_header = emalloc(len + 1);
+ memcpy(content_header, CONTENT_TYPE_HEADER, sizeof(CONTENT_TYPE_HEADER) - 1);
+ memcpy(content_header + sizeof(CONTENT_TYPE_HEADER) - 1 , logo_image->mimetype, logo_image->mimelen);
+ content_header[len] = '\0';
+ sapi_add_header(content_header, len, 0);
+
+ PHPWRITE((char*)logo_image->data, logo_image->size);
+ return 1;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_logos.h b/main/php_logos.h
new file mode 100644
index 0000000..d0f0b5e
--- /dev/null
+++ b/main/php_logos.h
@@ -0,0 +1,34 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+
+#ifndef _PHP_LOGOS_H
+#define _PHP_LOGOS_H
+
+BEGIN_EXTERN_C()
+PHPAPI int php_register_info_logo(char *logo_string, const char *mimetype, const unsigned char *data, int size);
+PHPAPI int php_unregister_info_logo(char *logo_string);
+END_EXTERN_C()
+
+int php_init_info_logos(void);
+int php_shutdown_info_logos(void);
+int php_info_logos(const char *logo_string TSRMLS_DC);
+
+#endif /* _PHP_LOGOS_H */
diff --git a/main/php_main.h b/main/php_main.h
new file mode 100644
index 0000000..68ae837
--- /dev/null
+++ b/main/php_main.h
@@ -0,0 +1,61 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef PHP_MAIN_H
+#define PHP_MAIN_H
+
+#include "zend_globals.h"
+#include "php_globals.h"
+#include "SAPI.h"
+
+BEGIN_EXTERN_C()
+PHPAPI int php_request_startup(TSRMLS_D);
+PHPAPI void php_request_shutdown(void *dummy);
+PHPAPI void php_request_shutdown_for_exec(void *dummy);
+PHPAPI int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules);
+PHPAPI void php_module_shutdown(TSRMLS_D);
+PHPAPI void php_module_shutdown_for_exec(void);
+PHPAPI int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals);
+PHPAPI int php_request_startup_for_hook(TSRMLS_D);
+PHPAPI void php_request_shutdown_for_hook(void *dummy);
+
+PHPAPI int php_register_extensions(zend_module_entry **ptr, int count TSRMLS_DC);
+
+PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC);
+PHPAPI int php_execute_simple_script(zend_file_handle *primary_file, zval **ret TSRMLS_DC);
+PHPAPI int php_handle_special_queries(TSRMLS_D);
+PHPAPI int php_lint_script(zend_file_handle *file TSRMLS_DC);
+
+PHPAPI void php_handle_aborted_connection(void);
+PHPAPI int php_handle_auth_data(const char *auth TSRMLS_DC);
+
+PHPAPI void php_html_puts(const char *str, uint siz TSRMLS_DC);
+PHPAPI int php_stream_open_for_zend_ex(const char *filename, zend_file_handle *handle, int mode TSRMLS_DC);
+
+extern void php_call_shutdown_functions(TSRMLS_D);
+extern void php_free_shutdown_functions(TSRMLS_D);
+
+/* environment module */
+extern int php_init_environ(void);
+extern int php_shutdown_environ(void);
+END_EXTERN_C()
+
+#endif
diff --git a/main/php_memory_streams.h b/main/php_memory_streams.h
new file mode 100644
index 0000000..0f975cc
--- /dev/null
+++ b/main/php_memory_streams.h
@@ -0,0 +1,68 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef PHP_MEMORY_STREAM_H
+#define PHP_MEMORY_STREAM_H
+
+#include "php_streams.h"
+
+#define PHP_STREAM_MAX_MEM 2 * 1024 * 1024
+
+#define TEMP_STREAM_DEFAULT 0
+#define TEMP_STREAM_READONLY 1
+#define TEMP_STREAM_TAKE_BUFFER 2
+
+#define php_stream_memory_create(mode) _php_stream_memory_create((mode) STREAMS_CC TSRMLS_CC)
+#define php_stream_memory_create_rel(mode) _php_stream_memory_create((mode) STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_memory_open(mode, buf, length) _php_stream_memory_open((mode), (buf), (length) STREAMS_CC TSRMLS_CC)
+#define php_stream_memory_get_buffer(stream, length) _php_stream_memory_get_buffer((stream), (length) STREAMS_CC TSRMLS_CC)
+
+#define php_stream_temp_new() php_stream_temp_create(TEMP_STREAM_DEFAULT, PHP_STREAM_MAX_MEM)
+#define php_stream_temp_create(mode, max_memory_usage) _php_stream_temp_create((mode), (max_memory_usage) STREAMS_CC TSRMLS_CC)
+#define php_stream_temp_create_rel(mode, max_memory_usage) _php_stream_temp_create((mode), (max_memory_usage) STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_temp_open(mode, max_memory_usage, buf, length) _php_stream_temp_open((mode), (max_memory_usage), (buf), (length) STREAMS_CC TSRMLS_CC)
+
+BEGIN_EXTERN_C()
+PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC TSRMLS_DC);
+PHPAPI php_stream *_php_stream_memory_open(int mode, char *buf, size_t length STREAMS_DC TSRMLS_DC);
+PHPAPI char *_php_stream_memory_get_buffer(php_stream *stream, size_t *length STREAMS_DC TSRMLS_DC);
+
+PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STREAMS_DC TSRMLS_DC);
+PHPAPI php_stream *_php_stream_temp_open(int mode, size_t max_memory_usage, char *buf, size_t length STREAMS_DC TSRMLS_DC);
+END_EXTERN_C()
+
+extern PHPAPI php_stream_ops php_stream_memory_ops;
+extern PHPAPI php_stream_ops php_stream_temp_ops;
+extern PHPAPI php_stream_ops php_stream_rfc2397_ops;
+extern PHPAPI php_stream_wrapper php_stream_rfc2397_wrapper;
+
+#define PHP_STREAM_IS_MEMORY &php_stream_memory_ops
+#define PHP_STREAM_IS_TEMP &php_stream_temp_ops
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_network.h b/main/php_network.h
new file mode 100644
index 0000000..8ffb51c
--- /dev/null
+++ b/main/php_network.h
@@ -0,0 +1,321 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Stig Venaas <venaas@uninett.no> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef _PHP_NETWORK_H
+#define _PHP_NETWORK_H
+
+#ifdef PHP_WIN32
+# include "win32/inet.h"
+#else
+# undef closesocket
+# define closesocket close
+#endif
+
+#ifndef HAVE_SHUTDOWN
+#undef shutdown
+#define shutdown(s,n) /* nothing */
+#endif
+
+#ifdef PHP_WIN32
+# ifdef EWOULDBLOCK
+# undef EWOULDBLOCK
+# endif
+# ifdef EINPROGRESS
+# undef EINPROGRESS
+# endif
+# define EWOULDBLOCK WSAEWOULDBLOCK
+# define EINPROGRESS WSAEWOULDBLOCK
+# define fsync _commit
+# define ftruncate(a, b) chsize(a, b)
+#endif /* defined(PHP_WIN32) */
+
+#ifndef EWOULDBLOCK
+# define EWOULDBLOCK EAGAIN
+#endif
+
+#ifdef PHP_WIN32
+#define php_socket_errno() WSAGetLastError()
+#else
+#define php_socket_errno() errno
+#endif
+
+/* like strerror, but caller must efree the returned string,
+ * unless buf is not NULL.
+ * Also works sensibly for win32 */
+BEGIN_EXTERN_C()
+PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize);
+END_EXTERN_C()
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+/* These are here, rather than with the win32 counterparts above,
+ * since <sys/socket.h> defines them. */
+#ifndef SHUT_RD
+# define SHUT_RD 0
+# define SHUT_WR 1
+# define SHUT_RDWR 2
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+#ifdef PHP_WIN32
+typedef SOCKET php_socket_t;
+#else
+typedef int php_socket_t;
+#endif
+
+#ifdef PHP_WIN32
+# define SOCK_ERR INVALID_SOCKET
+# define SOCK_CONN_ERR SOCKET_ERROR
+# define SOCK_RECV_ERR SOCKET_ERROR
+#else
+# define SOCK_ERR -1
+# define SOCK_CONN_ERR -1
+# define SOCK_RECV_ERR -1
+#endif
+
+/* uncomment this to debug poll(2) emulation on systems that have poll(2) */
+/* #define PHP_USE_POLL_2_EMULATION 1 */
+
+#if defined(HAVE_SYS_POLL_H) && defined(HAVE_POLL)
+# include <sys/poll.h>
+typedef struct pollfd php_pollfd;
+#else
+typedef struct _php_pollfd {
+ php_socket_t fd;
+ short events;
+ short revents;
+} php_pollfd;
+
+PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout);
+
+#ifndef POLLIN
+# define POLLIN 0x0001 /* There is data to read */
+# define POLLPRI 0x0002 /* There is urgent data to read */
+# define POLLOUT 0x0004 /* Writing now will not block */
+# define POLLERR 0x0008 /* Error condition */
+# define POLLHUP 0x0010 /* Hung up */
+# define POLLNVAL 0x0020 /* Invalid request: fd not open */
+#endif
+
+# ifndef PHP_USE_POLL_2_EMULATION
+# define PHP_USE_POLL_2_EMULATION 1
+# endif
+#endif
+
+#define PHP_POLLREADABLE (POLLIN|POLLERR|POLLHUP)
+
+#ifndef PHP_USE_POLL_2_EMULATION
+# define php_poll2(ufds, nfds, timeout) poll(ufds, nfds, timeout)
+#endif
+
+/* timeval-to-timeout (for poll(2)) */
+static inline int php_tvtoto(struct timeval *timeouttv)
+{
+ if (timeouttv) {
+ return (timeouttv->tv_sec * 1000) + (timeouttv->tv_usec / 1000);
+ }
+ return -1;
+}
+
+/* hybrid select(2)/poll(2) for a single descriptor.
+ * timeouttv follows same rules as select(2), but is reduced to millisecond accuracy.
+ * Returns 0 on timeout, -1 on error, or the event mask (ala poll(2)).
+ */
+static inline int php_pollfd_for(php_socket_t fd, int events, struct timeval *timeouttv)
+{
+ php_pollfd p;
+ int n;
+
+ p.fd = fd;
+ p.events = events;
+ p.revents = 0;
+
+ n = php_poll2(&p, 1, php_tvtoto(timeouttv));
+
+ if (n > 0) {
+ return p.revents;
+ }
+
+ return n;
+}
+
+static inline int php_pollfd_for_ms(php_socket_t fd, int events, int timeout)
+{
+ php_pollfd p;
+ int n;
+
+ p.fd = fd;
+ p.events = events;
+ p.revents = 0;
+
+ n = php_poll2(&p, 1, timeout);
+
+ if (n > 0) {
+ return p.revents;
+ }
+
+ return n;
+}
+
+/* emit warning and suggestion for unsafe select(2) usage */
+PHPAPI void _php_emit_fd_setsize_warning(int max_fd);
+
+#ifdef PHP_WIN32
+/* it is safe to FD_SET too many fd's under win32; the macro will simply ignore
+ * descriptors that go beyond the default FD_SETSIZE */
+# define PHP_SAFE_FD_SET(fd, set) FD_SET(fd, set)
+# define PHP_SAFE_FD_CLR(fd, set) FD_CLR(fd, set)
+# define PHP_SAFE_FD_ISSET(fd, set) FD_ISSET(fd, set)
+# define PHP_SAFE_MAX_FD(m, n) do { if (n + 1 >= FD_SETSIZE) { _php_emit_fd_setsize_warning(n); }} while(0)
+#else
+# define PHP_SAFE_FD_SET(fd, set) do { if (fd < FD_SETSIZE) FD_SET(fd, set); } while(0)
+# define PHP_SAFE_FD_CLR(fd, set) do { if (fd < FD_SETSIZE) FD_CLR(fd, set); } while(0)
+# define PHP_SAFE_FD_ISSET(fd, set) ((fd < FD_SETSIZE) && FD_ISSET(fd, set))
+# define PHP_SAFE_MAX_FD(m, n) do { if (m >= FD_SETSIZE) { _php_emit_fd_setsize_warning(m); m = FD_SETSIZE - 1; }} while(0)
+#endif
+
+
+#define PHP_SOCK_CHUNK_SIZE 8192
+
+#ifdef HAVE_SOCKADDR_STORAGE
+typedef struct sockaddr_storage php_sockaddr_storage;
+#else
+typedef struct {
+#ifdef HAVE_SOCKADDR_SA_LEN
+ unsigned char ss_len;
+ unsigned char ss_family;
+#else
+ unsigned short ss_family;
+#endif
+ char info[126];
+} php_sockaddr_storage;
+#endif
+
+BEGIN_EXTERN_C()
+PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, char **error_string TSRMLS_DC);
+PHPAPI void php_network_freeaddresses(struct sockaddr **sal);
+
+PHPAPI php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
+ int socktype, int asynchronous, struct timeval *timeout, char **error_string,
+ int *error_code, char *bindto, unsigned short bindport
+ TSRMLS_DC);
+
+PHPAPI int php_network_connect_socket(php_socket_t sockfd,
+ const struct sockaddr *addr,
+ socklen_t addrlen,
+ int asynchronous,
+ struct timeval *timeout,
+ char **error_string,
+ int *error_code);
+
+#define php_connect_nonb(sock, addr, addrlen, timeout) \
+ php_network_connect_socket((sock), (addr), (addrlen), 0, (timeout), NULL, NULL)
+
+PHPAPI php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port,
+ int socktype, char **error_string, int *error_code
+ TSRMLS_DC);
+
+PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
+ char **textaddr, long *textaddrlen,
+ struct sockaddr **addr,
+ socklen_t *addrlen,
+ struct timeval *timeout,
+ char **error_string,
+ int *error_code
+ TSRMLS_DC);
+
+PHPAPI int php_network_get_sock_name(php_socket_t sock,
+ char **textaddr, long *textaddrlen,
+ struct sockaddr **addr,
+ socklen_t *addrlen
+ TSRMLS_DC);
+
+PHPAPI int php_network_get_peer_name(php_socket_t sock,
+ char **textaddr, long *textaddrlen,
+ struct sockaddr **addr,
+ socklen_t *addrlen
+ TSRMLS_DC);
+
+PHPAPI void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port);
+PHPAPI int php_sockaddr_size(php_sockaddr_storage *addr);
+END_EXTERN_C()
+
+struct _php_netstream_data_t {
+ php_socket_t socket;
+ char is_blocked;
+ struct timeval timeout;
+ char timeout_event;
+ size_t ownsize;
+};
+typedef struct _php_netstream_data_t php_netstream_data_t;
+PHPAPI extern php_stream_ops php_stream_socket_ops;
+extern php_stream_ops php_stream_generic_socket_ops;
+#define PHP_STREAM_IS_SOCKET (&php_stream_socket_ops)
+
+BEGIN_EXTERN_C()
+PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const char *persistent_id STREAMS_DC TSRMLS_DC );
+/* open a connection to a host using php_hostconnect and return a stream */
+PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short port,
+ int socktype, struct timeval *timeout, const char *persistent_id STREAMS_DC TSRMLS_DC);
+PHPAPI void php_network_populate_name_from_sockaddr(
+ /* input address */
+ struct sockaddr *sa, socklen_t sl,
+ /* output readable address */
+ char **textaddr, long *textaddrlen,
+ /* output address */
+ struct sockaddr **addr,
+ socklen_t *addrlen
+ TSRMLS_DC);
+
+PHPAPI int php_network_parse_network_address_with_port(const char *addr,
+ long addrlen, struct sockaddr *sa, socklen_t *sl TSRMLS_DC);
+END_EXTERN_C()
+
+#define php_stream_sock_open_from_socket(socket, persistent) _php_stream_sock_open_from_socket((socket), (persistent) STREAMS_CC TSRMLS_CC)
+#define php_stream_sock_open_host(host, port, socktype, timeout, persistent) _php_stream_sock_open_host((host), (port), (socktype), (timeout), (persistent) STREAMS_CC TSRMLS_CC)
+
+/* {{{ memory debug */
+#define php_stream_sock_open_from_socket_rel(socket, persistent) _php_stream_sock_open_from_socket((socket), (persistent) STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_sock_open_host_rel(host, port, socktype, timeout, persistent) _php_stream_sock_open_host((host), (port), (socktype), (timeout), (persistent) STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_sock_open_unix_rel(path, pathlen, persistent, timeval) _php_stream_sock_open_unix((path), (pathlen), (persistent), (timeval) STREAMS_REL_CC TSRMLS_CC)
+
+/* }}} */
+
+#endif /* _PHP_NETWORK_H */
+
+/*
+ * Local variables:
+ * tab-width: 8
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/main/php_open_temporary_file.c b/main/php_open_temporary_file.c
new file mode 100644
index 0000000..b43d6a7
--- /dev/null
+++ b/main/php_open_temporary_file.c
@@ -0,0 +1,314 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "php.h"
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef PHP_WIN32
+#define O_RDONLY _O_RDONLY
+#include "win32/param.h"
+#include "win32/winutil.h"
+#elif defined(NETWARE)
+#ifdef USE_WINSOCK
+#include <novsock2.h>
+#else
+#include <sys/socket.h>
+#endif
+#include <sys/param.h>
+#else
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+
+#if !defined(P_tmpdir)
+#define P_tmpdir ""
+#endif
+
+/* {{{ php_do_open_temporary_file */
+
+/* Loosely based on a tempnam() implementation by UCLA */
+
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static int php_do_open_temporary_file(const char *path, const char *pfx, char **opened_path_p TSRMLS_DC)
+{
+ char *trailing_slash;
+ char *opened_path;
+ char cwd[MAXPATHLEN];
+ cwd_state new_state;
+ int fd = -1;
+#ifndef HAVE_MKSTEMP
+ int open_flags = O_CREAT | O_TRUNC | O_RDWR
+#ifdef PHP_WIN32
+ | _O_BINARY
+#endif
+ ;
+#endif
+
+ if (!path || !path[0]) {
+ return -1;
+ }
+
+#ifdef PHP_WIN32
+ if (!php_win32_check_trailing_space(pfx, (const int)strlen(pfx))) {
+ SetLastError(ERROR_INVALID_NAME);
+ return -1;
+ }
+#endif
+
+ if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
+ cwd[0] = '\0';
+ }
+
+ new_state.cwd = strdup(cwd);
+ new_state.cwd_length = strlen(cwd);
+
+ if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH TSRMLS_CC)) {
+ free(new_state.cwd);
+ return -1;
+ }
+
+ if (IS_SLASH(new_state.cwd[new_state.cwd_length - 1])) {
+ trailing_slash = "";
+ } else {
+ trailing_slash = "/";
+ }
+
+ if (spprintf(&opened_path, 0, "%s%s%sXXXXXX", new_state.cwd, trailing_slash, pfx) >= MAXPATHLEN) {
+ efree(opened_path);
+ free(new_state.cwd);
+ return -1;
+ }
+
+#ifdef PHP_WIN32
+
+ if (GetTempFileName(new_state.cwd, pfx, 0, opened_path)) {
+ /* Some versions of windows set the temp file to be read-only,
+ * which means that opening it will fail... */
+ if (VCWD_CHMOD(opened_path, 0600)) {
+ efree(opened_path);
+ free(new_state.cwd);
+ return -1;
+ }
+ fd = VCWD_OPEN_MODE(opened_path, open_flags, 0600);
+ }
+
+#elif defined(HAVE_MKSTEMP)
+ fd = mkstemp(opened_path);
+#else
+ if (mktemp(opened_path)) {
+ fd = VCWD_OPEN(opened_path, open_flags);
+ }
+#endif
+
+ if (fd == -1 || !opened_path_p) {
+ efree(opened_path);
+ } else {
+ *opened_path_p = opened_path;
+ }
+ free(new_state.cwd);
+ return fd;
+}
+/* }}} */
+
+/* Cache the chosen temporary directory. */
+static char* temporary_directory;
+
+PHPAPI void php_shutdown_temporary_directory(void)
+{
+ if (temporary_directory) {
+ free(temporary_directory);
+ temporary_directory = NULL;
+ }
+}
+
+/*
+ * Determine where to place temporary files.
+ */
+PHPAPI const char* php_get_temporary_directory(void)
+{
+ /* Did we determine the temporary directory already? */
+ if (temporary_directory) {
+ return temporary_directory;
+ }
+
+#ifdef PHP_WIN32
+ /* We can't count on the environment variables TEMP or TMP,
+ * and so must make the Win32 API call to get the default
+ * directory for temporary files. Note this call checks
+ * the environment values TMP and TEMP (in order) first.
+ */
+ {
+ char sTemp[MAX_PATH];
+ DWORD len = GetTempPath(sizeof(sTemp),sTemp);
+ assert(0 < len); /* should *never* fail! */
+ if (sTemp[len - 1] == DEFAULT_SLASH) {
+ temporary_directory = zend_strndup(sTemp, len - 1);
+ } else {
+ temporary_directory = zend_strndup(sTemp, len);
+ }
+ return temporary_directory;
+ }
+#else
+ /* On Unix use the (usual) TMPDIR environment variable. */
+ {
+ char* s = getenv("TMPDIR");
+ if (s && *s) {
+ int len = strlen(s);
+
+ if (s[len - 1] == DEFAULT_SLASH) {
+ temporary_directory = zend_strndup(s, len - 1);
+ } else {
+ temporary_directory = zend_strndup(s, len);
+ }
+
+ return temporary_directory;
+ }
+ }
+#ifdef P_tmpdir
+ /* Use the standard default temporary directory. */
+ if (P_tmpdir) {
+ temporary_directory = strdup(P_tmpdir);
+ return temporary_directory;
+ }
+#endif
+ /* Shouldn't ever(!) end up here ... last ditch default. */
+ temporary_directory = strdup("/tmp");
+ return temporary_directory;
+#endif
+}
+
+/* {{{ php_open_temporary_file
+ *
+ * Unlike tempnam(), the supplied dir argument takes precedence
+ * over the TMPDIR environment variable
+ * This function should do its best to return a file pointer to a newly created
+ * unique file, on every platform.
+ */
+PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, char **opened_path_p, zend_bool open_basedir_check TSRMLS_DC)
+{
+ int fd;
+ const char *temp_dir;
+
+ if (!pfx) {
+ pfx = "tmp.";
+ }
+ if (opened_path_p) {
+ *opened_path_p = NULL;
+ }
+
+ if (!dir || *dir == '\0') {
+def_tmp:
+ temp_dir = php_get_temporary_directory();
+
+ if (temp_dir && *temp_dir != '\0' && (!open_basedir_check || !php_check_open_basedir(temp_dir TSRMLS_CC))) {
+ return php_do_open_temporary_file(temp_dir, pfx, opened_path_p TSRMLS_CC);
+ } else {
+ return -1;
+ }
+ }
+
+ /* Try the directory given as parameter. */
+ fd = php_do_open_temporary_file(dir, pfx, opened_path_p TSRMLS_CC);
+ if (fd == -1) {
+ /* Use default temporary directory. */
+ goto def_tmp;
+ }
+ return fd;
+}
+
+PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC)
+{
+ return php_open_temporary_fd_ex(dir, pfx, opened_path_p, 0 TSRMLS_CC);
+}
+
+PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC)
+{
+ FILE *fp;
+ int fd = php_open_temporary_fd(dir, pfx, opened_path_p TSRMLS_CC);
+
+ if (fd == -1) {
+ return NULL;
+ }
+
+ fp = fdopen(fd, "r+b");
+ if (fp == NULL) {
+ close(fd);
+ }
+
+ return fp;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_open_temporary_file.h b/main/php_open_temporary_file.h
new file mode 100644
index 0000000..e7dce35
--- /dev/null
+++ b/main/php_open_temporary_file.h
@@ -0,0 +1,32 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_OPEN_TEMPORARY_FILE_H
+#define PHP_OPEN_TEMPORARY_FILE_H
+
+BEGIN_EXTERN_C()
+PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC);
+PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, char **opened_path_p, zend_bool open_basedir_check TSRMLS_DC);
+PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC);
+PHPAPI const char *php_get_temporary_directory(void);
+PHPAPI void php_shutdown_temporary_directory(void);
+END_EXTERN_C()
+
+#endif /* PHP_OPEN_TEMPORARY_FILE_H */
diff --git a/main/php_output.h b/main/php_output.h
new file mode 100644
index 0000000..833bdde
--- /dev/null
+++ b/main/php_output.h
@@ -0,0 +1,279 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Michael Wallner <mike@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_OUTPUT_H
+#define PHP_OUTPUT_H
+
+#define PHP_OUTPUT_NEWAPI 1
+
+/* handler ops */
+#define PHP_OUTPUT_HANDLER_WRITE 0x00 /* standard passthru */
+#define PHP_OUTPUT_HANDLER_START 0x01 /* start */
+#define PHP_OUTPUT_HANDLER_CLEAN 0x02 /* restart */
+#define PHP_OUTPUT_HANDLER_FLUSH 0x04 /* pass along as much as possible */
+#define PHP_OUTPUT_HANDLER_FINAL 0x08 /* finalize */
+#define PHP_OUTPUT_HANDLER_CONT PHP_OUTPUT_HANDLER_WRITE
+#define PHP_OUTPUT_HANDLER_END PHP_OUTPUT_HANDLER_FINAL
+
+/* handler types */
+#define PHP_OUTPUT_HANDLER_INTERNAL 0x0000
+#define PHP_OUTPUT_HANDLER_USER 0x0001
+
+/* handler ability flags */
+#define PHP_OUTPUT_HANDLER_CLEANABLE 0x0010
+#define PHP_OUTPUT_HANDLER_FLUSHABLE 0x0020
+#define PHP_OUTPUT_HANDLER_REMOVABLE 0x0040
+#define PHP_OUTPUT_HANDLER_STDFLAGS 0x0070
+
+/* handler status flags */
+#define PHP_OUTPUT_HANDLER_STARTED 0x1000
+#define PHP_OUTPUT_HANDLER_DISABLED 0x2000
+#define PHP_OUTPUT_HANDLER_PROCESSED 0x4000
+
+/* handler op return values */
+typedef enum _php_output_handler_status_t {
+ PHP_OUTPUT_HANDLER_FAILURE,
+ PHP_OUTPUT_HANDLER_SUCCESS,
+ PHP_OUTPUT_HANDLER_NO_DATA
+} php_output_handler_status_t;
+
+/* php_output_stack_pop() flags */
+#define PHP_OUTPUT_POP_TRY 0x000
+#define PHP_OUTPUT_POP_FORCE 0x001
+#define PHP_OUTPUT_POP_DISCARD 0x010
+#define PHP_OUTPUT_POP_SILENT 0x100
+
+/* real global flags */
+#define PHP_OUTPUT_IMPLICITFLUSH 0x01
+#define PHP_OUTPUT_DISABLED 0x02
+#define PHP_OUTPUT_WRITTEN 0x04
+#define PHP_OUTPUT_SENT 0x08
+/* supplementary flags for php_output_get_status() */
+#define PHP_OUTPUT_ACTIVE 0x10
+#define PHP_OUTPUT_LOCKED 0x20
+/* output layer is ready to use */
+#define PHP_OUTPUT_ACTIVATED 0x100000
+
+/* handler hooks */
+typedef enum _php_output_handler_hook_t {
+ PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ,
+ PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS,
+ PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL,
+ PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE,
+ PHP_OUTPUT_HANDLER_HOOK_DISABLE,
+ /* unused */
+ PHP_OUTPUT_HANDLER_HOOK_LAST
+} php_output_handler_hook_t;
+
+#define PHP_OUTPUT_HANDLER_INITBUF_SIZE(s) \
+( ((s) > 1) ? \
+ (s) + PHP_OUTPUT_HANDLER_ALIGNTO_SIZE - ((s) % (PHP_OUTPUT_HANDLER_ALIGNTO_SIZE)) : \
+ PHP_OUTPUT_HANDLER_DEFAULT_SIZE \
+)
+#define PHP_OUTPUT_HANDLER_ALIGNTO_SIZE 0x1000
+#define PHP_OUTPUT_HANDLER_DEFAULT_SIZE 0x4000
+
+typedef struct _php_output_buffer {
+ char *data;
+ size_t size;
+ size_t used;
+ uint free:1;
+ uint _res:31;
+} php_output_buffer;
+
+typedef struct _php_output_context {
+ int op;
+ php_output_buffer in;
+ php_output_buffer out;
+#ifdef ZTS
+ void ***tsrm_ls;
+#endif
+} php_output_context;
+
+#define PHP_OUTPUT_TSRMLS(ctx) TSRMLS_FETCH_FROM_CTX((ctx)->tsrm_ls)
+
+/* old-style, stateless callback */
+typedef void (*php_output_handler_func_t)(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC);
+/* new-style, opaque context callback */
+typedef int (*php_output_handler_context_func_t)(void **handler_context, php_output_context *output_context);
+/* output handler context dtor */
+typedef void (*php_output_handler_context_dtor_t)(void *opaq TSRMLS_DC);
+/* conflict check callback */
+typedef int (*php_output_handler_conflict_check_t)(const char *handler_name, size_t handler_name_len TSRMLS_DC);
+/* ctor for aliases */
+typedef struct _php_output_handler *(*php_output_handler_alias_ctor_t)(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags TSRMLS_DC);
+
+typedef struct _php_output_handler_user_func_t {
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ zval *zoh;
+} php_output_handler_user_func_t;
+
+typedef struct _php_output_handler {
+ char *name;
+ size_t name_len;
+ int flags;
+ int level;
+ size_t size;
+ php_output_buffer buffer;
+
+ void *opaq;
+ void (*dtor)(void *opaq TSRMLS_DC);
+
+ union {
+ php_output_handler_user_func_t *user;
+ php_output_handler_context_func_t internal;
+ } func;
+} php_output_handler;
+
+ZEND_BEGIN_MODULE_GLOBALS(output)
+ int flags;
+ zend_stack handlers;
+ php_output_handler *active;
+ php_output_handler *running;
+ const char *output_start_filename;
+ int output_start_lineno;
+ZEND_END_MODULE_GLOBALS(output)
+
+/* there should not be a need to use OG() from outside of output.c */
+#ifdef ZTS
+# define OG(v) TSRMG(output_globals_id, zend_output_globals *, v)
+#else
+# define OG(v) (output_globals.v)
+#endif
+
+/* convenience macros */
+#define PHPWRITE(str, str_len) php_output_write((str), (str_len) TSRMLS_CC)
+#define PHPWRITE_H(str, str_len) php_output_write_unbuffered((str), (str_len) TSRMLS_CC)
+
+#define PUTC(c) (php_output_write(&(c), 1 TSRMLS_CC), (c))
+#define PUTC_H(c) (php_output_write_unbuffered(&(c), 1 TSRMLS_CC), (c))
+
+#define PUTS(str) do { \
+ const char *__str = (str); \
+ php_output_write(__str, strlen(__str) TSRMLS_CC); \
+} while (0)
+#define PUTS_H(str) do { \
+ const char *__str = (str); \
+ php_output_write_unbuffered(__str, strlen(__str) TSRMLS_CC); \
+} while (0)
+
+
+BEGIN_EXTERN_C()
+
+extern const char php_output_default_handler_name[sizeof("default output handler")];
+extern const char php_output_devnull_handler_name[sizeof("null output handler")];
+
+#define php_output_tearup() \
+ php_output_startup(); \
+ php_output_activate(TSRMLS_C)
+#define php_output_teardown() \
+ php_output_end_all(TSRMLS_C); \
+ php_output_deactivate(TSRMLS_C); \
+ php_output_shutdown()
+
+/* MINIT */
+PHPAPI void php_output_startup(void);
+/* MSHUTDOWN */
+PHPAPI void php_output_shutdown(void);
+
+PHPAPI void php_output_register_constants(TSRMLS_D);
+
+/* RINIT */
+PHPAPI int php_output_activate(TSRMLS_D);
+/* RSHUTDOWN */
+PHPAPI void php_output_deactivate(TSRMLS_D);
+
+PHPAPI void php_output_set_status(int status TSRMLS_DC);
+PHPAPI int php_output_get_status(TSRMLS_D);
+PHPAPI void php_output_set_implicit_flush(int flush TSRMLS_DC);
+PHPAPI const char *php_output_get_start_filename(TSRMLS_D);
+PHPAPI int php_output_get_start_lineno(TSRMLS_D);
+
+PHPAPI int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC);
+PHPAPI int php_output_write(const char *str, size_t len TSRMLS_DC);
+
+PHPAPI int php_output_flush(TSRMLS_D);
+PHPAPI void php_output_flush_all(TSRMLS_D);
+PHPAPI int php_output_clean(TSRMLS_D);
+PHPAPI void php_output_clean_all(TSRMLS_D);
+PHPAPI int php_output_end(TSRMLS_D);
+PHPAPI void php_output_end_all(TSRMLS_D);
+PHPAPI int php_output_discard(TSRMLS_D);
+PHPAPI void php_output_discard_all(TSRMLS_D);
+
+PHPAPI int php_output_get_contents(zval *p TSRMLS_DC);
+PHPAPI int php_output_get_length(zval *p TSRMLS_DC);
+PHPAPI int php_output_get_level(TSRMLS_D);
+PHPAPI php_output_handler* php_output_get_active_handler(TSRMLS_D);
+
+PHPAPI int php_output_start_default(TSRMLS_D);
+PHPAPI int php_output_start_devnull(TSRMLS_D);
+
+PHPAPI int php_output_start_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC);
+PHPAPI int php_output_start_internal(const char *name, size_t name_len, php_output_handler_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC);
+
+PHPAPI php_output_handler *php_output_handler_create_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC);
+PHPAPI php_output_handler *php_output_handler_create_internal(const char *name, size_t name_len, php_output_handler_context_func_t handler, size_t chunk_size, int flags TSRMLS_DC);
+
+PHPAPI void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC);
+PHPAPI int php_output_handler_start(php_output_handler *handler TSRMLS_DC);
+PHPAPI int php_output_handler_started(const char *name, size_t name_len TSRMLS_DC);
+PHPAPI int php_output_handler_hook(php_output_handler_hook_t type, void *arg TSRMLS_DC);
+PHPAPI void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC);
+PHPAPI void php_output_handler_free(php_output_handler **handler TSRMLS_DC);
+
+PHPAPI int php_output_handler_conflict(const char *handler_new, size_t handler_new_len, const char *handler_set, size_t handler_set_len TSRMLS_DC);
+PHPAPI int php_output_handler_conflict_register(const char *handler_name, size_t handler_name_len, php_output_handler_conflict_check_t check_func TSRMLS_DC);
+PHPAPI int php_output_handler_reverse_conflict_register(const char *handler_name, size_t handler_name_len, php_output_handler_conflict_check_t check_func TSRMLS_DC);
+
+PHPAPI php_output_handler_alias_ctor_t *php_output_handler_alias(const char *handler_name, size_t handler_name_len TSRMLS_DC);
+PHPAPI int php_output_handler_alias_register(const char *handler_name, size_t handler_name_len, php_output_handler_alias_ctor_t func TSRMLS_DC);
+
+END_EXTERN_C()
+
+
+PHP_FUNCTION(ob_start);
+PHP_FUNCTION(ob_flush);
+PHP_FUNCTION(ob_clean);
+PHP_FUNCTION(ob_end_flush);
+PHP_FUNCTION(ob_end_clean);
+PHP_FUNCTION(ob_get_flush);
+PHP_FUNCTION(ob_get_clean);
+PHP_FUNCTION(ob_get_contents);
+PHP_FUNCTION(ob_get_length);
+PHP_FUNCTION(ob_get_level);
+PHP_FUNCTION(ob_get_status);
+PHP_FUNCTION(ob_implicit_flush);
+PHP_FUNCTION(ob_list_handlers);
+
+PHP_FUNCTION(output_add_rewrite_var);
+PHP_FUNCTION(output_reset_rewrite_vars);
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_reentrancy.h b/main/php_reentrancy.h
new file mode 100644
index 0000000..50f2e20
--- /dev/null
+++ b/main/php_reentrancy.h
@@ -0,0 +1,133 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Sascha Schumann <sascha@schumann.cx> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef PHP_REENTRANCY_H
+#define PHP_REENTRANCY_H
+
+#include "php.h"
+
+#include <sys/types.h>
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#include <time.h>
+
+/* currently, PHP does not check for these functions, but assumes
+ that they are available on all systems. */
+
+#define HAVE_LOCALTIME 1
+#define HAVE_GMTIME 1
+#define HAVE_ASCTIME 1
+#define HAVE_CTIME 1
+
+#if defined(PHP_IRIX_TIME_R)
+#undef HAVE_ASCTIME_R
+#undef HAVE_CTIME_R
+#endif
+
+#if defined(PHP_HPUX_TIME_R)
+#undef HAVE_LOCALTIME_R
+#undef HAVE_ASCTIME_R
+#undef HAVE_CTIME_R
+#undef HAVE_GMTIME_R
+#endif
+
+BEGIN_EXTERN_C()
+
+#if defined(HAVE_POSIX_READDIR_R)
+#define php_readdir_r readdir_r
+#else
+PHPAPI int php_readdir_r(DIR *dirp, struct dirent *entry,
+ struct dirent **result);
+#endif
+
+#if !defined(HAVE_LOCALTIME_R) && defined(HAVE_LOCALTIME)
+#define PHP_NEED_REENTRANCY 1
+PHPAPI struct tm *php_localtime_r(const time_t *const timep, struct tm *p_tm);
+#else
+#define php_localtime_r localtime_r
+#ifdef MISSING_LOCALTIME_R_DECL
+struct tm *localtime_r(const time_t *const timep, struct tm *p_tm);
+#endif
+#endif
+
+
+#if !defined(HAVE_CTIME_R) && defined(HAVE_CTIME)
+#define PHP_NEED_REENTRANCY 1
+PHPAPI char *php_ctime_r(const time_t *clock, char *buf);
+#else
+#define php_ctime_r ctime_r
+#ifdef MISSING_CTIME_R_DECL
+char *ctime_r(const time_t *clock, char *buf);
+#endif
+#endif
+
+
+#if !defined(HAVE_ASCTIME_R) && defined(HAVE_ASCTIME)
+#define PHP_NEED_REENTRANCY 1
+PHPAPI char *php_asctime_r(const struct tm *tm, char *buf);
+#else
+#define php_asctime_r asctime_r
+#ifdef MISSING_ASCTIME_R_DECL
+char *asctime_r(const struct tm *tm, char *buf);
+#endif
+#endif
+
+
+#if !defined(HAVE_GMTIME_R) && defined(HAVE_GMTIME) || defined(__BEOS__)
+#define PHP_NEED_REENTRANCY 1
+PHPAPI struct tm *php_gmtime_r(const time_t *const timep, struct tm *p_tm);
+#else
+#define php_gmtime_r gmtime_r
+#ifdef MISSING_GMTIME_R_DECL
+struct tm *php_gmtime_r(const time_t *const timep, struct tm *p_tm);
+#endif
+#endif
+
+#if !defined(HAVE_STRTOK_R)
+PHPAPI char *php_strtok_r(char *s, const char *delim, char **last);
+#else
+#define php_strtok_r strtok_r
+#ifdef MISSING_STRTOK_R_DECL
+char *strtok_r(char *s, const char *delim, char **last);
+#endif
+#endif
+
+#if !defined(HAVE_RAND_R)
+PHPAPI int php_rand_r(unsigned int *seed);
+#else
+#define php_rand_r rand_r
+#endif
+
+END_EXTERN_C()
+
+#if !defined(ZTS)
+#undef PHP_NEED_REENTRANCY
+#endif
+
+#if defined(PHP_NEED_REENTRANCY)
+void reentrancy_startup(void);
+void reentrancy_shutdown(void);
+#else
+#define reentrancy_startup()
+#define reentrancy_shutdown()
+#endif
+
+#endif
diff --git a/main/php_scandir.c b/main/php_scandir.c
new file mode 100644
index 0000000..9f3042e
--- /dev/null
+++ b/main/php_scandir.c
@@ -0,0 +1,136 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Shane Caraveo <shane@caraveo.com> |
+ | Ilia Alshanetsky <ilia@prohost.org> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "php.h"
+#include "php_scandir.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#ifndef HAVE_SCANDIR
+
+#ifdef PHP_WIN32
+#include "win32/param.h"
+#include "win32/readdir.h"
+#endif
+
+#include <stdlib.h>
+#ifndef NETWARE
+#include <search.h>
+#endif
+
+#endif /* HAVE_SCANDIR */
+
+#ifndef HAVE_ALPHASORT
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+PHPAPI int php_alphasort(const struct dirent **a, const struct dirent **b)
+{
+ return strcoll((*a)->d_name,(*b)->d_name);
+}
+#endif /* HAVE_ALPHASORT */
+
+#ifndef HAVE_SCANDIR
+PHPAPI int php_scandir(const char *dirname, struct dirent **namelist[], int (*selector) (const struct dirent *entry), int (*compare) (const struct dirent **a, const struct dirent **b))
+{
+ DIR *dirp = NULL;
+ struct dirent **vector = NULL;
+ int vector_size = 0;
+ int nfiles = 0;
+ char entry[sizeof(struct dirent)+MAXPATHLEN];
+ struct dirent *dp = (struct dirent *)&entry;
+
+ if (namelist == NULL) {
+ return -1;
+ }
+
+ if (!(dirp = opendir(dirname))) {
+ return -1;
+ }
+
+ while (!php_readdir_r(dirp, (struct dirent *)entry, &dp) && dp) {
+ int dsize = 0;
+ struct dirent *newdp = NULL;
+
+ if (selector && (*selector)(dp) == 0) {
+ continue;
+ }
+
+ if (nfiles == vector_size) {
+ struct dirent **newv;
+ if (vector_size == 0) {
+ vector_size = 10;
+ } else {
+ vector_size *= 2;
+ }
+
+ newv = (struct dirent **) realloc (vector, vector_size * sizeof (struct dirent *));
+ if (!newv) {
+ return -1;
+ }
+ vector = newv;
+ }
+
+ dsize = sizeof (struct dirent) + ((strlen(dp->d_name) + 1) * sizeof(char));
+ newdp = (struct dirent *) malloc(dsize);
+
+ if (newdp == NULL) {
+ goto fail;
+ }
+
+ vector[nfiles++] = (struct dirent *) memcpy(newdp, dp, dsize);
+ }
+
+ closedir(dirp);
+
+ *namelist = vector;
+
+ if (compare) {
+ qsort (*namelist, nfiles, sizeof(struct dirent *), compare);
+ }
+
+ return nfiles;
+
+fail:
+ while (nfiles-- > 0) {
+ free(vector[nfiles]);
+ }
+ free(vector);
+ return -1;
+}
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_scandir.h b/main/php_scandir.h
new file mode 100644
index 0000000..ad68e8d
--- /dev/null
+++ b/main/php_scandir.h
@@ -0,0 +1,54 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Shane Caraveo <shane@caraveo.com> |
+ | Ilia Alshanetsky <ilia@prohost.org> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_SCANDIR_H
+#define PHP_SCANDIR_H
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_DIR_H
+#include <sys/dir.h>
+#endif
+
+#ifdef PHP_WIN32
+#include "config.w32.h"
+#include "win32/readdir.h"
+#else
+#include <php_config.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#ifdef HAVE_SCANDIR
+#define php_scandir scandir
+#else
+PHPAPI int php_scandir(const char *dirname, struct dirent **namelist[], int (*selector) (const struct dirent *entry), int (*compare) (const struct dirent **a, const struct dirent **b));
+#endif
+
+#ifdef HAVE_ALPHASORT
+#define php_alphasort alphasort
+#else
+PHPAPI int php_alphasort(const struct dirent **a, const struct dirent **b);
+#endif
+
+#endif /* PHP_SCANDIR_H */
diff --git a/main/php_sprintf.c b/main/php_sprintf.c
new file mode 100644
index 0000000..9df43a5
--- /dev/null
+++ b/main/php_sprintf.c
@@ -0,0 +1,50 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Jaakko Hyvätti <jaakko.hyvatti@iki.fi> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "php.h"
+#ifdef PHP_WIN32
+#include "config.w32.h"
+#else
+#include <php_config.h>
+#endif
+
+PHPAPI int
+php_sprintf (char*s, const char* format, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start (args, format);
+ s[0] = '\0';
+ ret = vsprintf (s, format, args);
+ va_end (args);
+ return (ret < 0) ? -1 : ret;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_streams.h b/main/php_streams.h
new file mode 100644
index 0000000..f9b9433
--- /dev/null
+++ b/main/php_streams.h
@@ -0,0 +1,611 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong (wez@thebrainroom.com) |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef PHP_STREAMS_H
+#define PHP_STREAMS_H
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+
+BEGIN_EXTERN_C()
+PHPAPI int php_file_le_stream(void);
+PHPAPI int php_file_le_pstream(void);
+PHPAPI int php_file_le_stream_filter(void);
+END_EXTERN_C()
+
+/* {{{ Streams memory debugging stuff */
+
+#if ZEND_DEBUG
+/* these have more of a dependency on the definitions of the zend macros than
+ * I would prefer, but doing it this way saves loads of idefs :-/ */
+# define STREAMS_D int __php_stream_call_depth ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC
+# define STREAMS_C 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC
+# define STREAMS_REL_C __php_stream_call_depth + 1 ZEND_FILE_LINE_CC, \
+ __php_stream_call_depth ? __zend_orig_filename : __zend_filename, \
+ __php_stream_call_depth ? __zend_orig_lineno : __zend_lineno
+
+# define STREAMS_DC , STREAMS_D
+# define STREAMS_CC , STREAMS_C
+# define STREAMS_REL_CC , STREAMS_REL_C
+
+#else
+# define STREAMS_D
+# define STREAMS_C
+# define STREAMS_REL_C
+# define STREAMS_DC
+# define STREAMS_CC
+# define STREAMS_REL_CC
+#endif
+
+/* these functions relay the file/line number information. They are depth aware, so they will pass
+ * the ultimate ancestor, which is useful, because there can be several layers of calls */
+#define php_stream_alloc_rel(ops, thisptr, persistent, mode) _php_stream_alloc((ops), (thisptr), (persistent), (mode) STREAMS_REL_CC TSRMLS_CC)
+
+#define php_stream_copy_to_mem_rel(src, buf, maxlen, persistent) _php_stream_copy_to_mem((src), (buf), (maxlen), (persistent) STREAMS_REL_CC TSRMLS_CC)
+
+#define php_stream_fopen_rel(filename, mode, opened, options) _php_stream_fopen((filename), (mode), (opened), (options) STREAMS_REL_CC TSRMLS_CC)
+
+#define php_stream_fopen_with_path_rel(filename, mode, path, opened, options) _php_stream_fopen_with_path((filename), (mode), (path), (opened), (options) STREAMS_REL_CC TSRMLS_CC)
+
+#define php_stream_fopen_from_fd_rel(fd, mode, persistent_id) _php_stream_fopen_from_fd((fd), (mode), (persistent_id) STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_fopen_from_file_rel(file, mode) _php_stream_fopen_from_file((file), (mode) STREAMS_REL_CC TSRMLS_CC)
+
+#define php_stream_fopen_from_pipe_rel(file, mode) _php_stream_fopen_from_pipe((file), (mode) STREAMS_REL_CC TSRMLS_CC)
+
+#define php_stream_fopen_tmpfile_rel() _php_stream_fopen_tmpfile(0 STREAMS_REL_CC TSRMLS_CC)
+
+#define php_stream_fopen_temporary_file_rel(dir, pfx, opened_path) _php_stream_fopen_temporary_file((dir), (pfx), (opened_path) STREAMS_REL_CC TSRMLS_CC)
+
+#define php_stream_open_wrapper_rel(path, mode, options, opened) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), NULL STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_open_wrapper_ex_rel(path, mode, options, opened, context) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), (context) STREAMS_REL_CC TSRMLS_CC)
+
+#define php_stream_make_seekable_rel(origstream, newstream, flags) _php_stream_make_seekable((origstream), (newstream), (flags) STREAMS_REL_CC TSRMLS_CC)
+
+/* }}} */
+
+/* The contents of the php_stream_ops and php_stream should only be accessed
+ * using the functions/macros in this header.
+ * If you need to get at something that doesn't have an API,
+ * drop me a line <wez@thebrainroom.com> and we can sort out a way to do
+ * it properly.
+ *
+ * The only exceptions to this rule are that stream implementations can use
+ * the php_stream->abstract pointer to hold their context, and streams
+ * opened via stream_open_wrappers can use the zval ptr in
+ * php_stream->wrapperdata to hold meta data for php scripts to
+ * retrieve using file_get_wrapper_data(). */
+
+typedef struct _php_stream php_stream;
+typedef struct _php_stream_wrapper php_stream_wrapper;
+typedef struct _php_stream_context php_stream_context;
+typedef struct _php_stream_filter php_stream_filter;
+
+#include "streams/php_stream_context.h"
+#include "streams/php_stream_filter_api.h"
+
+typedef struct _php_stream_statbuf {
+ struct stat sb; /* regular info */
+ /* extended info to go here some day: content-type etc. etc. */
+} php_stream_statbuf;
+
+typedef struct _php_stream_dirent {
+ char d_name[MAXPATHLEN];
+} php_stream_dirent;
+
+/* operations on streams that are file-handles */
+typedef struct _php_stream_ops {
+ /* stdio like functions - these are mandatory! */
+ size_t (*write)(php_stream *stream, const char *buf, size_t count TSRMLS_DC);
+ size_t (*read)(php_stream *stream, char *buf, size_t count TSRMLS_DC);
+ int (*close)(php_stream *stream, int close_handle TSRMLS_DC);
+ int (*flush)(php_stream *stream TSRMLS_DC);
+
+ const char *label; /* label for this ops structure */
+
+ /* these are optional */
+ int (*seek)(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC);
+ int (*cast)(php_stream *stream, int castas, void **ret TSRMLS_DC);
+ int (*stat)(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC);
+ int (*set_option)(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC);
+} php_stream_ops;
+
+typedef struct _php_stream_wrapper_ops {
+ /* open/create a wrapped stream */
+ php_stream *(*stream_opener)(php_stream_wrapper *wrapper, char *filename, char *mode,
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
+ /* close/destroy a wrapped stream */
+ int (*stream_closer)(php_stream_wrapper *wrapper, php_stream *stream TSRMLS_DC);
+ /* stat a wrapped stream */
+ int (*stream_stat)(php_stream_wrapper *wrapper, php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC);
+ /* stat a URL */
+ int (*url_stat)(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC);
+ /* open a "directory" stream */
+ php_stream *(*dir_opener)(php_stream_wrapper *wrapper, char *filename, char *mode,
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
+
+ const char *label;
+
+ /* delete a file */
+ int (*unlink)(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
+
+ /* rename a file */
+ int (*rename)(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC);
+
+ /* Create/Remove directory */
+ int (*stream_mkdir)(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC);
+ int (*stream_rmdir)(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
+ /* Metadata handling */
+ int (*stream_metadata)(php_stream_wrapper *wrapper, char *url, int options, void *value, php_stream_context *context TSRMLS_DC);
+} php_stream_wrapper_ops;
+
+struct _php_stream_wrapper {
+ php_stream_wrapper_ops *wops; /* operations the wrapper can perform */
+ void *abstract; /* context for the wrapper */
+ int is_url; /* so that PG(allow_url_fopen) can be respected */
+
+ /* support for wrappers to return (multiple) error messages to the stream opener */
+ int err_count; /* unused */
+ char **err_stack; /* unusued */
+};
+
+#define PHP_STREAM_FLAG_NO_SEEK 1
+#define PHP_STREAM_FLAG_NO_BUFFER 2
+
+#define PHP_STREAM_FLAG_EOL_UNIX 0 /* also includes DOS */
+#define PHP_STREAM_FLAG_DETECT_EOL 4
+#define PHP_STREAM_FLAG_EOL_MAC 8
+
+/* set this when the stream might represent "interactive" data.
+ * When set, the read buffer will avoid certain operations that
+ * might otherwise cause the read to block for much longer than
+ * is strictly required. */
+#define PHP_STREAM_FLAG_AVOID_BLOCKING 16
+
+#define PHP_STREAM_FLAG_NO_CLOSE 32
+
+#define PHP_STREAM_FLAG_IS_DIR 64
+
+#define PHP_STREAM_FLAG_NO_FCLOSE 128
+
+struct _php_stream {
+ php_stream_ops *ops;
+ void *abstract; /* convenience pointer for abstraction */
+
+ php_stream_filter_chain readfilters, writefilters;
+
+ php_stream_wrapper *wrapper; /* which wrapper was used to open the stream */
+ void *wrapperthis; /* convenience pointer for a instance of a wrapper */
+ zval *wrapperdata; /* fgetwrapperdata retrieves this */
+
+ int fgetss_state; /* for fgetss to handle multiline tags */
+ int is_persistent;
+ char mode[16]; /* "rwb" etc. ala stdio */
+ int rsrc_id; /* used for auto-cleanup */
+ int in_free; /* to prevent recursion during free */
+ /* so we know how to clean it up correctly. This should be set to
+ * PHP_STREAM_FCLOSE_XXX as appropriate */
+ int fclose_stdiocast;
+ FILE *stdiocast; /* cache this, otherwise we might leak! */
+#if ZEND_DEBUG
+ int __exposed; /* non-zero if exposed as a zval somewhere */
+#endif
+ char *orig_path;
+
+ php_stream_context *context;
+ int flags; /* PHP_STREAM_FLAG_XXX */
+
+ /* buffer */
+ off_t position; /* of underlying stream */
+ unsigned char *readbuf;
+ size_t readbuflen;
+ off_t readpos;
+ off_t writepos;
+
+ /* how much data to read when filling buffer */
+ size_t chunk_size;
+
+ int eof;
+
+#if ZEND_DEBUG
+ const char *open_filename;
+ uint open_lineno;
+#endif
+
+ struct _php_stream *enclosing_stream; /* this is a private stream owned by enclosing_stream */
+}; /* php_stream */
+
+/* state definitions when closing down; these are private to streams.c */
+#define PHP_STREAM_FCLOSE_NONE 0
+#define PHP_STREAM_FCLOSE_FDOPEN 1
+#define PHP_STREAM_FCLOSE_FOPENCOOKIE 2
+
+/* allocate a new stream for a particular ops */
+BEGIN_EXTERN_C()
+PHPAPI php_stream *_php_stream_alloc(php_stream_ops *ops, void *abstract,
+ const char *persistent_id, const char *mode STREAMS_DC TSRMLS_DC);
+END_EXTERN_C()
+#define php_stream_alloc(ops, thisptr, persistent_id, mode) _php_stream_alloc((ops), (thisptr), (persistent_id), (mode) STREAMS_CC TSRMLS_CC)
+
+#define php_stream_get_resource_id(stream) (stream)->rsrc_id
+#if ZEND_DEBUG
+/* use this to tell the stream that it is OK if we don't explicitly close it */
+# define php_stream_auto_cleanup(stream) { (stream)->__exposed++; }
+/* use this to assign the stream to a zval and tell the stream that is
+ * has been exported to the engine; it will expect to be closed automatically
+ * when the resources are auto-destructed */
+# define php_stream_to_zval(stream, zval) { ZVAL_RESOURCE(zval, (stream)->rsrc_id); (stream)->__exposed++; }
+#else
+# define php_stream_auto_cleanup(stream) /* nothing */
+# define php_stream_to_zval(stream, zval) { ZVAL_RESOURCE(zval, (stream)->rsrc_id); }
+#endif
+
+#define php_stream_from_zval(xstr, ppzval) ZEND_FETCH_RESOURCE2((xstr), php_stream *, (ppzval), -1, "stream", php_file_le_stream(), php_file_le_pstream())
+#define php_stream_from_zval_no_verify(xstr, ppzval) (xstr) = (php_stream*)zend_fetch_resource((ppzval) TSRMLS_CC, -1, "stream", NULL, 2, php_file_le_stream(), php_file_le_pstream())
+
+BEGIN_EXTERN_C()
+PHPAPI php_stream *php_stream_encloses(php_stream *enclosing, php_stream *enclosed);
+#define php_stream_free_enclosed(stream_enclosed, close_options) _php_stream_free_enclosed((stream_enclosed), (close_options) TSRMLS_CC)
+PHPAPI int _php_stream_free_enclosed(php_stream *stream_enclosed, int close_options TSRMLS_DC);
+
+PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream **stream TSRMLS_DC);
+#define PHP_STREAM_PERSISTENT_SUCCESS 0 /* id exists */
+#define PHP_STREAM_PERSISTENT_FAILURE 1 /* id exists but is not a stream! */
+#define PHP_STREAM_PERSISTENT_NOT_EXIST 2 /* id does not exist */
+
+#define PHP_STREAM_FREE_CALL_DTOR 1 /* call ops->close */
+#define PHP_STREAM_FREE_RELEASE_STREAM 2 /* pefree(stream) */
+#define PHP_STREAM_FREE_PRESERVE_HANDLE 4 /* tell ops->close to not close it's underlying handle */
+#define PHP_STREAM_FREE_RSRC_DTOR 8 /* called from the resource list dtor */
+#define PHP_STREAM_FREE_PERSISTENT 16 /* manually freeing a persistent connection */
+#define PHP_STREAM_FREE_IGNORE_ENCLOSING 32 /* don't close the enclosing stream instead */
+#define PHP_STREAM_FREE_CLOSE (PHP_STREAM_FREE_CALL_DTOR | PHP_STREAM_FREE_RELEASE_STREAM)
+#define PHP_STREAM_FREE_CLOSE_CASTED (PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_PRESERVE_HANDLE)
+#define PHP_STREAM_FREE_CLOSE_PERSISTENT (PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_PERSISTENT)
+
+PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC);
+#define php_stream_free(stream, close_options) _php_stream_free((stream), (close_options) TSRMLS_CC)
+#define php_stream_close(stream) _php_stream_free((stream), PHP_STREAM_FREE_CLOSE TSRMLS_CC)
+#define php_stream_pclose(stream) _php_stream_free((stream), PHP_STREAM_FREE_CLOSE_PERSISTENT TSRMLS_CC)
+
+PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_DC);
+#define php_stream_rewind(stream) _php_stream_seek((stream), 0L, SEEK_SET TSRMLS_CC)
+#define php_stream_seek(stream, offset, whence) _php_stream_seek((stream), (offset), (whence) TSRMLS_CC)
+
+PHPAPI off_t _php_stream_tell(php_stream *stream TSRMLS_DC);
+#define php_stream_tell(stream) _php_stream_tell((stream) TSRMLS_CC)
+
+PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC);
+#define php_stream_read(stream, buf, count) _php_stream_read((stream), (buf), (count) TSRMLS_CC)
+
+PHPAPI size_t _php_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC);
+#define php_stream_write_string(stream, str) _php_stream_write(stream, str, strlen(str) TSRMLS_CC)
+#define php_stream_write(stream, buf, count) _php_stream_write(stream, (buf), (count) TSRMLS_CC)
+
+#ifdef ZTS
+PHPAPI size_t _php_stream_printf(php_stream *stream TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
+#else
+PHPAPI size_t _php_stream_printf(php_stream *stream TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
+#endif
+
+/* php_stream_printf macro & function require TSRMLS_CC */
+#define php_stream_printf _php_stream_printf
+
+PHPAPI int _php_stream_eof(php_stream *stream TSRMLS_DC);
+#define php_stream_eof(stream) _php_stream_eof((stream) TSRMLS_CC)
+
+PHPAPI int _php_stream_getc(php_stream *stream TSRMLS_DC);
+#define php_stream_getc(stream) _php_stream_getc((stream) TSRMLS_CC)
+
+PHPAPI int _php_stream_putc(php_stream *stream, int c TSRMLS_DC);
+#define php_stream_putc(stream, c) _php_stream_putc((stream), (c) TSRMLS_CC)
+
+PHPAPI int _php_stream_flush(php_stream *stream, int closing TSRMLS_DC);
+#define php_stream_flush(stream) _php_stream_flush((stream), 0 TSRMLS_CC)
+
+PHPAPI char *_php_stream_get_line(php_stream *stream, char *buf, size_t maxlen, size_t *returned_len TSRMLS_DC);
+#define php_stream_gets(stream, buf, maxlen) _php_stream_get_line((stream), (buf), (maxlen), NULL TSRMLS_CC)
+
+#define php_stream_get_line(stream, buf, maxlen, retlen) _php_stream_get_line((stream), (buf), (maxlen), (retlen) TSRMLS_CC)
+PHPAPI char *php_stream_get_record(php_stream *stream, size_t maxlen, size_t *returned_len, char *delim, size_t delim_len TSRMLS_DC);
+
+/* CAREFUL! this is equivalent to puts NOT fputs! */
+PHPAPI int _php_stream_puts(php_stream *stream, char *buf TSRMLS_DC);
+#define php_stream_puts(stream, buf) _php_stream_puts((stream), (buf) TSRMLS_CC)
+
+PHPAPI int _php_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC);
+#define php_stream_stat(stream, ssb) _php_stream_stat((stream), (ssb) TSRMLS_CC)
+
+PHPAPI int _php_stream_stat_path(char *path, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC);
+#define php_stream_stat_path(path, ssb) _php_stream_stat_path((path), 0, (ssb), NULL TSRMLS_CC)
+#define php_stream_stat_path_ex(path, flags, ssb, context) _php_stream_stat_path((path), (flags), (ssb), (context) TSRMLS_CC)
+
+PHPAPI int _php_stream_mkdir(char *path, int mode, int options, php_stream_context *context TSRMLS_DC);
+#define php_stream_mkdir(path, mode, options, context) _php_stream_mkdir(path, mode, options, context TSRMLS_CC)
+
+PHPAPI int _php_stream_rmdir(char *path, int options, php_stream_context *context TSRMLS_DC);
+#define php_stream_rmdir(path, options, context) _php_stream_rmdir(path, options, context TSRMLS_CC)
+
+PHPAPI php_stream *_php_stream_opendir(char *path, int options, php_stream_context *context STREAMS_DC TSRMLS_DC);
+#define php_stream_opendir(path, options, context) _php_stream_opendir((path), (options), (context) STREAMS_CC TSRMLS_CC)
+PHPAPI php_stream_dirent *_php_stream_readdir(php_stream *dirstream, php_stream_dirent *ent TSRMLS_DC);
+#define php_stream_readdir(dirstream, dirent) _php_stream_readdir((dirstream), (dirent) TSRMLS_CC)
+#define php_stream_closedir(dirstream) php_stream_close((dirstream))
+#define php_stream_rewinddir(dirstream) php_stream_rewind((dirstream))
+
+PHPAPI int php_stream_dirent_alphasort(const char **a, const char **b);
+PHPAPI int php_stream_dirent_alphasortr(const char **a, const char **b);
+
+PHPAPI int _php_stream_scandir(char *dirname, char **namelist[], int flags, php_stream_context *context,
+ int (*compare) (const char **a, const char **b) TSRMLS_DC);
+#define php_stream_scandir(dirname, namelist, context, compare) _php_stream_scandir((dirname), (namelist), 0, (context), (compare) TSRMLS_CC)
+
+PHPAPI int _php_stream_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC);
+#define php_stream_set_option(stream, option, value, ptrvalue) _php_stream_set_option((stream), (option), (value), (ptrvalue) TSRMLS_CC)
+
+#define php_stream_set_chunk_size(stream, size) _php_stream_set_option((stream), PHP_STREAM_OPTION_SET_CHUNK_SIZE, (size), NULL TSRMLS_CC)
+
+END_EXTERN_C()
+
+
+/* Flags for mkdir method in wrapper ops */
+#define PHP_STREAM_MKDIR_RECURSIVE 1
+/* define REPORT ERRORS 8 (below) */
+
+/* Flags for rmdir method in wrapper ops */
+/* define REPORT_ERRORS 8 (below) */
+
+/* Flags for url_stat method in wrapper ops */
+#define PHP_STREAM_URL_STAT_LINK 1
+#define PHP_STREAM_URL_STAT_QUIET 2
+
+/* change the blocking mode of stream: value == 1 => blocking, value == 0 => non-blocking. */
+#define PHP_STREAM_OPTION_BLOCKING 1
+
+/* change the buffering mode of stream. value is a PHP_STREAM_BUFFER_XXXX value, ptrparam is a ptr to a size_t holding
+ * the required buffer size */
+#define PHP_STREAM_OPTION_READ_BUFFER 2
+#define PHP_STREAM_OPTION_WRITE_BUFFER 3
+
+#define PHP_STREAM_BUFFER_NONE 0 /* unbuffered */
+#define PHP_STREAM_BUFFER_LINE 1 /* line buffered */
+#define PHP_STREAM_BUFFER_FULL 2 /* fully buffered */
+
+/* set the timeout duration for reads on the stream. ptrparam is a pointer to a struct timeval * */
+#define PHP_STREAM_OPTION_READ_TIMEOUT 4
+#define PHP_STREAM_OPTION_SET_CHUNK_SIZE 5
+
+/* set or release lock on a stream */
+#define PHP_STREAM_OPTION_LOCKING 6
+
+/* whether or not locking is supported */
+#define PHP_STREAM_LOCK_SUPPORTED 1
+
+#define php_stream_supports_lock(stream) _php_stream_set_option((stream), PHP_STREAM_OPTION_LOCKING, 0, (void *) PHP_STREAM_LOCK_SUPPORTED TSRMLS_CC) == 0 ? 1 : 0
+#define php_stream_lock(stream, mode) _php_stream_set_option((stream), PHP_STREAM_OPTION_LOCKING, (mode), (void *) NULL TSRMLS_CC)
+
+/* option code used by the php_stream_xport_XXX api */
+#define PHP_STREAM_OPTION_XPORT_API 7 /* see php_stream_transport.h */
+#define PHP_STREAM_OPTION_CRYPTO_API 8 /* see php_stream_transport.h */
+#define PHP_STREAM_OPTION_MMAP_API 9 /* see php_stream_mmap.h */
+#define PHP_STREAM_OPTION_TRUNCATE_API 10
+
+#define PHP_STREAM_TRUNCATE_SUPPORTED 0
+#define PHP_STREAM_TRUNCATE_SET_SIZE 1 /* ptrparam is a pointer to a size_t */
+
+#define php_stream_truncate_supported(stream) (_php_stream_set_option((stream), PHP_STREAM_OPTION_TRUNCATE_API, PHP_STREAM_TRUNCATE_SUPPORTED, NULL TSRMLS_CC) == PHP_STREAM_OPTION_RETURN_OK ? 1 : 0)
+
+BEGIN_EXTERN_C()
+PHPAPI int _php_stream_truncate_set_size(php_stream *stream, size_t newsize TSRMLS_DC);
+#define php_stream_truncate_set_size(stream, size) _php_stream_truncate_set_size((stream), (size) TSRMLS_CC)
+END_EXTERN_C()
+
+#define PHP_STREAM_OPTION_META_DATA_API 11 /* ptrparam is a zval* to which to add meta data information */
+#define php_stream_populate_meta_data(stream, zv) (_php_stream_set_option((stream), PHP_STREAM_OPTION_META_DATA_API, 0, zv TSRMLS_CC) == PHP_STREAM_OPTION_RETURN_OK ? 1 : 0)
+
+/* Check if the stream is still "live"; for sockets/pipes this means the socket
+ * is still connected; for files, this does not really have meaning */
+#define PHP_STREAM_OPTION_CHECK_LIVENESS 12 /* no parameters */
+
+#define PHP_STREAM_OPTION_RETURN_OK 0 /* option set OK */
+#define PHP_STREAM_OPTION_RETURN_ERR -1 /* problem setting option */
+#define PHP_STREAM_OPTION_RETURN_NOTIMPL -2 /* underlying stream does not implement; streams can handle it instead */
+
+/* copy up to maxlen bytes from src to dest. If maxlen is PHP_STREAM_COPY_ALL,
+ * copy until eof(src). */
+#define PHP_STREAM_COPY_ALL ((size_t)-1)
+
+BEGIN_EXTERN_C()
+ZEND_ATTRIBUTE_DEPRECATED
+PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, size_t maxlen STREAMS_DC TSRMLS_DC);
+#define php_stream_copy_to_stream(src, dest, maxlen) _php_stream_copy_to_stream((src), (dest), (maxlen) STREAMS_CC TSRMLS_CC)
+PHPAPI int _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC);
+#define php_stream_copy_to_stream_ex(src, dest, maxlen, len) _php_stream_copy_to_stream_ex((src), (dest), (maxlen), (len) STREAMS_CC TSRMLS_CC)
+
+
+/* read all data from stream and put into a buffer. Caller must free buffer
+ * when done. */
+PHPAPI size_t _php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen,
+ int persistent STREAMS_DC TSRMLS_DC);
+#define php_stream_copy_to_mem(src, buf, maxlen, persistent) _php_stream_copy_to_mem((src), (buf), (maxlen), (persistent) STREAMS_CC TSRMLS_CC)
+
+/* output all data from a stream */
+PHPAPI size_t _php_stream_passthru(php_stream * src STREAMS_DC TSRMLS_DC);
+#define php_stream_passthru(stream) _php_stream_passthru((stream) STREAMS_CC TSRMLS_CC)
+END_EXTERN_C()
+
+#include "streams/php_stream_transport.h"
+#include "streams/php_stream_plain_wrapper.h"
+#include "streams/php_stream_glob_wrapper.h"
+#include "streams/php_stream_userspace.h"
+#include "streams/php_stream_mmap.h"
+
+/* coerce the stream into some other form */
+/* cast as a stdio FILE * */
+#define PHP_STREAM_AS_STDIO 0
+/* cast as a POSIX fd or socketd */
+#define PHP_STREAM_AS_FD 1
+/* cast as a socketd */
+#define PHP_STREAM_AS_SOCKETD 2
+/* cast as fd/socket for select purposes */
+#define PHP_STREAM_AS_FD_FOR_SELECT 3
+
+/* try really, really hard to make sure the cast happens (avoid using this flag if possible) */
+#define PHP_STREAM_CAST_TRY_HARD 0x80000000
+#define PHP_STREAM_CAST_RELEASE 0x40000000 /* stream becomes invalid on success */
+#define PHP_STREAM_CAST_INTERNAL 0x20000000 /* stream cast for internal use */
+#define PHP_STREAM_CAST_MASK (PHP_STREAM_CAST_TRY_HARD | PHP_STREAM_CAST_RELEASE | PHP_STREAM_CAST_INTERNAL)
+BEGIN_EXTERN_C()
+PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC);
+END_EXTERN_C()
+/* use this to check if a stream can be cast into another form */
+#define php_stream_can_cast(stream, as) _php_stream_cast((stream), (as), NULL, 0 TSRMLS_CC)
+#define php_stream_cast(stream, as, ret, show_err) _php_stream_cast((stream), (as), (ret), (show_err) TSRMLS_CC)
+
+/* use this to check if a stream is of a particular type:
+ * PHPAPI int php_stream_is(php_stream *stream, php_stream_ops *ops); */
+#define php_stream_is(stream, anops) ((stream)->ops == anops)
+#define PHP_STREAM_IS_STDIO &php_stream_stdio_ops
+
+#define php_stream_is_persistent(stream) (stream)->is_persistent
+
+/* Wrappers support */
+
+#define IGNORE_PATH 0x00000000
+#define USE_PATH 0x00000001
+#define IGNORE_URL 0x00000002
+#define REPORT_ERRORS 0x00000008
+#define ENFORCE_SAFE_MODE 0 /* for BC only */
+
+/* If you don't need to write to the stream, but really need to
+ * be able to seek, use this flag in your options. */
+#define STREAM_MUST_SEEK 0x00000010
+/* If you are going to end up casting the stream into a FILE* or
+ * a socket, pass this flag and the streams/wrappers will not use
+ * buffering mechanisms while reading the headers, so that HTTP
+ * wrapped streams will work consistently.
+ * If you omit this flag, streams will use buffering and should end
+ * up working more optimally.
+ * */
+#define STREAM_WILL_CAST 0x00000020
+
+/* this flag applies to php_stream_locate_url_wrapper */
+#define STREAM_LOCATE_WRAPPERS_ONLY 0x00000040
+
+/* this flag is only used by include/require functions */
+#define STREAM_OPEN_FOR_INCLUDE 0x00000080
+
+/* this flag tells streams to ONLY open urls */
+#define STREAM_USE_URL 0x00000100
+
+/* this flag is used when only the headers from HTTP request are to be fetched */
+#define STREAM_ONLY_GET_HEADERS 0x00000200
+
+/* don't apply open_basedir checks */
+#define STREAM_DISABLE_OPEN_BASEDIR 0x00000400
+
+/* get (or create) a persistent version of the stream */
+#define STREAM_OPEN_PERSISTENT 0x00000800
+
+/* use glob stream for directory open in plain files stream */
+#define STREAM_USE_GLOB_DIR_OPEN 0x00001000
+
+/* don't check allow_url_fopen and allow_url_include */
+#define STREAM_DISABLE_URL_PROTECTION 0x00002000
+
+/* assume the path passed in exists and is fully expanded, avoiding syscalls */
+#define STREAM_ASSUME_REALPATH 0x00004000
+
+/* Antique - no longer has meaning */
+#define IGNORE_URL_WIN 0
+
+int php_init_stream_wrappers(int module_number TSRMLS_DC);
+int php_shutdown_stream_wrappers(int module_number TSRMLS_DC);
+void php_shutdown_stream_hashes(TSRMLS_D);
+PHP_RSHUTDOWN_FUNCTION(streams);
+
+BEGIN_EXTERN_C()
+PHPAPI int php_register_url_stream_wrapper(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC);
+PHPAPI int php_unregister_url_stream_wrapper(char *protocol TSRMLS_DC);
+PHPAPI int php_register_url_stream_wrapper_volatile(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC);
+PHPAPI int php_unregister_url_stream_wrapper_volatile(char *protocol TSRMLS_DC);
+PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
+PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, char **path_for_open, int options TSRMLS_DC);
+PHPAPI char *php_stream_locate_eol(php_stream *stream, char *buf, size_t buf_len TSRMLS_DC);
+
+#define php_stream_open_wrapper(path, mode, options, opened) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), NULL STREAMS_CC TSRMLS_CC)
+#define php_stream_open_wrapper_ex(path, mode, options, opened, context) _php_stream_open_wrapper_ex((path), (mode), (options), (opened), (context) STREAMS_CC TSRMLS_CC)
+
+#define php_stream_get_from_zval(stream, zstream, mode, options, opened, context) \
+ if (Z_TYPE_PP((zstream)) == IS_RESOURCE) { \
+ php_stream_from_zval((stream), (zstream)); \
+ } else (stream) = Z_TYPE_PP((zstream)) == IS_STRING ? \
+ php_stream_open_wrapper_ex(Z_STRVAL_PP((zstream)), (mode), (options), (opened), (context)) : NULL
+
+/* pushes an error message onto the stack for a wrapper instance */
+#ifdef ZTS
+PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 4, 5);
+#else
+PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options TSRMLS_DC, const char *fmt, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
+#endif
+
+#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 */
+#define PHP_STREAM_NO_PREFERENCE 0
+#define PHP_STREAM_PREFER_STDIO 1
+#define PHP_STREAM_FORCE_CONVERSION 2
+/* DO NOT call this on streams that are referenced by resources! */
+PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstream, int flags STREAMS_DC TSRMLS_DC);
+#define php_stream_make_seekable(origstream, newstream, flags) _php_stream_make_seekable((origstream), (newstream), (flags) STREAMS_CC TSRMLS_CC)
+
+/* Give other modules access to the url_stream_wrappers_hash and stream_filters_hash */
+PHPAPI HashTable *_php_stream_get_url_stream_wrappers_hash(TSRMLS_D);
+#define php_stream_get_url_stream_wrappers_hash() _php_stream_get_url_stream_wrappers_hash(TSRMLS_C)
+PHPAPI HashTable *php_stream_get_url_stream_wrappers_hash_global(void);
+PHPAPI HashTable *_php_get_stream_filters_hash(TSRMLS_D);
+#define php_get_stream_filters_hash() _php_get_stream_filters_hash(TSRMLS_C)
+PHPAPI HashTable *php_get_stream_filters_hash_global(void);
+extern php_stream_wrapper_ops *php_stream_user_wrapper_ops;
+END_EXTERN_C()
+#endif
+
+/* Definitions for user streams */
+#define PHP_STREAM_IS_URL 1
+
+/* Stream metadata definitions */
+/* Create if referred resource does not exist */
+#define PHP_STREAM_META_TOUCH 1
+#define PHP_STREAM_META_OWNER_NAME 2
+#define PHP_STREAM_META_OWNER 3
+#define PHP_STREAM_META_GROUP_NAME 4
+#define PHP_STREAM_META_GROUP 5
+#define PHP_STREAM_META_ACCESS 6
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_syslog.h b/main/php_syslog.h
new file mode 100644
index 0000000..e070487
--- /dev/null
+++ b/main/php_syslog.h
@@ -0,0 +1,52 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_SYSLOG_H
+#define PHP_SYSLOG_H
+
+#ifdef PHP_WIN32
+#include "win32/syslog.h"
+#else
+#include <php_config.h>
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+#endif
+
+/*
+ * The SCO OpenServer 5 Development System (not the UDK)
+ * defines syslog to std_syslog.
+ */
+
+#ifdef syslog
+
+#ifdef HAVE_STD_SYSLOG
+#define php_syslog std_syslog
+#endif
+
+#undef syslog
+
+#endif
+
+#ifndef php_syslog
+#define php_syslog syslog
+#endif
+
+#endif
diff --git a/main/php_ticks.c b/main/php_ticks.c
new file mode 100644
index 0000000..17ffb9c
--- /dev/null
+++ b/main/php_ticks.c
@@ -0,0 +1,86 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Stig Bakken <ssb@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+#include "php_ticks.h"
+
+int php_startup_ticks(TSRMLS_D)
+{
+ zend_llist_init(&PG(tick_functions), sizeof(void(*)(int)), NULL, 1);
+ return SUCCESS;
+}
+
+void php_deactivate_ticks(TSRMLS_D)
+{
+ zend_llist_clean(&PG(tick_functions));
+}
+
+void php_shutdown_ticks(TSRMLS_D)
+{
+ zend_llist_destroy(&PG(tick_functions));
+}
+
+static int php_compare_tick_functions(void *elem1, void *elem2)
+{
+ void(*func1)(int);
+ void(*func2)(int);
+ memcpy(&func1, elem1, sizeof(void(*)(int)));
+ memcpy(&func2, elem2, sizeof(void(*)(int)));
+ return (func1 == func2);
+}
+
+PHPAPI void php_add_tick_function(void (*func)(int))
+{
+ TSRMLS_FETCH();
+
+ zend_llist_add_element(&PG(tick_functions), (void *)&func);
+}
+
+PHPAPI void php_remove_tick_function(void (*func)(int))
+{
+ TSRMLS_FETCH();
+
+ zend_llist_del_element(&PG(tick_functions), (void *)func,
+ (int(*)(void*, void*))php_compare_tick_functions);
+}
+
+static void php_tick_iterator(void *data, void *arg TSRMLS_DC)
+{
+ void (*func)(int);
+
+ memcpy(&func, data, sizeof(void(*)(int)));
+ func(*((int *)arg));
+}
+
+void php_run_ticks(int count)
+{
+ TSRMLS_FETCH();
+
+ zend_llist_apply_with_argument(&PG(tick_functions), (llist_apply_with_arg_func_t) php_tick_iterator, &count TSRMLS_CC);
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_ticks.h b/main/php_ticks.h
new file mode 100644
index 0000000..cc966fa
--- /dev/null
+++ b/main/php_ticks.h
@@ -0,0 +1,41 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Stig Bakken <ssb@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_TICKS_H
+#define PHP_TICKS_H
+
+int php_startup_ticks(TSRMLS_D);
+void php_deactivate_ticks(TSRMLS_D);
+void php_shutdown_ticks(TSRMLS_D);
+void php_run_ticks(int count);
+
+BEGIN_EXTERN_C()
+PHPAPI void php_add_tick_function(void (*func)(int));
+PHPAPI void php_remove_tick_function(void (*func)(int));
+END_EXTERN_C()
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/main/php_variables.c b/main/php_variables.c
new file mode 100644
index 0000000..cf2b623
--- /dev/null
+++ b/main/php_variables.c
@@ -0,0 +1,865 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include <stdio.h>
+#include "php.h"
+#include "ext/standard/php_standard.h"
+#include "ext/standard/credits.h"
+#include "php_variables.h"
+#include "php_globals.h"
+#include "php_content_types.h"
+#include "SAPI.h"
+#include "php_logos.h"
+#include "zend_globals.h"
+
+/* for systems that need to override reading of environment variables */
+void _php_import_environment_variables(zval *array_ptr TSRMLS_DC);
+PHPAPI void (*php_import_environment_variables)(zval *array_ptr TSRMLS_DC) = _php_import_environment_variables;
+
+PHPAPI void php_register_variable(char *var, char *strval, zval *track_vars_array TSRMLS_DC)
+{
+ php_register_variable_safe(var, strval, strlen(strval), track_vars_array TSRMLS_CC);
+}
+
+/* binary-safe version */
+PHPAPI void php_register_variable_safe(char *var, char *strval, int str_len, zval *track_vars_array TSRMLS_DC)
+{
+ zval new_entry;
+ assert(strval != NULL);
+
+ /* Prepare value */
+ Z_STRLEN(new_entry) = str_len;
+ Z_STRVAL(new_entry) = estrndup(strval, Z_STRLEN(new_entry));
+ Z_TYPE(new_entry) = IS_STRING;
+
+ php_register_variable_ex(var, &new_entry, track_vars_array TSRMLS_CC);
+}
+
+PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars_array TSRMLS_DC)
+{
+ char *p = NULL;
+ char *ip; /* index pointer */
+ char *index;
+ char *var, *var_orig;
+ int var_len, index_len;
+ zval *gpc_element, **gpc_element_p;
+ zend_bool is_array = 0;
+ HashTable *symtable1 = NULL;
+ ALLOCA_FLAG(use_heap)
+
+ assert(var_name != NULL);
+
+ if (track_vars_array) {
+ symtable1 = Z_ARRVAL_P(track_vars_array);
+ }
+
+ if (!symtable1) {
+ /* Nothing to do */
+ zval_dtor(val);
+ return;
+ }
+
+
+ /* ignore leading spaces in the variable name */
+ while (*var_name && *var_name==' ') {
+ var_name++;
+ }
+
+ /*
+ * Prepare variable name
+ */
+ var_len = strlen(var_name);
+ var = var_orig = do_alloca(var_len + 1, use_heap);
+ memcpy(var_orig, var_name, var_len + 1);
+
+ /* ensure that we don't have spaces or dots in the variable name (not binary safe) */
+ for (p = var; *p; p++) {
+ if (*p == ' ' || *p == '.') {
+ *p='_';
+ } else if (*p == '[') {
+ is_array = 1;
+ ip = p;
+ *p = 0;
+ break;
+ }
+ }
+ var_len = p - var;
+
+ if (var_len==0) { /* empty variable name, or variable name with a space in it */
+ zval_dtor(val);
+ free_alloca(var_orig, use_heap);
+ return;
+ }
+
+ /* GLOBALS hijack attempt, reject parameter */
+ if (symtable1 == EG(active_symbol_table) &&
+ var_len == sizeof("GLOBALS")-1 &&
+ !memcmp(var, "GLOBALS", sizeof("GLOBALS")-1)) {
+ zval_dtor(val);
+ free_alloca(var_orig, use_heap);
+ return;
+ }
+
+ index = var;
+ index_len = var_len;
+
+ if (is_array) {
+ int nest_level = 0;
+ while (1) {
+ char *index_s;
+ int new_idx_len = 0;
+
+ if(++nest_level > PG(max_input_nesting_level)) {
+ HashTable *ht;
+ /* too many levels of nesting */
+
+ if (track_vars_array) {
+ ht = Z_ARRVAL_P(track_vars_array);
+ zend_symtable_del(ht, var, var_len + 1);
+ }
+
+ zval_dtor(val);
+
+ /* do not output the error message to the screen,
+ this helps us to to avoid "information disclosure" */
+ if (!PG(display_errors)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variable nesting level exceeded %ld. To increase the limit change max_input_nesting_level in php.ini.", PG(max_input_nesting_level));
+ }
+ free_alloca(var_orig, use_heap);
+ return;
+ }
+
+ ip++;
+ index_s = ip;
+ if (isspace(*ip)) {
+ ip++;
+ }
+ if (*ip==']') {
+ index_s = NULL;
+ } else {
+ ip = strchr(ip, ']');
+ if (!ip) {
+ /* PHP variables cannot contain '[' in their names, so we replace the character with a '_' */
+ *(index_s - 1) = '_';
+
+ index_len = 0;
+ if (index) {
+ index_len = strlen(index);
+ }
+ goto plain_var;
+ return;
+ }
+ *ip = 0;
+ new_idx_len = strlen(index_s);
+ }
+
+ if (!index) {
+ MAKE_STD_ZVAL(gpc_element);
+ array_init(gpc_element);
+ if (zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p) == FAILURE) {
+ zval_ptr_dtor(&gpc_element);
+ zval_dtor(val);
+ free_alloca(var_orig, use_heap);
+ return;
+ }
+ } else {
+ if (zend_symtable_find(symtable1, index, index_len + 1, (void **) &gpc_element_p) == FAILURE
+ || Z_TYPE_PP(gpc_element_p) != IS_ARRAY) {
+ MAKE_STD_ZVAL(gpc_element);
+ array_init(gpc_element);
+ zend_symtable_update(symtable1, index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
+ }
+ }
+ symtable1 = Z_ARRVAL_PP(gpc_element_p);
+ /* ip pointed to the '[' character, now obtain the key */
+ index = index_s;
+ index_len = new_idx_len;
+
+ ip++;
+ if (*ip == '[') {
+ is_array = 1;
+ *ip = 0;
+ } else {
+ goto plain_var;
+ }
+ }
+ } else {
+plain_var:
+ MAKE_STD_ZVAL(gpc_element);
+ gpc_element->value = val->value;
+ Z_TYPE_P(gpc_element) = Z_TYPE_P(val);
+ if (!index) {
+ if (zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p) == FAILURE) {
+ zval_ptr_dtor(&gpc_element);
+ }
+ } else {
+ /*
+ * According to rfc2965, more specific paths are listed above the less specific ones.
+ * If we encounter a duplicate cookie name, we should skip it, since it is not possible
+ * to have the same (plain text) cookie name for the same path and we should not overwrite
+ * more specific cookies with the less specific ones.
+ */
+ if (PG(http_globals)[TRACK_VARS_COOKIE] &&
+ symtable1 == Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) &&
+ zend_symtable_exists(symtable1, index, index_len + 1)) {
+ zval_ptr_dtor(&gpc_element);
+ } else {
+ zend_symtable_update(symtable1, index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
+ }
+ }
+ }
+ free_alloca(var_orig, use_heap);
+}
+
+SAPI_API SAPI_POST_HANDLER_FUNC(php_std_post_handler)
+{
+ char *var, *val, *e, *s, *p;
+ zval *array_ptr = (zval *) arg;
+ long count = 0;
+
+ if (SG(request_info).post_data == NULL) {
+ return;
+ }
+
+ s = SG(request_info).post_data;
+ e = s + SG(request_info).post_data_length;
+
+ while (s < e && (p = memchr(s, '&', (e - s)))) {
+last_value:
+ if ((val = memchr(s, '=', (p - s)))) { /* have a value */
+ unsigned int val_len, new_val_len;
+
+ if (++count > PG(max_input_vars)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
+ return;
+ }
+ var = s;
+
+ php_url_decode(var, (val - s));
+ val++;
+ val_len = php_url_decode(val, (p - val));
+ val = estrndup(val, val_len);
+ if (sapi_module.input_filter(PARSE_POST, var, &val, val_len, &new_val_len TSRMLS_CC)) {
+ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC);
+ }
+ efree(val);
+ }
+ s = p + 1;
+ }
+ if (s < e) {
+ p = e;
+ goto last_value;
+ }
+}
+
+SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter)
+{
+ /* TODO: check .ini setting here and apply user-defined input filter */
+ if(new_val_len) *new_val_len = val_len;
+ return 1;
+}
+
+SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data)
+{
+ char *res = NULL, *var, *val, *separator = NULL;
+ const char *c_var;
+ zval *array_ptr;
+ int free_buffer = 0;
+ char *strtok_buf = NULL;
+ long count = 0;
+
+ switch (arg) {
+ case PARSE_POST:
+ case PARSE_GET:
+ case PARSE_COOKIE:
+ ALLOC_ZVAL(array_ptr);
+ array_init(array_ptr);
+ INIT_PZVAL(array_ptr);
+ switch (arg) {
+ case PARSE_POST:
+ if (PG(http_globals)[TRACK_VARS_POST]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_POST]);
+ }
+ PG(http_globals)[TRACK_VARS_POST] = array_ptr;
+ break;
+ case PARSE_GET:
+ if (PG(http_globals)[TRACK_VARS_GET]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_GET]);
+ }
+ PG(http_globals)[TRACK_VARS_GET] = array_ptr;
+ break;
+ case PARSE_COOKIE:
+ if (PG(http_globals)[TRACK_VARS_COOKIE]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_COOKIE]);
+ }
+ PG(http_globals)[TRACK_VARS_COOKIE] = array_ptr;
+ break;
+ }
+ break;
+ default:
+ array_ptr = destArray;
+ break;
+ }
+
+ if (arg == PARSE_POST) {
+ sapi_handle_post(array_ptr TSRMLS_CC);
+ return;
+ }
+
+ if (arg == PARSE_GET) { /* GET data */
+ c_var = SG(request_info).query_string;
+ if (c_var && *c_var) {
+ res = (char *) estrdup(c_var);
+ free_buffer = 1;
+ } else {
+ free_buffer = 0;
+ }
+ } else if (arg == PARSE_COOKIE) { /* Cookie data */
+ c_var = SG(request_info).cookie_data;
+ if (c_var && *c_var) {
+ res = (char *) estrdup(c_var);
+ free_buffer = 1;
+ } else {
+ free_buffer = 0;
+ }
+ } else if (arg == PARSE_STRING) { /* String data */
+ res = str;
+ free_buffer = 1;
+ }
+
+ if (!res) {
+ return;
+ }
+
+ switch (arg) {
+ case PARSE_GET:
+ case PARSE_STRING:
+ separator = (char *) estrdup(PG(arg_separator).input);
+ break;
+ case PARSE_COOKIE:
+ separator = ";\0";
+ break;
+ }
+
+ var = php_strtok_r(res, separator, &strtok_buf);
+
+ while (var) {
+ val = strchr(var, '=');
+
+ if (arg == PARSE_COOKIE) {
+ /* Remove leading spaces from cookie names, needed for multi-cookie header where ; can be followed by a space */
+ while (isspace(*var)) {
+ var++;
+ }
+ if (var == val || *var == '\0') {
+ goto next_cookie;
+ }
+ }
+
+ if (++count > PG(max_input_vars)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
+ break;
+ }
+
+ if (val) { /* have a value */
+ int val_len;
+ unsigned int new_val_len;
+
+ *val++ = '\0';
+ php_url_decode(var, strlen(var));
+ val_len = php_url_decode(val, strlen(val));
+ val = estrndup(val, val_len);
+ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) {
+ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC);
+ }
+ efree(val);
+ } else {
+ int val_len;
+ unsigned int new_val_len;
+
+ php_url_decode(var, strlen(var));
+ val_len = 0;
+ val = estrndup("", val_len);
+ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) {
+ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC);
+ }
+ efree(val);
+ }
+next_cookie:
+ var = php_strtok_r(NULL, separator, &strtok_buf);
+ }
+
+ if (arg != PARSE_COOKIE) {
+ efree(separator);
+ }
+
+ if (free_buffer) {
+ efree(res);
+ }
+}
+
+void _php_import_environment_variables(zval *array_ptr TSRMLS_DC)
+{
+ char buf[128];
+ char **env, *p, *t = buf;
+ size_t alloc_size = sizeof(buf);
+ unsigned long nlen; /* ptrdiff_t is not portable */
+
+ for (env = environ; env != NULL && *env != NULL; env++) {
+ p = strchr(*env, '=');
+ if (!p) { /* malformed entry? */
+ continue;
+ }
+ nlen = p - *env;
+ if (nlen >= alloc_size) {
+ alloc_size = nlen + 64;
+ t = (t == buf ? emalloc(alloc_size): erealloc(t, alloc_size));
+ }
+ memcpy(t, *env, nlen);
+ t[nlen] = '\0';
+ php_register_variable(t, p + 1, array_ptr TSRMLS_CC);
+ }
+ if (t != buf && t != NULL) {
+ efree(t);
+ }
+}
+
+zend_bool php_std_auto_global_callback(char *name, uint name_len TSRMLS_DC)
+{
+ zend_printf("%s\n", name);
+ return 0; /* don't rearm */
+}
+
+/* {{{ php_build_argv
+ */
+static void php_build_argv(char *s, zval *track_vars_array TSRMLS_DC)
+{
+ zval *arr, *argc, *tmp;
+ int count = 0;
+ char *ss, *space;
+
+ if (!(SG(request_info).argc || track_vars_array)) {
+ return;
+ }
+
+ ALLOC_INIT_ZVAL(arr);
+ array_init(arr);
+
+ /* Prepare argv */
+ if (SG(request_info).argc) { /* are we in cli sapi? */
+ int i;
+ for (i = 0; i < SG(request_info).argc; i++) {
+ ALLOC_ZVAL(tmp);
+ Z_TYPE_P(tmp) = IS_STRING;
+ Z_STRLEN_P(tmp) = strlen(SG(request_info).argv[i]);
+ Z_STRVAL_P(tmp) = estrndup(SG(request_info).argv[i], Z_STRLEN_P(tmp));
+ INIT_PZVAL(tmp);
+ if (zend_hash_next_index_insert(Z_ARRVAL_P(arr), &tmp, sizeof(zval *), NULL) == FAILURE) {
+ if (Z_TYPE_P(tmp) == IS_STRING) {
+ efree(Z_STRVAL_P(tmp));
+ }
+ }
+ }
+ } else if (s && *s) {
+ ss = s;
+ while (ss) {
+ space = strchr(ss, '+');
+ if (space) {
+ *space = '\0';
+ }
+ /* auto-type */
+ ALLOC_ZVAL(tmp);
+ Z_TYPE_P(tmp) = IS_STRING;
+ Z_STRLEN_P(tmp) = strlen(ss);
+ Z_STRVAL_P(tmp) = estrndup(ss, Z_STRLEN_P(tmp));
+ INIT_PZVAL(tmp);
+ count++;
+ if (zend_hash_next_index_insert(Z_ARRVAL_P(arr), &tmp, sizeof(zval *), NULL) == FAILURE) {
+ if (Z_TYPE_P(tmp) == IS_STRING) {
+ efree(Z_STRVAL_P(tmp));
+ }
+ }
+ if (space) {
+ *space = '+';
+ ss = space + 1;
+ } else {
+ ss = space;
+ }
+ }
+ }
+
+ /* prepare argc */
+ ALLOC_INIT_ZVAL(argc);
+ if (SG(request_info).argc) {
+ Z_LVAL_P(argc) = SG(request_info).argc;
+ } else {
+ Z_LVAL_P(argc) = count;
+ }
+ Z_TYPE_P(argc) = IS_LONG;
+
+ if (SG(request_info).argc) {
+ Z_ADDREF_P(arr);
+ Z_ADDREF_P(argc);
+ zend_hash_update(&EG(symbol_table), "argv", sizeof("argv"), &arr, sizeof(zval *), NULL);
+ zend_hash_add(&EG(symbol_table), "argc", sizeof("argc"), &argc, sizeof(zval *), NULL);
+ }
+ if (track_vars_array) {
+ Z_ADDREF_P(arr);
+ Z_ADDREF_P(argc);
+ zend_hash_update(Z_ARRVAL_P(track_vars_array), "argv", sizeof("argv"), &arr, sizeof(zval *), NULL);
+ zend_hash_update(Z_ARRVAL_P(track_vars_array), "argc", sizeof("argc"), &argc, sizeof(zval *), NULL);
+ }
+ zval_ptr_dtor(&arr);
+ zval_ptr_dtor(&argc);
+}
+/* }}} */
+
+/* {{{ php_handle_special_queries
+ */
+PHPAPI int php_handle_special_queries(TSRMLS_D)
+{
+ if (PG(expose_php) && SG(request_info).query_string && SG(request_info).query_string[0] == '=') {
+ if (php_info_logos(SG(request_info).query_string + 1 TSRMLS_CC)) {
+ return 1;
+ } else if (!strcmp(SG(request_info).query_string + 1, PHP_CREDITS_GUID)) {
+ php_print_credits(PHP_CREDITS_ALL TSRMLS_CC);
+ return 1;
+ }
+ }
+ return 0;
+}
+/* }}} */
+
+/* {{{ php_register_server_variables
+ */
+static inline void php_register_server_variables(TSRMLS_D)
+{
+ zval *array_ptr = NULL;
+
+ ALLOC_ZVAL(array_ptr);
+ array_init(array_ptr);
+ INIT_PZVAL(array_ptr);
+ if (PG(http_globals)[TRACK_VARS_SERVER]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_SERVER]);
+ }
+ PG(http_globals)[TRACK_VARS_SERVER] = array_ptr;
+
+ /* Server variables */
+ if (sapi_module.register_server_variables) {
+ sapi_module.register_server_variables(array_ptr TSRMLS_CC);
+ }
+
+ /* PHP Authentication support */
+ if (SG(request_info).auth_user) {
+ php_register_variable("PHP_AUTH_USER", SG(request_info).auth_user, array_ptr TSRMLS_CC);
+ }
+ if (SG(request_info).auth_password) {
+ php_register_variable("PHP_AUTH_PW", SG(request_info).auth_password, array_ptr TSRMLS_CC);
+ }
+ if (SG(request_info).auth_digest) {
+ php_register_variable("PHP_AUTH_DIGEST", SG(request_info).auth_digest, array_ptr TSRMLS_CC);
+ }
+ /* store request init time */
+ {
+ zval request_time_float, request_time_long;
+ Z_TYPE(request_time_float) = IS_DOUBLE;
+ Z_DVAL(request_time_float) = sapi_get_request_time(TSRMLS_C);
+ php_register_variable_ex("REQUEST_TIME_FLOAT", &request_time_float, array_ptr TSRMLS_CC);
+ Z_TYPE(request_time_long) = IS_LONG;
+ Z_LVAL(request_time_long) = zend_dval_to_lval(Z_DVAL(request_time_float));
+ php_register_variable_ex("REQUEST_TIME", &request_time_long, array_ptr TSRMLS_CC);
+ }
+
+}
+/* }}} */
+
+/* {{{ php_autoglobal_merge
+ */
+static void php_autoglobal_merge(HashTable *dest, HashTable *src TSRMLS_DC)
+{
+ zval **src_entry, **dest_entry;
+ char *string_key;
+ uint string_key_len;
+ ulong num_key;
+ HashPosition pos;
+ int key_type;
+ int globals_check = (dest == (&EG(symbol_table)));
+
+ zend_hash_internal_pointer_reset_ex(src, &pos);
+ while (zend_hash_get_current_data_ex(src, (void **)&src_entry, &pos) == SUCCESS) {
+ key_type = zend_hash_get_current_key_ex(src, &string_key, &string_key_len, &num_key, 0, &pos);
+ if (Z_TYPE_PP(src_entry) != IS_ARRAY
+ || (key_type == HASH_KEY_IS_STRING && zend_hash_find(dest, string_key, string_key_len, (void **) &dest_entry) != SUCCESS)
+ || (key_type == HASH_KEY_IS_LONG && zend_hash_index_find(dest, num_key, (void **)&dest_entry) != SUCCESS)
+ || Z_TYPE_PP(dest_entry) != IS_ARRAY
+ ) {
+ Z_ADDREF_PP(src_entry);
+ if (key_type == HASH_KEY_IS_STRING) {
+ if (!globals_check || string_key_len != sizeof("GLOBALS") || memcmp(string_key, "GLOBALS", sizeof("GLOBALS") - 1)) {
+ zend_hash_update(dest, string_key, string_key_len, src_entry, sizeof(zval *), NULL);
+ } else {
+ Z_DELREF_PP(src_entry);
+ }
+ } else {
+ zend_hash_index_update(dest, num_key, src_entry, sizeof(zval *), NULL);
+ }
+ } else {
+ SEPARATE_ZVAL(dest_entry);
+ php_autoglobal_merge(Z_ARRVAL_PP(dest_entry), Z_ARRVAL_PP(src_entry) TSRMLS_CC);
+ }
+ zend_hash_move_forward_ex(src, &pos);
+ }
+}
+/* }}} */
+
+static zend_bool php_auto_globals_create_server(const char *name, uint name_len TSRMLS_DC);
+static zend_bool php_auto_globals_create_env(const char *name, uint name_len TSRMLS_DC);
+static zend_bool php_auto_globals_create_request(const char *name, uint name_len TSRMLS_DC);
+
+/* {{{ php_hash_environment
+ */
+int php_hash_environment(TSRMLS_D)
+{
+ memset(PG(http_globals), 0, sizeof(PG(http_globals)));
+ zend_activate_auto_globals(TSRMLS_C);
+ if (PG(register_argc_argv)) {
+ php_build_argv(SG(request_info).query_string, PG(http_globals)[TRACK_VARS_SERVER] TSRMLS_CC);
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+static zend_bool php_auto_globals_create_get(const char *name, uint name_len TSRMLS_DC)
+{
+ zval *vars;
+
+ if (PG(variables_order) && (strchr(PG(variables_order),'G') || strchr(PG(variables_order),'g'))) {
+ sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC);
+ vars = PG(http_globals)[TRACK_VARS_GET];
+ } else {
+ ALLOC_ZVAL(vars);
+ array_init(vars);
+ INIT_PZVAL(vars);
+ if (PG(http_globals)[TRACK_VARS_GET]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_GET]);
+ }
+ PG(http_globals)[TRACK_VARS_GET] = vars;
+ }
+
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL);
+ Z_ADDREF_P(vars);
+
+ return 0; /* don't rearm */
+}
+
+static zend_bool php_auto_globals_create_post(const char *name, uint name_len TSRMLS_DC)
+{
+ zval *vars;
+
+ if (PG(variables_order) &&
+ (strchr(PG(variables_order),'P') || strchr(PG(variables_order),'p')) &&
+ !SG(headers_sent) &&
+ SG(request_info).request_method &&
+ !strcasecmp(SG(request_info).request_method, "POST")) {
+ sapi_module.treat_data(PARSE_POST, NULL, NULL TSRMLS_CC);
+ vars = PG(http_globals)[TRACK_VARS_POST];
+ } else {
+ ALLOC_ZVAL(vars);
+ array_init(vars);
+ INIT_PZVAL(vars);
+ if (PG(http_globals)[TRACK_VARS_POST]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_POST]);
+ }
+ PG(http_globals)[TRACK_VARS_POST] = vars;
+ }
+
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL);
+ Z_ADDREF_P(vars);
+
+ return 0; /* don't rearm */
+}
+
+static zend_bool php_auto_globals_create_cookie(const char *name, uint name_len TSRMLS_DC)
+{
+ zval *vars;
+
+ if (PG(variables_order) && (strchr(PG(variables_order),'C') || strchr(PG(variables_order),'c'))) {
+ sapi_module.treat_data(PARSE_COOKIE, NULL, NULL TSRMLS_CC);
+ vars = PG(http_globals)[TRACK_VARS_COOKIE];
+ } else {
+ ALLOC_ZVAL(vars);
+ array_init(vars);
+ INIT_PZVAL(vars);
+ if (PG(http_globals)[TRACK_VARS_COOKIE]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_COOKIE]);
+ }
+ PG(http_globals)[TRACK_VARS_COOKIE] = vars;
+ }
+
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL);
+ Z_ADDREF_P(vars);
+
+ return 0; /* don't rearm */
+}
+
+static zend_bool php_auto_globals_create_files(const char *name, uint name_len TSRMLS_DC)
+{
+ zval *vars;
+
+ if (PG(http_globals)[TRACK_VARS_FILES]) {
+ vars = PG(http_globals)[TRACK_VARS_FILES];
+ } else {
+ ALLOC_ZVAL(vars);
+ array_init(vars);
+ INIT_PZVAL(vars);
+ PG(http_globals)[TRACK_VARS_FILES] = vars;
+ }
+
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL);
+ Z_ADDREF_P(vars);
+
+ return 0; /* don't rearm */
+}
+
+static zend_bool php_auto_globals_create_server(const char *name, uint name_len TSRMLS_DC)
+{
+ if (PG(variables_order) && (strchr(PG(variables_order),'S') || strchr(PG(variables_order),'s'))) {
+ php_register_server_variables(TSRMLS_C);
+
+ if (PG(register_argc_argv)) {
+ if (SG(request_info).argc) {
+ zval **argc, **argv;
+
+ if (zend_hash_find(&EG(symbol_table), "argc", sizeof("argc"), (void**)&argc) == SUCCESS &&
+ zend_hash_find(&EG(symbol_table), "argv", sizeof("argv"), (void**)&argv) == SUCCESS) {
+ Z_ADDREF_PP(argc);
+ Z_ADDREF_PP(argv);
+ zend_hash_update(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "argv", sizeof("argv"), argv, sizeof(zval *), NULL);
+ zend_hash_update(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "argc", sizeof("argc"), argc, sizeof(zval *), NULL);
+ }
+ } else {
+ php_build_argv(SG(request_info).query_string, PG(http_globals)[TRACK_VARS_SERVER] TSRMLS_CC);
+ }
+ }
+
+ } else {
+ zval *server_vars=NULL;
+ ALLOC_ZVAL(server_vars);
+ array_init(server_vars);
+ INIT_PZVAL(server_vars);
+ if (PG(http_globals)[TRACK_VARS_SERVER]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_SERVER]);
+ }
+ PG(http_globals)[TRACK_VARS_SERVER] = server_vars;
+ }
+
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &PG(http_globals)[TRACK_VARS_SERVER], sizeof(zval *), NULL);
+ Z_ADDREF_P(PG(http_globals)[TRACK_VARS_SERVER]);
+
+ return 0; /* don't rearm */
+}
+
+static zend_bool php_auto_globals_create_env(const char *name, uint name_len TSRMLS_DC)
+{
+ zval *env_vars = NULL;
+ ALLOC_ZVAL(env_vars);
+ array_init(env_vars);
+ INIT_PZVAL(env_vars);
+ if (PG(http_globals)[TRACK_VARS_ENV]) {
+ zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_ENV]);
+ }
+ PG(http_globals)[TRACK_VARS_ENV] = env_vars;
+
+ if (PG(variables_order) && (strchr(PG(variables_order),'E') || strchr(PG(variables_order),'e'))) {
+ php_import_environment_variables(PG(http_globals)[TRACK_VARS_ENV] TSRMLS_CC);
+ }
+
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &PG(http_globals)[TRACK_VARS_ENV], sizeof(zval *), NULL);
+ Z_ADDREF_P(PG(http_globals)[TRACK_VARS_ENV]);
+
+ return 0; /* don't rearm */
+}
+
+static zend_bool php_auto_globals_create_request(const char *name, uint name_len TSRMLS_DC)
+{
+ zval *form_variables;
+ unsigned char _gpc_flags[3] = {0, 0, 0};
+ char *p;
+
+ ALLOC_ZVAL(form_variables);
+ array_init(form_variables);
+ INIT_PZVAL(form_variables);
+
+ if (PG(request_order) != NULL) {
+ p = PG(request_order);
+ } else {
+ p = PG(variables_order);
+ }
+
+ for (; p && *p; p++) {
+ switch (*p) {
+ case 'g':
+ case 'G':
+ if (!_gpc_flags[0]) {
+ php_autoglobal_merge(Z_ARRVAL_P(form_variables), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]) TSRMLS_CC);
+ _gpc_flags[0] = 1;
+ }
+ break;
+ case 'p':
+ case 'P':
+ if (!_gpc_flags[1]) {
+ php_autoglobal_merge(Z_ARRVAL_P(form_variables), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_POST]) TSRMLS_CC);
+ _gpc_flags[1] = 1;
+ }
+ break;
+ case 'c':
+ case 'C':
+ if (!_gpc_flags[2]) {
+ php_autoglobal_merge(Z_ARRVAL_P(form_variables), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) TSRMLS_CC);
+ _gpc_flags[2] = 1;
+ }
+ break;
+ }
+ }
+
+ zend_hash_update(&EG(symbol_table), name, name_len + 1, &form_variables, sizeof(zval *), NULL);
+ return 0;
+}
+
+void php_startup_auto_globals(TSRMLS_D)
+{
+ zend_register_auto_global(ZEND_STRL("_GET"), 0, php_auto_globals_create_get TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_POST"), 0, php_auto_globals_create_post TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_COOKIE"), 0, php_auto_globals_create_cookie TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_SERVER"), PG(auto_globals_jit), php_auto_globals_create_server TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_ENV"), PG(auto_globals_jit), php_auto_globals_create_env TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_REQUEST"), PG(auto_globals_jit), php_auto_globals_create_request TSRMLS_CC);
+ zend_register_auto_global(ZEND_STRL("_FILES"), 0, php_auto_globals_create_files TSRMLS_CC);
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/php_variables.h b/main/php_variables.h
new file mode 100644
index 0000000..8f5e96a
--- /dev/null
+++ b/main/php_variables.h
@@ -0,0 +1,49 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_VARIABLES_H
+#define PHP_VARIABLES_H
+
+#include "php.h"
+#include "SAPI.h"
+
+#define PARSE_POST 0
+#define PARSE_GET 1
+#define PARSE_COOKIE 2
+#define PARSE_STRING 3
+#define PARSE_ENV 4
+#define PARSE_SERVER 5
+#define PARSE_SESSION 6
+
+BEGIN_EXTERN_C()
+void php_startup_auto_globals(TSRMLS_D);
+extern PHPAPI void (*php_import_environment_variables)(zval *array_ptr TSRMLS_DC);
+PHPAPI void php_register_variable(char *var, char *val, zval *track_vars_array TSRMLS_DC);
+/* binary-safe version */
+PHPAPI void php_register_variable_safe(char *var, char *val, int val_len, zval *track_vars_array TSRMLS_DC);
+PHPAPI void php_register_variable_ex(char *var, zval *val, zval *track_vars_array TSRMLS_DC);
+
+int php_hash_environment(TSRMLS_D);
+END_EXTERN_C()
+
+#define NUM_TRACK_VARS 6
+
+#endif /* PHP_VARIABLES_H */
diff --git a/main/php_version.h b/main/php_version.h
new file mode 100644
index 0000000..e23d89e
--- /dev/null
+++ b/main/php_version.h
@@ -0,0 +1,8 @@
+/* automatically generated by configure */
+/* edit configure.in to change version number */
+#define PHP_MAJOR_VERSION 5
+#define PHP_MINOR_VERSION 4
+#define PHP_RELEASE_VERSION 13
+#define PHP_EXTRA_VERSION ""
+#define PHP_VERSION "5.4.13"
+#define PHP_VERSION_ID 50413
diff --git a/main/reentrancy.c b/main/reentrancy.c
new file mode 100644
index 0000000..7f85224
--- /dev/null
+++ b/main/reentrancy.c
@@ -0,0 +1,450 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Sascha Schumann <sascha@schumann.cx> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#include "php_reentrancy.h"
+#include "ext/standard/php_rand.h" /* for PHP_RAND_MAX */
+
+enum {
+ LOCALTIME_R,
+ CTIME_R,
+ ASCTIME_R,
+ GMTIME_R,
+ READDIR_R,
+ NUMBER_OF_LOCKS
+};
+
+#if defined(PHP_NEED_REENTRANCY)
+
+#include <TSRM.h>
+
+static MUTEX_T reentrant_locks[NUMBER_OF_LOCKS];
+
+#define local_lock(x) tsrm_mutex_lock(reentrant_locks[x])
+#define local_unlock(x) tsrm_mutex_unlock(reentrant_locks[x])
+
+#else
+
+#define local_lock(x)
+#define local_unlock(x)
+
+#endif
+
+#if defined(PHP_IRIX_TIME_R)
+
+#define HAVE_CTIME_R 1
+#define HAVE_ASCTIME_R 1
+
+PHPAPI char *php_ctime_r(const time_t *clock, char *buf)
+{
+ if (ctime_r(clock, buf) == buf)
+ return (buf);
+ return (NULL);
+}
+
+PHPAPI char *php_asctime_r(const struct tm *tm, char *buf)
+{
+ if (asctime_r(tm, buf) == buf)
+ return (buf);
+ return (NULL);
+}
+
+#endif
+
+#if defined(PHP_HPUX_TIME_R)
+
+#define HAVE_LOCALTIME_R 1
+#define HAVE_CTIME_R 1
+#define HAVE_ASCTIME_R 1
+#define HAVE_GMTIME_R 1
+
+PHPAPI struct tm *php_localtime_r(const time_t *const timep, struct tm *p_tm)
+{
+ if (localtime_r(timep, p_tm) == 0)
+ return (p_tm);
+ return (NULL);
+}
+
+PHPAPI char *php_ctime_r(const time_t *clock, char *buf)
+{
+ if (ctime_r(clock, buf, 26) != -1)
+ return (buf);
+ return (NULL);
+}
+
+PHPAPI char *php_asctime_r(const struct tm *tm, char *buf)
+{
+ if (asctime_r(tm, buf, 26) != -1)
+ return (buf);
+ return (NULL);
+}
+
+PHPAPI struct tm *php_gmtime_r(const time_t *const timep, struct tm *p_tm)
+{
+ if (gmtime_r(timep, p_tm) == 0)
+ return (p_tm);
+ return (NULL);
+}
+
+#endif
+
+#if defined(__BEOS__)
+
+PHPAPI struct tm *php_gmtime_r(const time_t *const timep, struct tm *p_tm)
+{
+ /* Modified according to LibC definition */
+ if (((struct tm*)gmtime_r(timep, p_tm)) == p_tm)
+ return (p_tm);
+ return (NULL);
+}
+
+#endif /* BEOS */
+
+#if !defined(HAVE_POSIX_READDIR_R)
+
+PHPAPI int php_readdir_r(DIR *dirp, struct dirent *entry,
+ struct dirent **result)
+{
+#if defined(HAVE_OLD_READDIR_R)
+ int ret = 0;
+
+ /* We cannot rely on the return value of readdir_r
+ as it differs between various platforms
+ (HPUX returns 0 on success whereas Solaris returns non-zero)
+ */
+ entry->d_name[0] = '\0';
+ readdir_r(dirp, entry);
+
+ if (entry->d_name[0] == '\0') {
+ *result = NULL;
+ ret = errno;
+ } else {
+ *result = entry;
+ }
+ return ret;
+#else
+ struct dirent *ptr;
+ int ret = 0;
+
+ local_lock(READDIR_R);
+
+ errno = 0;
+
+ ptr = readdir(dirp);
+
+ if (!ptr && errno != 0)
+ ret = errno;
+
+ if (ptr)
+ memcpy(entry, ptr, sizeof(*ptr));
+
+ *result = ptr;
+
+ local_unlock(READDIR_R);
+
+ return ret;
+#endif
+}
+
+#endif
+
+#if !defined(HAVE_LOCALTIME_R) && defined(HAVE_LOCALTIME)
+
+PHPAPI struct tm *php_localtime_r(const time_t *const timep, struct tm *p_tm)
+{
+ struct tm *tmp;
+
+ local_lock(LOCALTIME_R);
+
+ tmp = localtime(timep);
+ if (tmp) {
+ memcpy(p_tm, tmp, sizeof(struct tm));
+ tmp = p_tm;
+ }
+
+ local_unlock(LOCALTIME_R);
+
+ return tmp;
+}
+
+#endif
+
+#if !defined(HAVE_CTIME_R) && defined(HAVE_CTIME)
+
+PHPAPI char *php_ctime_r(const time_t *clock, char *buf)
+{
+ char *tmp;
+
+ local_lock(CTIME_R);
+
+ tmp = ctime(clock);
+ strcpy(buf, tmp);
+
+ local_unlock(CTIME_R);
+
+ return buf;
+}
+
+#endif
+
+#if !defined(HAVE_ASCTIME_R) && defined(HAVE_ASCTIME)
+
+PHPAPI char *php_asctime_r(const struct tm *tm, char *buf)
+{
+ char *tmp;
+
+ local_lock(ASCTIME_R);
+
+ tmp = asctime(tm);
+ strcpy(buf, tmp);
+
+ local_unlock(ASCTIME_R);
+
+ return buf;
+}
+
+#endif
+
+#if !defined(HAVE_GMTIME_R) && defined(HAVE_GMTIME)
+
+PHPAPI struct tm *php_gmtime_r(const time_t *const timep, struct tm *p_tm)
+{
+ struct tm *tmp;
+
+ local_lock(GMTIME_R);
+
+ tmp = gmtime(timep);
+ if (tmp) {
+ memcpy(p_tm, tmp, sizeof(struct tm));
+ tmp = p_tm;
+ }
+
+ local_unlock(GMTIME_R);
+
+ return tmp;
+}
+
+#endif
+
+#if defined(PHP_NEED_REENTRANCY)
+
+void reentrancy_startup(void)
+{
+ int i;
+
+ for (i = 0; i < NUMBER_OF_LOCKS; i++) {
+ reentrant_locks[i] = tsrm_mutex_alloc();
+ }
+}
+
+void reentrancy_shutdown(void)
+{
+ int i;
+
+ for (i = 0; i < NUMBER_OF_LOCKS; i++) {
+ tsrm_mutex_free(reentrant_locks[i]);
+ }
+}
+
+#endif
+
+#ifndef HAVE_RAND_R
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Posix rand_r function added May 1999 by Wes Peters <wes@softweyr.com>.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+static int
+do_rand(unsigned long *ctx)
+{
+ return ((*ctx = *ctx * 1103515245 + 12345) % ((u_long)PHP_RAND_MAX + 1));
+}
+
+
+PHPAPI int
+php_rand_r(unsigned int *ctx)
+{
+ u_long val = (u_long) *ctx;
+ *ctx = do_rand(&val);
+ return (int) *ctx;
+}
+
+#endif
+
+
+#ifndef HAVE_STRTOK_R
+
+/*
+ * Copyright (c) 1998 Softweyr LLC. All rights reserved.
+ *
+ * strtok_r, from Berkeley strtok
+ * Oct 13, 1998 by Wes Peters <wes@softweyr.com>
+ *
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notices, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notices, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *
+ * This product includes software developed by Softweyr LLC, the
+ * University of California, Berkeley, and its contributors.
+ *
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE
+ * REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+
+PHPAPI char *
+php_strtok_r(char *s, const char *delim, char **last)
+{
+ char *spanp;
+ int c, sc;
+ char *tok;
+
+ if (s == NULL && (s = *last) == NULL)
+ {
+ return NULL;
+ }
+
+ /*
+ * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
+ */
+cont:
+ c = *s++;
+ for (spanp = (char *)delim; (sc = *spanp++) != 0; )
+ {
+ if (c == sc)
+ {
+ goto cont;
+ }
+ }
+
+ if (c == 0) /* no non-delimiter characters */
+ {
+ *last = NULL;
+ return NULL;
+ }
+ tok = s - 1;
+
+ /*
+ * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
+ * Note that delim must have one NUL; we stop if we see that, too.
+ */
+ for (;;)
+ {
+ c = *s++;
+ spanp = (char *)delim;
+ do
+ {
+ if ((sc = *spanp++) == c)
+ {
+ if (c == 0)
+ {
+ s = NULL;
+ }
+ else
+ {
+ char *w = s - 1;
+ *w = '\0';
+ }
+ *last = s;
+ return tok;
+ }
+ }
+ while (sc != 0);
+ }
+ /* NOTREACHED */
+}
+
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/rfc1867.c b/main/rfc1867.c
new file mode 100644
index 0000000..35a1a15
--- /dev/null
+++ b/main/rfc1867.c
@@ -0,0 +1,1299 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Rasmus Lerdorf <rasmus@php.net> |
+ | Jani Taskinen <jani@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/*
+ * This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/).
+ *
+ */
+
+#include <stdio.h>
+#include "php.h"
+#include "php_open_temporary_file.h"
+#include "zend_globals.h"
+#include "php_globals.h"
+#include "php_variables.h"
+#include "rfc1867.h"
+#include "ext/standard/php_string.h"
+
+#define DEBUG_FILE_UPLOAD ZEND_DEBUG
+
+static int dummy_encoding_translation(TSRMLS_D)
+{
+ return 0;
+}
+
+static char *php_ap_getword(const zend_encoding *encoding, char **line, char stop TSRMLS_DC);
+static char *php_ap_getword_conf(const zend_encoding *encoding, char *str TSRMLS_DC);
+
+static php_rfc1867_encoding_translation_t php_rfc1867_encoding_translation = dummy_encoding_translation;
+static php_rfc1867_get_detect_order_t php_rfc1867_get_detect_order = NULL;
+static php_rfc1867_set_input_encoding_t php_rfc1867_set_input_encoding = NULL;
+static php_rfc1867_getword_t php_rfc1867_getword = php_ap_getword;
+static php_rfc1867_getword_conf_t php_rfc1867_getword_conf = php_ap_getword_conf;
+static php_rfc1867_basename_t php_rfc1867_basename = NULL;
+
+PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC) = NULL;
+
+static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC);
+
+/* The longest property name we use in an uploaded file array */
+#define MAX_SIZE_OF_INDEX sizeof("[tmp_name]")
+
+/* The longest anonymous name */
+#define MAX_SIZE_ANONNAME 33
+
+/* Errors */
+#define UPLOAD_ERROR_OK 0 /* File upload succesful */
+#define UPLOAD_ERROR_A 1 /* Uploaded file exceeded upload_max_filesize */
+#define UPLOAD_ERROR_B 2 /* Uploaded file exceeded MAX_FILE_SIZE */
+#define UPLOAD_ERROR_C 3 /* Partially uploaded */
+#define UPLOAD_ERROR_D 4 /* No file uploaded */
+#define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */
+#define UPLOAD_ERROR_F 7 /* Failed to write file to disk */
+#define UPLOAD_ERROR_X 8 /* File upload stopped by extension */
+
+void php_rfc1867_register_constants(TSRMLS_D) /* {{{ */
+{
+ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_OK", UPLOAD_ERROR_OK, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_INI_SIZE", UPLOAD_ERROR_A, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FORM_SIZE", UPLOAD_ERROR_B, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL", UPLOAD_ERROR_C, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE", UPLOAD_ERROR_D, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_CANT_WRITE", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT);
+ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_EXTENSION", UPLOAD_ERROR_X, CONST_CS | CONST_PERSISTENT);
+}
+/* }}} */
+
+static void normalize_protected_variable(char *varname TSRMLS_DC) /* {{{ */
+{
+ char *s = varname, *index = NULL, *indexend = NULL, *p;
+
+ /* overjump leading space */
+ while (*s == ' ') {
+ s++;
+ }
+
+ /* and remove it */
+ if (s != varname) {
+ memmove(varname, s, strlen(s)+1);
+ }
+
+ for (p = varname; *p && *p != '['; p++) {
+ switch(*p) {
+ case ' ':
+ case '.':
+ *p = '_';
+ break;
+ }
+ }
+
+ /* find index */
+ index = strchr(varname, '[');
+ if (index) {
+ index++;
+ s = index;
+ } else {
+ return;
+ }
+
+ /* done? */
+ while (index) {
+ while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') {
+ index++;
+ }
+ indexend = strchr(index, ']');
+ indexend = indexend ? indexend + 1 : index + strlen(index);
+
+ if (s != index) {
+ memmove(s, index, strlen(index)+1);
+ s += indexend-index;
+ } else {
+ s = indexend;
+ }
+
+ if (*s == '[') {
+ s++;
+ index = s;
+ } else {
+ index = NULL;
+ }
+ }
+ *s = '\0';
+}
+/* }}} */
+
+static void add_protected_variable(char *varname TSRMLS_DC) /* {{{ */
+{
+ int dummy = 1;
+
+ normalize_protected_variable(varname TSRMLS_CC);
+ zend_hash_add(&PG(rfc1867_protected_variables), varname, strlen(varname)+1, &dummy, sizeof(int), NULL);
+}
+/* }}} */
+
+static zend_bool is_protected_variable(char *varname TSRMLS_DC) /* {{{ */
+{
+ normalize_protected_variable(varname TSRMLS_CC);
+ return zend_hash_exists(&PG(rfc1867_protected_variables), varname, strlen(varname)+1);
+}
+/* }}} */
+
+static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
+{
+ if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
+ php_register_variable_safe(var, strval, val_len, track_vars_array TSRMLS_CC);
+ }
+}
+/* }}} */
+
+static void safe_php_register_variable_ex(char *var, zval *val, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
+{
+ if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
+ php_register_variable_ex(var, val, track_vars_array TSRMLS_CC);
+ }
+}
+/* }}} */
+
+static void register_http_post_files_variable(char *strvar, char *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) /* {{{ */
+{
+ safe_php_register_variable(strvar, val, strlen(val), http_post_files, override_protection TSRMLS_CC);
+}
+/* }}} */
+
+static void register_http_post_files_variable_ex(char *var, zval *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) /* {{{ */
+{
+ safe_php_register_variable_ex(var, val, http_post_files, override_protection TSRMLS_CC);
+}
+/* }}} */
+
+static int unlink_filename(char **filename TSRMLS_DC) /* {{{ */
+{
+ VCWD_UNLINK(*filename);
+ return 0;
+}
+/* }}} */
+
+void destroy_uploaded_files_hash(TSRMLS_D) /* {{{ */
+{
+ zend_hash_apply(SG(rfc1867_uploaded_files), (apply_func_t) unlink_filename TSRMLS_CC);
+ zend_hash_destroy(SG(rfc1867_uploaded_files));
+ FREE_HASHTABLE(SG(rfc1867_uploaded_files));
+}
+/* }}} */
+
+/* {{{ Following code is based on apache_multipart_buffer.c from libapreq-0.33 package. */
+
+#define FILLUNIT (1024 * 5)
+
+typedef struct {
+
+ /* read buffer */
+ char *buffer;
+ char *buf_begin;
+ int bufsize;
+ int bytes_in_buffer;
+
+ /* boundary info */
+ char *boundary;
+ char *boundary_next;
+ int boundary_next_len;
+
+ const zend_encoding *input_encoding;
+ const zend_encoding **detect_order;
+ size_t detect_order_size;
+} multipart_buffer;
+
+typedef struct {
+ char *key;
+ char *value;
+} mime_header_entry;
+
+/*
+ * Fill up the buffer with client data.
+ * Returns number of bytes added to buffer.
+ */
+static int fill_buffer(multipart_buffer *self TSRMLS_DC)
+{
+ int bytes_to_read, total_read = 0, actual_read = 0;
+
+ /* shift the existing data if necessary */
+ if (self->bytes_in_buffer > 0 && self->buf_begin != self->buffer) {
+ memmove(self->buffer, self->buf_begin, self->bytes_in_buffer);
+ }
+
+ self->buf_begin = self->buffer;
+
+ /* calculate the free space in the buffer */
+ bytes_to_read = self->bufsize - self->bytes_in_buffer;
+
+ /* read the required number of bytes */
+ while (bytes_to_read > 0) {
+
+ char *buf = self->buffer + self->bytes_in_buffer;
+
+ actual_read = sapi_module.read_post(buf, bytes_to_read TSRMLS_CC);
+
+ /* update the buffer length */
+ if (actual_read > 0) {
+ self->bytes_in_buffer += actual_read;
+ SG(read_post_bytes) += actual_read;
+ total_read += actual_read;
+ bytes_to_read -= actual_read;
+ } else {
+ break;
+ }
+ }
+
+ return total_read;
+}
+
+/* eof if we are out of bytes, or if we hit the final boundary */
+static int multipart_buffer_eof(multipart_buffer *self TSRMLS_DC)
+{
+ if ( (self->bytes_in_buffer == 0 && fill_buffer(self TSRMLS_CC) < 1) ) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* create new multipart_buffer structure */
+static multipart_buffer *multipart_buffer_new(char *boundary, int boundary_len TSRMLS_DC)
+{
+ multipart_buffer *self = (multipart_buffer *) ecalloc(1, sizeof(multipart_buffer));
+
+ int minsize = boundary_len + 6;
+ if (minsize < FILLUNIT) minsize = FILLUNIT;
+
+ self->buffer = (char *) ecalloc(1, minsize + 1);
+ self->bufsize = minsize;
+
+ spprintf(&self->boundary, 0, "--%s", boundary);
+
+ self->boundary_next_len = spprintf(&self->boundary_next, 0, "\n--%s", boundary);
+
+ self->buf_begin = self->buffer;
+ self->bytes_in_buffer = 0;
+
+ if (php_rfc1867_encoding_translation(TSRMLS_C)) {
+ php_rfc1867_get_detect_order(&self->detect_order, &self->detect_order_size TSRMLS_CC);
+ } else {
+ self->detect_order = NULL;
+ self->detect_order_size = 0;
+ }
+
+ self->input_encoding = NULL;
+
+ return self;
+}
+
+/*
+ * Gets the next CRLF terminated line from the input buffer.
+ * If it doesn't find a CRLF, and the buffer isn't completely full, returns
+ * NULL; otherwise, returns the beginning of the null-terminated line,
+ * minus the CRLF.
+ *
+ * Note that we really just look for LF terminated lines. This works
+ * around a bug in internet explorer for the macintosh which sends mime
+ * boundaries that are only LF terminated when you use an image submit
+ * button in a multipart/form-data form.
+ */
+static char *next_line(multipart_buffer *self)
+{
+ /* look for LF in the data */
+ char* line = self->buf_begin;
+ char* ptr = memchr(self->buf_begin, '\n', self->bytes_in_buffer);
+
+ if (ptr) { /* LF found */
+
+ /* terminate the string, remove CRLF */
+ if ((ptr - line) > 0 && *(ptr-1) == '\r') {
+ *(ptr-1) = 0;
+ } else {
+ *ptr = 0;
+ }
+
+ /* bump the pointer */
+ self->buf_begin = ptr + 1;
+ self->bytes_in_buffer -= (self->buf_begin - line);
+
+ } else { /* no LF found */
+
+ /* buffer isn't completely full, fail */
+ if (self->bytes_in_buffer < self->bufsize) {
+ return NULL;
+ }
+ /* return entire buffer as a partial line */
+ line[self->bufsize] = 0;
+ self->buf_begin = ptr;
+ self->bytes_in_buffer = 0;
+ }
+
+ return line;
+}
+
+/* Returns the next CRLF terminated line from the client */
+static char *get_line(multipart_buffer *self TSRMLS_DC)
+{
+ char* ptr = next_line(self);
+
+ if (!ptr) {
+ fill_buffer(self TSRMLS_CC);
+ ptr = next_line(self);
+ }
+
+ return ptr;
+}
+
+/* Free header entry */
+static void php_free_hdr_entry(mime_header_entry *h)
+{
+ if (h->key) {
+ efree(h->key);
+ }
+ if (h->value) {
+ efree(h->value);
+ }
+}
+
+/* finds a boundary */
+static int find_boundary(multipart_buffer *self, char *boundary TSRMLS_DC)
+{
+ char *line;
+
+ /* loop thru lines */
+ while( (line = get_line(self TSRMLS_CC)) )
+ {
+ /* finished if we found the boundary */
+ if (!strcmp(line, boundary)) {
+ return 1;
+ }
+ }
+
+ /* didn't find the boundary */
+ return 0;
+}
+
+/* parse headers */
+static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header TSRMLS_DC)
+{
+ char *line;
+ mime_header_entry prev_entry, entry;
+ int prev_len, cur_len;
+
+ /* didn't find boundary, abort */
+ if (!find_boundary(self, self->boundary TSRMLS_CC)) {
+ return 0;
+ }
+
+ /* get lines of text, or CRLF_CRLF */
+
+ while( (line = get_line(self TSRMLS_CC)) && strlen(line) > 0 )
+ {
+ /* add header to table */
+ char *key = line;
+ char *value = NULL;
+
+ if (php_rfc1867_encoding_translation(TSRMLS_C)) {
+ self->input_encoding = zend_multibyte_encoding_detector(line, strlen(line), self->detect_order, self->detect_order_size TSRMLS_CC);
+ }
+
+ /* space in the beginning means same header */
+ if (!isspace(line[0])) {
+ value = strchr(line, ':');
+ }
+
+ if (value) {
+ *value = 0;
+ do { value++; } while(isspace(*value));
+
+ entry.value = estrdup(value);
+ entry.key = estrdup(key);
+
+ } else if (zend_llist_count(header)) { /* If no ':' on the line, add to previous line */
+
+ prev_len = strlen(prev_entry.value);
+ cur_len = strlen(line);
+
+ entry.value = emalloc(prev_len + cur_len + 1);
+ memcpy(entry.value, prev_entry.value, prev_len);
+ memcpy(entry.value + prev_len, line, cur_len);
+ entry.value[cur_len + prev_len] = '\0';
+
+ entry.key = estrdup(prev_entry.key);
+
+ zend_llist_remove_tail(header);
+ } else {
+ continue;
+ }
+
+ zend_llist_add_element(header, &entry);
+ prev_entry = entry;
+ }
+
+ return 1;
+}
+
+static char *php_mime_get_hdr_value(zend_llist header, char *key)
+{
+ mime_header_entry *entry;
+
+ if (key == NULL) {
+ return NULL;
+ }
+
+ entry = zend_llist_get_first(&header);
+ while (entry) {
+ if (!strcasecmp(entry->key, key)) {
+ return entry->value;
+ }
+ entry = zend_llist_get_next(&header);
+ }
+
+ return NULL;
+}
+
+static char *php_ap_getword(const zend_encoding *encoding, char **line, char stop TSRMLS_DC)
+{
+ char *pos = *line, quote;
+ char *res;
+
+ while (*pos && *pos != stop) {
+ if ((quote = *pos) == '"' || quote == '\'') {
+ ++pos;
+ while (*pos && *pos != quote) {
+ if (*pos == '\\' && pos[1] && pos[1] == quote) {
+ pos += 2;
+ } else {
+ ++pos;
+ }
+ }
+ if (*pos) {
+ ++pos;
+ }
+ } else ++pos;
+ }
+ if (*pos == '\0') {
+ res = estrdup(*line);
+ *line += strlen(*line);
+ return res;
+ }
+
+ res = estrndup(*line, pos - *line);
+
+ while (*pos == stop) {
+ ++pos;
+ }
+
+ *line = pos;
+ return res;
+}
+
+static char *substring_conf(char *start, int len, char quote)
+{
+ char *result = emalloc(len + 1);
+ char *resp = result;
+ int i;
+
+ for (i = 0; i < len && start[i] != quote; ++i) {
+ if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) {
+ *resp++ = start[++i];
+ } else {
+ *resp++ = start[i];
+ }
+ }
+
+ *resp = '\0';
+ return result;
+}
+
+static char *php_ap_getword_conf(const zend_encoding *encoding, char *str TSRMLS_DC)
+{
+ while (*str && isspace(*str)) {
+ ++str;
+ }
+
+ if (!*str) {
+ return estrdup("");
+ }
+
+ if (*str == '"' || *str == '\'') {
+ char quote = *str;
+
+ str++;
+ return substring_conf(str, strlen(str), quote);
+ } else {
+ char *strend = str;
+
+ while (*strend && !isspace(*strend)) {
+ ++strend;
+ }
+ return substring_conf(str, strend - str, 0);
+ }
+}
+
+static char *php_ap_basename(const zend_encoding *encoding, char *path TSRMLS_DC)
+{
+ char *s = strrchr(path, '\\');
+ char *s2 = strrchr(path, '/');
+
+ if (s && s2) {
+ if (s > s2) {
+ ++s;
+ } else {
+ s = ++s2;
+ }
+ return s;
+ } else if (s) {
+ return ++s;
+ } else if (s2) {
+ return ++s2;
+ }
+ return path;
+}
+
+/*
+ * Search for a string in a fixed-length byte string.
+ * If partial is true, partial matches are allowed at the end of the buffer.
+ * Returns NULL if not found, or a pointer to the start of the first match.
+ */
+static void *php_ap_memstr(char *haystack, int haystacklen, char *needle, int needlen, int partial)
+{
+ int len = haystacklen;
+ char *ptr = haystack;
+
+ /* iterate through first character matches */
+ while( (ptr = memchr(ptr, needle[0], len)) ) {
+
+ /* calculate length after match */
+ len = haystacklen - (ptr - (char *)haystack);
+
+ /* done if matches up to capacity of buffer */
+ if (memcmp(needle, ptr, needlen < len ? needlen : len) == 0 && (partial || len >= needlen)) {
+ break;
+ }
+
+ /* next character */
+ ptr++; len--;
+ }
+
+ return ptr;
+}
+
+/* read until a boundary condition */
+static int multipart_buffer_read(multipart_buffer *self, char *buf, int bytes, int *end TSRMLS_DC)
+{
+ int len, max;
+ char *bound;
+
+ /* fill buffer if needed */
+ if (bytes > self->bytes_in_buffer) {
+ fill_buffer(self TSRMLS_CC);
+ }
+
+ /* look for a potential boundary match, only read data up to that point */
+ if ((bound = php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 1))) {
+ max = bound - self->buf_begin;
+ if (end && php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 0)) {
+ *end = 1;
+ }
+ } else {
+ max = self->bytes_in_buffer;
+ }
+
+ /* maximum number of bytes we are reading */
+ len = max < bytes-1 ? max : bytes-1;
+
+ /* if we read any data... */
+ if (len > 0) {
+
+ /* copy the data */
+ memcpy(buf, self->buf_begin, len);
+ buf[len] = 0;
+
+ if (bound && len > 0 && buf[len-1] == '\r') {
+ buf[--len] = 0;
+ }
+
+ /* update the buffer */
+ self->bytes_in_buffer -= len;
+ self->buf_begin += len;
+ }
+
+ return len;
+}
+
+/*
+ XXX: this is horrible memory-usage-wise, but we only expect
+ to do this on small pieces of form data.
+*/
+static char *multipart_buffer_read_body(multipart_buffer *self, unsigned int *len TSRMLS_DC)
+{
+ char buf[FILLUNIT], *out=NULL;
+ int total_bytes=0, read_bytes=0;
+
+ while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf), NULL TSRMLS_CC))) {
+ out = erealloc(out, total_bytes + read_bytes + 1);
+ memcpy(out + total_bytes, buf, read_bytes);
+ total_bytes += read_bytes;
+ }
+
+ if (out) {
+ out[total_bytes] = '\0';
+ }
+ *len = total_bytes;
+
+ return out;
+}
+/* }}} */
+
+/*
+ * The combined READER/HANDLER
+ *
+ */
+
+SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
+{
+ char *boundary, *s = NULL, *boundary_end = NULL, *start_arr = NULL, *array_index = NULL;
+ char *temp_filename = NULL, *lbuf = NULL, *abuf = NULL;
+ int boundary_len = 0, total_bytes = 0, cancel_upload = 0, is_arr_upload = 0, array_len = 0;
+ int max_file_size = 0, skip_upload = 0, anonindex = 0, is_anonymous;
+ zval *http_post_files = NULL;
+ HashTable *uploaded_files = NULL;
+ multipart_buffer *mbuff;
+ zval *array_ptr = (zval *) arg;
+ int fd = -1;
+ zend_llist header;
+ void *event_extra_data = NULL;
+ unsigned int llen = 0;
+ int upload_cnt = INI_INT("max_file_uploads");
+ const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(TSRMLS_C);
+ php_rfc1867_getword_t getword;
+ php_rfc1867_getword_conf_t getword_conf;
+ php_rfc1867_basename_t _basename;
+ long count = 0;
+
+ if (php_rfc1867_encoding_translation(TSRMLS_C) && internal_encoding) {
+ getword = php_rfc1867_getword;
+ getword_conf = php_rfc1867_getword_conf;
+ _basename = php_rfc1867_basename;
+ } else {
+ getword = php_ap_getword;
+ getword_conf = php_ap_getword_conf;
+ _basename = php_ap_basename;
+ }
+
+ if (SG(post_max_size) > 0 && SG(request_info).content_length > SG(post_max_size)) {
+ sapi_module.sapi_error(E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes", SG(request_info).content_length, SG(post_max_size));
+ return;
+ }
+
+ /* Get the boundary */
+ boundary = strstr(content_type_dup, "boundary");
+ if (!boundary) {
+ int content_type_len = strlen(content_type_dup);
+ char *content_type_lcase = estrndup(content_type_dup, content_type_len);
+
+ php_strtolower(content_type_lcase, content_type_len);
+ boundary = strstr(content_type_lcase, "boundary");
+ if (boundary) {
+ boundary = content_type_dup + (boundary - content_type_lcase);
+ }
+ efree(content_type_lcase);
+ }
+
+ if (!boundary || !(boundary = strchr(boundary, '='))) {
+ sapi_module.sapi_error(E_WARNING, "Missing boundary in multipart/form-data POST data");
+ return;
+ }
+
+ boundary++;
+ boundary_len = strlen(boundary);
+
+ if (boundary[0] == '"') {
+ boundary++;
+ boundary_end = strchr(boundary, '"');
+ if (!boundary_end) {
+ sapi_module.sapi_error(E_WARNING, "Invalid boundary in multipart/form-data POST data");
+ return;
+ }
+ } else {
+ /* search for the end of the boundary */
+ boundary_end = strpbrk(boundary, ",;");
+ }
+ if (boundary_end) {
+ boundary_end[0] = '\0';
+ boundary_len = boundary_end-boundary;
+ }
+
+ /* Initialize the buffer */
+ if (!(mbuff = multipart_buffer_new(boundary, boundary_len TSRMLS_CC))) {
+ sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer");
+ return;
+ }
+
+ /* Initialize $_FILES[] */
+ zend_hash_init(&PG(rfc1867_protected_variables), 5, NULL, NULL, 0);
+
+ ALLOC_HASHTABLE(uploaded_files);
+ zend_hash_init(uploaded_files, 5, NULL, (dtor_func_t) free_estring, 0);
+ SG(rfc1867_uploaded_files) = uploaded_files;
+
+ ALLOC_ZVAL(http_post_files);
+ array_init(http_post_files);
+ INIT_PZVAL(http_post_files);
+ PG(http_globals)[TRACK_VARS_FILES] = http_post_files;
+
+ zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
+
+ if (php_rfc1867_callback != NULL) {
+ multipart_event_start event_start;
+
+ event_start.content_length = SG(request_info).content_length;
+ if (php_rfc1867_callback(MULTIPART_EVENT_START, &event_start, &event_extra_data TSRMLS_CC) == FAILURE) {
+ goto fileupload_done;
+ }
+ }
+
+ while (!multipart_buffer_eof(mbuff TSRMLS_CC))
+ {
+ char buff[FILLUNIT];
+ char *cd = NULL, *param = NULL, *filename = NULL, *tmp = NULL;
+ size_t blen = 0, wlen = 0;
+ off_t offset;
+
+ zend_llist_clean(&header);
+
+ if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) {
+ goto fileupload_done;
+ }
+
+ if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {
+ char *pair = NULL;
+ int end = 0;
+
+ while (isspace(*cd)) {
+ ++cd;
+ }
+
+ while (*cd && (pair = getword(mbuff->input_encoding, &cd, ';' TSRMLS_CC)))
+ {
+ char *key = NULL, *word = pair;
+
+ while (isspace(*cd)) {
+ ++cd;
+ }
+
+ if (strchr(pair, '=')) {
+ key = getword(mbuff->input_encoding, &pair, '=' TSRMLS_CC);
+
+ if (!strcasecmp(key, "name")) {
+ if (param) {
+ efree(param);
+ }
+ param = getword_conf(mbuff->input_encoding, pair TSRMLS_CC);
+ if (mbuff->input_encoding && internal_encoding) {
+ unsigned char *new_param;
+ size_t new_param_len;
+ if ((size_t)-1 != zend_multibyte_encoding_converter(&new_param, &new_param_len, (unsigned char *)param, strlen(param), internal_encoding, mbuff->input_encoding TSRMLS_CC)) {
+ efree(param);
+ param = (char *)new_param;
+ }
+ }
+ } else if (!strcasecmp(key, "filename")) {
+ if (filename) {
+ efree(filename);
+ }
+ filename = getword_conf(mbuff->input_encoding, pair TSRMLS_CC);
+ if (mbuff->input_encoding && internal_encoding) {
+ unsigned char *new_filename;
+ size_t new_filename_len;
+ if ((size_t)-1 != zend_multibyte_encoding_converter(&new_filename, &new_filename_len, (unsigned char *)filename, strlen(filename), internal_encoding, mbuff->input_encoding TSRMLS_CC)) {
+ efree(filename);
+ filename = (char *)new_filename;
+ }
+ }
+ }
+ }
+ if (key) {
+ efree(key);
+ }
+ efree(word);
+ }
+
+ /* Normal form variable, safe to read all data into memory */
+ if (!filename && param) {
+ unsigned int value_len;
+ char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC);
+ unsigned int new_val_len; /* Dummy variable */
+
+ if (!value) {
+ value = estrdup("");
+ value_len = 0;
+ }
+
+ if (mbuff->input_encoding && internal_encoding) {
+ unsigned char *new_value;
+ size_t new_value_len;
+ if ((size_t)-1 != zend_multibyte_encoding_converter(&new_value, &new_value_len, (unsigned char *)value, value_len, internal_encoding, mbuff->input_encoding TSRMLS_CC)) {
+ efree(value);
+ value = (char *)new_value;
+ value_len = new_value_len;
+ }
+ }
+
+ if (++count <= PG(max_input_vars) && sapi_module.input_filter(PARSE_POST, param, &value, value_len, &new_val_len TSRMLS_CC)) {
+ if (php_rfc1867_callback != NULL) {
+ multipart_event_formdata event_formdata;
+ size_t newlength = new_val_len;
+
+ event_formdata.post_bytes_processed = SG(read_post_bytes);
+ event_formdata.name = param;
+ event_formdata.value = &value;
+ event_formdata.length = new_val_len;
+ event_formdata.newlength = &newlength;
+ if (php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC) == FAILURE) {
+ efree(param);
+ efree(value);
+ continue;
+ }
+ new_val_len = newlength;
+ }
+ safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
+ } else {
+ if (count == PG(max_input_vars) + 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
+ }
+
+ if (php_rfc1867_callback != NULL) {
+ multipart_event_formdata event_formdata;
+
+ event_formdata.post_bytes_processed = SG(read_post_bytes);
+ event_formdata.name = param;
+ event_formdata.value = &value;
+ event_formdata.length = value_len;
+ event_formdata.newlength = NULL;
+ php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC);
+ }
+ }
+
+ if (!strcasecmp(param, "MAX_FILE_SIZE")) {
+ max_file_size = atol(value);
+ }
+
+ efree(param);
+ efree(value);
+ continue;
+ }
+
+ /* If file_uploads=off, skip the file part */
+ if (!PG(file_uploads)) {
+ skip_upload = 1;
+ } else if (upload_cnt <= 0) {
+ skip_upload = 1;
+ sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded");
+ }
+
+ /* Return with an error if the posted data is garbled */
+ if (!param && !filename) {
+ sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled");
+ goto fileupload_done;
+ }
+
+ if (!param) {
+ is_anonymous = 1;
+ param = emalloc(MAX_SIZE_ANONNAME);
+ snprintf(param, MAX_SIZE_ANONNAME, "%u", anonindex++);
+ } else {
+ is_anonymous = 0;
+ }
+
+ /* New Rule: never repair potential malicious user input */
+ if (!skip_upload) {
+ long c = 0;
+ tmp = param;
+
+ while (*tmp) {
+ if (*tmp == '[') {
+ c++;
+ } else if (*tmp == ']') {
+ c--;
+ if (tmp[1] && tmp[1] != '[') {
+ skip_upload = 1;
+ break;
+ }
+ }
+ if (c < 0) {
+ skip_upload = 1;
+ break;
+ }
+ tmp++;
+ }
+ /* Brackets should always be closed */
+ if(c != 0) {
+ skip_upload = 1;
+ }
+ }
+
+ total_bytes = cancel_upload = 0;
+ temp_filename = NULL;
+ fd = -1;
+
+ if (!skip_upload && php_rfc1867_callback != NULL) {
+ multipart_event_file_start event_file_start;
+
+ event_file_start.post_bytes_processed = SG(read_post_bytes);
+ event_file_start.name = param;
+ event_file_start.filename = &filename;
+ if (php_rfc1867_callback(MULTIPART_EVENT_FILE_START, &event_file_start, &event_extra_data TSRMLS_CC) == FAILURE) {
+ temp_filename = "";
+ efree(param);
+ efree(filename);
+ continue;
+ }
+ }
+
+ if (skip_upload) {
+ efree(param);
+ efree(filename);
+ continue;
+ }
+
+ if (strlen(filename) == 0) {
+#if DEBUG_FILE_UPLOAD
+ sapi_module.sapi_error(E_NOTICE, "No file uploaded");
+#endif
+ cancel_upload = UPLOAD_ERROR_D;
+ }
+
+ offset = 0;
+ end = 0;
+
+ if (!cancel_upload) {
+ /* only bother to open temp file if we have data */
+ blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC);
+#if DEBUG_FILE_UPLOAD
+ if (blen > 0) {
+#else
+ /* in non-debug mode we have no problem with 0-length files */
+ {
+#endif
+ fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), "php", &temp_filename, 1 TSRMLS_CC);
+ upload_cnt--;
+ if (fd == -1) {
+ sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file");
+ cancel_upload = UPLOAD_ERROR_E;
+ }
+ }
+ }
+
+ while (!cancel_upload && (blen > 0))
+ {
+ if (php_rfc1867_callback != NULL) {
+ multipart_event_file_data event_file_data;
+
+ event_file_data.post_bytes_processed = SG(read_post_bytes);
+ event_file_data.offset = offset;
+ event_file_data.data = buff;
+ event_file_data.length = blen;
+ event_file_data.newlength = &blen;
+ if (php_rfc1867_callback(MULTIPART_EVENT_FILE_DATA, &event_file_data, &event_extra_data TSRMLS_CC) == FAILURE) {
+ cancel_upload = UPLOAD_ERROR_X;
+ continue;
+ }
+ }
+
+ if (PG(upload_max_filesize) > 0 && (long)(total_bytes+blen) > PG(upload_max_filesize)) {
+#if DEBUG_FILE_UPLOAD
+ sapi_module.sapi_error(E_NOTICE, "upload_max_filesize of %ld bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename);
+#endif
+ cancel_upload = UPLOAD_ERROR_A;
+ } else if (max_file_size && ((long)(total_bytes+blen) > max_file_size)) {
+#if DEBUG_FILE_UPLOAD
+ sapi_module.sapi_error(E_NOTICE, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename);
+#endif
+ cancel_upload = UPLOAD_ERROR_B;
+ } else if (blen > 0) {
+ wlen = write(fd, buff, blen);
+
+ if (wlen == -1) {
+ /* write failed */
+#if DEBUG_FILE_UPLOAD
+ sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno));
+#endif
+ cancel_upload = UPLOAD_ERROR_F;
+ } else if (wlen < blen) {
+#if DEBUG_FILE_UPLOAD
+ sapi_module.sapi_error(E_NOTICE, "Only %d bytes were written, expected to write %d", wlen, blen);
+#endif
+ cancel_upload = UPLOAD_ERROR_F;
+ } else {
+ total_bytes += wlen;
+ }
+ offset += wlen;
+ }
+
+ /* read data for next iteration */
+ blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC);
+ }
+
+ if (fd != -1) { /* may not be initialized if file could not be created */
+ close(fd);
+ }
+
+ if (!cancel_upload && !end) {
+#if DEBUG_FILE_UPLOAD
+ sapi_module.sapi_error(E_NOTICE, "Missing mime boundary at the end of the data for file %s", strlen(filename) > 0 ? filename : "");
+#endif
+ cancel_upload = UPLOAD_ERROR_C;
+ }
+#if DEBUG_FILE_UPLOAD
+ if (strlen(filename) > 0 && total_bytes == 0 && !cancel_upload) {
+ sapi_module.sapi_error(E_WARNING, "Uploaded file size 0 - file [%s=%s] not saved", param, filename);
+ cancel_upload = 5;
+ }
+#endif
+ if (php_rfc1867_callback != NULL) {
+ multipart_event_file_end event_file_end;
+
+ event_file_end.post_bytes_processed = SG(read_post_bytes);
+ event_file_end.temp_filename = temp_filename;
+ event_file_end.cancel_upload = cancel_upload;
+ if (php_rfc1867_callback(MULTIPART_EVENT_FILE_END, &event_file_end, &event_extra_data TSRMLS_CC) == FAILURE) {
+ cancel_upload = UPLOAD_ERROR_X;
+ }
+ }
+
+ if (cancel_upload) {
+ if (temp_filename) {
+ if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
+ unlink(temp_filename);
+ }
+ efree(temp_filename);
+ }
+ temp_filename = "";
+ } else {
+ zend_hash_add(SG(rfc1867_uploaded_files), temp_filename, strlen(temp_filename) + 1, &temp_filename, sizeof(char *), NULL);
+ }
+
+ /* is_arr_upload is true when name of file upload field
+ * ends in [.*]
+ * start_arr is set to point to 1st [ */
+ is_arr_upload = (start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']');
+
+ if (is_arr_upload) {
+ array_len = strlen(start_arr);
+ if (array_index) {
+ efree(array_index);
+ }
+ array_index = estrndup(start_arr + 1, array_len - 2);
+ }
+
+ /* Add $foo_name */
+ if (llen < strlen(param) + MAX_SIZE_OF_INDEX + 1) {
+ llen = strlen(param);
+ lbuf = (char *) safe_erealloc(lbuf, llen, 1, MAX_SIZE_OF_INDEX + 1);
+ llen += MAX_SIZE_OF_INDEX + 1;
+ }
+
+ if (is_arr_upload) {
+ if (abuf) efree(abuf);
+ abuf = estrndup(param, strlen(param)-array_len);
+ snprintf(lbuf, llen, "%s_name[%s]", abuf, array_index);
+ } else {
+ snprintf(lbuf, llen, "%s_name", param);
+ }
+
+ /* The \ check should technically be needed for win32 systems only where
+ * it is a valid path separator. However, IE in all it's wisdom always sends
+ * the full path of the file on the user's filesystem, which means that unless
+ * the user does basename() they get a bogus file name. Until IE's user base drops
+ * to nill or problem is fixed this code must remain enabled for all systems. */
+ s = _basename(internal_encoding, filename TSRMLS_CC);
+ if (!s) {
+ s = filename;
+ }
+
+ if (!is_anonymous) {
+ safe_php_register_variable(lbuf, s, strlen(s), NULL, 0 TSRMLS_CC);
+ }
+
+ /* Add $foo[name] */
+ if (is_arr_upload) {
+ snprintf(lbuf, llen, "%s[name][%s]", abuf, array_index);
+ } else {
+ snprintf(lbuf, llen, "%s[name]", param);
+ }
+ register_http_post_files_variable(lbuf, s, http_post_files, 0 TSRMLS_CC);
+ efree(filename);
+ s = NULL;
+
+ /* Possible Content-Type: */
+ if (cancel_upload || !(cd = php_mime_get_hdr_value(header, "Content-Type"))) {
+ cd = "";
+ } else {
+ /* fix for Opera 6.01 */
+ s = strchr(cd, ';');
+ if (s != NULL) {
+ *s = '\0';
+ }
+ }
+
+ /* Add $foo_type */
+ if (is_arr_upload) {
+ snprintf(lbuf, llen, "%s_type[%s]", abuf, array_index);
+ } else {
+ snprintf(lbuf, llen, "%s_type", param);
+ }
+ if (!is_anonymous) {
+ safe_php_register_variable(lbuf, cd, strlen(cd), NULL, 0 TSRMLS_CC);
+ }
+
+ /* Add $foo[type] */
+ if (is_arr_upload) {
+ snprintf(lbuf, llen, "%s[type][%s]", abuf, array_index);
+ } else {
+ snprintf(lbuf, llen, "%s[type]", param);
+ }
+ register_http_post_files_variable(lbuf, cd, http_post_files, 0 TSRMLS_CC);
+
+ /* Restore Content-Type Header */
+ if (s != NULL) {
+ *s = ';';
+ }
+ s = "";
+
+ {
+ /* store temp_filename as-is (in case upload_tmp_dir
+ * contains escapeable characters. escape only the variable name.) */
+ zval zfilename;
+
+ /* Initialize variables */
+ add_protected_variable(param TSRMLS_CC);
+
+ /* if param is of form xxx[.*] this will cut it to xxx */
+ if (!is_anonymous) {
+ ZVAL_STRING(&zfilename, temp_filename, 1);
+ safe_php_register_variable_ex(param, &zfilename, NULL, 1 TSRMLS_CC);
+ }
+
+ /* Add $foo[tmp_name] */
+ if (is_arr_upload) {
+ snprintf(lbuf, llen, "%s[tmp_name][%s]", abuf, array_index);
+ } else {
+ snprintf(lbuf, llen, "%s[tmp_name]", param);
+ }
+ add_protected_variable(lbuf TSRMLS_CC);
+ ZVAL_STRING(&zfilename, temp_filename, 1);
+ register_http_post_files_variable_ex(lbuf, &zfilename, http_post_files, 1 TSRMLS_CC);
+ }
+
+ {
+ zval file_size, error_type;
+
+ error_type.value.lval = cancel_upload;
+ error_type.type = IS_LONG;
+
+ /* Add $foo[error] */
+ if (cancel_upload) {
+ file_size.value.lval = 0;
+ file_size.type = IS_LONG;
+ } else {
+ file_size.value.lval = total_bytes;
+ file_size.type = IS_LONG;
+ }
+
+ if (is_arr_upload) {
+ snprintf(lbuf, llen, "%s[error][%s]", abuf, array_index);
+ } else {
+ snprintf(lbuf, llen, "%s[error]", param);
+ }
+ register_http_post_files_variable_ex(lbuf, &error_type, http_post_files, 0 TSRMLS_CC);
+
+ /* Add $foo_size */
+ if (is_arr_upload) {
+ snprintf(lbuf, llen, "%s_size[%s]", abuf, array_index);
+ } else {
+ snprintf(lbuf, llen, "%s_size", param);
+ }
+ if (!is_anonymous) {
+ safe_php_register_variable_ex(lbuf, &file_size, NULL, 0 TSRMLS_CC);
+ }
+
+ /* Add $foo[size] */
+ if (is_arr_upload) {
+ snprintf(lbuf, llen, "%s[size][%s]", abuf, array_index);
+ } else {
+ snprintf(lbuf, llen, "%s[size]", param);
+ }
+ register_http_post_files_variable_ex(lbuf, &file_size, http_post_files, 0 TSRMLS_CC);
+ }
+ efree(param);
+ }
+ }
+
+fileupload_done:
+ if (php_rfc1867_callback != NULL) {
+ multipart_event_end event_end;
+
+ event_end.post_bytes_processed = SG(read_post_bytes);
+ php_rfc1867_callback(MULTIPART_EVENT_END, &event_end, &event_extra_data TSRMLS_CC);
+ }
+
+ if (lbuf) efree(lbuf);
+ if (abuf) efree(abuf);
+ if (array_index) efree(array_index);
+ zend_hash_destroy(&PG(rfc1867_protected_variables));
+ zend_llist_destroy(&header);
+ if (mbuff->boundary_next) efree(mbuff->boundary_next);
+ if (mbuff->boundary) efree(mbuff->boundary);
+ if (mbuff->buffer) efree(mbuff->buffer);
+ if (mbuff) efree(mbuff);
+}
+/* }}} */
+
+SAPI_API void php_rfc1867_set_multibyte_callbacks(
+ php_rfc1867_encoding_translation_t encoding_translation,
+ php_rfc1867_get_detect_order_t get_detect_order,
+ php_rfc1867_set_input_encoding_t set_input_encoding,
+ php_rfc1867_getword_t getword,
+ php_rfc1867_getword_conf_t getword_conf,
+ php_rfc1867_basename_t basename) /* {{{ */
+{
+ php_rfc1867_encoding_translation = encoding_translation;
+ php_rfc1867_get_detect_order = get_detect_order;
+ php_rfc1867_set_input_encoding = set_input_encoding;
+ php_rfc1867_getword = getword;
+ php_rfc1867_getword_conf = getword_conf;
+ php_rfc1867_basename = basename;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/rfc1867.h b/main/rfc1867.h
new file mode 100644
index 0000000..8a502c4
--- /dev/null
+++ b/main/rfc1867.h
@@ -0,0 +1,91 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef RFC1867_H
+#define RFC1867_H
+
+#include "SAPI.h"
+
+#define MULTIPART_CONTENT_TYPE "multipart/form-data"
+#define MULTIPART_EVENT_START 0
+#define MULTIPART_EVENT_FORMDATA 1
+#define MULTIPART_EVENT_FILE_START 2
+#define MULTIPART_EVENT_FILE_DATA 3
+#define MULTIPART_EVENT_FILE_END 4
+#define MULTIPART_EVENT_END 5
+
+typedef struct _multipart_event_start {
+ size_t content_length;
+} multipart_event_start;
+
+typedef struct _multipart_event_formdata {
+ size_t post_bytes_processed;
+ char *name;
+ char **value;
+ size_t length;
+ size_t *newlength;
+} multipart_event_formdata;
+
+typedef struct _multipart_event_file_start {
+ size_t post_bytes_processed;
+ char *name;
+ char **filename;
+} multipart_event_file_start;
+
+typedef struct _multipart_event_file_data {
+ size_t post_bytes_processed;
+ off_t offset;
+ char *data;
+ size_t length;
+ size_t *newlength;
+} multipart_event_file_data;
+
+typedef struct _multipart_event_file_end {
+ size_t post_bytes_processed;
+ char *temp_filename;
+ int cancel_upload;
+} multipart_event_file_end;
+
+typedef struct _multipart_event_end {
+ size_t post_bytes_processed;
+} multipart_event_end;
+
+typedef int (*php_rfc1867_encoding_translation_t)(TSRMLS_D);
+typedef void (*php_rfc1867_get_detect_order_t)(const zend_encoding ***list, size_t *list_size TSRMLS_DC);
+typedef void (*php_rfc1867_set_input_encoding_t)(const zend_encoding *encoding TSRMLS_DC);
+typedef char* (*php_rfc1867_getword_t)(const zend_encoding *encoding, char **line, char stop TSRMLS_DC);
+typedef char* (*php_rfc1867_getword_conf_t)(const zend_encoding *encoding, char *str TSRMLS_DC);
+typedef char* (*php_rfc1867_basename_t)(const zend_encoding *encoding, char *str TSRMLS_DC);
+
+SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler);
+
+void destroy_uploaded_files_hash(TSRMLS_D);
+void php_rfc1867_register_constants(TSRMLS_D);
+extern PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC);
+
+SAPI_API void php_rfc1867_set_multibyte_callbacks(
+ php_rfc1867_encoding_translation_t encoding_translation,
+ php_rfc1867_get_detect_order_t get_detect_order,
+ php_rfc1867_set_input_encoding_t set_input_encoding,
+ php_rfc1867_getword_t getword,
+ php_rfc1867_getword_conf_t getword_conf,
+ php_rfc1867_basename_t basename);
+
+#endif /* RFC1867_H */
diff --git a/main/snprintf.c b/main/snprintf.c
new file mode 100644
index 0000000..4514bd6
--- /dev/null
+++ b/main/snprintf.c
@@ -0,0 +1,1316 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#define _GNU_SOURCE
+#include "php.h"
+
+#include <zend_strtod.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#define LCONV_DECIMAL_POINT (*lconv->decimal_point)
+#else
+#define LCONV_DECIMAL_POINT '.'
+#endif
+
+/*
+ * Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+static char * __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad) /* {{{ */
+{
+ register char *s = NULL;
+ char *p, *rve, c;
+ size_t siz;
+
+ if (ndigit < 0) {
+ siz = -ndigit + 1;
+ } else {
+ siz = ndigit + 1;
+ }
+
+ /* __dtoa() doesn't allocate space for 0 so we do it by hand */
+ if (value == 0.0) {
+ *decpt = 1 - fmode; /* 1 for 'e', 0 for 'f' */
+ *sign = 0;
+ if ((rve = s = (char *)malloc(ndigit?siz:2)) == NULL) {
+ return(NULL);
+ }
+ *rve++ = '0';
+ *rve = '\0';
+ if (!ndigit) {
+ return(s);
+ }
+ } else {
+ p = zend_dtoa(value, fmode + 2, ndigit, decpt, sign, &rve);
+ if (*decpt == 9999) {
+ /* Infinity or Nan, convert to inf or nan like printf */
+ *decpt = 0;
+ c = *p;
+ zend_freedtoa(p);
+ return strdup((c == 'I' ? "INF" : "NAN"));
+ }
+ /* Make a local copy and adjust rve to be in terms of s */
+ if (pad && fmode) {
+ siz += *decpt;
+ }
+ if ((s = (char *)malloc(siz+1)) == NULL) {
+ zend_freedtoa(p);
+ return(NULL);
+ }
+ (void) strlcpy(s, p, siz);
+ rve = s + (rve - p);
+ zend_freedtoa(p);
+ }
+
+ /* Add trailing zeros */
+ if (pad) {
+ siz -= rve - s;
+ while (--siz) {
+ *rve++ = '0';
+ }
+ *rve = '\0';
+ }
+
+ return(s);
+}
+/* }}} */
+
+static inline char *php_ecvt(double value, int ndigit, int *decpt, int *sign) /* {{{ */
+{
+ return(__cvt(value, ndigit, decpt, sign, 0, 1));
+}
+/* }}} */
+
+static inline char *php_fcvt(double value, int ndigit, int *decpt, int *sign) /* {{{ */
+{
+ return(__cvt(value, ndigit, decpt, sign, 1, 1));
+}
+/* }}} */
+
+PHPAPI char *php_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf) /* {{{ */
+{
+ char *digits, *dst, *src;
+ int i, decpt, sign;
+
+ digits = zend_dtoa(value, 2, ndigit, &decpt, &sign, NULL);
+ if (decpt == 9999) {
+ /*
+ * Infinity or NaN, convert to inf or nan with sign.
+ * We assume the buffer is at least ndigit long.
+ */
+ snprintf(buf, ndigit + 1, "%s%s", (sign && *digits == 'I') ? "-" : "", *digits == 'I' ? "INF" : "NAN");
+ zend_freedtoa(digits);
+ return (buf);
+ }
+
+ dst = buf;
+ if (sign) {
+ *dst++ = '-';
+ }
+
+ if ((decpt >= 0 && decpt > ndigit) || decpt < -3) { /* use E-style */
+ /* exponential format (e.g. 1.2345e+13) */
+ if (--decpt < 0) {
+ sign = 1;
+ decpt = -decpt;
+ } else {
+ sign = 0;
+ }
+ src = digits;
+ *dst++ = *src++;
+ *dst++ = dec_point;
+ if (*src == '\0') {
+ *dst++ = '0';
+ } else {
+ do {
+ *dst++ = *src++;
+ } while (*src != '\0');
+ }
+ *dst++ = exponent;
+ if (sign) {
+ *dst++ = '-';
+ } else {
+ *dst++ = '+';
+ }
+ if (decpt < 10) {
+ *dst++ = '0' + decpt;
+ *dst = '\0';
+ } else {
+ /* XXX - optimize */
+ for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
+ continue;
+ dst[i + 1] = '\0';
+ while (decpt != 0) {
+ dst[i--] = '0' + decpt % 10;
+ decpt /= 10;
+ }
+ }
+ } else if (decpt < 0) {
+ /* standard format 0. */
+ *dst++ = '0'; /* zero before decimal point */
+ *dst++ = dec_point;
+ do {
+ *dst++ = '0';
+ } while (++decpt < 0);
+ src = digits;
+ while (*src != '\0') {
+ *dst++ = *src++;
+ }
+ *dst = '\0';
+ } else {
+ /* standard format */
+ for (i = 0, src = digits; i < decpt; i++) {
+ if (*src != '\0') {
+ *dst++ = *src++;
+ } else {
+ *dst++ = '0';
+ }
+ }
+ if (*src != '\0') {
+ if (src == digits) {
+ *dst++ = '0'; /* zero before decimal point */
+ }
+ *dst++ = dec_point;
+ for (i = decpt; digits[i] != '\0'; i++) {
+ *dst++ = digits[i];
+ }
+ }
+ *dst = '\0';
+ }
+ zend_freedtoa(digits);
+ return (buf);
+}
+/* }}} */
+
+/* {{{ Apache license */
+/* ====================================================================
+ * Copyright (c) 1995-1998 The Apache Group. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ * This code is based on, and used with the permission of, the
+ * SIO stdio-replacement strx_* functions by Panos Tsirigotis
+ * <panos@alumni.cs.colorado.edu> for xinetd.
+ */
+/* }}} */
+
+#define FALSE 0
+#define TRUE 1
+#define NUL '\0'
+#define INT_NULL ((int *)0)
+
+#define S_NULL "(null)"
+#define S_NULL_LEN 6
+
+#define FLOAT_DIGITS 6
+#define EXPONENT_LENGTH 10
+
+
+/*
+ * Convert num to its decimal format.
+ * Return value:
+ * - a pointer to a string containing the number (no sign)
+ * - len contains the length of the string
+ * - is_negative is set to TRUE or FALSE depending on the sign
+ * of the number (always set to FALSE if is_unsigned is TRUE)
+ *
+ * The caller provides a buffer for the string: that is the buf_end argument
+ * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
+ * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
+ */
+/* char * ap_php_conv_10() {{{ */
+char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned,
+ register bool_int * is_negative, char *buf_end, register int *len)
+{
+ register char *p = buf_end;
+ register u_wide_int magnitude;
+
+ if (is_unsigned) {
+ magnitude = (u_wide_int) num;
+ *is_negative = FALSE;
+ } else {
+ *is_negative = (num < 0);
+
+ /*
+ * On a 2's complement machine, negating the most negative integer
+ * results in a number that cannot be represented as a signed integer.
+ * Here is what we do to obtain the number's magnitude:
+ * a. add 1 to the number
+ * b. negate it (becomes positive)
+ * c. convert it to unsigned
+ * d. add 1
+ */
+ if (*is_negative) {
+ wide_int t = num + 1;
+ magnitude = ((u_wide_int) - t) + 1;
+ } else {
+ magnitude = (u_wide_int) num;
+ }
+ }
+
+ /*
+ * We use a do-while loop so that we write at least 1 digit
+ */
+ do {
+ register u_wide_int new_magnitude = magnitude / 10;
+
+ *--p = (char)(magnitude - new_magnitude * 10 + '0');
+ magnitude = new_magnitude;
+ }
+ while (magnitude);
+
+ *len = buf_end - p;
+ return (p);
+}
+/* }}} */
+
+/* If you change this value then also change bug24640.phpt.
+ * Also NDIG must be reasonable smaller than NUM_BUF_SIZE.
+ */
+#define NDIG 320
+
+
+/*
+ * Convert a floating point number to a string formats 'f', 'e' or 'E'.
+ * The result is placed in buf, and len denotes the length of the string
+ * The sign is returned in the is_negative argument (and is not placed
+ * in buf).
+ */
+/* PHPAPI char * php_conv_fp() {{{ */
+PHPAPI char * php_conv_fp(register char format, register double num,
+ boolean_e add_dp, int precision, char dec_point, bool_int * is_negative, char *buf, int *len)
+{
+ register char *s = buf;
+ register char *p, *p_orig;
+ int decimal_point;
+
+ if (precision >= NDIG - 1) {
+ precision = NDIG - 2;
+ }
+
+ if (format == 'F') {
+ p_orig = p = php_fcvt(num, precision, &decimal_point, is_negative);
+ } else { /* either e or E format */
+ p_orig = p = php_ecvt(num, precision + 1, &decimal_point, is_negative);
+ }
+
+ /*
+ * Check for Infinity and NaN
+ */
+ if (isalpha((int)*p)) {
+ *len = strlen(p);
+ memcpy(buf, p, *len + 1);
+ *is_negative = FALSE;
+ free(p_orig);
+ return (buf);
+ }
+ if (format == 'F') {
+ if (decimal_point <= 0) {
+ if (num != 0 || precision > 0) {
+ *s++ = '0';
+ if (precision > 0) {
+ *s++ = dec_point;
+ while (decimal_point++ < 0) {
+ *s++ = '0';
+ }
+ } else if (add_dp) {
+ *s++ = dec_point;
+ }
+ }
+ } else {
+ int addz = decimal_point >= NDIG ? decimal_point - NDIG + 1 : 0;
+ decimal_point -= addz;
+ while (decimal_point-- > 0) {
+ *s++ = *p++;
+ }
+ while (addz-- > 0) {
+ *s++ = '0';
+ }
+ if (precision > 0 || add_dp) {
+ *s++ = dec_point;
+ }
+ }
+ } else {
+ *s++ = *p++;
+ if (precision > 0 || add_dp) {
+ *s++ = '.';
+ }
+ }
+
+ /*
+ * copy the rest of p, the NUL is NOT copied
+ */
+ while (*p) {
+ *s++ = *p++;
+ }
+
+ if (format != 'F') {
+ char temp[EXPONENT_LENGTH]; /* for exponent conversion */
+ int t_len;
+ bool_int exponent_is_negative;
+
+ *s++ = format; /* either e or E */
+ decimal_point--;
+ if (decimal_point != 0) {
+ p = ap_php_conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, &temp[EXPONENT_LENGTH], &t_len);
+ *s++ = exponent_is_negative ? '-' : '+';
+
+ /*
+ * Make sure the exponent has at least 2 digits
+ */
+ while (t_len--) {
+ *s++ = *p++;
+ }
+ } else {
+ *s++ = '+';
+ *s++ = '0';
+ }
+ }
+ *len = s - buf;
+ free(p_orig);
+ return (buf);
+}
+/* }}} */
+
+/*
+ * Convert num to a base X number where X is a power of 2. nbits determines X.
+ * For example, if nbits is 3, we do base 8 conversion
+ * Return value:
+ * a pointer to a string containing the number
+ *
+ * The caller provides a buffer for the string: that is the buf_end argument
+ * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
+ * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
+ */
+char * ap_php_conv_p2(register u_wide_int num, register int nbits, char format, char *buf_end, register int *len) /* {{{ */
+{
+ register int mask = (1 << nbits) - 1;
+ register char *p = buf_end;
+ static char low_digits[] = "0123456789abcdef";
+ static char upper_digits[] = "0123456789ABCDEF";
+ register char *digits = (format == 'X') ? upper_digits : low_digits;
+
+ do {
+ *--p = digits[num & mask];
+ num >>= nbits;
+ }
+ while (num);
+
+ *len = buf_end - p;
+ return (p);
+}
+/* }}} */
+
+/*
+ * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
+ *
+ * XXX: this is a magic number; do not decrease it
+ * Emax = 1023
+ * NDIG = 320
+ * NUM_BUF_SIZE >= strlen("-") + Emax + strlrn(".") + NDIG + strlen("E+1023") + 1;
+ */
+#define NUM_BUF_SIZE 2048
+
+
+/*
+ * Descriptor for buffer area
+ */
+struct buf_area {
+ char *buf_end;
+ char *nextb; /* pointer to next byte to read/write */
+};
+
+typedef struct buf_area buffy;
+
+/*
+ * The INS_CHAR macro inserts a character in the buffer and writes
+ * the buffer back to disk if necessary
+ * It uses the char pointers sp and bep:
+ * sp points to the next available character in the buffer
+ * bep points to the end-of-buffer+1
+ * While using this macro, note that the nextb pointer is NOT updated.
+ *
+ * NOTE: Evaluation of the c argument should not have any side-effects
+ */
+#define INS_CHAR(c, sp, bep, cc) \
+ { \
+ if (sp < bep) \
+ { \
+ *sp++ = c; \
+ } \
+ cc++; \
+ }
+
+#define NUM( c ) ( c - '0' )
+
+#define STR_TO_DEC( str, num ) \
+ num = NUM( *str++ ) ; \
+ while ( isdigit((int)*str ) ) \
+ { \
+ num *= 10 ; \
+ num += NUM( *str++ ) ; \
+ }
+
+/*
+ * This macro does zero padding so that the precision
+ * requirement is satisfied. The padding is done by
+ * adding '0's to the left of the string that is going
+ * to be printed.
+ */
+#define FIX_PRECISION( adjust, precision, s, s_len ) \
+ if ( adjust ) \
+ while ( s_len < precision ) \
+ { \
+ *--s = '0' ; \
+ s_len++ ; \
+ }
+
+/*
+ * Macro that does padding. The padding is done by printing
+ * the character ch.
+ */
+#define PAD( width, len, ch ) do \
+ { \
+ INS_CHAR( ch, sp, bep, cc ) ; \
+ width-- ; \
+ } \
+ while ( width > len )
+
+/*
+ * Prefix the character ch to the string str
+ * Increase length
+ * Set the has_prefix flag
+ */
+#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES
+
+
+/*
+ * Do format conversion placing the output in buffer
+ */
+static int format_converter(register buffy * odp, const char *fmt, va_list ap) /* {{{ */
+{
+ char *sp;
+ char *bep;
+ int cc = 0;
+ int i;
+
+ char *s = NULL;
+ int s_len, free_zcopy;
+ zval *zvp, zcopy;
+
+ int min_width = 0;
+ int precision = 0;
+ enum {
+ LEFT, RIGHT
+ } adjust;
+ char pad_char;
+ char prefix_char;
+
+ double fp_num;
+ wide_int i_num = (wide_int) 0;
+ u_wide_int ui_num;
+
+ char num_buf[NUM_BUF_SIZE];
+ char char_buf[2]; /* for printing %% and %<unknown> */
+
+#ifdef HAVE_LOCALE_H
+ struct lconv *lconv = NULL;
+#endif
+
+ /*
+ * Flag variables
+ */
+ length_modifier_e modifier;
+ boolean_e alternate_form;
+ boolean_e print_sign;
+ boolean_e print_blank;
+ boolean_e adjust_precision;
+ boolean_e adjust_width;
+ bool_int is_negative;
+
+ sp = odp->nextb;
+ bep = odp->buf_end;
+
+ while (*fmt) {
+ if (*fmt != '%') {
+ INS_CHAR(*fmt, sp, bep, cc);
+ } else {
+ /*
+ * Default variable settings
+ */
+ adjust = RIGHT;
+ alternate_form = print_sign = print_blank = NO;
+ pad_char = ' ';
+ prefix_char = NUL;
+ free_zcopy = 0;
+
+ fmt++;
+
+ /*
+ * Try to avoid checking for flags, width or precision
+ */
+ if (isascii((int)*fmt) && !islower((int)*fmt)) {
+ /*
+ * Recognize flags: -, #, BLANK, +
+ */
+ for (;; fmt++) {
+ if (*fmt == '-')
+ adjust = LEFT;
+ else if (*fmt == '+')
+ print_sign = YES;
+ else if (*fmt == '#')
+ alternate_form = YES;
+ else if (*fmt == ' ')
+ print_blank = YES;
+ else if (*fmt == '0')
+ pad_char = '0';
+ else
+ break;
+ }
+
+ /*
+ * Check if a width was specified
+ */
+ if (isdigit((int)*fmt)) {
+ STR_TO_DEC(fmt, min_width);
+ adjust_width = YES;
+ } else if (*fmt == '*') {
+ min_width = va_arg(ap, int);
+ fmt++;
+ adjust_width = YES;
+ if (min_width < 0) {
+ adjust = LEFT;
+ min_width = -min_width;
+ }
+ } else
+ adjust_width = NO;
+
+ /*
+ * Check if a precision was specified
+ */
+ if (*fmt == '.') {
+ adjust_precision = YES;
+ fmt++;
+ if (isdigit((int)*fmt)) {
+ STR_TO_DEC(fmt, precision);
+ } else if (*fmt == '*') {
+ precision = va_arg(ap, int);
+ fmt++;
+ if (precision < 0)
+ precision = 0;
+ } else
+ precision = 0;
+
+ if (precision > FORMAT_CONV_MAX_PRECISION) {
+ precision = FORMAT_CONV_MAX_PRECISION;
+ }
+ } else
+ adjust_precision = NO;
+ } else
+ adjust_precision = adjust_width = NO;
+
+ /*
+ * Modifier check
+ */
+ switch (*fmt) {
+ case 'L':
+ fmt++;
+ modifier = LM_LONG_DOUBLE;
+ break;
+ case 'I':
+ fmt++;
+#if SIZEOF_LONG_LONG
+ if (*fmt == '6' && *(fmt+1) == '4') {
+ fmt += 2;
+ modifier = LM_LONG_LONG;
+ } else
+#endif
+ if (*fmt == '3' && *(fmt+1) == '2') {
+ fmt += 2;
+ modifier = LM_LONG;
+ } else {
+#ifdef _WIN64
+ modifier = LM_LONG_LONG;
+#else
+ modifier = LM_LONG;
+#endif
+ }
+ break;
+ case 'l':
+ fmt++;
+#if SIZEOF_LONG_LONG
+ if (*fmt == 'l') {
+ fmt++;
+ modifier = LM_LONG_LONG;
+ } else
+#endif
+ modifier = LM_LONG;
+ break;
+ case 'z':
+ fmt++;
+ modifier = LM_SIZE_T;
+ break;
+ case 'j':
+ fmt++;
+#if SIZEOF_INTMAX_T
+ modifier = LM_INTMAX_T;
+#else
+ modifier = LM_SIZE_T;
+#endif
+ break;
+ case 't':
+ fmt++;
+#if SIZEOF_PTRDIFF_T
+ modifier = LM_PTRDIFF_T;
+#else
+ modifier = LM_SIZE_T;
+#endif
+ break;
+ case 'h':
+ fmt++;
+ if (*fmt == 'h') {
+ fmt++;
+ }
+ /* these are promoted to int, so no break */
+ default:
+ modifier = LM_STD;
+ break;
+ }
+
+ /*
+ * Argument extraction and printing.
+ * First we determine the argument type.
+ * Then, we convert the argument to a string.
+ * On exit from the switch, s points to the string that
+ * must be printed, s_len has the length of the string
+ * The precision requirements, if any, are reflected in s_len.
+ *
+ * NOTE: pad_char may be set to '0' because of the 0 flag.
+ * It is reset to ' ' by non-numeric formats
+ */
+ switch (*fmt) {
+ case 'Z':
+ zvp = (zval*) va_arg(ap, zval*);
+ zend_make_printable_zval(zvp, &zcopy, &free_zcopy);
+ if (free_zcopy) {
+ zvp = &zcopy;
+ }
+ s_len = Z_STRLEN_P(zvp);
+ s = Z_STRVAL_P(zvp);
+ if (adjust_precision && precision < s_len) {
+ s_len = precision;
+ }
+ break;
+ case 'u':
+ switch(modifier) {
+ default:
+ i_num = (wide_int) va_arg(ap, unsigned int);
+ break;
+ case LM_LONG_DOUBLE:
+ goto fmt_error;
+ case LM_LONG:
+ i_num = (wide_int) va_arg(ap, unsigned long int);
+ break;
+ case LM_SIZE_T:
+ i_num = (wide_int) va_arg(ap, size_t);
+ break;
+#if SIZEOF_LONG_LONG
+ case LM_LONG_LONG:
+ i_num = (wide_int) va_arg(ap, u_wide_int);
+ break;
+#endif
+#if SIZEOF_INTMAX_T
+ case LM_INTMAX_T:
+ i_num = (wide_int) va_arg(ap, uintmax_t);
+ break;
+#endif
+#if SIZEOF_PTRDIFF_T
+ case LM_PTRDIFF_T:
+ i_num = (wide_int) va_arg(ap, ptrdiff_t);
+ break;
+#endif
+ }
+ /*
+ * The rest also applies to other integer formats, so fall
+ * into that case.
+ */
+ case 'd':
+ case 'i':
+ /*
+ * Get the arg if we haven't already.
+ */
+ if ((*fmt) != 'u') {
+ switch(modifier) {
+ default:
+ i_num = (wide_int) va_arg(ap, int);
+ break;
+ case LM_LONG_DOUBLE:
+ goto fmt_error;
+ case LM_LONG:
+ i_num = (wide_int) va_arg(ap, long int);
+ break;
+ case LM_SIZE_T:
+#if SIZEOF_SSIZE_T
+ i_num = (wide_int) va_arg(ap, ssize_t);
+#else
+ i_num = (wide_int) va_arg(ap, size_t);
+#endif
+ break;
+#if SIZEOF_LONG_LONG
+ case LM_LONG_LONG:
+ i_num = (wide_int) va_arg(ap, wide_int);
+ break;
+#endif
+#if SIZEOF_INTMAX_T
+ case LM_INTMAX_T:
+ i_num = (wide_int) va_arg(ap, intmax_t);
+ break;
+#endif
+#if SIZEOF_PTRDIFF_T
+ case LM_PTRDIFF_T:
+ i_num = (wide_int) va_arg(ap, ptrdiff_t);
+ break;
+#endif
+ }
+ }
+ s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
+ &num_buf[NUM_BUF_SIZE], &s_len);
+ FIX_PRECISION(adjust_precision, precision, s, s_len);
+
+ if (*fmt != 'u') {
+ if (is_negative) {
+ prefix_char = '-';
+ } else if (print_sign) {
+ prefix_char = '+';
+ } else if (print_blank) {
+ prefix_char = ' ';
+ }
+ }
+ break;
+
+
+ case 'o':
+ switch(modifier) {
+ default:
+ ui_num = (u_wide_int) va_arg(ap, unsigned int);
+ break;
+ case LM_LONG_DOUBLE:
+ goto fmt_error;
+ case LM_LONG:
+ ui_num = (u_wide_int) va_arg(ap, unsigned long int);
+ break;
+ case LM_SIZE_T:
+ ui_num = (u_wide_int) va_arg(ap, size_t);
+ break;
+#if SIZEOF_LONG_LONG
+ case LM_LONG_LONG:
+ ui_num = (u_wide_int) va_arg(ap, u_wide_int);
+ break;
+#endif
+#if SIZEOF_INTMAX_T
+ case LM_INTMAX_T:
+ ui_num = (u_wide_int) va_arg(ap, uintmax_t);
+ break;
+#endif
+#if SIZEOF_PTRDIFF_T
+ case LM_PTRDIFF_T:
+ ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
+ break;
+#endif
+ }
+ s = ap_php_conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
+ FIX_PRECISION(adjust_precision, precision, s, s_len);
+ if (alternate_form && *s != '0') {
+ *--s = '0';
+ s_len++;
+ }
+ break;
+
+
+ case 'x':
+ case 'X':
+ switch(modifier) {
+ default:
+ ui_num = (u_wide_int) va_arg(ap, unsigned int);
+ break;
+ case LM_LONG_DOUBLE:
+ goto fmt_error;
+ case LM_LONG:
+ ui_num = (u_wide_int) va_arg(ap, unsigned long int);
+ break;
+ case LM_SIZE_T:
+ ui_num = (u_wide_int) va_arg(ap, size_t);
+ break;
+#if SIZEOF_LONG_LONG
+ case LM_LONG_LONG:
+ ui_num = (u_wide_int) va_arg(ap, u_wide_int);
+ break;
+#endif
+#if SIZEOF_INTMAX_T
+ case LM_INTMAX_T:
+ ui_num = (u_wide_int) va_arg(ap, uintmax_t);
+ break;
+#endif
+#if SIZEOF_PTRDIFF_T
+ case LM_PTRDIFF_T:
+ ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
+ break;
+#endif
+ }
+ s = ap_php_conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
+ FIX_PRECISION(adjust_precision, precision, s, s_len);
+ if (alternate_form && i_num != 0) {
+ *--s = *fmt; /* 'x' or 'X' */
+ *--s = '0';
+ s_len += 2;
+ }
+ break;
+
+
+ case 's':
+ case 'v':
+ s = va_arg(ap, char *);
+ if (s != NULL) {
+ s_len = strlen(s);
+ if (adjust_precision && precision < s_len) {
+ s_len = precision;
+ }
+ } else {
+ s = S_NULL;
+ s_len = S_NULL_LEN;
+ }
+ pad_char = ' ';
+ break;
+
+
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ switch(modifier) {
+ case LM_LONG_DOUBLE:
+ fp_num = (double) va_arg(ap, long double);
+ break;
+ case LM_STD:
+ fp_num = va_arg(ap, double);
+ break;
+ default:
+ goto fmt_error;
+ }
+
+ if (zend_isnan(fp_num)) {
+ s = "NAN";
+ s_len = 3;
+ } else if (zend_isinf(fp_num)) {
+ s = "INF";
+ s_len = 3;
+ } else {
+#ifdef HAVE_LOCALE_H
+ if (!lconv) {
+ lconv = localeconv();
+ }
+#endif
+ s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
+ (adjust_precision == NO) ? FLOAT_DIGITS : precision,
+ (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
+ &is_negative, &num_buf[1], &s_len);
+ if (is_negative)
+ prefix_char = '-';
+ else if (print_sign)
+ prefix_char = '+';
+ else if (print_blank)
+ prefix_char = ' ';
+ }
+ break;
+
+
+ case 'g':
+ case 'k':
+ case 'G':
+ case 'H':
+ switch(modifier) {
+ case LM_LONG_DOUBLE:
+ fp_num = (double) va_arg(ap, long double);
+ break;
+ case LM_STD:
+ fp_num = va_arg(ap, double);
+ break;
+ default:
+ goto fmt_error;
+ }
+
+ if (zend_isnan(fp_num)) {
+ s = "NAN";
+ s_len = 3;
+ break;
+ } else if (zend_isinf(fp_num)) {
+ if (fp_num > 0) {
+ s = "INF";
+ s_len = 3;
+ } else {
+ s = "-INF";
+ s_len = 4;
+ }
+ break;
+ }
+
+ if (adjust_precision == NO) {
+ precision = FLOAT_DIGITS;
+ } else if (precision == 0) {
+ precision = 1;
+ }
+ /*
+ * * We use &num_buf[ 1 ], so that we have room for the sign
+ */
+#ifdef HAVE_LOCALE_H
+ if (!lconv) {
+ lconv = localeconv();
+ }
+#endif
+ s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
+ if (*s == '-') {
+ prefix_char = *s++;
+ } else if (print_sign) {
+ prefix_char = '+';
+ } else if (print_blank) {
+ prefix_char = ' ';
+ }
+
+ s_len = strlen(s);
+
+ if (alternate_form && (strchr(s, '.')) == NULL) {
+ s[s_len++] = '.';
+ }
+ break;
+
+
+ case 'c':
+ char_buf[0] = (char) (va_arg(ap, int));
+ s = &char_buf[0];
+ s_len = 1;
+ pad_char = ' ';
+ break;
+
+
+ case '%':
+ char_buf[0] = '%';
+ s = &char_buf[0];
+ s_len = 1;
+ pad_char = ' ';
+ break;
+
+
+ case 'n':
+ *(va_arg(ap, int *)) = cc;
+ goto skip_output;
+
+ /*
+ * Always extract the argument as a "char *" pointer. We
+ * should be using "void *" but there are still machines
+ * that don't understand it.
+ * If the pointer size is equal to the size of an unsigned
+ * integer we convert the pointer to a hex number, otherwise
+ * we print "%p" to indicate that we don't handle "%p".
+ */
+ case 'p':
+ if (sizeof(char *) <= sizeof(u_wide_int)) {
+ ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
+ s = ap_php_conv_p2(ui_num, 4, 'x',
+ &num_buf[NUM_BUF_SIZE], &s_len);
+ if (ui_num != 0) {
+ *--s = 'x';
+ *--s = '0';
+ s_len += 2;
+ }
+ } else {
+ s = "%p";
+ s_len = 2;
+ }
+ pad_char = ' ';
+ break;
+
+
+ case NUL:
+ /*
+ * The last character of the format string was %.
+ * We ignore it.
+ */
+ continue;
+
+
+fmt_error:
+ php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
+ /*
+ * The default case is for unrecognized %'s.
+ * We print %<char> to help the user identify what
+ * option is not understood.
+ * This is also useful in case the user wants to pass
+ * the output of format_converter to another function
+ * that understands some other %<char> (like syslog).
+ * Note that we can't point s inside fmt because the
+ * unknown <char> could be preceded by width etc.
+ */
+ default:
+ char_buf[0] = '%';
+ char_buf[1] = *fmt;
+ s = char_buf;
+ s_len = 2;
+ pad_char = ' ';
+ break;
+ }
+
+ if (prefix_char != NUL) {
+ *--s = prefix_char;
+ s_len++;
+ }
+ if (adjust_width && adjust == RIGHT && min_width > s_len) {
+ if (pad_char == '0' && prefix_char != NUL) {
+ INS_CHAR(*s, sp, bep, cc)
+ s++;
+ s_len--;
+ min_width--;
+ }
+ PAD(min_width, s_len, pad_char);
+ }
+ /*
+ * Print the string s.
+ */
+ for (i = s_len; i != 0; i--) {
+ INS_CHAR(*s, sp, bep, cc);
+ s++;
+ }
+
+ if (adjust_width && adjust == LEFT && min_width > s_len)
+ PAD(min_width, s_len, pad_char);
+ if (free_zcopy) {
+ zval_dtor(&zcopy);
+ }
+ }
+skip_output:
+ fmt++;
+ }
+ odp->nextb = sp;
+ return (cc);
+}
+/* }}} */
+
+/*
+ * This is the general purpose conversion function.
+ */
+static void strx_printv(int *ccp, char *buf, size_t len, const char *format, va_list ap) /* {{{ */
+{
+ buffy od;
+ int cc;
+
+ /*
+ * First initialize the descriptor
+ * Notice that if no length is given, we initialize buf_end to the
+ * highest possible address.
+ */
+ if (len == 0) {
+ od.buf_end = (char *) ~0;
+ od.nextb = (char *) ~0;
+ } else {
+ od.buf_end = &buf[len-1];
+ od.nextb = buf;
+ }
+
+ /*
+ * Do the conversion
+ */
+ cc = format_converter(&od, format, ap);
+ if (len != 0 && od.nextb <= od.buf_end) {
+ *(od.nextb) = '\0';
+ }
+ if (ccp) {
+ *ccp = cc;
+ }
+}
+/* }}} */
+
+PHPAPI int ap_php_slprintf(char *buf, size_t len, const char *format,...) /* {{{ */
+{
+ unsigned int cc;
+ va_list ap;
+
+ va_start(ap, format);
+ strx_printv(&cc, buf, len, format, ap);
+ va_end(ap);
+ if (cc >= len) {
+ cc = len -1;
+ buf[cc] = '\0';
+ }
+ return cc;
+}
+/* }}} */
+
+PHPAPI int ap_php_vslprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
+{
+ unsigned int cc;
+
+ strx_printv(&cc, buf, len, format, ap);
+ if (cc >= len) {
+ cc = len -1;
+ buf[cc] = '\0';
+ }
+ return cc;
+}
+/* }}} */
+
+PHPAPI int ap_php_snprintf(char *buf, size_t len, const char *format,...) /* {{{ */
+{
+ int cc;
+ va_list ap;
+
+ va_start(ap, format);
+ strx_printv(&cc, buf, len, format, ap);
+ va_end(ap);
+ return (cc);
+}
+/* }}} */
+
+PHPAPI int ap_php_vsnprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
+{
+ int cc;
+
+ strx_printv(&cc, buf, len, format, ap);
+ return (cc);
+}
+/* }}} */
+
+PHPAPI int ap_php_vasprintf(char **buf, const char *format, va_list ap) /* {{{ */
+{
+ va_list ap2;
+ int cc;
+
+ va_copy(ap2, ap);
+ cc = ap_php_vsnprintf(NULL, 0, format, ap2);
+ va_end(ap2);
+
+ *buf = NULL;
+
+ if (cc >= 0) {
+ if ((*buf = malloc(++cc)) != NULL) {
+ if ((cc = ap_php_vsnprintf(*buf, cc, format, ap)) < 0) {
+ free(*buf);
+ *buf = NULL;
+ }
+ }
+ }
+
+ return cc;
+}
+/* }}} */
+
+PHPAPI int ap_php_asprintf(char **buf, const char *format, ...) /* {{{ */
+{
+ int cc;
+ va_list ap;
+
+ va_start(ap, format);
+ cc = vasprintf(buf, format, ap);
+ va_end(ap);
+ return cc;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/snprintf.h b/main/snprintf.h
new file mode 100644
index 0000000..de03542
--- /dev/null
+++ b/main/snprintf.h
@@ -0,0 +1,179 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Stig Sæther Bakken <ssb@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/*
+
+Comparing: sprintf, snprintf, slprintf, spprintf
+
+sprintf offers the ability to make a lot of failures since it does not know
+ the size of the buffer it uses. Therefore usage of sprintf often
+ results in possible entries for buffer overrun attacks. So please
+ use this version only if you are sure the call is safe. sprintf
+ allways terminstes the buffer it writes to.
+
+snprintf knows the buffers size and will not write behind it. But you will
+ have to use either a static buffer or allocate a dynamic buffer
+ before beeing able to call the function. In other words you must
+ be sure that you really know the maximum size of the buffer required.
+ A bad thing is having a big maximum while in most cases you would
+ only need a small buffer. If the size of the resulting string is
+ longer or equal to the buffer size than the buffer is not terminated.
+ The function also returns the number of chars not including the
+ terminating \0 that were needed to fully comply to the print request.
+
+slprintf same as snprintf with the difference that it actually returns the
+ length printed not including the terminating \0.
+
+spprintf is the dynamical version of snprintf. It allocates the buffer in size
+ as needed and allows a maximum setting as snprintf (turn this feature
+ off by setting max_len to 0). spprintf is a little bit slower than
+ snprintf and offers possible memory leakes if you miss freeing the
+ buffer allocated by the function. Therfore this function should be
+ used where either no maximum is known or the maximum is much bigger
+ than normal size required. spprintf allways terminates the buffer.
+
+Example:
+
+ #define MAX 1024 | #define MAX 1024 | #define MAX 1024
+ char buffer[MAX] | char buffer[MAX] | char *buffer;
+ | |
+ | | // No need to initialize buffer:
+ | | // spprintf ignores value of buffer
+ sprintf(buffer, "test"); | snprintf(buffer, MAX, "test"); | spprintf(&buffer, MAX, "text");
+ | | if (!buffer)
+ | | return OUT_OF_MEMORY
+ // sprintf allways terminates | // manual termination of | // spprintf allays terminates buffer
+ // buffer | // buffer *IS* required |
+ | buffer[MAX-1] = 0; |
+ action_with_buffer(buffer); | action_with_buffer(buffer); | action_with_buffer(buffer);
+ | | efree(buffer);
+*/
+
+#ifndef SNPRINTF_H
+#define SNPRINTF_H
+
+typedef int bool_int;
+
+typedef enum {
+ NO = 0, YES = 1
+} boolean_e;
+
+
+BEGIN_EXTERN_C()
+PHPAPI int ap_php_slprintf(char *buf, size_t len, const char *format,...);
+PHPAPI int ap_php_vslprintf(char *buf, size_t len, const char *format, va_list ap);
+PHPAPI int ap_php_snprintf(char *, size_t, const char *, ...);
+PHPAPI int ap_php_vsnprintf(char *, size_t, const char *, va_list ap);
+PHPAPI int ap_php_vasprintf(char **buf, const char *format, va_list ap);
+PHPAPI int ap_php_asprintf(char **buf, const char *format, ...);
+PHPAPI int php_sprintf (char* s, const char* format, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
+PHPAPI char * php_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf);
+PHPAPI char * php_conv_fp(register char format, register double num,
+ boolean_e add_dp, int precision, char dec_point, bool_int * is_negative, char *buf, int *len);
+
+END_EXTERN_C()
+
+#ifdef slprintf
+#undef slprintf
+#endif
+#define slprintf ap_php_slprintf
+
+#ifdef vslprintf
+#undef vslprintf
+#endif
+#define vslprintf ap_php_vslprintf
+
+#ifdef snprintf
+#undef snprintf
+#endif
+#define snprintf ap_php_snprintf
+
+#ifdef vsnprintf
+#undef vsnprintf
+#endif
+#define vsnprintf ap_php_vsnprintf
+
+#ifndef HAVE_VASPRINTF
+#define vasprintf ap_php_vasprintf
+#endif
+
+#ifndef HAVE_ASPRINTF
+#define asprintf ap_php_asprintf
+#endif
+
+#ifdef sprintf
+#undef sprintf
+#endif
+#define sprintf php_sprintf
+
+typedef enum {
+ LM_STD = 0,
+#if SIZEOF_INTMAX_T
+ LM_INTMAX_T,
+#endif
+#if SIZEOF_PTRDIFF_T
+ LM_PTRDIFF_T,
+#endif
+#if SIZEOF_LONG_LONG
+ LM_LONG_LONG,
+#endif
+ LM_SIZE_T,
+ LM_LONG,
+ LM_LONG_DOUBLE
+} length_modifier_e;
+
+#ifdef PHP_WIN32
+# define WIDE_INT __int64
+#elif SIZEOF_LONG_LONG_INT
+# define WIDE_INT long long int
+#elif SIZEOF_LONG_LONG
+# define WIDE_INT long long
+#else
+# define WIDE_INT long
+#endif
+typedef WIDE_INT wide_int;
+typedef unsigned WIDE_INT u_wide_int;
+
+extern char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned,
+ register bool_int * is_negative, char *buf_end, register int *len);
+
+extern char * ap_php_conv_p2(register u_wide_int num, register int nbits,
+ char format, char *buf_end, register int *len);
+
+/* The maximum precision that's allowed for float conversion. Does not include
+ * decimal separator, exponent, sign, terminator. Currently does not affect
+ * the modes e/f, only g/k/H, as those have a different limit enforced at
+ * another level (see NDIG in php_conv_fp()).
+ * Applies to the formatting functions of both spprintf.c and snprintf.c, which
+ * use equally sized buffers of MAX_BUF_SIZE = 512 to hold the result of the
+ * call to php_gcvt().
+ * This should be reasonably smaller than MAX_BUF_SIZE (I think MAX_BUF_SIZE - 9
+ * should be enough, but let's give some more space) */
+#define FORMAT_CONV_MAX_PRECISION 500
+
+#endif /* SNPRINTF_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/main/spprintf.c b/main/spprintf.c
new file mode 100644
index 0000000..596e1ef
--- /dev/null
+++ b/main/spprintf.c
@@ -0,0 +1,831 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/* This is the spprintf implementation.
+ * It has emerged from apache snprintf. See original header:
+ */
+
+/* ====================================================================
+ * Copyright (c) 1995-1998 The Apache Group. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ * This code is based on, and used with the permission of, the
+ * SIO stdio-replacement strx_* functions by Panos Tsirigotis
+ * <panos@alumni.cs.colorado.edu> for xinetd.
+ */
+#define _GNU_SOURCE
+#include "php.h"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#define LCONV_DECIMAL_POINT (*lconv->decimal_point)
+#else
+#define LCONV_DECIMAL_POINT '.'
+#endif
+
+#include "snprintf.h"
+
+#define FALSE 0
+#define TRUE 1
+#define NUL '\0'
+#define INT_NULL ((int *)0)
+
+#define S_NULL "(null)"
+#define S_NULL_LEN 6
+
+#define FLOAT_DIGITS 6
+#define EXPONENT_LENGTH 10
+
+#include "ext/standard/php_smart_str.h"
+
+/* {{{ macros */
+
+/*
+ * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
+ *
+ * XXX: this is a magic number; do not decrease it
+ * Emax = 1023
+ * NDIG = 320
+ * NUM_BUF_SIZE >= strlen("-") + Emax + strlrn(".") + NDIG + strlen("E+1023") + 1;
+ */
+#define NUM_BUF_SIZE 2048
+
+/*
+ * The INS_CHAR macro inserts a character in the buffer.
+ *
+ * NOTE: Evaluation of the ch argument should not have any side-effects
+ */
+#define INS_CHAR_NR(xbuf, ch) do { \
+ smart_str_appendc(xbuf, ch); \
+} while (0)
+
+#define INS_STRING(xbuf, s, slen) do { \
+ smart_str_appendl(xbuf, s, slen); \
+} while (0)
+
+#define INS_CHAR(xbuf, ch) \
+ INS_CHAR_NR(xbuf, ch)
+
+/*
+ * Macro that does padding. The padding is done by printing
+ * the character ch.
+ */
+#define PAD(xbuf, count, ch) do { \
+ if ((count) > 0) { \
+ size_t newlen; \
+ smart_str_alloc(xbuf, (count), 0); \
+ memset(xbuf->c + xbuf->len, ch, (count)); \
+ xbuf->len += (count); \
+ } \
+} while (0)
+
+#define NUM(c) (c - '0')
+
+#define STR_TO_DEC(str, num) do { \
+ num = NUM(*str++); \
+ while (isdigit((int)*str)) { \
+ num *= 10; \
+ num += NUM(*str++); \
+ if (num >= INT_MAX / 10) { \
+ while (isdigit((int)*str++)); \
+ break; \
+ } \
+ } \
+} while (0)
+
+/*
+ * This macro does zero padding so that the precision
+ * requirement is satisfied. The padding is done by
+ * adding '0's to the left of the string that is going
+ * to be printed.
+ */
+#define FIX_PRECISION(adjust, precision, s, s_len) do { \
+ if (adjust) \
+ while (s_len < precision) { \
+ *--s = '0'; \
+ s_len++; \
+ } \
+} while (0)
+
+/* }}} */
+
+
+#if !HAVE_STRNLEN
+static size_t strnlen(const char *s, size_t maxlen) {
+ char *r = memchr(s, '\0', maxlen);
+ return r ? r-s : maxlen;
+}
+#endif
+
+/*
+ * Do format conversion placing the output in buffer
+ */
+static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap) /* {{{ */
+{
+ char *s = NULL;
+ int s_len, free_zcopy;
+ zval *zvp, zcopy;
+
+ int min_width = 0;
+ int precision = 0;
+ enum {
+ LEFT, RIGHT
+ } adjust;
+ char pad_char;
+ char prefix_char;
+
+ double fp_num;
+ wide_int i_num = (wide_int) 0;
+ u_wide_int ui_num = (u_wide_int) 0;
+
+ char num_buf[NUM_BUF_SIZE];
+ char char_buf[2]; /* for printing %% and %<unknown> */
+
+#ifdef HAVE_LOCALE_H
+ struct lconv *lconv = NULL;
+#endif
+
+ /*
+ * Flag variables
+ */
+ length_modifier_e modifier;
+ boolean_e alternate_form;
+ boolean_e print_sign;
+ boolean_e print_blank;
+ boolean_e adjust_precision;
+ boolean_e adjust_width;
+ bool_int is_negative;
+
+ while (*fmt) {
+ if (*fmt != '%') {
+ INS_CHAR(xbuf, *fmt);
+ } else {
+ /*
+ * Default variable settings
+ */
+ adjust = RIGHT;
+ alternate_form = print_sign = print_blank = NO;
+ pad_char = ' ';
+ prefix_char = NUL;
+ free_zcopy = 0;
+
+ fmt++;
+
+ /*
+ * Try to avoid checking for flags, width or precision
+ */
+ if (isascii((int)*fmt) && !islower((int)*fmt)) {
+ /*
+ * Recognize flags: -, #, BLANK, +
+ */
+ for (;; fmt++) {
+ if (*fmt == '-')
+ adjust = LEFT;
+ else if (*fmt == '+')
+ print_sign = YES;
+ else if (*fmt == '#')
+ alternate_form = YES;
+ else if (*fmt == ' ')
+ print_blank = YES;
+ else if (*fmt == '0')
+ pad_char = '0';
+ else
+ break;
+ }
+
+ /*
+ * Check if a width was specified
+ */
+ if (isdigit((int)*fmt)) {
+ STR_TO_DEC(fmt, min_width);
+ adjust_width = YES;
+ } else if (*fmt == '*') {
+ min_width = va_arg(ap, int);
+ fmt++;
+ adjust_width = YES;
+ if (min_width < 0) {
+ adjust = LEFT;
+ min_width = -min_width;
+ }
+ } else
+ adjust_width = NO;
+
+ /*
+ * Check if a precision was specified
+ */
+ if (*fmt == '.') {
+ adjust_precision = YES;
+ fmt++;
+ if (isdigit((int)*fmt)) {
+ STR_TO_DEC(fmt, precision);
+ } else if (*fmt == '*') {
+ precision = va_arg(ap, int);
+ fmt++;
+ if (precision < 0)
+ precision = 0;
+ } else
+ precision = 0;
+
+ if (precision > FORMAT_CONV_MAX_PRECISION) {
+ precision = FORMAT_CONV_MAX_PRECISION;
+ }
+ } else
+ adjust_precision = NO;
+ } else
+ adjust_precision = adjust_width = NO;
+
+ /*
+ * Modifier check
+ */
+ switch (*fmt) {
+ case 'L':
+ fmt++;
+ modifier = LM_LONG_DOUBLE;
+ break;
+ case 'I':
+ fmt++;
+#if SIZEOF_LONG_LONG
+ if (*fmt == '6' && *(fmt+1) == '4') {
+ fmt += 2;
+ modifier = LM_LONG_LONG;
+ } else
+#endif
+ if (*fmt == '3' && *(fmt+1) == '2') {
+ fmt += 2;
+ modifier = LM_LONG;
+ } else {
+#ifdef _WIN64
+ modifier = LM_LONG_LONG;
+#else
+ modifier = LM_LONG;
+#endif
+ }
+ break;
+ case 'l':
+ fmt++;
+#if SIZEOF_LONG_LONG
+ if (*fmt == 'l') {
+ fmt++;
+ modifier = LM_LONG_LONG;
+ } else
+#endif
+ modifier = LM_LONG;
+ break;
+ case 'z':
+ fmt++;
+ modifier = LM_SIZE_T;
+ break;
+ case 'j':
+ fmt++;
+#if SIZEOF_INTMAX_T
+ modifier = LM_INTMAX_T;
+#else
+ modifier = LM_SIZE_T;
+#endif
+ break;
+ case 't':
+ fmt++;
+#if SIZEOF_PTRDIFF_T
+ modifier = LM_PTRDIFF_T;
+#else
+ modifier = LM_SIZE_T;
+#endif
+ break;
+ case 'h':
+ fmt++;
+ if (*fmt == 'h') {
+ fmt++;
+ }
+ /* these are promoted to int, so no break */
+ default:
+ modifier = LM_STD;
+ break;
+ }
+
+ /*
+ * Argument extraction and printing.
+ * First we determine the argument type.
+ * Then, we convert the argument to a string.
+ * On exit from the switch, s points to the string that
+ * must be printed, s_len has the length of the string
+ * The precision requirements, if any, are reflected in s_len.
+ *
+ * NOTE: pad_char may be set to '0' because of the 0 flag.
+ * It is reset to ' ' by non-numeric formats
+ */
+ switch (*fmt) {
+ case 'Z':
+ zvp = (zval*) va_arg(ap, zval*);
+ zend_make_printable_zval(zvp, &zcopy, &free_zcopy);
+ if (free_zcopy) {
+ zvp = &zcopy;
+ }
+ s_len = Z_STRLEN_P(zvp);
+ s = Z_STRVAL_P(zvp);
+ if (adjust_precision && precision < s_len) {
+ s_len = precision;
+ }
+ break;
+ case 'u':
+ switch(modifier) {
+ default:
+ i_num = (wide_int) va_arg(ap, unsigned int);
+ break;
+ case LM_LONG_DOUBLE:
+ goto fmt_error;
+ case LM_LONG:
+ i_num = (wide_int) va_arg(ap, unsigned long int);
+ break;
+ case LM_SIZE_T:
+ i_num = (wide_int) va_arg(ap, size_t);
+ break;
+#if SIZEOF_LONG_LONG
+ case LM_LONG_LONG:
+ i_num = (wide_int) va_arg(ap, u_wide_int);
+ break;
+#endif
+#if SIZEOF_INTMAX_T
+ case LM_INTMAX_T:
+ i_num = (wide_int) va_arg(ap, uintmax_t);
+ break;
+#endif
+#if SIZEOF_PTRDIFF_T
+ case LM_PTRDIFF_T:
+ i_num = (wide_int) va_arg(ap, ptrdiff_t);
+ break;
+#endif
+ }
+ /*
+ * The rest also applies to other integer formats, so fall
+ * into that case.
+ */
+ case 'd':
+ case 'i':
+ /*
+ * Get the arg if we haven't already.
+ */
+ if ((*fmt) != 'u') {
+ switch(modifier) {
+ default:
+ i_num = (wide_int) va_arg(ap, int);
+ break;
+ case LM_LONG_DOUBLE:
+ goto fmt_error;
+ case LM_LONG:
+ i_num = (wide_int) va_arg(ap, long int);
+ break;
+ case LM_SIZE_T:
+#if SIZEOF_SSIZE_T
+ i_num = (wide_int) va_arg(ap, ssize_t);
+#else
+ i_num = (wide_int) va_arg(ap, size_t);
+#endif
+ break;
+#if SIZEOF_LONG_LONG
+ case LM_LONG_LONG:
+ i_num = (wide_int) va_arg(ap, wide_int);
+ break;
+#endif
+#if SIZEOF_INTMAX_T
+ case LM_INTMAX_T:
+ i_num = (wide_int) va_arg(ap, intmax_t);
+ break;
+#endif
+#if SIZEOF_PTRDIFF_T
+ case LM_PTRDIFF_T:
+ i_num = (wide_int) va_arg(ap, ptrdiff_t);
+ break;
+#endif
+ }
+ }
+ s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
+ &num_buf[NUM_BUF_SIZE], &s_len);
+ FIX_PRECISION(adjust_precision, precision, s, s_len);
+
+ if (*fmt != 'u') {
+ if (is_negative)
+ prefix_char = '-';
+ else if (print_sign)
+ prefix_char = '+';
+ else if (print_blank)
+ prefix_char = ' ';
+ }
+ break;
+
+
+ case 'o':
+ switch(modifier) {
+ default:
+ ui_num = (u_wide_int) va_arg(ap, unsigned int);
+ break;
+ case LM_LONG_DOUBLE:
+ goto fmt_error;
+ case LM_LONG:
+ ui_num = (u_wide_int) va_arg(ap, unsigned long int);
+ break;
+ case LM_SIZE_T:
+ ui_num = (u_wide_int) va_arg(ap, size_t);
+ break;
+#if SIZEOF_LONG_LONG
+ case LM_LONG_LONG:
+ ui_num = (u_wide_int) va_arg(ap, u_wide_int);
+ break;
+#endif
+#if SIZEOF_INTMAX_T
+ case LM_INTMAX_T:
+ ui_num = (u_wide_int) va_arg(ap, uintmax_t);
+ break;
+#endif
+#if SIZEOF_PTRDIFF_T
+ case LM_PTRDIFF_T:
+ ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
+ break;
+#endif
+ }
+ s = ap_php_conv_p2(ui_num, 3, *fmt,
+ &num_buf[NUM_BUF_SIZE], &s_len);
+ FIX_PRECISION(adjust_precision, precision, s, s_len);
+ if (alternate_form && *s != '0') {
+ *--s = '0';
+ s_len++;
+ }
+ break;
+
+
+ case 'x':
+ case 'X':
+ switch(modifier) {
+ default:
+ ui_num = (u_wide_int) va_arg(ap, unsigned int);
+ break;
+ case LM_LONG_DOUBLE:
+ goto fmt_error;
+ case LM_LONG:
+ ui_num = (u_wide_int) va_arg(ap, unsigned long int);
+ break;
+ case LM_SIZE_T:
+ ui_num = (u_wide_int) va_arg(ap, size_t);
+ break;
+#if SIZEOF_LONG_LONG
+ case LM_LONG_LONG:
+ ui_num = (u_wide_int) va_arg(ap, u_wide_int);
+ break;
+#endif
+#if SIZEOF_INTMAX_T
+ case LM_INTMAX_T:
+ ui_num = (u_wide_int) va_arg(ap, uintmax_t);
+ break;
+#endif
+#if SIZEOF_PTRDIFF_T
+ case LM_PTRDIFF_T:
+ ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
+ break;
+#endif
+ }
+ s = ap_php_conv_p2(ui_num, 4, *fmt,
+ &num_buf[NUM_BUF_SIZE], &s_len);
+ FIX_PRECISION(adjust_precision, precision, s, s_len);
+ if (alternate_form && ui_num != 0) {
+ *--s = *fmt; /* 'x' or 'X' */
+ *--s = '0';
+ s_len += 2;
+ }
+ break;
+
+
+ case 's':
+ case 'v':
+ s = va_arg(ap, char *);
+ if (s != NULL) {
+ if (!adjust_precision) {
+ s_len = strlen(s);
+ } else {
+ s_len = strnlen(s, precision);
+ }
+ } else {
+ s = S_NULL;
+ s_len = S_NULL_LEN;
+ }
+ pad_char = ' ';
+ break;
+
+
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ switch(modifier) {
+ case LM_LONG_DOUBLE:
+ fp_num = (double) va_arg(ap, long double);
+ break;
+ case LM_STD:
+ fp_num = va_arg(ap, double);
+ break;
+ default:
+ goto fmt_error;
+ }
+
+ if (zend_isnan(fp_num)) {
+ s = "nan";
+ s_len = 3;
+ } else if (zend_isinf(fp_num)) {
+ s = "inf";
+ s_len = 3;
+ } else {
+#ifdef HAVE_LOCALE_H
+ if (!lconv) {
+ lconv = localeconv();
+ }
+#endif
+ s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
+ (adjust_precision == NO) ? FLOAT_DIGITS : precision,
+ (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
+ &is_negative, &num_buf[1], &s_len);
+ if (is_negative)
+ prefix_char = '-';
+ else if (print_sign)
+ prefix_char = '+';
+ else if (print_blank)
+ prefix_char = ' ';
+ }
+ break;
+
+
+ case 'g':
+ case 'k':
+ case 'G':
+ case 'H':
+ switch(modifier) {
+ case LM_LONG_DOUBLE:
+ fp_num = (double) va_arg(ap, long double);
+ break;
+ case LM_STD:
+ fp_num = va_arg(ap, double);
+ break;
+ default:
+ goto fmt_error;
+ }
+
+ if (zend_isnan(fp_num)) {
+ s = "NAN";
+ s_len = 3;
+ break;
+ } else if (zend_isinf(fp_num)) {
+ if (fp_num > 0) {
+ s = "INF";
+ s_len = 3;
+ } else {
+ s = "-INF";
+ s_len = 4;
+ }
+ break;
+ }
+
+ if (adjust_precision == NO)
+ precision = FLOAT_DIGITS;
+ else if (precision == 0)
+ precision = 1;
+ /*
+ * * We use &num_buf[ 1 ], so that we have room for the sign
+ */
+#ifdef HAVE_LOCALE_H
+ if (!lconv) {
+ lconv = localeconv();
+ }
+#endif
+ s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
+ if (*s == '-')
+ prefix_char = *s++;
+ else if (print_sign)
+ prefix_char = '+';
+ else if (print_blank)
+ prefix_char = ' ';
+
+ s_len = strlen(s);
+
+ if (alternate_form && (strchr(s, '.')) == NULL)
+ s[s_len++] = '.';
+ break;
+
+
+ case 'c':
+ char_buf[0] = (char) (va_arg(ap, int));
+ s = &char_buf[0];
+ s_len = 1;
+ pad_char = ' ';
+ break;
+
+
+ case '%':
+ char_buf[0] = '%';
+ s = &char_buf[0];
+ s_len = 1;
+ pad_char = ' ';
+ break;
+
+
+ case 'n':
+ *(va_arg(ap, int *)) = xbuf->len;
+ goto skip_output;
+
+ /*
+ * Always extract the argument as a "char *" pointer. We
+ * should be using "void *" but there are still machines
+ * that don't understand it.
+ * If the pointer size is equal to the size of an unsigned
+ * integer we convert the pointer to a hex number, otherwise
+ * we print "%p" to indicate that we don't handle "%p".
+ */
+ case 'p':
+ if (sizeof(char *) <= sizeof(u_wide_int)) {
+ ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
+ s = ap_php_conv_p2(ui_num, 4, 'x',
+ &num_buf[NUM_BUF_SIZE], &s_len);
+ if (ui_num != 0) {
+ *--s = 'x';
+ *--s = '0';
+ s_len += 2;
+ }
+ } else {
+ s = "%p";
+ s_len = 2;
+ }
+ pad_char = ' ';
+ break;
+
+
+ case NUL:
+ /*
+ * The last character of the format string was %.
+ * We ignore it.
+ */
+ continue;
+
+
+fmt_error:
+ php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
+ /*
+ * The default case is for unrecognized %'s.
+ * We print %<char> to help the user identify what
+ * option is not understood.
+ * This is also useful in case the user wants to pass
+ * the output of format_converter to another function
+ * that understands some other %<char> (like syslog).
+ * Note that we can't point s inside fmt because the
+ * unknown <char> could be preceded by width etc.
+ */
+ default:
+ char_buf[0] = '%';
+ char_buf[1] = *fmt;
+ s = char_buf;
+ s_len = 2;
+ pad_char = ' ';
+ break;
+ }
+
+ if (prefix_char != NUL) {
+ *--s = prefix_char;
+ s_len++;
+ }
+ if (adjust_width && adjust == RIGHT && min_width > s_len) {
+ if (pad_char == '0' && prefix_char != NUL) {
+ INS_CHAR(xbuf, *s);
+ s++;
+ s_len--;
+ min_width--;
+ }
+ PAD(xbuf, min_width - s_len, pad_char);
+ }
+ /*
+ * Print the string s.
+ */
+ INS_STRING(xbuf, s, s_len);
+
+ if (adjust_width && adjust == LEFT && min_width > s_len)
+ PAD(xbuf, min_width - s_len, pad_char);
+ if (free_zcopy) {
+ zval_dtor(&zcopy);
+ }
+ }
+skip_output:
+ fmt++;
+ }
+ return;
+}
+/* }}} */
+
+/*
+ * This is the general purpose conversion function.
+ */
+PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) /* {{{ */
+{
+ smart_str xbuf = {0};
+
+ xbuf_format_converter(&xbuf, format, ap);
+
+ if (max_len && xbuf.len > max_len) {
+ xbuf.len = max_len;
+ }
+ smart_str_0(&xbuf);
+
+ *pbuf = xbuf.c;
+
+ return xbuf.len;
+}
+/* }}} */
+
+PHPAPI int spprintf(char **pbuf, size_t max_len, const char *format, ...) /* {{{ */
+{
+ int cc;
+ va_list ap;
+
+ va_start(ap, format);
+ cc = vspprintf(pbuf, max_len, format, ap);
+ va_end(ap);
+ return (cc);
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/spprintf.h b/main/spprintf.h
new file mode 100644
index 0000000..397928a
--- /dev/null
+++ b/main/spprintf.h
@@ -0,0 +1,52 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/*
+
+The pbuf parameter of all spprintf version receives a pointer to the allocated
+buffer. This buffer must be freed manually after usage using efree() function.
+The buffer will allways be terminated by a zero character. When pbuf is NULL
+the function can be used to calculate the required size of the buffer but for
+that purpose snprintf is faster. When both pbuf and the return value are 0
+than you are out of memory.
+
+There is also snprintf: See difference explained in snprintf.h
+
+*/
+
+#ifndef SPPRINTF_H
+#define SPPRINTF_H
+
+#include "snprintf.h"
+
+BEGIN_EXTERN_C()
+PHPAPI int spprintf( char **pbuf, size_t max_len, const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
+
+PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) PHP_ATTRIBUTE_FORMAT(printf, 3, 0);
+END_EXTERN_C()
+
+#endif /* SNPRINTF_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/main/streams/cast.c b/main/streams/cast.c
new file mode 100644
index 0000000..878b4b5
--- /dev/null
+++ b/main/streams/cast.c
@@ -0,0 +1,418 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#define _GNU_SOURCE
+#include "php.h"
+#include "php_globals.h"
+#include "php_network.h"
+#include "php_open_temporary_file.h"
+#include "ext/standard/file.h"
+#include <stddef.h>
+#include <fcntl.h>
+
+#include "php_streams_int.h"
+
+/* Under BSD, emulate fopencookie using funopen */
+#if defined(HAVE_FUNOPEN) && !defined(HAVE_FOPENCOOKIE)
+typedef struct {
+ int (*reader)(void *, char *, int);
+ int (*writer)(void *, const char *, int);
+ fpos_t (*seeker)(void *, fpos_t, int);
+ int (*closer)(void *);
+} COOKIE_IO_FUNCTIONS_T;
+
+FILE *fopencookie(void *cookie, const char *mode, COOKIE_IO_FUNCTIONS_T *funcs)
+{
+ return funopen(cookie, funcs->reader, funcs->writer, funcs->seeker, funcs->closer);
+}
+# define HAVE_FOPENCOOKIE 1
+# define PHP_EMULATE_FOPENCOOKIE 1
+# define PHP_STREAM_COOKIE_FUNCTIONS &stream_cookie_functions
+#elif defined(HAVE_FOPENCOOKIE)
+# define PHP_STREAM_COOKIE_FUNCTIONS stream_cookie_functions
+#endif
+
+/* {{{ STDIO with fopencookie */
+#if defined(PHP_EMULATE_FOPENCOOKIE)
+/* use our fopencookie emulation */
+static int stream_cookie_reader(void *cookie, char *buffer, int size)
+{
+ int ret;
+ TSRMLS_FETCH();
+
+ ret = php_stream_read((php_stream*)cookie, buffer, size);
+ return ret;
+}
+
+static int stream_cookie_writer(void *cookie, const char *buffer, int size)
+{
+ TSRMLS_FETCH();
+
+ return php_stream_write((php_stream *)cookie, (char *)buffer, size);
+}
+
+static fpos_t stream_cookie_seeker(void *cookie, off_t position, int whence)
+{
+ TSRMLS_FETCH();
+
+ return (fpos_t)php_stream_seek((php_stream *)cookie, position, whence);
+}
+
+static int stream_cookie_closer(void *cookie)
+{
+ php_stream *stream = (php_stream*)cookie;
+ TSRMLS_FETCH();
+
+ /* prevent recursion */
+ stream->fclose_stdiocast = PHP_STREAM_FCLOSE_NONE;
+ return php_stream_close(stream);
+}
+#elif defined(HAVE_FOPENCOOKIE)
+static ssize_t stream_cookie_reader(void *cookie, char *buffer, size_t size)
+{
+ ssize_t ret;
+ TSRMLS_FETCH();
+
+ ret = php_stream_read(((php_stream *)cookie), buffer, size);
+ return ret;
+}
+
+static ssize_t stream_cookie_writer(void *cookie, const char *buffer, size_t size)
+{
+ TSRMLS_FETCH();
+
+ return php_stream_write(((php_stream *)cookie), (char *)buffer, size);
+}
+
+# ifdef COOKIE_SEEKER_USES_OFF64_T
+static int stream_cookie_seeker(void *cookie, __off64_t *position, int whence)
+{
+ TSRMLS_FETCH();
+
+ *position = php_stream_seek((php_stream *)cookie, (off_t)*position, whence);
+
+ if (*position == -1) {
+ return -1;
+ }
+ return 0;
+}
+# else
+static int stream_cookie_seeker(void *cookie, off_t position, int whence)
+{
+ TSRMLS_FETCH();
+
+ return php_stream_seek((php_stream *)cookie, position, whence);
+}
+# endif
+
+static int stream_cookie_closer(void *cookie)
+{
+ php_stream *stream = (php_stream*)cookie;
+ TSRMLS_FETCH();
+
+ /* prevent recursion */
+ stream->fclose_stdiocast = PHP_STREAM_FCLOSE_NONE;
+ return php_stream_close(stream);
+}
+#endif /* elif defined(HAVE_FOPENCOOKIE) */
+
+#if HAVE_FOPENCOOKIE
+static COOKIE_IO_FUNCTIONS_T stream_cookie_functions =
+{
+ stream_cookie_reader, stream_cookie_writer,
+ stream_cookie_seeker, stream_cookie_closer
+};
+#else
+/* TODO: use socketpair() to emulate fopencookie, as suggested by Hartmut ? */
+#endif
+/* }}} */
+
+/* {{{ php_stream_mode_sanitize_fdopen_fopencookie
+ * Result should have at least size 5, e.g. to write wbx+\0 */
+void php_stream_mode_sanitize_fdopen_fopencookie(php_stream *stream, char *result)
+{
+ /* replace modes not supported by fdopen and fopencookie, but supported
+ * by PHP's fread(), so that their calls won't fail */
+ const char *cur_mode = stream->mode;
+ int has_plus = 0,
+ has_bin = 0,
+ i,
+ res_curs = 0;
+
+ if (cur_mode[0] == 'r' || cur_mode[0] == 'w' || cur_mode[0] == 'a') {
+ result[res_curs++] = cur_mode[0];
+ } else {
+ /* assume cur_mode[0] is 'c' or 'x'; substitute by 'w', which should not
+ * truncate anything in fdopen/fopencookie */
+ result[res_curs++] = 'w';
+
+ /* x is allowed (at least by glibc & compat), but not as the 1st mode
+ * as in PHP and in any case is (at best) ignored by fdopen and fopencookie */
+ }
+
+ /* assume current mode has at most length 4 (e.g. wbn+) */
+ for (i = 1; i < 4 && cur_mode[i] != '\0'; i++) {
+ if (cur_mode[i] == 'b') {
+ has_bin = 1;
+ } else if (cur_mode[i] == '+') {
+ has_plus = 1;
+ }
+ /* ignore 'n', 't' or other stuff */
+ }
+
+ if (has_bin) {
+ result[res_curs++] = 'b';
+ }
+ if (has_plus) {
+ result[res_curs++] = '+';
+ }
+
+ result[res_curs] = '\0';
+}
+/* }}} */
+
+/* {{{ php_stream_cast */
+PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC)
+{
+ int flags = castas & PHP_STREAM_CAST_MASK;
+ castas &= ~PHP_STREAM_CAST_MASK;
+
+ /* synchronize our buffer (if possible) */
+ if (ret && castas != PHP_STREAM_AS_FD_FOR_SELECT) {
+ php_stream_flush(stream);
+ if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) {
+ off_t dummy;
+
+ stream->ops->seek(stream, stream->position, SEEK_SET, &dummy TSRMLS_CC);
+ stream->readpos = stream->writepos = 0;
+ }
+ }
+
+ /* filtered streams can only be cast as stdio, and only when fopencookie is present */
+
+ if (castas == PHP_STREAM_AS_STDIO) {
+ if (stream->stdiocast) {
+ if (ret) {
+ *(FILE**)ret = stream->stdiocast;
+ }
+ goto exit_success;
+ }
+
+ /* if the stream is a stdio stream let's give it a chance to respond
+ * first, to avoid doubling up the layers of stdio with an fopencookie */
+ if (php_stream_is(stream, PHP_STREAM_IS_STDIO) &&
+ stream->ops->cast &&
+ !php_stream_is_filtered(stream) &&
+ stream->ops->cast(stream, castas, ret TSRMLS_CC) == SUCCESS
+ ) {
+ goto exit_success;
+ }
+
+#if HAVE_FOPENCOOKIE
+ /* if just checking, say yes we can be a FILE*, but don't actually create it yet */
+ if (ret == NULL) {
+ goto exit_success;
+ }
+
+ {
+ char fixed_mode[5];
+ php_stream_mode_sanitize_fdopen_fopencookie(stream, fixed_mode);
+ *(FILE**)ret = fopencookie(stream, fixed_mode, PHP_STREAM_COOKIE_FUNCTIONS);
+ }
+
+ if (*ret != NULL) {
+ off_t pos;
+
+ stream->fclose_stdiocast = PHP_STREAM_FCLOSE_FOPENCOOKIE;
+
+ /* If the stream position is not at the start, we need to force
+ * the stdio layer to believe it's real location. */
+ pos = php_stream_tell(stream);
+ if (pos > 0) {
+ fseek(*ret, pos, SEEK_SET);
+ }
+
+ goto exit_success;
+ }
+
+ /* must be either:
+ a) programmer error
+ b) no memory
+ -> lets bail
+ */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "fopencookie failed");
+ return FAILURE;
+#endif
+
+ if (!php_stream_is_filtered(stream) && stream->ops->cast && stream->ops->cast(stream, castas, NULL TSRMLS_CC) == SUCCESS) {
+ if (FAILURE == stream->ops->cast(stream, castas, ret TSRMLS_CC)) {
+ return FAILURE;
+ }
+ goto exit_success;
+ } else if (flags & PHP_STREAM_CAST_TRY_HARD) {
+ php_stream *newstream;
+
+ newstream = php_stream_fopen_tmpfile();
+ if (newstream) {
+ int retcopy = php_stream_copy_to_stream_ex(stream, newstream, PHP_STREAM_COPY_ALL, NULL);
+
+ if (retcopy != SUCCESS) {
+ php_stream_close(newstream);
+ } else {
+ int retcast = php_stream_cast(newstream, castas | flags, (void **)ret, show_err);
+
+ if (retcast == SUCCESS) {
+ rewind(*(FILE**)ret);
+ }
+
+ /* do some specialized cleanup */
+ if ((flags & PHP_STREAM_CAST_RELEASE)) {
+ php_stream_free(stream, PHP_STREAM_FREE_CLOSE_CASTED);
+ }
+
+ /* TODO: we probably should be setting .stdiocast and .fclose_stdiocast or
+ * we may be leaking the FILE*. Needs investigation, though. */
+ return retcast;
+ }
+ }
+ }
+ }
+
+ if (php_stream_is_filtered(stream)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot cast a filtered stream on this system");
+ return FAILURE;
+ } else if (stream->ops->cast && stream->ops->cast(stream, castas, ret TSRMLS_CC) == SUCCESS) {
+ goto exit_success;
+ }
+
+ if (show_err) {
+ /* these names depend on the values of the PHP_STREAM_AS_XXX defines in php_streams.h */
+ static const char *cast_names[4] = {
+ "STDIO FILE*",
+ "File Descriptor",
+ "Socket Descriptor",
+ "select()able descriptor"
+ };
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot represent a stream of type %s as a %s", stream->ops->label, cast_names[castas]);
+ }
+
+ return FAILURE;
+
+exit_success:
+
+ if ((stream->writepos - stream->readpos) > 0 &&
+ stream->fclose_stdiocast != PHP_STREAM_FCLOSE_FOPENCOOKIE &&
+ (flags & PHP_STREAM_CAST_INTERNAL) == 0
+ ) {
+ /* the data we have buffered will be lost to the third party library that
+ * will be accessing the stream. Emit a warning so that the end-user will
+ * know that they should try something else */
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%ld bytes of buffered data lost during stream conversion!", (long)(stream->writepos - stream->readpos));
+ }
+
+ if (castas == PHP_STREAM_AS_STDIO && ret) {
+ stream->stdiocast = *(FILE**)ret;
+ }
+
+ if (flags & PHP_STREAM_CAST_RELEASE) {
+ php_stream_free(stream, PHP_STREAM_FREE_CLOSE_CASTED);
+ }
+
+ return SUCCESS;
+
+}
+/* }}} */
+
+/* {{{ php_stream_open_wrapper_as_file */
+PHPAPI FILE * _php_stream_open_wrapper_as_file(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
+{
+ FILE *fp = NULL;
+ php_stream *stream = NULL;
+
+ stream = php_stream_open_wrapper_rel(path, mode, options|STREAM_WILL_CAST, opened_path);
+
+ if (stream == NULL) {
+ return NULL;
+ }
+
+ if (php_stream_cast(stream, PHP_STREAM_AS_STDIO|PHP_STREAM_CAST_TRY_HARD|PHP_STREAM_CAST_RELEASE, (void**)&fp, REPORT_ERRORS) == FAILURE) {
+ php_stream_close(stream);
+ if (opened_path && *opened_path) {
+ efree(*opened_path);
+ }
+ return NULL;
+ }
+ return fp;
+}
+/* }}} */
+
+/* {{{ php_stream_make_seekable */
+PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstream, int flags STREAMS_DC TSRMLS_DC)
+{
+ if (newstream == NULL) {
+ return PHP_STREAM_FAILED;
+ }
+ *newstream = NULL;
+
+ if (((flags & PHP_STREAM_FORCE_CONVERSION) == 0) && origstream->ops->seek != NULL) {
+ *newstream = origstream;
+ return PHP_STREAM_UNCHANGED;
+ }
+
+ /* Use a tmpfile and copy the old streams contents into it */
+
+ if (flags & PHP_STREAM_PREFER_STDIO) {
+ *newstream = php_stream_fopen_tmpfile();
+ } else {
+ *newstream = php_stream_temp_new();
+ }
+
+ if (*newstream == NULL) {
+ return PHP_STREAM_FAILED;
+ }
+
+#if ZEND_DEBUG
+ (*newstream)->open_filename = origstream->open_filename;
+ (*newstream)->open_lineno = origstream->open_lineno;
+#endif
+
+ if (php_stream_copy_to_stream_ex(origstream, *newstream, PHP_STREAM_COPY_ALL, NULL) != SUCCESS) {
+ php_stream_close(*newstream);
+ *newstream = NULL;
+ return PHP_STREAM_CRITICAL;
+ }
+
+ php_stream_close(origstream);
+ php_stream_seek(*newstream, 0, SEEK_SET);
+
+ return PHP_STREAM_RELEASED;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/streams/filter.c b/main/streams/filter.c
new file mode 100644
index 0000000..6de3a92
--- /dev/null
+++ b/main/streams/filter.c
@@ -0,0 +1,544 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "php.h"
+#include "php_globals.h"
+#include "php_network.h"
+#include "php_open_temporary_file.h"
+#include "ext/standard/file.h"
+#include <stddef.h>
+#include <fcntl.h>
+
+#include "php_streams_int.h"
+
+/* Global filter hash, copied to FG(stream_filters) on registration of volatile filter */
+static HashTable stream_filters_hash;
+
+/* Should only be used during core initialization */
+PHPAPI HashTable *php_get_stream_filters_hash_global(void)
+{
+ return &stream_filters_hash;
+}
+
+/* Normal hash selection/retrieval call */
+PHPAPI HashTable *_php_get_stream_filters_hash(TSRMLS_D)
+{
+ return (FG(stream_filters) ? FG(stream_filters) : &stream_filters_hash);
+}
+
+/* API for registering GLOBAL filters */
+PHPAPI int php_stream_filter_register_factory(const char *filterpattern, php_stream_filter_factory *factory TSRMLS_DC)
+{
+ return zend_hash_add(&stream_filters_hash, (char*)filterpattern, strlen(filterpattern) + 1, factory, sizeof(*factory), NULL);
+}
+
+PHPAPI int php_stream_filter_unregister_factory(const char *filterpattern TSRMLS_DC)
+{
+ return zend_hash_del(&stream_filters_hash, (char*)filterpattern, strlen(filterpattern) + 1);
+}
+
+/* API for registering VOLATILE wrappers */
+PHPAPI int php_stream_filter_register_factory_volatile(const char *filterpattern, php_stream_filter_factory *factory TSRMLS_DC)
+{
+ if (!FG(stream_filters)) {
+ php_stream_filter_factory tmpfactory;
+
+ ALLOC_HASHTABLE(FG(stream_filters));
+ zend_hash_init(FG(stream_filters), zend_hash_num_elements(&stream_filters_hash), NULL, NULL, 1);
+ zend_hash_copy(FG(stream_filters), &stream_filters_hash, NULL, &tmpfactory, sizeof(php_stream_filter_factory));
+ }
+
+ return zend_hash_add(FG(stream_filters), (char*)filterpattern, strlen(filterpattern) + 1, factory, sizeof(*factory), NULL);
+}
+
+/* Buckets */
+
+PHPAPI php_stream_bucket *php_stream_bucket_new(php_stream *stream, char *buf, size_t buflen, int own_buf, int buf_persistent TSRMLS_DC)
+{
+ int is_persistent = php_stream_is_persistent(stream);
+ php_stream_bucket *bucket;
+
+ bucket = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), is_persistent);
+
+ if (bucket == NULL) {
+ return NULL;
+ }
+
+ bucket->next = bucket->prev = NULL;
+
+ if (is_persistent && !buf_persistent) {
+ /* all data in a persistent bucket must also be persistent */
+ bucket->buf = pemalloc(buflen, 1);
+
+ if (bucket->buf == NULL) {
+ pefree(bucket, 1);
+ return NULL;
+ }
+
+ memcpy(bucket->buf, buf, buflen);
+ bucket->buflen = buflen;
+ bucket->own_buf = 1;
+ } else {
+ bucket->buf = buf;
+ bucket->buflen = buflen;
+ bucket->own_buf = own_buf;
+ }
+ bucket->is_persistent = is_persistent;
+ bucket->refcount = 1;
+ bucket->brigade = NULL;
+
+ return bucket;
+}
+
+/* Given a bucket, returns a version of that bucket with a writeable buffer.
+ * If the original bucket has a refcount of 1 and owns its buffer, then it
+ * is returned unchanged.
+ * Otherwise, a copy of the buffer is made.
+ * In both cases, the original bucket is unlinked from its brigade.
+ * If a copy is made, the original bucket is delref'd.
+ * */
+PHPAPI php_stream_bucket *php_stream_bucket_make_writeable(php_stream_bucket *bucket TSRMLS_DC)
+{
+ php_stream_bucket *retval;
+
+ php_stream_bucket_unlink(bucket TSRMLS_CC);
+
+ if (bucket->refcount == 1 && bucket->own_buf) {
+ return bucket;
+ }
+
+ retval = (php_stream_bucket*)pemalloc(sizeof(php_stream_bucket), bucket->is_persistent);
+ memcpy(retval, bucket, sizeof(*retval));
+
+ retval->buf = pemalloc(retval->buflen, retval->is_persistent);
+ memcpy(retval->buf, bucket->buf, retval->buflen);
+
+ retval->refcount = 1;
+ retval->own_buf = 1;
+
+ php_stream_bucket_delref(bucket TSRMLS_CC);
+
+ return retval;
+}
+
+PHPAPI int php_stream_bucket_split(php_stream_bucket *in, php_stream_bucket **left, php_stream_bucket **right, size_t length TSRMLS_DC)
+{
+ *left = (php_stream_bucket*)pecalloc(1, sizeof(php_stream_bucket), in->is_persistent);
+ *right = (php_stream_bucket*)pecalloc(1, sizeof(php_stream_bucket), in->is_persistent);
+
+ if (*left == NULL || *right == NULL) {
+ goto exit_fail;
+ }
+
+ (*left)->buf = pemalloc(length, in->is_persistent);
+ (*left)->buflen = length;
+ memcpy((*left)->buf, in->buf, length);
+ (*left)->refcount = 1;
+ (*left)->own_buf = 1;
+ (*left)->is_persistent = in->is_persistent;
+
+ (*right)->buflen = in->buflen - length;
+ (*right)->buf = pemalloc((*right)->buflen, in->is_persistent);
+ memcpy((*right)->buf, in->buf + length, (*right)->buflen);
+ (*right)->refcount = 1;
+ (*right)->own_buf = 1;
+ (*right)->is_persistent = in->is_persistent;
+
+ return SUCCESS;
+
+exit_fail:
+ if (*right) {
+ if ((*right)->buf) {
+ pefree((*right)->buf, in->is_persistent);
+ }
+ pefree(*right, in->is_persistent);
+ }
+ if (*left) {
+ if ((*left)->buf) {
+ pefree((*left)->buf, in->is_persistent);
+ }
+ pefree(*left, in->is_persistent);
+ }
+ return FAILURE;
+}
+
+PHPAPI void php_stream_bucket_delref(php_stream_bucket *bucket TSRMLS_DC)
+{
+ if (--bucket->refcount == 0) {
+ if (bucket->own_buf) {
+ pefree(bucket->buf, bucket->is_persistent);
+ }
+ pefree(bucket, bucket->is_persistent);
+ }
+}
+
+PHPAPI void php_stream_bucket_prepend(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket TSRMLS_DC)
+{
+ bucket->next = brigade->head;
+ bucket->prev = NULL;
+
+ if (brigade->head) {
+ brigade->head->prev = bucket;
+ } else {
+ brigade->tail = bucket;
+ }
+ brigade->head = bucket;
+ bucket->brigade = brigade;
+}
+
+PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket TSRMLS_DC)
+{
+ if (brigade->tail == bucket) {
+ return;
+ }
+
+ bucket->prev = brigade->tail;
+ bucket->next = NULL;
+
+ if (brigade->tail) {
+ brigade->tail->next = bucket;
+ } else {
+ brigade->head = bucket;
+ }
+ brigade->tail = bucket;
+ bucket->brigade = brigade;
+}
+
+PHPAPI void php_stream_bucket_unlink(php_stream_bucket *bucket TSRMLS_DC)
+{
+ if (bucket->prev) {
+ bucket->prev->next = bucket->next;
+ } else if (bucket->brigade) {
+ bucket->brigade->head = bucket->next;
+ }
+ if (bucket->next) {
+ bucket->next->prev = bucket->prev;
+ } else if (bucket->brigade) {
+ bucket->brigade->tail = bucket->prev;
+ }
+ bucket->brigade = NULL;
+ bucket->next = bucket->prev = NULL;
+}
+
+
+
+
+
+
+
+
+/* We allow very simple pattern matching for filter factories:
+ * if "convert.charset.utf-8/sjis" is requested, we search first for an exact
+ * match. If that fails, we try "convert.charset.*", then "convert.*"
+ * This means that we don't need to clog up the hashtable with a zillion
+ * charsets (for example) but still be able to provide them all as filters */
+PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC)
+{
+ HashTable *filter_hash = (FG(stream_filters) ? FG(stream_filters) : &stream_filters_hash);
+ php_stream_filter_factory *factory = NULL;
+ php_stream_filter *filter = NULL;
+ int n;
+ char *period;
+
+ n = strlen(filtername);
+
+ if (SUCCESS == zend_hash_find(filter_hash, (char*)filtername, n + 1, (void**)&factory)) {
+ filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);
+ } else if ((period = strrchr(filtername, '.'))) {
+ /* try a wildcard */
+ char *wildname;
+
+ wildname = emalloc(n+3);
+ memcpy(wildname, filtername, n+1);
+ period = wildname + (period - filtername);
+ while (period && !filter) {
+ *period = '\0';
+ strncat(wildname, ".*", 2);
+ if (SUCCESS == zend_hash_find(filter_hash, wildname, strlen(wildname) + 1, (void**)&factory)) {
+ filter = factory->create_filter(filtername, filterparams, persistent TSRMLS_CC);
+ }
+
+ *period = '\0';
+ period = strrchr(wildname, '.');
+ }
+ efree(wildname);
+ }
+
+ if (filter == NULL) {
+ /* TODO: these need correct docrefs */
+ if (factory == NULL)
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to locate filter \"%s\"", filtername);
+ else
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create or locate filter \"%s\"", filtername);
+ }
+
+ return filter;
+}
+
+PHPAPI php_stream_filter *_php_stream_filter_alloc(php_stream_filter_ops *fops, void *abstract, int persistent STREAMS_DC TSRMLS_DC)
+{
+ php_stream_filter *filter;
+
+ filter = (php_stream_filter*) pemalloc_rel_orig(sizeof(php_stream_filter), persistent);
+ memset(filter, 0, sizeof(php_stream_filter));
+
+ filter->fops = fops;
+ filter->abstract = abstract;
+ filter->is_persistent = persistent;
+
+ return filter;
+}
+
+PHPAPI void php_stream_filter_free(php_stream_filter *filter TSRMLS_DC)
+{
+ if (filter->fops->dtor)
+ filter->fops->dtor(filter TSRMLS_CC);
+ pefree(filter, filter->is_persistent);
+}
+
+PHPAPI int php_stream_filter_prepend_ex(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
+{
+ filter->next = chain->head;
+ filter->prev = NULL;
+
+ if (chain->head) {
+ chain->head->prev = filter;
+ } else {
+ chain->tail = filter;
+ }
+ chain->head = filter;
+ filter->chain = chain;
+
+ return SUCCESS;
+}
+
+PHPAPI void _php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
+{
+ php_stream_filter_prepend_ex(chain, filter TSRMLS_CC);
+}
+
+PHPAPI int php_stream_filter_append_ex(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
+{
+ php_stream *stream = chain->stream;
+
+ filter->prev = chain->tail;
+ filter->next = NULL;
+ if (chain->tail) {
+ chain->tail->next = filter;
+ } else {
+ chain->head = filter;
+ }
+ chain->tail = filter;
+ filter->chain = chain;
+
+ if (&(stream->readfilters) == chain && (stream->writepos - stream->readpos) > 0) {
+ /* Let's going ahead and wind anything in the buffer through this filter */
+ php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL };
+ php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out;
+ php_stream_filter_status_t status;
+ php_stream_bucket *bucket;
+ size_t consumed = 0;
+
+ bucket = php_stream_bucket_new(stream, (char*) stream->readbuf + stream->readpos, stream->writepos - stream->readpos, 0, 0 TSRMLS_CC);
+ php_stream_bucket_append(brig_inp, bucket TSRMLS_CC);
+ status = filter->fops->filter(stream, filter, brig_inp, brig_outp, &consumed, PSFS_FLAG_NORMAL TSRMLS_CC);
+
+ if (stream->readpos + consumed > (uint)stream->writepos) {
+ /* No behaving filter should cause this. */
+ status = PSFS_ERR_FATAL;
+ }
+
+ switch (status) {
+ case PSFS_ERR_FATAL:
+ while (brig_in.head) {
+ bucket = brig_in.head;
+ php_stream_bucket_unlink(bucket TSRMLS_CC);
+ php_stream_bucket_delref(bucket TSRMLS_CC);
+ }
+ while (brig_out.head) {
+ bucket = brig_out.head;
+ php_stream_bucket_unlink(bucket TSRMLS_CC);
+ php_stream_bucket_delref(bucket TSRMLS_CC);
+ }
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter failed to process pre-buffered data");
+ return FAILURE;
+ case PSFS_FEED_ME:
+ /* We don't actually need data yet,
+ leave this filter in a feed me state until data is needed.
+ Reset stream's internal read buffer since the filter is "holding" it. */
+ stream->readpos = 0;
+ stream->writepos = 0;
+ break;
+ case PSFS_PASS_ON:
+ /* If any data is consumed, we cannot rely upon the existing read buffer,
+ as the filtered data must replace the existing data, so invalidate the cache */
+ /* note that changes here should be reflected in
+ main/streams/streams.c::php_stream_fill_read_buffer */
+ stream->writepos = 0;
+ stream->readpos = 0;
+
+ while (brig_outp->head) {
+ bucket = brig_outp->head;
+ /* Grow buffer to hold this bucket if need be.
+ TODO: See warning in main/stream/streams.c::php_stream_fill_read_buffer */
+ if (stream->readbuflen - stream->writepos < bucket->buflen) {
+ stream->readbuflen += bucket->buflen;
+ stream->readbuf = perealloc(stream->readbuf, stream->readbuflen, stream->is_persistent);
+ }
+ memcpy(stream->readbuf + stream->writepos, bucket->buf, bucket->buflen);
+ stream->writepos += bucket->buflen;
+
+ php_stream_bucket_unlink(bucket TSRMLS_CC);
+ php_stream_bucket_delref(bucket TSRMLS_CC);
+ }
+ break;
+ }
+ }
+
+ return SUCCESS;
+}
+
+PHPAPI void _php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC)
+{
+ if (php_stream_filter_append_ex(chain, filter TSRMLS_CC) != SUCCESS) {
+ if (chain->head == filter) {
+ chain->head = NULL;
+ chain->tail = NULL;
+ } else {
+ filter->prev->next = NULL;
+ chain->tail = filter->prev;
+ }
+ }
+}
+
+PHPAPI int _php_stream_filter_flush(php_stream_filter *filter, int finish TSRMLS_DC)
+{
+ php_stream_bucket_brigade brig_a = { NULL, NULL }, brig_b = { NULL, NULL }, *inp = &brig_a, *outp = &brig_b, *brig_temp;
+ php_stream_bucket *bucket;
+ php_stream_filter_chain *chain;
+ php_stream_filter *current;
+ php_stream *stream;
+ size_t flushed_size = 0;
+ long flags = (finish ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC);
+
+ if (!filter->chain || !filter->chain->stream) {
+ /* Filter is not attached to a chain, or chain is somehow not part of a stream */
+ return FAILURE;
+ }
+
+ chain = filter->chain;
+ stream = chain->stream;
+
+ for(current = filter; current; current = current->next) {
+ php_stream_filter_status_t status;
+
+ status = filter->fops->filter(stream, filter, inp, outp, NULL, flags TSRMLS_CC);
+ if (status == PSFS_FEED_ME) {
+ /* We've flushed the data far enough */
+ return SUCCESS;
+ }
+ if (status == PSFS_ERR_FATAL) {
+ return FAILURE;
+ }
+ /* Otherwise we have data available to PASS_ON
+ Swap the brigades and continue */
+ brig_temp = inp;
+ inp = outp;
+ outp = brig_temp;
+ outp->head = NULL;
+ outp->tail = NULL;
+
+ flags = PSFS_FLAG_NORMAL;
+ }
+
+ /* Last filter returned data via PSFS_PASS_ON
+ Do something with it */
+
+ for(bucket = inp->head; bucket; bucket = bucket->next) {
+ flushed_size += bucket->buflen;
+ }
+
+ if (flushed_size == 0) {
+ /* Unlikely, but possible */
+ return SUCCESS;
+ }
+
+ if (chain == &(stream->readfilters)) {
+ /* Dump any newly flushed data to the read buffer */
+ if (stream->readpos > 0) {
+ /* Back the buffer up */
+ memcpy(stream->readbuf, stream->readbuf + stream->readpos, stream->writepos - stream->readpos);
+ stream->readpos = 0;
+ stream->writepos -= stream->readpos;
+ }
+ if (flushed_size > (stream->readbuflen - stream->writepos)) {
+ /* Grow the buffer */
+ stream->readbuf = perealloc(stream->readbuf, stream->writepos + flushed_size + stream->chunk_size, stream->is_persistent);
+ }
+ while ((bucket = inp->head)) {
+ memcpy(stream->readbuf + stream->writepos, bucket->buf, bucket->buflen);
+ stream->writepos += bucket->buflen;
+ php_stream_bucket_unlink(bucket TSRMLS_CC);
+ php_stream_bucket_delref(bucket TSRMLS_CC);
+ }
+ } else if (chain == &(stream->writefilters)) {
+ /* Send flushed data to the stream */
+ while ((bucket = inp->head)) {
+ stream->ops->write(stream, bucket->buf, bucket->buflen TSRMLS_CC);
+ php_stream_bucket_unlink(bucket TSRMLS_CC);
+ php_stream_bucket_delref(bucket TSRMLS_CC);
+ }
+ }
+
+ return SUCCESS;
+}
+
+PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, int call_dtor TSRMLS_DC)
+{
+ if (filter->prev) {
+ filter->prev->next = filter->next;
+ } else {
+ filter->chain->head = filter->next;
+ }
+ if (filter->next) {
+ filter->next->prev = filter->prev;
+ } else {
+ filter->chain->tail = filter->prev;
+ }
+
+ if (filter->rsrc_id > 0) {
+ zend_list_delete(filter->rsrc_id);
+ }
+
+ if (call_dtor) {
+ php_stream_filter_free(filter TSRMLS_CC);
+ return NULL;
+ }
+ return filter;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/streams/glob_wrapper.c b/main/streams/glob_wrapper.c
new file mode 100644
index 0000000..9c051a5
--- /dev/null
+++ b/main/streams/glob_wrapper.c
@@ -0,0 +1,291 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "php.h"
+#include "php_streams_int.h"
+
+#ifdef HAVE_GLOB
+# ifndef PHP_WIN32
+# include <glob.h>
+# else
+# include "win32/glob.h"
+# endif
+#endif
+
+#ifdef HAVE_GLOB
+#ifndef GLOB_ONLYDIR
+#define GLOB_ONLYDIR (1<<30)
+#define GLOB_FLAGMASK (~GLOB_ONLYDIR)
+#else
+#define GLOB_FLAGMASK (~0)
+#endif
+
+typedef struct {
+ glob_t glob;
+ size_t index;
+ int flags;
+ char *path;
+ size_t path_len;
+ char *pattern;
+ size_t pattern_len;
+} glob_s_t;
+
+PHPAPI char* _php_glob_stream_get_path(php_stream *stream, int copy, int *plen STREAMS_DC TSRMLS_DC) /* {{{ */
+{
+ glob_s_t *pglob = (glob_s_t *)stream->abstract;
+
+ if (pglob && pglob->path) {
+ if (plen) {
+ *plen = pglob->path_len;
+ }
+ if (copy) {
+ return estrndup(pglob->path, pglob->path_len);
+ } else {
+ return pglob->path;
+ }
+ } else {
+ if (plen) {
+ *plen = 0;
+ }
+ return NULL;
+ }
+}
+/* }}} */
+
+PHPAPI char* _php_glob_stream_get_pattern(php_stream *stream, int copy, int *plen STREAMS_DC TSRMLS_DC) /* {{{ */
+{
+ glob_s_t *pglob = (glob_s_t *)stream->abstract;
+
+ if (pglob && pglob->pattern) {
+ if (plen) {
+ *plen = pglob->pattern_len;
+ }
+ if (copy) {
+ return estrndup(pglob->pattern, pglob->pattern_len);
+ } else {
+ return pglob->pattern;
+ }
+ } else {
+ if (plen) {
+ *plen = 0;
+ }
+ return NULL;
+ }
+}
+/* }}} */
+
+PHPAPI int _php_glob_stream_get_count(php_stream *stream, int *pflags STREAMS_DC TSRMLS_DC) /* {{{ */
+{
+ glob_s_t *pglob = (glob_s_t *)stream->abstract;
+
+ if (pglob) {
+ if (pflags) {
+ *pflags = pglob->flags;
+ }
+ return pglob->glob.gl_pathc;
+ } else {
+ if (pflags) {
+ *pflags = 0;
+ }
+ return 0;
+ }
+}
+/* }}} */
+
+static void php_glob_stream_path_split(glob_s_t *pglob, char *path, int get_path, char **p_file TSRMLS_DC) /* {{{ */
+{
+ char *pos, *gpath = path;
+
+ if ((pos = strrchr(path, '/')) != NULL) {
+ path = pos+1;
+ }
+#if defined(PHP_WIN32) || defined(NETWARE)
+ if ((pos = strrchr(path, '\\')) != NULL) {
+ path = pos+1;
+ }
+#endif
+
+ *p_file = path;
+
+ if (get_path) {
+ if (pglob->path) {
+ efree(pglob->path);
+ }
+ if (path != gpath) {
+ path--;
+ }
+ pglob->path_len = path - gpath;
+ pglob->path = estrndup(gpath, pglob->path_len);
+ }
+}
+/* }}} */
+
+static size_t php_glob_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
+{
+ glob_s_t *pglob = (glob_s_t *)stream->abstract;
+ php_stream_dirent *ent = (php_stream_dirent*)buf;
+ char *path;
+
+ /* avoid problems if someone mis-uses the stream */
+ if (count == sizeof(php_stream_dirent) && pglob) {
+ if (pglob->index < (size_t)pglob->glob.gl_pathc) {
+ php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[pglob->index++], pglob->flags & GLOB_APPEND, &path TSRMLS_CC);
+ PHP_STRLCPY(ent->d_name, path, sizeof(ent->d_name), strlen(path));
+ return sizeof(php_stream_dirent);
+ }
+ pglob->index = pglob->glob.gl_pathc;
+ if (pglob->path) {
+ efree(pglob->path);
+ pglob->path = NULL;
+ }
+ }
+
+ return 0;
+}
+/* }}} */
+
+static int php_glob_stream_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
+{
+ glob_s_t *pglob = (glob_s_t *)stream->abstract;
+
+ if (pglob) {
+ pglob->index = 0;
+ globfree(&pglob->glob);
+ if (pglob->path) {
+ efree(pglob->path);
+ }
+ if (pglob->pattern) {
+ efree(pglob->pattern);
+ }
+ }
+ efree(stream->abstract);
+ return 0;
+}
+/* {{{ */
+
+static int php_glob_stream_rewind(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC) /* {{{ */
+{
+ glob_s_t *pglob = (glob_s_t *)stream->abstract;
+
+ if (pglob) {
+ pglob->index = 0;
+ if (pglob->path) {
+ efree(pglob->path);
+ pglob->path = NULL;
+ }
+ }
+ return 0;
+}
+/* }}} */
+
+php_stream_ops php_glob_stream_ops = {
+ NULL, php_glob_stream_read,
+ php_glob_stream_close, NULL,
+ "glob",
+ php_glob_stream_rewind,
+ NULL, /* cast */
+ NULL, /* stat */
+ NULL /* set_option */
+};
+
+ /* {{{ php_glob_stream_opener */
+static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, char *path, char *mode,
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ glob_s_t *pglob;
+ int ret;
+ char *tmp, *pos;
+
+ if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) {
+ return NULL;
+ }
+
+ if (!strncmp(path, "glob://", sizeof("glob://")-1)) {
+ path += sizeof("glob://")-1;
+ if (opened_path) {
+ *opened_path = estrdup(path);
+ }
+ }
+
+ pglob = ecalloc(sizeof(*pglob), 1);
+
+ if (0 != (ret = glob(path, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) {
+#ifdef GLOB_NOMATCH
+ if (GLOB_NOMATCH != ret)
+#endif
+ {
+ efree(pglob);
+ return NULL;
+ }
+ }
+
+ pos = path;
+ if ((tmp = strrchr(pos, '/')) != NULL) {
+ pos = tmp+1;
+ }
+#if defined(PHP_WIN32) || defined(NETWARE)
+ if ((tmp = strrchr(pos, '\\')) != NULL) {
+ pos = tmp+1;
+ }
+#endif
+
+ pglob->pattern_len = strlen(pos);
+ pglob->pattern = estrndup(pos, pglob->pattern_len);
+
+ pglob->flags |= GLOB_APPEND;
+
+ if (pglob->glob.gl_pathc) {
+ php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[0], 1, &tmp TSRMLS_CC);
+ } else {
+ php_glob_stream_path_split(pglob, path, 1, &tmp TSRMLS_CC);
+ }
+
+ return php_stream_alloc(&php_glob_stream_ops, pglob, 0, mode);
+}
+/* }}} */
+
+static php_stream_wrapper_ops php_glob_stream_wrapper_ops = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ php_glob_stream_opener,
+ "glob",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+php_stream_wrapper php_glob_stream_wrapper = {
+ &php_glob_stream_wrapper_ops,
+ NULL,
+ 0
+};
+#endif /* HAVE_GLOB */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/streams/memory.c b/main/streams/memory.c
new file mode 100644
index 0000000..328d3be
--- /dev/null
+++ b/main/streams/memory.c
@@ -0,0 +1,758 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#define _GNU_SOURCE
+#include "php.h"
+
+PHPAPI int php_url_decode(char *str, int len);
+PHPAPI unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_length);
+
+/* Memory streams use a dynamic memory buffer to emulate a stream.
+ * You can use php_stream_memory_open to create a readonly stream
+ * from an existing memory buffer.
+ */
+
+/* Temp streams are streams that uses memory streams as long their
+ * size is less than a given memory amount. When a write operation
+ * exceeds that limit the content is written to a temporary file.
+ */
+
+/* {{{ ------- MEMORY stream implementation -------*/
+
+typedef struct {
+ char *data;
+ size_t fpos;
+ size_t fsize;
+ size_t smax;
+ int mode;
+} php_stream_memory_data;
+
+
+/* {{{ */
+static size_t php_stream_memory_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
+{
+ php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
+ assert(ms != NULL);
+
+ if (ms->mode & TEMP_STREAM_READONLY) {
+ return 0;
+ }
+ if (ms->fpos + count > ms->fsize) {
+ char *tmp;
+
+ if (!ms->data) {
+ tmp = emalloc(ms->fpos + count);
+ } else {
+ tmp = erealloc(ms->data, ms->fpos + count);
+ }
+ if (!tmp) {
+ count = ms->fsize - ms->fpos + 1;
+ } else {
+ ms->data = tmp;
+ ms->fsize = ms->fpos + count;
+ }
+ }
+ if (!ms->data)
+ count = 0;
+ if (count) {
+ assert(buf!= NULL);
+ memcpy(ms->data+ms->fpos, (char*)buf, count);
+ ms->fpos += count;
+ }
+ return count;
+}
+/* }}} */
+
+
+/* {{{ */
+static size_t php_stream_memory_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
+ assert(ms != NULL);
+
+ if (ms->fpos + count >= ms->fsize) {
+ count = ms->fsize - ms->fpos;
+ stream->eof = 1;
+ }
+ if (count) {
+ assert(ms->data!= NULL);
+ assert(buf!= NULL);
+ memcpy(buf, ms->data+ms->fpos, count);
+ ms->fpos += count;
+ }
+ return count;
+}
+/* }}} */
+
+
+/* {{{ */
+static int php_stream_memory_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
+ assert(ms != NULL);
+
+ if (ms->data && close_handle && ms->mode != TEMP_STREAM_READONLY) {
+ efree(ms->data);
+ }
+ efree(ms);
+ return 0;
+}
+/* }}} */
+
+
+/* {{{ */
+static int php_stream_memory_flush(php_stream *stream TSRMLS_DC)
+{
+ /* nothing to do here */
+ return 0;
+}
+/* }}} */
+
+
+/* {{{ */
+static int php_stream_memory_seek(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC)
+{
+ php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
+ assert(ms != NULL);
+
+ switch(whence) {
+ case SEEK_CUR:
+ if (offset < 0) {
+ if (ms->fpos < (size_t)(-offset)) {
+ ms->fpos = 0;
+ *newoffs = -1;
+ return -1;
+ } else {
+ ms->fpos = ms->fpos + offset;
+ *newoffs = ms->fpos;
+ stream->eof = 0;
+ return 0;
+ }
+ } else {
+ if (ms->fpos + (size_t)(offset) > ms->fsize) {
+ ms->fpos = ms->fsize;
+ *newoffs = -1;
+ return -1;
+ } else {
+ ms->fpos = ms->fpos + offset;
+ *newoffs = ms->fpos;
+ stream->eof = 0;
+ return 0;
+ }
+ }
+ case SEEK_SET:
+ if (ms->fsize < (size_t)(offset)) {
+ ms->fpos = ms->fsize;
+ *newoffs = -1;
+ return -1;
+ } else {
+ ms->fpos = offset;
+ *newoffs = ms->fpos;
+ stream->eof = 0;
+ return 0;
+ }
+ case SEEK_END:
+ if (offset > 0) {
+ ms->fpos = ms->fsize;
+ *newoffs = -1;
+ return -1;
+ } else if (ms->fsize < (size_t)(-offset)) {
+ ms->fpos = 0;
+ *newoffs = -1;
+ return -1;
+ } else {
+ ms->fpos = ms->fsize + offset;
+ *newoffs = ms->fpos;
+ stream->eof = 0;
+ return 0;
+ }
+ default:
+ *newoffs = ms->fpos;
+ return -1;
+ }
+}
+/* }}} */
+
+/* {{{ */
+static int php_stream_memory_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
+{
+ return FAILURE;
+}
+/* }}} */
+
+static int php_stream_memory_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */
+{
+ time_t timestamp = 0;
+ php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
+ assert(ms != NULL);
+
+ memset(ssb, 0, sizeof(php_stream_statbuf));
+ /* read-only across the board */
+
+ ssb->sb.st_mode = ms->mode & TEMP_STREAM_READONLY ? 0444 : 0666;
+
+ ssb->sb.st_size = ms->fsize;
+ ssb->sb.st_mode |= S_IFREG; /* regular file */
+
+#ifdef NETWARE
+ ssb->sb.st_mtime.tv_sec = timestamp;
+ ssb->sb.st_atime.tv_sec = timestamp;
+ ssb->sb.st_ctime.tv_sec = timestamp;
+#else
+ ssb->sb.st_mtime = timestamp;
+ ssb->sb.st_atime = timestamp;
+ ssb->sb.st_ctime = timestamp;
+#endif
+
+ ssb->sb.st_nlink = 1;
+ ssb->sb.st_rdev = -1;
+ /* this is only for APC, so use /dev/null device - no chance of conflict there! */
+ ssb->sb.st_dev = 0xC;
+ /* generate unique inode number for alias/filename, so no phars will conflict */
+ ssb->sb.st_ino = 0;
+
+#ifndef PHP_WIN32
+ ssb->sb.st_blksize = -1;
+#endif
+
+#if !defined(PHP_WIN32) && !defined(__BEOS__)
+ ssb->sb.st_blocks = -1;
+#endif
+
+ return 0;
+}
+/* }}} */
+
+static int php_stream_memory_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC) /* {{{ */
+{
+ php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
+ size_t newsize;
+
+ switch(option) {
+ case PHP_STREAM_OPTION_TRUNCATE_API:
+ switch (value) {
+ case PHP_STREAM_TRUNCATE_SUPPORTED:
+ return PHP_STREAM_OPTION_RETURN_OK;
+
+ case PHP_STREAM_TRUNCATE_SET_SIZE:
+ if (ms->mode & TEMP_STREAM_READONLY) {
+ return PHP_STREAM_OPTION_RETURN_ERR;
+ }
+ newsize = *(size_t*)ptrparam;
+ if (newsize <= ms->fsize) {
+ if (newsize < ms->fpos) {
+ ms->fpos = newsize;
+ }
+ } else {
+ ms->data = erealloc(ms->data, newsize);
+ memset(ms->data+ms->fsize, 0, newsize - ms->fsize);
+ ms->fsize = newsize;
+ }
+ ms->fsize = newsize;
+ return PHP_STREAM_OPTION_RETURN_OK;
+ }
+ default:
+ return PHP_STREAM_OPTION_RETURN_NOTIMPL;
+ }
+}
+/* }}} */
+
+PHPAPI php_stream_ops php_stream_memory_ops = {
+ php_stream_memory_write, php_stream_memory_read,
+ php_stream_memory_close, php_stream_memory_flush,
+ "MEMORY",
+ php_stream_memory_seek,
+ php_stream_memory_cast,
+ php_stream_memory_stat,
+ php_stream_memory_set_option
+};
+
+
+/* {{{ */
+PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC TSRMLS_DC)
+{
+ php_stream_memory_data *self;
+ php_stream *stream;
+
+ self = emalloc(sizeof(*self));
+ self->data = NULL;
+ self->fpos = 0;
+ self->fsize = 0;
+ self->smax = ~0u;
+ self->mode = mode;
+
+ stream = php_stream_alloc_rel(&php_stream_memory_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b");
+ stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
+ return stream;
+}
+/* }}} */
+
+
+/* {{{ */
+PHPAPI php_stream *_php_stream_memory_open(int mode, char *buf, size_t length STREAMS_DC TSRMLS_DC)
+{
+ php_stream *stream;
+ php_stream_memory_data *ms;
+
+ if ((stream = php_stream_memory_create_rel(mode)) != NULL) {
+ ms = (php_stream_memory_data*)stream->abstract;
+
+ if (mode == TEMP_STREAM_READONLY || mode == TEMP_STREAM_TAKE_BUFFER) {
+ /* use the buffer directly */
+ ms->data = buf;
+ ms->fsize = length;
+ } else {
+ if (length) {
+ assert(buf != NULL);
+ php_stream_write(stream, buf, length);
+ }
+ }
+ }
+ return stream;
+}
+/* }}} */
+
+
+/* {{{ */
+PHPAPI char *_php_stream_memory_get_buffer(php_stream *stream, size_t *length STREAMS_DC TSRMLS_DC)
+{
+ php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
+
+ assert(ms != NULL);
+ assert(length != 0);
+
+ *length = ms->fsize;
+ return ms->data;
+}
+/* }}} */
+
+/* }}} */
+
+/* {{{ ------- TEMP stream implementation -------*/
+
+typedef struct {
+ php_stream *innerstream;
+ size_t smax;
+ int mode;
+ zval* meta;
+} php_stream_temp_data;
+
+
+/* {{{ */
+static size_t php_stream_temp_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
+{
+ php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
+ assert(ts != NULL);
+
+ if (!ts->innerstream) {
+ return -1;
+ }
+ if (php_stream_is(ts->innerstream, PHP_STREAM_IS_MEMORY)) {
+ size_t memsize;
+ char *membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize);
+
+ if (memsize + count >= ts->smax) {
+ php_stream *file = php_stream_fopen_tmpfile();
+ php_stream_write(file, membuf, memsize);
+ php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE);
+ ts->innerstream = file;
+ php_stream_encloses(stream, ts->innerstream);
+ }
+ }
+ return php_stream_write(ts->innerstream, buf, count);
+}
+/* }}} */
+
+
+/* {{{ */
+static size_t php_stream_temp_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
+ size_t got;
+
+ assert(ts != NULL);
+
+ if (!ts->innerstream) {
+ return -1;
+ }
+
+ got = php_stream_read(ts->innerstream, buf, count);
+
+ stream->eof = ts->innerstream->eof;
+
+ return got;
+}
+/* }}} */
+
+
+/* {{{ */
+static int php_stream_temp_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
+ int ret;
+
+ assert(ts != NULL);
+
+ if (ts->innerstream) {
+ ret = php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE | (close_handle ? 0 : PHP_STREAM_FREE_PRESERVE_HANDLE));
+ } else {
+ ret = 0;
+ }
+
+ if (ts->meta) {
+ zval_ptr_dtor(&ts->meta);
+ }
+
+ efree(ts);
+
+ return ret;
+}
+/* }}} */
+
+
+/* {{{ */
+static int php_stream_temp_flush(php_stream *stream TSRMLS_DC)
+{
+ php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
+ assert(ts != NULL);
+
+ return ts->innerstream ? php_stream_flush(ts->innerstream) : -1;
+}
+/* }}} */
+
+
+/* {{{ */
+static int php_stream_temp_seek(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC)
+{
+ php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
+ int ret;
+
+ assert(ts != NULL);
+
+ if (!ts->innerstream) {
+ *newoffs = -1;
+ return -1;
+ }
+ ret = php_stream_seek(ts->innerstream, offset, whence);
+ *newoffs = php_stream_tell(ts->innerstream);
+ stream->eof = ts->innerstream->eof;
+
+ return ret;
+}
+/* }}} */
+
+/* {{{ */
+static int php_stream_temp_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
+{
+ php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
+ php_stream *file;
+ size_t memsize;
+ char *membuf;
+ off_t pos;
+
+ assert(ts != NULL);
+
+ if (!ts->innerstream) {
+ return FAILURE;
+ }
+ if (php_stream_is(ts->innerstream, PHP_STREAM_IS_STDIO)) {
+ return php_stream_cast(ts->innerstream, castas, ret, 0);
+ }
+
+ /* we are still using a memory based backing. If they are if we can be
+ * a FILE*, say yes because we can perform the conversion.
+ * If they actually want to perform the conversion, we need to switch
+ * the memory stream to a tmpfile stream */
+
+ if (ret == NULL && castas == PHP_STREAM_AS_STDIO) {
+ return SUCCESS;
+ }
+
+ /* say "no" to other stream forms */
+ if (ret == NULL) {
+ return FAILURE;
+ }
+
+ /* perform the conversion and then pass the request on to the innerstream */
+ membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize);
+ file = php_stream_fopen_tmpfile();
+ php_stream_write(file, membuf, memsize);
+ pos = php_stream_tell(ts->innerstream);
+
+ php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE);
+ ts->innerstream = file;
+ php_stream_encloses(stream, ts->innerstream);
+ php_stream_seek(ts->innerstream, pos, SEEK_SET);
+
+ return php_stream_cast(ts->innerstream, castas, ret, 1);
+}
+/* }}} */
+
+static int php_stream_temp_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */
+{
+ php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
+
+ if (!ts || !ts->innerstream) {
+ return -1;
+ }
+ return php_stream_stat(ts->innerstream, ssb);
+}
+/* }}} */
+
+static int php_stream_temp_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC) /* {{{ */
+{
+ php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
+
+ switch(option) {
+ case PHP_STREAM_OPTION_META_DATA_API:
+ if (ts->meta) {
+ zend_hash_copy(Z_ARRVAL_P((zval*)ptrparam), Z_ARRVAL_P(ts->meta), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*));
+ }
+ return PHP_STREAM_OPTION_RETURN_OK;
+ default:
+ if (ts->innerstream) {
+ return php_stream_set_option(ts->innerstream, option, value, ptrparam);
+ }
+ return PHP_STREAM_OPTION_RETURN_NOTIMPL;
+ }
+}
+/* }}} */
+
+PHPAPI php_stream_ops php_stream_temp_ops = {
+ php_stream_temp_write, php_stream_temp_read,
+ php_stream_temp_close, php_stream_temp_flush,
+ "TEMP",
+ php_stream_temp_seek,
+ php_stream_temp_cast,
+ php_stream_temp_stat,
+ php_stream_temp_set_option
+};
+
+/* }}} */
+
+/* {{{ _php_stream_temp_create */
+PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STREAMS_DC TSRMLS_DC)
+{
+ php_stream_temp_data *self;
+ php_stream *stream;
+
+ self = ecalloc(1, sizeof(*self));
+ self->smax = max_memory_usage;
+ self->mode = mode;
+ self->meta = NULL;
+ stream = php_stream_alloc_rel(&php_stream_temp_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b");
+ stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
+ self->innerstream = php_stream_memory_create_rel(mode);
+ php_stream_encloses(stream, self->innerstream);
+
+ return stream;
+}
+/* }}} */
+
+
+/* {{{ _php_stream_temp_open */
+PHPAPI php_stream *_php_stream_temp_open(int mode, size_t max_memory_usage, char *buf, size_t length STREAMS_DC TSRMLS_DC)
+{
+ php_stream *stream;
+ php_stream_temp_data *ts;
+ off_t newoffs;
+
+ if ((stream = php_stream_temp_create_rel(mode, max_memory_usage)) != NULL) {
+ if (length) {
+ assert(buf != NULL);
+ php_stream_temp_write(stream, buf, length TSRMLS_CC);
+ php_stream_temp_seek(stream, 0, SEEK_SET, &newoffs TSRMLS_CC);
+ }
+ ts = (php_stream_temp_data*)stream->abstract;
+ assert(ts != NULL);
+ ts->mode = mode;
+ }
+ return stream;
+}
+/* }}} */
+
+PHPAPI php_stream_ops php_stream_rfc2397_ops = {
+ php_stream_temp_write, php_stream_temp_read,
+ php_stream_temp_close, php_stream_temp_flush,
+ "RFC2397",
+ php_stream_temp_seek,
+ php_stream_temp_cast,
+ php_stream_temp_stat,
+ php_stream_temp_set_option
+};
+
+static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
+{
+ php_stream *stream;
+ php_stream_temp_data *ts;
+ char *comma, *semi, *sep, *key;
+ size_t mlen, dlen, plen, vlen;
+ off_t newoffs;
+ zval *meta = NULL;
+ int base64 = 0, ilen;
+
+ if (memcmp(path, "data:", 5)) {
+ return NULL;
+ }
+
+ path += 5;
+ dlen = strlen(path);
+
+ if (dlen >= 2 && path[0] == '/' && path[1] == '/') {
+ dlen -= 2;
+ path += 2;
+ }
+
+ if ((comma = memchr(path, ',', dlen)) == NULL) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: no comma in URL");
+ return NULL;
+ }
+
+ if (comma != path) {
+ /* meta info */
+ mlen = comma - path;
+ dlen -= mlen;
+ semi = memchr(path, ';', mlen);
+ sep = memchr(path, '/', mlen);
+
+ if (!semi && !sep) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: illegal media type");
+ return NULL;
+ }
+
+ MAKE_STD_ZVAL(meta);
+ array_init(meta);
+ if (!semi) { /* there is only a mime type */
+ add_assoc_stringl(meta, "mediatype", path, mlen, 1);
+ mlen = 0;
+ } else if (sep && sep < semi) { /* there is a mime type */
+ plen = semi - path;
+ add_assoc_stringl(meta, "mediatype", path, plen, 1);
+ mlen -= plen;
+ path += plen;
+ } else if (semi != path || mlen != sizeof(";base64")-1 || memcmp(path, ";base64", sizeof(";base64")-1)) { /* must be error since parameters are only allowed after mediatype */
+ zval_ptr_dtor(&meta);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: illegal media type");
+ return NULL;
+ }
+ /* get parameters and potentially ';base64' */
+ while(semi && (semi == path)) {
+ path++;
+ mlen--;
+ sep = memchr(path, '=', mlen);
+ semi = memchr(path, ';', mlen);
+ if (!sep || (semi && semi < sep)) { /* must be ';base64' or failure */
+ if (mlen != sizeof("base64")-1 || memcmp(path, "base64", sizeof("base64")-1)) {
+ /* must be error since parameters are only allowed after mediatype and we have no '=' sign */
+ zval_ptr_dtor(&meta);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: illegal parameter");
+ return NULL;
+ }
+ base64 = 1;
+ mlen -= sizeof("base64") - 1;
+ path += sizeof("base64") - 1;
+ break;
+ }
+ /* found parameter ... the heart of cs ppl lies in +1/-1 or was it +2 this time? */
+ plen = sep - path;
+ vlen = (semi ? semi - sep : mlen - plen) - 1 /* '=' */;
+ key = estrndup(path, plen);
+ add_assoc_stringl_ex(meta, key, plen + 1, sep + 1, vlen, 1);
+ efree(key);
+ plen += vlen + 1;
+ mlen -= plen;
+ path += plen;
+ }
+ if (mlen) {
+ zval_ptr_dtor(&meta);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: illegal URL");
+ return NULL;
+ }
+ } else {
+ MAKE_STD_ZVAL(meta);
+ array_init(meta);
+ }
+ add_assoc_bool(meta, "base64", base64);
+
+ /* skip ',' */
+ comma++;
+ dlen--;
+
+ if (base64) {
+ comma = (char*)php_base64_decode((const unsigned char *)comma, dlen, &ilen);
+ if (!comma) {
+ zval_ptr_dtor(&meta);
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: unable to decode");
+ return NULL;
+ }
+ } else {
+ comma = estrndup(comma, dlen);
+ ilen = dlen = php_url_decode(comma, dlen);
+ }
+
+ if ((stream = php_stream_temp_create_rel(0, ~0u)) != NULL) {
+ /* store data */
+ php_stream_temp_write(stream, comma, ilen TSRMLS_CC);
+ php_stream_temp_seek(stream, 0, SEEK_SET, &newoffs TSRMLS_CC);
+ /* set special stream stuff (enforce exact mode) */
+ vlen = strlen(mode);
+ if (vlen >= sizeof(stream->mode)) {
+ vlen = sizeof(stream->mode) - 1;
+ }
+ memcpy(stream->mode, mode, vlen);
+ stream->mode[vlen] = '\0';
+ stream->ops = &php_stream_rfc2397_ops;
+ ts = (php_stream_temp_data*)stream->abstract;
+ assert(ts != NULL);
+ ts->mode = mode && mode[0] == 'r' && mode[1] != '+' ? TEMP_STREAM_READONLY : 0;
+ ts->meta = meta;
+ }
+ efree(comma);
+
+ return stream;
+}
+
+PHPAPI php_stream_wrapper_ops php_stream_rfc2397_wops = {
+ php_stream_url_wrap_rfc2397,
+ NULL, /* close */
+ NULL, /* fstat */
+ NULL, /* stat */
+ NULL, /* opendir */
+ "RFC2397",
+ NULL, /* unlink */
+ NULL, /* rename */
+ NULL, /* mkdir */
+ NULL /* rmdir */
+};
+
+PHPAPI php_stream_wrapper php_stream_rfc2397_wrapper = {
+ &php_stream_rfc2397_wops,
+ NULL,
+ 1, /* is_url */
+};
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/streams/mmap.c b/main/streams/mmap.c
new file mode 100644
index 0000000..4f9388c
--- /dev/null
+++ b/main/streams/mmap.c
@@ -0,0 +1,75 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/* Memory Mapping interface for streams */
+#include "php.h"
+#include "php_streams_int.h"
+
+PHPAPI char *_php_stream_mmap_range(php_stream *stream, size_t offset, size_t length, php_stream_mmap_operation_t mode, size_t *mapped_len TSRMLS_DC)
+{
+ php_stream_mmap_range range;
+
+ range.offset = offset;
+ range.length = length;
+ range.mode = mode;
+ range.mapped = NULL;
+
+ /* For now, we impose an arbitrary limit to avoid
+ * runaway swapping when large files are passed thru. */
+ if (length > 4 * 1024 * 1024) {
+ return NULL;
+ }
+
+ if (PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_MMAP_API, PHP_STREAM_MMAP_MAP_RANGE, &range)) {
+ if (mapped_len) {
+ *mapped_len = range.length;
+ }
+ return range.mapped;
+ }
+ return NULL;
+}
+
+PHPAPI int _php_stream_mmap_unmap(php_stream *stream TSRMLS_DC)
+{
+ return php_stream_set_option(stream, PHP_STREAM_OPTION_MMAP_API, PHP_STREAM_MMAP_UNMAP, NULL) == PHP_STREAM_OPTION_RETURN_OK ? 1 : 0;
+}
+
+PHPAPI int _php_stream_mmap_unmap_ex(php_stream *stream, off_t readden TSRMLS_DC)
+{
+ int ret = 1;
+
+ if (php_stream_seek(stream, readden, SEEK_CUR) != 0) {
+ ret = 0;
+ }
+ if (php_stream_mmap_unmap(stream) == 0) {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/streams/php_stream_context.h b/main/streams/php_stream_context.h
new file mode 100644
index 0000000..240f6e0
--- /dev/null
+++ b/main/streams/php_stream_context.h
@@ -0,0 +1,136 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/* Stream context and status notification related definitions */
+
+/* callback for status notifications */
+typedef void (*php_stream_notification_func)(php_stream_context *context,
+ int notifycode, int severity,
+ char *xmsg, int xcode,
+ size_t bytes_sofar, size_t bytes_max,
+ void * ptr TSRMLS_DC);
+
+#define PHP_STREAM_NOTIFIER_PROGRESS 1
+
+/* Attempt to fetch context from the zval passed,
+ If no context was passed, use the default context
+ The default context has not yet been created, do it now. */
+#define php_stream_context_from_zval(zcontext, nocontext) ( \
+ (zcontext) ? zend_fetch_resource(&(zcontext) TSRMLS_CC, -1, "Stream-Context", NULL, 1, php_le_stream_context(TSRMLS_C)) : \
+ (nocontext) ? NULL : \
+ FG(default_context) ? FG(default_context) : \
+ (FG(default_context) = php_stream_context_alloc(TSRMLS_C)) )
+
+#define php_stream_context_to_zval(context, zval) { ZVAL_RESOURCE(zval, (context)->rsrc_id); zend_list_addref((context)->rsrc_id); }
+
+typedef struct _php_stream_notifier php_stream_notifier;
+
+struct _php_stream_notifier {
+ php_stream_notification_func func;
+ void (*dtor)(php_stream_notifier *notifier);
+ void *ptr;
+ int mask;
+ size_t progress, progress_max; /* position for progress notification */
+};
+
+struct _php_stream_context {
+ php_stream_notifier *notifier;
+ zval *options; /* hash keyed by wrapper family or specific wrapper */
+ zval *links; /* hash keyed by hostent for connection pooling */
+ int rsrc_id; /* used for auto-cleanup */
+};
+
+BEGIN_EXTERN_C()
+PHPAPI void php_stream_context_free(php_stream_context *context);
+PHPAPI php_stream_context *php_stream_context_alloc(TSRMLS_D);
+PHPAPI int php_stream_context_get_option(php_stream_context *context,
+ const char *wrappername, const char *optionname, zval ***optionvalue);
+PHPAPI int php_stream_context_set_option(php_stream_context *context,
+ const char *wrappername, const char *optionname, zval *optionvalue);
+
+PHPAPI int php_stream_context_get_link(php_stream_context *context,
+ const char *hostent, php_stream **stream);
+PHPAPI int php_stream_context_set_link(php_stream_context *context,
+ const char *hostent, php_stream *stream);
+PHPAPI int php_stream_context_del_link(php_stream_context *context,
+ php_stream *stream);
+
+PHPAPI php_stream_notifier *php_stream_notification_alloc(void);
+PHPAPI void php_stream_notification_free(php_stream_notifier *notifier);
+END_EXTERN_C()
+
+/* not all notification codes are implemented */
+#define PHP_STREAM_NOTIFY_RESOLVE 1
+#define PHP_STREAM_NOTIFY_CONNECT 2
+#define PHP_STREAM_NOTIFY_AUTH_REQUIRED 3
+#define PHP_STREAM_NOTIFY_MIME_TYPE_IS 4
+#define PHP_STREAM_NOTIFY_FILE_SIZE_IS 5
+#define PHP_STREAM_NOTIFY_REDIRECTED 6
+#define PHP_STREAM_NOTIFY_PROGRESS 7
+#define PHP_STREAM_NOTIFY_COMPLETED 8
+#define PHP_STREAM_NOTIFY_FAILURE 9
+#define PHP_STREAM_NOTIFY_AUTH_RESULT 10
+
+#define PHP_STREAM_NOTIFY_SEVERITY_INFO 0
+#define PHP_STREAM_NOTIFY_SEVERITY_WARN 1
+#define PHP_STREAM_NOTIFY_SEVERITY_ERR 2
+
+BEGIN_EXTERN_C()
+PHPAPI void php_stream_notification_notify(php_stream_context *context, int notifycode, int severity,
+ char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr TSRMLS_DC);
+PHPAPI php_stream_context *php_stream_context_set(php_stream *stream, php_stream_context *context);
+END_EXTERN_C()
+
+#define php_stream_notify_info(context, code, xmsg, xcode) do { if ((context) && (context)->notifier) { \
+ php_stream_notification_notify((context), (code), PHP_STREAM_NOTIFY_SEVERITY_INFO, \
+ (xmsg), (xcode), 0, 0, NULL TSRMLS_CC); } } while (0)
+
+#define php_stream_notify_progress(context, bsofar, bmax) do { if ((context) && (context)->notifier) { \
+ php_stream_notification_notify((context), PHP_STREAM_NOTIFY_PROGRESS, PHP_STREAM_NOTIFY_SEVERITY_INFO, \
+ NULL, 0, (bsofar), (bmax), NULL TSRMLS_CC); } } while(0)
+
+#define php_stream_notify_progress_init(context, sofar, bmax) do { if ((context) && (context)->notifier) { \
+ (context)->notifier->progress = (sofar); \
+ (context)->notifier->progress_max = (bmax); \
+ (context)->notifier->mask |= PHP_STREAM_NOTIFIER_PROGRESS; \
+ php_stream_notify_progress((context), (sofar), (bmax)); } } while (0)
+
+#define php_stream_notify_progress_increment(context, dsofar, dmax) do { if ((context) && (context)->notifier && (context)->notifier->mask & PHP_STREAM_NOTIFIER_PROGRESS) { \
+ (context)->notifier->progress += (dsofar); \
+ (context)->notifier->progress_max += (dmax); \
+ php_stream_notify_progress((context), (context)->notifier->progress, (context)->notifier->progress_max); } } while (0)
+
+#define php_stream_notify_file_size(context, file_size, xmsg, xcode) do { if ((context) && (context)->notifier) { \
+ php_stream_notification_notify((context), PHP_STREAM_NOTIFY_FILE_SIZE_IS, PHP_STREAM_NOTIFY_SEVERITY_INFO, \
+ (xmsg), (xcode), 0, (file_size), NULL TSRMLS_CC); } } while(0)
+
+#define php_stream_notify_error(context, code, xmsg, xcode) do { if ((context) && (context)->notifier) {\
+ php_stream_notification_notify((context), (code), PHP_STREAM_NOTIFY_SEVERITY_ERR, \
+ (xmsg), (xcode), 0, 0, NULL TSRMLS_CC); } } while(0)
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/streams/php_stream_filter_api.h b/main/streams/php_stream_filter_api.h
new file mode 100644
index 0000000..abb5906
--- /dev/null
+++ b/main/streams/php_stream_filter_api.h
@@ -0,0 +1,162 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ | With suggestions from: |
+ | Moriyoshi Koizumi <moriyoshi@at.wakwak.com> |
+ | Sara Golemon <pollita@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/* The filter API works on the principle of "Bucket-Brigades". This is
+ * partially inspired by the Apache 2 method of doing things, although
+ * it is intentially a light-weight implementation.
+ *
+ * Each stream can have a chain of filters for reading and another for writing.
+ *
+ * When data is written to the stream, it is placed into a bucket and placed at
+ * the start of the input brigade.
+ *
+ * The first filter in the chain is invoked on the brigade and (depending on
+ * it's return value), the next filter is invoked and so on.
+ * */
+
+#define PHP_STREAM_FILTER_READ 0x0001
+#define PHP_STREAM_FILTER_WRITE 0x0002
+#define PHP_STREAM_FILTER_ALL (PHP_STREAM_FILTER_READ | PHP_STREAM_FILTER_WRITE)
+
+typedef struct _php_stream_bucket php_stream_bucket;
+typedef struct _php_stream_bucket_brigade php_stream_bucket_brigade;
+
+struct _php_stream_bucket {
+ php_stream_bucket *next, *prev;
+ php_stream_bucket_brigade *brigade;
+
+ char *buf;
+ size_t buflen;
+ /* if non-zero, buf should be pefreed when the bucket is destroyed */
+ int own_buf;
+ int is_persistent;
+
+ /* destroy this struct when refcount falls to zero */
+ int refcount;
+};
+
+struct _php_stream_bucket_brigade {
+ php_stream_bucket *head, *tail;
+};
+
+typedef enum {
+ PSFS_ERR_FATAL, /* error in data stream */
+ PSFS_FEED_ME, /* filter needs more data; stop processing chain until more is available */
+ PSFS_PASS_ON /* filter generated output buckets; pass them on to next in chain */
+} php_stream_filter_status_t;
+
+/* Buckets API. */
+BEGIN_EXTERN_C()
+PHPAPI php_stream_bucket *php_stream_bucket_new(php_stream *stream, char *buf, size_t buflen, int own_buf, int buf_persistent TSRMLS_DC);
+PHPAPI int php_stream_bucket_split(php_stream_bucket *in, php_stream_bucket **left, php_stream_bucket **right, size_t length TSRMLS_DC);
+PHPAPI void php_stream_bucket_delref(php_stream_bucket *bucket TSRMLS_DC);
+#define php_stream_bucket_addref(bucket) (bucket)->refcount++
+PHPAPI void php_stream_bucket_prepend(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket TSRMLS_DC);
+PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket TSRMLS_DC);
+PHPAPI void php_stream_bucket_unlink(php_stream_bucket *bucket TSRMLS_DC);
+PHPAPI php_stream_bucket *php_stream_bucket_make_writeable(php_stream_bucket *bucket TSRMLS_DC);
+END_EXTERN_C()
+
+#define PSFS_FLAG_NORMAL 0 /* regular read/write */
+#define PSFS_FLAG_FLUSH_INC 1 /* an incremental flush */
+#define PSFS_FLAG_FLUSH_CLOSE 2 /* final flush prior to closing */
+
+typedef struct _php_stream_filter_ops {
+
+ php_stream_filter_status_t (*filter)(
+ php_stream *stream,
+ php_stream_filter *thisfilter,
+ php_stream_bucket_brigade *buckets_in,
+ php_stream_bucket_brigade *buckets_out,
+ size_t *bytes_consumed,
+ int flags
+ TSRMLS_DC);
+
+ void (*dtor)(php_stream_filter *thisfilter TSRMLS_DC);
+
+ const char *label;
+
+} php_stream_filter_ops;
+
+typedef struct _php_stream_filter_chain {
+ php_stream_filter *head, *tail;
+
+ /* Owning stream */
+ php_stream *stream;
+} php_stream_filter_chain;
+
+struct _php_stream_filter {
+ php_stream_filter_ops *fops;
+ void *abstract; /* for use by filter implementation */
+ php_stream_filter *next;
+ php_stream_filter *prev;
+ int is_persistent;
+
+ /* link into stream and chain */
+ php_stream_filter_chain *chain;
+
+ /* buffered buckets */
+ php_stream_bucket_brigade buffer;
+
+ /* filters are auto_registered when they're applied */
+ int rsrc_id;
+};
+
+/* stack filter onto a stream */
+BEGIN_EXTERN_C()
+PHPAPI void _php_stream_filter_prepend(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC);
+PHPAPI int php_stream_filter_prepend_ex(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC);
+PHPAPI void _php_stream_filter_append(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC);
+PHPAPI int php_stream_filter_append_ex(php_stream_filter_chain *chain, php_stream_filter *filter TSRMLS_DC);
+PHPAPI int _php_stream_filter_flush(php_stream_filter *filter, int finish TSRMLS_DC);
+PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, int call_dtor TSRMLS_DC);
+PHPAPI void php_stream_filter_free(php_stream_filter *filter TSRMLS_DC);
+PHPAPI php_stream_filter *_php_stream_filter_alloc(php_stream_filter_ops *fops, void *abstract, int persistent STREAMS_DC TSRMLS_DC);
+END_EXTERN_C()
+#define php_stream_filter_alloc(fops, thisptr, persistent) _php_stream_filter_alloc((fops), (thisptr), (persistent) STREAMS_CC TSRMLS_CC)
+#define php_stream_filter_alloc_rel(fops, thisptr, persistent) _php_stream_filter_alloc((fops), (thisptr), (persistent) STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_filter_prepend(chain, filter) _php_stream_filter_prepend((chain), (filter) TSRMLS_CC)
+#define php_stream_filter_append(chain, filter) _php_stream_filter_append((chain), (filter) TSRMLS_CC)
+#define php_stream_filter_flush(filter, finish) _php_stream_filter_flush((filter), (finish) TSRMLS_CC)
+
+#define php_stream_is_filtered(stream) ((stream)->readfilters.head || (stream)->writefilters.head)
+
+typedef struct _php_stream_filter_factory {
+ php_stream_filter *(*create_filter)(const char *filtername, zval *filterparams, int persistent TSRMLS_DC);
+} php_stream_filter_factory;
+
+BEGIN_EXTERN_C()
+PHPAPI int php_stream_filter_register_factory(const char *filterpattern, php_stream_filter_factory *factory TSRMLS_DC);
+PHPAPI int php_stream_filter_unregister_factory(const char *filterpattern TSRMLS_DC);
+PHPAPI int php_stream_filter_register_factory_volatile(const char *filterpattern, php_stream_filter_factory *factory TSRMLS_DC);
+PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, zval *filterparams, int persistent TSRMLS_DC);
+END_EXTERN_C()
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/streams/php_stream_glob_wrapper.h b/main/streams/php_stream_glob_wrapper.h
new file mode 100644
index 0000000..330e917
--- /dev/null
+++ b/main/streams/php_stream_glob_wrapper.h
@@ -0,0 +1,44 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+PHPAPI extern php_stream_wrapper php_glob_stream_wrapper;
+PHPAPI extern php_stream_ops php_glob_stream_ops;
+
+BEGIN_EXTERN_C()
+
+PHPAPI char* _php_glob_stream_get_path(php_stream *stream, int copy, int *plen STREAMS_DC TSRMLS_DC);
+#define php_glob_stream_get_path(stream, copy, plen) _php_glob_stream_get_path((stream), (copy), (plen) STREAMS_CC TSRMLS_CC)
+
+PHPAPI char* _php_glob_stream_get_pattern(php_stream *stream, int copy, int *plen STREAMS_DC TSRMLS_DC);
+#define php_glob_stream_get_pattern(stream, copy, plen) _php_glob_stream_get_pattern((stream), (copy), (plen) STREAMS_CC TSRMLS_CC)
+
+PHPAPI int _php_glob_stream_get_count(php_stream *stream, int *pflags STREAMS_DC TSRMLS_DC);
+#define php_glob_stream_get_count(stream, pflags) _php_glob_stream_get_count((stream), (pflags) STREAMS_CC TSRMLS_CC)
+
+END_EXTERN_C()
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/streams/php_stream_mmap.h b/main/streams/php_stream_mmap.h
new file mode 100644
index 0000000..7895ac6
--- /dev/null
+++ b/main/streams/php_stream_mmap.h
@@ -0,0 +1,88 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/* Memory Mapping interface for streams.
+ * The intention is to provide a uniform interface over the most common
+ * operations that are used within PHP itself, rather than a complete
+ * API for all memory mapping needs.
+ *
+ * ATM, we support only mmap(), but win32 memory mapping support will
+ * follow soon.
+ * */
+
+typedef enum {
+ /* Does the stream support mmap ? */
+ PHP_STREAM_MMAP_SUPPORTED,
+ /* Request a range and offset to be mapped;
+ * while mapped, you MUST NOT use any read/write functions
+ * on the stream (win9x compatibility) */
+ PHP_STREAM_MMAP_MAP_RANGE,
+ /* Unmap the last range that was mapped for the stream */
+ PHP_STREAM_MMAP_UNMAP
+} php_stream_mmap_operation_t;
+
+typedef enum {
+ PHP_STREAM_MAP_MODE_READONLY,
+ PHP_STREAM_MAP_MODE_READWRITE,
+ PHP_STREAM_MAP_MODE_SHARED_READONLY,
+ PHP_STREAM_MAP_MODE_SHARED_READWRITE
+} php_stream_mmap_access_t;
+
+typedef struct {
+ /* requested offset and length.
+ * If length is 0, the whole file is mapped */
+ size_t offset;
+ size_t length;
+
+ php_stream_mmap_access_t mode;
+
+ /* returned mapped address */
+ char *mapped;
+
+} php_stream_mmap_range;
+
+#define PHP_STREAM_MMAP_ALL 0
+
+#define php_stream_mmap_supported(stream) (_php_stream_set_option((stream), PHP_STREAM_OPTION_MMAP_API, PHP_STREAM_MMAP_SUPPORTED, NULL TSRMLS_CC) == 0 ? 1 : 0)
+
+/* Returns 1 if the stream in its current state can be memory mapped,
+ * 0 otherwise */
+#define php_stream_mmap_possible(stream) (!php_stream_is_filtered((stream)) && php_stream_mmap_supported((stream)))
+
+BEGIN_EXTERN_C()
+PHPAPI char *_php_stream_mmap_range(php_stream *stream, size_t offset, size_t length, php_stream_mmap_operation_t mode, size_t *mapped_len TSRMLS_DC);
+#define php_stream_mmap_range(stream, offset, length, mode, mapped_len) _php_stream_mmap_range((stream), (offset), (length), (mode), (mapped_len) TSRMLS_CC)
+
+/* un-maps the last mapped range */
+PHPAPI int _php_stream_mmap_unmap(php_stream *stream TSRMLS_DC);
+#define php_stream_mmap_unmap(stream) _php_stream_mmap_unmap((stream) TSRMLS_CC)
+
+PHPAPI int _php_stream_mmap_unmap_ex(php_stream *stream, off_t readden TSRMLS_DC);
+#define php_stream_mmap_unmap_ex(stream, readden) _php_stream_mmap_unmap_ex((stream), (readden) TSRMLS_CC)
+END_EXTERN_C()
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/streams/php_stream_plain_wrapper.h b/main/streams/php_stream_plain_wrapper.h
new file mode 100644
index 0000000..d88b30c
--- /dev/null
+++ b/main/streams/php_stream_plain_wrapper.h
@@ -0,0 +1,66 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/* definitions for the plain files wrapper */
+
+/* operations for a plain file; use the php_stream_fopen_XXX funcs below */
+PHPAPI extern php_stream_ops php_stream_stdio_ops;
+PHPAPI extern php_stream_wrapper php_plain_files_wrapper;
+
+BEGIN_EXTERN_C()
+
+/* like fopen, but returns a stream */
+PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, char **opened_path, int options STREAMS_DC TSRMLS_DC);
+#define php_stream_fopen(filename, mode, opened) _php_stream_fopen((filename), (mode), (opened), 0 STREAMS_CC TSRMLS_CC)
+
+PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char *path, char **opened_path, int options STREAMS_DC TSRMLS_DC);
+#define php_stream_fopen_with_path(filename, mode, path, opened) _php_stream_fopen_with_path((filename), (mode), (path), (opened), 0 STREAMS_CC TSRMLS_CC)
+
+PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STREAMS_DC TSRMLS_DC);
+#define php_stream_fopen_from_file(file, mode) _php_stream_fopen_from_file((file), (mode) STREAMS_CC TSRMLS_CC)
+
+PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id STREAMS_DC TSRMLS_DC);
+#define php_stream_fopen_from_fd(fd, mode, persistent_id) _php_stream_fopen_from_fd((fd), (mode), (persistent_id) STREAMS_CC TSRMLS_CC)
+
+PHPAPI php_stream *_php_stream_fopen_from_pipe(FILE *file, const char *mode STREAMS_DC TSRMLS_DC);
+#define php_stream_fopen_from_pipe(file, mode) _php_stream_fopen_from_pipe((file), (mode) STREAMS_CC TSRMLS_CC)
+
+PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC TSRMLS_DC);
+#define php_stream_fopen_tmpfile() _php_stream_fopen_tmpfile(0 STREAMS_CC TSRMLS_CC)
+
+PHPAPI php_stream *_php_stream_fopen_temporary_file(const char *dir, const char *pfx, char **opened_path STREAMS_DC TSRMLS_DC);
+#define php_stream_fopen_temporary_file(dir, pfx, opened_path) _php_stream_fopen_temporary_file((dir), (pfx), (opened_path) STREAMS_CC TSRMLS_CC)
+
+/* This is a utility API for extensions that are opening a stream, converting it
+ * to a FILE* and then closing it again. Be warned that fileno() on the result
+ * will most likely fail on systems with fopencookie. */
+PHPAPI FILE * _php_stream_open_wrapper_as_file(char * path, char * mode, int options, char **opened_path STREAMS_DC TSRMLS_DC);
+#define php_stream_open_wrapper_as_file(path, mode, options, opened_path) _php_stream_open_wrapper_as_file((path), (mode), (options), (opened_path) STREAMS_CC TSRMLS_CC)
+
+END_EXTERN_C()
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/streams/php_stream_transport.h b/main/streams/php_stream_transport.h
new file mode 100644
index 0000000..c2d9110
--- /dev/null
+++ b/main/streams/php_stream_transport.h
@@ -0,0 +1,211 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+#ifdef PHP_WIN32
+#include "config.w32.h"
+#include <Ws2tcpip.h>
+#endif
+
+#if HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+typedef php_stream *(php_stream_transport_factory_func)(const char *proto, long protolen,
+ char *resourcename, long resourcenamelen,
+ const char *persistent_id, int options, int flags,
+ struct timeval *timeout,
+ php_stream_context *context STREAMS_DC TSRMLS_DC);
+typedef php_stream_transport_factory_func *php_stream_transport_factory;
+
+BEGIN_EXTERN_C()
+PHPAPI int php_stream_xport_register(char *protocol, php_stream_transport_factory factory TSRMLS_DC);
+PHPAPI int php_stream_xport_unregister(char *protocol TSRMLS_DC);
+
+#define STREAM_XPORT_CLIENT 0
+#define STREAM_XPORT_SERVER 1
+
+#define STREAM_XPORT_CONNECT 2
+#define STREAM_XPORT_BIND 4
+#define STREAM_XPORT_LISTEN 8
+#define STREAM_XPORT_CONNECT_ASYNC 16
+
+/* Open a client or server socket connection */
+PHPAPI php_stream *_php_stream_xport_create(const char *name, long namelen, int options,
+ int flags, const char *persistent_id,
+ struct timeval *timeout,
+ php_stream_context *context,
+ char **error_string,
+ int *error_code
+ STREAMS_DC TSRMLS_DC);
+
+#define php_stream_xport_create(name, namelen, options, flags, persistent_id, timeout, context, estr, ecode) \
+ _php_stream_xport_create(name, namelen, options, flags, persistent_id, timeout, context, estr, ecode STREAMS_CC TSRMLS_CC)
+
+/* Bind the stream to a local address */
+PHPAPI int php_stream_xport_bind(php_stream *stream,
+ const char *name, long namelen,
+ char **error_text
+ TSRMLS_DC);
+
+/* Connect to a remote address */
+PHPAPI int php_stream_xport_connect(php_stream *stream,
+ const char *name, long namelen,
+ int asynchronous,
+ struct timeval *timeout,
+ char **error_text,
+ int *error_code
+ TSRMLS_DC);
+
+/* Prepare to listen */
+PHPAPI int php_stream_xport_listen(php_stream *stream,
+ int backlog,
+ char **error_text
+ TSRMLS_DC);
+
+/* Get the next client and their address as a string, or the underlying address
+ * structure. You must efree either of these if you request them */
+PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client,
+ char **textaddr, int *textaddrlen,
+ void **addr, socklen_t *addrlen,
+ struct timeval *timeout,
+ char **error_text
+ TSRMLS_DC);
+
+/* Get the name of either the socket or it's peer */
+PHPAPI int php_stream_xport_get_name(php_stream *stream, int want_peer,
+ char **textaddr, int *textaddrlen,
+ void **addr, socklen_t *addrlen
+ TSRMLS_DC);
+
+enum php_stream_xport_send_recv_flags {
+ STREAM_OOB = 1,
+ STREAM_PEEK = 2
+};
+
+/* Similar to recv() system call; read data from the stream, optionally
+ * peeking, optionally retrieving OOB data */
+PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t buflen,
+ long flags, void **addr, socklen_t *addrlen,
+ char **textaddr, int *textaddrlen TSRMLS_DC);
+
+/* Similar to send() system call; send data to the stream, optionally
+ * sending it as OOB data */
+PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t buflen,
+ long flags, void *addr, socklen_t addrlen TSRMLS_DC);
+
+typedef enum {
+ STREAM_SHUT_RD,
+ STREAM_SHUT_WR,
+ STREAM_SHUT_RDWR
+} stream_shutdown_t;
+
+/* Similar to shutdown() system call; shut down part of a full-duplex
+ * connection */
+PHPAPI int php_stream_xport_shutdown(php_stream *stream, stream_shutdown_t how TSRMLS_DC);
+END_EXTERN_C()
+
+
+/* Structure definition for the set_option interface that the above functions wrap */
+
+typedef struct _php_stream_xport_param {
+ enum {
+ STREAM_XPORT_OP_BIND, STREAM_XPORT_OP_CONNECT,
+ STREAM_XPORT_OP_LISTEN, STREAM_XPORT_OP_ACCEPT,
+ STREAM_XPORT_OP_CONNECT_ASYNC,
+ STREAM_XPORT_OP_GET_NAME,
+ STREAM_XPORT_OP_GET_PEER_NAME,
+ STREAM_XPORT_OP_RECV,
+ STREAM_XPORT_OP_SEND,
+ STREAM_XPORT_OP_SHUTDOWN
+ } op;
+ unsigned int want_addr:1;
+ unsigned int want_textaddr:1;
+ unsigned int want_errortext:1;
+ unsigned int how:2;
+
+ struct {
+ char *name;
+ long namelen;
+ int backlog;
+ struct timeval *timeout;
+ struct sockaddr *addr;
+ socklen_t addrlen;
+ char *buf;
+ size_t buflen;
+ long flags;
+ } inputs;
+ struct {
+ php_stream *client;
+ int returncode;
+ struct sockaddr *addr;
+ socklen_t addrlen;
+ char *textaddr;
+ long textaddrlen;
+
+ char *error_text;
+ int error_code;
+ } outputs;
+} php_stream_xport_param;
+
+
+/* These functions provide crypto support on the underlying transport */
+typedef enum {
+ STREAM_CRYPTO_METHOD_SSLv2_CLIENT,
+ STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
+ STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
+ STREAM_CRYPTO_METHOD_TLS_CLIENT,
+ STREAM_CRYPTO_METHOD_SSLv2_SERVER,
+ STREAM_CRYPTO_METHOD_SSLv3_SERVER,
+ STREAM_CRYPTO_METHOD_SSLv23_SERVER,
+ STREAM_CRYPTO_METHOD_TLS_SERVER
+} php_stream_xport_crypt_method_t;
+
+BEGIN_EXTERN_C()
+PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_crypt_method_t crypto_method, php_stream *session_stream TSRMLS_DC);
+PHPAPI int php_stream_xport_crypto_enable(php_stream *stream, int activate TSRMLS_DC);
+END_EXTERN_C()
+
+typedef struct _php_stream_xport_crypto_param {
+ enum {
+ STREAM_XPORT_CRYPTO_OP_SETUP,
+ STREAM_XPORT_CRYPTO_OP_ENABLE
+ } op;
+ struct {
+ int activate;
+ php_stream_xport_crypt_method_t method;
+ php_stream *session;
+ } inputs;
+ struct {
+ int returncode;
+ } outputs;
+} php_stream_xport_crypto_param;
+
+BEGIN_EXTERN_C()
+PHPAPI HashTable *php_stream_xport_get_hash(void);
+PHPAPI php_stream_transport_factory_func php_stream_generic_socket_factory;
+END_EXTERN_C()
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/streams/php_stream_userspace.h b/main/streams/php_stream_userspace.h
new file mode 100644
index 0000000..2830dd0
--- /dev/null
+++ b/main/streams/php_stream_userspace.h
@@ -0,0 +1,35 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+
+/* for user-space streams */
+PHPAPI extern php_stream_ops php_stream_userspace_ops;
+PHPAPI extern php_stream_ops php_stream_userspace_dir_ops;
+#define PHP_STREAM_IS_USERSPACE &php_stream_userspace_ops
+#define PHP_STREAM_IS_USERSPACE_DIR &php_stream_userspace_dir_ops
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/streams/php_streams_int.h b/main/streams/php_streams_int.h
new file mode 100644
index 0000000..daae2b8
--- /dev/null
+++ b/main/streams/php_streams_int.h
@@ -0,0 +1,71 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+
+#if ZEND_DEBUG
+
+#define emalloc_rel_orig(size) \
+ ( __php_stream_call_depth == 0 \
+ ? _emalloc((size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_RELAY_CC) \
+ : _emalloc((size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_ORIG_RELAY_CC) )
+
+#define erealloc_rel_orig(ptr, size) \
+ ( __php_stream_call_depth == 0 \
+ ? _erealloc((ptr), (size), 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_RELAY_CC) \
+ : _erealloc((ptr), (size), 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_ORIG_RELAY_CC) )
+
+#define pemalloc_rel_orig(size, persistent) ((persistent) ? malloc((size)) : emalloc_rel_orig((size)))
+#define perealloc_rel_orig(ptr, size, persistent) ((persistent) ? realloc((ptr), (size)) : erealloc_rel_orig((ptr), (size)))
+#else
+# define pemalloc_rel_orig(size, persistent) pemalloc((size), (persistent))
+# define perealloc_rel_orig(ptr, size, persistent) perealloc((ptr), (size), (persistent))
+# define emalloc_rel_orig(size) emalloc((size))
+#endif
+
+#define STREAM_DEBUG 0
+#define STREAM_WRAPPER_PLAIN_FILES ((php_stream_wrapper*)-1)
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *) -1)
+#endif
+
+#define CHUNK_SIZE 8192
+
+#ifdef PHP_WIN32
+# ifdef EWOULDBLOCK
+# undef EWOULDBLOCK
+# endif
+# define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
+
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG)
+#endif
+
+/* This functions transforms the first char to 'w' if it's not 'r', 'a' or 'w'
+ * and strips any subsequent chars except '+' and 'b'.
+ * Use this to sanitize stream->mode if you call e.g. fdopen, fopencookie or
+ * any other function that expects standard modes and you allow non-standard
+ * ones. result should be a char[5]. */
+void php_stream_mode_sanitize_fdopen_fopencookie(php_stream *stream, char *result);
+
+void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC);
+void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const char *path, const char *caption TSRMLS_DC);
+
diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c
new file mode 100644
index 0000000..4ee8150
--- /dev/null
+++ b/main/streams/plain_wrapper.c
@@ -0,0 +1,1505 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#include "php.h"
+#include "php_globals.h"
+#include "php_network.h"
+#include "php_open_temporary_file.h"
+#include "ext/standard/file.h"
+#include "ext/standard/flock_compat.h"
+#include "ext/standard/php_filestat.h"
+#include <stddef.h>
+#include <fcntl.h>
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include "SAPI.h"
+
+#include "php_streams_int.h"
+#ifdef PHP_WIN32
+# include "win32/winutil.h"
+#endif
+
+#define php_stream_fopen_from_fd_int(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_CC TSRMLS_CC)
+#define php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_REL_CC TSRMLS_CC)
+#define php_stream_fopen_from_file_int(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_CC TSRMLS_CC)
+#define php_stream_fopen_from_file_int_rel(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_REL_CC TSRMLS_CC)
+
+#if !defined(WINDOWS) && !defined(NETWARE)
+extern int php_get_uid_by_name(const char *name, uid_t *uid TSRMLS_DC);
+extern int php_get_gid_by_name(const char *name, gid_t *gid TSRMLS_DC);
+#endif
+
+/* parse standard "fopen" modes into open() flags */
+PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
+{
+ int flags;
+
+ switch (mode[0]) {
+ case 'r':
+ flags = 0;
+ break;
+ case 'w':
+ flags = O_TRUNC|O_CREAT;
+ break;
+ case 'a':
+ flags = O_CREAT|O_APPEND;
+ break;
+ case 'x':
+ flags = O_CREAT|O_EXCL;
+ break;
+ case 'c':
+ flags = O_CREAT;
+ break;
+ default:
+ /* unknown mode */
+ return FAILURE;
+ }
+#if defined(O_NONBLOCK)
+ if (strchr(mode, 'n')) {
+ flags |= O_NONBLOCK;
+ }
+#endif
+ if (strchr(mode, '+')) {
+ flags |= O_RDWR;
+ } else if (flags) {
+ flags |= O_WRONLY;
+ } else {
+ flags |= O_RDONLY;
+ }
+
+#if defined(_O_TEXT) && defined(O_BINARY)
+ if (strchr(mode, 't')) {
+ flags |= _O_TEXT;
+ } else {
+ flags |= O_BINARY;
+ }
+#endif
+
+ *open_flags = flags;
+ return SUCCESS;
+}
+
+
+/* {{{ ------- STDIO stream implementation -------*/
+
+typedef struct {
+ FILE *file;
+ int fd; /* underlying file descriptor */
+ unsigned is_process_pipe:1; /* use pclose instead of fclose */
+ unsigned is_pipe:1; /* don't try and seek */
+ unsigned cached_fstat:1; /* sb is valid */
+ unsigned _reserved:29;
+
+ int lock_flag; /* stores the lock state */
+ char *temp_file_name; /* if non-null, this is the path to a temporary file that
+ * is to be deleted when the stream is closed */
+#if HAVE_FLUSHIO
+ char last_op;
+#endif
+
+#if HAVE_MMAP
+ char *last_mapped_addr;
+ size_t last_mapped_len;
+#endif
+#ifdef PHP_WIN32
+ char *last_mapped_addr;
+ HANDLE file_mapping;
+#endif
+
+ struct stat sb;
+} php_stdio_stream_data;
+#define PHP_STDIOP_GET_FD(anfd, data) anfd = (data)->file ? fileno((data)->file) : (data)->fd
+
+static int do_fstat(php_stdio_stream_data *d, int force)
+{
+ if (!d->cached_fstat || force) {
+ int fd;
+ int r;
+
+ PHP_STDIOP_GET_FD(fd, d);
+ r = fstat(fd, &d->sb);
+ d->cached_fstat = r == 0;
+
+ return r;
+ }
+ return 0;
+}
+
+static php_stream *_php_stream_fopen_from_fd_int(int fd, const char *mode, const char *persistent_id STREAMS_DC TSRMLS_DC)
+{
+ php_stdio_stream_data *self;
+
+ self = pemalloc_rel_orig(sizeof(*self), persistent_id);
+ memset(self, 0, sizeof(*self));
+ self->file = NULL;
+ self->is_pipe = 0;
+ self->lock_flag = LOCK_UN;
+ self->is_process_pipe = 0;
+ self->temp_file_name = NULL;
+ self->fd = fd;
+
+ return php_stream_alloc_rel(&php_stream_stdio_ops, self, persistent_id, mode);
+}
+
+static php_stream *_php_stream_fopen_from_file_int(FILE *file, const char *mode STREAMS_DC TSRMLS_DC)
+{
+ php_stdio_stream_data *self;
+
+ self = emalloc_rel_orig(sizeof(*self));
+ memset(self, 0, sizeof(*self));
+ self->file = file;
+ self->is_pipe = 0;
+ self->lock_flag = LOCK_UN;
+ self->is_process_pipe = 0;
+ self->temp_file_name = NULL;
+ self->fd = fileno(file);
+
+ return php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode);
+}
+
+PHPAPI php_stream *_php_stream_fopen_temporary_file(const char *dir, const char *pfx, char **opened_path STREAMS_DC TSRMLS_DC)
+{
+ int fd = php_open_temporary_fd(dir, pfx, opened_path TSRMLS_CC);
+
+ if (fd != -1) {
+ php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, "r+b", NULL);
+ if (stream) {
+ return stream;
+ }
+ close(fd);
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to allocate stream");
+
+ return NULL;
+ }
+ return NULL;
+}
+
+PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC TSRMLS_DC)
+{
+ char *opened_path = NULL;
+ int fd = php_open_temporary_fd(NULL, "php", &opened_path TSRMLS_CC);
+
+ if (fd != -1) {
+ php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, "r+b", NULL);
+ if (stream) {
+ php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
+ stream->wrapper = &php_plain_files_wrapper;
+ stream->orig_path = estrdup(opened_path);
+
+ self->temp_file_name = opened_path;
+ self->lock_flag = LOCK_UN;
+
+ return stream;
+ }
+ close(fd);
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to allocate stream");
+
+ return NULL;
+ }
+ return NULL;
+}
+
+PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id STREAMS_DC TSRMLS_DC)
+{
+ php_stream *stream = php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id);
+
+ if (stream) {
+ php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
+
+#ifdef S_ISFIFO
+ /* detect if this is a pipe */
+ if (self->fd >= 0) {
+ self->is_pipe = (do_fstat(self, 0) == 0 && S_ISFIFO(self->sb.st_mode)) ? 1 : 0;
+ }
+#elif defined(PHP_WIN32)
+ {
+ zend_uintptr_t handle = _get_osfhandle(self->fd);
+
+ if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) {
+ self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE;
+ }
+ }
+#endif
+
+ if (self->is_pipe) {
+ stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
+ } else {
+ stream->position = lseek(self->fd, 0, SEEK_CUR);
+#ifdef ESPIPE
+ if (stream->position == (off_t)-1 && errno == ESPIPE) {
+ stream->position = 0;
+ stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
+ self->is_pipe = 1;
+ }
+#endif
+ }
+ }
+
+ return stream;
+}
+
+PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STREAMS_DC TSRMLS_DC)
+{
+ php_stream *stream = php_stream_fopen_from_file_int_rel(file, mode);
+
+ if (stream) {
+ php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
+
+#ifdef S_ISFIFO
+ /* detect if this is a pipe */
+ if (self->fd >= 0) {
+ self->is_pipe = (do_fstat(self, 0) == 0 && S_ISFIFO(self->sb.st_mode)) ? 1 : 0;
+ }
+#elif defined(PHP_WIN32)
+ {
+ zend_uintptr_t handle = _get_osfhandle(self->fd);
+
+ if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) {
+ self->is_pipe = GetFileType((HANDLE)handle) == FILE_TYPE_PIPE;
+ }
+ }
+#endif
+
+ if (self->is_pipe) {
+ stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
+ } else {
+ stream->position = ftell(file);
+ }
+ }
+
+ return stream;
+}
+
+PHPAPI php_stream *_php_stream_fopen_from_pipe(FILE *file, const char *mode STREAMS_DC TSRMLS_DC)
+{
+ php_stdio_stream_data *self;
+ php_stream *stream;
+
+ self = emalloc_rel_orig(sizeof(*self));
+ memset(self, 0, sizeof(*self));
+ self->file = file;
+ self->is_pipe = 1;
+ self->lock_flag = LOCK_UN;
+ self->is_process_pipe = 1;
+ self->fd = fileno(file);
+ self->temp_file_name = NULL;
+
+ stream = php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode);
+ stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
+ return stream;
+}
+
+static size_t php_stdiop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
+{
+ php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
+
+ assert(data != NULL);
+
+ if (data->fd >= 0) {
+ int bytes_written = write(data->fd, buf, count);
+ if (bytes_written < 0) return 0;
+ return (size_t) bytes_written;
+ } else {
+
+#if HAVE_FLUSHIO
+ if (!data->is_pipe && data->last_op == 'r') {
+ fseek(data->file, 0, SEEK_CUR);
+ }
+ data->last_op = 'w';
+#endif
+
+ return fwrite(buf, 1, count, data->file);
+ }
+}
+
+static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
+ size_t ret;
+
+ assert(data != NULL);
+
+ if (data->fd >= 0) {
+ ret = read(data->fd, buf, count);
+
+ if (ret == (size_t)-1 && errno == EINTR) {
+ /* Read was interrupted, retry once,
+ If read still fails, giveup with feof==0
+ so script can retry if desired */
+ ret = read(data->fd, buf, count);
+ }
+
+ stream->eof = (ret == 0 || (ret == (size_t)-1 && errno != EWOULDBLOCK && errno != EINTR && errno != EBADF));
+
+ } else {
+#if HAVE_FLUSHIO
+ if (!data->is_pipe && data->last_op == 'w')
+ fseek(data->file, 0, SEEK_CUR);
+ data->last_op = 'r';
+#endif
+
+ ret = fread(buf, 1, count, data->file);
+
+ stream->eof = feof(data->file);
+ }
+ return ret;
+}
+
+static int php_stdiop_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ int ret;
+ php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
+
+ assert(data != NULL);
+
+#if HAVE_MMAP
+ if (data->last_mapped_addr) {
+ munmap(data->last_mapped_addr, data->last_mapped_len);
+ data->last_mapped_addr = NULL;
+ }
+#elif defined(PHP_WIN32)
+ if (data->last_mapped_addr) {
+ UnmapViewOfFile(data->last_mapped_addr);
+ data->last_mapped_addr = NULL;
+ }
+ if (data->file_mapping) {
+ CloseHandle(data->file_mapping);
+ data->file_mapping = NULL;
+ }
+#endif
+
+ if (close_handle) {
+ if (data->file) {
+ if (data->is_process_pipe) {
+ errno = 0;
+ ret = pclose(data->file);
+
+#if HAVE_SYS_WAIT_H
+ if (WIFEXITED(ret)) {
+ ret = WEXITSTATUS(ret);
+ }
+#endif
+ } else {
+ ret = fclose(data->file);
+ data->file = NULL;
+ }
+ } else if (data->fd != -1) {
+ ret = close(data->fd);
+ data->fd = -1;
+ } else {
+ return 0; /* everything should be closed already -> success */
+ }
+ if (data->temp_file_name) {
+ unlink(data->temp_file_name);
+ /* temporary streams are never persistent */
+ efree(data->temp_file_name);
+ data->temp_file_name = NULL;
+ }
+ } else {
+ ret = 0;
+ data->file = NULL;
+ data->fd = -1;
+ }
+
+ pefree(data, stream->is_persistent);
+
+ return ret;
+}
+
+static int php_stdiop_flush(php_stream *stream TSRMLS_DC)
+{
+ php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
+
+ assert(data != NULL);
+
+ /*
+ * stdio buffers data in user land. By calling fflush(3), this
+ * data is send to the kernel using write(2). fsync'ing is
+ * something completely different.
+ */
+ if (data->file) {
+ return fflush(data->file);
+ }
+ return 0;
+}
+
+static int php_stdiop_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
+{
+ php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
+ int ret;
+
+ assert(data != NULL);
+
+ if (data->is_pipe) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot seek on a pipe");
+ return -1;
+ }
+
+ if (data->fd >= 0) {
+ off_t result;
+
+ result = lseek(data->fd, offset, whence);
+ if (result == (off_t)-1)
+ return -1;
+
+ *newoffset = result;
+ return 0;
+
+ } else {
+ ret = fseek(data->file, offset, whence);
+ *newoffset = ftell(data->file);
+ return ret;
+ }
+}
+
+static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
+{
+ int fd;
+ php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
+
+ assert(data != NULL);
+
+ /* as soon as someone touches the stdio layer, buffering may ensue,
+ * so we need to stop using the fd directly in that case */
+
+ switch (castas) {
+ case PHP_STREAM_AS_STDIO:
+ if (ret) {
+
+ if (data->file == NULL) {
+ /* we were opened as a plain file descriptor, so we
+ * need fdopen now */
+ char fixed_mode[5];
+ php_stream_mode_sanitize_fdopen_fopencookie(stream, fixed_mode);
+ data->file = fdopen(data->fd, fixed_mode);
+ if (data->file == NULL) {
+ return FAILURE;
+ }
+ }
+
+ *(FILE**)ret = data->file;
+ data->fd = -1;
+ }
+ return SUCCESS;
+
+ case PHP_STREAM_AS_FD_FOR_SELECT:
+ PHP_STDIOP_GET_FD(fd, data);
+ if (fd < 0) {
+ return FAILURE;
+ }
+ if (ret) {
+ *(int*)ret = fd;
+ }
+ return SUCCESS;
+
+ case PHP_STREAM_AS_FD:
+ PHP_STDIOP_GET_FD(fd, data);
+
+ if (fd < 0) {
+ return FAILURE;
+ }
+ if (data->file) {
+ fflush(data->file);
+ }
+ if (ret) {
+ *(int*)ret = fd;
+ }
+ return SUCCESS;
+ default:
+ return FAILURE;
+ }
+}
+
+static int php_stdiop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
+{
+ int ret;
+ php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
+
+ assert(data != NULL);
+
+ ret = do_fstat(data, 1);
+ memcpy(&ssb->sb, &data->sb, sizeof(ssb->sb));
+ return ret;
+}
+
+static int php_stdiop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
+{
+ php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
+ size_t size;
+ int fd;
+#ifdef O_NONBLOCK
+ /* FIXME: make this work for win32 */
+ int flags;
+ int oldval;
+#endif
+
+ PHP_STDIOP_GET_FD(fd, data);
+
+ switch(option) {
+ case PHP_STREAM_OPTION_BLOCKING:
+ if (fd == -1)
+ return -1;
+#ifdef O_NONBLOCK
+ flags = fcntl(fd, F_GETFL, 0);
+ oldval = (flags & O_NONBLOCK) ? 0 : 1;
+ if (value)
+ flags &= ~O_NONBLOCK;
+ else
+ flags |= O_NONBLOCK;
+
+ if (-1 == fcntl(fd, F_SETFL, flags))
+ return -1;
+ return oldval;
+#else
+ return -1; /* not yet implemented */
+#endif
+
+ case PHP_STREAM_OPTION_WRITE_BUFFER:
+
+ if (data->file == NULL) {
+ return -1;
+ }
+
+ if (ptrparam)
+ size = *(size_t *)ptrparam;
+ else
+ size = BUFSIZ;
+
+ switch(value) {
+ case PHP_STREAM_BUFFER_NONE:
+ return setvbuf(data->file, NULL, _IONBF, 0);
+
+ case PHP_STREAM_BUFFER_LINE:
+ return setvbuf(data->file, NULL, _IOLBF, size);
+
+ case PHP_STREAM_BUFFER_FULL:
+ return setvbuf(data->file, NULL, _IOFBF, size);
+
+ default:
+ return -1;
+ }
+ break;
+
+ case PHP_STREAM_OPTION_LOCKING:
+ if (fd == -1) {
+ return -1;
+ }
+
+ if ((zend_uintptr_t) ptrparam == PHP_STREAM_LOCK_SUPPORTED) {
+ return 0;
+ }
+
+ if (!flock(fd, value)) {
+ data->lock_flag = value;
+ return 0;
+ } else {
+ return -1;
+ }
+ break;
+
+ case PHP_STREAM_OPTION_MMAP_API:
+#if HAVE_MMAP
+ {
+ php_stream_mmap_range *range = (php_stream_mmap_range*)ptrparam;
+ int prot, flags;
+
+ switch (value) {
+ case PHP_STREAM_MMAP_SUPPORTED:
+ return fd == -1 ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
+
+ case PHP_STREAM_MMAP_MAP_RANGE:
+ do_fstat(data, 1);
+ if (range->length == 0 && range->offset > 0 && range->offset < data->sb.st_size) {
+ range->length = data->sb.st_size - range->offset;
+ }
+ if (range->length == 0 || range->length > data->sb.st_size) {
+ range->length = data->sb.st_size;
+ }
+ if (range->offset >= data->sb.st_size) {
+ range->offset = data->sb.st_size;
+ range->length = 0;
+ }
+ switch (range->mode) {
+ case PHP_STREAM_MAP_MODE_READONLY:
+ prot = PROT_READ;
+ flags = MAP_PRIVATE;
+ break;
+ case PHP_STREAM_MAP_MODE_READWRITE:
+ prot = PROT_READ | PROT_WRITE;
+ flags = MAP_PRIVATE;
+ break;
+ case PHP_STREAM_MAP_MODE_SHARED_READONLY:
+ prot = PROT_READ;
+ flags = MAP_SHARED;
+ break;
+ case PHP_STREAM_MAP_MODE_SHARED_READWRITE:
+ prot = PROT_READ | PROT_WRITE;
+ flags = MAP_SHARED;
+ break;
+ default:
+ return PHP_STREAM_OPTION_RETURN_ERR;
+ }
+ range->mapped = (char*)mmap(NULL, range->length, prot, flags, fd, range->offset);
+ if (range->mapped == (char*)MAP_FAILED) {
+ range->mapped = NULL;
+ return PHP_STREAM_OPTION_RETURN_ERR;
+ }
+ /* remember the mapping */
+ data->last_mapped_addr = range->mapped;
+ data->last_mapped_len = range->length;
+ return PHP_STREAM_OPTION_RETURN_OK;
+
+ case PHP_STREAM_MMAP_UNMAP:
+ if (data->last_mapped_addr) {
+ munmap(data->last_mapped_addr, data->last_mapped_len);
+ data->last_mapped_addr = NULL;
+
+ return PHP_STREAM_OPTION_RETURN_OK;
+ }
+ return PHP_STREAM_OPTION_RETURN_ERR;
+ }
+ }
+#elif defined(PHP_WIN32)
+ {
+ php_stream_mmap_range *range = (php_stream_mmap_range*)ptrparam;
+ HANDLE hfile = (HANDLE)_get_osfhandle(fd);
+ DWORD prot, acc, loffs = 0, delta = 0;
+
+ switch (value) {
+ case PHP_STREAM_MMAP_SUPPORTED:
+ return hfile == INVALID_HANDLE_VALUE ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
+
+ case PHP_STREAM_MMAP_MAP_RANGE:
+ switch (range->mode) {
+ case PHP_STREAM_MAP_MODE_READONLY:
+ prot = PAGE_READONLY;
+ acc = FILE_MAP_READ;
+ break;
+ case PHP_STREAM_MAP_MODE_READWRITE:
+ prot = PAGE_READWRITE;
+ acc = FILE_MAP_READ | FILE_MAP_WRITE;
+ break;
+ case PHP_STREAM_MAP_MODE_SHARED_READONLY:
+ prot = PAGE_READONLY;
+ acc = FILE_MAP_READ;
+ /* TODO: we should assign a name for the mapping */
+ break;
+ case PHP_STREAM_MAP_MODE_SHARED_READWRITE:
+ prot = PAGE_READWRITE;
+ acc = FILE_MAP_READ | FILE_MAP_WRITE;
+ /* TODO: we should assign a name for the mapping */
+ break;
+ default:
+ return PHP_STREAM_OPTION_RETURN_ERR;
+ }
+
+ /* create a mapping capable of viewing the whole file (this costs no real resources) */
+ data->file_mapping = CreateFileMapping(hfile, NULL, prot, 0, 0, NULL);
+
+ if (data->file_mapping == NULL) {
+ return PHP_STREAM_OPTION_RETURN_ERR;
+ }
+
+ size = GetFileSize(hfile, NULL);
+ if (range->length == 0 && range->offset > 0 && range->offset < size) {
+ range->length = size - range->offset;
+ }
+ if (range->length == 0 || range->length > size) {
+ range->length = size;
+ }
+ if (range->offset >= size) {
+ range->offset = size;
+ range->length = 0;
+ }
+
+ /* figure out how big a chunk to map to be able to view the part that we need */
+ if (range->offset != 0) {
+ SYSTEM_INFO info;
+ DWORD gran;
+
+ GetSystemInfo(&info);
+ gran = info.dwAllocationGranularity;
+ loffs = (range->offset / gran) * gran;
+ delta = range->offset - loffs;
+ }
+
+ data->last_mapped_addr = MapViewOfFile(data->file_mapping, acc, 0, loffs, range->length + delta);
+
+ if (data->last_mapped_addr) {
+ /* give them back the address of the start offset they requested */
+ range->mapped = data->last_mapped_addr + delta;
+ return PHP_STREAM_OPTION_RETURN_OK;
+ }
+
+ CloseHandle(data->file_mapping);
+ data->file_mapping = NULL;
+
+ return PHP_STREAM_OPTION_RETURN_ERR;
+
+ case PHP_STREAM_MMAP_UNMAP:
+ if (data->last_mapped_addr) {
+ UnmapViewOfFile(data->last_mapped_addr);
+ data->last_mapped_addr = NULL;
+ CloseHandle(data->file_mapping);
+ data->file_mapping = NULL;
+ return PHP_STREAM_OPTION_RETURN_OK;
+ }
+ return PHP_STREAM_OPTION_RETURN_ERR;
+
+ default:
+ return PHP_STREAM_OPTION_RETURN_ERR;
+ }
+ }
+
+#endif
+ return PHP_STREAM_OPTION_RETURN_NOTIMPL;
+
+ case PHP_STREAM_OPTION_TRUNCATE_API:
+ switch (value) {
+ case PHP_STREAM_TRUNCATE_SUPPORTED:
+ return fd == -1 ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
+
+ case PHP_STREAM_TRUNCATE_SET_SIZE: {
+ ptrdiff_t new_size = *(ptrdiff_t*)ptrparam;
+ if (new_size < 0) {
+ return PHP_STREAM_OPTION_RETURN_ERR;
+ }
+ return ftruncate(fd, new_size) == 0 ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
+ }
+ }
+
+ default:
+ return PHP_STREAM_OPTION_RETURN_NOTIMPL;
+ }
+}
+
+PHPAPI php_stream_ops php_stream_stdio_ops = {
+ php_stdiop_write, php_stdiop_read,
+ php_stdiop_close, php_stdiop_flush,
+ "STDIO",
+ php_stdiop_seek,
+ php_stdiop_cast,
+ php_stdiop_stat,
+ php_stdiop_set_option
+};
+/* }}} */
+
+/* {{{ plain files opendir/readdir implementation */
+static size_t php_plain_files_dirstream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ DIR *dir = (DIR*)stream->abstract;
+ /* avoid libc5 readdir problems */
+ char entry[sizeof(struct dirent)+MAXPATHLEN];
+ struct dirent *result = (struct dirent *)&entry;
+ php_stream_dirent *ent = (php_stream_dirent*)buf;
+
+ /* avoid problems if someone mis-uses the stream */
+ if (count != sizeof(php_stream_dirent))
+ return 0;
+
+ if (php_readdir_r(dir, (struct dirent *)entry, &result) == 0 && result) {
+ PHP_STRLCPY(ent->d_name, result->d_name, sizeof(ent->d_name), strlen(result->d_name));
+ return sizeof(php_stream_dirent);
+ }
+ return 0;
+}
+
+static int php_plain_files_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ return closedir((DIR *)stream->abstract);
+}
+
+static int php_plain_files_dirstream_rewind(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC)
+{
+ rewinddir((DIR *)stream->abstract);
+ return 0;
+}
+
+static php_stream_ops php_plain_files_dirstream_ops = {
+ NULL, php_plain_files_dirstream_read,
+ php_plain_files_dirstream_close, NULL,
+ "dir",
+ php_plain_files_dirstream_rewind,
+ NULL, /* cast */
+ NULL, /* stat */
+ NULL /* set_option */
+};
+
+static php_stream *php_plain_files_dir_opener(php_stream_wrapper *wrapper, char *path, char *mode,
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ DIR *dir = NULL;
+ php_stream *stream = NULL;
+
+#ifdef HAVE_GLOB
+ if (options & STREAM_USE_GLOB_DIR_OPEN) {
+ return php_glob_stream_wrapper.wops->dir_opener(&php_glob_stream_wrapper, path, mode, options, opened_path, context STREAMS_REL_CC TSRMLS_CC);
+ }
+#endif
+
+ if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) {
+ return NULL;
+ }
+
+ dir = VCWD_OPENDIR(path);
+
+#ifdef PHP_WIN32
+ if (!dir) {
+ php_win32_docref2_from_error(GetLastError(), path, path TSRMLS_CC);
+ }
+
+ if (dir && dir->finished) {
+ closedir(dir);
+ dir = NULL;
+ }
+#endif
+ if (dir) {
+ stream = php_stream_alloc(&php_plain_files_dirstream_ops, dir, 0, mode);
+ if (stream == NULL)
+ closedir(dir);
+ }
+
+ return stream;
+}
+/* }}} */
+
+/* {{{ php_stream_fopen */
+PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, char **opened_path, int options STREAMS_DC TSRMLS_DC)
+{
+ char *realpath = NULL;
+ int open_flags;
+ int fd;
+ php_stream *ret;
+ int persistent = options & STREAM_OPEN_PERSISTENT;
+ char *persistent_id = NULL;
+
+ if (FAILURE == php_stream_parse_fopen_modes(mode, &open_flags)) {
+ if (options & REPORT_ERRORS) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "`%s' is not a valid mode for fopen", mode);
+ }
+ return NULL;
+ }
+
+ if (options & STREAM_ASSUME_REALPATH) {
+ realpath = estrdup(filename);
+ } else {
+ if ((realpath = expand_filepath(filename, NULL TSRMLS_CC)) == NULL) {
+ return NULL;
+ }
+ }
+
+ if (persistent) {
+ spprintf(&persistent_id, 0, "streams_stdio_%d_%s", open_flags, realpath);
+ switch (php_stream_from_persistent_id(persistent_id, &ret TSRMLS_CC)) {
+ case PHP_STREAM_PERSISTENT_SUCCESS:
+ if (opened_path) {
+ *opened_path = realpath;
+ realpath = NULL;
+ }
+ /* fall through */
+
+ case PHP_STREAM_PERSISTENT_FAILURE:
+ if (realpath) {
+ efree(realpath);
+ }
+ efree(persistent_id);;
+ return ret;
+ }
+ }
+
+ fd = open(realpath, open_flags, 0666);
+
+ if (fd != -1) {
+
+ if (options & STREAM_OPEN_FOR_INCLUDE) {
+ ret = php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id);
+ } else {
+ ret = php_stream_fopen_from_fd_rel(fd, mode, persistent_id);
+ }
+
+ if (ret) {
+ if (opened_path) {
+ *opened_path = realpath;
+ realpath = NULL;
+ }
+ if (realpath) {
+ efree(realpath);
+ }
+ if (persistent_id) {
+ efree(persistent_id);
+ }
+
+ /* WIN32 always set ISREG flag */
+#ifndef PHP_WIN32
+ /* sanity checks for include/require.
+ * We check these after opening the stream, so that we save
+ * on fstat() syscalls */
+ if (options & STREAM_OPEN_FOR_INCLUDE) {
+ php_stdio_stream_data *self = (php_stdio_stream_data*)ret->abstract;
+ int r;
+
+ r = do_fstat(self, 0);
+ if ((r == 0 && !S_ISREG(self->sb.st_mode))) {
+ if (opened_path) {
+ efree(*opened_path);
+ *opened_path = NULL;
+ }
+ php_stream_close(ret);
+ return NULL;
+ }
+ }
+#endif
+
+ return ret;
+ }
+ close(fd);
+ }
+ efree(realpath);
+ if (persistent_id) {
+ efree(persistent_id);
+ }
+ return NULL;
+}
+/* }}} */
+
+
+static php_stream *php_plain_files_stream_opener(php_stream_wrapper *wrapper, char *path, char *mode,
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) {
+ return NULL;
+ }
+
+ return php_stream_fopen_rel(path, mode, opened_path, options);
+}
+
+static int php_plain_files_url_stater(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
+{
+
+ if (strncmp(url, "file://", sizeof("file://") - 1) == 0) {
+ url += sizeof("file://") - 1;
+ }
+
+ if (php_check_open_basedir_ex(url, (flags & PHP_STREAM_URL_STAT_QUIET) ? 0 : 1 TSRMLS_CC)) {
+ return -1;
+ }
+
+#ifdef PHP_WIN32
+ if (EG(windows_version_info).dwMajorVersion >= 5) {
+ if (flags & PHP_STREAM_URL_STAT_LINK) {
+ return VCWD_LSTAT(url, &ssb->sb);
+ }
+ }
+#else
+# ifdef HAVE_SYMLINK
+ if (flags & PHP_STREAM_URL_STAT_LINK) {
+ return VCWD_LSTAT(url, &ssb->sb);
+ } else
+# endif
+#endif
+ return VCWD_STAT(url, &ssb->sb);
+}
+
+static int php_plain_files_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
+{
+ char *p;
+ int ret;
+
+ if ((p = strstr(url, "://")) != NULL) {
+ url = p + 3;
+ }
+
+ if (php_check_open_basedir(url TSRMLS_CC)) {
+ return 0;
+ }
+
+ ret = VCWD_UNLINK(url);
+ if (ret == -1) {
+ if (options & REPORT_ERRORS) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(errno));
+ }
+ return 0;
+ }
+
+ /* Clear stat cache (and realpath cache) */
+ php_clear_stat_cache(1, NULL, 0 TSRMLS_CC);
+
+ return 1;
+}
+
+static int php_plain_files_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC)
+{
+ char *p;
+ int ret;
+
+ if (!url_from || !url_to) {
+ return 0;
+ }
+
+#ifdef PHP_WIN32
+ if (!php_win32_check_trailing_space(url_from, strlen(url_from))) {
+ php_win32_docref2_from_error(ERROR_INVALID_NAME, url_from, url_to TSRMLS_CC);
+ return 0;
+ }
+ if (!php_win32_check_trailing_space(url_to, strlen(url_to))) {
+ php_win32_docref2_from_error(ERROR_INVALID_NAME, url_from, url_to TSRMLS_CC);
+ return 0;
+ }
+#endif
+
+ if ((p = strstr(url_from, "://")) != NULL) {
+ url_from = p + 3;
+ }
+
+ if ((p = strstr(url_to, "://")) != NULL) {
+ url_to = p + 3;
+ }
+
+ if (php_check_open_basedir(url_from TSRMLS_CC) || php_check_open_basedir(url_to TSRMLS_CC)) {
+ return 0;
+ }
+
+ ret = VCWD_RENAME(url_from, url_to);
+
+ if (ret == -1) {
+#ifndef PHP_WIN32
+# ifdef EXDEV
+ if (errno == EXDEV) {
+ struct stat sb;
+ if (php_copy_file(url_from, url_to TSRMLS_CC) == SUCCESS) {
+ if (VCWD_STAT(url_from, &sb) == 0) {
+# if !defined(TSRM_WIN32) && !defined(NETWARE)
+ if (VCWD_CHMOD(url_to, sb.st_mode)) {
+ if (errno == EPERM) {
+ php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
+ VCWD_UNLINK(url_from);
+ return 1;
+ }
+ php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
+ return 0;
+ }
+ if (VCWD_CHOWN(url_to, sb.st_uid, sb.st_gid)) {
+ if (errno == EPERM) {
+ php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
+ VCWD_UNLINK(url_from);
+ return 1;
+ }
+ php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
+ return 0;
+ }
+# endif
+ VCWD_UNLINK(url_from);
+ return 1;
+ }
+ }
+ php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
+ return 0;
+ }
+# endif
+#endif
+
+#ifdef PHP_WIN32
+ php_win32_docref2_from_error(GetLastError(), url_from, url_to TSRMLS_CC);
+#else
+ php_error_docref2(NULL TSRMLS_CC, url_from, url_to, E_WARNING, "%s", strerror(errno));
+#endif
+ return 0;
+ }
+
+ /* Clear stat cache (and realpath cache) */
+ php_clear_stat_cache(1, NULL, 0 TSRMLS_CC);
+
+ return 1;
+}
+
+static int php_plain_files_mkdir(php_stream_wrapper *wrapper, char *dir, int mode, int options, php_stream_context *context TSRMLS_DC)
+{
+ int ret, recursive = options & PHP_STREAM_MKDIR_RECURSIVE;
+ char *p;
+
+ if ((p = strstr(dir, "://")) != NULL) {
+ dir = p + 3;
+ }
+
+ if (!recursive) {
+ ret = php_mkdir(dir, mode TSRMLS_CC);
+ } else {
+ /* we look for directory separator from the end of string, thus hopefuly reducing our work load */
+ char *e;
+ struct stat sb;
+ int dir_len = strlen(dir);
+ int offset = 0;
+ char buf[MAXPATHLEN];
+
+ if (!expand_filepath_with_mode(dir, buf, NULL, 0, CWD_EXPAND TSRMLS_CC)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid path");
+ return 0;
+ }
+
+ e = buf + strlen(buf);
+
+ if ((p = memchr(buf, DEFAULT_SLASH, dir_len))) {
+ offset = p - buf + 1;
+ }
+
+ if (p && dir_len == 1) {
+ /* buf == "DEFAULT_SLASH" */
+ }
+ else {
+ /* find a top level directory we need to create */
+ while ( (p = strrchr(buf + offset, DEFAULT_SLASH)) || (offset != 1 && (p = strrchr(buf, DEFAULT_SLASH))) ) {
+ int n = 0;
+
+ *p = '\0';
+ while (p > buf && *(p-1) == DEFAULT_SLASH) {
+ ++n;
+ --p;
+ *p = '\0';
+ }
+ if (VCWD_STAT(buf, &sb) == 0) {
+ while (1) {
+ *p = DEFAULT_SLASH;
+ if (!n) break;
+ --n;
+ ++p;
+ }
+ break;
+ }
+ }
+ }
+
+ if (p == buf) {
+ ret = php_mkdir(dir, mode TSRMLS_CC);
+ } else if (!(ret = php_mkdir(buf, mode TSRMLS_CC))) {
+ if (!p) {
+ p = buf;
+ }
+ /* create any needed directories if the creation of the 1st directory worked */
+ while (++p != e) {
+ if (*p == '\0') {
+ *p = DEFAULT_SLASH;
+ if ((*(p+1) != '\0') &&
+ (ret = VCWD_MKDIR(buf, (mode_t)mode)) < 0) {
+ if (options & REPORT_ERRORS) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (ret < 0) {
+ /* Failure */
+ return 0;
+ } else {
+ /* Success */
+ return 1;
+ }
+}
+
+static int php_plain_files_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
+{
+#if PHP_WIN32
+ int url_len = strlen(url);
+#endif
+ if (php_check_open_basedir(url TSRMLS_CC)) {
+ return 0;
+ }
+
+#if PHP_WIN32
+ if (!php_win32_check_trailing_space(url, url_len)) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(ENOENT));
+ return 0;
+ }
+#endif
+
+ if (VCWD_RMDIR(url) < 0) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(errno));
+ return 0;
+ }
+
+ /* Clear stat cache (and realpath cache) */
+ php_clear_stat_cache(1, NULL, 0 TSRMLS_CC);
+
+ return 1;
+}
+
+static int php_plain_files_metadata(php_stream_wrapper *wrapper, char *url, int option, void *value, php_stream_context *context TSRMLS_DC)
+{
+ struct utimbuf *newtime;
+ char *p;
+#if !defined(WINDOWS) && !defined(NETWARE)
+ uid_t uid;
+ gid_t gid;
+#endif
+ mode_t mode;
+ int ret = 0;
+#if PHP_WIN32
+ int url_len = strlen(url);
+#endif
+
+#if PHP_WIN32
+ if (!php_win32_check_trailing_space(url, url_len)) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(ENOENT));
+ return 0;
+ }
+#endif
+
+ if ((p = strstr(url, "://")) != NULL) {
+ url = p + 3;
+ }
+
+ if (php_check_open_basedir(url TSRMLS_CC)) {
+ return 0;
+ }
+
+ switch(option) {
+ case PHP_STREAM_META_TOUCH:
+ newtime = (struct utimbuf *)value;
+ if (VCWD_ACCESS(url, F_OK) != 0) {
+ FILE *file = VCWD_FOPEN(url, "w");
+ if (file == NULL) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to create file %s because %s", url, strerror(errno));
+ return 0;
+ }
+ fclose(file);
+ }
+
+ ret = VCWD_UTIME(url, newtime);
+ break;
+#if !defined(WINDOWS) && !defined(NETWARE)
+ case PHP_STREAM_META_OWNER_NAME:
+ case PHP_STREAM_META_OWNER:
+ if(option == PHP_STREAM_META_OWNER_NAME) {
+ if(php_get_uid_by_name((char *)value, &uid TSRMLS_CC) != SUCCESS) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to find uid for %s", (char *)value);
+ return 0;
+ }
+ } else {
+ uid = (uid_t)*(long *)value;
+ }
+ ret = VCWD_CHOWN(url, uid, -1);
+ break;
+ case PHP_STREAM_META_GROUP:
+ case PHP_STREAM_META_GROUP_NAME:
+ if(option == PHP_STREAM_META_OWNER_NAME) {
+ if(php_get_gid_by_name((char *)value, &gid TSRMLS_CC) != SUCCESS) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unable to find gid for %s", (char *)value);
+ return 0;
+ }
+ } else {
+ gid = (gid_t)*(long *)value;
+ }
+ ret = VCWD_CHOWN(url, -1, gid);
+ break;
+#endif
+ case PHP_STREAM_META_ACCESS:
+ mode = (mode_t)*(long *)value;
+ ret = VCWD_CHMOD(url, mode);
+ break;
+ default:
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Unknown option %d for stream_metadata", option);
+ return 0;
+ }
+ if (ret == -1) {
+ php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "Operation failed: %s", strerror(errno));
+ return 0;
+ }
+ php_clear_stat_cache(0, NULL, 0 TSRMLS_CC);
+ return 1;
+}
+
+
+static php_stream_wrapper_ops php_plain_files_wrapper_ops = {
+ php_plain_files_stream_opener,
+ NULL,
+ NULL,
+ php_plain_files_url_stater,
+ php_plain_files_dir_opener,
+ "plainfile",
+ php_plain_files_unlink,
+ php_plain_files_rename,
+ php_plain_files_mkdir,
+ php_plain_files_rmdir,
+ php_plain_files_metadata
+};
+
+php_stream_wrapper php_plain_files_wrapper = {
+ &php_plain_files_wrapper_ops,
+ NULL,
+ 0
+};
+
+/* {{{ php_stream_fopen_with_path */
+PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char *path, char **opened_path, int options STREAMS_DC TSRMLS_DC)
+{
+ /* code ripped off from fopen_wrappers.c */
+ char *pathbuf, *ptr, *end;
+ const char *exec_fname;
+ char trypath[MAXPATHLEN];
+ php_stream *stream;
+ int path_length;
+ int filename_length;
+ int exec_fname_length;
+
+ if (opened_path) {
+ *opened_path = NULL;
+ }
+
+ if(!filename) {
+ return NULL;
+ }
+
+ filename_length = strlen(filename);
+
+ /* Relative path open */
+ if (*filename == '.' && (IS_SLASH(filename[1]) || filename[1] == '.')) {
+ /* further checks, we could have ....... filenames */
+ ptr = filename + 1;
+ if (*ptr == '.') {
+ while (*(++ptr) == '.');
+ if (!IS_SLASH(*ptr)) { /* not a relative path after all */
+ goto not_relative_path;
+ }
+ }
+
+
+ if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(filename TSRMLS_CC)) {
+ return NULL;
+ }
+
+ return php_stream_fopen_rel(filename, mode, opened_path, options);
+ }
+
+not_relative_path:
+
+ /* Absolute path open */
+ if (IS_ABSOLUTE_PATH(filename, filename_length)) {
+
+ if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(filename TSRMLS_CC)) {
+ return NULL;
+ }
+
+ return php_stream_fopen_rel(filename, mode, opened_path, options);
+ }
+
+#ifdef PHP_WIN32
+ if (IS_SLASH(filename[0])) {
+ size_t cwd_len;
+ char *cwd;
+ cwd = virtual_getcwd_ex(&cwd_len TSRMLS_CC);
+ /* getcwd() will return always return [DRIVE_LETTER]:/) on windows. */
+ *(cwd+3) = '\0';
+
+ if (snprintf(trypath, MAXPATHLEN, "%s%s", cwd, filename) >= MAXPATHLEN) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", cwd, filename, MAXPATHLEN);
+ }
+
+ free(cwd);
+
+ if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(trypath TSRMLS_CC)) {
+ return NULL;
+ }
+
+ return php_stream_fopen_rel(trypath, mode, opened_path, options);
+ }
+#endif
+
+ if (!path || (path && !*path)) {
+ return php_stream_fopen_rel(filename, mode, opened_path, options);
+ }
+
+ /* check in provided path */
+ /* append the calling scripts' current working directory
+ * as a fall back case
+ */
+ if (zend_is_executing(TSRMLS_C)) {
+ exec_fname = zend_get_executed_filename(TSRMLS_C);
+ exec_fname_length = strlen(exec_fname);
+ path_length = strlen(path);
+
+ while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
+ if ((exec_fname && exec_fname[0] == '[')
+ || exec_fname_length<=0) {
+ /* [no active file] or no path */
+ pathbuf = estrdup(path);
+ } else {
+ pathbuf = (char *) emalloc(exec_fname_length + path_length +1 +1);
+ memcpy(pathbuf, path, path_length);
+ pathbuf[path_length] = DEFAULT_DIR_SEPARATOR;
+ memcpy(pathbuf+path_length+1, exec_fname, exec_fname_length);
+ pathbuf[path_length + exec_fname_length +1] = '\0';
+ }
+ } else {
+ pathbuf = estrdup(path);
+ }
+
+ ptr = pathbuf;
+
+ while (ptr && *ptr) {
+ end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
+ if (end != NULL) {
+ *end = '\0';
+ end++;
+ }
+ if (*ptr == '\0') {
+ goto stream_skip;
+ }
+ if (snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename) >= MAXPATHLEN) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN);
+ }
+
+ if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir_ex(trypath, 0 TSRMLS_CC)) {
+ goto stream_skip;
+ }
+
+ stream = php_stream_fopen_rel(trypath, mode, opened_path, options);
+ if (stream) {
+ efree(pathbuf);
+ return stream;
+ }
+stream_skip:
+ ptr = end;
+ } /* end provided path */
+
+ efree(pathbuf);
+ return NULL;
+
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/streams/streams.c b/main/streams/streams.c
new file mode 100644
index 0000000..47d86b5
--- /dev/null
+++ b/main/streams/streams.c
@@ -0,0 +1,2397 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Wez Furlong <wez@thebrainroom.com> |
+ | Borrowed code from: |
+ | Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
+ | Jim Winstead <jimw@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#define _GNU_SOURCE
+#include "php.h"
+#include "php_globals.h"
+#include "php_network.h"
+#include "php_open_temporary_file.h"
+#include "ext/standard/file.h"
+#include "ext/standard/basic_functions.h" /* for BG(mmap_file) (not strictly required) */
+#include "ext/standard/php_string.h" /* for php_memnstr, used by php_stream_get_record() */
+#include <stddef.h>
+#include <fcntl.h>
+#include "php_streams_int.h"
+
+/* {{{ resource and registration code */
+/* Global wrapper hash, copied to FG(stream_wrappers) on registration of volatile wrapper */
+static HashTable url_stream_wrappers_hash;
+static int le_stream = FAILURE; /* true global */
+static int le_pstream = FAILURE; /* true global */
+static int le_stream_filter = FAILURE; /* true global */
+
+PHPAPI int php_file_le_stream(void)
+{
+ return le_stream;
+}
+
+PHPAPI int php_file_le_pstream(void)
+{
+ return le_pstream;
+}
+
+PHPAPI int php_file_le_stream_filter(void)
+{
+ return le_stream_filter;
+}
+
+PHPAPI HashTable *_php_stream_get_url_stream_wrappers_hash(TSRMLS_D)
+{
+ return (FG(stream_wrappers) ? FG(stream_wrappers) : &url_stream_wrappers_hash);
+}
+
+PHPAPI HashTable *php_stream_get_url_stream_wrappers_hash_global(void)
+{
+ return &url_stream_wrappers_hash;
+}
+
+static int _php_stream_release_context(zend_rsrc_list_entry *le, void *pContext TSRMLS_DC)
+{
+ if (le->ptr == pContext) {
+ return --le->refcount == 0;
+ }
+ return 0;
+}
+
+static int forget_persistent_resource_id_numbers(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ php_stream *stream;
+
+ if (Z_TYPE_P(rsrc) != le_pstream) {
+ return 0;
+ }
+
+ stream = (php_stream*)rsrc->ptr;
+
+#if STREAM_DEBUG
+fprintf(stderr, "forget_persistent: %s:%p\n", stream->ops->label, stream);
+#endif
+
+ stream->rsrc_id = FAILURE;
+
+ if (stream->context) {
+ zend_hash_apply_with_argument(&EG(regular_list),
+ (apply_func_arg_t) _php_stream_release_context,
+ stream->context TSRMLS_CC);
+ stream->context = NULL;
+ }
+
+ return 0;
+}
+
+PHP_RSHUTDOWN_FUNCTION(streams)
+{
+ zend_hash_apply(&EG(persistent_list), (apply_func_t)forget_persistent_resource_id_numbers TSRMLS_CC);
+ return SUCCESS;
+}
+
+PHPAPI php_stream *php_stream_encloses(php_stream *enclosing, php_stream *enclosed)
+{
+ php_stream *orig = enclosed->enclosing_stream;
+
+ php_stream_auto_cleanup(enclosed);
+ enclosed->enclosing_stream = enclosing;
+ return orig;
+}
+
+PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream **stream TSRMLS_DC)
+{
+ zend_rsrc_list_entry *le;
+
+ if (zend_hash_find(&EG(persistent_list), (char*)persistent_id, strlen(persistent_id)+1, (void*) &le) == SUCCESS) {
+ if (Z_TYPE_P(le) == le_pstream) {
+ if (stream) {
+ HashPosition pos;
+ zend_rsrc_list_entry *regentry;
+ ulong index = -1; /* intentional */
+
+ /* see if this persistent resource already has been loaded to the
+ * regular list; allowing the same resource in several entries in the
+ * regular list causes trouble (see bug #54623) */
+ zend_hash_internal_pointer_reset_ex(&EG(regular_list), &pos);
+ while (zend_hash_get_current_data_ex(&EG(regular_list),
+ (void **)&regentry, &pos) == SUCCESS) {
+ if (regentry->ptr == le->ptr) {
+ zend_hash_get_current_key_ex(&EG(regular_list), NULL, NULL,
+ &index, 0, &pos);
+ break;
+ }
+ zend_hash_move_forward_ex(&EG(regular_list), &pos);
+ }
+
+ *stream = (php_stream*)le->ptr;
+ if (index == -1) { /* not found in regular list */
+ le->refcount++;
+ (*stream)->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, *stream, le_pstream);
+ } else {
+ regentry->refcount++;
+ (*stream)->rsrc_id = index;
+ }
+ }
+ return PHP_STREAM_PERSISTENT_SUCCESS;
+ }
+ return PHP_STREAM_PERSISTENT_FAILURE;
+ }
+ return PHP_STREAM_PERSISTENT_NOT_EXIST;
+}
+
+/* }}} */
+
+static zend_llist *php_get_wrapper_errors_list(php_stream_wrapper *wrapper TSRMLS_DC)
+{
+ zend_llist *list = NULL;
+ if (!FG(wrapper_errors)) {
+ return NULL;
+ } else {
+ zend_hash_find(FG(wrapper_errors), (const char*)&wrapper,
+ sizeof wrapper, (void**)&list);
+ return list;
+ }
+}
+
+/* {{{ wrapper error reporting */
+void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const char *path, const char *caption TSRMLS_DC)
+{
+ char *tmp = estrdup(path);
+ char *msg;
+ int free_msg = 0;
+
+ if (wrapper) {
+ zend_llist *err_list = php_get_wrapper_errors_list(wrapper TSRMLS_CC);
+ if (err_list) {
+ size_t l = 0;
+ int brlen;
+ int i;
+ int count = zend_llist_count(err_list);
+ const char *br;
+ const char **err_buf_p;
+ zend_llist_position pos;
+
+ if (PG(html_errors)) {
+ brlen = 7;
+ br = "<br />\n";
+ } else {
+ brlen = 1;
+ br = "\n";
+ }
+
+ for (err_buf_p = zend_llist_get_first_ex(err_list, &pos), i = 0;
+ err_buf_p;
+ err_buf_p = zend_llist_get_next_ex(err_list, &pos), i++) {
+ l += strlen(*err_buf_p);
+ if (i < count - 1) {
+ l += brlen;
+ }
+ }
+ msg = emalloc(l + 1);
+ msg[0] = '\0';
+ for (err_buf_p = zend_llist_get_first_ex(err_list, &pos), i = 0;
+ err_buf_p;
+ err_buf_p = zend_llist_get_next_ex(err_list, &pos), i++) {
+ strcat(msg, *err_buf_p);
+ if (i < count - 1) {
+ strcat(msg, br);
+ }
+ }
+
+ free_msg = 1;
+ } else {
+ if (wrapper == &php_plain_files_wrapper) {
+ msg = strerror(errno); /* TODO: not ts on linux */
+ } else {
+ msg = "operation failed";
+ }
+ }
+ } else {
+ msg = "no suitable wrapper could be found";
+ }
+
+ php_strip_url_passwd(tmp);
+ php_error_docref1(NULL TSRMLS_CC, tmp, E_WARNING, "%s: %s", caption, msg);
+ efree(tmp);
+ if (free_msg) {
+ efree(msg);
+ }
+}
+
+void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC)
+{
+ if (wrapper && FG(wrapper_errors)) {
+ zend_hash_del(FG(wrapper_errors), (const char*)&wrapper, sizeof wrapper);
+ }
+}
+
+static void wrapper_error_dtor(void *error)
+{
+ efree(*(char**)error);
+}
+
+PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options TSRMLS_DC, const char *fmt, ...)
+{
+ va_list args;
+ char *buffer = NULL;
+
+ va_start(args, fmt);
+ vspprintf(&buffer, 0, fmt, args);
+ va_end(args);
+
+ if (options & REPORT_ERRORS || wrapper == NULL) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", buffer);
+ efree(buffer);
+ } else {
+ zend_llist *list = NULL;
+ if (!FG(wrapper_errors)) {
+ ALLOC_HASHTABLE(FG(wrapper_errors));
+ zend_hash_init(FG(wrapper_errors), 8, NULL,
+ (dtor_func_t)zend_llist_destroy, 0);
+ } else {
+ zend_hash_find(FG(wrapper_errors), (const char*)&wrapper,
+ sizeof wrapper, (void**)&list);
+ }
+
+ if (!list) {
+ zend_llist new_list;
+ zend_llist_init(&new_list, sizeof buffer, wrapper_error_dtor, 0);
+ zend_hash_update(FG(wrapper_errors), (const char*)&wrapper,
+ sizeof wrapper, &new_list, sizeof new_list, (void**)&list);
+ }
+
+ /* append to linked list */
+ zend_llist_add_element(list, &buffer);
+ }
+}
+
+
+/* }}} */
+
+/* allocate a new stream for a particular ops */
+PHPAPI php_stream *_php_stream_alloc(php_stream_ops *ops, void *abstract, const char *persistent_id, const char *mode STREAMS_DC TSRMLS_DC) /* {{{ */
+{
+ php_stream *ret;
+
+ ret = (php_stream*) pemalloc_rel_orig(sizeof(php_stream), persistent_id ? 1 : 0);
+
+ memset(ret, 0, sizeof(php_stream));
+
+ ret->readfilters.stream = ret;
+ ret->writefilters.stream = ret;
+
+#if STREAM_DEBUG
+fprintf(stderr, "stream_alloc: %s:%p persistent=%s\n", ops->label, ret, persistent_id);
+#endif
+
+ ret->ops = ops;
+ ret->abstract = abstract;
+ ret->is_persistent = persistent_id ? 1 : 0;
+ ret->chunk_size = FG(def_chunk_size);
+
+#if ZEND_DEBUG
+ ret->open_filename = __zend_orig_filename ? __zend_orig_filename : __zend_filename;
+ ret->open_lineno = __zend_orig_lineno ? __zend_orig_lineno : __zend_lineno;
+#endif
+
+ if (FG(auto_detect_line_endings)) {
+ ret->flags |= PHP_STREAM_FLAG_DETECT_EOL;
+ }
+
+ if (persistent_id) {
+ zend_rsrc_list_entry le;
+
+ Z_TYPE(le) = le_pstream;
+ le.ptr = ret;
+ le.refcount = 0;
+
+ if (FAILURE == zend_hash_update(&EG(persistent_list), (char *)persistent_id,
+ strlen(persistent_id) + 1,
+ (void *)&le, sizeof(le), NULL)) {
+
+ pefree(ret, 1);
+ return NULL;
+ }
+ }
+
+ ret->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, ret, persistent_id ? le_pstream : le_stream);
+ strlcpy(ret->mode, mode, sizeof(ret->mode));
+
+ ret->wrapper = NULL;
+ ret->wrapperthis = NULL;
+ ret->wrapperdata = NULL;
+ ret->stdiocast = NULL;
+ ret->orig_path = NULL;
+ ret->context = NULL;
+ ret->readbuf = NULL;
+ ret->enclosing_stream = NULL;
+
+ return ret;
+}
+/* }}} */
+
+PHPAPI int _php_stream_free_enclosed(php_stream *stream_enclosed, int close_options TSRMLS_DC) /* {{{ */
+{
+ return _php_stream_free(stream_enclosed,
+ close_options | PHP_STREAM_FREE_IGNORE_ENCLOSING TSRMLS_CC);
+}
+/* }}} */
+
+#if STREAM_DEBUG
+static const char *_php_stream_pretty_free_options(int close_options, char *out)
+{
+ if (close_options & PHP_STREAM_FREE_CALL_DTOR)
+ strcat(out, "CALL_DTOR, ");
+ if (close_options & PHP_STREAM_FREE_RELEASE_STREAM)
+ strcat(out, "RELEASE_STREAM, ");
+ if (close_options & PHP_STREAM_FREE_PRESERVE_HANDLE)
+ strcat(out, "PREVERSE_HANDLE, ");
+ if (close_options & PHP_STREAM_FREE_RSRC_DTOR)
+ strcat(out, "RSRC_DTOR, ");
+ if (close_options & PHP_STREAM_FREE_PERSISTENT)
+ strcat(out, "PERSISTENT, ");
+ if (close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING)
+ strcat(out, "IGNORE_ENCLOSING, ");
+ if (out[0] != '\0')
+ out[strlen(out) - 2] = '\0';
+ return out;
+}
+#endif
+
+static int _php_stream_free_persistent(zend_rsrc_list_entry *le, void *pStream TSRMLS_DC)
+{
+ return le->ptr == pStream;
+}
+
+
+PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* {{{ */
+{
+ int ret = 1;
+ int preserve_handle = close_options & PHP_STREAM_FREE_PRESERVE_HANDLE ? 1 : 0;
+ int release_cast = 1;
+ php_stream_context *context = NULL;
+
+ /* on an resource list destruction, the context, another resource, may have
+ * already been freed (if it was created after the stream resource), so
+ * don't reference it */
+ if (EG(active)) {
+ context = stream->context;
+ }
+
+ if (stream->flags & PHP_STREAM_FLAG_NO_CLOSE) {
+ preserve_handle = 1;
+ }
+
+#if STREAM_DEBUG
+ {
+ char out[200] = "";
+ fprintf(stderr, "stream_free: %s:%p[%s] in_free=%d opts=%s\n",
+ stream->ops->label, stream, stream->orig_path, stream->in_free, _php_stream_pretty_free_options(close_options, out));
+ }
+
+#endif
+
+ if (stream->in_free) {
+ /* hopefully called recursively from the enclosing stream; the pointer was NULLed below */
+ if ((stream->in_free == 1) && (close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING) && (stream->enclosing_stream == NULL)) {
+ close_options |= PHP_STREAM_FREE_RSRC_DTOR; /* restore flag */
+ } else {
+ return 1; /* recursion protection */
+ }
+ }
+
+ stream->in_free++;
+
+ /* force correct order on enclosing/enclosed stream destruction (only from resource
+ * destructor as in when reverse destroying the resource list) */
+ if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) &&
+ !(close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING) &&
+ (close_options & (PHP_STREAM_FREE_CALL_DTOR | PHP_STREAM_FREE_RELEASE_STREAM)) && /* always? */
+ (stream->enclosing_stream != NULL)) {
+ php_stream *enclosing_stream = stream->enclosing_stream;
+ stream->enclosing_stream = NULL;
+ /* we force PHP_STREAM_CALL_DTOR because that's from where the
+ * enclosing stream can free this stream. We remove rsrc_dtor because
+ * we want the enclosing stream to be deleted from the resource list */
+ return _php_stream_free(enclosing_stream,
+ (close_options | PHP_STREAM_FREE_CALL_DTOR) & ~PHP_STREAM_FREE_RSRC_DTOR TSRMLS_CC);
+ }
+
+ /* if we are releasing the stream only (and preserving the underlying handle),
+ * we need to do things a little differently.
+ * We are only ever called like this when the stream is cast to a FILE*
+ * for include (or other similar) purposes.
+ * */
+ if (preserve_handle) {
+ if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) {
+ /* If the stream was fopencookied, we must NOT touch anything
+ * here, as the cookied stream relies on it all.
+ * Instead, mark the stream as OK to auto-clean */
+ php_stream_auto_cleanup(stream);
+ stream->in_free--;
+ return 0;
+ }
+ /* otherwise, make sure that we don't close the FILE* from a cast */
+ release_cast = 0;
+ }
+
+#if STREAM_DEBUG
+fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remove_rsrc=%d\n",
+ stream->ops->label, stream, stream->orig_path, preserve_handle, release_cast,
+ (close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0);
+#endif
+
+ /* make sure everything is saved */
+ _php_stream_flush(stream, 1 TSRMLS_CC);
+
+ /* If not called from the resource dtor, remove the stream from the resource list. */
+ if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0) {
+ /* zend_list_delete actually only decreases the refcount; if we're
+ * releasing the stream, we want to actually delete the resource from
+ * the resource list, otherwise the resource will point to invalid memory.
+ * In any case, let's always completely delete it from the resource list,
+ * not only when PHP_STREAM_FREE_RELEASE_STREAM is set */
+ while (zend_list_delete(stream->rsrc_id) == SUCCESS) {}
+ }
+
+ /* Remove stream from any context link list */
+ if (context && context->links) {
+ php_stream_context_del_link(context, stream);
+ }
+
+ if (close_options & PHP_STREAM_FREE_CALL_DTOR) {
+ if (release_cast && stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) {
+ /* calling fclose on an fopencookied stream will ultimately
+ call this very same function. If we were called via fclose,
+ the cookie_closer unsets the fclose_stdiocast flags, so
+ we can be sure that we only reach here when PHP code calls
+ php_stream_free.
+ Lets let the cookie code clean it all up.
+ */
+ stream->in_free = 0;
+ return fclose(stream->stdiocast);
+ }
+
+ ret = stream->ops->close(stream, preserve_handle ? 0 : 1 TSRMLS_CC);
+ stream->abstract = NULL;
+
+ /* tidy up any FILE* that might have been fdopened */
+ if (release_cast && stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FDOPEN && stream->stdiocast) {
+ fclose(stream->stdiocast);
+ stream->stdiocast = NULL;
+ stream->fclose_stdiocast = PHP_STREAM_FCLOSE_NONE;
+ }
+ }
+
+ if (close_options & PHP_STREAM_FREE_RELEASE_STREAM) {
+ while (stream->readfilters.head) {
+ php_stream_filter_remove(stream->readfilters.head, 1 TSRMLS_CC);
+ }
+ while (stream->writefilters.head) {
+ php_stream_filter_remove(stream->writefilters.head, 1 TSRMLS_CC);
+ }
+
+ if (stream->wrapper && stream->wrapper->wops && stream->wrapper->wops->stream_closer) {
+ stream->wrapper->wops->stream_closer(stream->wrapper, stream TSRMLS_CC);
+ stream->wrapper = NULL;
+ }
+
+ if (stream->wrapperdata) {
+ zval_ptr_dtor(&stream->wrapperdata);
+ stream->wrapperdata = NULL;
+ }
+
+ if (stream->readbuf) {
+ pefree(stream->readbuf, stream->is_persistent);
+ stream->readbuf = NULL;
+ }
+
+ if (stream->is_persistent && (close_options & PHP_STREAM_FREE_PERSISTENT)) {
+ /* we don't work with *stream but need its value for comparison */
+ zend_hash_apply_with_argument(&EG(persistent_list), (apply_func_arg_t) _php_stream_free_persistent, stream TSRMLS_CC);
+ }
+#if ZEND_DEBUG
+ if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) && (stream->__exposed == 0) && (EG(error_reporting) & E_WARNING)) {
+ /* it leaked: Lets deliberately NOT pefree it so that the memory manager shows it
+ * as leaked; it will log a warning, but lets help it out and display what kind
+ * of stream it was. */
+ char *leakinfo;
+ spprintf(&leakinfo, 0, __FILE__ "(%d) : Stream of type '%s' %p (path:%s) was not closed\n", __LINE__, stream->ops->label, stream, stream->orig_path);
+
+ if (stream->orig_path) {
+ pefree(stream->orig_path, stream->is_persistent);
+ stream->orig_path = NULL;
+ }
+
+# if defined(PHP_WIN32)
+ OutputDebugString(leakinfo);
+# else
+ fprintf(stderr, "%s", leakinfo);
+# endif
+ efree(leakinfo);
+ } else {
+ if (stream->orig_path) {
+ pefree(stream->orig_path, stream->is_persistent);
+ stream->orig_path = NULL;
+ }
+
+ pefree(stream, stream->is_persistent);
+ }
+#else
+ if (stream->orig_path) {
+ pefree(stream->orig_path, stream->is_persistent);
+ stream->orig_path = NULL;
+ }
+
+ pefree(stream, stream->is_persistent);
+#endif
+ }
+
+ if (context) {
+ zend_list_delete(context->rsrc_id);
+ }
+
+ return ret;
+}
+/* }}} */
+
+/* {{{ generic stream operations */
+
+static void php_stream_fill_read_buffer(php_stream *stream, size_t size TSRMLS_DC)
+{
+ /* allocate/fill the buffer */
+
+ if (stream->readfilters.head) {
+ char *chunk_buf;
+ int err_flag = 0;
+ php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL };
+ php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out, *brig_swap;
+
+ /* Invalidate the existing cache, otherwise reads can fail, see note in
+ main/streams/filter.c::_php_stream_filter_append */
+ stream->writepos = stream->readpos = 0;
+
+ /* allocate a buffer for reading chunks */
+ chunk_buf = emalloc(stream->chunk_size);
+
+ while (!stream->eof && !err_flag && (stream->writepos - stream->readpos < (off_t)size)) {
+ size_t justread = 0;
+ int flags;
+ php_stream_bucket *bucket;
+ php_stream_filter_status_t status = PSFS_ERR_FATAL;
+ php_stream_filter *filter;
+
+ /* read a chunk into a bucket */
+ justread = stream->ops->read(stream, chunk_buf, stream->chunk_size TSRMLS_CC);
+ if (justread && justread != (size_t)-1) {
+ bucket = php_stream_bucket_new(stream, chunk_buf, justread, 0, 0 TSRMLS_CC);
+
+ /* after this call, bucket is owned by the brigade */
+ php_stream_bucket_append(brig_inp, bucket TSRMLS_CC);
+
+ flags = PSFS_FLAG_NORMAL;
+ } else {
+ flags = stream->eof ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC;
+ }
+
+ /* wind the handle... */
+ for (filter = stream->readfilters.head; filter; filter = filter->next) {
+ status = filter->fops->filter(stream, filter, brig_inp, brig_outp, NULL, flags TSRMLS_CC);
+
+ if (status != PSFS_PASS_ON) {
+ break;
+ }
+
+ /* brig_out becomes brig_in.
+ * brig_in will always be empty here, as the filter MUST attach any un-consumed buckets
+ * to its own brigade */
+ brig_swap = brig_inp;
+ brig_inp = brig_outp;
+ brig_outp = brig_swap;
+ memset(brig_outp, 0, sizeof(*brig_outp));
+ }
+
+ switch (status) {
+ case PSFS_PASS_ON:
+ /* we get here when the last filter in the chain has data to pass on.
+ * in this situation, we are passing the brig_in brigade into the
+ * stream read buffer */
+ while (brig_inp->head) {
+ bucket = brig_inp->head;
+ /* grow buffer to hold this bucket
+ * TODO: this can fail for persistent streams */
+ if (stream->readbuflen - stream->writepos < bucket->buflen) {
+ stream->readbuflen += bucket->buflen;
+ stream->readbuf = perealloc(stream->readbuf, stream->readbuflen,
+ stream->is_persistent);
+ }
+ memcpy(stream->readbuf + stream->writepos, bucket->buf, bucket->buflen);
+ stream->writepos += bucket->buflen;
+
+ php_stream_bucket_unlink(bucket TSRMLS_CC);
+ php_stream_bucket_delref(bucket TSRMLS_CC);
+ }
+ break;
+
+ case PSFS_FEED_ME:
+ /* when a filter needs feeding, there is no brig_out to deal with.
+ * we simply continue the loop; if the caller needs more data,
+ * we will read again, otherwise out job is done here */
+ if (justread == 0) {
+ /* there is no data */
+ err_flag = 1;
+ break;
+ }
+ continue;
+
+ case PSFS_ERR_FATAL:
+ /* some fatal error. Theoretically, the stream is borked, so all
+ * further reads should fail. */
+ err_flag = 1;
+ break;
+ }
+
+ if (justread == 0 || justread == (size_t)-1) {
+ break;
+ }
+ }
+
+ efree(chunk_buf);
+
+ } else {
+ /* is there enough data in the buffer ? */
+ if (stream->writepos - stream->readpos < (off_t)size) {
+ size_t justread = 0;
+
+ /* reduce buffer memory consumption if possible, to avoid a realloc */
+ if (stream->readbuf && stream->readbuflen - stream->writepos < stream->chunk_size) {
+ memmove(stream->readbuf, stream->readbuf + stream->readpos, stream->readbuflen - stream->readpos);
+ stream->writepos -= stream->readpos;
+ stream->readpos = 0;
+ }
+
+ /* grow the buffer if required
+ * TODO: this can fail for persistent streams */
+ if (stream->readbuflen - stream->writepos < stream->chunk_size) {
+ stream->readbuflen += stream->chunk_size;
+ stream->readbuf = perealloc(stream->readbuf, stream->readbuflen,
+ stream->is_persistent);
+ }
+
+ justread = stream->ops->read(stream, stream->readbuf + stream->writepos,
+ stream->readbuflen - stream->writepos
+ TSRMLS_CC);
+
+ if (justread != (size_t)-1) {
+ stream->writepos += justread;
+ }
+ }
+ }
+}
+
+PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS_DC)
+{
+ size_t toread = 0, didread = 0;
+
+ while (size > 0) {
+
+ /* take from the read buffer first.
+ * It is possible that a buffered stream was switched to non-buffered, so we
+ * drain the remainder of the buffer before using the "raw" read mode for
+ * the excess */
+ if (stream->writepos > stream->readpos) {
+
+ toread = stream->writepos - stream->readpos;
+ if (toread > size) {
+ toread = size;
+ }
+
+ memcpy(buf, stream->readbuf + stream->readpos, toread);
+ stream->readpos += toread;
+ size -= toread;
+ buf += toread;
+ didread += toread;
+ }
+
+ /* ignore eof here; the underlying state might have changed */
+ if (size == 0) {
+ break;
+ }
+
+ if (!stream->readfilters.head && (stream->flags & PHP_STREAM_FLAG_NO_BUFFER || stream->chunk_size == 1)) {
+ toread = stream->ops->read(stream, buf, size TSRMLS_CC);
+ } else {
+ php_stream_fill_read_buffer(stream, size TSRMLS_CC);
+
+ toread = stream->writepos - stream->readpos;
+ if (toread > size) {
+ toread = size;
+ }
+
+ if (toread > 0) {
+ memcpy(buf, stream->readbuf + stream->readpos, toread);
+ stream->readpos += toread;
+ }
+ }
+ if (toread > 0) {
+ didread += toread;
+ buf += toread;
+ size -= toread;
+ } else {
+ /* EOF, or temporary end of data (for non-blocking mode). */
+ break;
+ }
+
+ /* just break anyway, to avoid greedy read */
+ if (stream->wrapper != &php_plain_files_wrapper) {
+ break;
+ }
+ }
+
+ if (didread > 0) {
+ stream->position += didread;
+ }
+
+ return didread;
+}
+
+PHPAPI int _php_stream_eof(php_stream *stream TSRMLS_DC)
+{
+ /* if there is data in the buffer, it's not EOF */
+ if (stream->writepos - stream->readpos > 0) {
+ return 0;
+ }
+
+ /* use the configured timeout when checking eof */
+ if (!stream->eof && PHP_STREAM_OPTION_RETURN_ERR ==
+ php_stream_set_option(stream, PHP_STREAM_OPTION_CHECK_LIVENESS,
+ 0, NULL)) {
+ stream->eof = 1;
+ }
+
+ return stream->eof;
+}
+
+PHPAPI int _php_stream_putc(php_stream *stream, int c TSRMLS_DC)
+{
+ unsigned char buf = c;
+
+ if (php_stream_write(stream, &buf, 1) > 0) {
+ return 1;
+ }
+ return EOF;
+}
+
+PHPAPI int _php_stream_getc(php_stream *stream TSRMLS_DC)
+{
+ char buf;
+
+ if (php_stream_read(stream, &buf, 1) > 0) {
+ return buf & 0xff;
+ }
+ return EOF;
+}
+
+PHPAPI int _php_stream_puts(php_stream *stream, char *buf TSRMLS_DC)
+{
+ int len;
+ char newline[2] = "\n"; /* is this OK for Win? */
+ len = strlen(buf);
+
+ if (len > 0 && php_stream_write(stream, buf, len) && php_stream_write(stream, newline, 1)) {
+ return 1;
+ }
+ return 0;
+}
+
+PHPAPI int _php_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
+{
+ memset(ssb, 0, sizeof(*ssb));
+
+ /* if the stream was wrapped, allow the wrapper to stat it */
+ if (stream->wrapper && stream->wrapper->wops->stream_stat != NULL) {
+ return stream->wrapper->wops->stream_stat(stream->wrapper, stream, ssb TSRMLS_CC);
+ }
+
+ /* if the stream doesn't directly support stat-ing, return with failure.
+ * We could try and emulate this by casting to a FD and fstat-ing it,
+ * but since the fd might not represent the actual underlying content
+ * this would give bogus results. */
+ if (stream->ops->stat == NULL) {
+ return -1;
+ }
+
+ return (stream->ops->stat)(stream, ssb TSRMLS_CC);
+}
+
+PHPAPI char *php_stream_locate_eol(php_stream *stream, char *buf, size_t buf_len TSRMLS_DC)
+{
+ size_t avail;
+ char *cr, *lf, *eol = NULL;
+ char *readptr;
+
+ if (!buf) {
+ readptr = stream->readbuf + stream->readpos;
+ avail = stream->writepos - stream->readpos;
+ } else {
+ readptr = buf;
+ avail = buf_len;
+ }
+
+ /* Look for EOL */
+ if (stream->flags & PHP_STREAM_FLAG_DETECT_EOL) {
+ cr = memchr(readptr, '\r', avail);
+ lf = memchr(readptr, '\n', avail);
+
+ if (cr && lf != cr + 1 && !(lf && lf < cr)) {
+ /* mac */
+ stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL;
+ stream->flags |= PHP_STREAM_FLAG_EOL_MAC;
+ eol = cr;
+ } else if ((cr && lf && cr == lf - 1) || (lf)) {
+ /* dos or unix endings */
+ stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL;
+ eol = lf;
+ }
+ } else if (stream->flags & PHP_STREAM_FLAG_EOL_MAC) {
+ eol = memchr(readptr, '\r', avail);
+ } else {
+ /* unix (and dos) line endings */
+ eol = memchr(readptr, '\n', avail);
+ }
+
+ return eol;
+}
+
+/* If buf == NULL, the buffer will be allocated automatically and will be of an
+ * appropriate length to hold the line, regardless of the line length, memory
+ * permitting */
+PHPAPI char *_php_stream_get_line(php_stream *stream, char *buf, size_t maxlen,
+ size_t *returned_len TSRMLS_DC)
+{
+ size_t avail = 0;
+ size_t current_buf_size = 0;
+ size_t total_copied = 0;
+ int grow_mode = 0;
+ char *bufstart = buf;
+
+ if (buf == NULL) {
+ grow_mode = 1;
+ } else if (maxlen == 0) {
+ return NULL;
+ }
+
+ /*
+ * If the underlying stream operations block when no new data is readable,
+ * we need to take extra precautions.
+ *
+ * If there is buffered data available, we check for a EOL. If it exists,
+ * we pass the data immediately back to the caller. This saves a call
+ * to the read implementation and will not block where blocking
+ * is not necessary at all.
+ *
+ * If the stream buffer contains more data than the caller requested,
+ * we can also avoid that costly step and simply return that data.
+ */
+
+ for (;;) {
+ avail = stream->writepos - stream->readpos;
+
+ if (avail > 0) {
+ size_t cpysz = 0;
+ char *readptr;
+ char *eol;
+ int done = 0;
+
+ readptr = stream->readbuf + stream->readpos;
+ eol = php_stream_locate_eol(stream, NULL, 0 TSRMLS_CC);
+
+ if (eol) {
+ cpysz = eol - readptr + 1;
+ done = 1;
+ } else {
+ cpysz = avail;
+ }
+
+ if (grow_mode) {
+ /* allow room for a NUL. If this realloc is really a realloc
+ * (ie: second time around), we get an extra byte. In most
+ * cases, with the default chunk size of 8K, we will only
+ * incur that overhead once. When people have lines longer
+ * than 8K, we waste 1 byte per additional 8K or so.
+ * That seems acceptable to me, to avoid making this code
+ * hard to follow */
+ bufstart = erealloc(bufstart, current_buf_size + cpysz + 1);
+ current_buf_size += cpysz + 1;
+ buf = bufstart + total_copied;
+ } else {
+ if (cpysz >= maxlen - 1) {
+ cpysz = maxlen - 1;
+ done = 1;
+ }
+ }
+
+ memcpy(buf, readptr, cpysz);
+
+ stream->position += cpysz;
+ stream->readpos += cpysz;
+ buf += cpysz;
+ maxlen -= cpysz;
+ total_copied += cpysz;
+
+ if (done) {
+ break;
+ }
+ } else if (stream->eof) {
+ break;
+ } else {
+ /* XXX: Should be fine to always read chunk_size */
+ size_t toread;
+
+ if (grow_mode) {
+ toread = stream->chunk_size;
+ } else {
+ toread = maxlen - 1;
+ if (toread > stream->chunk_size) {
+ toread = stream->chunk_size;
+ }
+ }
+
+ php_stream_fill_read_buffer(stream, toread TSRMLS_CC);
+
+ if (stream->writepos - stream->readpos == 0) {
+ break;
+ }
+ }
+ }
+
+ if (total_copied == 0) {
+ if (grow_mode) {
+ assert(bufstart == NULL);
+ }
+ return NULL;
+ }
+
+ buf[0] = '\0';
+ if (returned_len) {
+ *returned_len = total_copied;
+ }
+
+ return bufstart;
+}
+
+#define STREAM_BUFFERED_AMOUNT(stream) \
+ ((size_t)(((stream)->writepos) - (stream)->readpos))
+
+static char *_php_stream_search_delim(php_stream *stream,
+ size_t maxlen,
+ size_t skiplen,
+ char *delim, /* non-empty! */
+ size_t delim_len TSRMLS_DC)
+{
+ size_t seek_len;
+
+ /* set the maximum number of bytes we're allowed to read from buffer */
+ seek_len = MIN(STREAM_BUFFERED_AMOUNT(stream), maxlen);
+ if (seek_len <= skiplen) {
+ return NULL;
+ }
+
+ if (delim_len == 1) {
+ return memchr(&stream->readbuf[stream->readpos + skiplen],
+ delim[0], seek_len - skiplen);
+ } else {
+ return php_memnstr((char*)&stream->readbuf[stream->readpos + skiplen],
+ delim, delim_len,
+ (char*)&stream->readbuf[stream->readpos + seek_len]);
+ }
+}
+
+PHPAPI char *php_stream_get_record(php_stream *stream, size_t maxlen, size_t *returned_len, char *delim, size_t delim_len TSRMLS_DC)
+{
+ char *ret_buf, /* returned buffer */
+ *found_delim = NULL;
+ size_t buffered_len,
+ tent_ret_len; /* tentative returned length */
+ int has_delim = delim_len > 0;
+
+ if (maxlen == 0) {
+ return NULL;
+ }
+
+ if (has_delim) {
+ found_delim = _php_stream_search_delim(
+ stream, maxlen, 0, delim, delim_len TSRMLS_CC);
+ }
+
+ buffered_len = STREAM_BUFFERED_AMOUNT(stream);
+ /* try to read up to maxlen length bytes while we don't find the delim */
+ while (!found_delim && buffered_len < maxlen) {
+ size_t just_read,
+ to_read_now;
+
+ to_read_now = MIN(maxlen - buffered_len, stream->chunk_size);
+
+ php_stream_fill_read_buffer(stream, buffered_len + to_read_now TSRMLS_CC);
+
+ just_read = STREAM_BUFFERED_AMOUNT(stream) - buffered_len;
+
+ /* Assume the stream is temporarily or permanently out of data */
+ if (just_read == 0) {
+ break;
+ }
+
+ if (has_delim) {
+ /* search for delimiter, but skip buffered_len (the number of bytes
+ * buffered before this loop iteration), as they have already been
+ * searched for the delimiter.
+ * The left part of the delimiter may still remain in the buffer,
+ * so subtract up to <delim_len - 1> from buffered_len, which is
+ * the ammount of data we skip on this search as an optimization
+ */
+ found_delim = _php_stream_search_delim(
+ stream, maxlen,
+ buffered_len >= (delim_len - 1)
+ ? buffered_len - (delim_len - 1)
+ : 0,
+ delim, delim_len TSRMLS_CC);
+ if (found_delim) {
+ break;
+ }
+ }
+ buffered_len += just_read;
+ }
+
+ if (has_delim && found_delim) {
+ tent_ret_len = found_delim - (char*)&stream->readbuf[stream->readpos];
+ } else if (!has_delim && STREAM_BUFFERED_AMOUNT(stream) >= maxlen) {
+ tent_ret_len = maxlen;
+ } else {
+ /* return with error if the delimiter string (if any) was not found, we
+ * could not completely fill the read buffer with maxlen bytes and we
+ * don't know we've reached end of file. Added with non-blocking streams
+ * in mind, where this situation is frequent */
+ if (STREAM_BUFFERED_AMOUNT(stream) < maxlen && !stream->eof) {
+ return NULL;
+ } else if (STREAM_BUFFERED_AMOUNT(stream) == 0 && stream->eof) {
+ /* refuse to return an empty string just because by accident
+ * we knew of EOF in a read that returned no data */
+ return NULL;
+ } else {
+ tent_ret_len = MIN(STREAM_BUFFERED_AMOUNT(stream), maxlen);
+ }
+ }
+
+ ret_buf = emalloc(tent_ret_len + 1);
+ /* php_stream_read will not call ops->read here because the necessary
+ * data is guaranteedly buffered */
+ *returned_len = php_stream_read(stream, ret_buf, tent_ret_len);
+
+ if (found_delim) {
+ stream->readpos += delim_len;
+ stream->position += delim_len;
+ }
+ ret_buf[*returned_len] = '\0';
+ return ret_buf;
+}
+
+/* Writes a buffer directly to a stream, using multiple of the chunk size */
+static size_t _php_stream_write_buffer(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
+{
+ size_t didwrite = 0, towrite, justwrote;
+
+ /* if we have a seekable stream we need to ensure that data is written at the
+ * current stream->position. This means invalidating the read buffer and then
+ * performing a low-level seek */
+ if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && stream->readpos != stream->writepos) {
+ stream->readpos = stream->writepos = 0;
+
+ stream->ops->seek(stream, stream->position, SEEK_SET, &stream->position TSRMLS_CC);
+ }
+
+
+ while (count > 0) {
+ towrite = count;
+ if (towrite > stream->chunk_size)
+ towrite = stream->chunk_size;
+
+ justwrote = stream->ops->write(stream, buf, towrite TSRMLS_CC);
+
+ /* convert justwrote to an integer, since normally it is unsigned */
+ if ((int)justwrote > 0) {
+ buf += justwrote;
+ count -= justwrote;
+ didwrite += justwrote;
+
+ /* Only screw with the buffer if we can seek, otherwise we lose data
+ * buffered from fifos and sockets */
+ if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) {
+ stream->position += justwrote;
+ }
+ } else {
+ break;
+ }
+ }
+ return didwrite;
+
+}
+
+/* push some data through the write filter chain.
+ * buf may be NULL, if flags are set to indicate a flush.
+ * This may trigger a real write to the stream.
+ * Returns the number of bytes consumed from buf by the first filter in the chain.
+ * */
+static size_t _php_stream_write_filtered(php_stream *stream, const char *buf, size_t count, int flags TSRMLS_DC)
+{
+ size_t consumed = 0;
+ php_stream_bucket *bucket;
+ php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL };
+ php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out, *brig_swap;
+ php_stream_filter_status_t status = PSFS_ERR_FATAL;
+ php_stream_filter *filter;
+
+ if (buf) {
+ bucket = php_stream_bucket_new(stream, (char *)buf, count, 0, 0 TSRMLS_CC);
+ php_stream_bucket_append(&brig_in, bucket TSRMLS_CC);
+ }
+
+ for (filter = stream->writefilters.head; filter; filter = filter->next) {
+ /* for our return value, we are interested in the number of bytes consumed from
+ * the first filter in the chain */
+ status = filter->fops->filter(stream, filter, brig_inp, brig_outp,
+ filter == stream->writefilters.head ? &consumed : NULL, flags TSRMLS_CC);
+
+ if (status != PSFS_PASS_ON) {
+ break;
+ }
+ /* brig_out becomes brig_in.
+ * brig_in will always be empty here, as the filter MUST attach any un-consumed buckets
+ * to its own brigade */
+ brig_swap = brig_inp;
+ brig_inp = brig_outp;
+ brig_outp = brig_swap;
+ memset(brig_outp, 0, sizeof(*brig_outp));
+ }
+
+ switch (status) {
+ case PSFS_PASS_ON:
+ /* filter chain generated some output; push it through to the
+ * underlying stream */
+ while (brig_inp->head) {
+ bucket = brig_inp->head;
+ _php_stream_write_buffer(stream, bucket->buf, bucket->buflen TSRMLS_CC);
+ /* Potential error situation - eg: no space on device. Perhaps we should keep this brigade
+ * hanging around and try to write it later.
+ * At the moment, we just drop it on the floor
+ * */
+
+ php_stream_bucket_unlink(bucket TSRMLS_CC);
+ php_stream_bucket_delref(bucket TSRMLS_CC);
+ }
+ break;
+ case PSFS_FEED_ME:
+ /* need more data before we can push data through to the stream */
+ break;
+
+ case PSFS_ERR_FATAL:
+ /* some fatal error. Theoretically, the stream is borked, so all
+ * further writes should fail. */
+ break;
+ }
+
+ return consumed;
+}
+
+PHPAPI int _php_stream_flush(php_stream *stream, int closing TSRMLS_DC)
+{
+ int ret = 0;
+
+ if (stream->writefilters.head) {
+ _php_stream_write_filtered(stream, NULL, 0, closing ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC TSRMLS_CC);
+ }
+
+ if (stream->ops->flush) {
+ ret = stream->ops->flush(stream TSRMLS_CC);
+ }
+
+ return ret;
+}
+
+PHPAPI size_t _php_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
+{
+ if (buf == NULL || count == 0 || stream->ops->write == NULL) {
+ return 0;
+ }
+
+ if (stream->writefilters.head) {
+ return _php_stream_write_filtered(stream, buf, count, PSFS_FLAG_NORMAL TSRMLS_CC);
+ } else {
+ return _php_stream_write_buffer(stream, buf, count TSRMLS_CC);
+ }
+}
+
+PHPAPI size_t _php_stream_printf(php_stream *stream TSRMLS_DC, const char *fmt, ...)
+{
+ size_t count;
+ char *buf;
+ va_list ap;
+
+ va_start(ap, fmt);
+ count = vspprintf(&buf, 0, fmt, ap);
+ va_end(ap);
+
+ if (!buf) {
+ return 0; /* error condition */
+ }
+
+ count = php_stream_write(stream, buf, count);
+ efree(buf);
+
+ return count;
+}
+
+PHPAPI off_t _php_stream_tell(php_stream *stream TSRMLS_DC)
+{
+ return stream->position;
+}
+
+PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_DC)
+{
+ if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) {
+ /* flush to commit data written to the fopencookie FILE* */
+ fflush(stream->stdiocast);
+ }
+
+ /* handle the case where we are in the buffer */
+ if ((stream->flags & PHP_STREAM_FLAG_NO_BUFFER) == 0) {
+ switch(whence) {
+ case SEEK_CUR:
+ if (offset > 0 && offset <= stream->writepos - stream->readpos) {
+ stream->readpos += offset; /* if offset = ..., then readpos = writepos */
+ stream->position += offset;
+ stream->eof = 0;
+ return 0;
+ }
+ break;
+ case SEEK_SET:
+ if (offset > stream->position &&
+ offset <= stream->position + stream->writepos - stream->readpos) {
+ stream->readpos += offset - stream->position;
+ stream->position = offset;
+ stream->eof = 0;
+ return 0;
+ }
+ break;
+ }
+ }
+
+
+ if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) {
+ int ret;
+
+ if (stream->writefilters.head) {
+ _php_stream_flush(stream, 0 TSRMLS_CC);
+ }
+
+ switch(whence) {
+ case SEEK_CUR:
+ offset = stream->position + offset;
+ whence = SEEK_SET;
+ break;
+ }
+ ret = stream->ops->seek(stream, offset, whence, &stream->position TSRMLS_CC);
+
+ if (((stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) || ret == 0) {
+ if (ret == 0) {
+ stream->eof = 0;
+ }
+
+ /* invalidate the buffer contents */
+ stream->readpos = stream->writepos = 0;
+
+ return ret;
+ }
+ /* else the stream has decided that it can't support seeking after all;
+ * fall through to attempt emulation */
+ }
+
+ /* emulate forward moving seeks with reads */
+ if (whence == SEEK_CUR && offset >= 0) {
+ char tmp[1024];
+ size_t didread;
+ while(offset > 0) {
+ if ((didread = php_stream_read(stream, tmp, MIN(offset, sizeof(tmp)))) == 0) {
+ return -1;
+ }
+ offset -= didread;
+ }
+ stream->eof = 0;
+ return 0;
+ }
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream does not support seeking");
+
+ return -1;
+}
+
+PHPAPI int _php_stream_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
+{
+ int ret = PHP_STREAM_OPTION_RETURN_NOTIMPL;
+
+ if (stream->ops->set_option) {
+ ret = stream->ops->set_option(stream, option, value, ptrparam TSRMLS_CC);
+ }
+
+ if (ret == PHP_STREAM_OPTION_RETURN_NOTIMPL) {
+ switch(option) {
+ case PHP_STREAM_OPTION_SET_CHUNK_SIZE:
+ ret = stream->chunk_size;
+ stream->chunk_size = value;
+ return ret;
+
+ case PHP_STREAM_OPTION_READ_BUFFER:
+ /* try to match the buffer mode as best we can */
+ if (value == PHP_STREAM_BUFFER_NONE) {
+ stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
+ } else if (stream->flags & PHP_STREAM_FLAG_NO_BUFFER) {
+ stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;
+ }
+ ret = PHP_STREAM_OPTION_RETURN_OK;
+ break;
+
+ default:
+ ;
+ }
+ }
+
+ return ret;
+}
+
+PHPAPI int _php_stream_truncate_set_size(php_stream *stream, size_t newsize TSRMLS_DC)
+{
+ return php_stream_set_option(stream, PHP_STREAM_OPTION_TRUNCATE_API, PHP_STREAM_TRUNCATE_SET_SIZE, &newsize);
+}
+
+PHPAPI size_t _php_stream_passthru(php_stream * stream STREAMS_DC TSRMLS_DC)
+{
+ size_t bcount = 0;
+ char buf[8192];
+ int b;
+
+ if (php_stream_mmap_possible(stream)) {
+ char *p;
+ size_t mapped;
+
+ p = php_stream_mmap_range(stream, php_stream_tell(stream), PHP_STREAM_MMAP_ALL, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped);
+
+ if (p) {
+ PHPWRITE(p, mapped);
+
+ php_stream_mmap_unmap_ex(stream, mapped);
+
+ return mapped;
+ }
+ }
+
+ while ((b = php_stream_read(stream, buf, sizeof(buf))) > 0) {
+ PHPWRITE(buf, b);
+ bcount += b;
+ }
+
+ return bcount;
+}
+
+
+PHPAPI size_t _php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen, int persistent STREAMS_DC TSRMLS_DC)
+{
+ size_t ret = 0;
+ char *ptr;
+ size_t len = 0, max_len;
+ int step = CHUNK_SIZE;
+ int min_room = CHUNK_SIZE / 4;
+ php_stream_statbuf ssbuf;
+
+ if (maxlen == 0) {
+ return 0;
+ }
+
+ if (maxlen == PHP_STREAM_COPY_ALL) {
+ maxlen = 0;
+ }
+
+ if (maxlen > 0) {
+ ptr = *buf = pemalloc_rel_orig(maxlen + 1, persistent);
+ while ((len < maxlen) && !php_stream_eof(src)) {
+ ret = php_stream_read(src, ptr, maxlen - len);
+ if (!ret) {
+ break;
+ }
+ len += ret;
+ ptr += ret;
+ }
+ if (len) {
+ *ptr = '\0';
+ } else {
+ pefree(*buf, persistent);
+ *buf = NULL;
+ }
+ return len;
+ }
+
+ /* avoid many reallocs by allocating a good sized chunk to begin with, if
+ * we can. Note that the stream may be filtered, in which case the stat
+ * result may be inaccurate, as the filter may inflate or deflate the
+ * number of bytes that we can read. In order to avoid an upsize followed
+ * by a downsize of the buffer, overestimate by the step size (which is
+ * 2K). */
+ if (php_stream_stat(src, &ssbuf) == 0 && ssbuf.sb.st_size > 0) {
+ max_len = ssbuf.sb.st_size + step;
+ } else {
+ max_len = step;
+ }
+
+ ptr = *buf = pemalloc_rel_orig(max_len, persistent);
+
+ while((ret = php_stream_read(src, ptr, max_len - len))) {
+ len += ret;
+ if (len + min_room >= max_len) {
+ *buf = perealloc_rel_orig(*buf, max_len + step, persistent);
+ max_len += step;
+ ptr = *buf + len;
+ } else {
+ ptr += ret;
+ }
+ }
+ if (len) {
+ *buf = perealloc_rel_orig(*buf, len + 1, persistent);
+ (*buf)[len] = '\0';
+ } else {
+ pefree(*buf, persistent);
+ *buf = NULL;
+ }
+ return len;
+}
+
+/* Returns SUCCESS/FAILURE and sets *len to the number of bytes moved */
+PHPAPI int _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC)
+{
+ char buf[CHUNK_SIZE];
+ size_t readchunk;
+ size_t haveread = 0;
+ size_t didread;
+ size_t dummy;
+ php_stream_statbuf ssbuf;
+
+ if (!len) {
+ len = &dummy;
+ }
+
+ if (maxlen == 0) {
+ *len = 0;
+ return SUCCESS;
+ }
+
+ if (maxlen == PHP_STREAM_COPY_ALL) {
+ maxlen = 0;
+ }
+
+ if (php_stream_stat(src, &ssbuf) == 0) {
+ if (ssbuf.sb.st_size == 0
+#ifdef S_ISREG
+ && S_ISREG(ssbuf.sb.st_mode)
+#endif
+ ) {
+ *len = 0;
+ return SUCCESS;
+ }
+ }
+
+ if (php_stream_mmap_possible(src)) {
+ char *p;
+ size_t mapped;
+
+ p = php_stream_mmap_range(src, php_stream_tell(src), maxlen, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped);
+
+ if (p) {
+ mapped = php_stream_write(dest, p, mapped);
+
+ php_stream_mmap_unmap_ex(src, mapped);
+
+ *len = mapped;
+
+ /* we've got at least 1 byte to read.
+ * less than 1 is an error */
+
+ if (mapped > 0) {
+ return SUCCESS;
+ }
+ return FAILURE;
+ }
+ }
+
+ while(1) {
+ readchunk = sizeof(buf);
+
+ if (maxlen && (maxlen - haveread) < readchunk) {
+ readchunk = maxlen - haveread;
+ }
+
+ didread = php_stream_read(src, buf, readchunk);
+
+ if (didread) {
+ /* extra paranoid */
+ size_t didwrite, towrite;
+ char *writeptr;
+
+ towrite = didread;
+ writeptr = buf;
+ haveread += didread;
+
+ while(towrite) {
+ didwrite = php_stream_write(dest, writeptr, towrite);
+ if (didwrite == 0) {
+ *len = haveread - (didread - towrite);
+ return FAILURE;
+ }
+
+ towrite -= didwrite;
+ writeptr += didwrite;
+ }
+ } else {
+ break;
+ }
+
+ if (maxlen - haveread == 0) {
+ break;
+ }
+ }
+
+ *len = haveread;
+
+ /* we've got at least 1 byte to read.
+ * less than 1 is an error */
+
+ if (haveread > 0 || src->eof) {
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+
+/* Returns the number of bytes moved.
+ * Returns 1 when source len is 0.
+ * Deprecated in favor of php_stream_copy_to_stream_ex() */
+ZEND_ATTRIBUTE_DEPRECATED
+PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, size_t maxlen STREAMS_DC TSRMLS_DC)
+{
+ size_t len;
+ int ret = _php_stream_copy_to_stream_ex(src, dest, maxlen, &len STREAMS_REL_CC TSRMLS_CC);
+ if (ret == SUCCESS && len == 0 && maxlen != 0) {
+ return 1;
+ }
+ return len;
+}
+/* }}} */
+
+/* {{{ wrapper init and registration */
+
+static void stream_resource_regular_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ php_stream *stream = (php_stream*)rsrc->ptr;
+ /* set the return value for pclose */
+ FG(pclose_ret) = php_stream_free(stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR);
+}
+
+static void stream_resource_persistent_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ php_stream *stream = (php_stream*)rsrc->ptr;
+ FG(pclose_ret) = php_stream_free(stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR);
+}
+
+void php_shutdown_stream_hashes(TSRMLS_D)
+{
+ if (FG(stream_wrappers)) {
+ zend_hash_destroy(FG(stream_wrappers));
+ efree(FG(stream_wrappers));
+ FG(stream_wrappers) = NULL;
+ }
+
+ if (FG(stream_filters)) {
+ zend_hash_destroy(FG(stream_filters));
+ efree(FG(stream_filters));
+ FG(stream_filters) = NULL;
+ }
+
+ if (FG(wrapper_errors)) {
+ zend_hash_destroy(FG(wrapper_errors));
+ efree(FG(wrapper_errors));
+ FG(wrapper_errors) = NULL;
+ }
+}
+
+int php_init_stream_wrappers(int module_number TSRMLS_DC)
+{
+ le_stream = zend_register_list_destructors_ex(stream_resource_regular_dtor, NULL, "stream", module_number);
+ le_pstream = zend_register_list_destructors_ex(NULL, stream_resource_persistent_dtor, "persistent stream", module_number);
+
+ /* Filters are cleaned up by the streams they're attached to */
+ le_stream_filter = zend_register_list_destructors_ex(NULL, NULL, "stream filter", module_number);
+
+ return (
+ zend_hash_init(&url_stream_wrappers_hash, 0, NULL, NULL, 1) == SUCCESS
+ &&
+ zend_hash_init(php_get_stream_filters_hash_global(), 0, NULL, NULL, 1) == SUCCESS
+ &&
+ zend_hash_init(php_stream_xport_get_hash(), 0, NULL, NULL, 1) == SUCCESS
+ &&
+ php_stream_xport_register("tcp", php_stream_generic_socket_factory TSRMLS_CC) == SUCCESS
+ &&
+ php_stream_xport_register("udp", php_stream_generic_socket_factory TSRMLS_CC) == SUCCESS
+#if defined(AF_UNIX) && !(defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE))
+ &&
+ php_stream_xport_register("unix", php_stream_generic_socket_factory TSRMLS_CC) == SUCCESS
+ &&
+ php_stream_xport_register("udg", php_stream_generic_socket_factory TSRMLS_CC) == SUCCESS
+#endif
+ ) ? SUCCESS : FAILURE;
+}
+
+int php_shutdown_stream_wrappers(int module_number TSRMLS_DC)
+{
+ zend_hash_destroy(&url_stream_wrappers_hash);
+ zend_hash_destroy(php_get_stream_filters_hash_global());
+ zend_hash_destroy(php_stream_xport_get_hash());
+ return SUCCESS;
+}
+
+/* Validate protocol scheme names during registration
+ * Must conform to /^[a-zA-Z0-9+.-]+$/
+ */
+static inline int php_stream_wrapper_scheme_validate(char *protocol, int protocol_len)
+{
+ int i;
+
+ for(i = 0; i < protocol_len; i++) {
+ if (!isalnum((int)protocol[i]) &&
+ protocol[i] != '+' &&
+ protocol[i] != '-' &&
+ protocol[i] != '.') {
+ return FAILURE;
+ }
+ }
+
+ return SUCCESS;
+}
+
+/* API for registering GLOBAL wrappers */
+PHPAPI int php_register_url_stream_wrapper(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC)
+{
+ int protocol_len = strlen(protocol);
+
+ if (php_stream_wrapper_scheme_validate(protocol, protocol_len) == FAILURE) {
+ return FAILURE;
+ }
+
+ return zend_hash_add(&url_stream_wrappers_hash, protocol, protocol_len + 1, &wrapper, sizeof(wrapper), NULL);
+}
+
+PHPAPI int php_unregister_url_stream_wrapper(char *protocol TSRMLS_DC)
+{
+ return zend_hash_del(&url_stream_wrappers_hash, protocol, strlen(protocol) + 1);
+}
+
+static void clone_wrapper_hash(TSRMLS_D)
+{
+ php_stream_wrapper *tmp;
+
+ ALLOC_HASHTABLE(FG(stream_wrappers));
+ zend_hash_init(FG(stream_wrappers), zend_hash_num_elements(&url_stream_wrappers_hash), NULL, NULL, 1);
+ zend_hash_copy(FG(stream_wrappers), &url_stream_wrappers_hash, NULL, &tmp, sizeof(tmp));
+}
+
+/* API for registering VOLATILE wrappers */
+PHPAPI int php_register_url_stream_wrapper_volatile(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC)
+{
+ int protocol_len = strlen(protocol);
+
+ if (php_stream_wrapper_scheme_validate(protocol, protocol_len) == FAILURE) {
+ return FAILURE;
+ }
+
+ if (!FG(stream_wrappers)) {
+ clone_wrapper_hash(TSRMLS_C);
+ }
+
+ return zend_hash_add(FG(stream_wrappers), protocol, protocol_len + 1, &wrapper, sizeof(wrapper), NULL);
+}
+
+PHPAPI int php_unregister_url_stream_wrapper_volatile(char *protocol TSRMLS_DC)
+{
+ if (!FG(stream_wrappers)) {
+ clone_wrapper_hash(TSRMLS_C);
+ }
+
+ return zend_hash_del(FG(stream_wrappers), protocol, strlen(protocol) + 1);
+}
+/* }}} */
+
+/* {{{ php_stream_locate_url_wrapper */
+PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, char **path_for_open, int options TSRMLS_DC)
+{
+ HashTable *wrapper_hash = (FG(stream_wrappers) ? FG(stream_wrappers) : &url_stream_wrappers_hash);
+ php_stream_wrapper **wrapperpp = NULL;
+ const char *p, *protocol = NULL;
+ int n = 0;
+
+ if (path_for_open) {
+ *path_for_open = (char*)path;
+ }
+
+ if (options & IGNORE_URL) {
+ return (options & STREAM_LOCATE_WRAPPERS_ONLY) ? NULL : &php_plain_files_wrapper;
+ }
+
+ for (p = path; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
+ n++;
+ }
+
+ if ((*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || (n == 4 && !memcmp("data:", path, 5)))) {
+ protocol = path;
+ } else if (n == 5 && strncasecmp(path, "zlib:", 5) == 0) {
+ /* BC with older php scripts and zlib wrapper */
+ protocol = "compress.zlib";
+ n = 13;
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Use of \"zlib:\" wrapper is deprecated; please use \"compress.zlib://\" instead");
+ }
+
+ if (protocol) {
+ char *tmp = estrndup(protocol, n);
+ if (FAILURE == zend_hash_find(wrapper_hash, (char*)tmp, n + 1, (void**)&wrapperpp)) {
+ php_strtolower(tmp, n);
+ if (FAILURE == zend_hash_find(wrapper_hash, (char*)tmp, n + 1, (void**)&wrapperpp)) {
+ char wrapper_name[32];
+
+ if (n >= sizeof(wrapper_name)) {
+ n = sizeof(wrapper_name) - 1;
+ }
+ PHP_STRLCPY(wrapper_name, protocol, sizeof(wrapper_name), n);
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find the wrapper \"%s\" - did you forget to enable it when you configured PHP?", wrapper_name);
+
+ wrapperpp = NULL;
+ protocol = NULL;
+ }
+ }
+ efree(tmp);
+ }
+ /* TODO: curl based streams probably support file:// properly */
+ if (!protocol || !strncasecmp(protocol, "file", n)) {
+ /* fall back on regular file access */
+ php_stream_wrapper *plain_files_wrapper = &php_plain_files_wrapper;
+
+ if (protocol) {
+ int localhost = 0;
+
+ if (!strncasecmp(path, "file://localhost/", 17)) {
+ localhost = 1;
+ }
+
+#ifdef PHP_WIN32
+ if (localhost == 0 && path[n+3] != '\0' && path[n+3] != '/' && path[n+4] != ':') {
+#else
+ if (localhost == 0 && path[n+3] != '\0' && path[n+3] != '/') {
+#endif
+ if (options & REPORT_ERRORS) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "remote host file access not supported, %s", path);
+ }
+ return NULL;
+ }
+
+ if (path_for_open) {
+ /* skip past protocol and :/, but handle windows correctly */
+ *path_for_open = (char*)path + n + 1;
+ if (localhost == 1) {
+ (*path_for_open) += 11;
+ }
+ while (*(++*path_for_open)=='/');
+#ifdef PHP_WIN32
+ if (*(*path_for_open + 1) != ':')
+#endif
+ (*path_for_open)--;
+ }
+ }
+
+ if (options & STREAM_LOCATE_WRAPPERS_ONLY) {
+ return NULL;
+ }
+
+ if (FG(stream_wrappers)) {
+ /* The file:// wrapper may have been disabled/overridden */
+
+ if (wrapperpp) {
+ /* It was found so go ahead and provide it */
+ return *wrapperpp;
+ }
+
+ /* Check again, the original check might have not known the protocol name */
+ if (zend_hash_find(wrapper_hash, "file", sizeof("file"), (void**)&wrapperpp) == SUCCESS) {
+ return *wrapperpp;
+ }
+
+ if (options & REPORT_ERRORS) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "file:// wrapper is disabled in the server configuration");
+ }
+ return NULL;
+ }
+
+ return plain_files_wrapper;
+ }
+
+ if (wrapperpp && (*wrapperpp)->is_url &&
+ (options & STREAM_DISABLE_URL_PROTECTION) == 0 &&
+ (!PG(allow_url_fopen) ||
+ (((options & STREAM_OPEN_FOR_INCLUDE) ||
+ PG(in_user_include)) && !PG(allow_url_include)))) {
+ if (options & REPORT_ERRORS) {
+ /* protocol[n] probably isn't '\0' */
+ char *protocol_dup = estrndup(protocol, n);
+ if (!PG(allow_url_fopen)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s:// wrapper is disabled in the server configuration by allow_url_fopen=0", protocol_dup);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s:// wrapper is disabled in the server configuration by allow_url_include=0", protocol_dup);
+ }
+ efree(protocol_dup);
+ }
+ return NULL;
+ }
+
+ return *wrapperpp;
+}
+/* }}} */
+
+/* {{{ _php_stream_mkdir
+ */
+PHPAPI int _php_stream_mkdir(char *path, int mode, int options, php_stream_context *context TSRMLS_DC)
+{
+ php_stream_wrapper *wrapper = NULL;
+
+ wrapper = php_stream_locate_url_wrapper(path, NULL, 0 TSRMLS_CC);
+ if (!wrapper || !wrapper->wops || !wrapper->wops->stream_mkdir) {
+ return 0;
+ }
+
+ return wrapper->wops->stream_mkdir(wrapper, path, mode, options, context TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ _php_stream_rmdir
+ */
+PHPAPI int _php_stream_rmdir(char *path, int options, php_stream_context *context TSRMLS_DC)
+{
+ php_stream_wrapper *wrapper = NULL;
+
+ wrapper = php_stream_locate_url_wrapper(path, NULL, 0 TSRMLS_CC);
+ if (!wrapper || !wrapper->wops || !wrapper->wops->stream_rmdir) {
+ return 0;
+ }
+
+ return wrapper->wops->stream_rmdir(wrapper, path, options, context TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ _php_stream_stat_path */
+PHPAPI int _php_stream_stat_path(char *path, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
+{
+ php_stream_wrapper *wrapper = NULL;
+ char *path_to_open = path;
+ int ret;
+
+ /* Try to hit the cache first */
+ if (flags & PHP_STREAM_URL_STAT_LINK) {
+ if (BG(CurrentLStatFile) && strcmp(path, BG(CurrentLStatFile)) == 0) {
+ memcpy(ssb, &BG(lssb), sizeof(php_stream_statbuf));
+ return 0;
+ }
+ } else {
+ if (BG(CurrentStatFile) && strcmp(path, BG(CurrentStatFile)) == 0) {
+ memcpy(ssb, &BG(ssb), sizeof(php_stream_statbuf));
+ return 0;
+ }
+ }
+
+ wrapper = php_stream_locate_url_wrapper(path, &path_to_open, 0 TSRMLS_CC);
+ if (wrapper && wrapper->wops->url_stat) {
+ ret = wrapper->wops->url_stat(wrapper, path_to_open, flags, ssb, context TSRMLS_CC);
+ if (ret == 0) {
+ /* Drop into cache */
+ if (flags & PHP_STREAM_URL_STAT_LINK) {
+ if (BG(CurrentLStatFile)) {
+ efree(BG(CurrentLStatFile));
+ }
+ BG(CurrentLStatFile) = estrdup(path);
+ memcpy(&BG(lssb), ssb, sizeof(php_stream_statbuf));
+ } else {
+ if (BG(CurrentStatFile)) {
+ efree(BG(CurrentStatFile));
+ }
+ BG(CurrentStatFile) = estrdup(path);
+ memcpy(&BG(ssb), ssb, sizeof(php_stream_statbuf));
+ }
+ }
+ return ret;
+ }
+ return -1;
+}
+/* }}} */
+
+/* {{{ php_stream_opendir */
+PHPAPI php_stream *_php_stream_opendir(char *path, int options,
+ php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ php_stream *stream = NULL;
+ php_stream_wrapper *wrapper = NULL;
+ char *path_to_open;
+
+ if (!path || !*path) {
+ return NULL;
+ }
+
+ path_to_open = path;
+
+ wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options TSRMLS_CC);
+
+ if (wrapper && wrapper->wops->dir_opener) {
+ stream = wrapper->wops->dir_opener(wrapper,
+ path_to_open, "r", options ^ REPORT_ERRORS, NULL,
+ context STREAMS_REL_CC TSRMLS_CC);
+
+ if (stream) {
+ stream->wrapper = wrapper;
+ stream->flags |= PHP_STREAM_FLAG_NO_BUFFER | PHP_STREAM_FLAG_IS_DIR;
+ }
+ } else if (wrapper) {
+ php_stream_wrapper_log_error(wrapper, options ^ REPORT_ERRORS TSRMLS_CC, "not implemented");
+ }
+ if (stream == NULL && (options & REPORT_ERRORS)) {
+ php_stream_display_wrapper_errors(wrapper, path, "failed to open dir" TSRMLS_CC);
+ }
+ php_stream_tidy_wrapper_error_log(wrapper TSRMLS_CC);
+
+ return stream;
+}
+/* }}} */
+
+/* {{{ _php_stream_readdir */
+PHPAPI php_stream_dirent *_php_stream_readdir(php_stream *dirstream, php_stream_dirent *ent TSRMLS_DC)
+{
+
+ if (sizeof(php_stream_dirent) == php_stream_read(dirstream, (char*)ent, sizeof(php_stream_dirent))) {
+ return ent;
+ }
+
+ return NULL;
+}
+/* }}} */
+
+/* {{{ php_stream_open_wrapper_ex */
+PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options,
+ char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ php_stream *stream = NULL;
+ php_stream_wrapper *wrapper = NULL;
+ char *path_to_open;
+ int persistent = options & STREAM_OPEN_PERSISTENT;
+ char *resolved_path = NULL;
+ char *copy_of_path = NULL;
+
+ if (opened_path) {
+ *opened_path = NULL;
+ }
+
+ if (!path || !*path) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filename cannot be empty");
+ return NULL;
+ }
+
+ if (options & USE_PATH) {
+ resolved_path = zend_resolve_path(path, strlen(path) TSRMLS_CC);
+ if (resolved_path) {
+ path = resolved_path;
+ /* we've found this file, don't re-check include_path or run realpath */
+ options |= STREAM_ASSUME_REALPATH;
+ options &= ~USE_PATH;
+ }
+ }
+
+ path_to_open = path;
+
+ wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options TSRMLS_CC);
+ if (options & STREAM_USE_URL && (!wrapper || !wrapper->is_url)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "This function may only be used against URLs");
+ if (resolved_path) {
+ efree(resolved_path);
+ }
+ return NULL;
+ }
+
+ if (wrapper) {
+ if (!wrapper->wops->stream_opener) {
+ php_stream_wrapper_log_error(wrapper, options ^ REPORT_ERRORS TSRMLS_CC,
+ "wrapper does not support stream open");
+ } else {
+ stream = wrapper->wops->stream_opener(wrapper,
+ path_to_open, mode, options ^ REPORT_ERRORS,
+ opened_path, context STREAMS_REL_CC TSRMLS_CC);
+ }
+
+ /* if the caller asked for a persistent stream but the wrapper did not
+ * return one, force an error here */
+ if (stream && (options & STREAM_OPEN_PERSISTENT) && !stream->is_persistent) {
+ php_stream_wrapper_log_error(wrapper, options ^ REPORT_ERRORS TSRMLS_CC,
+ "wrapper does not support persistent streams");
+ php_stream_close(stream);
+ stream = NULL;
+ }
+
+ if (stream) {
+ stream->wrapper = wrapper;
+ }
+ }
+
+ if (stream) {
+ if (opened_path && !*opened_path && resolved_path) {
+ *opened_path = resolved_path;
+ resolved_path = NULL;
+ }
+ if (stream->orig_path) {
+ pefree(stream->orig_path, persistent);
+ }
+ copy_of_path = pestrdup(path, persistent);
+ stream->orig_path = copy_of_path;
+#if ZEND_DEBUG
+ stream->open_filename = __zend_orig_filename ? __zend_orig_filename : __zend_filename;
+ stream->open_lineno = __zend_orig_lineno ? __zend_orig_lineno : __zend_lineno;
+#endif
+ }
+
+ if (stream != NULL && (options & STREAM_MUST_SEEK)) {
+ php_stream *newstream;
+
+ switch(php_stream_make_seekable_rel(stream, &newstream,
+ (options & STREAM_WILL_CAST)
+ ? PHP_STREAM_PREFER_STDIO : PHP_STREAM_NO_PREFERENCE)) {
+ case PHP_STREAM_UNCHANGED:
+ if (resolved_path) {
+ efree(resolved_path);
+ }
+ return stream;
+ case PHP_STREAM_RELEASED:
+ if (newstream->orig_path) {
+ pefree(newstream->orig_path, persistent);
+ }
+ newstream->orig_path = pestrdup(path, persistent);
+ if (resolved_path) {
+ efree(resolved_path);
+ }
+ return newstream;
+ default:
+ php_stream_close(stream);
+ stream = NULL;
+ if (options & REPORT_ERRORS) {
+ char *tmp = estrdup(path);
+ php_strip_url_passwd(tmp);
+ php_error_docref1(NULL TSRMLS_CC, tmp, E_WARNING, "could not make seekable - %s",
+ tmp);
+ efree(tmp);
+
+ options ^= REPORT_ERRORS;
+ }
+ }
+ }
+
+ if (stream && stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && strchr(mode, 'a') && stream->position == 0) {
+ off_t newpos = 0;
+
+ /* if opened for append, we need to revise our idea of the initial file position */
+ if (0 == stream->ops->seek(stream, 0, SEEK_CUR, &newpos TSRMLS_CC)) {
+ stream->position = newpos;
+ }
+ }
+
+ if (stream == NULL && (options & REPORT_ERRORS)) {
+ php_stream_display_wrapper_errors(wrapper, path, "failed to open stream" TSRMLS_CC);
+ if (opened_path && *opened_path) {
+ efree(*opened_path);
+ *opened_path = NULL;
+ }
+ }
+ php_stream_tidy_wrapper_error_log(wrapper TSRMLS_CC);
+#if ZEND_DEBUG
+ if (stream == NULL && copy_of_path != NULL) {
+ pefree(copy_of_path, persistent);
+ }
+#endif
+ if (resolved_path) {
+ efree(resolved_path);
+ }
+ return stream;
+}
+/* }}} */
+
+/* {{{ context API */
+PHPAPI php_stream_context *php_stream_context_set(php_stream *stream, php_stream_context *context)
+{
+ php_stream_context *oldcontext = stream->context;
+ TSRMLS_FETCH();
+
+ stream->context = context;
+
+ if (context) {
+ zend_list_addref(context->rsrc_id);
+ }
+ if (oldcontext) {
+ zend_list_delete(oldcontext->rsrc_id);
+ }
+
+ return oldcontext;
+}
+
+PHPAPI void php_stream_notification_notify(php_stream_context *context, int notifycode, int severity,
+ char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr TSRMLS_DC)
+{
+ if (context && context->notifier)
+ context->notifier->func(context, notifycode, severity, xmsg, xcode, bytes_sofar, bytes_max, ptr TSRMLS_CC);
+}
+
+PHPAPI void php_stream_context_free(php_stream_context *context)
+{
+ if (context->options) {
+ zval_ptr_dtor(&context->options);
+ context->options = NULL;
+ }
+ if (context->notifier) {
+ php_stream_notification_free(context->notifier);
+ context->notifier = NULL;
+ }
+ if (context->links) {
+ zval_ptr_dtor(&context->links);
+ context->links = NULL;
+ }
+ efree(context);
+}
+
+PHPAPI php_stream_context *php_stream_context_alloc(TSRMLS_D)
+{
+ php_stream_context *context;
+
+ context = ecalloc(1, sizeof(php_stream_context));
+ context->notifier = NULL;
+ MAKE_STD_ZVAL(context->options);
+ array_init(context->options);
+
+ context->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, context, php_le_stream_context(TSRMLS_C));
+ return context;
+}
+
+PHPAPI php_stream_notifier *php_stream_notification_alloc(void)
+{
+ return ecalloc(1, sizeof(php_stream_notifier));
+}
+
+PHPAPI void php_stream_notification_free(php_stream_notifier *notifier)
+{
+ if (notifier->dtor) {
+ notifier->dtor(notifier);
+ }
+ efree(notifier);
+}
+
+PHPAPI int php_stream_context_get_option(php_stream_context *context,
+ const char *wrappername, const char *optionname, zval ***optionvalue)
+{
+ zval **wrapperhash;
+
+ if (FAILURE == zend_hash_find(Z_ARRVAL_P(context->options), (char*)wrappername, strlen(wrappername)+1, (void**)&wrapperhash)) {
+ return FAILURE;
+ }
+ return zend_hash_find(Z_ARRVAL_PP(wrapperhash), (char*)optionname, strlen(optionname)+1, (void**)optionvalue);
+}
+
+PHPAPI int php_stream_context_set_option(php_stream_context *context,
+ const char *wrappername, const char *optionname, zval *optionvalue)
+{
+ zval **wrapperhash;
+ zval *category, *copied_val;
+
+ ALLOC_INIT_ZVAL(copied_val);
+ *copied_val = *optionvalue;
+ zval_copy_ctor(copied_val);
+ INIT_PZVAL(copied_val);
+
+ if (FAILURE == zend_hash_find(Z_ARRVAL_P(context->options), (char*)wrappername, strlen(wrappername)+1, (void**)&wrapperhash)) {
+ MAKE_STD_ZVAL(category);
+ array_init(category);
+ if (FAILURE == zend_hash_update(Z_ARRVAL_P(context->options), (char*)wrappername, strlen(wrappername)+1, (void**)&category, sizeof(zval *), NULL)) {
+ return FAILURE;
+ }
+
+ wrapperhash = &category;
+ }
+ return zend_hash_update(Z_ARRVAL_PP(wrapperhash), (char*)optionname, strlen(optionname)+1, (void**)&copied_val, sizeof(zval *), NULL);
+}
+
+PHPAPI int php_stream_context_get_link(php_stream_context *context,
+ const char *hostent, php_stream **stream)
+{
+ php_stream **pstream;
+
+ if (!stream || !hostent || !context || !(context->links)) {
+ return FAILURE;
+ }
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_P(context->links), (char*)hostent, strlen(hostent)+1, (void**)&pstream)) {
+ *stream = *pstream;
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+
+PHPAPI int php_stream_context_set_link(php_stream_context *context,
+ const char *hostent, php_stream *stream)
+{
+ if (!context) {
+ return FAILURE;
+ }
+ if (!context->links) {
+ ALLOC_INIT_ZVAL(context->links);
+ array_init(context->links);
+ }
+ if (!stream) {
+ /* Delete any entry for <hostent> */
+ return zend_hash_del(Z_ARRVAL_P(context->links), (char*)hostent, strlen(hostent)+1);
+ }
+ return zend_hash_update(Z_ARRVAL_P(context->links), (char*)hostent, strlen(hostent)+1, (void**)&stream, sizeof(php_stream *), NULL);
+}
+
+PHPAPI int php_stream_context_del_link(php_stream_context *context,
+ php_stream *stream)
+{
+ php_stream **pstream;
+ char *hostent;
+ int ret = SUCCESS;
+
+ if (!context || !context->links || !stream) {
+ return FAILURE;
+ }
+
+ for(zend_hash_internal_pointer_reset(Z_ARRVAL_P(context->links));
+ SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(context->links), (void**)&pstream);
+ zend_hash_move_forward(Z_ARRVAL_P(context->links))) {
+ if (*pstream == stream) {
+ if (SUCCESS == zend_hash_get_current_key(Z_ARRVAL_P(context->links), &hostent, NULL, 0)) {
+ if (FAILURE == zend_hash_del(Z_ARRVAL_P(context->links), (char*)hostent, strlen(hostent)+1)) {
+ ret = FAILURE;
+ }
+ } else {
+ ret = FAILURE;
+ }
+ }
+ }
+
+ return ret;
+}
+/* }}} */
+
+/* {{{ php_stream_dirent_alphasort
+ */
+PHPAPI int php_stream_dirent_alphasort(const char **a, const char **b)
+{
+ return strcoll(*a, *b);
+}
+/* }}} */
+
+/* {{{ php_stream_dirent_alphasortr
+ */
+PHPAPI int php_stream_dirent_alphasortr(const char **a, const char **b)
+{
+ return strcoll(*b, *a);
+}
+/* }}} */
+
+/* {{{ php_stream_scandir
+ */
+PHPAPI int _php_stream_scandir(char *dirname, char **namelist[], int flags, php_stream_context *context,
+ int (*compare) (const char **a, const char **b) TSRMLS_DC)
+{
+ php_stream *stream;
+ php_stream_dirent sdp;
+ char **vector = NULL;
+ unsigned int vector_size = 0;
+ unsigned int nfiles = 0;
+
+ if (!namelist) {
+ return FAILURE;
+ }
+
+ stream = php_stream_opendir(dirname, REPORT_ERRORS, context);
+ if (!stream) {
+ return FAILURE;
+ }
+
+ while (php_stream_readdir(stream, &sdp)) {
+ if (nfiles == vector_size) {
+ if (vector_size == 0) {
+ vector_size = 10;
+ } else {
+ if(vector_size*2 < vector_size) {
+ /* overflow */
+ efree(vector);
+ return FAILURE;
+ }
+ vector_size *= 2;
+ }
+ vector = (char **) safe_erealloc(vector, vector_size, sizeof(char *), 0);
+ }
+
+ vector[nfiles] = estrdup(sdp.d_name);
+
+ nfiles++;
+ if(vector_size < 10 || nfiles == 0) {
+ /* overflow */
+ efree(vector);
+ return FAILURE;
+ }
+ }
+ php_stream_closedir(stream);
+
+ *namelist = vector;
+
+ if (compare) {
+ qsort(*namelist, nfiles, sizeof(char *), (int(*)(const void *, const void *))compare);
+ }
+ return nfiles;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/streams/transports.c b/main/streams/transports.c
new file mode 100644
index 0000000..c24bf97
--- /dev/null
+++ b/main/streams/transports.c
@@ -0,0 +1,532 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+#include "php_streams_int.h"
+#include "ext/standard/file.h"
+
+static HashTable xport_hash;
+
+PHPAPI HashTable *php_stream_xport_get_hash(void)
+{
+ return &xport_hash;
+}
+
+PHPAPI int php_stream_xport_register(char *protocol, php_stream_transport_factory factory TSRMLS_DC)
+{
+ return zend_hash_update(&xport_hash, protocol, strlen(protocol) + 1, &factory, sizeof(factory), NULL);
+}
+
+PHPAPI int php_stream_xport_unregister(char *protocol TSRMLS_DC)
+{
+ return zend_hash_del(&xport_hash, protocol, strlen(protocol) + 1);
+}
+
+#define ERR_REPORT(out_err, fmt, arg) \
+ if (out_err) { spprintf(out_err, 0, fmt, arg); } \
+ else { php_error_docref(NULL TSRMLS_CC, E_WARNING, fmt, arg); }
+
+#define ERR_RETURN(out_err, local_err, fmt) \
+ if (out_err) { *out_err = local_err; } \
+ else { php_error_docref(NULL TSRMLS_CC, E_WARNING, fmt, local_err ? local_err : "Unspecified error"); \
+ if (local_err) { efree(local_err); local_err = NULL; } \
+ }
+
+PHPAPI php_stream *_php_stream_xport_create(const char *name, long namelen, int options,
+ int flags, const char *persistent_id,
+ struct timeval *timeout,
+ php_stream_context *context,
+ char **error_string,
+ int *error_code
+ STREAMS_DC TSRMLS_DC)
+{
+ php_stream *stream = NULL;
+ php_stream_transport_factory *factory = NULL;
+ const char *p, *protocol = NULL;
+ int n = 0, failed = 0;
+ char *error_text = NULL;
+ struct timeval default_timeout = { 0, 0 };
+
+ default_timeout.tv_sec = FG(default_socket_timeout);
+
+ if (timeout == NULL) {
+ timeout = &default_timeout;
+ }
+
+ /* check for a cached persistent socket */
+ if (persistent_id) {
+ switch(php_stream_from_persistent_id(persistent_id, &stream TSRMLS_CC)) {
+ case PHP_STREAM_PERSISTENT_SUCCESS:
+ /* use a 0 second timeout when checking if the socket
+ * has already died */
+ if (PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_CHECK_LIVENESS, 0, NULL)) {
+ return stream;
+ }
+ /* dead - kill it */
+ php_stream_pclose(stream);
+ stream = NULL;
+
+ /* fall through */
+
+ case PHP_STREAM_PERSISTENT_FAILURE:
+ default:
+ /* failed; get a new one */
+ ;
+ }
+ }
+
+ for (p = name; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
+ n++;
+ }
+
+ if ((*p == ':') && (n > 1) && !strncmp("://", p, 3)) {
+ protocol = name;
+ name = p + 3;
+ namelen -= n + 3;
+ } else {
+ protocol = "tcp";
+ n = 3;
+ }
+
+ if (protocol) {
+ char *tmp = estrndup(protocol, n);
+ if (FAILURE == zend_hash_find(&xport_hash, (char*)tmp, n + 1, (void**)&factory)) {
+ char wrapper_name[32];
+
+ if (n >= sizeof(wrapper_name))
+ n = sizeof(wrapper_name) - 1;
+ PHP_STRLCPY(wrapper_name, protocol, sizeof(wrapper_name), n);
+
+ ERR_REPORT(error_string, "Unable to find the socket transport \"%s\" - did you forget to enable it when you configured PHP?",
+ wrapper_name);
+
+ efree(tmp);
+ return NULL;
+ }
+ efree(tmp);
+ }
+
+ if (factory == NULL) {
+ /* should never happen */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not find a factory !?");
+ return NULL;
+ }
+
+ stream = (*factory)(protocol, n,
+ (char*)name, namelen, persistent_id, options, flags, timeout,
+ context STREAMS_REL_CC TSRMLS_CC);
+
+ if (stream) {
+ php_stream_context_set(stream, context);
+
+ if ((flags & STREAM_XPORT_SERVER) == 0) {
+ /* client */
+
+ if (flags & (STREAM_XPORT_CONNECT|STREAM_XPORT_CONNECT_ASYNC)) {
+ if (-1 == php_stream_xport_connect(stream, name, namelen,
+ flags & STREAM_XPORT_CONNECT_ASYNC ? 1 : 0,
+ timeout, &error_text, error_code TSRMLS_CC)) {
+
+ ERR_RETURN(error_string, error_text, "connect() failed: %s");
+
+ failed = 1;
+ }
+ }
+
+ } else {
+ /* server */
+ if (flags & STREAM_XPORT_BIND) {
+ if (0 != php_stream_xport_bind(stream, name, namelen, &error_text TSRMLS_CC)) {
+ ERR_RETURN(error_string, error_text, "bind() failed: %s");
+ failed = 1;
+ } else if (flags & STREAM_XPORT_LISTEN) {
+ zval **zbacklog = NULL;
+ int backlog = 32;
+
+ if (stream->context && php_stream_context_get_option(stream->context, "socket", "backlog", &zbacklog) == SUCCESS) {
+ zval *ztmp = *zbacklog;
+
+ convert_to_long_ex(&ztmp);
+ backlog = Z_LVAL_P(ztmp);
+ if (ztmp != *zbacklog) {
+ zval_ptr_dtor(&ztmp);
+ }
+ }
+
+ if (0 != php_stream_xport_listen(stream, backlog, &error_text TSRMLS_CC)) {
+ ERR_RETURN(error_string, error_text, "listen() failed: %s");
+ failed = 1;
+ }
+ }
+ }
+ }
+ }
+
+ if (failed) {
+ /* failure means that they don't get a stream to play with */
+ if (persistent_id) {
+ php_stream_pclose(stream);
+ } else {
+ php_stream_close(stream);
+ }
+ stream = NULL;
+ }
+
+ return stream;
+}
+
+/* Bind the stream to a local address */
+PHPAPI int php_stream_xport_bind(php_stream *stream,
+ const char *name, long namelen,
+ char **error_text
+ TSRMLS_DC)
+{
+ php_stream_xport_param param;
+ int ret;
+
+ memset(&param, 0, sizeof(param));
+ param.op = STREAM_XPORT_OP_BIND;
+ param.inputs.name = (char*)name;
+ param.inputs.namelen = namelen;
+ param.want_errortext = error_text ? 1 : 0;
+
+ ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
+
+ if (ret == PHP_STREAM_OPTION_RETURN_OK) {
+ if (error_text) {
+ *error_text = param.outputs.error_text;
+ }
+
+ return param.outputs.returncode;
+ }
+
+ return ret;
+}
+
+/* Connect to a remote address */
+PHPAPI int php_stream_xport_connect(php_stream *stream,
+ const char *name, long namelen,
+ int asynchronous,
+ struct timeval *timeout,
+ char **error_text,
+ int *error_code
+ TSRMLS_DC)
+{
+ php_stream_xport_param param;
+ int ret;
+
+ memset(&param, 0, sizeof(param));
+ param.op = asynchronous ? STREAM_XPORT_OP_CONNECT_ASYNC: STREAM_XPORT_OP_CONNECT;
+ param.inputs.name = (char*)name;
+ param.inputs.namelen = namelen;
+ param.inputs.timeout = timeout;
+
+ param.want_errortext = error_text ? 1 : 0;
+
+ ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
+
+ if (ret == PHP_STREAM_OPTION_RETURN_OK) {
+ if (error_text) {
+ *error_text = param.outputs.error_text;
+ }
+ if (error_code) {
+ *error_code = param.outputs.error_code;
+ }
+ return param.outputs.returncode;
+ }
+
+ return ret;
+
+}
+
+/* Prepare to listen */
+PHPAPI int php_stream_xport_listen(php_stream *stream, int backlog, char **error_text TSRMLS_DC)
+{
+ php_stream_xport_param param;
+ int ret;
+
+ memset(&param, 0, sizeof(param));
+ param.op = STREAM_XPORT_OP_LISTEN;
+ param.inputs.backlog = backlog;
+ param.want_errortext = error_text ? 1 : 0;
+
+ ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
+
+ if (ret == PHP_STREAM_OPTION_RETURN_OK) {
+ if (error_text) {
+ *error_text = param.outputs.error_text;
+ }
+
+ return param.outputs.returncode;
+ }
+
+ return ret;
+}
+
+/* Get the next client and their address (as a string) */
+PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client,
+ char **textaddr, int *textaddrlen,
+ void **addr, socklen_t *addrlen,
+ struct timeval *timeout,
+ char **error_text
+ TSRMLS_DC)
+{
+ php_stream_xport_param param;
+ int ret;
+
+ memset(&param, 0, sizeof(param));
+
+ param.op = STREAM_XPORT_OP_ACCEPT;
+ param.inputs.timeout = timeout;
+ param.want_addr = addr ? 1 : 0;
+ param.want_textaddr = textaddr ? 1 : 0;
+ param.want_errortext = error_text ? 1 : 0;
+
+ ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
+
+ if (ret == PHP_STREAM_OPTION_RETURN_OK) {
+ *client = param.outputs.client;
+ if (addr) {
+ *addr = param.outputs.addr;
+ *addrlen = param.outputs.addrlen;
+ }
+ if (textaddr) {
+ *textaddr = param.outputs.textaddr;
+ *textaddrlen = param.outputs.textaddrlen;
+ }
+ if (error_text) {
+ *error_text = param.outputs.error_text;
+ }
+
+ return param.outputs.returncode;
+ }
+ return ret;
+}
+
+PHPAPI int php_stream_xport_get_name(php_stream *stream, int want_peer,
+ char **textaddr, int *textaddrlen,
+ void **addr, socklen_t *addrlen
+ TSRMLS_DC)
+{
+ php_stream_xport_param param;
+ int ret;
+
+ memset(&param, 0, sizeof(param));
+
+ param.op = want_peer ? STREAM_XPORT_OP_GET_PEER_NAME : STREAM_XPORT_OP_GET_NAME;
+ param.want_addr = addr ? 1 : 0;
+ param.want_textaddr = textaddr ? 1 : 0;
+
+ ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
+
+ if (ret == PHP_STREAM_OPTION_RETURN_OK) {
+ if (addr) {
+ *addr = param.outputs.addr;
+ *addrlen = param.outputs.addrlen;
+ }
+ if (textaddr) {
+ *textaddr = param.outputs.textaddr;
+ *textaddrlen = param.outputs.textaddrlen;
+ }
+
+ return param.outputs.returncode;
+ }
+ return ret;
+}
+
+PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_crypt_method_t crypto_method, php_stream *session_stream TSRMLS_DC)
+{
+ php_stream_xport_crypto_param param;
+ int ret;
+
+ memset(&param, 0, sizeof(param));
+ param.op = STREAM_XPORT_CRYPTO_OP_SETUP;
+ param.inputs.method = crypto_method;
+ param.inputs.session = session_stream;
+
+ ret = php_stream_set_option(stream, PHP_STREAM_OPTION_CRYPTO_API, 0, &param);
+
+ if (ret == PHP_STREAM_OPTION_RETURN_OK) {
+ return param.outputs.returncode;
+ }
+
+ php_error_docref("streams.crypto" TSRMLS_CC, E_WARNING, "this stream does not support SSL/crypto");
+
+ return ret;
+}
+
+PHPAPI int php_stream_xport_crypto_enable(php_stream *stream, int activate TSRMLS_DC)
+{
+ php_stream_xport_crypto_param param;
+ int ret;
+
+ memset(&param, 0, sizeof(param));
+ param.op = STREAM_XPORT_CRYPTO_OP_ENABLE;
+ param.inputs.activate = activate;
+
+ ret = php_stream_set_option(stream, PHP_STREAM_OPTION_CRYPTO_API, 0, &param);
+
+ if (ret == PHP_STREAM_OPTION_RETURN_OK) {
+ return param.outputs.returncode;
+ }
+
+ php_error_docref("streams.crypto" TSRMLS_CC, E_WARNING, "this stream does not support SSL/crypto");
+
+ return ret;
+}
+
+/* Similar to recv() system call; read data from the stream, optionally
+ * peeking, optionally retrieving OOB data */
+PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t buflen,
+ long flags, void **addr, socklen_t *addrlen, char **textaddr, int *textaddrlen
+ TSRMLS_DC)
+{
+ php_stream_xport_param param;
+ int ret = 0;
+ int recvd_len = 0;
+#if 0
+ int oob;
+
+ if (flags == 0 && addr == NULL) {
+ return php_stream_read(stream, buf, buflen);
+ }
+
+ if (stream->readfilters.head) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot peek or fetch OOB data from a filtered stream");
+ return -1;
+ }
+
+ oob = (flags & STREAM_OOB) == STREAM_OOB;
+
+ if (!oob && addr == NULL) {
+ /* must be peeking at regular data; copy content from the buffer
+ * first, then adjust the pointer/len before handing off to the
+ * stream */
+ recvd_len = stream->writepos - stream->readpos;
+ if (recvd_len > buflen) {
+ recvd_len = buflen;
+ }
+ if (recvd_len) {
+ memcpy(buf, stream->readbuf, recvd_len);
+ buf += recvd_len;
+ buflen -= recvd_len;
+ }
+ /* if we filled their buffer, return */
+ if (buflen == 0) {
+ return recvd_len;
+ }
+ }
+#endif
+
+ /* otherwise, we are going to bypass the buffer */
+
+ memset(&param, 0, sizeof(param));
+
+ param.op = STREAM_XPORT_OP_RECV;
+ param.want_addr = addr ? 1 : 0;
+ param.want_textaddr = textaddr ? 1 : 0;
+ param.inputs.buf = buf;
+ param.inputs.buflen = buflen;
+ param.inputs.flags = flags;
+
+ ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
+
+ if (ret == PHP_STREAM_OPTION_RETURN_OK) {
+ if (addr) {
+ *addr = param.outputs.addr;
+ *addrlen = param.outputs.addrlen;
+ }
+ if (textaddr) {
+ *textaddr = param.outputs.textaddr;
+ *textaddrlen = param.outputs.textaddrlen;
+ }
+ return recvd_len + param.outputs.returncode;
+ }
+ return recvd_len ? recvd_len : -1;
+}
+
+/* Similar to send() system call; send data to the stream, optionally
+ * sending it as OOB data */
+PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t buflen,
+ long flags, void *addr, socklen_t addrlen TSRMLS_DC)
+{
+ php_stream_xport_param param;
+ int ret = 0;
+ int oob;
+
+#if 0
+ if (flags == 0 && addr == NULL) {
+ return php_stream_write(stream, buf, buflen);
+ }
+#endif
+
+ oob = (flags & STREAM_OOB) == STREAM_OOB;
+
+ if ((oob || addr) && stream->writefilters.head) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot write OOB data, or data to a targeted address on a filtered stream");
+ return -1;
+ }
+
+ memset(&param, 0, sizeof(param));
+
+ param.op = STREAM_XPORT_OP_SEND;
+ param.want_addr = addr ? 1 : 0;
+ param.inputs.buf = (char*)buf;
+ param.inputs.buflen = buflen;
+ param.inputs.flags = flags;
+ param.inputs.addr = addr;
+ param.inputs.addrlen = addrlen;
+
+ ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
+
+ if (ret == PHP_STREAM_OPTION_RETURN_OK) {
+ return param.outputs.returncode;
+ }
+ return -1;
+}
+
+/* Similar to shutdown() system call; shut down part of a full-duplex
+ * connection */
+PHPAPI int php_stream_xport_shutdown(php_stream *stream, stream_shutdown_t how TSRMLS_DC)
+{
+ php_stream_xport_param param;
+ int ret = 0;
+
+ memset(&param, 0, sizeof(param));
+
+ param.op = STREAM_XPORT_OP_SHUTDOWN;
+ param.how = how;
+
+ ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
+
+ if (ret == PHP_STREAM_OPTION_RETURN_OK) {
+ return param.outputs.returncode;
+ }
+ return -1;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/streams/userspace.c b/main/streams/userspace.c
new file mode 100644
index 0000000..69edbaa
--- /dev/null
+++ b/main/streams/userspace.c
@@ -0,0 +1,1676 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Wez Furlong <wez@thebrainroom.com> |
+ | Sara Golemon <pollita@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+#include "php_globals.h"
+#include "ext/standard/file.h"
+#include "ext/standard/flock_compat.h"
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#include <stddef.h>
+
+#if HAVE_UTIME
+# ifdef PHP_WIN32
+# include <sys/utime.h>
+# else
+# include <utime.h>
+# endif
+#endif
+
+static int le_protocols;
+
+struct php_user_stream_wrapper {
+ char * protoname;
+ char * classname;
+ zend_class_entry *ce;
+ php_stream_wrapper wrapper;
+};
+
+static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
+static int user_wrapper_stat_url(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC);
+static int user_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
+static int user_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC);
+static int user_wrapper_mkdir(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC);
+static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
+static int user_wrapper_metadata(php_stream_wrapper *wrapper, char *url, int option, void *value, php_stream_context *context TSRMLS_DC);
+static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filename, char *mode,
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
+
+static php_stream_wrapper_ops user_stream_wops = {
+ user_wrapper_opener,
+ NULL, /* close - the streams themselves know how */
+ NULL, /* stat - the streams themselves know how */
+ user_wrapper_stat_url,
+ user_wrapper_opendir,
+ "user-space",
+ user_wrapper_unlink,
+ user_wrapper_rename,
+ user_wrapper_mkdir,
+ user_wrapper_rmdir,
+ user_wrapper_metadata
+};
+
+
+static void stream_wrapper_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ struct php_user_stream_wrapper * uwrap = (struct php_user_stream_wrapper*)rsrc->ptr;
+
+ efree(uwrap->protoname);
+ efree(uwrap->classname);
+ efree(uwrap);
+}
+
+
+PHP_MINIT_FUNCTION(user_streams)
+{
+ le_protocols = zend_register_list_destructors_ex(stream_wrapper_dtor, NULL, "stream factory", 0);
+ if (le_protocols == FAILURE)
+ return FAILURE;
+
+ REGISTER_LONG_CONSTANT("STREAM_USE_PATH", USE_PATH, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_IGNORE_URL", IGNORE_URL, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_REPORT_ERRORS", REPORT_ERRORS, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_MUST_SEEK", STREAM_MUST_SEEK, CONST_CS|CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("STREAM_URL_STAT_LINK", PHP_STREAM_URL_STAT_LINK, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_URL_STAT_QUIET", PHP_STREAM_URL_STAT_QUIET, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_MKDIR_RECURSIVE", PHP_STREAM_MKDIR_RECURSIVE, CONST_CS|CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("STREAM_IS_URL", PHP_STREAM_IS_URL, CONST_CS|CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("STREAM_OPTION_BLOCKING", PHP_STREAM_OPTION_BLOCKING, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_OPTION_READ_TIMEOUT", PHP_STREAM_OPTION_READ_TIMEOUT, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_OPTION_READ_BUFFER", PHP_STREAM_OPTION_READ_BUFFER, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_OPTION_WRITE_BUFFER", PHP_STREAM_OPTION_WRITE_BUFFER, CONST_CS|CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("STREAM_BUFFER_NONE", PHP_STREAM_BUFFER_NONE, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_BUFFER_LINE", PHP_STREAM_BUFFER_LINE, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_BUFFER_FULL", PHP_STREAM_BUFFER_FULL, CONST_CS|CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("STREAM_CAST_AS_STREAM", PHP_STREAM_AS_STDIO, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_CAST_FOR_SELECT", PHP_STREAM_AS_FD_FOR_SELECT, CONST_CS|CONST_PERSISTENT);
+
+ REGISTER_LONG_CONSTANT("STREAM_META_TOUCH", PHP_STREAM_META_TOUCH, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_OWNER", PHP_STREAM_META_OWNER, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_OWNER_NAME", PHP_STREAM_META_OWNER_NAME, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_GROUP", PHP_STREAM_META_GROUP, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_GROUP_NAME", PHP_STREAM_META_GROUP_NAME, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("STREAM_META_ACCESS", PHP_STREAM_META_ACCESS, CONST_CS|CONST_PERSISTENT);
+ return SUCCESS;
+}
+
+struct _php_userstream_data {
+ struct php_user_stream_wrapper * wrapper;
+ zval * object;
+};
+typedef struct _php_userstream_data php_userstream_data_t;
+
+/* names of methods */
+#define USERSTREAM_OPEN "stream_open"
+#define USERSTREAM_CLOSE "stream_close"
+#define USERSTREAM_READ "stream_read"
+#define USERSTREAM_WRITE "stream_write"
+#define USERSTREAM_FLUSH "stream_flush"
+#define USERSTREAM_SEEK "stream_seek"
+#define USERSTREAM_TELL "stream_tell"
+#define USERSTREAM_EOF "stream_eof"
+#define USERSTREAM_STAT "stream_stat"
+#define USERSTREAM_STATURL "url_stat"
+#define USERSTREAM_UNLINK "unlink"
+#define USERSTREAM_RENAME "rename"
+#define USERSTREAM_MKDIR "mkdir"
+#define USERSTREAM_RMDIR "rmdir"
+#define USERSTREAM_DIR_OPEN "dir_opendir"
+#define USERSTREAM_DIR_READ "dir_readdir"
+#define USERSTREAM_DIR_REWIND "dir_rewinddir"
+#define USERSTREAM_DIR_CLOSE "dir_closedir"
+#define USERSTREAM_LOCK "stream_lock"
+#define USERSTREAM_CAST "stream_cast"
+#define USERSTREAM_SET_OPTION "stream_set_option"
+#define USERSTREAM_TRUNCATE "stream_truncate"
+#define USERSTREAM_METADATA "stream_metadata"
+
+/* {{{ class should have methods like these:
+
+ function stream_open($path, $mode, $options, &$opened_path)
+ {
+ return true/false;
+ }
+
+ function stream_read($count)
+ {
+ return false on error;
+ else return string;
+ }
+
+ function stream_write($data)
+ {
+ return false on error;
+ else return count written;
+ }
+
+ function stream_close()
+ {
+ }
+
+ function stream_flush()
+ {
+ return true/false;
+ }
+
+ function stream_seek($offset, $whence)
+ {
+ return true/false;
+ }
+
+ function stream_tell()
+ {
+ return (int)$position;
+ }
+
+ function stream_eof()
+ {
+ return true/false;
+ }
+
+ function stream_stat()
+ {
+ return array( just like that returned by fstat() );
+ }
+
+ function stream_cast($castas)
+ {
+ if ($castas == STREAM_CAST_FOR_SELECT) {
+ return $this->underlying_stream;
+ }
+ return false;
+ }
+
+ function stream_set_option($option, $arg1, $arg2)
+ {
+ switch($option) {
+ case STREAM_OPTION_BLOCKING:
+ $blocking = $arg1;
+ ...
+ case STREAM_OPTION_READ_TIMEOUT:
+ $sec = $arg1;
+ $usec = $arg2;
+ ...
+ case STREAM_OPTION_WRITE_BUFFER:
+ $mode = $arg1;
+ $size = $arg2;
+ ...
+ default:
+ return false;
+ }
+ }
+
+ function url_stat(string $url, int $flags)
+ {
+ return array( just like that returned by stat() );
+ }
+
+ function unlink(string $url)
+ {
+ return true / false;
+ }
+
+ function rename(string $from, string $to)
+ {
+ return true / false;
+ }
+
+ function mkdir($dir, $mode, $options)
+ {
+ return true / false;
+ }
+
+ function rmdir($dir, $options)
+ {
+ return true / false;
+ }
+
+ function dir_opendir(string $url, int $options)
+ {
+ return true / false;
+ }
+
+ function dir_readdir()
+ {
+ return string next filename in dir ;
+ }
+
+ function dir_closedir()
+ {
+ release dir related resources;
+ }
+
+ function dir_rewinddir()
+ {
+ reset to start of dir list;
+ }
+
+ function stream_lock($operation)
+ {
+ return true / false;
+ }
+
+ function stream_truncate($new_size)
+ {
+ return true / false;
+ }
+
+ }}} **/
+
+static zval *user_stream_create_object(struct php_user_stream_wrapper *uwrap, php_stream_context *context TSRMLS_DC)
+{
+ zval *object;
+ /* create an instance of our class */
+ ALLOC_ZVAL(object);
+ object_init_ex(object, uwrap->ce);
+ Z_SET_REFCOUNT_P(object, 1);
+ Z_SET_ISREF_P(object);
+
+ if (context) {
+ add_property_resource(object, "context", context->rsrc_id);
+ zend_list_addref(context->rsrc_id);
+ } else {
+ add_property_null(object, "context");
+ }
+
+ if (uwrap->ce->constructor) {
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ zval *retval_ptr;
+
+ fci.size = sizeof(fci);
+ fci.function_table = &uwrap->ce->function_table;
+ fci.function_name = NULL;
+ fci.symbol_table = NULL;
+ fci.object_ptr = object;
+ fci.retval_ptr_ptr = &retval_ptr;
+ fci.param_count = 0;
+ fci.params = NULL;
+ fci.no_separation = 1;
+
+ fcc.initialized = 1;
+ fcc.function_handler = uwrap->ce->constructor;
+ fcc.calling_scope = EG(scope);
+ fcc.called_scope = Z_OBJCE_P(object);
+ fcc.object_ptr = object;
+
+ if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute %s::%s()", uwrap->ce->name, uwrap->ce->constructor->common.function_name);
+ zval_dtor(object);
+ FREE_ZVAL(object);
+ return NULL;
+ } else {
+ if (retval_ptr) {
+ zval_ptr_dtor(&retval_ptr);
+ }
+ }
+ }
+ return object;
+}
+
+static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
+ php_userstream_data_t *us;
+ zval *zfilename, *zmode, *zopened, *zoptions, *zretval = NULL, *zfuncname;
+ zval **args[4];
+ int call_result;
+ php_stream *stream = NULL;
+ zend_bool old_in_user_include;
+
+ /* Try to catch bad usage without preventing flexibility */
+ if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "infinite recursion prevented");
+ return NULL;
+ }
+ FG(user_stream_current_filename) = filename;
+
+ /* if the user stream was registered as local and we are in include context,
+ we add allow_url_include restrictions to allow_url_fopen ones */
+ /* we need only is_url == 0 here since if is_url == 1 and remote wrappers
+ were restricted we wouldn't get here */
+ old_in_user_include = PG(in_user_include);
+ if(uwrap->wrapper.is_url == 0 &&
+ (options & STREAM_OPEN_FOR_INCLUDE) &&
+ !PG(allow_url_include)) {
+ PG(in_user_include) = 1;
+ }
+
+ us = emalloc(sizeof(*us));
+ us->wrapper = uwrap;
+
+ us->object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(us->object == NULL) {
+ FG(user_stream_current_filename) = NULL;
+ PG(in_user_include) = old_in_user_include;
+ efree(us);
+ return NULL;
+ }
+
+ /* call it's stream_open method - set up params first */
+ MAKE_STD_ZVAL(zfilename);
+ ZVAL_STRING(zfilename, filename, 1);
+ args[0] = &zfilename;
+
+ MAKE_STD_ZVAL(zmode);
+ ZVAL_STRING(zmode, mode, 1);
+ args[1] = &zmode;
+
+ MAKE_STD_ZVAL(zoptions);
+ ZVAL_LONG(zoptions, options);
+ args[2] = &zoptions;
+
+ MAKE_STD_ZVAL(zopened);
+ Z_SET_REFCOUNT_P(zopened, 1);
+ Z_SET_ISREF_P(zopened);
+ ZVAL_NULL(zopened);
+ args[3] = &zopened;
+
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, USERSTREAM_OPEN, 1);
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ zfuncname,
+ &zretval,
+ 4, args,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && zretval != NULL && zval_is_true(zretval)) {
+ /* the stream is now open! */
+ stream = php_stream_alloc_rel(&php_stream_userspace_ops, us, 0, mode);
+
+ /* if the opened path is set, copy it out */
+ if (Z_TYPE_P(zopened) == IS_STRING && opened_path) {
+ *opened_path = estrndup(Z_STRVAL_P(zopened), Z_STRLEN_P(zopened));
+ }
+
+ /* set wrapper data to be a reference to our object */
+ stream->wrapperdata = us->object;
+ zval_add_ref(&stream->wrapperdata);
+ } else {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "\"%s::" USERSTREAM_OPEN "\" call failed",
+ us->wrapper->classname);
+ }
+
+ /* destroy everything else */
+ if (stream == NULL) {
+ zval_ptr_dtor(&us->object);
+ efree(us);
+ }
+ if (zretval)
+ zval_ptr_dtor(&zretval);
+
+ zval_ptr_dtor(&zfuncname);
+ zval_ptr_dtor(&zopened);
+ zval_ptr_dtor(&zoptions);
+ zval_ptr_dtor(&zmode);
+ zval_ptr_dtor(&zfilename);
+
+ FG(user_stream_current_filename) = NULL;
+
+ PG(in_user_include) = old_in_user_include;
+ return stream;
+}
+
+static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filename, char *mode,
+ int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
+ php_userstream_data_t *us;
+ zval *zfilename, *zoptions, *zretval = NULL, *zfuncname;
+ zval **args[2];
+ int call_result;
+ php_stream *stream = NULL;
+
+ /* Try to catch bad usage without preventing flexibility */
+ if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "infinite recursion prevented");
+ return NULL;
+ }
+ FG(user_stream_current_filename) = filename;
+
+ us = emalloc(sizeof(*us));
+ us->wrapper = uwrap;
+
+ us->object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(us->object == NULL) {
+ FG(user_stream_current_filename) = NULL;
+ efree(us);
+ return NULL;
+ }
+
+ /* call it's dir_open method - set up params first */
+ MAKE_STD_ZVAL(zfilename);
+ ZVAL_STRING(zfilename, filename, 1);
+ args[0] = &zfilename;
+
+ MAKE_STD_ZVAL(zoptions);
+ ZVAL_LONG(zoptions, options);
+ args[1] = &zoptions;
+
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, USERSTREAM_DIR_OPEN, 1);
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ zfuncname,
+ &zretval,
+ 2, args,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && zretval != NULL && zval_is_true(zretval)) {
+ /* the stream is now open! */
+ stream = php_stream_alloc_rel(&php_stream_userspace_dir_ops, us, 0, mode);
+
+ /* set wrapper data to be a reference to our object */
+ stream->wrapperdata = us->object;
+ zval_add_ref(&stream->wrapperdata);
+ } else {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "\"%s::" USERSTREAM_DIR_OPEN "\" call failed",
+ us->wrapper->classname);
+ }
+
+ /* destroy everything else */
+ if (stream == NULL) {
+ zval_ptr_dtor(&us->object);
+ efree(us);
+ }
+ if (zretval)
+ zval_ptr_dtor(&zretval);
+
+ zval_ptr_dtor(&zfuncname);
+ zval_ptr_dtor(&zoptions);
+ zval_ptr_dtor(&zfilename);
+
+ FG(user_stream_current_filename) = NULL;
+
+ return stream;
+}
+
+
+/* {{{ proto bool stream_wrapper_register(string protocol, string classname[, integer flags])
+ Registers a custom URL protocol handler class */
+PHP_FUNCTION(stream_wrapper_register)
+{
+ char *protocol, *classname;
+ int protocol_len, classname_len;
+ struct php_user_stream_wrapper * uwrap;
+ int rsrc_id;
+ long flags = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &protocol, &protocol_len, &classname, &classname_len, &flags) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ uwrap = (struct php_user_stream_wrapper *)ecalloc(1, sizeof(*uwrap));
+ uwrap->protoname = estrndup(protocol, protocol_len);
+ uwrap->classname = estrndup(classname, classname_len);
+ uwrap->wrapper.wops = &user_stream_wops;
+ uwrap->wrapper.abstract = uwrap;
+ uwrap->wrapper.is_url = ((flags & PHP_STREAM_IS_URL) != 0);
+
+ rsrc_id = ZEND_REGISTER_RESOURCE(NULL, uwrap, le_protocols);
+
+ if (zend_lookup_class(uwrap->classname, classname_len, (zend_class_entry***)&uwrap->ce TSRMLS_CC) == SUCCESS) {
+ uwrap->ce = *(zend_class_entry**)uwrap->ce;
+ if (php_register_url_stream_wrapper_volatile(protocol, &uwrap->wrapper TSRMLS_CC) == SUCCESS) {
+ RETURN_TRUE;
+ } else {
+ /* We failed. But why? */
+ if (zend_hash_exists(php_stream_get_url_stream_wrappers_hash(), protocol, protocol_len + 1)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Protocol %s:// is already defined.", protocol);
+ } else {
+ /* Hash doesn't exist so it must have been an invalid protocol scheme */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid protocol scheme specified. Unable to register wrapper class %s to %s://", classname, protocol);
+ }
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "class '%s' is undefined", classname);
+ }
+
+ zend_list_delete(rsrc_id);
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool stream_wrapper_unregister(string protocol)
+ Unregister a wrapper for the life of the current request. */
+PHP_FUNCTION(stream_wrapper_unregister)
+{
+ char *protocol;
+ int protocol_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &protocol, &protocol_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (php_unregister_url_stream_wrapper_volatile(protocol TSRMLS_CC) == FAILURE) {
+ /* We failed */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to unregister protocol %s://", protocol);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool stream_wrapper_restore(string protocol)
+ Restore the original protocol handler, overriding if necessary */
+PHP_FUNCTION(stream_wrapper_restore)
+{
+ char *protocol;
+ int protocol_len;
+ php_stream_wrapper **wrapperpp = NULL, *wrapper;
+ HashTable *global_wrapper_hash;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &protocol, &protocol_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ global_wrapper_hash = php_stream_get_url_stream_wrappers_hash_global();
+ if (php_stream_get_url_stream_wrappers_hash() == global_wrapper_hash) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s:// was never changed, nothing to restore", protocol);
+ RETURN_TRUE;
+ }
+
+ if ((zend_hash_find(global_wrapper_hash, protocol, protocol_len + 1, (void**)&wrapperpp) == FAILURE) || !wrapperpp) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s:// never existed, nothing to restore", protocol);
+ RETURN_FALSE;
+ }
+
+ /* next line might delete the pointer that wrapperpp points at, so deref it now */
+ wrapper = *wrapperpp;
+
+ /* A failure here could be okay given that the protocol might have been merely unregistered */
+ php_unregister_url_stream_wrapper_volatile(protocol TSRMLS_CC);
+
+ if (php_register_url_stream_wrapper_volatile(protocol, wrapper TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to restore original %s:// wrapper", protocol);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+static size_t php_userstreamop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
+{
+ zval func_name;
+ zval *retval = NULL;
+ int call_result;
+ php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+ zval **args[1];
+ zval *zbufptr;
+ size_t didwrite = 0;
+
+ assert(us != NULL);
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_WRITE, sizeof(USERSTREAM_WRITE)-1, 0);
+
+ MAKE_STD_ZVAL(zbufptr);
+ ZVAL_STRINGL(zbufptr, (char*)buf, count, 1);;
+ args[0] = &zbufptr;
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 1, args,
+ 0, NULL TSRMLS_CC);
+ zval_ptr_dtor(&zbufptr);
+
+ didwrite = 0;
+ if (call_result == SUCCESS && retval != NULL) {
+ convert_to_long(retval);
+ didwrite = Z_LVAL_P(retval);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_WRITE " is not implemented!",
+ us->wrapper->classname);
+ }
+
+ /* don't allow strange buffer overruns due to bogus return */
+ if (didwrite > count) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_WRITE " wrote %ld bytes more data than requested (%ld written, %ld max)",
+ us->wrapper->classname,
+ (long)(didwrite - count), (long)didwrite, (long)count);
+ didwrite = count;
+ }
+
+ if (retval)
+ zval_ptr_dtor(&retval);
+
+ return didwrite;
+}
+
+static size_t php_userstreamop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ zval func_name;
+ zval *retval = NULL;
+ zval **args[1];
+ int call_result;
+ size_t didread = 0;
+ php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+ zval *zcount;
+
+ assert(us != NULL);
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_READ, sizeof(USERSTREAM_READ)-1, 0);
+
+ MAKE_STD_ZVAL(zcount);
+ ZVAL_LONG(zcount, count);
+ args[0] = &zcount;
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 1, args,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && retval != NULL) {
+ convert_to_string(retval);
+ didread = Z_STRLEN_P(retval);
+ if (didread > count) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_READ " - read %ld bytes more data than requested (%ld read, %ld max) - excess data will be lost",
+ us->wrapper->classname, (long)(didread - count), (long)didread, (long)count);
+ didread = count;
+ }
+ if (didread > 0)
+ memcpy(buf, Z_STRVAL_P(retval), didread);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_READ " is not implemented!",
+ us->wrapper->classname);
+ }
+ zval_ptr_dtor(&zcount);
+
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ retval = NULL;
+ }
+
+ /* since the user stream has no way of setting the eof flag directly, we need to ask it if we hit eof */
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_EOF, sizeof(USERSTREAM_EOF)-1, 0);
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 0, NULL, 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && retval != NULL && zval_is_true(retval)) {
+ stream->eof = 1;
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF",
+ us->wrapper->classname);
+
+ stream->eof = 1;
+ }
+
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ retval = NULL;
+ }
+
+ return didread;
+}
+
+static int php_userstreamop_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ zval func_name;
+ zval *retval = NULL;
+ php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+
+ assert(us != NULL);
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_CLOSE, sizeof(USERSTREAM_CLOSE)-1, 0);
+
+ call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 0, NULL, 0, NULL TSRMLS_CC);
+
+ if (retval)
+ zval_ptr_dtor(&retval);
+
+ zval_ptr_dtor(&us->object);
+
+ efree(us);
+
+ return 0;
+}
+
+static int php_userstreamop_flush(php_stream *stream TSRMLS_DC)
+{
+ zval func_name;
+ zval *retval = NULL;
+ int call_result;
+ php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+
+ assert(us != NULL);
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_FLUSH, sizeof(USERSTREAM_FLUSH)-1, 0);
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 0, NULL, 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && retval != NULL && zval_is_true(retval))
+ call_result = 0;
+ else
+ call_result = -1;
+
+ if (retval)
+ zval_ptr_dtor(&retval);
+
+ return call_result;
+}
+
+static int php_userstreamop_seek(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC)
+{
+ zval func_name;
+ zval *retval = NULL;
+ int call_result, ret;
+ php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+ zval **args[2];
+ zval *zoffs, *zwhence;
+
+ assert(us != NULL);
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_SEEK, sizeof(USERSTREAM_SEEK)-1, 0);
+
+ MAKE_STD_ZVAL(zoffs);
+ ZVAL_LONG(zoffs, offset);
+ args[0] = &zoffs;
+
+ MAKE_STD_ZVAL(zwhence);
+ ZVAL_LONG(zwhence, whence);
+ args[1] = &zwhence;
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 2, args,
+ 0, NULL TSRMLS_CC);
+
+ zval_ptr_dtor(&zoffs);
+ zval_ptr_dtor(&zwhence);
+
+ if (call_result == FAILURE) {
+ /* stream_seek is not implemented, so disable seeks for this stream */
+ stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
+ /* there should be no retval to clean up */
+
+ if (retval)
+ zval_ptr_dtor(&retval);
+
+ return -1;
+ } else if (call_result == SUCCESS && retval != NULL && zval_is_true(retval)) {
+ ret = 0;
+ } else {
+ ret = -1;
+ }
+
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ retval = NULL;
+ }
+
+ if (ret) {
+ return ret;
+ }
+
+ /* now determine where we are */
+ ZVAL_STRINGL(&func_name, USERSTREAM_TELL, sizeof(USERSTREAM_TELL)-1, 0);
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 0, NULL, 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_LONG) {
+ *newoffs = Z_LVAL_P(retval);
+ ret = 0;
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_TELL " is not implemented!", us->wrapper->classname);
+ ret = -1;
+ } else {
+ ret = -1;
+ }
+
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+ return ret;
+}
+
+/* parse the return value from one of the stat functions and store the
+ * relevant fields into the statbuf provided */
+static int statbuf_from_array(zval *array, php_stream_statbuf *ssb TSRMLS_DC)
+{
+ zval **elem;
+
+#define STAT_PROP_ENTRY_EX(name, name2) \
+ if (SUCCESS == zend_hash_find(Z_ARRVAL_P(array), #name, sizeof(#name), (void**)&elem)) { \
+ SEPARATE_ZVAL(elem); \
+ convert_to_long(*elem); \
+ ssb->sb.st_##name2 = Z_LVAL_PP(elem); \
+ }
+
+#define STAT_PROP_ENTRY(name) STAT_PROP_ENTRY_EX(name,name)
+
+ memset(ssb, 0, sizeof(php_stream_statbuf));
+ STAT_PROP_ENTRY(dev);
+ STAT_PROP_ENTRY(ino);
+ STAT_PROP_ENTRY(mode);
+ STAT_PROP_ENTRY(nlink);
+ STAT_PROP_ENTRY(uid);
+ STAT_PROP_ENTRY(gid);
+#if HAVE_ST_RDEV
+ STAT_PROP_ENTRY(rdev);
+#endif
+ STAT_PROP_ENTRY(size);
+#ifdef NETWARE
+ STAT_PROP_ENTRY_EX(atime, atime.tv_sec);
+ STAT_PROP_ENTRY_EX(mtime, mtime.tv_sec);
+ STAT_PROP_ENTRY_EX(ctime, ctime.tv_sec);
+#else
+ STAT_PROP_ENTRY(atime);
+ STAT_PROP_ENTRY(mtime);
+ STAT_PROP_ENTRY(ctime);
+#endif
+#ifdef HAVE_ST_BLKSIZE
+ STAT_PROP_ENTRY(blksize);
+#endif
+#ifdef HAVE_ST_BLOCKS
+ STAT_PROP_ENTRY(blocks);
+#endif
+
+#undef STAT_PROP_ENTRY
+#undef STAT_PROP_ENTRY_EX
+ return SUCCESS;
+}
+
+static int php_userstreamop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
+{
+ zval func_name;
+ zval *retval = NULL;
+ int call_result;
+ php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+ int ret = -1;
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_STAT, sizeof(USERSTREAM_STAT)-1, 0);
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 0, NULL, 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_ARRAY) {
+ if (SUCCESS == statbuf_from_array(retval, ssb TSRMLS_CC))
+ ret = 0;
+ } else {
+ if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_STAT " is not implemented!",
+ us->wrapper->classname);
+ }
+ }
+
+ if (retval)
+ zval_ptr_dtor(&retval);
+
+ return ret;
+}
+
+
+static int php_userstreamop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC) {
+ zval func_name;
+ zval *retval = NULL;
+ int call_result;
+ php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+ int ret = PHP_STREAM_OPTION_RETURN_NOTIMPL;
+ zval *zvalue = NULL;
+ zval **args[3];
+
+ switch (option) {
+ case PHP_STREAM_OPTION_CHECK_LIVENESS:
+ ZVAL_STRINGL(&func_name, USERSTREAM_EOF, sizeof(USERSTREAM_EOF)-1, 0);
+ call_result = call_user_function_ex(NULL, &us->object, &func_name, &retval, 0, NULL, 0, NULL TSRMLS_CC);
+ if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_BOOL) {
+ ret = zval_is_true(retval) ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
+ } else {
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF",
+ us->wrapper->classname);
+ }
+ break;
+
+ case PHP_STREAM_OPTION_LOCKING:
+ MAKE_STD_ZVAL(zvalue);
+ ZVAL_LONG(zvalue, 0);
+
+ if (value & LOCK_NB) {
+ Z_LVAL_P(zvalue) |= PHP_LOCK_NB;
+ }
+ switch(value & ~LOCK_NB) {
+ case LOCK_SH:
+ Z_LVAL_P(zvalue) |= PHP_LOCK_SH;
+ break;
+ case LOCK_EX:
+ Z_LVAL_P(zvalue) |= PHP_LOCK_EX;
+ break;
+ case LOCK_UN:
+ Z_LVAL_P(zvalue) |= PHP_LOCK_UN;
+ break;
+ }
+
+ args[0] = &zvalue;
+
+ /* TODO wouldblock */
+ ZVAL_STRINGL(&func_name, USERSTREAM_LOCK, sizeof(USERSTREAM_LOCK)-1, 0);
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 1, args, 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_BOOL) {
+ ret = !Z_LVAL_P(retval);
+ } else if (call_result == FAILURE) {
+ if (value == 0) {
+ /* lock support test (TODO: more check) */
+ ret = PHP_STREAM_OPTION_RETURN_OK;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_LOCK " is not implemented!",
+ us->wrapper->classname);
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
+ }
+ }
+
+ break;
+
+ case PHP_STREAM_OPTION_TRUNCATE_API:
+ ZVAL_STRINGL(&func_name, USERSTREAM_TRUNCATE, sizeof(USERSTREAM_TRUNCATE)-1, 0);
+
+ switch (value) {
+ case PHP_STREAM_TRUNCATE_SUPPORTED:
+ if (zend_is_callable_ex(&func_name, us->object, IS_CALLABLE_CHECK_SILENT,
+ NULL, NULL, NULL, NULL TSRMLS_CC))
+ ret = PHP_STREAM_OPTION_RETURN_OK;
+ else
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
+ break;
+
+ case PHP_STREAM_TRUNCATE_SET_SIZE: {
+ ptrdiff_t new_size = *(ptrdiff_t*) ptrparam;
+ if (new_size >= 0 && new_size <= (ptrdiff_t)LONG_MAX) {
+ MAKE_STD_ZVAL(zvalue);
+ ZVAL_LONG(zvalue, (long)new_size);
+ args[0] = &zvalue;
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 1, args, 0, NULL TSRMLS_CC);
+ if (call_result == SUCCESS && retval != NULL) {
+ if (Z_TYPE_P(retval) == IS_BOOL) {
+ ret = Z_LVAL_P(retval) ? PHP_STREAM_OPTION_RETURN_OK :
+ PHP_STREAM_OPTION_RETURN_ERR;
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "%s::" USERSTREAM_TRUNCATE " did not return a boolean!",
+ us->wrapper->classname);
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "%s::" USERSTREAM_TRUNCATE " is not implemented!",
+ us->wrapper->classname);
+ }
+ } else { /* bad new size */
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
+ }
+ break;
+ }
+ }
+ break;
+
+ case PHP_STREAM_OPTION_READ_BUFFER:
+ case PHP_STREAM_OPTION_WRITE_BUFFER:
+ case PHP_STREAM_OPTION_READ_TIMEOUT:
+ case PHP_STREAM_OPTION_BLOCKING: {
+ zval *zoption = NULL;
+ zval *zptrparam = NULL;
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_SET_OPTION, sizeof(USERSTREAM_SET_OPTION)-1, 0);
+
+ ALLOC_INIT_ZVAL(zoption);
+ ZVAL_LONG(zoption, option);
+
+ ALLOC_INIT_ZVAL(zvalue);
+ ALLOC_INIT_ZVAL(zptrparam);
+
+ args[0] = &zoption;
+ args[1] = &zvalue;
+ args[2] = &zptrparam;
+
+ switch(option) {
+ case PHP_STREAM_OPTION_READ_BUFFER:
+ case PHP_STREAM_OPTION_WRITE_BUFFER:
+ ZVAL_LONG(zvalue, value);
+ if (ptrparam) {
+ ZVAL_LONG(zptrparam, *(long *)ptrparam);
+ } else {
+ ZVAL_LONG(zptrparam, BUFSIZ);
+ }
+ break;
+ case PHP_STREAM_OPTION_READ_TIMEOUT: {
+ struct timeval tv = *(struct timeval*)ptrparam;
+ ZVAL_LONG(zvalue, tv.tv_sec);
+ ZVAL_LONG(zptrparam, tv.tv_usec);
+ break;
+ }
+ case PHP_STREAM_OPTION_BLOCKING:
+ ZVAL_LONG(zvalue, value);
+ break;
+ default:
+ break;
+ }
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 3, args, 0, NULL TSRMLS_CC);
+
+ if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_SET_OPTION " is not implemented!",
+ us->wrapper->classname);
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
+ } else if (retval && zend_is_true(retval)) {
+ ret = PHP_STREAM_OPTION_RETURN_OK;
+ } else {
+ ret = PHP_STREAM_OPTION_RETURN_ERR;
+ }
+
+ if (zoption) {
+ zval_ptr_dtor(&zoption);
+ }
+ if (zptrparam) {
+ zval_ptr_dtor(&zptrparam);
+ }
+
+ break;
+ }
+ }
+
+ /* clean up */
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+
+
+ if (zvalue) {
+ zval_ptr_dtor(&zvalue);
+ }
+
+ return ret;
+}
+
+
+static int user_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
+{
+ struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
+ zval *zfilename, *zfuncname, *zretval;
+ zval **args[1];
+ int call_result;
+ zval *object;
+ int ret = 0;
+
+ /* create an instance of our class */
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ return ret;
+ }
+
+ /* call the unlink method */
+ MAKE_STD_ZVAL(zfilename);
+ ZVAL_STRING(zfilename, url, 1);
+ args[0] = &zfilename;
+
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, USERSTREAM_UNLINK, 1);
+
+ call_result = call_user_function_ex(NULL,
+ &object,
+ zfuncname,
+ &zretval,
+ 1, args,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && zretval && Z_TYPE_P(zretval) == IS_BOOL) {
+ ret = Z_LVAL_P(zretval);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_UNLINK " is not implemented!", uwrap->classname);
+ }
+
+ /* clean up */
+ zval_ptr_dtor(&object);
+ if (zretval)
+ zval_ptr_dtor(&zretval);
+
+ zval_ptr_dtor(&zfuncname);
+ zval_ptr_dtor(&zfilename);
+
+ return ret;
+}
+
+static int user_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC)
+{
+ struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
+ zval *zold_name, *znew_name, *zfuncname, *zretval;
+ zval **args[2];
+ int call_result;
+ zval *object;
+ int ret = 0;
+
+ /* create an instance of our class */
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ return ret;
+ }
+
+ /* call the rename method */
+ MAKE_STD_ZVAL(zold_name);
+ ZVAL_STRING(zold_name, url_from, 1);
+ args[0] = &zold_name;
+
+ MAKE_STD_ZVAL(znew_name);
+ ZVAL_STRING(znew_name, url_to, 1);
+ args[1] = &znew_name;
+
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, USERSTREAM_RENAME, 1);
+
+ call_result = call_user_function_ex(NULL,
+ &object,
+ zfuncname,
+ &zretval,
+ 2, args,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && zretval && Z_TYPE_P(zretval) == IS_BOOL) {
+ ret = Z_LVAL_P(zretval);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_RENAME " is not implemented!", uwrap->classname);
+ }
+
+ /* clean up */
+ zval_ptr_dtor(&object);
+ if (zretval)
+ zval_ptr_dtor(&zretval);
+
+ zval_ptr_dtor(&zfuncname);
+ zval_ptr_dtor(&zold_name);
+ zval_ptr_dtor(&znew_name);
+
+ return ret;
+}
+
+static int user_wrapper_mkdir(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC)
+{
+ struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
+ zval *zfilename, *zmode, *zoptions, *zfuncname, *zretval;
+ zval **args[3];
+ int call_result;
+ zval *object;
+ int ret = 0;
+
+ /* create an instance of our class */
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ return ret;
+ }
+
+ /* call the mkdir method */
+ MAKE_STD_ZVAL(zfilename);
+ ZVAL_STRING(zfilename, url, 1);
+ args[0] = &zfilename;
+
+ MAKE_STD_ZVAL(zmode);
+ ZVAL_LONG(zmode, mode);
+ args[1] = &zmode;
+
+ MAKE_STD_ZVAL(zoptions);
+ ZVAL_LONG(zoptions, options);
+ args[2] = &zoptions;
+
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, USERSTREAM_MKDIR, 1);
+
+ call_result = call_user_function_ex(NULL,
+ &object,
+ zfuncname,
+ &zretval,
+ 3, args,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && zretval && Z_TYPE_P(zretval) == IS_BOOL) {
+ ret = Z_LVAL_P(zretval);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_MKDIR " is not implemented!", uwrap->classname);
+ }
+
+ /* clean up */
+ zval_ptr_dtor(&object);
+ if (zretval) {
+ zval_ptr_dtor(&zretval);
+ }
+
+ zval_ptr_dtor(&zfuncname);
+ zval_ptr_dtor(&zfilename);
+ zval_ptr_dtor(&zmode);
+ zval_ptr_dtor(&zoptions);
+
+ return ret;
+}
+
+static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
+{
+ struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
+ zval *zfilename, *zoptions, *zfuncname, *zretval;
+ zval **args[3];
+ int call_result;
+ zval *object;
+ int ret = 0;
+
+ /* create an instance of our class */
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ return ret;
+ }
+
+ /* call the rmdir method */
+ MAKE_STD_ZVAL(zfilename);
+ ZVAL_STRING(zfilename, url, 1);
+ args[0] = &zfilename;
+
+ MAKE_STD_ZVAL(zoptions);
+ ZVAL_LONG(zoptions, options);
+ args[1] = &zoptions;
+
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, USERSTREAM_RMDIR, 1);
+
+ call_result = call_user_function_ex(NULL,
+ &object,
+ zfuncname,
+ &zretval,
+ 2, args,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && zretval && Z_TYPE_P(zretval) == IS_BOOL) {
+ ret = Z_LVAL_P(zretval);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_RMDIR " is not implemented!", uwrap->classname);
+ }
+
+ /* clean up */
+ zval_ptr_dtor(&object);
+ if (zretval) {
+ zval_ptr_dtor(&zretval);
+ }
+
+ zval_ptr_dtor(&zfuncname);
+ zval_ptr_dtor(&zfilename);
+ zval_ptr_dtor(&zoptions);
+
+ return ret;
+}
+
+static int user_wrapper_metadata(php_stream_wrapper *wrapper, char *url, int option, void *value, php_stream_context *context TSRMLS_DC)
+{
+ struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
+ zval *zfilename, *zoption, *zvalue, *zfuncname, *zretval;
+ zval **args[3];
+ int call_result;
+ zval *object;
+ int ret = 0;
+
+ MAKE_STD_ZVAL(zvalue);
+ switch(option) {
+ case PHP_STREAM_META_TOUCH:
+ array_init(zvalue);
+ if(value) {
+ struct utimbuf *newtime = (struct utimbuf *)value;
+ add_index_long(zvalue, 0, newtime->modtime);
+ add_index_long(zvalue, 1, newtime->actime);
+ }
+ break;
+ case PHP_STREAM_META_GROUP:
+ case PHP_STREAM_META_OWNER:
+ case PHP_STREAM_META_ACCESS:
+ ZVAL_LONG(zvalue, *(long *)value);
+ break;
+ case PHP_STREAM_META_GROUP_NAME:
+ case PHP_STREAM_META_OWNER_NAME:
+ ZVAL_STRING(zvalue, value, 1);
+ break;
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown option %d for " USERSTREAM_METADATA, option);
+ zval_ptr_dtor(&zvalue);
+ return ret;
+ }
+
+ /* create an instance of our class */
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ zval_ptr_dtor(&zvalue);
+ return ret;
+ }
+
+ /* call the mkdir method */
+ MAKE_STD_ZVAL(zfilename);
+ ZVAL_STRING(zfilename, url, 1);
+ args[0] = &zfilename;
+
+ MAKE_STD_ZVAL(zoption);
+ ZVAL_LONG(zoption, option);
+ args[1] = &zoption;
+
+ args[2] = &zvalue;
+
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, USERSTREAM_METADATA, 1);
+
+ call_result = call_user_function_ex(NULL,
+ &object,
+ zfuncname,
+ &zretval,
+ 3, args,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && zretval && Z_TYPE_P(zretval) == IS_BOOL) {
+ ret = Z_LVAL_P(zretval);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_METADATA " is not implemented!", uwrap->classname);
+ }
+
+ /* clean up */
+ zval_ptr_dtor(&object);
+ if (zretval) {
+ zval_ptr_dtor(&zretval);
+ }
+
+ zval_ptr_dtor(&zfuncname);
+ zval_ptr_dtor(&zfilename);
+ zval_ptr_dtor(&zoption);
+ zval_ptr_dtor(&zvalue);
+
+ return ret;
+}
+
+
+static int user_wrapper_stat_url(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
+{
+ struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
+ zval *zfilename, *zfuncname, *zretval, *zflags;
+ zval **args[2];
+ int call_result;
+ zval *object;
+ int ret = -1;
+
+ /* create an instance of our class */
+ object = user_stream_create_object(uwrap, context TSRMLS_CC);
+ if(object == NULL) {
+ return ret;
+ }
+
+ /* call it's stat_url method - set up params first */
+ MAKE_STD_ZVAL(zfilename);
+ ZVAL_STRING(zfilename, url, 1);
+ args[0] = &zfilename;
+
+ MAKE_STD_ZVAL(zflags);
+ ZVAL_LONG(zflags, flags);
+ args[1] = &zflags;
+
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, USERSTREAM_STATURL, 1);
+
+ call_result = call_user_function_ex(NULL,
+ &object,
+ zfuncname,
+ &zretval,
+ 2, args,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && zretval != NULL && Z_TYPE_P(zretval) == IS_ARRAY) {
+ /* We got the info we needed */
+ if (SUCCESS == statbuf_from_array(zretval, ssb TSRMLS_CC))
+ ret = 0;
+ } else {
+ if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_STATURL " is not implemented!",
+ uwrap->classname);
+ }
+ }
+
+ /* clean up */
+ zval_ptr_dtor(&object);
+ if (zretval)
+ zval_ptr_dtor(&zretval);
+
+ zval_ptr_dtor(&zfuncname);
+ zval_ptr_dtor(&zfilename);
+ zval_ptr_dtor(&zflags);
+
+ return ret;
+
+}
+
+static size_t php_userstreamop_readdir(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ zval func_name;
+ zval *retval = NULL;
+ int call_result;
+ size_t didread = 0;
+ php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+ php_stream_dirent *ent = (php_stream_dirent*)buf;
+
+ /* avoid problems if someone mis-uses the stream */
+ if (count != sizeof(php_stream_dirent))
+ return 0;
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_DIR_READ, sizeof(USERSTREAM_DIR_READ)-1, 0);
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 0, NULL,
+ 0, NULL TSRMLS_CC);
+
+ if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) != IS_BOOL) {
+ convert_to_string(retval);
+ PHP_STRLCPY(ent->d_name, Z_STRVAL_P(retval), sizeof(ent->d_name), Z_STRLEN_P(retval));
+
+ didread = sizeof(php_stream_dirent);
+ } else if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_DIR_READ " is not implemented!",
+ us->wrapper->classname);
+ }
+
+ if (retval)
+ zval_ptr_dtor(&retval);
+
+ return didread;
+}
+
+static int php_userstreamop_closedir(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ zval func_name;
+ zval *retval = NULL;
+ php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+
+ assert(us != NULL);
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_DIR_CLOSE, sizeof(USERSTREAM_DIR_CLOSE)-1, 0);
+
+ call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 0, NULL, 0, NULL TSRMLS_CC);
+
+ if (retval)
+ zval_ptr_dtor(&retval);
+
+ zval_ptr_dtor(&us->object);
+
+ efree(us);
+
+ return 0;
+}
+
+static int php_userstreamop_rewinddir(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC)
+{
+ zval func_name;
+ zval *retval = NULL;
+ php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_DIR_REWIND, sizeof(USERSTREAM_DIR_REWIND)-1, 0);
+
+ call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 0, NULL, 0, NULL TSRMLS_CC);
+
+ if (retval)
+ zval_ptr_dtor(&retval);
+
+ return 0;
+
+}
+
+static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr TSRMLS_DC)
+{
+ php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
+ zval func_name;
+ zval *retval = NULL;
+ zval *zcastas = NULL;
+ zval **args[1];
+ php_stream * intstream = NULL;
+ int call_result;
+ int ret = FAILURE;
+
+ ZVAL_STRINGL(&func_name, USERSTREAM_CAST, sizeof(USERSTREAM_CAST)-1, 0);
+
+ ALLOC_INIT_ZVAL(zcastas);
+ switch(castas) {
+ case PHP_STREAM_AS_FD_FOR_SELECT:
+ ZVAL_LONG(zcastas, PHP_STREAM_AS_FD_FOR_SELECT);
+ break;
+ default:
+ ZVAL_LONG(zcastas, PHP_STREAM_AS_STDIO);
+ break;
+ }
+ args[0] = &zcastas;
+
+ call_result = call_user_function_ex(NULL,
+ &us->object,
+ &func_name,
+ &retval,
+ 1, args, 0, NULL TSRMLS_CC);
+
+ do {
+ if (call_result == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_CAST " is not implemented!",
+ us->wrapper->classname);
+ break;
+ }
+ if (retval == NULL || !zend_is_true(retval)) {
+ break;
+ }
+ php_stream_from_zval_no_verify(intstream, &retval);
+ if (!intstream) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_CAST " must return a stream resource",
+ us->wrapper->classname);
+ break;
+ }
+ if (intstream == stream) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_CAST " must not return itself",
+ us->wrapper->classname);
+ intstream = NULL;
+ break;
+ }
+ ret = php_stream_cast(intstream, castas, retptr, 1);
+ } while (0);
+
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+ if (zcastas) {
+ zval_ptr_dtor(&zcastas);
+ }
+
+ return ret;
+}
+
+php_stream_ops php_stream_userspace_ops = {
+ php_userstreamop_write, php_userstreamop_read,
+ php_userstreamop_close, php_userstreamop_flush,
+ "user-space",
+ php_userstreamop_seek,
+ php_userstreamop_cast,
+ php_userstreamop_stat,
+ php_userstreamop_set_option,
+};
+
+php_stream_ops php_stream_userspace_dir_ops = {
+ NULL, /* write */
+ php_userstreamop_readdir,
+ php_userstreamop_closedir,
+ NULL, /* flush */
+ "user-space-dir",
+ php_userstreamop_rewinddir,
+ NULL, /* cast */
+ NULL, /* stat */
+ NULL /* set_option */
+};
+
+
diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c
new file mode 100644
index 0000000..beffc73
--- /dev/null
+++ b/main/streams/xp_socket.c
@@ -0,0 +1,838 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+#include "ext/standard/file.h"
+#include "streams/php_streams_int.h"
+#include "php_network.h"
+
+#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE)
+# undef AF_UNIX
+#endif
+
+#if defined(AF_UNIX)
+#include <sys/un.h>
+#endif
+
+#ifndef MSG_DONTWAIT
+# define MSG_DONTWAIT 0
+#endif
+
+#ifndef MSG_PEEK
+# define MSG_PEEK 0
+#endif
+
+php_stream_ops php_stream_generic_socket_ops;
+PHPAPI php_stream_ops php_stream_socket_ops;
+php_stream_ops php_stream_udp_socket_ops;
+#ifdef AF_UNIX
+php_stream_ops php_stream_unix_socket_ops;
+php_stream_ops php_stream_unixdg_socket_ops;
+#endif
+
+
+static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC);
+
+/* {{{ Generic socket stream operations */
+static size_t php_sockop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
+{
+ php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
+ int didwrite;
+ struct timeval *ptimeout;
+
+ if (sock->socket == -1) {
+ return 0;
+ }
+
+ if (sock->timeout.tv_sec == -1)
+ ptimeout = NULL;
+ else
+ ptimeout = &sock->timeout;
+
+retry:
+ didwrite = send(sock->socket, buf, count, (sock->is_blocked && ptimeout) ? MSG_DONTWAIT : 0);
+
+ if (didwrite <= 0) {
+ long err = php_socket_errno();
+ char *estr;
+
+ if (sock->is_blocked && err == EWOULDBLOCK) {
+ int retval;
+
+ sock->timeout_event = 0;
+
+ do {
+ retval = php_pollfd_for(sock->socket, POLLOUT, ptimeout);
+
+ if (retval == 0) {
+ sock->timeout_event = 1;
+ break;
+ }
+
+ if (retval > 0) {
+ /* writable now; retry */
+ goto retry;
+ }
+
+ err = php_socket_errno();
+ } while (err == EINTR);
+ }
+ estr = php_socket_strerror(err, NULL, 0);
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "send of %ld bytes failed with errno=%ld %s",
+ (long)count, err, estr);
+ efree(estr);
+ }
+
+ if (didwrite > 0) {
+ php_stream_notify_progress_increment(stream->context, didwrite, 0);
+ }
+
+ if (didwrite < 0) {
+ didwrite = 0;
+ }
+
+ return didwrite;
+}
+
+static void php_sock_stream_wait_for_data(php_stream *stream, php_netstream_data_t *sock TSRMLS_DC)
+{
+ int retval;
+ struct timeval *ptimeout;
+
+ if (sock->socket == -1) {
+ return;
+ }
+
+ sock->timeout_event = 0;
+
+ if (sock->timeout.tv_sec == -1)
+ ptimeout = NULL;
+ else
+ ptimeout = &sock->timeout;
+
+ while(1) {
+ retval = php_pollfd_for(sock->socket, PHP_POLLREADABLE, ptimeout);
+
+ if (retval == 0)
+ sock->timeout_event = 1;
+
+ if (retval >= 0)
+ break;
+
+ if (php_socket_errno() != EINTR)
+ break;
+ }
+}
+
+static size_t php_sockop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
+ int nr_bytes = 0;
+
+ if (sock->socket == -1) {
+ return 0;
+ }
+
+ if (sock->is_blocked) {
+ php_sock_stream_wait_for_data(stream, sock TSRMLS_CC);
+ if (sock->timeout_event)
+ return 0;
+ }
+
+ nr_bytes = recv(sock->socket, buf, count, (sock->is_blocked && sock->timeout.tv_sec != -1) ? MSG_DONTWAIT : 0);
+
+ stream->eof = (nr_bytes == 0 || (nr_bytes == -1 && php_socket_errno() != EWOULDBLOCK));
+
+ if (nr_bytes > 0) {
+ php_stream_notify_progress_increment(stream->context, nr_bytes, 0);
+ }
+
+ if (nr_bytes < 0) {
+ nr_bytes = 0;
+ }
+
+ return nr_bytes;
+}
+
+
+static int php_sockop_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
+#ifdef PHP_WIN32
+ int n;
+#endif
+
+ if (close_handle) {
+
+#ifdef PHP_WIN32
+ if (sock->socket == -1)
+ sock->socket = SOCK_ERR;
+#endif
+ if (sock->socket != SOCK_ERR) {
+#ifdef PHP_WIN32
+ /* prevent more data from coming in */
+ shutdown(sock->socket, SHUT_RD);
+
+ /* try to make sure that the OS sends all data before we close the connection.
+ * Essentially, we are waiting for the socket to become writeable, which means
+ * that all pending data has been sent.
+ * We use a small timeout which should encourage the OS to send the data,
+ * but at the same time avoid hanging indefintely.
+ * */
+ do {
+ n = php_pollfd_for_ms(sock->socket, POLLOUT, 500);
+ } while (n == -1 && php_socket_errno() == EINTR);
+#endif
+ closesocket(sock->socket);
+ sock->socket = SOCK_ERR;
+ }
+
+ }
+
+ pefree(sock, php_stream_is_persistent(stream));
+
+ return 0;
+}
+
+static int php_sockop_flush(php_stream *stream TSRMLS_DC)
+{
+#if 0
+ php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
+ return fsync(sock->socket);
+#endif
+ return 0;
+}
+
+static int php_sockop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
+{
+ php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
+#if ZEND_WIN32
+ return 0;
+#else
+ return fstat(sock->socket, &ssb->sb);
+#endif
+}
+
+static inline int sock_sendto(php_netstream_data_t *sock, char *buf, size_t buflen, int flags,
+ struct sockaddr *addr, socklen_t addrlen
+ TSRMLS_DC)
+{
+ int ret;
+ if (addr) {
+ ret = sendto(sock->socket, buf, buflen, flags, addr, addrlen);
+ return (ret == SOCK_CONN_ERR) ? -1 : ret;
+ }
+ return ((ret = send(sock->socket, buf, buflen, flags)) == SOCK_CONN_ERR) ? -1 : ret;
+}
+
+static inline int sock_recvfrom(php_netstream_data_t *sock, char *buf, size_t buflen, int flags,
+ char **textaddr, long *textaddrlen,
+ struct sockaddr **addr, socklen_t *addrlen
+ TSRMLS_DC)
+{
+ php_sockaddr_storage sa;
+ socklen_t sl = sizeof(sa);
+ int ret;
+ int want_addr = textaddr || addr;
+
+ if (want_addr) {
+ ret = recvfrom(sock->socket, buf, buflen, flags, (struct sockaddr*)&sa, &sl);
+ ret = (ret == SOCK_CONN_ERR) ? -1 : ret;
+ php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
+ textaddr, textaddrlen, addr, addrlen TSRMLS_CC);
+ } else {
+ ret = recv(sock->socket, buf, buflen, flags);
+ ret = (ret == SOCK_CONN_ERR) ? -1 : ret;
+ }
+
+ return ret;
+}
+
+static int php_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
+{
+ int oldmode, flags;
+ php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
+ php_stream_xport_param *xparam;
+
+ switch(option) {
+ case PHP_STREAM_OPTION_CHECK_LIVENESS:
+ {
+ struct timeval tv;
+ char buf;
+ int alive = 1;
+
+ if (value == -1) {
+ if (sock->timeout.tv_sec == -1) {
+ tv.tv_sec = FG(default_socket_timeout);
+ tv.tv_usec = 0;
+ } else {
+ tv = sock->timeout;
+ }
+ } else {
+ tv.tv_sec = value;
+ tv.tv_usec = 0;
+ }
+
+ if (sock->socket == -1) {
+ alive = 0;
+ } else if (php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
+ if (0 >= recv(sock->socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EWOULDBLOCK) {
+ alive = 0;
+ }
+ }
+ return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
+ }
+
+ case PHP_STREAM_OPTION_BLOCKING:
+ oldmode = sock->is_blocked;
+ if (SUCCESS == php_set_sock_blocking(sock->socket, value TSRMLS_CC)) {
+ sock->is_blocked = value;
+ return oldmode;
+ }
+ return PHP_STREAM_OPTION_RETURN_ERR;
+
+ case PHP_STREAM_OPTION_READ_TIMEOUT:
+ sock->timeout = *(struct timeval*)ptrparam;
+ sock->timeout_event = 0;
+ return PHP_STREAM_OPTION_RETURN_OK;
+
+ case PHP_STREAM_OPTION_META_DATA_API:
+ add_assoc_bool((zval *)ptrparam, "timed_out", sock->timeout_event);
+ add_assoc_bool((zval *)ptrparam, "blocked", sock->is_blocked);
+ add_assoc_bool((zval *)ptrparam, "eof", stream->eof);
+ return PHP_STREAM_OPTION_RETURN_OK;
+
+ case PHP_STREAM_OPTION_XPORT_API:
+ xparam = (php_stream_xport_param *)ptrparam;
+
+ switch (xparam->op) {
+ case STREAM_XPORT_OP_LISTEN:
+ xparam->outputs.returncode = (listen(sock->socket, xparam->inputs.backlog) == 0) ? 0: -1;
+ return PHP_STREAM_OPTION_RETURN_OK;
+
+ case STREAM_XPORT_OP_GET_NAME:
+ xparam->outputs.returncode = php_network_get_sock_name(sock->socket,
+ xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
+ xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
+ xparam->want_addr ? &xparam->outputs.addr : NULL,
+ xparam->want_addr ? &xparam->outputs.addrlen : NULL
+ TSRMLS_CC);
+ return PHP_STREAM_OPTION_RETURN_OK;
+
+ case STREAM_XPORT_OP_GET_PEER_NAME:
+ xparam->outputs.returncode = php_network_get_peer_name(sock->socket,
+ xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
+ xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
+ xparam->want_addr ? &xparam->outputs.addr : NULL,
+ xparam->want_addr ? &xparam->outputs.addrlen : NULL
+ TSRMLS_CC);
+ return PHP_STREAM_OPTION_RETURN_OK;
+
+ case STREAM_XPORT_OP_SEND:
+ flags = 0;
+ if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
+ flags |= MSG_OOB;
+ }
+ xparam->outputs.returncode = sock_sendto(sock,
+ xparam->inputs.buf, xparam->inputs.buflen,
+ flags,
+ xparam->inputs.addr,
+ xparam->inputs.addrlen TSRMLS_CC);
+ if (xparam->outputs.returncode == -1) {
+ char *err = php_socket_strerror(php_socket_errno(), NULL, 0);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "%s\n", err);
+ efree(err);
+ }
+ return PHP_STREAM_OPTION_RETURN_OK;
+
+ case STREAM_XPORT_OP_RECV:
+ flags = 0;
+ if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
+ flags |= MSG_OOB;
+ }
+ if ((xparam->inputs.flags & STREAM_PEEK) == STREAM_PEEK) {
+ flags |= MSG_PEEK;
+ }
+ xparam->outputs.returncode = sock_recvfrom(sock,
+ xparam->inputs.buf, xparam->inputs.buflen,
+ flags,
+ xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
+ xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
+ xparam->want_addr ? &xparam->outputs.addr : NULL,
+ xparam->want_addr ? &xparam->outputs.addrlen : NULL
+ TSRMLS_CC);
+ return PHP_STREAM_OPTION_RETURN_OK;
+
+
+#ifdef HAVE_SHUTDOWN
+# ifndef SHUT_RD
+# define SHUT_RD 0
+# endif
+# ifndef SHUT_WR
+# define SHUT_WR 1
+# endif
+# ifndef SHUT_RDWR
+# define SHUT_RDWR 2
+# endif
+ case STREAM_XPORT_OP_SHUTDOWN: {
+ static const int shutdown_how[] = {SHUT_RD, SHUT_WR, SHUT_RDWR};
+
+ xparam->outputs.returncode = shutdown(sock->socket, shutdown_how[xparam->how]);
+ return PHP_STREAM_OPTION_RETURN_OK;
+ }
+#endif
+
+ default:
+ return PHP_STREAM_OPTION_RETURN_NOTIMPL;
+ }
+
+ default:
+ return PHP_STREAM_OPTION_RETURN_NOTIMPL;
+ }
+}
+
+static int php_sockop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
+{
+ php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
+
+ switch(castas) {
+ case PHP_STREAM_AS_STDIO:
+ if (ret) {
+ *(FILE**)ret = fdopen(sock->socket, stream->mode);
+ if (*ret)
+ return SUCCESS;
+ return FAILURE;
+ }
+ return SUCCESS;
+ case PHP_STREAM_AS_FD_FOR_SELECT:
+ case PHP_STREAM_AS_FD:
+ case PHP_STREAM_AS_SOCKETD:
+ if (ret)
+ *(int*)ret = sock->socket;
+ return SUCCESS;
+ default:
+ return FAILURE;
+ }
+}
+/* }}} */
+
+/* These may look identical, but we need them this way so that
+ * we can determine which type of socket we are dealing with
+ * by inspecting stream->ops.
+ * A "useful" side-effect is that the user's scripts can then
+ * make similar decisions using stream_get_meta_data.
+ * */
+php_stream_ops php_stream_generic_socket_ops = {
+ php_sockop_write, php_sockop_read,
+ php_sockop_close, php_sockop_flush,
+ "generic_socket",
+ NULL, /* seek */
+ php_sockop_cast,
+ php_sockop_stat,
+ php_sockop_set_option,
+};
+
+
+php_stream_ops php_stream_socket_ops = {
+ php_sockop_write, php_sockop_read,
+ php_sockop_close, php_sockop_flush,
+ "tcp_socket",
+ NULL, /* seek */
+ php_sockop_cast,
+ php_sockop_stat,
+ php_tcp_sockop_set_option,
+};
+
+php_stream_ops php_stream_udp_socket_ops = {
+ php_sockop_write, php_sockop_read,
+ php_sockop_close, php_sockop_flush,
+ "udp_socket",
+ NULL, /* seek */
+ php_sockop_cast,
+ php_sockop_stat,
+ php_tcp_sockop_set_option,
+};
+
+#ifdef AF_UNIX
+php_stream_ops php_stream_unix_socket_ops = {
+ php_sockop_write, php_sockop_read,
+ php_sockop_close, php_sockop_flush,
+ "unix_socket",
+ NULL, /* seek */
+ php_sockop_cast,
+ php_sockop_stat,
+ php_tcp_sockop_set_option,
+};
+php_stream_ops php_stream_unixdg_socket_ops = {
+ php_sockop_write, php_sockop_read,
+ php_sockop_close, php_sockop_flush,
+ "udg_socket",
+ NULL, /* seek */
+ php_sockop_cast,
+ php_sockop_stat,
+ php_tcp_sockop_set_option,
+};
+#endif
+
+
+/* network socket operations */
+
+#ifdef AF_UNIX
+static inline int parse_unix_address(php_stream_xport_param *xparam, struct sockaddr_un *unix_addr TSRMLS_DC)
+{
+ memset(unix_addr, 0, sizeof(*unix_addr));
+ unix_addr->sun_family = AF_UNIX;
+
+ /* we need to be binary safe on systems that support an abstract
+ * namespace */
+ if (xparam->inputs.namelen >= sizeof(unix_addr->sun_path)) {
+ /* On linux, when the path begins with a NUL byte we are
+ * referring to an abstract namespace. In theory we should
+ * allow an extra byte below, since we don't need the NULL.
+ * BUT, to get into this branch of code, the name is too long,
+ * so we don't care. */
+ xparam->inputs.namelen = sizeof(unix_addr->sun_path) - 1;
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE,
+ "socket path exceeded the maximum allowed length of %lu bytes "
+ "and was truncated", (unsigned long)sizeof(unix_addr->sun_path));
+ }
+
+ memcpy(unix_addr->sun_path, xparam->inputs.name, xparam->inputs.namelen);
+
+ return 1;
+}
+#endif
+
+static inline char *parse_ip_address_ex(const char *str, int str_len, int *portno, int get_err, char **err TSRMLS_DC)
+{
+ char *colon;
+ char *host = NULL;
+
+#ifdef HAVE_IPV6
+ char *p;
+
+ if (*(str) == '[' && str_len > 1) {
+ /* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */
+ p = memchr(str + 1, ']', str_len - 2);
+ if (!p || *(p + 1) != ':') {
+ if (get_err) {
+ spprintf(err, 0, "Failed to parse IPv6 address \"%s\"", str);
+ }
+ return NULL;
+ }
+ *portno = atoi(p + 2);
+ return estrndup(str + 1, p - str - 1);
+ }
+#endif
+ if (str_len) {
+ colon = memchr(str, ':', str_len - 1);
+ } else {
+ colon = NULL;
+ }
+ if (colon) {
+ *portno = atoi(colon + 1);
+ host = estrndup(str, colon - str);
+ } else {
+ if (get_err) {
+ spprintf(err, 0, "Failed to parse address \"%s\"", str);
+ }
+ return NULL;
+ }
+
+ return host;
+}
+
+static inline char *parse_ip_address(php_stream_xport_param *xparam, int *portno TSRMLS_DC)
+{
+ return parse_ip_address_ex(xparam->inputs.name, xparam->inputs.namelen, portno, xparam->want_errortext, &xparam->outputs.error_text TSRMLS_CC);
+}
+
+static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *sock,
+ php_stream_xport_param *xparam TSRMLS_DC)
+{
+ char *host = NULL;
+ int portno, err;
+
+#ifdef AF_UNIX
+ if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
+ struct sockaddr_un unix_addr;
+
+ sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
+
+ if (sock->socket == SOCK_ERR) {
+ if (xparam->want_errortext) {
+ spprintf(&xparam->outputs.error_text, 0, "Failed to create unix%s socket %s",
+ stream->ops == &php_stream_unix_socket_ops ? "" : "datagram",
+ strerror(errno));
+ }
+ return -1;
+ }
+
+ parse_unix_address(xparam, &unix_addr TSRMLS_CC);
+
+ return bind(sock->socket, (struct sockaddr *)&unix_addr, sizeof(unix_addr));
+ }
+#endif
+
+ host = parse_ip_address(xparam, &portno TSRMLS_CC);
+
+ if (host == NULL) {
+ return -1;
+ }
+
+ sock->socket = php_network_bind_socket_to_local_addr(host, portno,
+ stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
+ xparam->want_errortext ? &xparam->outputs.error_text : NULL,
+ &err
+ TSRMLS_CC);
+
+ if (host) {
+ efree(host);
+ }
+
+ return sock->socket == -1 ? -1 : 0;
+}
+
+static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_t *sock,
+ php_stream_xport_param *xparam TSRMLS_DC)
+{
+ char *host = NULL, *bindto = NULL;
+ int portno, bindport = 0;
+ int err = 0;
+ int ret;
+ zval **tmpzval = NULL;
+
+#ifdef AF_UNIX
+ if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
+ struct sockaddr_un unix_addr;
+
+ sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
+
+ if (sock->socket == SOCK_ERR) {
+ if (xparam->want_errortext) {
+ spprintf(&xparam->outputs.error_text, 0, "Failed to create unix socket");
+ }
+ return -1;
+ }
+
+ parse_unix_address(xparam, &unix_addr TSRMLS_CC);
+
+ ret = php_network_connect_socket(sock->socket,
+ (const struct sockaddr *)&unix_addr, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + xparam->inputs.namelen,
+ xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC, xparam->inputs.timeout,
+ xparam->want_errortext ? &xparam->outputs.error_text : NULL,
+ &err);
+
+ xparam->outputs.error_code = err;
+
+ goto out;
+ }
+#endif
+
+ host = parse_ip_address(xparam, &portno TSRMLS_CC);
+
+ if (host == NULL) {
+ return -1;
+ }
+
+ if (stream->context && php_stream_context_get_option(stream->context, "socket", "bindto", &tmpzval) == SUCCESS) {
+ if (Z_TYPE_PP(tmpzval) != IS_STRING) {
+ if (xparam->want_errortext) {
+ spprintf(&xparam->outputs.error_text, 0, "local_addr context option is not a string.");
+ }
+ efree(host);
+ return -1;
+ }
+ bindto = parse_ip_address_ex(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), &bindport, xparam->want_errortext, &xparam->outputs.error_text TSRMLS_CC);
+ }
+
+ /* Note: the test here for php_stream_udp_socket_ops is important, because we
+ * want the default to be TCP sockets so that the openssl extension can
+ * re-use this code. */
+
+ sock->socket = php_network_connect_socket_to_host(host, portno,
+ stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
+ xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC,
+ xparam->inputs.timeout,
+ xparam->want_errortext ? &xparam->outputs.error_text : NULL,
+ &err,
+ bindto,
+ bindport
+ TSRMLS_CC);
+
+ ret = sock->socket == -1 ? -1 : 0;
+ xparam->outputs.error_code = err;
+
+ if (host) {
+ efree(host);
+ }
+ if (bindto) {
+ efree(bindto);
+ }
+
+#ifdef AF_UNIX
+out:
+#endif
+
+ if (ret >= 0 && xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC && err == EINPROGRESS) {
+ /* indicates pending connection */
+ return 1;
+ }
+
+ return ret;
+}
+
+static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t *sock,
+ php_stream_xport_param *xparam STREAMS_DC TSRMLS_DC)
+{
+ int clisock;
+
+ xparam->outputs.client = NULL;
+
+ clisock = php_network_accept_incoming(sock->socket,
+ xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
+ xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
+ xparam->want_addr ? &xparam->outputs.addr : NULL,
+ xparam->want_addr ? &xparam->outputs.addrlen : NULL,
+ xparam->inputs.timeout,
+ xparam->want_errortext ? &xparam->outputs.error_text : NULL,
+ &xparam->outputs.error_code
+ TSRMLS_CC);
+
+ if (clisock >= 0) {
+ php_netstream_data_t *clisockdata;
+
+ clisockdata = emalloc(sizeof(*clisockdata));
+
+ if (clisockdata == NULL) {
+ close(clisock);
+ /* technically a fatal error */
+ } else {
+ memcpy(clisockdata, sock, sizeof(*clisockdata));
+ clisockdata->socket = clisock;
+
+ xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
+ if (xparam->outputs.client) {
+ xparam->outputs.client->context = stream->context;
+ if (stream->context) {
+ zend_list_addref(stream->context->rsrc_id);
+ }
+ }
+ }
+ }
+
+ return xparam->outputs.client == NULL ? -1 : 0;
+}
+
+static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
+{
+ php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
+ php_stream_xport_param *xparam;
+
+ switch(option) {
+ case PHP_STREAM_OPTION_XPORT_API:
+ xparam = (php_stream_xport_param *)ptrparam;
+
+ switch(xparam->op) {
+ case STREAM_XPORT_OP_CONNECT:
+ case STREAM_XPORT_OP_CONNECT_ASYNC:
+ xparam->outputs.returncode = php_tcp_sockop_connect(stream, sock, xparam TSRMLS_CC);
+ return PHP_STREAM_OPTION_RETURN_OK;
+
+ case STREAM_XPORT_OP_BIND:
+ xparam->outputs.returncode = php_tcp_sockop_bind(stream, sock, xparam TSRMLS_CC);
+ return PHP_STREAM_OPTION_RETURN_OK;
+
+
+ case STREAM_XPORT_OP_ACCEPT:
+ xparam->outputs.returncode = php_tcp_sockop_accept(stream, sock, xparam STREAMS_CC TSRMLS_CC);
+ return PHP_STREAM_OPTION_RETURN_OK;
+ default:
+ /* fall through */
+ ;
+ }
+ }
+ return php_sockop_set_option(stream, option, value, ptrparam TSRMLS_CC);
+}
+
+
+PHPAPI php_stream *php_stream_generic_socket_factory(const char *proto, long protolen,
+ char *resourcename, long resourcenamelen,
+ const char *persistent_id, int options, int flags,
+ struct timeval *timeout,
+ php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+ php_stream *stream = NULL;
+ php_netstream_data_t *sock;
+ php_stream_ops *ops;
+
+ /* which type of socket ? */
+ if (strncmp(proto, "tcp", protolen) == 0) {
+ ops = &php_stream_socket_ops;
+ } else if (strncmp(proto, "udp", protolen) == 0) {
+ ops = &php_stream_udp_socket_ops;
+ }
+#ifdef AF_UNIX
+ else if (strncmp(proto, "unix", protolen) == 0) {
+ ops = &php_stream_unix_socket_ops;
+ } else if (strncmp(proto, "udg", protolen) == 0) {
+ ops = &php_stream_unixdg_socket_ops;
+ }
+#endif
+ else {
+ /* should never happen */
+ return NULL;
+ }
+
+ sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
+ memset(sock, 0, sizeof(php_netstream_data_t));
+
+ sock->is_blocked = 1;
+ sock->timeout.tv_sec = FG(default_socket_timeout);
+ sock->timeout.tv_usec = 0;
+
+ /* we don't know the socket until we have determined if we are binding or
+ * connecting */
+ sock->socket = -1;
+
+ stream = php_stream_alloc_rel(ops, sock, persistent_id, "r+");
+
+ if (stream == NULL) {
+ pefree(sock, persistent_id ? 1 : 0);
+ return NULL;
+ }
+
+ if (flags == 0) {
+ return stream;
+ }
+
+ return stream;
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/main/strlcat.c b/main/strlcat.c
new file mode 100644
index 0000000..ca22839
--- /dev/null
+++ b/main/strlcat.c
@@ -0,0 +1,106 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+
+#ifndef HAVE_STRLCAT
+
+/* $OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+PHPAPI size_t php_strlcat(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (*d != '\0' && n-- != 0)
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
+#endif /* !HAVE_STRLCAT */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/strlcpy.c b/main/strlcpy.c
new file mode 100644
index 0000000..371faaf
--- /dev/null
+++ b/main/strlcpy.c
@@ -0,0 +1,103 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+
+#ifndef HAVE_STRLCPY
+
+/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+PHPAPI size_t php_strlcpy(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+
+#endif /* !HAVE_STRLCPY */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/main/win32_internal_function_disabled.h b/main/win32_internal_function_disabled.h
new file mode 100644
index 0000000..3a78f6c
--- /dev/null
+++ b/main/win32_internal_function_disabled.h
@@ -0,0 +1,34 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Pierre A. Joye <pierre@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/* 5 means the min version is 5 (XP/2000), 6 (2k8/vista), etc. */
+
+/*
+Windows Server 2008 6.0
+Windows Vista 6.0
+Windows Server 2003 R2 5.2
+Windows Server 2003 5.2
+Windows XP 5.1
+Windows 2000 5.0
+*/
+static const char *function_name_5[] = {"link", NULL};
+const int function_name_cnt_5 = 1;
+static const char *function_name_6[] = {"readlink", "symlink", NULL};
+const int function_name_cnt_6 = 2;
diff --git a/main/win95nt.h b/main/win95nt.h
new file mode 100644
index 0000000..2e944c2
--- /dev/null
+++ b/main/win95nt.h
@@ -0,0 +1,89 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/* Defines and types for Windows 95/NT */
+#define HAVE_DECLARED_TIMEZONE
+#define WIN32_LEAN_AND_MEAN
+#include <io.h>
+#include <malloc.h>
+#include <direct.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <process.h>
+
+typedef int uid_t;
+typedef int gid_t;
+typedef char * caddr_t;
+#define lstat(x, y) php_sys_lstat(x, y)
+#define _IFIFO 0010000 /* fifo */
+#define _IFBLK 0060000 /* block special */
+#define _IFLNK 0120000 /* symbolic link */
+#define S_IFIFO _IFIFO
+#define S_IFBLK _IFBLK
+#define S_IFLNK _IFLNK
+#ifndef S_ISREG
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#define chdir(path) _chdir(path)
+#define mkdir(a, b) _mkdir(a)
+#define rmdir(a) _rmdir(a)
+#define getpid _getpid
+#define php_sleep(t) SleepEx(t*1000, TRUE)
+#ifndef getcwd
+# define getcwd(a, b) _getcwd(a, b)
+#endif
+#define off_t _off_t
+typedef unsigned int uint;
+typedef unsigned long ulong;
+#if !NSAPI
+typedef long pid_t;
+#endif
+
+/* missing in vc5 math.h */
+#define M_PI 3.14159265358979323846
+#define M_TWOPI (M_PI * 2.0)
+#define M_PI_2 1.57079632679489661923
+#ifndef M_PI_4
+#define M_PI_4 0.78539816339744830962
+#endif
+
+#if !defined(PHP_DEBUG)
+#ifdef inline
+#undef inline
+#endif
+#define inline __inline
+#endif
+
+/* General Windows stuff */
+#ifndef WINDOWS
+# define WINDOWS 1
+#endif
+
+
+/* Prevent use of VC5 OpenFile function */
+#define NOOPENFILE
+
+/* sendmail is built-in */
+#ifdef PHP_PROG_SENDMAIL
+#undef PHP_PROG_SENDMAIL
+#define PHP_PROG_SENDMAIL "Built in mailer"
+#endif