#include "php_snuffleupagus.h" static void (*orig_register_server_variables)(zval *track_vars_array) = NULL; static const unsigned char sp_hexchars[] = "0123456789ABCDEF"; static const char sp_is_dangerous_char[256] = { /* |-> 0 1 2 3 4 5 6 7 8 9 a b c d e f */ /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 0x40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static void sp_server_strip(HashTable *svars, const char *key, size_t keylen) { zval *value = zend_hash_str_find(svars, key, keylen); if (!value || Z_TYPE_P(value) != IS_STRING) { return; } zend_string *tmp_zstr = Z_STR_P(value); char *tmp = ZSTR_VAL(tmp_zstr); char *tmpend = tmp + ZSTR_LEN(tmp_zstr); for (char *p = tmp; p < tmpend; p++) { if (sp_is_dangerous_char[(int)*p]) { *p = '_'; } } } static void sp_server_encode(HashTable *svars, const char *key, size_t keylen) { zval *value = zend_hash_str_find(svars, key, keylen); if (!value || Z_TYPE_P(value) != IS_STRING) { return; } zend_string *tmp_zstr = Z_STR_P(value); char *tmp = ZSTR_VAL(tmp_zstr); char *tmpend = tmp + ZSTR_LEN(tmp_zstr); int extra = 0; for (char *p = tmp; p < tmpend; p++) { extra += sp_is_dangerous_char[(int)*p] * 2; } if (!extra) { return; } zend_string *new_zstr = zend_string_alloc(ZSTR_LEN(tmp_zstr) + extra, 0); char *n = ZSTR_VAL(new_zstr); for (char *p = tmp; p < tmpend; p++, n++) { if (sp_is_dangerous_char[(int)*p]) { *n++ = '%'; *n++ = sp_hexchars[*p >> 4]; *n = sp_hexchars[*p & 15]; } else { *n = *p; } } ZSTR_VAL(new_zstr)[ZSTR_LEN(new_zstr)] = 0; Z_STR_P(value) = new_zstr; zend_string_release_ex(tmp_zstr, 0); } static void sp_register_server_variables(zval *track_vars_array) { orig_register_server_variables(track_vars_array); HashTable *svars; svars = Z_ARRVAL_P(track_vars_array); if (SPCFG(server_encode)) { sp_server_encode(svars, ZEND_STRL("REQUEST_URI")); sp_server_encode(svars, ZEND_STRL("QUERY_STRING")); } if (SPCFG(server_strip)) { sp_server_strip(svars, ZEND_STRL("PHP_SELF")); sp_server_strip(svars, ZEND_STRL("HTTP_HOST")); sp_server_strip(svars, ZEND_STRL("HTTP_USER_AGENT")); // for cgi + fpm sp_server_strip(svars, ZEND_STRL("PATH_INFO")); sp_server_strip(svars, ZEND_STRL("PATH_TRANSLATED")); sp_server_strip(svars, ZEND_STRL("ORIG_PATH_TRANSLATED")); sp_server_strip(svars, ZEND_STRL("ORIG_PATH_INFO")); } } void sp_hook_register_server_variables() { if (sapi_module.register_server_variables && sapi_module.register_server_variables != sp_register_server_variables) { orig_register_server_variables = sapi_module.register_server_variables; sapi_module.register_server_variables = sp_register_server_variables; } }