{"id":352,"date":"2009-07-22T20:11:25","date_gmt":"2009-07-22T18:11:25","guid":{"rendered":"http:\/\/blog.benny-baumann.de\/?p=352"},"modified":"2009-07-22T20:24:55","modified_gmt":"2009-07-22T18:24:55","slug":"rrdtool-fur-php","status":"publish","type":"post","link":"https:\/\/blog.benny-baumann.de\/?p=352","title":{"rendered":"RRDTool f\u00fcr PHP"},"content":{"rendered":"<p>Mehr oder weniger aus eigenem Interesse habe ich die Tage einmal nach einer M\u00f6glichkeit gesucht, die Funktionalit\u00e4t von Mailgraph und Bindgraph, die auf meinem Webspace werkeln, mit einem eigenen PHP-Skript nutzen zu k\u00f6nnen. Diese Scripte nutzen beide <a href=\"http:\/\/oss.oetiker.ch\/rrdtool\/\">RRDTool<\/a>, also so ziemlich der Standard in dieser Hinsicht. Bindings sind auch f\u00fcr Python und Perl vorhanden &#8211; jedoch f\u00fcr PHP gibt es kein offizielles. Durch einen Blogeintrag bei <a href=\"http:\/\/www.ioncannon.net\/system-administration\/59\/php-rrdtool-tutorial\/\">IONCANNON<\/a>, der zugleich eine einfache Einf\u00fchrung in die Nutzung gibt, bin ich auf einen etwas \u00e4lteren Versuch aufmerksam geworden, mit dem jemand eine solche M\u00f6glichkeit geschaffen hat.<!--more--><\/p>\n<p>Da jedoch die Links, die zu der an vielen Stellen erw\u00e4hnten Extension f\u00fchrten, oftmals nicht mehr funktionierten, brachte mich erst ein <a href=\"https:\/\/lists.oetiker.ch\/pipermail\/rrd-users\/2008-August\/014536.html\">Beitrag einer Mailingliste<\/a> (dessen Link auch inkorrekt ist), auf die richtige Spur: Unter <a href=\"http:\/\/oss.oetiker.ch\/rrdtool\/pub\/contrib\/\">http:\/\/oss.oetiker.ch\/rrdtool\/pub\/contrib\/<\/a> wird man mit der Datei <a href=\"http:\/\/oss.oetiker.ch\/rrdtool\/pub\/contrib\/php_rrdtool.tar.gz\">php_rrdtool.tar.gz<\/a> f\u00fcndig. Deren Installation wird wiederum beim <a href=\"http:\/\/www.prbproject.org\/?p=docs\">PRB-Projekt<\/a> recht anschaulich beschrieben. Jedoch sollte man nicht voreilig sein, da mir beim betrachten des Sources ein paar potenzielle Stolpersteine aufgefallen sind. Dazu aber gleich mehr.<\/p>\n<p>Wo wir gerade die Dokumentation angesprochen haben: Wer einen Blick auf den oben genannten Blog-Eintrag geworfen hat, wird festgestellt haben, dass dort mehrfach ein Array mit kryptischen Argumenten definiert wurde. Wer RRDTool kennt, dem werden diese Angaben sicherlich bekannt vorkommen; wer sich aber unsicher f\u00fchlt, kann einen Blick in die <a href=\"http:\/\/oss.oetiker.ch\/rrdtool\/tut\/rrdtutorial.en.html\">Original-Dokumentation von RRDTool<\/a> werfen, die mit einer sehr guten Einf\u00fchrung in die Thematik aufwartet.<\/p>\n<p>Aber wie es immer so mit Tutorials ist: Irgendwas m\u00f6chte immer nicht \ud83d\ude09 Und genau das war bei mir gestern der Fall, als ich die Demos aus dem oben erw\u00e4hnten Tutorial versuch habe. Je mehr ich versucht habe, desto bizarrer die Fehlermeldungen. Dass die Steps-Size nicht 0 sein darf, obwohl &#8211;step 300 angegeben war, war da noch eher das Harmloseste in der Sammlung der Fehlermeldungen. Aber mit etwas Trial&amp;Error war auch dies zu bewerkstelligen. Am Ende fielen aus meinem Editor 3 funktionierende PHP-Dateien rrdc.php, rrdu.php und rrdg.php:<\/p>\n<p>rrdc.php:<\/p>\n<pre lang=\"php\" escaped=\"true\">&lt;?php\r\n\r\n$fname = \"net.rrd\";\r\n\r\n$opts = array(\r\n  \"--step\", \"300\", \"--start\", \"0\",\r\n  \"DS:input:COUNTER:600:U:U\",\r\n  \"DS:output:COUNTER:600:U:U\",\r\n  \"RRA:AVERAGE:0.5:1:600\",\r\n  \"RRA:AVERAGE:0.5:6:700\",\r\n  \"RRA:AVERAGE:0.5:24:775\",\r\n  \"RRA:AVERAGE:0.5:288:797\",\r\n  \"RRA:MAX:0.5:1:600\",\r\n  \"RRA:MAX:0.5:6:700\",\r\n  \"RRA:MAX:0.5:24:775\",\r\n  \"RRA:MAX:0.5:288:797\"\r\n  );\r\n\r\n$ret = rrd_create($fname, $opts, count($opts));\r\n\r\nif( !$ret )\r\n{\r\n  $err = rrd_error();\r\n  echo \"Create error: $err\\n\";\r\n}\r\n\r\n?&gt;<\/pre>\n<p>rrdu.php:<\/p>\n<pre lang=\"php\" escaped=\"true\">&lt;?php\r\n\r\n$fname = \"net.rrd\";\r\n\r\n$total_input_traffic = 0;\r\n$total_output_traffic = 0;\r\n\r\n$t = time();\r\n\r\nwhile($t &lt; time()+86400)\r\n{\r\n  $total_input_traffic += rand(100000, 1500000);\r\n  $total_output_traffic += rand(100000, 3000000);\r\n\r\n  $t += 300;\r\n  echo $t . \": \" . $total_input_traffic . \" and \" . $total_output_traffic . \"\\n\";\r\n\r\n  $ret = rrd_update($fname, \"$t:$total_input_traffic:$total_output_traffic\");\r\n\r\n  if( !$ret )\r\n  {\r\n    $err = rrd_error();\r\n    echo \"ERROR occurred: $err\\n\";\r\n  }\r\n\r\n}\r\n\r\n?&gt;<\/pre>\n<p>rrdg.php:<\/p>\n<pre lang=\"php\" escaped=\"true\">&lt;?php\r\n\r\n$opts = array(\r\n  \"-s-1d\",\r\n  \"-e+1d\",\r\n  \/\/\"-\u2013vertical-label=B\/s\",\r\n  \"DEF:inoctets=net.rrd:input:AVERAGE\",\r\n  \"DEF:outoctets=net.rrd:output:AVERAGE\",\r\n  \"AREA:inoctets#00FF00:In traffic\",\r\n  \"LINE1:outoctets#0000FF:Out traffic\",\r\n  \"CDEF:inbits=inoctets,8,*\",\r\n  \"CDEF:outbits=outoctets,8,*\",\r\n  \"COMMENT: \",\r\n  \"GPRINT:inbits:AVERAGE:Avg In traffic\\: %6.2lf %Sbps\",\r\n  \"COMMENT: \",\r\n  \"GPRINT:inbits:MAX:Max In traffic\\: %6.2lf %Sbps\",\r\n  \"GPRINT:outbits:AVERAGE:Avg Out traffic\\: %6.2lf %Sbps\",\r\n  \"COMMENT: \",\r\n  \"GPRINT:outbits:MAX:Max Out traffic\\: %6.2lf %Sbps\"\r\n  );\r\n\r\n$ret = rrd_graph(\"net_1d.gif\", $opts, count($opts));\r\n\r\nif( !is_array($ret) ) {\r\n  $err = rrd_error();\r\n  echo \"rrd_graph() ERROR: $err\\n\";\r\n} else {\r\n  print_r($ret);\r\n}<\/pre>\n<p>W\u00e4hrend rrdc.php das Erzeugen eines Round-Robin-Archives demonstriert und genauso wie rrdg.php (Ausgabe als Grafik) bis auf kleinere Bugfixes mit dem Original identisch ist, ist rrdu.php eine Version des Originals f\u00fcr Ungeduldige, die mal eben f\u00fcr 24h ein paar Daten generiert. Der Rest bleibt aber mit den Code-Vorlagen identisch und darf daher in der urspr\u00fcnglichen Anleitung nachgeschlagen werden.<\/p>\n<p>Wie oben erw\u00e4hnt, gab es nun noch ein paar Probleme mit der Extension selbst. Neben einem mehr oder weniger geringf\u00fcgigen Schreibfehler in der Infoseite der Extension und einer Reihe deplazierter Spaces fiel mir das Fehlen der Pr\u00fcfungen f\u00fcr die open_basedir Restriction auf. Diese sollte man sich (mit den anderen \u00c4nderungen) mit folgendem Patch vor dem Installieren der Extension einpflegen:<\/p>\n<pre lang=\"diff\" escaped=\"true\">\r\n--- rrdtool.c\t2005-12-03 13:34:06.000000000 +0000\r\n+++ rrdtool.c\t2009-07-22 16:49:47.000000000 +0000\r\n@@ -12,6 +12,9 @@\r\n  *       Jeffrey Wheat &lt;jeff@cetlink.net&gt; - 10\/01\/2002\r\n  *       - Fixed to build with php-4.2.3\r\n  *\r\n+ *       Benny Baumann &lt;BenBE@geshi.org&gt; - 07\/22\/2009\r\n+ *       - Added open_basedir checks\r\n+ *\r\n  * See README, INSTALL, and USAGE files for more details.\r\n  *\r\n  * $Id: rrdtool.c,v 1.1.1.1 2002\/02\/26 10:21:20 oetiker Exp $\r\n@@ -40,13 +43,13 @@\r\n  *\/\r\n\r\n function_entry rrdtool_functions[] = {\r\n-\tPHP_FE(rrd_graph,\t\t\t\tNULL)\r\n-\tPHP_FE(rrd_fetch,\t\t\t\tNULL)\r\n-\tPHP_FE(rrd_error,\t\t\t\tNULL)\r\n+\tPHP_FE(rrd_graph,\t\t\tNULL)\r\n+\tPHP_FE(rrd_fetch,\t\t\tNULL)\r\n+\tPHP_FE(rrd_error,\t\t\tNULL)\r\n \tPHP_FE(rrd_clear_error,\t\t\tNULL)\r\n-\tPHP_FE(rrd_update,\t\t\t\tNULL)\r\n-\tPHP_FE(rrd_last,\t\t\t\tNULL)\r\n-\tPHP_FE(rrd_create,\t\t\t\tNULL)\r\n+\tPHP_FE(rrd_update,\t\t\tNULL)\r\n+\tPHP_FE(rrd_last,\t\t\tNULL)\r\n+\tPHP_FE(rrd_create,\t\t\tNULL)\r\n \tPHP_FE(rrdtool_info,\t\t\tNULL)\r\n \tPHP_FE(rrdtool_logo_guid,\t\tNULL)\r\n \t{NULL, NULL, NULL}\r\n@@ -86,8 +89,8 @@\r\n \/* {{{ PHP_MINIT_FUNCTION *\/\r\n PHP_MINIT_FUNCTION(rrdtool)\r\n {\r\n-\tphp_register_info_logo(RRDTOOL_LOGO_GUID   , \"image\/gif\", rrdtool_logo   , sizeof(rrdtool_logo));\r\n-\r\n+\tphp_register_info_logo(RRDTOOL_LOGO_GUID, \"image\/gif\", rrdtool_logo, sizeof(rrdtool_logo));\r\n+\r\n \treturn SUCCESS;\r\n }\r\n \/* }}} *\/\r\n@@ -96,7 +99,7 @@\r\n PHP_MSHUTDOWN_FUNCTION(rrdtool)\r\n {\r\n \tphp_unregister_info_logo(RRDTOOL_LOGO_GUID);\r\n-\r\n+\r\n \treturn SUCCESS;\r\n }\r\n \/* }}} *\/\r\n@@ -109,7 +112,7 @@\r\n \tif (SG(request_info).request_uri) {\r\n \t\tPUTS(SG(request_info).request_uri);\r\n \t}\r\n-\tPUTS(\"?=\"RRDTOOL_LOGO_GUID\"\\\" alt=\\\"ClamAV logo\\\" \/&gt;&lt;\/a&gt;\\n\");\r\n+\tPUTS(\"?=\"RRDTOOL_LOGO_GUID\"\\\" alt=\\\"RRDTool logo\\\" \/&gt;&lt;\/a&gt;\\n\");\r\n \tphp_printf(\"&lt;h1 class=\\\"p\\\"&gt;rrdtool Version %s&lt;\/h1&gt;\\n\", PHP_RRD_VERSION_STRING);\r\n \tphp_info_print_box_end();\r\n \tphp_info_print_table_start();\r\n@@ -129,25 +132,29 @@\r\n \tint i, xsize, ysize, argc;\r\n \tdouble ymin,ymax;\r\n \tchar **argv, **calcpr;\r\n-\r\n\r\n \tif ( rrd_test_error() )\r\n \t\trrd_clear_error();\r\n-\r\n+\r\n \tif ( (ZEND_NUM_ARGS() &gt;= 3 &amp;&amp; ZEND_NUM_ARGS() &lt;= 6) &amp;&amp; zend_get_parameters(ht, 3, &amp;file, &amp;args, &amp;p_argc) == SUCCESS)\r\n \t{\r\n \t\tif ( args-&gt;type != IS_ARRAY )\r\n-\t\t{\r\n+\t\t{\r\n \t\t\tphp_error(E_WARNING, \"2nd Variable passed to rrd_graph is not an array!\\n\");\r\n \t\t\tRETURN_FALSE;\r\n \t\t}\r\n-\r\n+\r\n \t\tconvert_to_long(p_argc);\r\n \t\tconvert_to_string(file);\r\n\r\n \t\tconvert_to_array(args);\r\n \t\targs_arr = args-&gt;value.ht;\r\n\r\n+\t\t\/\/BenBE: Added Basedir Restriction ...\r\n+\t\tif (php_check_open_basedir(file TSRMLS_CC)) {\r\n+\t\t\tRETURN_FALSE;\r\n+\t\t}\r\n+\r\n \t\targc = p_argc-&gt;value.lval + 3;\r\n \t\targv = (char **) emalloc(argc * sizeof(char *));\r\n\r\n@@ -210,7 +217,7 @@\r\n \t\tefree(argv);\r\n \t}\r\n \telse\r\n-\t{\r\n+\t{\r\n \t\tWRONG_PARAM_COUNT;\r\n \t}\r\n \treturn;\r\n@@ -229,30 +236,35 @@\r\n \tint i, j, argc;\r\n \ttime_t start, end;\r\n \tunsigned long step, ds_cnt;\r\n-\tchar **argv, **ds_namv;\r\n+\tchar **argv, **ds_namv;\r\n \trrd_value_t *data, *datap;\r\n-\r\n+\r\n \tif ( rrd_test_error() )\r\n \t\trrd_clear_error();\r\n-\r\n-\tif ( ZEND_NUM_ARGS() == 3 &amp;&amp;\r\n-\t\t zend_get_parameters(ht, 3, &amp;file, &amp;args, &amp;p_argc) == SUCCESS)\r\n+\r\n+\tif ( ZEND_NUM_ARGS() == 3 &amp;&amp;\r\n+\t\tzend_get_parameters(ht, 3, &amp;file, &amp;args, &amp;p_argc) == SUCCESS)\r\n \t{\r\n \t\tif ( args-&gt;type != IS_ARRAY )\r\n-\t\t{\r\n+\t\t{\r\n \t\t\tphp_error(E_WARNING, \"2nd Variable passed to rrd_fetch is not an array!\\n\");\r\n \t\t\tRETURN_FALSE;\r\n \t\t}\r\n-\r\n+\r\n \t\tconvert_to_long(p_argc);\r\n \t\tconvert_to_string(file);\r\n\r\n \t\tconvert_to_array(args);\r\n \t\targs_arr = args-&gt;value.ht;\r\n\r\n+\t\t\/\/BenBE: Added Basedir Restriction ...\r\n+\t\tif (php_check_open_basedir(file TSRMLS_CC)) {\r\n+\t\t\tRETURN_FALSE;\r\n+\t\t}\r\n+\r\n \t\targc = p_argc-&gt;value.lval + 3;\r\n \t\targv = (char **) emalloc(argc * sizeof(char *));\r\n-\r\n+\r\n \t\targv[0] = \"dummy\";\r\n \t\targv[1] = estrdup(\"fetch\");\r\n \t\targv[2] = estrdup(file-&gt;value.str.val);\r\n@@ -274,7 +286,7 @@\r\n \t\t\tif ( i &lt; argc )\r\n \t\t\t\tzend_hash_move_forward(args_arr);\r\n \t\t}\r\n-\r\n+\r\n \t\toptind = 0; opterr = 0;\r\n\r\n \t\tif ( rrd_fetch(argc-1, &amp;argv[1], &amp;start,&amp;end,&amp;step,&amp;ds_cnt,&amp;ds_namv,&amp;data) != -1 )\r\n@@ -303,11 +315,11 @@\r\n \t\t\tif (data)\r\n \t\t\t{\r\n \t\t\t\tdatap = data;\r\n-\r\n+\r\n \t\t\t\tfor (i = start; i &lt;= end; i += step)\r\n \t\t\t\t\tfor (j = 0; j &lt; ds_cnt; j++)\r\n \t\t\t\t\t\tadd_next_index_double(p_data, *(datap++));\r\n-\r\n+\r\n \t\t\t\tfree(data);\r\n \t\t\t}\r\n\r\n@@ -326,7 +338,7 @@\r\n \t\tefree(argv);\r\n \t}\r\n \telse\r\n-\t{\r\n+\t{\r\n \t\tWRONG_PARAM_COUNT;\r\n \t}\r\n \treturn;\r\n@@ -341,8 +353,7 @@\r\n\r\n \tif ( rrd_test_error() )\r\n \t{\r\n-\t\tmsg = rrd_get_error();\r\n-\r\n+\t\tmsg = rrd_get_error();\r\n \t\tRETVAL_STRING(msg, 1);\r\n \t\trrd_clear_error();\r\n \t}\r\n@@ -372,12 +383,17 @@\r\n \tif ( rrd_test_error() )\r\n \t\trrd_clear_error();\r\n\r\n-\tif ( ZEND_NUM_ARGS() == 2 &amp;&amp;\r\n-\t\t zend_get_parameters(ht, 2, &amp;file, &amp;opt) == SUCCESS )\r\n+\tif ( ZEND_NUM_ARGS() == 2 &amp;&amp;\r\n+\t\tzend_get_parameters(ht, 2, &amp;file, &amp;opt) == SUCCESS )\r\n \t{\r\n \t\tconvert_to_string(file);\r\n \t\tconvert_to_string(opt);\r\n\r\n+\t\t\/\/BenBE: Added Basedir Restriction ...\r\n+\t\tif (php_check_open_basedir(file TSRMLS_CC)) {\r\n+\t\t\tRETURN_FALSE;\r\n+\t\t}\r\n+\r\n \t\targv = (char **) emalloc(4 * sizeof(char *));\r\n\r\n \t\targv[0] = \"dummy\";\r\n@@ -413,14 +429,19 @@\r\n \tunsigned long retval;\r\n\r\n \tchar **argv = (char **) emalloc(3 * sizeof(char *));\r\n-\r\n+\r\n \tif ( rrd_test_error() )\r\n \t\trrd_clear_error();\r\n-\r\n+\r\n \tif (zend_get_parameters(ht, 1, &amp;file) == SUCCESS)\r\n \t{\r\n \t\tconvert_to_string(file);\r\n\r\n+\t\t\/\/BenBE: Added Basedir Restriction ...\r\n+\t\tif (php_check_open_basedir(file TSRMLS_CC)) {\r\n+\t\t\tRETURN_FALSE;\r\n+\t\t}\r\n+\r\n \t\targv[0] = \"dummy\";\r\n \t\targv[1] = estrdup(\"last\");\r\n \t\targv[2] = estrdup(file-&gt;value.str.val);\r\n@@ -453,7 +474,7 @@\r\n \tif ( rrd_test_error() )\r\n \t\trrd_clear_error();\r\n\r\n-\tif ( ZEND_NUM_ARGS() == 3 &amp;&amp;\r\n+\tif ( ZEND_NUM_ARGS() == 3 &amp;&amp;\r\n \t\tgetParameters(ht, 3, &amp;file, &amp;args, &amp;p_argc) == SUCCESS )\r\n \t{\r\n \t\tif ( args-&gt;type != IS_ARRAY )\r\n@@ -464,11 +485,16 @@\r\n\r\n \t\tconvert_to_long(p_argc);\r\n \t\tconvert_to_string(file);\r\n-\r\n+\r\n \t\tconvert_to_array(args);\r\n \t\targs_arr = args-&gt;value.ht;\r\n \t\tzend_hash_internal_pointer_reset(args_arr);\r\n\r\n+\t\t\/\/BenBE: Added Basedir Restriction ...\r\n+\t\tif (php_check_open_basedir(file TSRMLS_CC)) {\r\n+\t\t\tRETURN_FALSE;\r\n+\t\t}\r\n+\r\n \t\targc = p_argc-&gt;value.lval + 3;\r\n \t\targv = (char **) emalloc(argc * sizeof(char *));\r\n\r\n@@ -493,10 +519,10 @@\r\n \t\t\tif ( i &lt; argc )\r\n \t\t\t\tzend_hash_move_forward(args_arr);\r\n \t\t}\r\n-\r\n+\r\n \t\toptind = 0;  opterr = 0;\r\n\r\n-\t\tif ( rrd_create(argc-1, &amp;argv[1]) != -1 )\r\n+\t\tif ( rrd_create(argc - 1, &amp;argv[1]) != -1 )\r\n \t\t{\r\n \t\t\tRETVAL_TRUE;\r\n \t\t}\r\n@@ -511,7 +537,7 @@\r\n \t}\r\n \telse\r\n \t{\r\n-\t    WRONG_PARAM_COUNT;\r\n+\t\tWRONG_PARAM_COUNT;\r\n \t}\r\n \treturn;\r\n }<\/pre>\n<p><a href=\"http:\/\/blog.benny-baumann.de\/wp-content\/uploads\/rrdtool.benbe.patch\">Dieser Patch<\/a> f\u00fcgt f\u00fcr die wichtigsten Dateioperationen eine Basedir-Pr\u00fcfung hinzu; <strong>was er jedoch nicht pr\u00fcft, sind Pfadangaben innerhalb der Argumente!<\/strong> Nach dem man diesen Patch erfolgreich angewendet hat, erfolgt die Installation wie folgt:<\/p>\n<pre lang=\"bash\" escaped=\"true\">phpize5\r\n.\/configure\r\nmake\r\nmake install<\/pre>\n<p>Wenn dies erfolgreich durchl\u00e4uft (librrd4-dev und die anderen Header sind auffindbar), kann man die oben erw\u00e4hnten Scripts ausprobieren. Jetzt fehlt nur noch ein Wrapper, der einem erspart, st\u00e4ndig diese kryptischen Arrays zu schreiben &#8230;<\/p>\n<p class=\"wp-flattr-button\"><a href=\"https:\/\/blog.benny-baumann.de\/?flattrss_redirect&amp;id=352&amp;md5=6490d612fb490f4a73c405243f783f8e\" title=\"Flattr\" target=\"_blank\"><img src=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" srcset=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" alt=\"Flattr this!\"\/><\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Mehr oder weniger aus eigenem Interesse habe ich die Tage einmal nach einer M\u00f6glichkeit gesucht, die Funktionalit\u00e4t von Mailgraph und Bindgraph, die auf meinem Webspace werkeln, mit einem eigenen PHP-Skript nutzen zu k\u00f6nnen. Diese Scripte nutzen beide RRDTool, also so ziemlich der Standard in dieser Hinsicht. Bindings sind auch f\u00fcr Python und Perl vorhanden &#8211; [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[29],"tags":[224,98,154,13,21,223],"class_list":["post-352","post","type-post","status-publish","format-standard","hentry","category-software","tag-bindgraph","tag-developement","tag-mailgraph","tag-patch","tag-php","tag-rrdtool"],"_links":{"self":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/352","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=352"}],"version-history":[{"count":6,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/352\/revisions"}],"predecessor-version":[{"id":359,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/352\/revisions\/359"}],"wp:attachment":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=352"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=352"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=352"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}