php-src/ext/tidy/tidy.c
Peter Kokot 92ac598aab Remove local variables
This patch removes the so called local variables defined per
file basis for certain editors to properly show tab width, and
similar settings. These are mainly used by Vim and Emacs editors
yet with recent changes the once working definitions don't work
anymore in Vim without custom plugins or additional configuration.
Neither are these settings synced across the PHP code base.

A simpler and better approach is EditorConfig and fixing code
using some code style fixing tools in the future instead.

This patch also removes the so called modelines for Vim. Modelines
allow Vim editor specifically to set some editor configuration such as
syntax highlighting, indentation style and tab width to be set in the
first line or the last 5 lines per file basis. Since the php test
files have syntax highlighting already set in most editors properly and
EditorConfig takes care of the indentation settings, this patch removes
these as well for the Vim 6.0 and newer versions.

With the removal of local variables for certain editors such as
Emacs and Vim, the footer is also probably not needed anymore when
creating extensions using ext_skel.php script.

Additionally, Vim modelines for setting php syntax and some editor
settings has been removed from some *.phpt files.  All these are
mostly not relevant for phpt files neither work properly in the
middle of the file.
2019-02-03 21:03:00 +01:00

2056 lines
51 KiB
C

/*
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
| Copyright (c) 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: John Coggeshall <john@php.net> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_tidy.h"
#if HAVE_TIDY
#include "php_ini.h"
#include "ext/standard/info.h"
#if HAVE_TIDY_H
#include "tidy.h"
#elif HAVE_TIDYP_H
#include "tidyp.h"
#endif
#if HAVE_TIDYBUFFIO_H
#include "tidybuffio.h"
#else
#include "buffio.h"
#endif
/* compatibility with older versions of libtidy */
#ifndef TIDY_CALL
#define TIDY_CALL
#endif
/* {{{ ext/tidy macros
*/
#define FIX_BUFFER(bptr) do { if ((bptr)->size) { (bptr)->bp[(bptr)->size-1] = '\0'; } } while(0)
#define TIDY_SET_CONTEXT \
zval *object = getThis();
#define TIDY_FETCH_OBJECT \
PHPTidyObj *obj; \
TIDY_SET_CONTEXT; \
if (object) { \
if (zend_parse_parameters_none() == FAILURE) { \
return; \
} \
} else { \
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), NULL, "O", &object, tidy_ce_doc) == FAILURE) { \
RETURN_FALSE; \
} \
} \
obj = Z_TIDY_P(object); \
#define TIDY_FETCH_ONLY_OBJECT \
PHPTidyObj *obj; \
TIDY_SET_CONTEXT; \
if (zend_parse_parameters_none() == FAILURE) { \
return; \
} \
obj = Z_TIDY_P(object); \
#define TIDY_APPLY_CONFIG_ZVAL(_doc, _val) \
if(_val) { \
if(Z_TYPE_P(_val) == IS_ARRAY) { \
_php_tidy_apply_config_array(_doc, Z_ARRVAL_P(_val)); \
} else { \
convert_to_string_ex(_val); \
TIDY_OPEN_BASE_DIR_CHECK(Z_STRVAL_P(_val)); \
switch (tidyLoadConfig(_doc, Z_STRVAL_P(_val))) { \
case -1: \
php_error_docref(NULL, E_WARNING, "Could not load configuration file '%s'", Z_STRVAL_P(_val)); \
break; \
case 1: \
php_error_docref(NULL, E_NOTICE, "There were errors while parsing the configuration file '%s'", Z_STRVAL_P(_val)); \
break; \
} \
} \
}
#define REGISTER_TIDY_CLASS(classname, name, parent, __flags) \
{ \
zend_class_entry ce; \
INIT_CLASS_ENTRY(ce, # classname, tidy_funcs_ ## name); \
ce.create_object = tidy_object_new_ ## name; \
tidy_ce_ ## name = zend_register_internal_class_ex(&ce, parent); \
tidy_ce_ ## name->ce_flags |= __flags; \
memcpy(&tidy_object_handlers_ ## name, &std_object_handlers, sizeof(zend_object_handlers)); \
tidy_object_handlers_ ## name.clone_obj = NULL; \
}
#define TIDY_TAG_CONST(tag) REGISTER_LONG_CONSTANT("TIDY_TAG_" #tag, TidyTag_##tag, CONST_CS | CONST_PERSISTENT)
#define TIDY_NODE_CONST(name, type) REGISTER_LONG_CONSTANT("TIDY_NODETYPE_" #name, TidyNode_##type, CONST_CS | CONST_PERSISTENT)
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define ADD_PROPERTY_STRING(_table, _key, _string) \
{ \
zval tmp; \
if (_string) { \
ZVAL_STRING(&tmp, (char *)_string); \
} else { \
ZVAL_EMPTY_STRING(&tmp); \
} \
zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \
}
#define ADD_PROPERTY_STRINGL(_table, _key, _string, _len) \
{ \
zval tmp; \
if (_string) { \
ZVAL_STRINGL(&tmp, (char *)_string, _len); \
} else { \
ZVAL_EMPTY_STRING(&tmp); \
} \
zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \
}
#define ADD_PROPERTY_LONG(_table, _key, _long) \
{ \
zval tmp; \
ZVAL_LONG(&tmp, _long); \
zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \
}
#define ADD_PROPERTY_NULL(_table, _key) \
{ \
zval tmp; \
ZVAL_NULL(&tmp); \
zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \
}
#define ADD_PROPERTY_BOOL(_table, _key, _bool) \
{ \
zval tmp; \
ZVAL_BOOL(&tmp, _bool); \
zend_hash_str_update(_table, #_key, sizeof(#_key) - 1, &tmp); \
}
#define TIDY_OPEN_BASE_DIR_CHECK(filename) \
if (php_check_open_basedir(filename)) { \
RETURN_FALSE; \
} \
#define TIDY_SET_DEFAULT_CONFIG(_doc) \
if (TG(default_config) && TG(default_config)[0]) { \
if (tidyLoadConfig(_doc, TG(default_config)) < 0) { \
php_error_docref(NULL, E_WARNING, "Unable to load Tidy configuration file at '%s'.", TG(default_config)); \
} \
}
/* }}} */
/* {{{ ext/tidy structs
*/
typedef struct _PHPTidyDoc PHPTidyDoc;
typedef struct _PHPTidyObj PHPTidyObj;
typedef enum {
is_node,
is_doc
} tidy_obj_type;
typedef enum {
is_root_node,
is_html_node,
is_head_node,
is_body_node
} tidy_base_nodetypes;
struct _PHPTidyDoc {
TidyDoc doc;
TidyBuffer *errbuf;
unsigned int ref_count;
unsigned int initialized:1;
};
struct _PHPTidyObj {
TidyNode node;
tidy_obj_type type;
PHPTidyDoc *ptdoc;
zend_object std;
};
static inline PHPTidyObj *php_tidy_fetch_object(zend_object *obj) {
return (PHPTidyObj *)((char*)(obj) - XtOffsetOf(PHPTidyObj, std));
}
#define Z_TIDY_P(zv) php_tidy_fetch_object(Z_OBJ_P((zv)))
/* }}} */
/* {{{ ext/tidy prototypes
*/
static zend_string *php_tidy_file_to_mem(char *, zend_bool);
static void tidy_object_free_storage(zend_object *);
static zend_object *tidy_object_new_node(zend_class_entry *);
static zend_object *tidy_object_new_doc(zend_class_entry *);
static zval * tidy_instanciate(zend_class_entry *, zval *);
static int tidy_doc_cast_handler(zval *, zval *, int);
static int tidy_node_cast_handler(zval *, zval *, int);
static void tidy_doc_update_properties(PHPTidyObj *);
static void tidy_add_default_properties(PHPTidyObj *, tidy_obj_type);
static void *php_tidy_get_opt_val(PHPTidyDoc *, TidyOption, TidyOptionType *);
static void php_tidy_create_node(INTERNAL_FUNCTION_PARAMETERS, tidy_base_nodetypes);
static int _php_tidy_set_tidy_opt(TidyDoc, char *, zval *);
static int _php_tidy_apply_config_array(TidyDoc doc, HashTable *ht_options);
static void _php_tidy_register_nodetypes(INIT_FUNC_ARGS);
static void _php_tidy_register_tags(INIT_FUNC_ARGS);
static PHP_INI_MH(php_tidy_set_clean_output);
static void php_tidy_clean_output_start(const char *name, size_t name_len);
static php_output_handler *php_tidy_output_handler_init(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags);
static int php_tidy_output_handler(void **nothing, php_output_context *output_context);
static PHP_MINIT_FUNCTION(tidy);
static PHP_MSHUTDOWN_FUNCTION(tidy);
static PHP_RINIT_FUNCTION(tidy);
static PHP_MINFO_FUNCTION(tidy);
static PHP_FUNCTION(tidy_getopt);
static PHP_FUNCTION(tidy_parse_string);
static PHP_FUNCTION(tidy_parse_file);
static PHP_FUNCTION(tidy_clean_repair);
static PHP_FUNCTION(tidy_repair_string);
static PHP_FUNCTION(tidy_repair_file);
static PHP_FUNCTION(tidy_diagnose);
static PHP_FUNCTION(tidy_get_output);
static PHP_FUNCTION(tidy_get_error_buffer);
static PHP_FUNCTION(tidy_get_release);
static PHP_FUNCTION(tidy_get_config);
static PHP_FUNCTION(tidy_get_status);
static PHP_FUNCTION(tidy_get_html_ver);
#if HAVE_TIDYOPTGETDOC
static PHP_FUNCTION(tidy_get_opt_doc);
#endif
static PHP_FUNCTION(tidy_is_xhtml);
static PHP_FUNCTION(tidy_is_xml);
static PHP_FUNCTION(tidy_error_count);
static PHP_FUNCTION(tidy_warning_count);
static PHP_FUNCTION(tidy_access_count);
static PHP_FUNCTION(tidy_config_count);
static PHP_FUNCTION(tidy_get_root);
static PHP_FUNCTION(tidy_get_html);
static PHP_FUNCTION(tidy_get_head);
static PHP_FUNCTION(tidy_get_body);
static TIDY_DOC_METHOD(__construct);
static TIDY_DOC_METHOD(parseFile);
static TIDY_DOC_METHOD(parseString);
static TIDY_NODE_METHOD(hasChildren);
static TIDY_NODE_METHOD(hasSiblings);
static TIDY_NODE_METHOD(isComment);
static TIDY_NODE_METHOD(isHtml);
static TIDY_NODE_METHOD(isText);
static TIDY_NODE_METHOD(isJste);
static TIDY_NODE_METHOD(isAsp);
static TIDY_NODE_METHOD(isPhp);
static TIDY_NODE_METHOD(getParent);
static TIDY_NODE_METHOD(__construct);
/* }}} */
ZEND_DECLARE_MODULE_GLOBALS(tidy)
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("tidy.default_config", "", PHP_INI_SYSTEM, OnUpdateString, default_config, zend_tidy_globals, tidy_globals)
STD_PHP_INI_ENTRY("tidy.clean_output", "0", PHP_INI_USER, php_tidy_set_clean_output, clean_output, zend_tidy_globals, tidy_globals)
PHP_INI_END()
/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_parse_string, 0, 0, 1)
ZEND_ARG_INFO(0, input)
ZEND_ARG_INFO(0, config_options)
ZEND_ARG_INFO(0, encoding)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_get_error_buffer, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_get_output, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_parse_file, 0, 0, 1)
ZEND_ARG_INFO(0, file)
ZEND_ARG_INFO(0, config_options)
ZEND_ARG_INFO(0, encoding)
ZEND_ARG_INFO(0, use_include_path)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_clean_repair, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_repair_string, 0, 0, 1)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(0, config_file)
ZEND_ARG_INFO(0, encoding)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_repair_file, 0, 0, 1)
ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, config_file)
ZEND_ARG_INFO(0, encoding)
ZEND_ARG_INFO(0, use_include_path)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_diagnose, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_release, 0)
ZEND_END_ARG_INFO()
#if HAVE_TIDYOPTGETDOC
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_get_opt_doc, 0, 0, 2)
ZEND_ARG_INFO(0, resource)
ZEND_ARG_INFO(0, optname)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_get_opt_doc_method, 0, 0, 1)
ZEND_ARG_INFO(0, optname)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_get_config, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_get_status, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_get_html_ver, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_is_xhtml, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_is_xml, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_error_count, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_warning_count, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_access_count, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_config_count, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_getopt, 0, 0, 1)
ZEND_ARG_INFO(0, option)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_root, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_html, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_tidy_get_head, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_get_body, 0, 0, 1)
ZEND_ARG_INFO(0, tidy)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_tidy_construct, 0, 0, 0)
ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, config_file)
ZEND_ARG_INFO(0, encoding)
ZEND_ARG_INFO(0, use_include_path)
ZEND_END_ARG_INFO()
/* }}} */
static const zend_function_entry tidy_functions[] = {
PHP_FE(tidy_getopt, arginfo_tidy_getopt)
PHP_FE(tidy_parse_string, arginfo_tidy_parse_string)
PHP_FE(tidy_parse_file, arginfo_tidy_parse_file)
PHP_FE(tidy_get_output, arginfo_tidy_get_output)
PHP_FE(tidy_get_error_buffer, arginfo_tidy_get_error_buffer)
PHP_FE(tidy_clean_repair, arginfo_tidy_clean_repair)
PHP_FE(tidy_repair_string, arginfo_tidy_repair_string)
PHP_FE(tidy_repair_file, arginfo_tidy_repair_file)
PHP_FE(tidy_diagnose, arginfo_tidy_diagnose)
PHP_FE(tidy_get_release, arginfo_tidy_get_release)
PHP_FE(tidy_get_config, arginfo_tidy_get_config)
PHP_FE(tidy_get_status, arginfo_tidy_get_status)
PHP_FE(tidy_get_html_ver, arginfo_tidy_get_html_ver)
PHP_FE(tidy_is_xhtml, arginfo_tidy_is_xhtml)
PHP_FE(tidy_is_xml, arginfo_tidy_is_xml)
PHP_FE(tidy_error_count, arginfo_tidy_error_count)
PHP_FE(tidy_warning_count, arginfo_tidy_warning_count)
PHP_FE(tidy_access_count, arginfo_tidy_access_count)
PHP_FE(tidy_config_count, arginfo_tidy_config_count)
#if HAVE_TIDYOPTGETDOC
PHP_FE(tidy_get_opt_doc, arginfo_tidy_get_opt_doc)
#endif
PHP_FE(tidy_get_root, arginfo_tidy_get_root)
PHP_FE(tidy_get_head, arginfo_tidy_get_head)
PHP_FE(tidy_get_html, arginfo_tidy_get_html)
PHP_FE(tidy_get_body, arginfo_tidy_get_body)
PHP_FE_END
};
static const zend_function_entry tidy_funcs_doc[] = {
TIDY_METHOD_MAP(getOpt, tidy_getopt, arginfo_tidy_getopt)
TIDY_METHOD_MAP(cleanRepair, tidy_clean_repair, NULL)
TIDY_DOC_ME(parseFile, arginfo_tidy_parse_file)
TIDY_DOC_ME(parseString, arginfo_tidy_parse_string)
TIDY_METHOD_MAP(repairString, tidy_repair_string, arginfo_tidy_repair_string)
TIDY_METHOD_MAP(repairFile, tidy_repair_file, arginfo_tidy_repair_file)
TIDY_METHOD_MAP(diagnose, tidy_diagnose, NULL)
TIDY_METHOD_MAP(getRelease, tidy_get_release, NULL)
TIDY_METHOD_MAP(getConfig, tidy_get_config, NULL)
TIDY_METHOD_MAP(getStatus, tidy_get_status, NULL)
TIDY_METHOD_MAP(getHtmlVer, tidy_get_html_ver, NULL)
#if HAVE_TIDYOPTGETDOC
TIDY_METHOD_MAP(getOptDoc, tidy_get_opt_doc, arginfo_tidy_get_opt_doc_method)
#endif
TIDY_METHOD_MAP(isXhtml, tidy_is_xhtml, NULL)
TIDY_METHOD_MAP(isXml, tidy_is_xml, NULL)
TIDY_METHOD_MAP(root, tidy_get_root, NULL)
TIDY_METHOD_MAP(head, tidy_get_head, NULL)
TIDY_METHOD_MAP(html, tidy_get_html, NULL)
TIDY_METHOD_MAP(body, tidy_get_body, NULL)
TIDY_DOC_ME(__construct, arginfo_tidy_construct)
PHP_FE_END
};
static const zend_function_entry tidy_funcs_node[] = {
TIDY_NODE_ME(hasChildren, NULL)
TIDY_NODE_ME(hasSiblings, NULL)
TIDY_NODE_ME(isComment, NULL)
TIDY_NODE_ME(isHtml, NULL)
TIDY_NODE_ME(isText, NULL)
TIDY_NODE_ME(isJste, NULL)
TIDY_NODE_ME(isAsp, NULL)
TIDY_NODE_ME(isPhp, NULL)
TIDY_NODE_ME(getParent, NULL)
TIDY_NODE_PRIVATE_ME(__construct, NULL)
PHP_FE_END
};
static zend_class_entry *tidy_ce_doc, *tidy_ce_node;
static zend_object_handlers tidy_object_handlers_doc;
static zend_object_handlers tidy_object_handlers_node;
zend_module_entry tidy_module_entry = {
STANDARD_MODULE_HEADER,
"tidy",
tidy_functions,
PHP_MINIT(tidy),
PHP_MSHUTDOWN(tidy),
PHP_RINIT(tidy),
NULL,
PHP_MINFO(tidy),
PHP_TIDY_VERSION,
PHP_MODULE_GLOBALS(tidy),
NULL,
NULL,
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
#ifdef COMPILE_DL_TIDY
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
ZEND_GET_MODULE(tidy)
#endif
static void* TIDY_CALL php_tidy_malloc(size_t len)
{
return emalloc(len);
}
static void* TIDY_CALL php_tidy_realloc(void *buf, size_t len)
{
return erealloc(buf, len);
}
static void TIDY_CALL php_tidy_free(void *buf)
{
efree(buf);
}
static void TIDY_CALL php_tidy_panic(ctmbstr msg)
{
php_error_docref(NULL, E_ERROR, "Could not allocate memory for tidy! (Reason: %s)", (char *)msg);
}
static int _php_tidy_set_tidy_opt(TidyDoc doc, char *optname, zval *value)
{
TidyOption opt = tidyGetOptionByName(doc, optname);
zend_string *str, *tmp_str;
zend_long lval;
if (!opt) {
php_error_docref(NULL, E_NOTICE, "Unknown Tidy Configuration Option '%s'", optname);
return FAILURE;
}
if (tidyOptIsReadOnly(opt)) {
php_error_docref(NULL, E_NOTICE, "Attempting to set read-only option '%s'", optname);
return FAILURE;
}
switch(tidyOptGetType(opt)) {
case TidyString:
str = zval_get_tmp_string(value, &tmp_str);
if (tidyOptSetValue(doc, tidyOptGetId(opt), ZSTR_VAL(str))) {
zend_tmp_string_release(tmp_str);
return SUCCESS;
}
zend_tmp_string_release(tmp_str);
break;
case TidyInteger:
lval = zval_get_long(value);
if (tidyOptSetInt(doc, tidyOptGetId(opt), lval)) {
return SUCCESS;
}
break;
case TidyBoolean:
lval = zval_get_long(value);
if (tidyOptSetBool(doc, tidyOptGetId(opt), lval)) {
return SUCCESS;
}
break;
default:
php_error_docref(NULL, E_WARNING, "Unable to determine type of configuration option");
break;
}
return FAILURE;
}
static void php_tidy_quick_repair(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_file)
{
char *enc = NULL;
size_t enc_len = 0;
zend_bool use_include_path = 0;
TidyDoc doc;
TidyBuffer *errbuf;
zend_string *data, *arg1;
zval *config = NULL;
if (is_file) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|zsb", &arg1, &config, &enc, &enc_len, &use_include_path) == FAILURE) {
RETURN_FALSE;
}
if (!(data = php_tidy_file_to_mem(ZSTR_VAL(arg1), use_include_path))) {
RETURN_FALSE;
}
} else {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|zsb", &arg1, &config, &enc, &enc_len, &use_include_path) == FAILURE) {
RETURN_FALSE;
}
data = arg1;
}
if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(data))) {
php_error_docref(NULL, E_WARNING, "Input string is too long");
RETURN_FALSE;
}
doc = tidyCreate();
errbuf = emalloc(sizeof(TidyBuffer));
tidyBufInit(errbuf);
if (tidySetErrorBuffer(doc, errbuf) != 0) {
tidyBufFree(errbuf);
efree(errbuf);
tidyRelease(doc);
php_error_docref(NULL, E_ERROR, "Could not set Tidy error buffer");
}
tidyOptSetBool(doc, TidyForceOutput, yes);
tidyOptSetBool(doc, TidyMark, no);
TIDY_SET_DEFAULT_CONFIG(doc);
if (config) {
TIDY_APPLY_CONFIG_ZVAL(doc, config);
}
if(enc_len) {
if (tidySetCharEncoding(doc, enc) < 0) {
php_error_docref(NULL, E_WARNING, "Could not set encoding '%s'", enc);
RETVAL_FALSE;
}
}
if (data) {
TidyBuffer buf;
tidyBufInit(&buf);
tidyBufAttach(&buf, (byte *) ZSTR_VAL(data), (uint32_t)ZSTR_LEN(data));
if (tidyParseBuffer(doc, &buf) < 0) {
php_error_docref(NULL, E_WARNING, "%s", errbuf->bp);
RETVAL_FALSE;
} else {
if (tidyCleanAndRepair(doc) >= 0) {
TidyBuffer output;
tidyBufInit(&output);
tidySaveBuffer (doc, &output);
FIX_BUFFER(&output);
RETVAL_STRINGL((char *) output.bp, output.size ? output.size-1 : 0);
tidyBufFree(&output);
} else {
RETVAL_FALSE;
}
}
}
if (is_file) {
zend_string_release_ex(data, 0);
}
tidyBufFree(errbuf);
efree(errbuf);
tidyRelease(doc);
}
static zend_string *php_tidy_file_to_mem(char *filename, zend_bool use_include_path)
{
php_stream *stream;
zend_string *data = NULL;
if (!(stream = php_stream_open_wrapper(filename, "rb", (use_include_path ? USE_PATH : 0), NULL))) {
return NULL;
}
if ((data = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0)) == NULL) {
data = ZSTR_EMPTY_ALLOC();
}
php_stream_close(stream);
return data;
}
static void tidy_object_free_storage(zend_object *object)
{
PHPTidyObj *intern = php_tidy_fetch_object(object);
zend_object_std_dtor(&intern->std);
if (intern->ptdoc) {
intern->ptdoc->ref_count--;
if (intern->ptdoc->ref_count <= 0) {
tidyBufFree(intern->ptdoc->errbuf);
efree(intern->ptdoc->errbuf);
tidyRelease(intern->ptdoc->doc);
efree(intern->ptdoc);
}
}
}
static zend_object *tidy_object_new(zend_class_entry *class_type, zend_object_handlers *handlers, tidy_obj_type objtype)
{
PHPTidyObj *intern;
intern = zend_object_alloc(sizeof(PHPTidyObj), class_type);
zend_object_std_init(&intern->std, class_type);
object_properties_init(&intern->std, class_type);
switch(objtype) {
case is_node:
break;
case is_doc:
intern->ptdoc = emalloc(sizeof(PHPTidyDoc));
intern->ptdoc->doc = tidyCreate();
intern->ptdoc->ref_count = 1;
intern->ptdoc->initialized = 0;
intern->ptdoc->errbuf = emalloc(sizeof(TidyBuffer));
tidyBufInit(intern->ptdoc->errbuf);
if (tidySetErrorBuffer(intern->ptdoc->doc, intern->ptdoc->errbuf) != 0) {
tidyBufFree(intern->ptdoc->errbuf);
efree(intern->ptdoc->errbuf);
tidyRelease(intern->ptdoc->doc);
efree(intern->ptdoc);
efree(intern);
php_error_docref(NULL, E_ERROR, "Could not set Tidy error buffer");
}
tidyOptSetBool(intern->ptdoc->doc, TidyForceOutput, yes);
tidyOptSetBool(intern->ptdoc->doc, TidyMark, no);
TIDY_SET_DEFAULT_CONFIG(intern->ptdoc->doc);
tidy_add_default_properties(intern, is_doc);
break;
}
intern->std.handlers = handlers;
return &intern->std;
}
static zend_object *tidy_object_new_node(zend_class_entry *class_type)
{
return tidy_object_new(class_type, &tidy_object_handlers_node, is_node);
}
static zend_object *tidy_object_new_doc(zend_class_entry *class_type)
{
return tidy_object_new(class_type, &tidy_object_handlers_doc, is_doc);
}
static zval * tidy_instanciate(zend_class_entry *pce, zval *object)
{
object_init_ex(object, pce);
return object;
}
static int tidy_doc_cast_handler(zval *in, zval *out, int type)
{
TidyBuffer output;
PHPTidyObj *obj;
switch (type) {
case IS_LONG:
case _IS_NUMBER:
ZVAL_LONG(out, 0);
break;
case IS_DOUBLE:
ZVAL_DOUBLE(out, 0);
break;
case _IS_BOOL:
ZVAL_TRUE(out);
break;
case IS_STRING:
obj = Z_TIDY_P(in);
tidyBufInit(&output);
tidySaveBuffer (obj->ptdoc->doc, &output);
ZVAL_STRINGL(out, (char *) output.bp, output.size ? output.size-1 : 0);
tidyBufFree(&output);
break;
default:
return FAILURE;
}
return SUCCESS;
}
static int tidy_node_cast_handler(zval *in, zval *out, int type)
{
TidyBuffer buf;
PHPTidyObj *obj;
switch(type) {
case IS_LONG:
case _IS_NUMBER:
ZVAL_LONG(out, 0);
break;
case IS_DOUBLE:
ZVAL_DOUBLE(out, 0);
break;
case _IS_BOOL:
ZVAL_TRUE(out);
break;
case IS_STRING:
obj = Z_TIDY_P(in);
tidyBufInit(&buf);
if (obj->ptdoc) {
tidyNodeGetText(obj->ptdoc->doc, obj->node, &buf);
ZVAL_STRINGL(out, (char *) buf.bp, buf.size-1);
} else {
ZVAL_EMPTY_STRING(out);
}
tidyBufFree(&buf);
break;
default:
return FAILURE;
}
return SUCCESS;
}
static void tidy_doc_update_properties(PHPTidyObj *obj)
{
TidyBuffer output;
zval temp;
tidyBufInit(&output);
tidySaveBuffer (obj->ptdoc->doc, &output);
if (output.size) {
if (!obj->std.properties) {
rebuild_object_properties(&obj->std);
}
ZVAL_STRINGL(&temp, (char*)output.bp, output.size-1);
zend_hash_str_update(obj->std.properties, "value", sizeof("value") - 1, &temp);
}
tidyBufFree(&output);
if (obj->ptdoc->errbuf->size) {
if (!obj->std.properties) {
rebuild_object_properties(&obj->std);
}
ZVAL_STRINGL(&temp, (char*)obj->ptdoc->errbuf->bp, obj->ptdoc->errbuf->size-1);
zend_hash_str_update(obj->std.properties, "errorBuffer", sizeof("errorBuffer") - 1, &temp);
}
}
static void tidy_add_default_properties(PHPTidyObj *obj, tidy_obj_type type)
{
TidyBuffer buf;
TidyAttr tempattr;
TidyNode tempnode;
zval attribute, children, temp;
PHPTidyObj *newobj;
switch(type) {
case is_node:
if (!obj->std.properties) {
rebuild_object_properties(&obj->std);
}
tidyBufInit(&buf);
tidyNodeGetText(obj->ptdoc->doc, obj->node, &buf);
ADD_PROPERTY_STRINGL(obj->std.properties, value, buf.bp, buf.size ? buf.size-1 : 0);
tidyBufFree(&buf);
ADD_PROPERTY_STRING(obj->std.properties, name, tidyNodeGetName(obj->node));
ADD_PROPERTY_LONG(obj->std.properties, type, tidyNodeGetType(obj->node));
ADD_PROPERTY_LONG(obj->std.properties, line, tidyNodeLine(obj->node));
ADD_PROPERTY_LONG(obj->std.properties, column, tidyNodeColumn(obj->node));
ADD_PROPERTY_BOOL(obj->std.properties, proprietary, tidyNodeIsProp(obj->ptdoc->doc, obj->node));
switch(tidyNodeGetType(obj->node)) {
case TidyNode_Root:
case TidyNode_DocType:
case TidyNode_Text:
case TidyNode_Comment:
break;
default:
ADD_PROPERTY_LONG(obj->std.properties, id, tidyNodeGetId(obj->node));
}
tempattr = tidyAttrFirst(obj->node);
if (tempattr) {
char *name, *val;
array_init(&attribute);
do {
name = (char *)tidyAttrName(tempattr);
val = (char *)tidyAttrValue(tempattr);
if (name && val) {
add_assoc_string(&attribute, name, val);
}
} while((tempattr = tidyAttrNext(tempattr)));
} else {
ZVAL_NULL(&attribute);
}
zend_hash_str_update(obj->std.properties, "attribute", sizeof("attribute") - 1, &attribute);
tempnode = tidyGetChild(obj->node);
if (tempnode) {
array_init(&children);
do {
tidy_instanciate(tidy_ce_node, &temp);
newobj = Z_TIDY_P(&temp);
newobj->node = tempnode;
newobj->type = is_node;
newobj->ptdoc = obj->ptdoc;
newobj->ptdoc->ref_count++;
tidy_add_default_properties(newobj, is_node);
add_next_index_zval(&children, &temp);
} while((tempnode = tidyGetNext(tempnode)));
} else {
ZVAL_NULL(&children);
}
zend_hash_str_update(obj->std.properties, "child", sizeof("child") - 1, &children);
break;
case is_doc:
if (!obj->std.properties) {
rebuild_object_properties(&obj->std);
}
ADD_PROPERTY_NULL(obj->std.properties, errorBuffer);
ADD_PROPERTY_NULL(obj->std.properties, value);
break;
}
}
static void *php_tidy_get_opt_val(PHPTidyDoc *ptdoc, TidyOption opt, TidyOptionType *type)
{
*type = tidyOptGetType(opt);
switch (*type) {
case TidyString: {
char *val = (char *) tidyOptGetValue(ptdoc->doc, tidyOptGetId(opt));
if (val) {
return (void *) zend_string_init(val, strlen(val), 0);
} else {
return (void *) ZSTR_EMPTY_ALLOC();
}
}
break;
case TidyInteger:
return (void *) (uintptr_t) tidyOptGetInt(ptdoc->doc, tidyOptGetId(opt));
break;
case TidyBoolean:
return (void *) tidyOptGetBool(ptdoc->doc, tidyOptGetId(opt));
break;
}
/* should not happen */
return NULL;
}
static void php_tidy_create_node(INTERNAL_FUNCTION_PARAMETERS, tidy_base_nodetypes node_type)
{
PHPTidyObj *newobj;
TidyNode node;
TIDY_FETCH_OBJECT;
switch (node_type) {
case is_root_node:
node = tidyGetRoot(obj->ptdoc->doc);
break;
case is_html_node:
node = tidyGetHtml(obj->ptdoc->doc);
break;
case is_head_node:
node = tidyGetHead(obj->ptdoc->doc);
break;
case is_body_node:
node = tidyGetBody(obj->ptdoc->doc);
break;
default:
RETURN_NULL();
break;
}
if (!node) {
RETURN_NULL();
}
tidy_instanciate(tidy_ce_node, return_value);
newobj = Z_TIDY_P(return_value);
newobj->type = is_node;
newobj->ptdoc = obj->ptdoc;
newobj->node = node;
newobj->ptdoc->ref_count++;
tidy_add_default_properties(newobj, is_node);
}
static int _php_tidy_apply_config_array(TidyDoc doc, HashTable *ht_options)
{
zval *opt_val;
zend_string *opt_name;
ZEND_HASH_FOREACH_STR_KEY_VAL(ht_options, opt_name, opt_val) {
if (opt_name == NULL) {
continue;
}
_php_tidy_set_tidy_opt(doc, ZSTR_VAL(opt_name), opt_val);
} ZEND_HASH_FOREACH_END();
return SUCCESS;
}
static int php_tidy_parse_string(PHPTidyObj *obj, char *string, uint32_t len, char *enc)
{
TidyBuffer buf;
if(enc) {
if (tidySetCharEncoding(obj->ptdoc->doc, enc) < 0) {
php_error_docref(NULL, E_WARNING, "Could not set encoding '%s'", enc);
return FAILURE;
}
}
obj->ptdoc->initialized = 1;
tidyBufInit(&buf);
tidyBufAttach(&buf, (byte *) string, len);
if (tidyParseBuffer(obj->ptdoc->doc, &buf) < 0) {
php_error_docref(NULL, E_WARNING, "%s", obj->ptdoc->errbuf->bp);
return FAILURE;
}
tidy_doc_update_properties(obj);
return SUCCESS;
}
static PHP_MINIT_FUNCTION(tidy)
{
tidySetMallocCall(php_tidy_malloc);
tidySetReallocCall(php_tidy_realloc);
tidySetFreeCall(php_tidy_free);
tidySetPanicCall(php_tidy_panic);
REGISTER_INI_ENTRIES();
REGISTER_TIDY_CLASS(tidy, doc, NULL, 0);
REGISTER_TIDY_CLASS(tidyNode, node, NULL, ZEND_ACC_FINAL);
tidy_object_handlers_doc.cast_object = tidy_doc_cast_handler;
tidy_object_handlers_node.cast_object = tidy_node_cast_handler;
tidy_object_handlers_node.offset = tidy_object_handlers_doc.offset = XtOffsetOf(PHPTidyObj, std);
tidy_object_handlers_node.free_obj = tidy_object_handlers_doc.free_obj = tidy_object_free_storage;
_php_tidy_register_tags(INIT_FUNC_ARGS_PASSTHRU);
_php_tidy_register_nodetypes(INIT_FUNC_ARGS_PASSTHRU);
php_output_handler_alias_register(ZEND_STRL("ob_tidyhandler"), php_tidy_output_handler_init);
return SUCCESS;
}
static PHP_RINIT_FUNCTION(tidy)
{
#if defined(COMPILE_DL_TIDY) && defined(ZTS)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
php_tidy_clean_output_start(ZEND_STRL("ob_tidyhandler"));
return SUCCESS;
}
static PHP_MSHUTDOWN_FUNCTION(tidy)
{
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
static PHP_MINFO_FUNCTION(tidy)
{
php_info_print_table_start();
php_info_print_table_row(2, "Tidy support", "enabled");
#if HAVE_TIDYBUFFIO_H
php_info_print_table_row(2, "libTidy Version", (char *)tidyLibraryVersion());
#elif HAVE_TIDYP_H
php_info_print_table_row(2, "libtidyp Version", (char *)tidyVersion());
#endif
#if HAVE_TIDYRELEASEDATE
php_info_print_table_row(2, "libTidy Release", (char *)tidyReleaseDate());
#endif
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
static PHP_INI_MH(php_tidy_set_clean_output)
{
int status;
zend_bool value;
if (ZSTR_LEN(new_value)==2 && strcasecmp("on", ZSTR_VAL(new_value))==0) {
value = (zend_bool) 1;
} else if (ZSTR_LEN(new_value)==3 && strcasecmp("yes", ZSTR_VAL(new_value))==0) {
value = (zend_bool) 1;
} else if (ZSTR_LEN(new_value)==4 && strcasecmp("true", ZSTR_VAL(new_value))==0) {
value = (zend_bool) 1;
} else {
value = (zend_bool) atoi(ZSTR_VAL(new_value));
}
if (stage == PHP_INI_STAGE_RUNTIME) {
status = php_output_get_status();
if (value && (status & PHP_OUTPUT_WRITTEN)) {
php_error_docref(NULL, E_WARNING, "Cannot enable tidy.clean_output - there has already been output");
return FAILURE;
}
if (status & PHP_OUTPUT_SENT) {
php_error_docref(NULL, E_WARNING, "Cannot change tidy.clean_output - headers already sent");
return FAILURE;
}
}
status = OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
if (stage == PHP_INI_STAGE_RUNTIME && value) {
if (!php_output_handler_started(ZEND_STRL("ob_tidyhandler"))) {
php_tidy_clean_output_start(ZEND_STRL("ob_tidyhandler"));
}
}
return status;
}
/*
* NOTE: tidy does not support iterative/cumulative parsing, so chunk-sized output handler is not possible
*/
static void php_tidy_clean_output_start(const char *name, size_t name_len)
{
php_output_handler *h;
if (TG(clean_output) && (h = php_tidy_output_handler_init(name, name_len, 0, PHP_OUTPUT_HANDLER_STDFLAGS))) {
php_output_handler_start(h);
}
}
static php_output_handler *php_tidy_output_handler_init(const char *handler_name, size_t handler_name_len, size_t chunk_size, int flags)
{
if (chunk_size) {
php_error_docref(NULL, E_WARNING, "Cannot use a chunk size for ob_tidyhandler");
return NULL;
}
if (!TG(clean_output)) {
TG(clean_output) = 1;
}
return php_output_handler_create_internal(handler_name, handler_name_len, php_tidy_output_handler, chunk_size, flags);
}
static int php_tidy_output_handler(void **nothing, php_output_context *output_context)
{
int status = FAILURE;
TidyDoc doc;
TidyBuffer inbuf, outbuf, errbuf;
if (TG(clean_output) && (output_context->op & PHP_OUTPUT_HANDLER_START) && (output_context->op & PHP_OUTPUT_HANDLER_FINAL)) {
doc = tidyCreate();
tidyBufInit(&errbuf);
if (0 == tidySetErrorBuffer(doc, &errbuf)) {
tidyOptSetBool(doc, TidyForceOutput, yes);
tidyOptSetBool(doc, TidyMark, no);
if (ZEND_SIZE_T_UINT_OVFL(output_context->in.used)) {
php_error_docref(NULL, E_WARNING, "Input string is too long");
return status;
}
TIDY_SET_DEFAULT_CONFIG(doc);
tidyBufInit(&inbuf);
tidyBufAttach(&inbuf, (byte *) output_context->in.data, (uint32_t)output_context->in.used);
if (0 <= tidyParseBuffer(doc, &inbuf) && 0 <= tidyCleanAndRepair(doc)) {
tidyBufInit(&outbuf);
tidySaveBuffer(doc, &outbuf);
FIX_BUFFER(&outbuf);
output_context->out.data = (char *) outbuf.bp;
output_context->out.used = outbuf.size ? outbuf.size-1 : 0;
output_context->out.free = 1;
status = SUCCESS;
}
}
tidyRelease(doc);
tidyBufFree(&errbuf);
}
return status;
}
/* {{{ proto bool tidy_parse_string(string input [, mixed config_options [, string encoding]])
Parse a document stored in a string */
static PHP_FUNCTION(tidy_parse_string)
{
char *enc = NULL;
size_t enc_len = 0;
zend_string *input;
zval *options = NULL;
PHPTidyObj *obj;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|zs", &input, &options, &enc, &enc_len) == FAILURE) {
RETURN_FALSE;
}
if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(input))) {
php_error_docref(NULL, E_WARNING, "Input string is too long");
RETURN_FALSE;
}
tidy_instanciate(tidy_ce_doc, return_value);
obj = Z_TIDY_P(return_value);
TIDY_APPLY_CONFIG_ZVAL(obj->ptdoc->doc, options);
if (php_tidy_parse_string(obj, ZSTR_VAL(input), (uint32_t)ZSTR_LEN(input), enc) == FAILURE) {
zval_ptr_dtor(return_value);
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto string tidy_get_error_buffer()
Return warnings and errors which occurred parsing the specified document*/
static PHP_FUNCTION(tidy_get_error_buffer)
{
TIDY_FETCH_OBJECT;
if (obj->ptdoc->errbuf && obj->ptdoc->errbuf->bp) {
RETURN_STRINGL((char*)obj->ptdoc->errbuf->bp, obj->ptdoc->errbuf->size-1);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto string tidy_get_output(tidy tidy)
Return a string representing the parsed tidy markup */
static PHP_FUNCTION(tidy_get_output)
{
TidyBuffer output;
TIDY_FETCH_OBJECT;
tidyBufInit(&output);
tidySaveBuffer(obj->ptdoc->doc, &output);
FIX_BUFFER(&output);
RETVAL_STRINGL((char *) output.bp, output.size ? output.size-1 : 0);
tidyBufFree(&output);
}
/* }}} */
/* {{{ proto bool tidy_parse_file(string file [, mixed config_options [, string encoding [, bool use_include_path]]])
Parse markup in file or URI */
static PHP_FUNCTION(tidy_parse_file)
{
char *enc = NULL;
size_t enc_len = 0;
zend_bool use_include_path = 0;
zend_string *inputfile, *contents;
zval *options = NULL;
PHPTidyObj *obj;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|zsb", &inputfile,
&options, &enc, &enc_len, &use_include_path) == FAILURE) {
RETURN_FALSE;
}
tidy_instanciate(tidy_ce_doc, return_value);
obj = Z_TIDY_P(return_value);
if (!(contents = php_tidy_file_to_mem(ZSTR_VAL(inputfile), use_include_path))) {
php_error_docref(NULL, E_WARNING, "Cannot Load '%s' into memory%s", ZSTR_VAL(inputfile), (use_include_path) ? " (Using include path)" : "");
RETURN_FALSE;
}
if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(contents))) {
php_error_docref(NULL, E_WARNING, "Input string is too long");
RETURN_FALSE;
}
TIDY_APPLY_CONFIG_ZVAL(obj->ptdoc->doc, options);
if (php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc) == FAILURE) {
zval_ptr_dtor(return_value);
RETVAL_FALSE;
}
zend_string_release_ex(contents, 0);
}
/* }}} */
/* {{{ proto bool tidy_clean_repair(tidy tidy)
Execute configured cleanup and repair operations on parsed markup */
static PHP_FUNCTION(tidy_clean_repair)
{
TIDY_FETCH_OBJECT;
if (tidyCleanAndRepair(obj->ptdoc->doc) >= 0) {
tidy_doc_update_properties(obj);
RETURN_TRUE;
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto bool tidy_repair_string(string data [, mixed config_file [, string encoding]])
Repair a string using an optionally provided configuration file */
static PHP_FUNCTION(tidy_repair_string)
{
php_tidy_quick_repair(INTERNAL_FUNCTION_PARAM_PASSTHRU, FALSE);
}
/* }}} */
/* {{{ proto bool tidy_repair_file(string filename [, mixed config_file [, string encoding [, bool use_include_path]]])
Repair a file using an optionally provided configuration file */
static PHP_FUNCTION(tidy_repair_file)
{
php_tidy_quick_repair(INTERNAL_FUNCTION_PARAM_PASSTHRU, TRUE);
}
/* }}} */
/* {{{ proto bool tidy_diagnose()
Run configured diagnostics on parsed and repaired markup. */
static PHP_FUNCTION(tidy_diagnose)
{
TIDY_FETCH_OBJECT;
if (obj->ptdoc->initialized && tidyRunDiagnostics(obj->ptdoc->doc) >= 0) {
tidy_doc_update_properties(obj);
RETURN_TRUE;
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto string tidy_get_release()
Get release date (version) for Tidy library */
static PHP_FUNCTION(tidy_get_release)
{
if (zend_parse_parameters_none() == FAILURE) {
return;
}
#if HAVE_TIDYRELEASEDATE
RETURN_STRING((char *)tidyReleaseDate());
#else
RETURN_STRING((char *)"unknown");
#endif
}
/* }}} */
#if HAVE_TIDYOPTGETDOC
/* {{{ proto string tidy_get_opt_doc(tidy resource, string optname)
Returns the documentation for the given option name */
static PHP_FUNCTION(tidy_get_opt_doc)
{
PHPTidyObj *obj;
char *optval, *optname;
size_t optname_len;
TidyOption opt;
TIDY_SET_CONTEXT;
if (object) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &optname, &optname_len) == FAILURE) {
RETURN_FALSE;
}
} else {
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), NULL, "Os", &object, tidy_ce_doc, &optname, &optname_len) == FAILURE) {
RETURN_FALSE;
}
}
obj = Z_TIDY_P(object);
opt = tidyGetOptionByName(obj->ptdoc->doc, optname);
if (!opt) {
php_error_docref(NULL, E_WARNING, "Unknown Tidy Configuration Option '%s'", optname);
RETURN_FALSE;
}
if ( (optval = (char *) tidyOptGetDoc(obj->ptdoc->doc, opt)) ) {
RETURN_STRING(optval);
}
RETURN_FALSE;
}
/* }}} */
#endif
/* {{{ proto array tidy_get_config(tidy tidy)
Get current Tidy configuration */
static PHP_FUNCTION(tidy_get_config)
{
TidyIterator itOpt;
char *opt_name;
void *opt_value;
TidyOptionType optt;
TIDY_FETCH_OBJECT;
itOpt = tidyGetOptionList(obj->ptdoc->doc);
array_init(return_value);
while (itOpt) {
TidyOption opt = tidyGetNextOption(obj->ptdoc->doc, &itOpt);
opt_name = (char *)tidyOptGetName(opt);
opt_value = php_tidy_get_opt_val(obj->ptdoc, opt, &optt);
switch (optt) {
case TidyString:
add_assoc_str(return_value, opt_name, (zend_string*)opt_value);
break;
case TidyInteger:
add_assoc_long(return_value, opt_name, (zend_long)opt_value);
break;
case TidyBoolean:
add_assoc_bool(return_value, opt_name, opt_value ? 1 : 0);
break;
}
}
return;
}
/* }}} */
/* {{{ proto int tidy_get_status(tidy tidy)
Get status of specified document. */
static PHP_FUNCTION(tidy_get_status)
{
TIDY_FETCH_OBJECT;
RETURN_LONG(tidyStatus(obj->ptdoc->doc));
}
/* }}} */
/* {{{ proto int tidy_get_html_ver(tidy tidy)
Get the Detected HTML version for the specified document. */
static PHP_FUNCTION(tidy_get_html_ver)
{
TIDY_FETCH_OBJECT;
RETURN_LONG(tidyDetectedHtmlVersion(obj->ptdoc->doc));
}
/* }}} */
/* {{{ proto bool tidy_is_xhtml(tidy tidy)
Indicates if the document is a XHTML document. */
static PHP_FUNCTION(tidy_is_xhtml)
{
TIDY_FETCH_OBJECT;
RETURN_BOOL(tidyDetectedXhtml(obj->ptdoc->doc));
}
/* }}} */
/* {{{ proto bool tidy_is_xml(tidy tidy)
Indicates if the document is a generic (non HTML/XHTML) XML document. */
static PHP_FUNCTION(tidy_is_xml)
{
TIDY_FETCH_OBJECT;
RETURN_BOOL(tidyDetectedGenericXml(obj->ptdoc->doc));
}
/* }}} */
/* {{{ proto int tidy_error_count(tidy tidy)
Returns the Number of Tidy errors encountered for specified document. */
static PHP_FUNCTION(tidy_error_count)
{
TIDY_FETCH_OBJECT;
RETURN_LONG(tidyErrorCount(obj->ptdoc->doc));
}
/* }}} */
/* {{{ proto int tidy_warning_count(tidy tidy)
Returns the Number of Tidy warnings encountered for specified document. */
static PHP_FUNCTION(tidy_warning_count)
{
TIDY_FETCH_OBJECT;
RETURN_LONG(tidyWarningCount(obj->ptdoc->doc));
}
/* }}} */
/* {{{ proto int tidy_access_count(tidy tidy)
Returns the Number of Tidy accessibility warnings encountered for specified document. */
static PHP_FUNCTION(tidy_access_count)
{
TIDY_FETCH_OBJECT;
RETURN_LONG(tidyAccessWarningCount(obj->ptdoc->doc));
}
/* }}} */
/* {{{ proto int tidy_config_count(tidy tidy)
Returns the Number of Tidy configuration errors encountered for specified document. */
static PHP_FUNCTION(tidy_config_count)
{
TIDY_FETCH_OBJECT;
RETURN_LONG(tidyConfigErrorCount(obj->ptdoc->doc));
}
/* }}} */
/* {{{ proto mixed tidy_getopt(string option)
Returns the value of the specified configuration option for the tidy document. */
static PHP_FUNCTION(tidy_getopt)
{
PHPTidyObj *obj;
char *optname;
void *optval;
size_t optname_len;
TidyOption opt;
TidyOptionType optt;
TIDY_SET_CONTEXT;
if (object) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &optname, &optname_len) == FAILURE) {
RETURN_FALSE;
}
} else {
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), NULL, "Os", &object, tidy_ce_doc, &optname, &optname_len) == FAILURE) {
RETURN_FALSE;
}
}
obj = Z_TIDY_P(object);
opt = tidyGetOptionByName(obj->ptdoc->doc, optname);
if (!opt) {
php_error_docref(NULL, E_WARNING, "Unknown Tidy Configuration Option '%s'", optname);
RETURN_FALSE;
}
optval = php_tidy_get_opt_val(obj->ptdoc, opt, &optt);
switch (optt) {
case TidyString:
RETVAL_STR((zend_string*)optval);
return;
case TidyInteger:
RETURN_LONG((zend_long)optval);
break;
case TidyBoolean:
if (optval) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
break;
default:
php_error_docref(NULL, E_WARNING, "Unable to determine type of configuration option");
break;
}
RETURN_FALSE;
}
/* }}} */
static TIDY_DOC_METHOD(__construct)
{
char *enc = NULL;
size_t enc_len = 0;
zend_bool use_include_path = 0;
zval *options = NULL;
zend_string *contents, *inputfile = NULL;
PHPTidyObj *obj;
TIDY_SET_CONTEXT;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|Pzsb", &inputfile,
&options, &enc, &enc_len, &use_include_path) == FAILURE) {
RETURN_FALSE;
}
obj = Z_TIDY_P(object);
if (inputfile) {
if (!(contents = php_tidy_file_to_mem(ZSTR_VAL(inputfile), use_include_path))) {
php_error_docref(NULL, E_WARNING, "Cannot Load '%s' into memory%s", ZSTR_VAL(inputfile), (use_include_path) ? " (Using include path)" : "");
return;
}
if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(contents))) {
php_error_docref(NULL, E_WARNING, "Input string is too long");
RETURN_FALSE;
}
TIDY_APPLY_CONFIG_ZVAL(obj->ptdoc->doc, options);
php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc);
zend_string_release_ex(contents, 0);
}
}
static TIDY_DOC_METHOD(parseFile)
{
char *enc = NULL;
size_t enc_len = 0;
zend_bool use_include_path = 0;
zval *options = NULL;
zend_string *inputfile, *contents;
PHPTidyObj *obj;
TIDY_SET_CONTEXT;
obj = Z_TIDY_P(object);
if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|zsb", &inputfile,
&options, &enc, &enc_len, &use_include_path) == FAILURE) {
RETURN_FALSE;
}
if (!(contents = php_tidy_file_to_mem(ZSTR_VAL(inputfile), use_include_path))) {
php_error_docref(NULL, E_WARNING, "Cannot Load '%s' into memory%s", ZSTR_VAL(inputfile), (use_include_path) ? " (Using include path)" : "");
RETURN_FALSE;
}
if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(contents))) {
php_error_docref(NULL, E_WARNING, "Input string is too long");
RETURN_FALSE;
}
TIDY_APPLY_CONFIG_ZVAL(obj->ptdoc->doc, options);
if (php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc) == FAILURE) {
RETVAL_FALSE;
} else {
RETVAL_TRUE;
}
zend_string_release_ex(contents, 0);
}
static TIDY_DOC_METHOD(parseString)
{
char *enc = NULL;
size_t enc_len = 0;
zval *options = NULL;
PHPTidyObj *obj;
zend_string *input;
TIDY_SET_CONTEXT;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|zs", &input, &options, &enc, &enc_len) == FAILURE) {
RETURN_FALSE;
}
if (ZEND_SIZE_T_UINT_OVFL(ZSTR_LEN(input))) {
php_error_docref(NULL, E_WARNING, "Input string is too long");
RETURN_FALSE;
}
obj = Z_TIDY_P(object);
TIDY_APPLY_CONFIG_ZVAL(obj->ptdoc->doc, options);
if(php_tidy_parse_string(obj, ZSTR_VAL(input), (uint32_t)ZSTR_LEN(input), enc) == SUCCESS) {
RETURN_TRUE;
}
RETURN_FALSE;
}
/* {{{ proto TidyNode tidy_get_root()
Returns a TidyNode Object representing the root of the tidy parse tree */
static PHP_FUNCTION(tidy_get_root)
{
php_tidy_create_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, is_root_node);
}
/* }}} */
/* {{{ proto TidyNode tidy_get_html()
Returns a TidyNode Object starting from the <HTML> tag of the tidy parse tree */
static PHP_FUNCTION(tidy_get_html)
{
php_tidy_create_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, is_html_node);
}
/* }}} */
/* {{{ proto TidyNode tidy_get_head()
Returns a TidyNode Object starting from the <HEAD> tag of the tidy parse tree */
static PHP_FUNCTION(tidy_get_head)
{
php_tidy_create_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, is_head_node);
}
/* }}} */
/* {{{ proto TidyNode tidy_get_body(tidy tidy)
Returns a TidyNode Object starting from the <BODY> tag of the tidy parse tree */
static PHP_FUNCTION(tidy_get_body)
{
php_tidy_create_node(INTERNAL_FUNCTION_PARAM_PASSTHRU, is_body_node);
}
/* }}} */
/* {{{ proto bool tidyNode::hasChildren()
Returns true if this node has children */
static TIDY_NODE_METHOD(hasChildren)
{
TIDY_FETCH_ONLY_OBJECT;
if (tidyGetChild(obj->node)) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto bool tidyNode::hasSiblings()
Returns true if this node has siblings */
static TIDY_NODE_METHOD(hasSiblings)
{
TIDY_FETCH_ONLY_OBJECT;
if (obj->node && tidyGetNext(obj->node)) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto bool tidyNode::isComment()
Returns true if this node represents a comment */
static TIDY_NODE_METHOD(isComment)
{
TIDY_FETCH_ONLY_OBJECT;
if (tidyNodeGetType(obj->node) == TidyNode_Comment) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto bool tidyNode::isHtml()
Returns true if this node is part of a HTML document */
static TIDY_NODE_METHOD(isHtml)
{
TIDY_FETCH_ONLY_OBJECT;
if (tidyNodeGetType(obj->node) & (TidyNode_Start | TidyNode_End | TidyNode_StartEnd)) {
RETURN_TRUE;
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto bool tidyNode::isText()
Returns true if this node represents text (no markup) */
static TIDY_NODE_METHOD(isText)
{
TIDY_FETCH_ONLY_OBJECT;
if (tidyNodeGetType(obj->node) == TidyNode_Text) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto bool tidyNode::isJste()
Returns true if this node is JSTE */
static TIDY_NODE_METHOD(isJste)
{
TIDY_FETCH_ONLY_OBJECT;
if (tidyNodeGetType(obj->node) == TidyNode_Jste) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto bool tidyNode::isAsp()
Returns true if this node is ASP */
static TIDY_NODE_METHOD(isAsp)
{
TIDY_FETCH_ONLY_OBJECT;
if (tidyNodeGetType(obj->node) == TidyNode_Asp) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto bool tidyNode::isPhp()
Returns true if this node is PHP */
static TIDY_NODE_METHOD(isPhp)
{
TIDY_FETCH_ONLY_OBJECT;
if (tidyNodeGetType(obj->node) == TidyNode_Php) {
RETURN_TRUE;
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto tidyNode tidyNode::getParent()
Returns the parent node if available or NULL */
static TIDY_NODE_METHOD(getParent)
{
TidyNode parent_node;
PHPTidyObj *newobj;
TIDY_FETCH_ONLY_OBJECT;
parent_node = tidyGetParent(obj->node);
if(parent_node) {
tidy_instanciate(tidy_ce_node, return_value);
newobj = Z_TIDY_P(return_value);
newobj->node = parent_node;
newobj->type = is_node;
newobj->ptdoc = obj->ptdoc;
newobj->ptdoc->ref_count++;
tidy_add_default_properties(newobj, is_node);
} else {
ZVAL_NULL(return_value);
}
}
/* }}} */
/* {{{ proto tidyNode::__construct()
__constructor for tidyNode. */
static TIDY_NODE_METHOD(__construct)
{
zend_throw_error(NULL, "You should not create a tidyNode manually");
}
/* }}} */
static void _php_tidy_register_nodetypes(INIT_FUNC_ARGS)
{
TIDY_NODE_CONST(ROOT, Root);
TIDY_NODE_CONST(DOCTYPE, DocType);
TIDY_NODE_CONST(COMMENT, Comment);
TIDY_NODE_CONST(PROCINS, ProcIns);
TIDY_NODE_CONST(TEXT, Text);
TIDY_NODE_CONST(START, Start);
TIDY_NODE_CONST(END, End);
TIDY_NODE_CONST(STARTEND, StartEnd);
TIDY_NODE_CONST(CDATA, CDATA);
TIDY_NODE_CONST(SECTION, Section);
TIDY_NODE_CONST(ASP, Asp);
TIDY_NODE_CONST(JSTE, Jste);
TIDY_NODE_CONST(PHP, Php);
TIDY_NODE_CONST(XMLDECL, XmlDecl);
}
static void _php_tidy_register_tags(INIT_FUNC_ARGS)
{
TIDY_TAG_CONST(UNKNOWN);
TIDY_TAG_CONST(A);
TIDY_TAG_CONST(ABBR);
TIDY_TAG_CONST(ACRONYM);
TIDY_TAG_CONST(ADDRESS);
TIDY_TAG_CONST(ALIGN);
TIDY_TAG_CONST(APPLET);
TIDY_TAG_CONST(AREA);
TIDY_TAG_CONST(B);
TIDY_TAG_CONST(BASE);
TIDY_TAG_CONST(BASEFONT);
TIDY_TAG_CONST(BDO);
TIDY_TAG_CONST(BGSOUND);
TIDY_TAG_CONST(BIG);
TIDY_TAG_CONST(BLINK);
TIDY_TAG_CONST(BLOCKQUOTE);
TIDY_TAG_CONST(BODY);
TIDY_TAG_CONST(BR);
TIDY_TAG_CONST(BUTTON);
TIDY_TAG_CONST(CAPTION);
TIDY_TAG_CONST(CENTER);
TIDY_TAG_CONST(CITE);
TIDY_TAG_CONST(CODE);
TIDY_TAG_CONST(COL);
TIDY_TAG_CONST(COLGROUP);
TIDY_TAG_CONST(COMMENT);
TIDY_TAG_CONST(DD);
TIDY_TAG_CONST(DEL);
TIDY_TAG_CONST(DFN);
TIDY_TAG_CONST(DIR);
TIDY_TAG_CONST(DIV);
TIDY_TAG_CONST(DL);
TIDY_TAG_CONST(DT);
TIDY_TAG_CONST(EM);
TIDY_TAG_CONST(EMBED);
TIDY_TAG_CONST(FIELDSET);
TIDY_TAG_CONST(FONT);
TIDY_TAG_CONST(FORM);
TIDY_TAG_CONST(FRAME);
TIDY_TAG_CONST(FRAMESET);
TIDY_TAG_CONST(H1);
TIDY_TAG_CONST(H2);
TIDY_TAG_CONST(H3);
TIDY_TAG_CONST(H4);
TIDY_TAG_CONST(H5);
TIDY_TAG_CONST(H6);
TIDY_TAG_CONST(HEAD);
TIDY_TAG_CONST(HR);
TIDY_TAG_CONST(HTML);
TIDY_TAG_CONST(I);
TIDY_TAG_CONST(IFRAME);
TIDY_TAG_CONST(ILAYER);
TIDY_TAG_CONST(IMG);
TIDY_TAG_CONST(INPUT);
TIDY_TAG_CONST(INS);
TIDY_TAG_CONST(ISINDEX);
TIDY_TAG_CONST(KBD);
TIDY_TAG_CONST(KEYGEN);
TIDY_TAG_CONST(LABEL);
TIDY_TAG_CONST(LAYER);
TIDY_TAG_CONST(LEGEND);
TIDY_TAG_CONST(LI);
TIDY_TAG_CONST(LINK);
TIDY_TAG_CONST(LISTING);
TIDY_TAG_CONST(MAP);
TIDY_TAG_CONST(MARQUEE);
TIDY_TAG_CONST(MENU);
TIDY_TAG_CONST(META);
TIDY_TAG_CONST(MULTICOL);
TIDY_TAG_CONST(NOBR);
TIDY_TAG_CONST(NOEMBED);
TIDY_TAG_CONST(NOFRAMES);
TIDY_TAG_CONST(NOLAYER);
TIDY_TAG_CONST(NOSAVE);
TIDY_TAG_CONST(NOSCRIPT);
TIDY_TAG_CONST(OBJECT);
TIDY_TAG_CONST(OL);
TIDY_TAG_CONST(OPTGROUP);
TIDY_TAG_CONST(OPTION);
TIDY_TAG_CONST(P);
TIDY_TAG_CONST(PARAM);
TIDY_TAG_CONST(PLAINTEXT);
TIDY_TAG_CONST(PRE);
TIDY_TAG_CONST(Q);
TIDY_TAG_CONST(RB);
TIDY_TAG_CONST(RBC);
TIDY_TAG_CONST(RP);
TIDY_TAG_CONST(RT);
TIDY_TAG_CONST(RTC);
TIDY_TAG_CONST(RUBY);
TIDY_TAG_CONST(S);
TIDY_TAG_CONST(SAMP);
TIDY_TAG_CONST(SCRIPT);
TIDY_TAG_CONST(SELECT);
TIDY_TAG_CONST(SERVER);
TIDY_TAG_CONST(SERVLET);
TIDY_TAG_CONST(SMALL);
TIDY_TAG_CONST(SPACER);
TIDY_TAG_CONST(SPAN);
TIDY_TAG_CONST(STRIKE);
TIDY_TAG_CONST(STRONG);
TIDY_TAG_CONST(STYLE);
TIDY_TAG_CONST(SUB);
TIDY_TAG_CONST(SUP);
TIDY_TAG_CONST(TABLE);
TIDY_TAG_CONST(TBODY);
TIDY_TAG_CONST(TD);
TIDY_TAG_CONST(TEXTAREA);
TIDY_TAG_CONST(TFOOT);
TIDY_TAG_CONST(TH);
TIDY_TAG_CONST(THEAD);
TIDY_TAG_CONST(TITLE);
TIDY_TAG_CONST(TR);
TIDY_TAG_CONST(TT);
TIDY_TAG_CONST(U);
TIDY_TAG_CONST(UL);
TIDY_TAG_CONST(VAR);
TIDY_TAG_CONST(WBR);
TIDY_TAG_CONST(XMP);
# if HAVE_TIDYBUFFIO_H
TIDY_TAG_CONST(ARTICLE);
TIDY_TAG_CONST(ASIDE);
TIDY_TAG_CONST(AUDIO);
TIDY_TAG_CONST(BDI);
TIDY_TAG_CONST(CANVAS);
TIDY_TAG_CONST(COMMAND);
TIDY_TAG_CONST(DATALIST);
TIDY_TAG_CONST(DETAILS);
TIDY_TAG_CONST(DIALOG);
TIDY_TAG_CONST(FIGCAPTION);
TIDY_TAG_CONST(FIGURE);
TIDY_TAG_CONST(FOOTER);
TIDY_TAG_CONST(HEADER);
TIDY_TAG_CONST(HGROUP);
TIDY_TAG_CONST(MAIN);
TIDY_TAG_CONST(MARK);
TIDY_TAG_CONST(MENUITEM);
TIDY_TAG_CONST(METER);
TIDY_TAG_CONST(NAV);
TIDY_TAG_CONST(OUTPUT);
TIDY_TAG_CONST(PROGRESS);
TIDY_TAG_CONST(SECTION);
TIDY_TAG_CONST(SOURCE);
TIDY_TAG_CONST(SUMMARY);
TIDY_TAG_CONST(TEMPLATE);
TIDY_TAG_CONST(TIME);
TIDY_TAG_CONST(TRACK);
TIDY_TAG_CONST(VIDEO);
# endif
}
#endif