commit 7d8a301b568be109aab2f042cff1de14c0f115bd Author: Miroslav Kubelik Date: Wed Jun 23 08:38:41 2010 +0000 rrd pecl extension - initial commit git-svn-id: http://svn.php.net/repository/pecl/rrd/trunk@300689 c90b9560-bf6c-de11-be94-00142212c4b1 diff --git a/config.m4 b/config.m4 new file mode 100644 index 0000000..a830eb8 --- /dev/null +++ b/config.m4 @@ -0,0 +1,87 @@ +dnl config.m4 for extension php_rrd +dnl Comments in this file start with the string 'dnl'. + +PHP_ARG_WITH(rrd, for rrdtool support, +[ --with-rrd[=DIR] Include rrdtool support (requires rrdtool >= 1.2.x)]) + +if test "$PHP_RRD" != "no"; then + if test "$PHP_RRD" != "yes"; then + AC_MSG_CHECKING(if rrdtool specified path is valid) + if test -r $PHP_RRD/include/rrd.h && test -f $PHP_RRD/lib/librrd.$SHLIB_SUFFIX_NAME -o -f $PHP_RRD/lib/librrd.a; then # path given as parameter + RRDTOOL_DIR=$PHP_RRD + RRDTOOL_INCDIR=$PHP_RRD/include + RRDTOOL_LIBDIR=$PHP_RRD/lib + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_ERROR([The specified RRDTool path is invalid or the installation is incomplete + Please specify another path or reinstall the rrdtool distribution]) + fi + else + dnl Header path + AC_MSG_CHECKING([for rrdtool header files in default path]) + for i in /usr/local/rrdtool /usr/local /usr /opt ""; do + test -r $i/include/rrd.h && RRDTOOL_DIR=$i && RRDTOOL_INCDIR=$i/include + done + if test -z "$RRDTOOL_INCDIR"; then + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([Please reinstall the rrdtool distribution]) + else + AC_MSG_RESULT(found in $RRDTOOL_INCDIR) + fi + dnl Library path + AC_MSG_CHECKING([for rrdtool library files in default path]) + for i in librrd.$SHLIB_SUFFIX_NAME librrd.a; do + test -f $RRDTOOL_DIR/lib/$i && RRDTOOL_LIBDIR=$RRDTOOL_DIR/lib + done + if test -z "$RRDTOOL_LIBDIR"; then + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([Please reinstall the rrdtool distribution]) + else + AC_MSG_RESULT(found in $RRDTOOL_LIBDIR) + fi + fi + +dnl Finish the setup + + RRD_H_PATH="$RRDTOOL_INCDIR/rrd.h" + PHP_RRDTOOL_DIR=$RRDTOOL_DIR + PHP_ADD_INCLUDE($RRDTOOL_INCDIR) + + PHP_CHECK_LIBRARY(rrd, rrd_create, + [],[ + PHP_CHECK_LIBRARY(rrd, rrd_create, + [],[ + AC_MSG_ERROR([wrong rrd lib version or lib not found]) + ],[ + -L$RRDTOOL_LIBDIR -ldl + ]) + ],[ + -L$RRDTOOL_LIBDIR -ldl + ]) + + AC_MSG_CHECKING([rrdtool version]) + AC_TRY_COMPILE([ +#include <$RRD_H_PATH> + ], [int main() { + double some_variable; + some_variable = rrd_version(); + } + ], [ + AC_MSG_RESULT([1.2.x]) + ac_cv_rrdversion=yes + ], [ + AC_MSG_RESULT([1.0.x]) + ac_cv_rrdversion=no + ]) + + if test "$ac_cv_rrdversion" = yes; then + AC_DEFINE(HAVE_RRD_12X, 1, [Whether you have rrd_version]) + fi + + PHP_ADD_LIBRARY_WITH_PATH(rrd, $RRDTOOL_LIBDIR, RRD_SHARED_LIBADD) + + PHP_NEW_EXTENSION(rrd, rrd.c rrd_graph.c rrd_create.c rrd_update.c, $ext_shared) + PHP_SUBST(RRD_SHARED_LIBADD) + AC_DEFINE(HAVE_RRDTOOL, 1, [ ]) +fi diff --git a/php_rrd.h b/php_rrd.h new file mode 100644 index 0000000..dbe7602 --- /dev/null +++ b/php_rrd.h @@ -0,0 +1,38 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2010 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: Miroslav Kubelik | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_RRD_H +#define PHP_RRD_H + +extern zend_module_entry rrd_module_entry; +#define phpext_rrd_ptr &rrd_module_entry + +#ifdef ZTS +#include "TSRM.h" +#endif + +typedef struct _rrd_args { + int count; + char **args; +} rrd_args; + +rrd_args *rrd_args_init_by_phparray(const char *command_name, const char *filename, + const zval *options TSRMLS_DC); +void rrd_args_free(rrd_args *args); + +#endif /* PHP_RRD_H */ diff --git a/rrd.c b/rrd.c new file mode 100644 index 0000000..3fecf6f --- /dev/null +++ b/rrd.c @@ -0,0 +1,136 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2010 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: Miroslav Kubelik | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "ext/standard/php_smart_str.h" +#include "php_rrd.h" +#include "rrd_graph.h" +#include "rrd_create.h" +#include "rrd_update.h" + +/* {{{ */ +static function_entry rrd_functions[] = { + PHP_FE(rrd_update, arginfo_rrd_update) + PHP_FE(rrd_create, arginfo_rrd_create) + {NULL, NULL, NULL} +}; +/* }}} */ + +#ifdef COMPILE_DL_RRD + ZEND_GET_MODULE(rrd) +#endif + +/* {{{ PHP_MINIT_FUNCTION */ +static PHP_MINIT_FUNCTION(rrd) +{ + rrd_graph_minit(TSRMLS_CC); + rrd_create_minit(TSRMLS_CC); + rrd_update_minit(TSRMLS_CC); + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MINFO_FUNCTION */ +static PHP_MINFO_FUNCTION(rrd) +{ + php_info_print_table_start(); + php_info_print_table_header(2, "rrd wrapper", "enabled"); + php_info_print_table_row(2, "Version", "0.1"); + php_info_print_table_end(); +} +/* }}} */ + +/* {{{ rrd module_entry */ +zend_module_entry rrd_module_entry = { + STANDARD_MODULE_HEADER, + "rrd", + rrd_functions, + PHP_MINIT(rrd), + NULL, /* PHP_MSHUTDOWN(rrd) */ + NULL, /* PHP_RINIT(rrd) */ + NULL, /* PHP_RSHUTDOWN(rrd) */ + PHP_MINFO(rrd), + "0.1", + STANDARD_MODULE_PROPERTIES +}; +/* }}} */ + +/* {{{ Inits rrd arguments object for a particular rrd command by php array + * filename paremeter is optional. + */ +rrd_args *rrd_args_init_by_phparray(const char *command_name, const char *filename, + const zval *options TSRMLS_DC) +{ + uint i, option_count, args_counter = 2; + + if (Z_TYPE_P(options) != IS_ARRAY) return NULL; + option_count = zend_hash_num_elements(Z_ARRVAL_P(options)); + if (!option_count) return NULL; + if (!strlen(command_name)) return NULL; + + rrd_args *result = (rrd_args *)emalloc(sizeof(rrd_args)); + /* "dummy" + command_name + filename if presented */ + result->count = option_count + (strlen(command_name) ? 3 : 2); + result->args = (char **)safe_emalloc(result->count, sizeof(char *), 0); + + /* "dummy" and command_name are needed always needed */ + result->args[0] = "dummy"; + result->args[1] = estrdup(filename); + + /* append filename if it's presented */ + if (strlen(filename)) result->args[args_counter++] = estrdup(filename); + + zend_hash_internal_pointer_reset(Z_ARRVAL_P(options)); + for(i=0; iargs[args_counter++] = estrdup(option.c); + smart_str_free(&option); + + zend_hash_move_forward(Z_ARRVAL_P(options)); + } + + return result; +} +/* }}} */ + +/* {{{ Frees all memory for arguments object + */ +void rrd_args_free(rrd_args *args) +{ + int i; + if (!args || !args->args) return; + + for (i=1; icount; i++) + efree(args->args[i]); + + efree(args->args); + efree(args); +} +/* }}} */ \ No newline at end of file diff --git a/rrd_create.c b/rrd_create.c new file mode 100644 index 0000000..490d570 --- /dev/null +++ b/rrd_create.c @@ -0,0 +1,407 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2010 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: Miroslav Kubelik | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "php.h" +#include "rrd_create.h" +#include "php_rrd.h" +#include "ext/standard/php_smart_str.h" + +/* declare class entry */ +static zend_class_entry *ce_rrd_create; +/* declare class handlers */ +static zend_object_handlers rrd_create_handlers; + +/* overloading the standard zend object structure (std property) in the need +of having dedicated creating/cloning/destruction functions +*/ +typedef struct _rrd_create_object { + zend_object std; + /** path to newly created rrd file */ + char *file_path; + /* "--start" parameters in rrd create */ + char *start_time; + /* "--step" parameters in rrd create */ + zval *zv_step; + /* "DS" parameters in rrd create */ + zval *zv_arr_data_sources; + /* "RRA" parameters in rrd create */ + zval *zv_arr_archives; +} rrd_create_object; + +/* {{{ rrd_create_object_dtor +close all resources and the memory allocated for our internal object +*/ +static void rrd_create_object_dtor(void *object TSRMLS_DC) +{ + rrd_create_object *intern_obj = (rrd_create_object *)object; + + if (intern_obj->file_path) + efree(intern_obj->file_path); + if (intern_obj->start_time) + efree(intern_obj->start_time); + if (intern_obj->zv_step) + zval_dtor(intern_obj->zv_step); + if (intern_obj->zv_arr_data_sources) + zval_dtor(intern_obj->zv_arr_data_sources); + if (intern_obj->zv_arr_archives) + zval_dtor(intern_obj->zv_arr_archives); + + zend_object_std_dtor(&intern_obj->std TSRMLS_CC); + efree(intern_obj); +} +/* }}} */ + +/* {{{ rrd_create_object_new +creates new rrd create object +*/ +static zend_object_value rrd_create_object_new(zend_class_entry *ce TSRMLS_DC) +{ + rrd_create_object *intern_obj; + zend_object_value retval; + zval *tmp; + + intern_obj = ecalloc(1, sizeof(*intern_obj)); + zend_object_std_init(&intern_obj->std, ce TSRMLS_CC); + + intern_obj->file_path = NULL; + intern_obj->start_time = NULL; + intern_obj->zv_step = NULL; + intern_obj->zv_arr_data_sources = NULL; + intern_obj->zv_arr_archives = NULL; + + zend_hash_copy(intern_obj->std.properties, &ce->default_properties, + (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval*) + ); + + retval.handle = zend_objects_store_put(intern_obj, + (zend_objects_store_dtor_t)zend_objects_destroy_object, + rrd_create_object_dtor, NULL TSRMLS_CC + ); + + retval.handlers = &rrd_create_handlers; + + return retval; +} +/* }}} */ + +/* {{{ proto void RRDCreator::__construct(string path [,string startTime] + [,int step]) +creates new object for creating rrd database + */ +PHP_METHOD(RRDCreator, __construct) +{ + rrd_create_object *intern_obj; + char *path; int path_length; + /* better to set defaults for optional parameters */ + char *start_time = NULL; int start_time_length = 0; + uint step = 0; + int argc = ZEND_NUM_ARGS(); + + if (zend_parse_parameters(argc TSRMLS_CC, "s|sl", &path, &path_length, + &start_time, &start_time_length, &step) == FAILURE) { + return; + } + + if (path_length == 0) { + zend_throw_exception(zend_exception_get_default(TSRMLS_C), + "path for rrd file cannot be empty string", 0 TSRMLS_CC); + return; + } + + if (argc > 1 && start_time_length == 0) { + zend_throw_exception(zend_exception_get_default(TSRMLS_C), + "startTime cannot be empty string", 0 TSRMLS_CC); + return; + } + if (argc > 2 && step <= 0) { + zend_throw_exception(zend_exception_get_default(TSRMLS_C), + "step parameter must be greater then 0", 0 TSRMLS_CC); + return; + } + + intern_obj = (rrd_create_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + intern_obj->file_path = estrdup(path); + if (start_time) intern_obj->start_time = estrdup(start_time); + if (step) { + MAKE_STD_ZVAL(intern_obj->zv_step); + ZVAL_LONG(intern_obj->zv_step,step); + } + return; +} +/* }}} */ + +/* {{{ proto RRDCreator::addDataSource(string description) + Add information about data source + */ +PHP_METHOD(RRDCreator, addDataSource) +{ + rrd_create_object *intern_obj; + char *desc, *rrd_source_desc; + int desc_length; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &desc, &desc_length) == FAILURE) { + return; + } + + if (desc_length == 0) { + zend_throw_exception(zend_exception_get_default(TSRMLS_C), + "description parameter cannot be empty string", 0 TSRMLS_CC); + return; + } + + intern_obj = (rrd_create_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (!intern_obj->zv_arr_data_sources) { + MAKE_STD_ZVAL(intern_obj->zv_arr_data_sources); + array_init(intern_obj->zv_arr_data_sources); + } + + rrd_source_desc = emalloc(desc_length + 4); + strcpy(rrd_source_desc, "DS:"); + strcat(rrd_source_desc, desc); + + add_next_index_string(intern_obj->zv_arr_data_sources, rrd_source_desc, 1); + efree(rrd_source_desc); + + return; +} +/* }}} */ + +/* {{{ proto RRDCreator::addArchive(string description) + Add information about new round robin archive + */ +PHP_METHOD(RRDCreator, addArchive) +{ + rrd_create_object *intern_obj; + char *desc, *rrd_archive_desc; + int desc_length; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &desc, &desc_length) == FAILURE) { + return; + } + + if (desc_length == 0) { + zend_throw_exception(zend_exception_get_default(TSRMLS_C), + "description parameter cannot be empty string", 0 TSRMLS_CC); + return; + } + + intern_obj = (rrd_create_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (!intern_obj->zv_arr_archives) { + MAKE_STD_ZVAL(intern_obj->zv_arr_archives); + array_init(intern_obj->zv_arr_archives); + } + + rrd_archive_desc = emalloc(desc_length + 5); + strcpy(rrd_archive_desc, "RRA:"); + strcat(rrd_archive_desc, desc); + + add_next_index_string(intern_obj->zv_arr_archives, rrd_archive_desc, 1); + efree(rrd_archive_desc); + + return; +} +/* }}} */ + +/* {{{ rrd_create_add_string_arg + Adds strings form php array into array (in C sense) of arguments for rrd_create + call + @param argv "C" array of arguments for rrd_create, is already allocated + with "counter param" filled elements + @param arr php array of strings + @param counter count of filled elements in array, is increased for each newly + added string +*/ +static void rrd_create_add_string_arg(char **argv, zval *arr, uint *counter TSRMLS_DC) +{ + uint elements = zend_hash_num_elements(Z_ARRVAL_P(arr)); + uint i; + + zend_hash_internal_pointer_reset(Z_ARRVAL_P(arr)); + for(i=0; izv_arr_archives)); + uint data_source_count = zend_hash_num_elements(Z_ARRVAL_P(intern_obj->zv_arr_data_sources)); + + /* 0-2 are defined below + start_time + step = 5 options */ + argc = archive_count + data_source_count + 5; + + argv = (char **) safe_emalloc(argc, sizeof(char *), 0); + /* "dummy" and "create" arguments are needed */ + argv[0] = "dummy"; + argv[1] = estrdup("create"); + argv[2] = estrdup(intern_obj->file_path); + arg_counter = 3; + + if (intern_obj->start_time) { + const char *prefix = "--start="; + char *start_time_str = emalloc(strlen(intern_obj->start_time) + + strlen(prefix) + 1); + + strcpy(start_time_str, prefix); + strcat(start_time_str, intern_obj->start_time); + + argv[arg_counter++] = estrdup(start_time_str); + efree(start_time_str); + } else { + argc--; + } + + if (intern_obj->zv_step) { + const char *prefix = "--step="; + char *start_time_str; + + convert_to_string(intern_obj->zv_step); + start_time_str = emalloc(strlen(prefix) + Z_STRLEN_P(intern_obj->zv_step) + 1); + + strcpy(start_time_str, prefix); + strcat(start_time_str, Z_STRVAL_P(intern_obj->zv_step)); + + argv[arg_counter++] = estrdup(start_time_str); + /* back to long, doesn't needed, but we are consistent */ + convert_to_long(intern_obj->zv_step); + efree(start_time_str); + } else { + argc--; + } + + /* add array of archive, data source strings into argument list for rrd_create */ + rrd_create_add_string_arg(argv, intern_obj->zv_arr_data_sources, &arg_counter TSRMLS_CC); + rrd_create_add_string_arg(argv, intern_obj->zv_arr_archives, &arg_counter TSRMLS_CC); + + if (rrd_test_error()) rrd_clear_error(); + + /* call rrd_create and test if fails */ + if (rrd_create(argc-1, &argv[1]) == -1) { + + for (i=1; icount - 1, &argv->args[1]) == -1 ) { + RETVAL_FALSE; + } else { + RETVAL_TRUE; + } + + rrd_args_free(argv); +} +/* }}} */ + +/* arguments */ +ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 1) + ZEND_ARG_INFO(0, path) + ZEND_ARG_INFO(0, startTime) + ZEND_ARG_INFO(0, step) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_description, 0, 0, 1) + ZEND_ARG_INFO(0, description) +ZEND_END_ARG_INFO() + +/* class method table */ +static zend_function_entry rrd_create_methods[] = { + PHP_ME(RRDCreator, __construct, arginfo_construct, ZEND_ACC_PUBLIC) + PHP_ME(RRDCreator, save, NULL, ZEND_ACC_PUBLIC) + PHP_ME(RRDCreator, addDataSource, arginfo_description, ZEND_ACC_PUBLIC) + PHP_ME(RRDCreator, addArchive, arginfo_description, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +/* minit hook, called from main module minit */ +void rrd_create_minit(TSRMLS_DC) +{ + zend_class_entry ce; + INIT_CLASS_ENTRY(ce, "RRDCreator", rrd_create_methods); + ce.create_object = rrd_create_object_new; + ce_rrd_create = zend_register_internal_class(&ce TSRMLS_CC); + + memcpy(&rrd_create_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + rrd_create_handlers.clone_obj = NULL; +} + diff --git a/rrd_create.h b/rrd_create.h new file mode 100644 index 0000000..cfb60ed --- /dev/null +++ b/rrd_create.h @@ -0,0 +1,30 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2010 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: Miroslav Kubelik | + +----------------------------------------------------------------------+ +*/ + +#ifndef RRD_CREATE_H +#define RRD_CREATE_H + +void rrd_create_minit(TSRMLS_DC); +PHP_FUNCTION(rrd_create); + +ZEND_BEGIN_ARG_INFO(arginfo_rrd_create, 0) + ZEND_ARG_INFO(0, file) + ZEND_ARG_INFO(0, options) +ZEND_END_ARG_INFO() + +#endif /* RRD_CREATE_H */ diff --git a/rrd_graph.c b/rrd_graph.c new file mode 100644 index 0000000..5a4eed9 --- /dev/null +++ b/rrd_graph.c @@ -0,0 +1,264 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2010 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: Miroslav Kubelik | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "php.h" +#include "rrd_graph.h" +#include "ext/standard/php_smart_str.h" + +/* declare class entry */ +static zend_class_entry *ce_rrd_graph; +/* declare class handlers */ +static zend_object_handlers rrd_graph_handlers; + +/* overloading the standard zend object structure (std property) in the need +of having dedicated creating/cloning/destruction functions +*/ +typedef struct _rrd_graph_object { + zend_object std; + char *file_path; + zval *zv_arr_options; +} rrd_graph_object; + +/* {{{ rrd_graph_object_dtor +close all resources and the memory allocated for our internal object +*/ +static void rrd_graph_object_dtor(void *object TSRMLS_DC) +{ + rrd_graph_object *intern_obj = (rrd_graph_object *)object; + + if (intern_obj->file_path) + efree(intern_obj->file_path); + if (intern_obj->zv_arr_options) { + zval_dtor(intern_obj->zv_arr_options); + } + + zend_object_std_dtor(&intern_obj->std TSRMLS_CC); + efree(intern_obj); +} +/* }}} */ + +/* {{{ rrd_graph_object_new +creates new rrd graph object +*/ +static zend_object_value rrd_graph_object_new(zend_class_entry *ce TSRMLS_DC) +{ + rrd_graph_object *intern_obj; + zend_object_value retval; + zval *tmp; + + intern_obj = ecalloc(1, sizeof(*intern_obj)); + zend_object_std_init(&intern_obj->std, ce TSRMLS_CC); + intern_obj->file_path = NULL; + intern_obj->zv_arr_options = NULL; + + zend_hash_copy(intern_obj->std.properties, &ce->default_properties, + (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval*) + ); + + retval.handle = zend_objects_store_put(intern_obj, + (zend_objects_store_dtor_t)zend_objects_destroy_object, + rrd_graph_object_dtor, NULL TSRMLS_CC + ); + + retval.handlers = &rrd_graph_handlers; + + return retval; +} +/* }}} */ + +/* {{{ proto void RRDGraph::__construct(string path) +creates new object for rrd graph function + */ +PHP_METHOD(RRDGraph, __construct) +{ + rrd_graph_object *intern_obj; + char *path; + int path_length; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &path_length) == FAILURE) { + return; + } + + intern_obj = (rrd_graph_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + intern_obj->file_path = estrdup(path); +} +/* }}} */ + +/* {{{ proto void RRDGraph::setOptions(array options) +set command options for rrd graph call + */ +PHP_METHOD(RRDGraph, setOptions) +{ + rrd_graph_object *intern_obj; + zval *zv_arr_options; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &zv_arr_options) == FAILURE) { + return; + } + + intern_obj = (rrd_graph_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + /* if our array is initialized, so delete it first */ + if (intern_obj->zv_arr_options) { + zval_dtor(intern_obj->zv_arr_options); + } + + /* copy array from parameter */ + MAKE_STD_ZVAL(intern_obj->zv_arr_options); + *intern_obj->zv_arr_options = *zv_arr_options; + zval_copy_ctor(intern_obj->zv_arr_options); + + return; +} +/* }}} */ + +/* {{{ proto array RRDGraph::save() +Saves graph according to current properties. + */ +PHP_METHOD(RRDGraph, save) +{ + rrd_graph_object *intern_obj = (rrd_graph_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + + int xsize, ysize; + double ymin,ymax; + char **calcpr; + /* array of arguments for rrd_graph call */ + char **argv; + unsigned int argc,i; + + if (!intern_obj->zv_arr_options || Z_TYPE_P(intern_obj->zv_arr_options) != IS_ARRAY) { + zend_throw_exception(zend_exception_get_default(TSRMLS_C), + "options aren't correctly set", 0 TSRMLS_CC); + return; + } + + if (rrd_test_error()) rrd_clear_error(); + + argc = zend_hash_num_elements(Z_ARRVAL_P(intern_obj->zv_arr_options)) + 3; + argv = (char **) safe_emalloc(argc, sizeof(char *), 0); + /* "dummy" and "graph" arguments are needed */ + argv[0] = "dummy"; + argv[1] = estrdup("graph"); + argv[2] = estrdup(intern_obj->file_path); + + /* makes array of arguments for rrd_graph call from options array */ + zend_hash_internal_pointer_reset(Z_ARRVAL_P(intern_obj->zv_arr_options)); + for(i=3; izv_arr_options), &str_key, &num_key, 0) == HASH_KEY_IS_STRING) { + smart_str_appends(&option, str_key); + smart_str_appendc(&option, '='); + }; + + zend_hash_get_current_data(Z_ARRVAL_P(intern_obj->zv_arr_options), (void**) &item); + + if (Z_TYPE_PP(item) != IS_STRING) + convert_to_string(*item); + + smart_str_appendl(&option, Z_STRVAL_PP(item), Z_STRLEN_PP(item)); + smart_str_0(&option); + + argv[i] = estrdup(option.c); + + smart_str_free(&option); + + if (izv_arr_options)); + } + + /* call rrd graph and test if fails */ + if (rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) == -1) { + + for (i=1; ivalue.ht, "calcpr", sizeof("calcpr"), + (void *)&zv_calcpr_array, sizeof(zval *), NULL); + + for (i=1; i | + +----------------------------------------------------------------------+ +*/ + +#ifndef RRD_GRAPH_H +#define RRD_GRAPH_H + +void rrd_graph_minit(TSRMLS_DC); + +#endif /* RRD_GRAPH_H */ diff --git a/rrd_update.c b/rrd_update.c new file mode 100644 index 0000000..7035ee9 --- /dev/null +++ b/rrd_update.c @@ -0,0 +1,285 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2010 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: Miroslav Kubelik | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "php.h" +#include "php_rrd.h" +#include "rrd_update.h" +#include "ext/standard/php_smart_str.h" + +/* declare class entry */ +static zend_class_entry *ce_rrd_update; +/* declare class handlers */ +static zend_object_handlers rrd_update_handlers; + +/* overloading the standard zend object structure (std property) in the need +of having dedicated creating/cloning/destruction functions +*/ +typedef struct _rrd_update_object { + zend_object std; + + /** path to newly created rrd file */ + char *file_path; +} rrd_update_object; + +/* {{{ rrd_update_object_dtor +close all resources and the memory allocated for our internal object +*/ +static void rrd_update_object_dtor(void *object TSRMLS_DC) +{ + rrd_update_object *intern_obj = (rrd_update_object *)object; + + if (intern_obj->file_path) + efree(intern_obj->file_path); + + zend_object_std_dtor(&intern_obj->std TSRMLS_CC); + efree(intern_obj); +} +/* }}} */ + + +/* {{{ rrd_update_object_new +creates new rrd update object +*/ +static zend_object_value rrd_update_object_new(zend_class_entry *ce TSRMLS_DC) +{ + rrd_update_object *intern_obj; + zend_object_value retval; + zval *tmp; + + intern_obj = ecalloc(1, sizeof(*intern_obj)); + zend_object_std_init(&intern_obj->std, ce TSRMLS_CC); + + intern_obj->file_path = NULL; + + zend_hash_copy(intern_obj->std.properties, &ce->default_properties, + (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval*) + ); + + retval.handle = zend_objects_store_put(intern_obj, + (zend_objects_store_dtor_t)zend_objects_destroy_object, + rrd_update_object_dtor, NULL TSRMLS_CC + ); + + retval.handlers = &rrd_update_handlers; + + return retval; +} +/* }}} */ + + /* {{{ proto void RRDUpdater::__construct(string path) +creates new object for rrd update function + */ +PHP_METHOD(RRDUpdater, __construct) +{ + rrd_update_object *intern_obj; + char *path; + int path_length; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &path_length) == FAILURE) { + return; + } + + intern_obj = (rrd_update_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + intern_obj->file_path = estrdup(path); +} +/* }}} */ + +/* {{{ proto array RRDUpdater::update(array $values, [string time=time()]) + Updates data sources in RRD database + */ +PHP_METHOD(RRDUpdater, update) +{ + rrd_update_object *intern_obj; + zval *zv_values_array; + + zval *zv_update_argv; + rrd_args *update_argv; + + char *time = NULL; + int time_str_length = 0; + + int argc = ZEND_NUM_ARGS(); + uint ds_count,i; + /* string for all data source names formated for rrd_update call */ + smart_str ds_names = {0}; + /* string for all data source values for rrd_update call */ + smart_str ds_vals = {0}; + + if (zend_parse_parameters(argc TSRMLS_CC, "a|s", &zv_values_array, &time, + &time_str_length) == FAILURE) { + return; + } + + ds_count = zend_hash_num_elements(Z_ARRVAL_P(zv_values_array)); + if (ds_count<=0) { + RETURN_TRUE; + } + + intern_obj = (rrd_update_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (php_check_open_basedir(intern_obj->file_path TSRMLS_CC)) { + RETURN_FALSE; + } + + if (time_str_length == 0) { + if (argc > 1) { + zend_throw_exception(zend_exception_get_default(TSRMLS_C), + "time cannot be empty string", 0 TSRMLS_CC); + return; + } + + /* default time string, see rrdtool update man page, it's need to be + freed + */ + time = estrdup("N"); + } + + zend_hash_internal_pointer_reset(Z_ARRVAL_P(zv_values_array)); + for(i=0; ifile_path, zv_update_argv TSRMLS_CC); + if (!update_argv) { + zend_error(E_WARNING, "cannot allocate arguments options"); + zval_dtor(zv_update_argv); + if (time_str_length == 0) efree(time); + RETURN_FALSE; + } + + if (rrd_test_error()) rrd_clear_error(); + + /* call rrd_update and test if fails */ + if (rrd_update(update_argv->count - 1, &update_argv->args[1]) == -1) { + zval_dtor(zv_update_argv); + rrd_args_free(update_argv); + if (time_str_length == 0) efree(time); + + /* throw exception with rrd error string */ + zend_throw_exception(zend_exception_get_default(TSRMLS_C), rrd_get_error(), 0 TSRMLS_CC); + rrd_clear_error(); + return; + } + + /* parameter isn't presented and we alloced default one, so we neeed to + * freed + */ + if (time_str_length == 0) efree(time); + zval_dtor(zv_update_argv); + rrd_args_free(update_argv); + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int rrd_update(string file, array options) + Updates the RRD file with a particular options and values. +*/ +PHP_FUNCTION(rrd_update) +{ + char *filename; + int filename_length; + zval *zv_arr_options; + rrd_args *argv; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &filename, + &filename_length, &zv_arr_options) == FAILURE) { + return; + } + + if (php_check_open_basedir(filename TSRMLS_CC)) RETURN_FALSE; + + argv = rrd_args_init_by_phparray("update", filename, zv_arr_options TSRMLS_CC); + if (!argv) { + zend_error(E_WARNING, "cannot allocate arguments options"); + RETURN_FALSE; + } + + if (rrd_test_error()) rrd_clear_error(); + + if (rrd_update(argv->count - 1, &argv->args[1]) == -1 ) { + RETVAL_FALSE; + } else { + RETVAL_TRUE; + } + + rrd_args_free(argv); +} +/* }}} */ + +/* arguments */ +ZEND_BEGIN_ARG_INFO(arginfo_construct, 0) + ZEND_ARG_INFO(0, path) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_update, 0, 0, 1) + ZEND_ARG_INFO(0, values) + ZEND_ARG_INFO(0, time) +ZEND_END_ARG_INFO() + +/* class method table */ +static zend_function_entry rrd_update_methods[] = { + PHP_ME(RRDUpdater, __construct, arginfo_construct, ZEND_ACC_PUBLIC) + PHP_ME(RRDUpdater, update, arginfo_update, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +/* minit hook, called from main module minit */ +void rrd_update_minit(TSRMLS_DC) +{ + zend_class_entry ce; + INIT_CLASS_ENTRY(ce, "RRDUpdater", rrd_update_methods); + ce.create_object = rrd_update_object_new; + ce_rrd_update = zend_register_internal_class(&ce TSRMLS_CC); + + memcpy(&rrd_update_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + rrd_update_handlers.clone_obj = NULL; +} diff --git a/rrd_update.h b/rrd_update.h new file mode 100644 index 0000000..6b868f4 --- /dev/null +++ b/rrd_update.h @@ -0,0 +1,30 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2010 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: Miroslav Kubelik | + +----------------------------------------------------------------------+ +*/ + +#ifndef RRD_UPDATE_H +#define RRD_UPDATE_H + +void rrd_update_minit(TSRMLS_DC); +PHP_FUNCTION(rrd_update); + +ZEND_BEGIN_ARG_INFO(arginfo_rrd_update, 0) + ZEND_ARG_INFO(0, file) + ZEND_ARG_INFO(0, options) +ZEND_END_ARG_INFO() + +#endif /* RRD_UPDATE_H */ diff --git a/tests/rrd_001.phpt b/tests/rrd_001.phpt new file mode 100644 index 0000000..190dba1 --- /dev/null +++ b/tests/rrd_001.phpt @@ -0,0 +1,10 @@ +--TEST-- +rrd module presence test +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +rrd extension loaded diff --git a/tests/rrd_002.phpt b/tests/rrd_002.phpt new file mode 100644 index 0000000..5e3cdbf --- /dev/null +++ b/tests/rrd_002.phpt @@ -0,0 +1,62 @@ +--TEST-- +RRDGraph test +--SKIPIF-- + +--FILE-- +setOptions(array( + "--start" => "920804400", + "--end" => "920808000", + "--vertical-label" => "m/s", + "DEF:myspeed=$rrdFile:speed:AVERAGE", + "CDEF:realspeed=myspeed,1000,*", + "LINE2:realspeed#FF0000" +)); +var_dump($graphObj->save()); +?> +--EXPECTF-- +creting test.rrd via exec +updating test.rrd via exec +exporting speed-orig.png via exec +array(3) { + ["xsize"]=> + int(497) + ["ysize"]=> + int(149) + ["calcpr"]=> + NULL +} diff --git a/tests/rrd_003.phpt b/tests/rrd_003.phpt new file mode 100644 index 0000000..91a16f4 --- /dev/null +++ b/tests/rrd_003.phpt @@ -0,0 +1,23 @@ +--TEST-- +RRDCreator test +--SKIPIF-- + +--FILE-- +addDataSource("speed:COUNTER:600:U:U"); +$creator->addArchive("AVERAGE:0.5:1:24"); +$creator->addArchive("AVERAGE:0.5:6:10"); +$creator->save(); +?> +--EXPECTF-- +creating original rrd for RRDCreator via exec diff --git a/tests/rrd_004.phpt b/tests/rrd_004.phpt new file mode 100644 index 0000000..4139163 --- /dev/null +++ b/tests/rrd_004.phpt @@ -0,0 +1,55 @@ +--TEST-- +RRDUpdater test +--SKIPIF-- + +--FILE-- +update(array("speed" => "12345"), "920804700"); +$updator->update(array("speed" => "12357"), "920805000"); +$updator->update(array("speed" => "12363"), "920805300"); +$updator->update(array("speed" => "12363"), "920805600"); +$updator->update(array("speed" => "12363"), "920805900"); +$updator->update(array("speed" => "12373"), "920806200"); +$updator->update(array("speed" => "12383"), "920806500"); +$updator->update(array("speed" => "12393"), "920806800"); +$updator->update(array("speed" => "12399"), "920807100"); +$updator->update(array("speed" => "12405"), "920807400"); +$updator->update(array("speed" => "12411"), "920807700"); +$updator->update(array("speed" => "12415"), "920808000"); +$updator->update(array("speed" => "12420"), "920808300"); +$updator->update(array("speed" => "12422"), "920808600"); +$updator->update(array("speed" => "12423"), "920808900"); + +$command = "rrdtool graph ".dirname(__FILE__)."/updateTest.png " + . "--start 920804400 --end 920808000 " + . "--vertical-label m/s " + . "DEF:myspeed=$rrdFile:speed:AVERAGE " + . "CDEF:realspeed=myspeed,1000,* " + . "LINE2:realspeed#FF0000"; + +echo "exporting updateTest.png via exec\n"; +exec($command); + +$command = "rrdtool fetch $rrdFile AVERAGE --start 920804400 --end 920809200"; +$output = array(); +exec($command, $output); +$originalFetch = file(dirname(__FILE__)."/testData/updateFetch.txt", FILE_IGNORE_NEW_LINES); +echo "comparing original and current fetch\n"; +var_dump(array_diff($output, $originalFetch)); +?> +--EXPECTF-- +creating rrdfile for update test via exec +exporting updateTest.png via exec +comparing original and current fetch +array(0) { +} \ No newline at end of file diff --git a/tests/rrd_005.phpt b/tests/rrd_005.phpt new file mode 100644 index 0000000..4351ea8 --- /dev/null +++ b/tests/rrd_005.phpt @@ -0,0 +1,41 @@ +--TEST-- +RRDUpdater default timestamp test +--SKIPIF-- + +--FILE-- +update(array("speed" => "12345")); +sleep(1); +$updator->update(array("speed" => "12357")); +sleep(1); +$updator->update(array("speed" => "12363")); +sleep(1); +$updator->update(array("speed" => "12363")); +sleep(1); +$updator->update(array("speed" => "12363")); +sleep(1); + +$command = "rrdtool graph ".dirname(__FILE__)."/updateTestDefaultVal.png " + . "--start -5s --end now " + . "--vertical-label m/s " + . "DEF:myspeed=$rrdFile:speed:AVERAGE " + . "CDEF:realspeed=myspeed,1000,* " + . "LINE2:realspeed#FF0000"; + +echo "exporting updateTestDefaultVal.png via exec\n"; +exec($command); +?> +--EXPECTF-- +creating rrdfile for update test via exec +exporting updateTestDefaultVal.png via exec diff --git a/tests/rrd_006.phpt b/tests/rrd_006.phpt new file mode 100644 index 0000000..d1ad4f0 --- /dev/null +++ b/tests/rrd_006.phpt @@ -0,0 +1,49 @@ +--TEST-- +rrd_update test +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +creating rrdfile for update test via exec +exporting rrd_update_1.png via exec +bool(true) diff --git a/tests/rrd_007.phpt b/tests/rrd_007.phpt new file mode 100644 index 0000000..7efb0c9 --- /dev/null +++ b/tests/rrd_007.phpt @@ -0,0 +1,24 @@ +--TEST-- +rrd_create test +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +creating original rrd for rrd_create test via exec +bool(true) diff --git a/tests/skipif.inc b/tests/skipif.inc new file mode 100644 index 0000000..a29a968 --- /dev/null +++ b/tests/skipif.inc @@ -0,0 +1,5 @@ + diff --git a/tests/testData/speed.png b/tests/testData/speed.png new file mode 100644 index 0000000..719757b Binary files /dev/null and b/tests/testData/speed.png differ diff --git a/tests/testData/updateFetch.txt b/tests/testData/updateFetch.txt new file mode 100644 index 0000000..4d0b360 --- /dev/null +++ b/tests/testData/updateFetch.txt @@ -0,0 +1,19 @@ + speed + + 920804700: nan + 920805000: 4.0000000000e-02 + 920805300: 2.0000000000e-02 + 920805600: 0.0000000000e+00 + 920805900: 0.0000000000e+00 + 920806200: 3.3333333333e-02 + 920806500: 3.3333333333e-02 + 920806800: 3.3333333333e-02 + 920807100: 2.0000000000e-02 + 920807400: 2.0000000000e-02 + 920807700: 2.0000000000e-02 + 920808000: 1.3333333333e-02 + 920808300: 1.6666666667e-02 + 920808600: 6.6666666667e-03 + 920808900: 3.3333333333e-03 + 920809200: nan + 920809500: nan