├── tests ├── skipif.inc ├── rrdtool-bin.inc.in ├── rrd_001.phpt ├── rrd_022.phpt ├── rrd_020.phpt ├── rrd_009.phpt ├── rrd_013.phpt ├── rrd_007.phpt ├── rrd_003.phpt ├── data │ ├── definition.inc │ └── Makefile.in ├── rrd_011.phpt ├── rrd_016.phpt ├── rrd_015.phpt ├── rrd_002.phpt ├── rrd_014.phpt ├── rrd_018.phpt ├── rrd_008.phpt ├── rrd_005.phpt ├── rrd_021.phpt ├── rrd_006.phpt ├── rrd_019.phpt ├── rrd_012.phpt ├── rrd_010.phpt ├── rrd_004.phpt └── rrd_017.phpt ├── CREDITS ├── README.md ├── .gitignore ├── rrd_create.h ├── rrd_update.h ├── rrd_graph.h ├── rrd_info.h ├── config.w32 ├── php_rrd.h ├── LICENSE ├── config.m4 ├── rrd_info.c ├── rrd_update.c ├── rrd_create.c ├── package.xml ├── rrd_graph.c └── rrd.c /tests/skipif.inc: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /tests/rrdtool-bin.inc.in: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /tests/rrd_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd module presence test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 9 | --EXPECTF-- 10 | rrd extension loaded 11 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | RRD 2 | Miroslav Kubelik (koubel@php.net) 3 | Big Thanks: 4 | Joe Miller - author of first rrdtool extension 5 | Jeffrey Wheat, Dan Cech, Benny Baumann - patches and improvements 6 | Remi Collet - for relentless bug fixing and support 7 | -------------------------------------------------------------------------------- /tests/rrd_022.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrdc_disconnect test 3 | --SKIPIF-- 4 | = 1.4"); 8 | } 9 | 10 | ?> 11 | --FILE-- 12 | 15 | --EXPECTF-- 16 | NULL 17 | -------------------------------------------------------------------------------- /tests/rrd_020.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_version test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | = 2); 10 | ?> 11 | --EXPECTF-- 12 | string(%i) "%s" 13 | bool(true) 14 | bool(true) 15 | -------------------------------------------------------------------------------- /tests/rrd_009.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_error test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 11 | --EXPECTF-- 12 | string(31) "can't parse argument 'badParam'" 13 | bool(false) -------------------------------------------------------------------------------- /tests/rrd_013.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_last test 3 | --SKIPIF-- 4 | 11 | --FILE-- 12 | 16 | --EXPECTF-- 17 | int(920808900) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PECL/rrd - native bindings for RRD tool system 2 | 3 | This is the native PHP bindings for RRD tool system. Uses native librrd C API. 4 | 5 | * PHP PECL extension info - https://pecl.php.net/package/rrd 6 | * PHP usage documentation - https://www.php.net/rrd 7 | * rrd tool - https://oss.oetiker.ch/rrdtool/ 8 | * librrd C API - https://oss.oetiker.ch/rrdtool/doc/librrd.en.html 9 | 10 | -------------------------------------------------------------------------------- /tests/rrd_007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_create test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 16 | --EXPECTF-- 17 | bool(true) 18 | -------------------------------------------------------------------------------- /tests/rrd_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | RRDCreator test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | addDataSource("speed:COUNTER:600:U:U"); 10 | $creator->addArchive("AVERAGE:0.5:1:24"); 11 | $creator->addArchive("AVERAGE:0.5:6:10"); 12 | $creator->save(); 13 | var_dump(file_exists($rrdFile)); 14 | ?> 15 | --EXPECTF-- 16 | bool(true) 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.lo 2 | *.la 3 | Makefile 4 | .deps 5 | .libs 6 | Makefile.fragments 7 | Makefile.global 8 | Makefile.objects 9 | acinclude.m4 10 | aclocal.m4 11 | autom4te.cache 12 | build 13 | config.guess 14 | config.h 15 | config.h.in 16 | config.log 17 | config.nice 18 | config.status 19 | config.sub 20 | configure 21 | configure.in 22 | include 23 | install-sh 24 | libtool 25 | ltmain.sh 26 | missing 27 | mkinstalldirs 28 | modules 29 | run-tests.php 30 | tmp-php.ini 31 | tests/rrdtool-bin.inc 32 | -------------------------------------------------------------------------------- /tests/data/definition.inc: -------------------------------------------------------------------------------- 1 | 8 | * --------------------------------------------------------------- 9 | */ 10 | 11 | #ifndef RRD_CREATE_H 12 | #define RRD_CREATE_H 13 | 14 | void rrd_create_minit(); 15 | PHP_FUNCTION(rrd_create); 16 | 17 | #endif /* RRD_CREATE_H */ 18 | -------------------------------------------------------------------------------- /rrd_update.h: -------------------------------------------------------------------------------- 1 | /** 2 | * PHP bindings to the rrdtool 3 | * 4 | * This source file is subject to the BSD license that is bundled 5 | * with this package in the file LICENSE. 6 | * --------------------------------------------------------------- 7 | * Author: Miroslav Kubelik 8 | * --------------------------------------------------------------- 9 | */ 10 | 11 | #ifndef RRD_UPDATE_H 12 | #define RRD_UPDATE_H 13 | 14 | void rrd_update_minit(); 15 | PHP_FUNCTION(rrd_update); 16 | 17 | #endif /* RRD_UPDATE_H */ 18 | -------------------------------------------------------------------------------- /rrd_graph.h: -------------------------------------------------------------------------------- 1 | /** 2 | * PHP bindings to the rrdtool 3 | * 4 | * This source file is subject to the BSD license that is bundled 5 | * with this package in the file LICENSE. 6 | * --------------------------------------------------------------- 7 | * Author: Miroslav Kubelik 8 | * --------------------------------------------------------------- 9 | */ 10 | 11 | #ifndef RRD_GRAPH_H 12 | #define RRD_GRAPH_H 13 | 14 | extern void rrd_graph_minit(); 15 | extern PHP_FUNCTION(rrd_graph); 16 | 17 | #endif /* RRD_GRAPH_H */ 18 | -------------------------------------------------------------------------------- /tests/rrd_011.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_first test 3 | --SKIPIF-- 4 | 11 | --FILE-- 12 | 19 | --EXPECTF-- 20 | int(920802000) 21 | int(920791800) 22 | bool(false) 23 | bool(false) 24 | -------------------------------------------------------------------------------- /tests/rrd_016.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_tune test 3 | --SKIPIF-- 4 | 11 | --FILE-- 12 | 21 | --EXPECTF-- 22 | bool(true) 23 | bool(false) 24 | bool(true) 25 | %s -------------------------------------------------------------------------------- /rrd_info.h: -------------------------------------------------------------------------------- 1 | /** 2 | * PHP bindings to the rrdtool 3 | * 4 | * This source file is subject to the BSD license that is bundled 5 | * with this package in the file LICENSE. 6 | * --------------------------------------------------------------- 7 | * Author: Miroslav Kubelik 8 | * --------------------------------------------------------------- 9 | */ 10 | 11 | #ifndef RRD_INFO_H 12 | #define RRD_INFO_H 13 | 14 | extern PHP_FUNCTION(rrd_info); 15 | 16 | /* necessary, because rrd_info_t definition is needed for function definition */ 17 | #include 18 | extern unsigned rrd_info_toarray(const rrd_info_t *rrd_info_data, zval *array); 19 | 20 | #endif /* RRD_INFO_H */ 21 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // vim: ft=javascript: 2 | 3 | ARG_WITH("rrd", "whether to enable RRD support", "no"); 4 | 5 | if ("no" != PHP_RRD) { 6 | if (CHECK_LIB("rrdlib.lib;librrd*.lib", "rrd", PHP_RRD) && 7 | CHECK_HEADER_ADD_INCLUDE("rrd.h", "CFLAGS_RRD")) { 8 | 9 | /* This leads to mode_t redefinition, but actually it's strange as it 10 | seems to be dedicated to perl. */ 11 | ADD_FLAG("CFLAGS_RRD", "/D PERLPATCHLEVEL=0"); 12 | 13 | ADD_FLAG("CFLAGS_RRD", "/D HAVE_RRD_LASTUPDATE_R=1"); 14 | 15 | EXTENSION("rrd", "rrd.c rrd_graph.c rrd_create.c rrd_update.c rrd_info.c"); 16 | 17 | AC_DEFINE('HAVE_RRD', 1, 'Have RRD library'); 18 | } else { 19 | WARNING("rrd not enabled, libs or headers not found"); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /tests/rrd_015.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_restore test 3 | --SKIPIF-- 4 | 10 | --FILE-- 11 | 23 | --EXPECTF-- 24 | bool(true) 25 | bool(true) 26 | bool(true) 27 | 28 | -------------------------------------------------------------------------------- /tests/rrd_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | RRDGraph test 3 | --SKIPIF-- 4 | 11 | --FILE-- 12 | setOptions(array( 17 | "--start" => "920804400", 18 | "--end" => 920808000, 19 | "--vertical-label" => "m/s", 20 | "DEF:myspeed=$data_updatedDb:speed:AVERAGE", 21 | "CDEF:realspeed=myspeed,1000,*", 22 | "LINE2:realspeed#FF0000" 23 | )); 24 | var_dump($graphObj->save()); 25 | var_dump(file_exists($outputPngFile)); 26 | ?> 27 | --EXPECTF-- 28 | array(3) { 29 | ["xsize"]=> 30 | int(497) 31 | ["ysize"]=> 32 | int(%d) 33 | ["calcpr"]=> 34 | NULL 35 | } 36 | bool(true) 37 | -------------------------------------------------------------------------------- /php_rrd.h: -------------------------------------------------------------------------------- 1 | /** 2 | * PHP bindings to the rrdtool 3 | * 4 | * This source file is subject to the BSD license that is bundled 5 | * with this package in the file LICENSE. 6 | * --------------------------------------------------------------- 7 | * Author: Miroslav Kubelik 8 | * --------------------------------------------------------------- 9 | */ 10 | 11 | #ifndef PHP_RRD_H 12 | #define PHP_RRD_H 13 | 14 | extern zend_module_entry rrd_module_entry; 15 | #define phpext_rrd_ptr &rrd_module_entry 16 | 17 | #define PHP_RRD_VERSION "2.0.3" 18 | 19 | #ifdef ZTS 20 | #include "TSRM.h" 21 | #endif 22 | 23 | #ifndef zend_parse_parameters_none 24 | # define zend_parse_parameters_none() zend_parse_parameters(ZEND_NUM_ARGS(), "") 25 | #endif 26 | 27 | typedef struct _rrd_args { 28 | int count; 29 | char **args; 30 | } rrd_args; 31 | 32 | extern rrd_args *rrd_args_init_by_phparray(const char *command_name, const char *filename, 33 | const zval *options); 34 | extern void rrd_args_free(rrd_args *args); 35 | 36 | #endif /* PHP_RRD_H */ 37 | -------------------------------------------------------------------------------- /tests/rrd_014.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_lastupdate test 3 | --SKIPIF-- 4 | 13 | --FILE-- 14 | 19 | --EXPECTF-- 20 | array(4) { 21 | ["last_update"]=> 22 | int(920808900) 23 | ["ds_cnt"]=> 24 | int(1) 25 | ["ds_navm"]=> 26 | array(1) { 27 | [0]=> 28 | string(5) "speed" 29 | } 30 | ["data"]=> 31 | array(1) { 32 | [0]=> 33 | string(5) "12423" 34 | } 35 | } 36 | array(4) { 37 | ["last_update"]=> 38 | int(920808900) 39 | ["ds_cnt"]=> 40 | int(2) 41 | ["ds_navm"]=> 42 | array(2) { 43 | [0]=> 44 | string(6) "speed1" 45 | [1]=> 46 | string(6) "speed2" 47 | } 48 | ["data"]=> 49 | array(2) { 50 | [0]=> 51 | string(5) "12423" 52 | [1]=> 53 | string(5) "11423" 54 | } 55 | } -------------------------------------------------------------------------------- /tests/rrd_018.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | RRDGraph saveVerbose test 3 | --SKIPIF-- 4 | 11 | --FILE-- 12 | setOptions(array( 18 | "--start" => "920804400", 19 | "--end" => 920808000, 20 | "--vertical-label" => "m/s", 21 | "DEF:myspeed=$rrdFile:speed:AVERAGE", 22 | "CDEF:realspeed=myspeed,1000,*", 23 | "LINE2:realspeed#FF0000" 24 | )); 25 | var_dump($graphObj->saveVerbose()); 26 | ?> 27 | --EXPECTF-- 28 | array(10) { 29 | ["graph_left"]=> 30 | int(67) 31 | ["graph_top"]=> 32 | int(%d) 33 | ["graph_width"]=> 34 | int(400) 35 | ["graph_height"]=> 36 | int(100) 37 | ["image_width"]=> 38 | int(497) 39 | ["image_height"]=> 40 | int(%d) 41 | ["graph_start"]=> 42 | int(920804400) 43 | ["graph_end"]=> 44 | int(920808000) 45 | ["value_min"]=> 46 | float(0) 47 | ["value_max"]=> 48 | float(40) 49 | } 50 | -------------------------------------------------------------------------------- /tests/rrd_008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_graph test 3 | --SKIPIF-- 4 | 12 | --FILE-- 13 | 37 | --EXPECTF-- 38 | exporting image via exec 39 | array(3) { 40 | ["xsize"]=> 41 | int(497) 42 | ["ysize"]=> 43 | int(%d) 44 | ["calcpr"]=> 45 | NULL 46 | } 47 | -------------------------------------------------------------------------------- /tests/rrd_005.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | RRDUpdater default timestamp test 3 | --SKIPIF-- 4 | 12 | --FILE-- 13 | update(array("speed" => "12345")); 21 | sleep(1); 22 | $updator->update(array("speed" => "12357")); 23 | sleep(1); 24 | $updator->update(array("speed" => "12363")); 25 | sleep(1); 26 | $updator->update(array("speed" => "12363")); 27 | sleep(1); 28 | $updator->update(array("speed" => "12363")); 29 | sleep(1); 30 | 31 | //mostly for "visual test" 32 | $command = "$rrdtool_bin graph " 33 | . dirname(__FILE__) . "/rrd_updater_default_val.png " 34 | . "--start -5s --end now " 35 | . "--vertical-label m/s " 36 | . "DEF:myspeed=$rrdFile:speed:AVERAGE " 37 | . "CDEF:realspeed=myspeed,1000,* " 38 | . "LINE2:realspeed#FF0000"; 39 | 40 | echo "exporting graph via exec\n"; 41 | exec($command); 42 | ?> 43 | --EXPECTF-- 44 | exporting %s via exec 45 | -------------------------------------------------------------------------------- /tests/rrd_021.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | RRDUpdater more data source test 3 | --SKIPIF-- 4 | 14 | --FILE-- 15 | update(array("speed1" => 12345, "speed2" => 11340), 920804700); 23 | $updator->update(array("speed1" => 12357, "speed2" => 11357), 920805000); 24 | $updator->update(array("speed1" => 12363, "speed2" => 11363), 920805300); 25 | 26 | //mostly for "visual test" 27 | $command = "$rrdtool_bin fetch $rrdFile AVERAGE " 28 | . "--start 920804400 --end 920808000 " 29 | . ">" . dirname(__FILE__) . "/rrd_updater_moreDS_fetch.txt"; 30 | $output = array(); 31 | exec($command, $output); 32 | $originalFetch = file($data_moreDSUpdaterTxt, FILE_IGNORE_NEW_LINES); 33 | echo "comparing original and current fetch\n"; 34 | var_dump(array_diff($output, $originalFetch)); 35 | ?> 36 | --EXPECTF-- 37 | comparing original and current fetch 38 | array(0) { 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/rrd_006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_update test 3 | --SKIPIF-- 4 | 12 | --FILE-- 13 | 49 | --EXPECTF-- 50 | exporting rrd_update_1.png via exec 51 | bool(true) 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 - 2015, Miroslav Kubelík 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /tests/rrd_019.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | RRDGraph saveVerbose full export test 3 | --SKIPIF-- 4 | 11 | --FILE-- 12 | setOptions(array( 18 | "--start" => "920804400", 19 | "--end" => 920808000, 20 | "--vertical-label" => "m/s", 21 | "DEF:myspeed=$rrdFile:speed:AVERAGE", 22 | "CDEF:realspeed=myspeed,1000,*", 23 | "LINE2:realspeed#FF0000" 24 | )); 25 | $output = $graphObj->saveVerbose(); 26 | $imgData = $output["image"]; unset($output["image"]); 27 | //output without img data 28 | var_dump($output); 29 | //detection of correct PNG header 30 | var_dump(substr($imgData, 0, 8) == "\x89PNG\x0d\x0a\x1a\x0a"); 31 | ?> 32 | --EXPECTF-- 33 | array(10) { 34 | ["graph_left"]=> 35 | int(67) 36 | ["graph_top"]=> 37 | int(%d) 38 | ["graph_width"]=> 39 | int(400) 40 | ["graph_height"]=> 41 | int(100) 42 | ["image_width"]=> 43 | int(497) 44 | ["image_height"]=> 45 | int(%d) 46 | ["graph_start"]=> 47 | int(920804400) 48 | ["graph_end"]=> 49 | int(920808000) 50 | ["value_min"]=> 51 | float(0) 52 | ["value_max"]=> 53 | float(40) 54 | } 55 | bool(true) 56 | -------------------------------------------------------------------------------- /tests/rrd_012.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_info test 3 | --SKIPIF-- 4 | 11 | --FILE-- 12 | 19 | --EXPECTF-- 20 | array(27) { 21 | ["filename"]=> 22 | string(%d) %s 23 | ["rrd_version"]=> 24 | string(4) %s 25 | ["step"]=> 26 | int(300) 27 | ["last_update"]=> 28 | int(920808900) 29 | ["header_size"]=> 30 | int(%d) 31 | ["ds[speed].index"]=> 32 | int(0) 33 | ["ds[speed].type"]=> 34 | string(7) "COUNTER" 35 | ["ds[speed].minimal_heartbeat"]=> 36 | int(600) 37 | ["ds[speed].min"]=> 38 | float(NAN) 39 | ["ds[speed].max"]=> 40 | float(NAN) 41 | ["ds[speed].last_ds"]=> 42 | string(5) "12423" 43 | ["ds[speed].value"]=> 44 | float(0) 45 | ["ds[speed].unknown_sec"]=> 46 | int(0) 47 | ["rra[0].cf"]=> 48 | string(7) "AVERAGE" 49 | ["rra[0].rows"]=> 50 | int(24) 51 | ["rra[0].cur_row"]=> 52 | int(%d) 53 | ["rra[0].pdp_per_row"]=> 54 | int(1) 55 | ["rra[0].xff"]=> 56 | float(0.5) 57 | ["rra[0].cdp_prep[0].value"]=> 58 | float(NAN) 59 | ["rra[0].cdp_prep[0].unknown_datapoints"]=> 60 | int(0) 61 | ["rra[1].cf"]=> 62 | string(7) "AVERAGE" 63 | ["rra[1].rows"]=> 64 | int(10) 65 | ["rra[1].cur_row"]=> 66 | int(%d) 67 | ["rra[1].pdp_per_row"]=> 68 | int(6) 69 | ["rra[1].xff"]=> 70 | float(0.5) 71 | ["rra[1].cdp_prep[0].value"]=> 72 | float(0.02666666666%s) 73 | ["rra[1].cdp_prep[0].unknown_datapoints"]=> 74 | int(0) 75 | } 76 | bool(true) 77 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl config.m4 for extension php_rrd 2 | dnl Comments in this file start with the string 'dnl'. 3 | 4 | PHP_ARG_WITH(rrd, for rrdtool support, 5 | [ --with-rrd Include rrdtool support (requires rrdtool >= 1.3.0)], yes) 6 | 7 | AC_ARG_WITH(rrd-binary, 8 | [AC_HELP_STRING([--with-rrd-binary][=PATH], [rrd binary dir path, mostly for testing (default=$PATH)])], 9 | [AC_PATH_PROG(RRDTOOL_BIN, rrdtool, no, $withval)], 10 | [AC_PATH_PROG(RRDTOOL_BIN, rrdtool, no, $PATH)]) 11 | 12 | AC_SUBST(RRDTOOL_BIN) 13 | if test -f $srcdir/tests/rrdtool-bin.inc.in; then 14 | AC_OUTPUT(tests/rrdtool-bin.inc) 15 | AC_OUTPUT(tests/data/Makefile) 16 | fi 17 | 18 | if test "$PHP_RRD" != "no"; then 19 | AC_PATH_PROG(PKG_CONFIG, pkg-config, no) 20 | AC_MSG_CHECKING(for librdd) 21 | if test -x "$PKG_CONFIG" && $PKG_CONFIG --exists librrd && $PKG_CONFIG librrd --atleast-version 1.3.0; then 22 | AC_MSG_RESULT(found) 23 | LIBRRD_CFLAGS=`$PKG_CONFIG librrd --cflags` 24 | LIBRRD_LDFLAGS=`$PKG_CONFIG librrd --libs` 25 | 26 | PHP_EVAL_LIBLINE($LIBRRD_LDFLAGS, RRD_SHARED_LIBADD) 27 | PHP_EVAL_INCLINE($LIBRRD_CFLAGS) 28 | AC_DEFINE(HAVE_RRDTOOL, 1, [ ]) 29 | else 30 | AC_MSG_ERROR(pkgconfig and librrd in version >= 1.3.0 must be installed) 31 | fi 32 | 33 | dnl rrd_lastupdate_r available in 1.4.0+ 34 | AC_CHECK_LIB([rrd], [rrd_lastupdate_r], 35 | [ 36 | AC_DEFINE(HAVE_RRD_LASTUPDATE_R, 1, [ ]) 37 | ], , [$LIBRRD_LDFLAGS]) 38 | 39 | 40 | dnl rrdc_disconnect available in 1.4.0+ 41 | AC_CHECK_LIB([rrd], [rrdc_disconnect], 42 | [ 43 | AC_DEFINE(HAVE_RRDC_DISCONNECT, 1, [ ]) 44 | ], , [$LIBRRD_LDFLAGS]) 45 | 46 | PHP_NEW_EXTENSION(rrd, rrd.c rrd_graph.c rrd_create.c rrd_update.c rrd_info.c, $ext_shared) 47 | PHP_SUBST(RRD_SHARED_LIBADD) 48 | fi 49 | -------------------------------------------------------------------------------- /tests/rrd_010.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_fetch test 3 | --SKIPIF-- 4 | 11 | --FILE-- 12 | 20 | --EXPECTF-- 21 | array(4) { 22 | ["start"]=> 23 | int(920804400) 24 | ["end"]=> 25 | int(920808300) 26 | ["step"]=> 27 | int(300) 28 | ["data"]=> 29 | array(2) { 30 | ["speed1"]=> 31 | array(13) { 32 | [920804700]=> 33 | float(NAN) 34 | [920805000]=> 35 | float(0.04) 36 | [920805300]=> 37 | float(0.02) 38 | [920805600]=> 39 | float(0) 40 | [920805900]=> 41 | float(0) 42 | [920806200]=> 43 | float(0.03333333333%s) 44 | [920806500]=> 45 | float(0.03333333333%s) 46 | [920806800]=> 47 | float(0.03333333333%s) 48 | [920807100]=> 49 | float(0.02) 50 | [920807400]=> 51 | float(0.02) 52 | [920807700]=> 53 | float(0.02) 54 | [920808000]=> 55 | float(0.01333333333%s) 56 | [920808300]=> 57 | float(0.01666666666%s) 58 | } 59 | ["speed2"]=> 60 | array(13) { 61 | [920804700]=> 62 | float(NAN) 63 | [920805000]=> 64 | float(0.05666666666%s) 65 | [920805300]=> 66 | float(0.02) 67 | [920805600]=> 68 | float(0.00333333333%s) 69 | [920805900]=> 70 | float(0) 71 | [920806200]=> 72 | float(0.03) 73 | [920806500]=> 74 | float(0) 75 | [920806800]=> 76 | float(0.06666666666%s) 77 | [920807100]=> 78 | float(0.02) 79 | [920807400]=> 80 | float(0.02) 81 | [920807700]=> 82 | float(0.02) 83 | [920808000]=> 84 | float(0.01333333333%s) 85 | [920808300]=> 86 | float(0.01666666666%s) 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tests/rrd_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | RRDUpdater test 3 | --SKIPIF-- 4 | 14 | --FILE-- 15 | update(array("speed" => "12345"), "920804700"); 23 | $updator->update(array("speed" => "12357"), "920805000"); 24 | $updator->update(array("speed" => "12363"), "920805300"); 25 | $updator->update(array("speed" => "12363"), "920805600"); 26 | $updator->update(array("speed" => "12363"), "920805900"); 27 | $updator->update(array("speed" => "12373"), "920806200"); 28 | $updator->update(array("speed" => "12383"), "920806500"); 29 | $updator->update(array("speed" => "12393"), "920806800"); 30 | $updator->update(array("speed" => "12399"), "920807100"); 31 | $updator->update(array("speed" => "12405"), "920807400"); 32 | $updator->update(array("speed" => "12411"), "920807700"); 33 | $updator->update(array("speed" => "12415"), "920808000"); 34 | $updator->update(array("speed" => "12420"), "920808300"); 35 | $updator->update(array("speed" => "12422"), "920808600"); 36 | $updator->update(array("speed" => "12423"), "920808900"); 37 | 38 | //graph just for "visual test" if test fails 39 | $command = "$rrdtool_bin graph " 40 | . dirname(__FILE__) . "/rrd_updater_test.png " 41 | . "--start 920804400 --end 920808000 " 42 | . "--vertical-label m/s " 43 | . "DEF:myspeed=$rrdFile:speed:AVERAGE " 44 | . "CDEF:realspeed=myspeed,1000,* " 45 | . "LINE2:realspeed#FF0000"; 46 | 47 | echo "exporting rrd_updater_test.png via exec\n"; 48 | exec($command); 49 | 50 | $command = "$rrdtool_bin fetch $rrdFile AVERAGE --start 920804400 --end 920809200"; 51 | exec($command, $output); 52 | // maybe bug in exec output catching 53 | if ($output[1] === "\n") { 54 | $output[1] = ""; 55 | } 56 | $originalFetch = file($data_updaterTxt, FILE_IGNORE_NEW_LINES); 57 | echo "comparing original and current fetch\n"; 58 | var_dump(array_diff($output, $originalFetch)); 59 | ?> 60 | --EXPECTF-- 61 | exporting rrd_updater_test.png via exec 62 | comparing original and current fetch 63 | array(0) { 64 | } 65 | -------------------------------------------------------------------------------- /tests/rrd_017.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rrd_xport test 3 | --SKIPIF-- 4 | 11 | --FILE-- 12 | 23 | --EXPECTF-- 24 | array(4) { 25 | ["start"]=> 26 | int(920804700) 27 | ["end"]=> 28 | int(920808300) 29 | ["step"]=> 30 | int(300) 31 | ["data"]=> 32 | array(2) { 33 | [0]=> 34 | array(2) { 35 | ["legend"]=> 36 | string(7) "myspeed" 37 | ["data"]=> 38 | array(13) { 39 | [920804700]=> 40 | float(NAN) 41 | [920805000]=> 42 | float(0.04) 43 | [920805300]=> 44 | float(0.02) 45 | [920805600]=> 46 | float(0) 47 | [920805900]=> 48 | float(0) 49 | [920806200]=> 50 | float(0.0333333333%s) 51 | [920806500]=> 52 | float(0.0333333333%s) 53 | [920806800]=> 54 | float(0.0333333333%s) 55 | [920807100]=> 56 | float(0.02) 57 | [920807400]=> 58 | float(0.02) 59 | [920807700]=> 60 | float(0.02) 61 | [920808000]=> 62 | float(0.0133333333%s) 63 | [920808300]=> 64 | float(0.0166666666%s) 65 | } 66 | } 67 | [1]=> 68 | array(2) { 69 | ["legend"]=> 70 | string(9) "realspeed" 71 | ["data"]=> 72 | array(13) { 73 | [920804700]=> 74 | float(NAN) 75 | [920805000]=> 76 | float(40) 77 | [920805300]=> 78 | float(20) 79 | [920805600]=> 80 | float(0) 81 | [920805900]=> 82 | float(0) 83 | [920806200]=> 84 | float(33.333333333%s) 85 | [920806500]=> 86 | float(33.333333333%s) 87 | [920806800]=> 88 | float(33.333333333%s) 89 | [920807100]=> 90 | float(20) 91 | [920807400]=> 92 | float(20) 93 | [920807700]=> 94 | float(20) 95 | [920808000]=> 96 | float(13.333333333%s) 97 | [920808300]=> 98 | float(16.666666666%s) 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /rrd_info.c: -------------------------------------------------------------------------------- 1 | /** 2 | * PHP bindings to the rrdtool 3 | * 4 | * This source file is subject to the BSD license that is bundled 5 | * with this package in the file LICENSE. 6 | * --------------------------------------------------------------- 7 | * Author: Miroslav Kubelik 8 | * --------------------------------------------------------------- 9 | */ 10 | 11 | #ifdef HAVE_CONFIG_H 12 | #include "config.h" 13 | #endif 14 | 15 | #include "php.h" 16 | 17 | #include 18 | 19 | #include "php_rrd.h" 20 | #include "rrd_info.h" 21 | 22 | /* {{{ proto array rrd_info(string file) 23 | Gets the header information from an RRD. 24 | */ 25 | PHP_FUNCTION(rrd_info) 26 | { 27 | char *filename; 28 | size_t filename_length; 29 | /* list of arguments for rrd_info call, it's more efficient then u 30 | * usage of rrd_args, because there isn't array of arguments in parameters 31 | */ 32 | char *argv[3]; 33 | /* return value from rrd_info_r() */ 34 | rrd_info_t *rrd_info_data; 35 | 36 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &filename, 37 | &filename_length) == FAILURE) { 38 | return; 39 | } 40 | 41 | if (php_check_open_basedir(filename)) RETURN_FALSE; 42 | 43 | argv[0] = "dummy"; 44 | argv[1] = estrdup("info"); 45 | argv[2] = estrndup(filename, filename_length); 46 | 47 | rrd_info_data = rrd_info(2, &argv[1]); 48 | 49 | efree(argv[2]); efree(argv[1]); 50 | 51 | if (!rrd_info_data) RETURN_FALSE; 52 | 53 | /* making return array*/ 54 | array_init(return_value); 55 | rrd_info_toarray(rrd_info_data, return_value); 56 | rrd_info_free(rrd_info_data); 57 | } 58 | /* }}} */ 59 | 60 | /* {{{ converts rrd_info_t struct into php array 61 | @return int 1 OK, 0 conversion failed 62 | */ 63 | unsigned rrd_info_toarray(const rrd_info_t *rrd_info_data, zval *array) 64 | { 65 | const rrd_info_t *data_p; 66 | 67 | if (!rrd_info_data || Z_TYPE_P(array) != IS_ARRAY) return 0; 68 | 69 | data_p = rrd_info_data; 70 | while (data_p) { 71 | switch (data_p->type) { 72 | case RD_I_VAL: 73 | add_assoc_double(array, data_p->key, data_p->value.u_val); 74 | break; 75 | case RD_I_CNT: 76 | add_assoc_long(array, data_p->key, data_p->value.u_cnt); 77 | break; 78 | case RD_I_INT: 79 | add_assoc_long(array, data_p->key, data_p->value.u_int); 80 | break; 81 | case RD_I_STR: 82 | add_assoc_string(array, data_p->key, data_p->value.u_str); 83 | break; 84 | case RD_I_BLO: 85 | add_assoc_stringl(array, data_p->key, (char *)data_p->value.u_blo.ptr, 86 | data_p->value.u_blo.size); 87 | break; 88 | } 89 | data_p = data_p->next; 90 | } 91 | 92 | return 1; 93 | } 94 | /* }}} */ 95 | -------------------------------------------------------------------------------- /tests/data/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile for creating data for test 2 | # 3 | # usage from main extension directory for creating fresh data 4 | # make -C tests/data clean 5 | # make -C tests/data all 6 | # 7 | rrd_binary = @RRDTOOL_BIN@ 8 | 9 | all: speed.png rrd_updater_fetch.txt speed-dump.xml moreDS-empty.rrd moreDS_fetch.txt 10 | @echo 'You can run "make test"' 11 | 12 | clean: 13 | rm -f *.rrd *.png *.xml *fetch.txt 14 | 15 | speed-empty.rrd: 16 | $(rrd_binary) create speed-empty.rrd --start 920804400 \ 17 | DS:speed:COUNTER:600:U:U \ 18 | RRA:AVERAGE:0.5:1:24 \ 19 | RRA:AVERAGE:0.5:6:10 20 | 21 | speed.rrd: speed-empty.rrd 22 | cp speed-empty.rrd speed.rrd 23 | $(rrd_binary) update speed.rrd \ 24 | 920804700:12345 920805000:12357 920805300:12363 \ 25 | 920805600:12363 920805900:12363 920806200:12373 \ 26 | 920806500:12383 920806800:12393 920807100:12399 \ 27 | 920807400:12405 920807700:12411 920808000:12415 \ 28 | 920808300:12420 920808600:12422 920808900:12423 29 | 30 | speed.png: speed.rrd 31 | $(rrd_binary) graph speed.png \ 32 | --start 920804400 --end 920808000 \ 33 | --vertical-label m/s \ 34 | DEF:myspeed=speed.rrd:speed:AVERAGE \ 35 | CDEF:realspeed=myspeed,1000,* \ 36 | LINE2:realspeed#FF0000 37 | 38 | rrd_updater_fetch.txt: speed.rrd 39 | $(rrd_binary) fetch speed.rrd AVERAGE \ 40 | --start 920804400 --end 920809200 >rrd_updater_fetch.txt 41 | 42 | speed-dump.xml: speed.rrd 43 | $(rrd_binary) dump speed.rrd >speed-dump.xml 44 | 45 | moreDS-empty.rrd: 46 | $(rrd_binary) create moreDS-empty.rrd --start 920804400 \ 47 | DS:speed1:COUNTER:600:U:U \ 48 | DS:speed2:COUNTER:600:U:U \ 49 | RRA:AVERAGE:0.5:1:24 \ 50 | RRA:AVERAGE:0.5:6:10 51 | cp moreDS-empty.rrd moreDS-updater.rrd 52 | $(rrd_binary) update moreDS-updater.rrd \ 53 | 920804700:12345:11340 920805000:12357:11357 920805300:12363:11363 54 | $(rrd_binary) fetch moreDS-updater.rrd AVERAGE \ 55 | --start 920804400 --end 920808000 >moreDS_updater_fetch.txt 56 | rm moreDS-updater.rrd 57 | 58 | moreDS.rrd: 59 | $(rrd_binary) create moreDS.rrd --start 920804400 \ 60 | DS:speed1:COUNTER:600:U:U \ 61 | DS:speed2:COUNTER:600:U:U \ 62 | RRA:AVERAGE:0.5:1:24 \ 63 | RRA:AVERAGE:0.5:6:10 64 | $(rrd_binary) update moreDS.rrd \ 65 | 920804700:12345:11340 920805000:12357:11357 920805300:12363:11363 \ 66 | 920805600:12363:11364 920805900:12363:11364 920806200:12373:11373 \ 67 | 920806500:12383:11373 920806800:12393:11393 920807100:12399:11399 \ 68 | 920807400:12405:11405 920807700:12411:11411 920808000:12415:11415 \ 69 | 920808300:12420:11420 920808600:12422:11422 920808900:12423:11423 70 | 71 | moreDS_fetch.txt: moreDS.rrd 72 | $(rrd_binary) fetch moreDS.rrd AVERAGE \ 73 | --start 920804400 --end 920808000 >moreDS_fetch.txt 74 | -------------------------------------------------------------------------------- /rrd_update.c: -------------------------------------------------------------------------------- 1 | /** 2 | * PHP bindings to the rrdtool 3 | * 4 | * This source file is subject to the BSD license that is bundled 5 | * with this package in the file LICENSE. 6 | * --------------------------------------------------------------- 7 | * Author: Miroslav Kubelik 8 | * --------------------------------------------------------------- 9 | */ 10 | 11 | #ifdef HAVE_CONFIG_H 12 | #include "config.h" 13 | #endif 14 | 15 | #include "php.h" 16 | #include "zend_exceptions.h" 17 | #include "ext/standard/php_smart_string.h" 18 | 19 | #include 20 | 21 | #include "php_rrd.h" 22 | #include "rrd_update.h" 23 | 24 | /* declare class entry */ 25 | static zend_class_entry *ce_rrd_update; 26 | /* declare class handlers */ 27 | static zend_object_handlers rrd_update_handlers; 28 | 29 | /** 30 | * overloading the standard zend object structure (std property) in the need 31 | * of having dedicated creating/cloning/destruction functions 32 | */ 33 | typedef struct _rrd_update_object { 34 | /** path to newly created rrd file */ 35 | char *file_path; 36 | zend_object std; 37 | } rrd_update_object; 38 | 39 | /** 40 | * fetch our custom object from user space object 41 | */ 42 | static inline rrd_update_object *php_rrd_update_fetch_object(zend_object *obj) { 43 | return (rrd_update_object *)((char*)(obj) - XtOffsetOf(rrd_update_object, std)); 44 | } 45 | 46 | /* {{{ rrd_update_object_dtor 47 | close all resources and the memory allocated for our internal object 48 | */ 49 | static void rrd_update_object_dtor(zend_object *object) 50 | { 51 | rrd_update_object *intern_obj = php_rrd_update_fetch_object(object); 52 | if (!intern_obj) return; 53 | 54 | if (intern_obj->file_path) 55 | efree(intern_obj->file_path); 56 | 57 | zend_object_std_dtor(&intern_obj->std); 58 | } 59 | /* }}} */ 60 | 61 | /* {{{ rrd_update_object_new 62 | creates new rrd update object 63 | */ 64 | static zend_object *rrd_update_object_new(zend_class_entry *ce) 65 | { 66 | rrd_update_object *intern_obj = ecalloc(1, sizeof(rrd_update_object) + 67 | zend_object_properties_size(ce)); 68 | intern_obj->file_path = NULL; 69 | 70 | zend_object_std_init(&intern_obj->std, ce); 71 | object_properties_init(&intern_obj->std, ce); 72 | 73 | intern_obj->std.handlers = &rrd_update_handlers; 74 | 75 | return &intern_obj->std; 76 | } 77 | /* }}} */ 78 | 79 | /* {{{ proto void RRDUpdater::__construct(string path) 80 | creates new object for rrd update function 81 | */ 82 | PHP_METHOD(RRDUpdater, __construct) 83 | { 84 | rrd_update_object *intern_obj; 85 | char *path; 86 | size_t path_length; 87 | 88 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &path, &path_length) == FAILURE) { 89 | return; 90 | } 91 | 92 | intern_obj = php_rrd_update_fetch_object(Z_OBJ_P(getThis())); 93 | intern_obj->file_path = estrdup(path); 94 | } 95 | /* }}} */ 96 | 97 | /* {{{ proto array RRDUpdater::update(array $values, [string time=time()]) 98 | Updates data sources in RRD database 99 | */ 100 | PHP_METHOD(RRDUpdater, update) 101 | { 102 | rrd_update_object *intern_obj; 103 | zval *zv_values_array; 104 | 105 | /* help structures for preparing arguments for rrd_update call */ 106 | zval zv_update_argv; 107 | rrd_args *update_argv; 108 | 109 | /* 'N' means default time string for rrd update, 110 | * see rrdtool update man page 111 | */ 112 | char *time = "N"; 113 | size_t time_str_length = 1; 114 | 115 | int argc = ZEND_NUM_ARGS(); 116 | zend_string *zs_ds_name; 117 | zval *zv_ds_val; 118 | 119 | /* string for all data source names formated for rrd_update call */ 120 | smart_string ds_names = {0}; 121 | /* string for all data source values for rrd_update call */ 122 | smart_string ds_vals = {0}; 123 | 124 | if (zend_parse_parameters(argc, "a|s", &zv_values_array, &time, 125 | &time_str_length) == FAILURE) { 126 | return; 127 | } 128 | 129 | if (zend_hash_num_elements(Z_ARRVAL_P(zv_values_array)) <= 0) { 130 | RETURN_TRUE; 131 | } 132 | 133 | intern_obj = php_rrd_update_fetch_object(Z_OBJ_P(getThis())); 134 | 135 | if (php_check_open_basedir(intern_obj->file_path)) { 136 | RETURN_FALSE; 137 | } 138 | 139 | if (argc > 1 && time_str_length == 0) { 140 | zend_throw_exception(NULL, "time cannot be empty string", 0); 141 | return; 142 | } 143 | 144 | ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zv_values_array), zs_ds_name, zv_ds_val) { 145 | if (ds_names.len) { 146 | smart_string_appendc(&ds_names, ':'); 147 | } else { 148 | smart_string_appends(&ds_names, "--template="); 149 | } 150 | 151 | smart_string_appends(&ds_names, ZSTR_VAL(zs_ds_name)); 152 | 153 | /* "timestamp:ds1Value:ds2Value" string */ 154 | if (!ds_vals.len) { 155 | smart_string_appends(&ds_vals, time); 156 | } 157 | smart_string_appendc(&ds_vals, ':'); 158 | if (Z_TYPE_P(zv_ds_val) != IS_STRING) { 159 | convert_to_string(zv_ds_val); 160 | } 161 | smart_string_appendl(&ds_vals, Z_STRVAL_P(zv_ds_val), Z_STRLEN_P(zv_ds_val)); 162 | } ZEND_HASH_FOREACH_END(); 163 | smart_string_0(&ds_names); 164 | smart_string_0(&ds_vals); 165 | 166 | /* add copy of names and values strings into arguments array and free 167 | * original strings 168 | */ 169 | array_init(&zv_update_argv); 170 | add_next_index_string(&zv_update_argv, ds_names.c); 171 | add_next_index_string(&zv_update_argv, ds_vals.c); 172 | smart_string_free(&ds_names); 173 | smart_string_free(&ds_vals); 174 | 175 | update_argv = rrd_args_init_by_phparray("update", intern_obj->file_path, &zv_update_argv); 176 | if (!update_argv) { 177 | zend_error(E_WARNING, "cannot allocate arguments options"); 178 | zval_dtor(&zv_update_argv); 179 | if (time_str_length == 0) efree(time); 180 | RETURN_FALSE; 181 | } 182 | 183 | if (rrd_test_error()) rrd_clear_error(); 184 | 185 | /* call rrd_update and test if fails */ 186 | if (rrd_update(update_argv->count - 1, &update_argv->args[1]) == -1) { 187 | zval_dtor(&zv_update_argv); 188 | rrd_args_free(update_argv); 189 | 190 | /* throw exception with rrd error string */ 191 | zend_throw_exception(NULL, rrd_get_error(), 0); 192 | rrd_clear_error(); 193 | return; 194 | } 195 | 196 | zval_dtor(&zv_update_argv); 197 | rrd_args_free(update_argv); 198 | 199 | RETURN_TRUE; 200 | } 201 | /* }}} */ 202 | 203 | /* {{{ proto int rrd_update(string file, array options) 204 | Updates the RRD file with a particular options and values. 205 | */ 206 | PHP_FUNCTION(rrd_update) 207 | { 208 | char *filename; 209 | size_t filename_length; 210 | zval *zv_arr_options; 211 | rrd_args *argv; 212 | 213 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "pa", &filename, 214 | &filename_length, &zv_arr_options) == FAILURE) { 215 | return; 216 | } 217 | 218 | if (php_check_open_basedir(filename)) RETURN_FALSE; 219 | 220 | argv = rrd_args_init_by_phparray("update", filename, zv_arr_options); 221 | if (!argv) { 222 | zend_error(E_WARNING, "cannot allocate arguments options"); 223 | RETURN_FALSE; 224 | } 225 | 226 | if (rrd_test_error()) rrd_clear_error(); 227 | 228 | if (rrd_update(argv->count - 1, &argv->args[1]) == -1 ) { 229 | RETVAL_FALSE; 230 | } else { 231 | RETVAL_TRUE; 232 | } 233 | 234 | rrd_args_free(argv); 235 | } 236 | /* }}} */ 237 | 238 | ZEND_BEGIN_ARG_INFO(arginfo_rrdupdater_construct, 0) 239 | ZEND_ARG_INFO(0, path) 240 | ZEND_END_ARG_INFO() 241 | 242 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rrdupdater_update, 0, 0, 1) 243 | ZEND_ARG_INFO(0, values) 244 | ZEND_ARG_INFO(0, time) 245 | ZEND_END_ARG_INFO() 246 | 247 | /* class method table */ 248 | static zend_function_entry rrd_update_methods[] = { 249 | PHP_ME(RRDUpdater, __construct, arginfo_rrdupdater_construct, ZEND_ACC_PUBLIC) 250 | PHP_ME(RRDUpdater, update, arginfo_rrdupdater_update, ZEND_ACC_PUBLIC) 251 | PHP_FE_END 252 | }; 253 | 254 | /* minit hook, called from main module minit */ 255 | void rrd_update_minit() 256 | { 257 | zend_class_entry ce; 258 | INIT_CLASS_ENTRY(ce, "RRDUpdater", rrd_update_methods); 259 | ce.create_object = rrd_update_object_new; 260 | ce_rrd_update = zend_register_internal_class(&ce); 261 | 262 | memcpy(&rrd_update_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 263 | rrd_update_handlers.clone_obj = NULL; 264 | rrd_update_handlers.offset = XtOffsetOf(rrd_update_object, std); 265 | rrd_update_handlers.free_obj = rrd_update_object_dtor; 266 | } 267 | -------------------------------------------------------------------------------- /rrd_create.c: -------------------------------------------------------------------------------- 1 | /** 2 | * PHP bindings to the rrdtool 3 | * 4 | * This source file is subject to the BSD license that is bundled 5 | * with this package in the file LICENSE. 6 | * --------------------------------------------------------------- 7 | * Author: Miroslav Kubelik 8 | * --------------------------------------------------------------- 9 | */ 10 | 11 | #ifdef HAVE_CONFIG_H 12 | #include "config.h" 13 | #endif 14 | 15 | #include "php.h" 16 | #include "zend_exceptions.h" 17 | #include "ext/standard/php_array.h" 18 | 19 | #include 20 | 21 | #include "php_rrd.h" 22 | #include "rrd_create.h" 23 | 24 | /* declare class entry */ 25 | static zend_class_entry *ce_rrd_create; 26 | /* declare class handlers */ 27 | static zend_object_handlers rrd_create_handlers; 28 | 29 | /* overloading the standard zend object structure (std property) in the need 30 | of having dedicated creating/cloning/destruction functions 31 | */ 32 | typedef struct _rrd_create_object { 33 | /** path to newly created rrd file */ 34 | char *file_path; 35 | /* "--start" parameters in rrd create */ 36 | char *start_time; 37 | /* "--step" parameters in rrd create */ 38 | zval zv_step; 39 | /* "DS" parameters in rrd create */ 40 | zval zv_arr_data_sources; 41 | /* "RRA" parameters in rrd create */ 42 | zval zv_arr_archives; 43 | zend_object std; 44 | } rrd_create_object; 45 | 46 | /** 47 | * fetch our custom object from user space object 48 | */ 49 | static inline rrd_create_object *php_rrd_create_fetch_object(zend_object *obj) { 50 | return (rrd_create_object *)((char*)(obj) - XtOffsetOf(rrd_create_object, std)); 51 | } 52 | 53 | /* {{{ rrd_create_object_dtor 54 | close all resources and the memory allocated for our internal object 55 | */ 56 | static void rrd_create_object_dtor(zend_object *object) 57 | { 58 | rrd_create_object *intern_obj = php_rrd_create_fetch_object(object); 59 | if (!intern_obj) return; 60 | 61 | if (intern_obj->file_path) 62 | efree(intern_obj->file_path); 63 | if (intern_obj->start_time) 64 | efree(intern_obj->start_time); 65 | if (!Z_ISUNDEF(intern_obj->zv_step)) 66 | zval_dtor(&intern_obj->zv_step); 67 | if (!Z_ISUNDEF(intern_obj->zv_arr_data_sources)) 68 | zval_dtor(&intern_obj->zv_arr_data_sources); 69 | if (!Z_ISUNDEF(intern_obj->zv_arr_archives)) 70 | zval_dtor(&intern_obj->zv_arr_archives); 71 | 72 | zend_object_std_dtor(&intern_obj->std); 73 | } 74 | /* }}} */ 75 | 76 | /* {{{ rrd_create_object_new 77 | creates new rrd create object 78 | */ 79 | static zend_object *rrd_create_object_new(zend_class_entry *ce) 80 | { 81 | rrd_create_object *intern_obj = ecalloc(1, sizeof(rrd_create_object) + 82 | zend_object_properties_size(ce)); 83 | intern_obj->file_path = NULL; 84 | intern_obj->start_time = NULL; 85 | ZVAL_UNDEF(&intern_obj->zv_step); 86 | ZVAL_UNDEF(&intern_obj->zv_arr_data_sources); 87 | ZVAL_UNDEF(&intern_obj->zv_arr_archives); 88 | 89 | zend_object_std_init(&intern_obj->std, ce); 90 | object_properties_init(&intern_obj->std, ce); 91 | 92 | intern_obj->std.handlers = &rrd_create_handlers; 93 | 94 | return &intern_obj->std; 95 | } 96 | /* }}} */ 97 | 98 | /* {{{ proto void RRDCreator::__construct(string path [,string startTime] 99 | [,int step]) 100 | creates new object for creating rrd database 101 | */ 102 | PHP_METHOD(RRDCreator, __construct) 103 | { 104 | rrd_create_object *intern_obj; 105 | char *path; size_t path_length; 106 | /* better to set defaults for optional parameters */ 107 | zend_string *start_time; 108 | long step = 0; 109 | int argc = ZEND_NUM_ARGS(); 110 | 111 | if (zend_parse_parameters(argc, "p|Sl", &path, &path_length, 112 | &start_time, &step) == FAILURE) { 113 | return; 114 | } 115 | 116 | if (path_length == 0) { 117 | zend_throw_exception(NULL, 118 | "path for rrd file cannot be empty string", 0); 119 | return; 120 | } 121 | 122 | if (argc > 1 && ZSTR_LEN(start_time) == 0) { 123 | zend_throw_exception(NULL, 124 | "startTime cannot be empty string", 0); 125 | return; 126 | } 127 | if (argc > 2 && step <= 0) { 128 | zend_throw_exception(NULL, 129 | "step parameter must be greater then 0", 0); 130 | return; 131 | } 132 | 133 | intern_obj = php_rrd_create_fetch_object(Z_OBJ_P(getThis())); 134 | intern_obj->file_path = estrdup(path); 135 | if (start_time) intern_obj->start_time = estrdup(ZSTR_VAL(start_time)); 136 | if (step) { 137 | ZVAL_LONG(&intern_obj->zv_step, step); 138 | } 139 | } 140 | /* }}} */ 141 | 142 | /* {{{ proto RRDCreator::addDataSource(string description) 143 | Add information about data source 144 | */ 145 | PHP_METHOD(RRDCreator, addDataSource) 146 | { 147 | rrd_create_object *intern_obj; 148 | zend_string *description; 149 | char *rrd_source_desc; 150 | 151 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &description) == FAILURE) { 152 | return; 153 | } 154 | 155 | if (ZSTR_LEN(description) == 0) { 156 | zend_throw_exception(NULL, 157 | "description parameter cannot be empty string", 0); 158 | return; 159 | } 160 | 161 | 162 | intern_obj = php_rrd_create_fetch_object(Z_OBJ_P(getThis())); 163 | 164 | if (Z_ISUNDEF(intern_obj->zv_arr_data_sources)) { 165 | array_init(&intern_obj->zv_arr_data_sources); 166 | } 167 | 168 | rrd_source_desc = emalloc(ZSTR_LEN(description) + 4); 169 | strcpy(rrd_source_desc, "DS:"); 170 | strcat(rrd_source_desc, ZSTR_VAL(description)); 171 | 172 | add_next_index_string(&intern_obj->zv_arr_data_sources, rrd_source_desc); 173 | efree(rrd_source_desc); 174 | } 175 | /* }}} */ 176 | 177 | /* {{{ proto RRDCreator::addArchive(string description) 178 | Add information about new round robin archive 179 | */ 180 | PHP_METHOD(RRDCreator, addArchive) 181 | { 182 | rrd_create_object *intern_obj; 183 | zend_string *description; 184 | char *rrd_archive_desc; 185 | 186 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &description) == FAILURE) { 187 | return; 188 | } 189 | 190 | if (ZSTR_LEN(description) == 0) { 191 | zend_throw_exception(NULL, 192 | "description parameter cannot be empty string", 0); 193 | return; 194 | } 195 | 196 | intern_obj = php_rrd_create_fetch_object(Z_OBJ_P(getThis())); 197 | 198 | if (Z_ISUNDEF(intern_obj->zv_arr_archives)) { 199 | array_init(&intern_obj->zv_arr_archives); 200 | } 201 | 202 | rrd_archive_desc = emalloc(ZSTR_LEN(description) + 5); 203 | strcpy(rrd_archive_desc, "RRA:"); 204 | strcat(rrd_archive_desc, ZSTR_VAL(description)); 205 | 206 | add_next_index_string(&intern_obj->zv_arr_archives, rrd_archive_desc); 207 | efree(rrd_archive_desc); 208 | } 209 | /* }}} */ 210 | 211 | /* {{{ proto bool RRDCreator::save() 212 | Saves new rrd database according to current properties. 213 | */ 214 | PHP_METHOD(RRDCreator, save) 215 | { 216 | rrd_create_object *intern_obj = php_rrd_create_fetch_object(Z_OBJ_P(getThis())); 217 | /* help structures for preparing arguments for rrd_create call */ 218 | zval zv_create_argv; 219 | rrd_args *create_argv; 220 | 221 | array_init(&zv_create_argv); 222 | 223 | if (intern_obj->start_time) { 224 | const char *prefix = "--start="; 225 | char *start_time_str = emalloc(strlen(intern_obj->start_time) 226 | + strlen(prefix) + 1); 227 | 228 | strcpy(start_time_str, prefix); 229 | strcat(start_time_str, intern_obj->start_time); 230 | add_next_index_string(&zv_create_argv, start_time_str); 231 | 232 | efree(start_time_str); 233 | } 234 | 235 | if (!Z_ISUNDEF(intern_obj->zv_step)) { 236 | const char *prefix = "--step="; 237 | char *start_time_str; 238 | 239 | convert_to_string(&intern_obj->zv_step); 240 | start_time_str = emalloc(strlen(prefix) + Z_STRLEN(intern_obj->zv_step) + 1); 241 | 242 | strcpy(start_time_str, prefix); 243 | strcat(start_time_str, Z_STRVAL(intern_obj->zv_step)); 244 | add_next_index_string(&zv_create_argv, start_time_str); 245 | 246 | /* back to long, doesn't needed, but we are consistent */ 247 | convert_to_long(&intern_obj->zv_step); 248 | efree(start_time_str); 249 | } 250 | 251 | /* add array of archive and data source strings into argument list */ 252 | php_array_merge(Z_ARRVAL(zv_create_argv), Z_ARRVAL(intern_obj->zv_arr_data_sources)); 253 | php_array_merge(Z_ARRVAL(zv_create_argv), Z_ARRVAL(intern_obj->zv_arr_archives)); 254 | 255 | create_argv = rrd_args_init_by_phparray("create", intern_obj->file_path, &zv_create_argv); 256 | if (!create_argv) { 257 | zend_error(E_WARNING, "cannot allocate arguments options"); 258 | zval_dtor(&zv_create_argv); 259 | RETURN_FALSE; 260 | } 261 | 262 | if (rrd_test_error()) rrd_clear_error(); 263 | 264 | /* call rrd_create and test if fails */ 265 | if (rrd_create(create_argv->count - 1, &create_argv->args[1]) == -1) { 266 | zval_dtor(&zv_create_argv); 267 | rrd_args_free(create_argv); 268 | 269 | /* throw exception with rrd error string */ 270 | zend_throw_exception(NULL, rrd_get_error(), 0); 271 | rrd_clear_error(); 272 | return; 273 | } 274 | 275 | zval_dtor(&zv_create_argv); 276 | rrd_args_free(create_argv); 277 | RETURN_TRUE; 278 | } 279 | /* }}} */ 280 | 281 | /* {{{ proto bool rrd_create(string file, array options) 282 | Create an RRD file with the options passed 283 | */ 284 | PHP_FUNCTION(rrd_create) 285 | { 286 | char *filename; 287 | size_t filename_length; 288 | zval *zv_arr_options; 289 | rrd_args *argv; 290 | 291 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "pa", &filename, 292 | &filename_length, &zv_arr_options) == FAILURE) { 293 | return; 294 | } 295 | 296 | if (php_check_open_basedir(filename)) RETURN_FALSE; 297 | 298 | argv = rrd_args_init_by_phparray("create", filename, zv_arr_options); 299 | if (!argv) { 300 | zend_error(E_WARNING, "cannot allocate arguments options"); 301 | RETURN_FALSE; 302 | } 303 | 304 | if (rrd_test_error()) rrd_clear_error(); 305 | 306 | if (rrd_create(argv->count - 1, &argv->args[1]) == -1 ) { 307 | RETVAL_FALSE; 308 | } else { 309 | RETVAL_TRUE; 310 | } 311 | 312 | rrd_args_free(argv); 313 | } 314 | /* }}} */ 315 | 316 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rrdcreator_construct, 0, 0, 1) 317 | ZEND_ARG_INFO(0, path) 318 | ZEND_ARG_INFO(0, startTime) 319 | ZEND_ARG_INFO(0, step) 320 | ZEND_END_ARG_INFO() 321 | 322 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rrdcreator_description, 0, 0, 1) 323 | ZEND_ARG_INFO(0, description) 324 | ZEND_END_ARG_INFO() 325 | 326 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rrdcreator_void, 0, 0, 0) 327 | ZEND_END_ARG_INFO() 328 | 329 | /* class method table */ 330 | static zend_function_entry rrd_create_methods[] = { 331 | PHP_ME(RRDCreator, __construct, arginfo_rrdcreator_construct, ZEND_ACC_PUBLIC) 332 | PHP_ME(RRDCreator, save, arginfo_rrdcreator_void, ZEND_ACC_PUBLIC) 333 | PHP_ME(RRDCreator, addDataSource, arginfo_rrdcreator_description, ZEND_ACC_PUBLIC) 334 | PHP_ME(RRDCreator, addArchive, arginfo_rrdcreator_description, ZEND_ACC_PUBLIC) 335 | PHP_FE_END 336 | }; 337 | 338 | /* minit hook, called from main module minit */ 339 | void rrd_create_minit() 340 | { 341 | zend_class_entry ce; 342 | INIT_CLASS_ENTRY(ce, "RRDCreator", rrd_create_methods); 343 | ce.create_object = rrd_create_object_new; 344 | ce_rrd_create = zend_register_internal_class(&ce); 345 | 346 | memcpy(&rrd_create_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 347 | rrd_create_handlers.clone_obj = NULL; 348 | rrd_create_handlers.offset = XtOffsetOf(rrd_create_object, std); 349 | rrd_create_handlers.free_obj = rrd_create_object_dtor; 350 | } 351 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | rrd 4 | pecl.php.net 5 | PHP bindings to rrd tool system 6 | Procedural and simple OO wrapper for rrdtool - data logging and graphing system for time series data. 7 | 8 | Miroslav Kubelik 9 | koubel 10 | koubel@php.net 11 | yes 12 | 13 | 14 | 2021-04-22 15 | 16 | 2.0.3 17 | 1.1 18 | 19 | 20 | stable 21 | stable 22 | 23 | BSD 24 | 26 | ]]> 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 7.0.0 80 | 81 | 82 | 1.4.0 83 | 84 | 85 | 86 | rrd 87 | 88 | 89 | 90 | 91 | 2.0.3 92 | 1.1 93 | 94 | 95 | stable 96 | stable 97 | 98 | BSD 99 | 101 | ]]> 102 | 103 | 2021-04-22 104 | 105 | 106 | 107 | 2.0.2 108 | 1.1 109 | 110 | 111 | stable 112 | stable 113 | 114 | 117 | 118 | 2021-04-18 119 | 120 | 121 | 122 | 2.0.1 123 | 1.1 124 | 125 | 126 | stable 127 | stable 128 | 129 | 133 | 134 | 2016-05-10 135 | 136 | 137 | 138 | 2.0.0 139 | 1.1 140 | 141 | 142 | stable 143 | stable 144 | 145 | 148 | 149 | 2015-12-28 150 | 151 | 152 | 153 | 2.0.0beta2 154 | 1.1 155 | 156 | 157 | beta 158 | stable 159 | 160 | 163 | 164 | 2015-06-16 165 | 166 | 167 | 168 | 2.0.0beta1 169 | 1.1 170 | 171 | 172 | beta 173 | stable 174 | 175 | 178 | 179 | 2015-06-16 180 | 181 | 182 | 183 | 1.1.3 184 | 1.1.3 185 | 186 | 187 | stable 188 | stable 189 | 190 | 193 | 194 | 2014-01-15 195 | 196 | 197 | 198 | 1.1.2 199 | 1.1.2 200 | 201 | 202 | stable 203 | stable 204 | 205 | 209 | 210 | 2014-01-14 211 | 212 | 213 | 214 | 1.1.1 215 | 1.1.1 216 | 217 | 218 | stable 219 | stable 220 | 221 | 224 | 225 | 2013-09-03 226 | 227 | 228 | 229 | 1.1.0 230 | 1.1.0 231 | 232 | 233 | stable 234 | stable 235 | 236 | 239 | 240 | 2012-06-04 241 | 242 | 243 | 244 | 1.0.5 245 | 1.0.5 246 | 247 | 248 | stable 249 | stable 250 | 251 | 254 | 255 | 2011-11-16 256 | 257 | 258 | 259 | 1.0.5RC2 260 | 1.0.5 261 | 262 | 263 | beta 264 | stable 265 | 266 | 269 | 270 | 2011-10-17 271 | 272 | 273 | 274 | 1.0.5RC1 275 | 1.0.5 276 | 277 | 278 | beta 279 | stable 280 | 281 | 287 | 288 | 2011-09-27 289 | 290 | 291 | 292 | 1.0.4 293 | 1.0.4 294 | 295 | 296 | stable 297 | stable 298 | 299 | 302 | 303 | 2011-08-12 304 | 305 | 306 | 307 | 1.0.3 308 | 1.0.3 309 | 310 | 311 | stable 312 | stable 313 | 314 | 317 | 318 | 2011-04-29 319 | 320 | 321 | 322 | 1.0.2 323 | 1.0.2 324 | 325 | 326 | stable 327 | stable 328 | 329 | 332 | 333 | 2011-04-19 334 | 335 | 336 | 337 | 1.0.1 338 | 1.0.1 339 | 340 | 341 | stable 342 | stable 343 | 344 | 347 | 348 | 2011-04-16 349 | 350 | 351 | 352 | 1.0.0 353 | 1.0.0 354 | 355 | 356 | stable 357 | stable 358 | 359 | 364 | 365 | 2011-04-12 366 | 367 | 368 | 369 | 0.10.0 370 | 0.10.0 371 | 372 | 373 | stable 374 | beta 375 | 376 | 382 | 383 | 2011-03-03 384 | 385 | 386 | 387 | 0.9.0 388 | 0.9.0 389 | 390 | 391 | beta 392 | beta 393 | 394 | first official pecl release 395 | 2011-01-03 396 | 397 | 398 | 399 | -------------------------------------------------------------------------------- /rrd_graph.c: -------------------------------------------------------------------------------- 1 | /** 2 | * PHP bindings to the rrdtool 3 | * 4 | * This source file is subject to the BSD license that is bundled 5 | * with this package in the file LICENSE. 6 | * --------------------------------------------------------------- 7 | * Author: Miroslav Kubelik 8 | * --------------------------------------------------------------- 9 | */ 10 | 11 | #ifdef HAVE_CONFIG_H 12 | #include "config.h" 13 | #endif 14 | 15 | #include "php.h" 16 | #include "zend_exceptions.h" 17 | #include "ext/standard/php_smart_string.h" 18 | 19 | #include 20 | 21 | #include "php_rrd.h" 22 | #include "rrd_info.h" 23 | #include "rrd_graph.h" 24 | 25 | /* declare class entry */ 26 | static zend_class_entry *ce_rrd_graph; 27 | /* declare class handlers */ 28 | static zend_object_handlers rrd_graph_handlers; 29 | 30 | /** 31 | * overloading the standard zend object structure (std property) in the need 32 | * of having dedicated creating/cloning/destruction functions 33 | */ 34 | typedef struct _rrd_graph_object { 35 | char *file_path; 36 | zval zv_arr_options; 37 | zend_object std; 38 | } rrd_graph_object; 39 | 40 | /** 41 | * fetch our custom object from user space object 42 | */ 43 | static inline rrd_graph_object *php_rrd_graph_fetch_object(zend_object *obj) { 44 | return (rrd_graph_object *)((char*)(obj) - XtOffsetOf(rrd_graph_object, std)); 45 | } 46 | 47 | /* {{{ rrd_graph_object_dtor 48 | close all resources and the memory allocated for our internal object 49 | */ 50 | static void rrd_graph_object_dtor(zend_object *object) 51 | { 52 | rrd_graph_object *intern_obj = php_rrd_graph_fetch_object(object); 53 | if (!intern_obj) return; 54 | 55 | if (intern_obj->file_path){ 56 | efree(intern_obj->file_path); 57 | } 58 | if (!Z_ISUNDEF(intern_obj->zv_arr_options)) { 59 | zval_dtor(&intern_obj->zv_arr_options); 60 | } 61 | 62 | zend_object_std_dtor(&intern_obj->std); 63 | } 64 | /* }}} */ 65 | 66 | /* {{{ rrd_graph_object_new 67 | creates new rrd graph object 68 | */ 69 | static zend_object *rrd_graph_object_new(zend_class_entry *ce) 70 | { 71 | rrd_graph_object *intern_obj = ecalloc(1, sizeof(rrd_graph_object) + 72 | zend_object_properties_size(ce)); 73 | intern_obj->file_path = NULL; 74 | ZVAL_UNDEF(&intern_obj->zv_arr_options); 75 | 76 | zend_object_std_init(&intern_obj->std, ce); 77 | object_properties_init(&intern_obj->std, ce); 78 | 79 | intern_obj->std.handlers = &rrd_graph_handlers; 80 | 81 | return &intern_obj->std; 82 | } 83 | /* }}} */ 84 | 85 | /* {{{ proto void RRDGraph::__construct(string path) 86 | creates new object for rrd graph function 87 | */ 88 | PHP_METHOD(RRDGraph, __construct) 89 | { 90 | rrd_graph_object *intern_obj; 91 | char *path; 92 | size_t path_length; 93 | 94 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &path, &path_length) == FAILURE) { 95 | return; 96 | } 97 | 98 | intern_obj = php_rrd_graph_fetch_object(Z_OBJ_P(getThis())); 99 | intern_obj->file_path = estrdup(path); 100 | } 101 | /* }}} */ 102 | 103 | /* {{{ proto void RRDGraph::setOptions(array options) 104 | set command options for rrd graph call 105 | */ 106 | PHP_METHOD(RRDGraph, setOptions) 107 | { 108 | rrd_graph_object *intern_obj; 109 | zval *zv_arr_options; 110 | 111 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &zv_arr_options) == FAILURE) { 112 | return; 113 | } 114 | 115 | intern_obj = php_rrd_graph_fetch_object(Z_OBJ_P(getThis())); 116 | 117 | /* if our array is initialized, so delete it first */ 118 | if (!Z_ISUNDEF(intern_obj->zv_arr_options)) { 119 | zval_dtor(&intern_obj->zv_arr_options); 120 | } 121 | 122 | /* copy array from parameter */ 123 | ZVAL_DUP(&intern_obj->zv_arr_options, zv_arr_options); 124 | } 125 | /* }}} */ 126 | 127 | /* {{{ 128 | creates arguments for rrd_graph call for RRDGraph instance options 129 | */ 130 | static rrd_args *rrd_graph_obj_create_argv(const char *command_name, const rrd_graph_object *obj) 131 | { 132 | /* iterated item and keys*/ 133 | zval *zv_option_val; 134 | zend_ulong num_key; 135 | zend_string *zs_key; 136 | /* arguments for rrd_graph call as php array - temporary storage */ 137 | zval zv_argv; 138 | rrd_args *result; 139 | 140 | array_init(&zv_argv); 141 | 142 | ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(obj->zv_arr_options), num_key, zs_key, zv_option_val) { 143 | (void)num_key; /* to avoid -Wunused-but-set-variable */ 144 | smart_string option = {0}; /* one argument option */ 145 | 146 | /* option with string key means long option, hence they are used as 147 | * "key=value" e.g. "--start=920804400" 148 | */ 149 | if (zs_key) { 150 | smart_string_appends(&option, ZSTR_VAL(zs_key)); 151 | smart_string_appendc(&option, '='); 152 | } 153 | 154 | /* use always string for option value */ 155 | if (Z_TYPE_P(zv_option_val) != IS_STRING) { 156 | convert_to_string(zv_option_val); 157 | } 158 | 159 | smart_string_appendl(&option, Z_STRVAL_P(zv_option_val), Z_STRLEN_P(zv_option_val)); 160 | smart_string_0(&option); 161 | 162 | add_next_index_string(&zv_argv, option.c); 163 | 164 | smart_string_free(&option); 165 | } ZEND_HASH_FOREACH_END(); 166 | 167 | result = rrd_args_init_by_phparray(command_name, obj->file_path, &zv_argv); 168 | zval_dtor(&zv_argv); 169 | 170 | return result; 171 | } 172 | /* }}} */ 173 | 174 | /* {{{ proto array RRDGraph::save() 175 | Saves graph according to current option 176 | */ 177 | PHP_METHOD(RRDGraph, save) 178 | { 179 | rrd_graph_object *intern_obj = php_rrd_graph_fetch_object(Z_OBJ_P(getThis())); 180 | 181 | /* returned values if rrd_graph doesn't fail */ 182 | int xsize, ysize; 183 | double ymin,ymax; 184 | char **calcpr; 185 | 186 | /* arguments for rrd_graph call */ 187 | rrd_args *graph_argv; 188 | 189 | if (Z_TYPE(intern_obj->zv_arr_options) != IS_ARRAY) { 190 | zend_throw_exception(NULL, "options aren't correctly set", 0); 191 | return; 192 | } 193 | 194 | if (php_check_open_basedir(intern_obj->file_path)) { 195 | RETURN_FALSE; 196 | } 197 | 198 | graph_argv = rrd_graph_obj_create_argv("graph", intern_obj); 199 | if (!graph_argv) { 200 | zend_error(E_WARNING, "cannot allocate arguments options"); 201 | RETURN_FALSE; 202 | } 203 | 204 | if (rrd_test_error()) rrd_clear_error(); 205 | 206 | /* call rrd graph and test if fails */ 207 | if (rrd_graph(graph_argv->count - 1, &graph_argv->args[1], &calcpr, &xsize, 208 | &ysize, NULL, &ymin, &ymax) == -1) { 209 | 210 | /* throw exception with rrd error string */ 211 | zend_throw_exception(NULL, rrd_get_error(), 0); 212 | rrd_clear_error(); 213 | rrd_args_free(graph_argv); 214 | return; 215 | } 216 | 217 | /* making return array */ 218 | array_init(return_value); 219 | add_assoc_long(return_value, "xsize", xsize); 220 | add_assoc_long(return_value, "ysize", ysize); 221 | 222 | /* add calcpr return values under "calcpr" key 223 | * 224 | * if calcpr isn't presented add PHP NULL value 225 | */ 226 | if (!calcpr) { 227 | add_assoc_null(return_value, "calcpr"); 228 | } else { 229 | /* calcpr is presented, hence create array for it, and add it to return array */ 230 | zval zv_calcpr_array; 231 | array_init(&zv_calcpr_array); 232 | if (calcpr) { 233 | unsigned i; 234 | for (i = 0; calcpr[i]; i++) { 235 | add_next_index_string(&zv_calcpr_array, calcpr[i]); 236 | free(calcpr[i]); 237 | } 238 | free(calcpr); 239 | } 240 | add_assoc_zval(return_value, "calcpr", &zv_calcpr_array); 241 | } 242 | 243 | rrd_args_free(graph_argv); 244 | } 245 | /* }}} */ 246 | 247 | /* {{{ proto array RRDGraph::saveVerbose() 248 | Saves graph according to current option with return an extra information about 249 | saved image. 250 | */ 251 | PHP_METHOD(RRDGraph, saveVerbose) 252 | { 253 | rrd_graph_object *intern_obj = php_rrd_graph_fetch_object(Z_OBJ_P(getThis())); 254 | /* return value from rrd_graphv */ 255 | rrd_info_t *rrd_info_data; 256 | 257 | /* arguments for rrd_graph call */ 258 | rrd_args *graph_argv; 259 | 260 | if (Z_TYPE(intern_obj->zv_arr_options) != IS_ARRAY) { 261 | zend_throw_exception(NULL, "options aren't correctly set", 0); 262 | return; 263 | } 264 | 265 | graph_argv = rrd_graph_obj_create_argv("graphv", intern_obj); 266 | if (!graph_argv) { 267 | zend_error(E_WARNING, "cannot allocate arguments options"); 268 | RETURN_FALSE; 269 | } 270 | 271 | if (rrd_test_error()) rrd_clear_error(); 272 | 273 | /* call rrd graphv and test if fails */ 274 | rrd_info_data = rrd_graph_v(graph_argv->count - 1, &graph_argv->args[1]); 275 | if (!rrd_info_data) { 276 | /* throw exception with rrd error string */ 277 | zend_throw_exception(NULL, rrd_get_error(), 0); 278 | rrd_clear_error(); 279 | rrd_args_free(graph_argv); 280 | return; 281 | } 282 | 283 | /* making return array */ 284 | array_init(return_value); 285 | rrd_info_toarray(rrd_info_data, return_value); 286 | 287 | rrd_info_free(rrd_info_data); 288 | rrd_args_free(graph_argv); 289 | } 290 | /* }}} */ 291 | 292 | /* {{{ proto array rrd_graph(string file, array options) 293 | Ceates a graph based on options passed via an array. 294 | */ 295 | PHP_FUNCTION(rrd_graph) 296 | { 297 | char *filename; 298 | size_t filename_length; 299 | zval *zv_arr_options; 300 | rrd_args *argv; 301 | /* returned values if rrd_graph doesn't fail */ 302 | int xsize, ysize; 303 | double ymin,ymax; 304 | char **calcpr; 305 | 306 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "pa", &filename, 307 | &filename_length, &zv_arr_options) == FAILURE) { 308 | return; 309 | } 310 | 311 | if (php_check_open_basedir(filename)) RETURN_FALSE; 312 | 313 | argv = rrd_args_init_by_phparray("graph", filename, zv_arr_options); 314 | if (!argv) { 315 | zend_error(E_WARNING, "cannot allocate arguments options"); 316 | RETURN_FALSE; 317 | } 318 | 319 | if (rrd_test_error()) rrd_clear_error(); 320 | 321 | /* call rrd graph and test if fails */ 322 | if (rrd_graph(argv->count - 1, &argv->args[1], &calcpr, &xsize, &ysize, 323 | NULL, &ymin, &ymax) == -1) { 324 | 325 | rrd_args_free(argv); 326 | RETURN_FALSE; 327 | } 328 | 329 | /* making return array*/ 330 | array_init(return_value); 331 | add_assoc_long(return_value, "xsize", xsize); 332 | add_assoc_long(return_value, "ysize", ysize); 333 | 334 | /* add calcpr return values under "calcpr" key 335 | * 336 | * if calcpr isn't presented add PHP NULL value 337 | */ 338 | if (!calcpr) { 339 | add_assoc_null(return_value, "calcpr"); 340 | } else { 341 | /* calcpr is presented, hence create array for it, and add it to return array */ 342 | zval zv_calcpr_array; 343 | array_init(&zv_calcpr_array); 344 | if (calcpr) { 345 | unsigned i; 346 | for (i = 0; calcpr[i]; i++) { 347 | add_next_index_string(&zv_calcpr_array, calcpr[i]); 348 | free(calcpr[i]); 349 | } 350 | free(calcpr); 351 | } 352 | add_assoc_zval(return_value, "calcpr", &zv_calcpr_array); 353 | } 354 | 355 | rrd_args_free(argv); 356 | } 357 | /* }}} */ 358 | 359 | /* arguments */ 360 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rrd_void, 0, 0, 0) 361 | ZEND_END_ARG_INFO() 362 | 363 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rrd_path, 0, 0, 1) 364 | ZEND_ARG_INFO(0, path) 365 | ZEND_END_ARG_INFO() 366 | 367 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rrd_options, 0, 0, 1) 368 | ZEND_ARG_INFO(0, options) 369 | ZEND_END_ARG_INFO() 370 | 371 | /* class method table */ 372 | static zend_function_entry rrd_graph_methods[] = { 373 | PHP_ME(RRDGraph, __construct, arginfo_rrd_path, ZEND_ACC_PUBLIC) 374 | PHP_ME(RRDGraph, save, arginfo_rrd_void, ZEND_ACC_PUBLIC) 375 | PHP_ME(RRDGraph, saveVerbose, arginfo_rrd_void, ZEND_ACC_PUBLIC) 376 | PHP_ME(RRDGraph, setOptions, arginfo_rrd_options, ZEND_ACC_PUBLIC) 377 | PHP_FE_END 378 | }; 379 | 380 | /* minit hook, called from main module minit */ 381 | void rrd_graph_minit() 382 | { 383 | zend_class_entry ce; 384 | INIT_CLASS_ENTRY(ce, "RRDGraph", rrd_graph_methods); 385 | ce.create_object = rrd_graph_object_new; 386 | ce_rrd_graph = zend_register_internal_class(&ce); 387 | 388 | memcpy(&rrd_graph_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 389 | rrd_graph_handlers.clone_obj = NULL; 390 | rrd_graph_handlers.offset = XtOffsetOf(rrd_graph_object, std); 391 | rrd_graph_handlers.free_obj = rrd_graph_object_dtor; 392 | } 393 | -------------------------------------------------------------------------------- /rrd.c: -------------------------------------------------------------------------------- 1 | /** 2 | * PHP bindings to the rrdtool 3 | * 4 | * This source file is subject to the BSD license that is bundled 5 | * with this package in the file LICENSE. 6 | * --------------------------------------------------------------- 7 | * Author: Miroslav Kubelik 8 | * --------------------------------------------------------------- 9 | */ 10 | #ifdef HAVE_CONFIG_H 11 | #include "config.h" 12 | #endif 13 | 14 | #include "php.h" 15 | #include "ext/standard/php_smart_string.h" 16 | #include "ext/standard/php_array.h" 17 | #include "ext/standard/info.h" 18 | 19 | #include 20 | #ifdef HAVE_RRDC_DISCONNECT 21 | #include 22 | #endif 23 | 24 | #include "php_rrd.h" 25 | #include "rrd_graph.h" 26 | #include "rrd_create.h" 27 | #include "rrd_update.h" 28 | #include "rrd_info.h" 29 | 30 | /* {{{ proto string rrd_error() 31 | Get the error message set by the last rrd tool function call, this function 32 | clear error buffer also. 33 | */ 34 | PHP_FUNCTION(rrd_error) 35 | { 36 | if (zend_parse_parameters_none() == FAILURE) { 37 | return; 38 | } 39 | 40 | if (!rrd_test_error()) RETURN_FALSE; 41 | 42 | RETVAL_STRING(rrd_get_error()); 43 | rrd_clear_error(); 44 | } 45 | /* }}} */ 46 | 47 | /* {{{ proto array rrd_fetch(string file, array options) 48 | Fetch data from RRD in requested resolution. 49 | */ 50 | PHP_FUNCTION(rrd_fetch) 51 | { 52 | char *filename; 53 | size_t filename_length; 54 | zval *zv_arr_options; 55 | rrd_args *argv; 56 | /* returned values if rrd_fetch doesn't fail */ 57 | time_t start, end; 58 | zend_ulong step, 59 | ds_cnt; /* count of data sources */ 60 | char **ds_namv; /* list of data source names */ 61 | rrd_value_t *ds_data; /* all data from all sources */ 62 | 63 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "pa", &filename, 64 | &filename_length, &zv_arr_options) == FAILURE) { 65 | return; 66 | } 67 | 68 | if (php_check_open_basedir(filename)) RETURN_FALSE; 69 | 70 | argv = rrd_args_init_by_phparray("fetch", filename, zv_arr_options); 71 | if (!argv) { 72 | zend_error(E_WARNING, "cannot allocate arguments options"); 73 | RETURN_FALSE; 74 | } 75 | 76 | if (rrd_test_error()) rrd_clear_error(); 77 | 78 | /* call rrd_fetch and test if fails */ 79 | if (rrd_fetch(argv->count - 1, &argv->args[1], &start, &end, &step, &ds_cnt, 80 | &ds_namv, &ds_data) == -1 ) { 81 | rrd_args_free(argv); 82 | RETURN_FALSE; 83 | } 84 | 85 | /* making return array */ 86 | array_init(return_value); 87 | add_assoc_long(return_value, "start", start); 88 | add_assoc_long(return_value, "end", end); 89 | add_assoc_long(return_value, "step", step); 90 | 91 | /* add "ds_namv" and "data" array into return values if there is any 92 | * result data 93 | */ 94 | if (!ds_data || !ds_namv || !ds_cnt) { 95 | add_assoc_null(return_value, "data"); 96 | } else { 97 | rrd_value_t *datap = ds_data; 98 | unsigned timestamp, ds_counter; 99 | /* final array for all data from all data sources */ 100 | zval zv_data_array; 101 | 102 | array_init(&zv_data_array); 103 | 104 | /* add arrays for each data source, each array will be filled with 105 | * retrieved data for a particular data source 106 | */ 107 | for (ds_counter = 0; ds_counter < ds_cnt; ds_counter++) { 108 | zval zv_ds_data_array; 109 | array_init(&zv_ds_data_array); 110 | 111 | add_assoc_zval(&zv_data_array, ds_namv[ds_counter], &zv_ds_data_array); 112 | } 113 | 114 | for (timestamp = start + step; timestamp <= end; timestamp += step) { 115 | /* try to find current data source result array in the 116 | * zv_data_array 117 | */ 118 | zend_hash_internal_pointer_reset(Z_ARRVAL(zv_data_array)); 119 | for (ds_counter = 0; ds_counter < ds_cnt; ds_counter++) { 120 | /* pointer for one data source retrieved data */ 121 | zval *ds_data_array; 122 | /* value for key (timestamp) in data array */ 123 | char str_timestamp[11]; 124 | ZEND_LTOA((zend_ulong)timestamp, str_timestamp, sizeof(str_timestamp)); 125 | 126 | /* gets pointer for data source result array */ 127 | ds_data_array = zend_hash_get_current_data(Z_ARRVAL(zv_data_array)); 128 | 129 | add_assoc_double(ds_data_array, str_timestamp, *(datap++)); 130 | zend_hash_move_forward(Z_ARRVAL(zv_data_array)); 131 | } 132 | } 133 | add_assoc_zval(return_value, "data", &zv_data_array); 134 | 135 | /* free data from rrd_fetch */ 136 | free(ds_data); 137 | for (ds_counter = 0; ds_counter < ds_cnt; ds_counter++) { 138 | free(ds_namv[ds_counter]); 139 | } 140 | free(ds_namv); 141 | } 142 | 143 | rrd_args_free(argv); 144 | } 145 | /* }}} */ 146 | 147 | /* {{{ proto int rrd_first(string file [, int rraindex = 0]) 148 | Gets first update time of an RRD file 149 | */ 150 | PHP_FUNCTION(rrd_first) 151 | { 152 | char *filename; 153 | size_t filename_length; 154 | long rraindex = 0; 155 | /* return value from rrd_first_r call */ 156 | time_t rrd_first_return_val; 157 | 158 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|l", &filename, 159 | &filename_length, &rraindex) == FAILURE) { 160 | return; 161 | } 162 | 163 | if (rraindex < 0) { 164 | rrd_set_error("invalid rraindex number, rraindex must be >= 0"); 165 | RETURN_FALSE; 166 | } 167 | 168 | if (php_check_open_basedir(filename)) { 169 | RETURN_FALSE; 170 | } 171 | 172 | if (rrd_test_error()) rrd_clear_error(); 173 | 174 | /* call rrd_first and test if fails */ 175 | rrd_first_return_val = rrd_first_r(filename, rraindex); 176 | if (rrd_first_return_val == -1) { 177 | RETURN_FALSE; 178 | } 179 | RETURN_LONG(rrd_first_return_val); 180 | } 181 | /* }}} */ 182 | 183 | /* {{{ proto int rrd_last(string file) 184 | Gets last update time of an RRD file 185 | */ 186 | PHP_FUNCTION(rrd_last) 187 | { 188 | char *filename; 189 | size_t filename_length; 190 | /* return value from rrd_first_r call */ 191 | time_t rrd_last_return_val; 192 | 193 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &filename, 194 | &filename_length) == FAILURE) { 195 | return; 196 | } 197 | 198 | if (php_check_open_basedir(filename)) { 199 | RETURN_FALSE; 200 | } 201 | 202 | if (rrd_test_error()) rrd_clear_error(); 203 | 204 | /* call rrd_last and test if fails */ 205 | rrd_last_return_val = rrd_last_r(filename); 206 | if (rrd_last_return_val == -1) { 207 | RETURN_FALSE; 208 | } 209 | RETURN_LONG(rrd_last_return_val); 210 | } 211 | /* }}} */ 212 | 213 | /* {{{ proto int rrd_lastupdate(string file) 214 | Gets last update details of an RRD file */ 215 | PHP_FUNCTION(rrd_lastupdate) 216 | { 217 | char *filename; 218 | size_t filename_length; 219 | /* list of arguments for rrd_lastupdate call, it's more efficient then 220 | * usage of rrd_args, because there isn't array of arguments in parameters 221 | */ 222 | char *argv[3]; 223 | /* return values from rrd_lastupdate_r function */ 224 | time_t last_update; 225 | unsigned long ds_cnt; 226 | char **ds_namv; 227 | char **last_ds; 228 | 229 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &filename, 230 | &filename_length) == FAILURE) { 231 | return; 232 | } 233 | 234 | if (php_check_open_basedir(filename)) { 235 | RETURN_FALSE; 236 | } 237 | 238 | argv[0] = "dummy"; 239 | argv[1] = estrdup("lastupdate"); 240 | argv[2] = estrndup(filename, filename_length); 241 | 242 | if (rrd_test_error()) rrd_clear_error(); 243 | 244 | #ifdef HAVE_RRD_LASTUPDATE_R 245 | if (rrd_lastupdate_r(argv[2], &last_update, &ds_cnt, &ds_namv, 246 | &last_ds) == -1) { 247 | #else 248 | if (rrd_lastupdate(2, &argv[1], &last_update, &ds_cnt, &ds_namv, 249 | &last_ds) == -1) { 250 | #endif 251 | efree(argv[2]); efree(argv[1]); 252 | RETURN_FALSE; 253 | } 254 | 255 | efree(argv[2]); efree(argv[1]); 256 | 257 | /* making return array*/ 258 | array_init(return_value); 259 | add_assoc_long(return_value, "last_update", last_update); 260 | add_assoc_long(return_value, "ds_cnt", ds_cnt); 261 | 262 | /* "ds_navm" return array or null, if no available */ 263 | if (!ds_namv || !ds_cnt) { 264 | add_assoc_null(return_value, "ds_namv"); 265 | } else { 266 | unsigned i; 267 | zval zv_ds_namv_array; 268 | array_init(&zv_ds_namv_array); 269 | 270 | for (i = 0; i < ds_cnt; i++) { 271 | add_next_index_string(&zv_ds_namv_array, ds_namv[i]); 272 | free(ds_namv[i]); 273 | } 274 | free(ds_namv); 275 | add_assoc_zval(return_value, "ds_navm", &zv_ds_namv_array); 276 | } 277 | 278 | /* "data" return array or null, if no available */ 279 | if (!last_ds || !ds_cnt) { 280 | add_assoc_null(return_value, "data"); 281 | } else { 282 | unsigned i; 283 | zval zv_data_array; 284 | array_init(&zv_data_array); 285 | 286 | /* simple array for "data" is enough, data source names and timestamps are 287 | * available under other return value keys 288 | */ 289 | for (i = 0; i < ds_cnt; i++) { 290 | add_next_index_string(&zv_data_array, last_ds[i]); 291 | free(last_ds[i]); 292 | } 293 | free(last_ds); 294 | add_assoc_zval(return_value, "data", &zv_data_array); 295 | } 296 | } 297 | 298 | /* {{{ proto array rrd_restore(string xmlFile, string rrdFile [, array options]) 299 | Restores an RRD file from a XML dump */ 300 | PHP_FUNCTION(rrd_restore) 301 | { 302 | char *xml_filename, *rrd_filename; 303 | size_t xml_filename_length, rrd_filename_length; 304 | zval *zv_arr_options = NULL; 305 | /* this is merge of options and rrd_filename. This is needed because 306 | * rrd_args_init_by_phparray allows only one filename as argument, so 307 | * rrd_filename mugst be part of array of arguments 308 | */ 309 | zval zv_options; 310 | rrd_args *argv; 311 | 312 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "pp|a", &xml_filename, 313 | &xml_filename_length, &rrd_filename, &rrd_filename_length, 314 | &zv_arr_options) == FAILURE) { 315 | return; 316 | } 317 | 318 | if (php_check_open_basedir(xml_filename) || 319 | php_check_open_basedir(rrd_filename)) { 320 | RETURN_FALSE; 321 | } 322 | 323 | /* zv_options = merge rrd_filename and zv_arr_options content */ 324 | array_init(&zv_options); 325 | add_next_index_string(&zv_options, rrd_filename); 326 | if (zv_arr_options && Z_TYPE_P(zv_arr_options) == IS_ARRAY) { 327 | php_array_merge(Z_ARRVAL(zv_options), Z_ARRVAL_P(zv_arr_options)); 328 | } 329 | 330 | argv = rrd_args_init_by_phparray("restore", xml_filename, &zv_options); 331 | if (!argv) { 332 | zend_error(E_WARNING, "cannot allocate arguments options"); 333 | zval_dtor(&zv_options); 334 | RETURN_FALSE; 335 | } 336 | 337 | if (rrd_test_error()) rrd_clear_error(); 338 | 339 | /* call rrd_ restore and test if fails */ 340 | if (rrd_restore(argv->count-1, &argv->args[1]) == -1) { 341 | RETVAL_FALSE; 342 | } else { 343 | RETVAL_TRUE; 344 | } 345 | zval_dtor(&zv_options); 346 | rrd_args_free(argv); 347 | } 348 | /* }}} */ 349 | 350 | /* {{{ proto bool rrd_tune(string file, array options) 351 | Tune an RRD file with the options passed (passed via array) */ 352 | PHP_FUNCTION(rrd_tune) 353 | { 354 | char *filename; 355 | size_t filename_length; 356 | zval *zv_arr_options; 357 | rrd_args *argv; 358 | 359 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "pa", &filename, 360 | &filename_length, &zv_arr_options) == FAILURE) { 361 | return; 362 | } 363 | 364 | if (!zend_hash_num_elements(Z_ARRVAL_P(zv_arr_options))) { 365 | zend_error(E_WARNING, "options array mustn't be empty"); 366 | RETURN_FALSE; 367 | } 368 | 369 | if (php_check_open_basedir(filename)) RETURN_FALSE; 370 | 371 | argv = rrd_args_init_by_phparray("tune", filename, zv_arr_options); 372 | if (!argv) { 373 | zend_error(E_WARNING, "cannot allocate arguments options"); 374 | RETURN_FALSE; 375 | } 376 | 377 | if (rrd_test_error()) rrd_clear_error(); 378 | 379 | /* call rrd_tune and test if fails */ 380 | if (rrd_tune(argv->count-1, &argv->args[1]) == -1 ) { 381 | RETVAL_FALSE; 382 | } else { 383 | RETVAL_TRUE; 384 | } 385 | rrd_args_free(argv); 386 | } 387 | /* }}} */ 388 | 389 | /* {{{ proto array rrd_xport(array options) 390 | * Creates a graph based on options passed via an array 391 | */ 392 | PHP_FUNCTION(rrd_xport) 393 | { 394 | zval *zv_arr_options; 395 | rrd_args *argv; 396 | /* return values from rrd_xport */ 397 | int xxsize; 398 | time_t start, end, time_index; 399 | zend_ulong step, outvar_count; 400 | char **legend_v; 401 | rrd_value_t *data, *data_ptr; 402 | zval zv_data; 403 | zend_ulong outvar_index; 404 | 405 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &zv_arr_options) == FAILURE) { 406 | return; 407 | } 408 | 409 | argv = rrd_args_init_by_phparray("xport", "", zv_arr_options); 410 | if (!argv) { 411 | zend_error(E_WARNING, "cannot allocate arguments options"); 412 | RETURN_FALSE; 413 | } 414 | 415 | if (rrd_test_error()) rrd_clear_error(); 416 | 417 | /* call rrd_xport and test if fails */ 418 | if (rrd_xport(argv->count-1, &argv->args[1], &xxsize, &start, &end, &step, 419 | &outvar_count, &legend_v, &data) == -1) { 420 | php_printf("rrd_xport failed"); 421 | rrd_args_free(argv); 422 | RETURN_FALSE; 423 | } 424 | 425 | rrd_args_free(argv); 426 | 427 | /* fill rrd_xport return values into array */ 428 | array_init(return_value); 429 | 430 | add_assoc_long(return_value, "start", start + step); 431 | add_assoc_long(return_value, "end", end); 432 | add_assoc_long(return_value, "step", step); 433 | 434 | /* no data available */ 435 | if (!data) { 436 | add_assoc_null(return_value, "data"); 437 | return; 438 | } 439 | 440 | array_init(&zv_data); 441 | 442 | for (outvar_index = 0; outvar_index < outvar_count; outvar_index++) { 443 | /* array for a whole one output variable data, it contains indexes 444 | * array( 445 | * "legend" => "variable legend", 446 | * "data" => array( 447 | * 920807400 => 0.14, 448 | * 920807800 => 21, 449 | * ... 450 | * )) 451 | */ 452 | zval zv_var_data, time_data; 453 | array_init(&zv_var_data); 454 | array_init(&time_data); 455 | 456 | add_assoc_string(&zv_var_data, "legend", legend_v[outvar_index]); 457 | free(legend_v[outvar_index]); 458 | 459 | data_ptr = data + outvar_index; 460 | for (time_index = start + step; time_index <= end; time_index += step) { 461 | /* value for key (timestamp) in data array */ 462 | char str_timestamp[11]; 463 | ZEND_LTOA((zend_ulong)time_index, str_timestamp, sizeof(str_timestamp)); 464 | 465 | add_assoc_double(&time_data, str_timestamp, *data_ptr); 466 | data_ptr += outvar_count; 467 | } 468 | add_assoc_zval(&zv_var_data, "data", &time_data); 469 | add_next_index_zval(&zv_data, &zv_var_data); 470 | } 471 | add_assoc_zval(return_value, "data", &zv_data); 472 | free(legend_v); 473 | free(data); 474 | } 475 | /* }}} */ 476 | 477 | #ifdef HAVE_RRDC_DISCONNECT 478 | /* {{{ proto void rrdc_disconnect() 479 | * Close any outstanding connection to rrd cache daemon. 480 | */ 481 | PHP_FUNCTION(rrdc_disconnect) 482 | { 483 | if (zend_parse_parameters_none() == FAILURE) { 484 | return; 485 | } 486 | 487 | rrdc_disconnect(); 488 | } 489 | #endif 490 | 491 | /* {{{ proto string rrd_version() 492 | * Gets version of underlying librrd. 493 | */ 494 | PHP_FUNCTION(rrd_version) 495 | { 496 | if (zend_parse_parameters_none() == FAILURE) { 497 | return; 498 | } 499 | 500 | RETVAL_STRING(rrd_strversion()); 501 | } 502 | 503 | /* {{{ arguments */ 504 | ZEND_BEGIN_ARG_INFO(arginfo_rrd_fetch, 0) 505 | ZEND_ARG_INFO(0, file) 506 | ZEND_ARG_INFO(0, options) 507 | ZEND_END_ARG_INFO() 508 | 509 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rrd_first, 0, 0, 1) 510 | ZEND_ARG_INFO(0, file) 511 | ZEND_ARG_INFO(0, raaindex) 512 | ZEND_END_ARG_INFO() 513 | 514 | ZEND_BEGIN_ARG_INFO(arginfo_rrd_last, 0) 515 | ZEND_ARG_INFO(0, file) 516 | ZEND_END_ARG_INFO() 517 | 518 | ZEND_BEGIN_ARG_INFO(arginfo_rrd_lastupdate, 0) 519 | ZEND_ARG_INFO(0, file) 520 | ZEND_END_ARG_INFO() 521 | 522 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rrd_restore, 0, 0, 2) 523 | ZEND_ARG_INFO(0, xml_file) 524 | ZEND_ARG_INFO(0, rrd_file) 525 | ZEND_ARG_INFO(0, options) 526 | ZEND_END_ARG_INFO() 527 | 528 | ZEND_BEGIN_ARG_INFO(arginfo_rrd_tune, 0) 529 | ZEND_ARG_INFO(0, file) 530 | ZEND_ARG_INFO(0, options) 531 | ZEND_END_ARG_INFO() 532 | 533 | ZEND_BEGIN_ARG_INFO(arginfo_rrd_xport, 0) 534 | ZEND_ARG_INFO(0, options) 535 | ZEND_END_ARG_INFO() 536 | 537 | ZEND_BEGIN_ARG_INFO(arginfo_rrd_info, 0) 538 | ZEND_ARG_INFO(0, file) 539 | ZEND_END_ARG_INFO() 540 | 541 | ZEND_BEGIN_ARG_INFO(arginfo_rrd_graph, 0) 542 | ZEND_ARG_INFO(0, file) 543 | ZEND_ARG_INFO(0, options) 544 | ZEND_END_ARG_INFO() 545 | 546 | ZEND_BEGIN_ARG_INFO(arginfo_rrd_create, 0) 547 | ZEND_ARG_INFO(0, filename) 548 | ZEND_ARG_INFO(0, options) 549 | ZEND_END_ARG_INFO() 550 | 551 | ZEND_BEGIN_ARG_INFO(arginfo_rrd_update, 0) 552 | ZEND_ARG_INFO(0, file) 553 | ZEND_ARG_INFO(0, options) 554 | ZEND_END_ARG_INFO() 555 | 556 | ZEND_BEGIN_ARG_INFO(arginfo_rrd_void, 0) 557 | ZEND_END_ARG_INFO() 558 | /* }}} */ 559 | 560 | /* {{{ */ 561 | static zend_function_entry rrd_functions[] = { 562 | PHP_FE(rrd_update, arginfo_rrd_update) 563 | PHP_FE(rrd_create, arginfo_rrd_create) 564 | PHP_FE(rrd_graph, arginfo_rrd_graph) 565 | PHP_FE(rrd_error, arginfo_rrd_void) 566 | PHP_FE(rrd_fetch, arginfo_rrd_fetch) 567 | PHP_FE(rrd_first, arginfo_rrd_first) 568 | PHP_FE(rrd_info, arginfo_rrd_info) 569 | PHP_FE(rrd_last, arginfo_rrd_last) 570 | PHP_FE(rrd_lastupdate, arginfo_rrd_lastupdate) 571 | PHP_FE(rrd_restore, arginfo_rrd_restore) 572 | PHP_FE(rrd_tune, arginfo_rrd_tune) 573 | PHP_FE(rrd_xport, arginfo_rrd_xport) 574 | #ifdef HAVE_RRDC_DISCONNECT 575 | PHP_FE(rrdc_disconnect, arginfo_rrd_void) 576 | #endif 577 | PHP_FE(rrd_version, arginfo_rrd_void) 578 | PHP_FE_END 579 | }; 580 | /* }}} */ 581 | 582 | #ifdef COMPILE_DL_RRD 583 | ZEND_GET_MODULE(rrd) 584 | #endif 585 | 586 | /* {{{ PHP_MINIT_FUNCTION */ 587 | static PHP_MINIT_FUNCTION(rrd) 588 | { 589 | rrd_graph_minit(); 590 | rrd_create_minit(); 591 | rrd_update_minit(); 592 | return SUCCESS; 593 | } 594 | /* }}} */ 595 | 596 | /* {{{ PHP_MINFO_FUNCTION */ 597 | static PHP_MINFO_FUNCTION(rrd) 598 | { 599 | php_info_print_table_start(); 600 | php_info_print_table_header(2, "rrd tool module", "enabled"); 601 | php_info_print_table_row(2, "rrd tool module version", PHP_RRD_VERSION); 602 | php_info_print_table_row(2, "rrdtool library version", rrd_strversion()); 603 | php_info_print_table_end(); 604 | } 605 | /* }}} */ 606 | 607 | 608 | /* {{{ PHP_MSHUTDOWN_FUNCTION */ 609 | static PHP_MSHUTDOWN_FUNCTION(rrd) 610 | { 611 | #ifdef HAVE_RRDC_DISCONNECT 612 | /* ensure that any connection to rrd cache deamon will be closed */ 613 | rrdc_disconnect(); 614 | #endif 615 | return SUCCESS; 616 | } 617 | /* }}} */ 618 | 619 | /* {{{ rrd module_entry */ 620 | zend_module_entry rrd_module_entry = { 621 | STANDARD_MODULE_HEADER, 622 | "rrd", 623 | rrd_functions, 624 | PHP_MINIT(rrd), 625 | PHP_MSHUTDOWN(rrd), 626 | NULL, /* PHP_RINIT(rrd) */ 627 | NULL, /* PHP_RSHUTDOWN(rrd) */ 628 | PHP_MINFO(rrd), 629 | PHP_RRD_VERSION, 630 | STANDARD_MODULE_PROPERTIES 631 | }; 632 | /* }}} */ 633 | 634 | /* {{{ Inits rrd arguments object for a particular rrd command by php array 635 | * filename paremeter is optional. 636 | */ 637 | rrd_args *rrd_args_init_by_phparray(const char *command_name, const char *filename, 638 | const zval *options) 639 | { 640 | unsigned i, option_count, args_counter = 2; 641 | rrd_args *result; 642 | 643 | if (Z_TYPE_P(options) != IS_ARRAY) return NULL; 644 | option_count = zend_hash_num_elements(Z_ARRVAL_P(options)); 645 | if (!option_count) return NULL; 646 | if (!strlen(command_name)) return NULL; 647 | 648 | result = (rrd_args *)emalloc(sizeof(rrd_args)); 649 | /* "dummy" + command_name + filename if presented */ 650 | result->count = option_count + (strlen(filename) ? 3 : 2); 651 | result->args = (char **)safe_emalloc(result->count, sizeof(char *), 0); 652 | 653 | /* "dummy" and command_name are always needed */ 654 | result->args[0] = "dummy"; 655 | result->args[1] = estrdup(command_name); 656 | 657 | /* append filename if it's presented */ 658 | if (strlen(filename)) result->args[args_counter++] = estrdup(filename); 659 | 660 | zend_hash_internal_pointer_reset(Z_ARRVAL_P(options)); 661 | for (i=0; i < option_count; i++) { 662 | zval *item; 663 | smart_string option = {0}; /* one argument option */ 664 | 665 | /* force using strings as array items */ 666 | item = zend_hash_get_current_data(Z_ARRVAL_P(options)); 667 | if (Z_TYPE_P(item) != IS_STRING) convert_to_string(item); 668 | smart_string_appendl(&option, Z_STRVAL_P(item), Z_STRLEN_P(item)); 669 | smart_string_0(&option); 670 | 671 | result->args[args_counter++] = estrdup(option.c); 672 | smart_string_free(&option); 673 | 674 | zend_hash_move_forward(Z_ARRVAL_P(options)); 675 | } 676 | 677 | return result; 678 | } 679 | /* }}} */ 680 | 681 | /* {{{ Frees all memory for arguments object 682 | */ 683 | void rrd_args_free(rrd_args *args) 684 | { 685 | int i; 686 | if (!args || !args->args) return; 687 | 688 | for (i = 1; i < args->count; i++) { 689 | efree(args->args[i]); 690 | } 691 | 692 | efree(args->args); 693 | efree(args); 694 | } 695 | /* }}} */ 696 | --------------------------------------------------------------------------------