本文使用PHP实现了一种与Google GraphViz Charts参数兼容的API,相较于Google GraphViz Charts API的优点是支持中文。
Contents
环境搭建
基于Debian,需要安装GraphViz及gd库
apt-get install php5 apt-get install graphviz apt-get install php5-gd
root@server1:/var/www/gv# dot -V dot - graphviz version 2.26.3 (20100126.1600)
API代码
<?php
/**
* graphviz api
*
* $Id api.php i@annhe.net 2015-6-8 $
**/
$host = $_SERVER['HTTP_HOST'];
$siteurl = "http://" . $host . "/gv/";
$cht = "dot";
$chl = "graph {fontname=\"SimSun\";node[shape=box];a[label=\"nothing to do~\"];}";
$error = "error.png";
$engine = array("dot", "neato", "fdp", "sfdp", "twopi", "circo");
$imgtype = "png";
$imgtype_arr = array("png", "gif", "jpeg");
if(isset($_GET['cht'])) {
$cht = $_GET['cht'];
$arr = explode(':', $cht);
if(!array_key_exists("1", $arr)) {
$cht = "dot";
} else {
$cht = $arr['1'];
}
if(!in_array($cht, $engine)) {
$cht = "dot";
}
}
if(isset($_GET['chl'])) {
$chl = $_GET['chl'];
}
if(isset($_GET['chof'])) {
$imgtype = $_GET['chof'];
if(!in_array($imgtype, $imgtype_arr)) {
$imgtype = "png";
}
}
$gvname = md5($chl) . $cht;
$gvpath = "./gv/" . $gvname . ".gv";
$imgpath = "img/" . $gvname . "." . $imgtype;
$file = fopen("$gvpath", "w");
$encode = mb_detect_encoding($chl, array("ASCII","UTF-8","GB2312", "GBK", "EUC-CN"));
if($encode != "UTF-8") {
$chl = iconv("$encode", "UTF-8", $chl);
}
$chl = str_replace(">", ">", $chl);
$chl = str_replace("<", "<", $chl);
$chl = str_replace(""", "\"", $chl);
fwrite($file, "$chl");
fclose($file);
if(!file_exists($imgpath)) {
exec("$cht -T$imgtype $gvpath -o $imgpath",$out, $ret);
if($ret != 0) {
$imgpath = $error;
$imgtype = "png";
}
}
$imgstrout = "image$imgtype(imagecreatefrom$imgtype('$imgpath'));";
header("Content-Type: image/$imgtype; charset=UTF-8");
eval($imgstrout);
?>
演示
参数与Google GraphViz Charts一致,及
- cht=gv[:<opt_engine>] , 可选参数 , 如果没有,这默认为gv:dot。其他可用引擎有 neato twopi circo fdp sfdp (比Google GraphViz Charts多一个sfdp)
- chl=<DOT_string>, 必选参数。支持中文
- chof=<png|gif|jpeg>, 可选参数,默认为png
Discuz插件形式的演示:http://www.tecbbs.com/forum.php?mod=viewthread&tid=6724
WordPress尚未做成插件,暂时直接URL插入图片
GraphViz API演示
GraphViz中文演示
问题
直接返回图片内容
API一开始返回的是图片URL,这样程序需要有2次HTTP请求才能确定图片链接,会严重拖慢网页加载速度。因此改为直接返回图片内容,只需要一次HTTP请求。
$imgstrout = "image$imgtype(imagecreatefrom$imgtype('$imgpath'));";
header("Content-Type: image/$imgtype; charset=UTF-8");
eval($imgstrout);
eval()函数将字符串作为PHP代码来执行。
Gif not recognized问题
如果API搭建在Centos上,可能需要rpm方式安装GraphViz,yum方式的GraphViz版本太旧,不支持gif输出。 需要安装 graphviz-gd。
[root@HADOOP-215 gv]# dot -Tgif 05acaa447bc10f15991d19580ccc0d41dot.gv -o test.gif Format: "gif" not recognized. Use one of: canon cmap cmapx cmapx_np dot eps fig gv imap imap_np ismap pic plain plain-ext pov ps ps2 svg svgz tk vml vmlz xdot xdot1.2 xdot1.4[root@HADOOP-215 gv]# yum install graphviz-gd Loaded plugins: fastestmirror, priorities Loading mirror speeds from cached hostfile ===================================================================================================================================== Package Arch Version Repository Size ===================================================================================================================================== Installing: graphviz-gd x86_64 2.38.0-1.el6 graphviz-stable 6.6 k Installing for dependencies: graphviz-plugins-gd x86_64 2.38.0-1.el6 graphviz-stable 20 k Transaction Summary ===================================================================================================================================== Install 2 Package(s) [root@HADOOP-215 gv]# dot -Tgif 05acaa447bc10f15991d19580ccc0d41dot.gv -o test.gif [root@HADOOP-215 gv]# ls 05acaa447bc10f15991d19580ccc0d41circo.gv 05acaa447bc10f15991d19580ccc0d41fdp.gv test.gif 05acaa447bc10f15991d19580ccc0d41dot.gv 76fadd7c49a49f7a08d97a34c111d534dot.gv
另外,GraphViz 的repo文件链接是:wget http://www.graphviz.org/graphviz-rhel.repo,下载之后可以直接yum安装最新稳定版本的GraphViz。
urlencode问题
dot源码需要进行urlencode,但是考虑到和Google GraphViz Charts保持一致,只进行部分字符的encode
$texcode = str_replace('#', "%23", $texcode); //'#' 需要urlencode
如果不encode,获得的dot源码不完整
digraph example3 { Server1 -> Server2 Server2 -> Server3 Server3 -> Server1 Server1 [shape=box, label="Server1\nWeb Server", fillcolo
r="
完整的代码是
digraph example3 { Server1 -> Server2 Server2 -> Server3 Server3 -> Server1 Server1 [shape=box, label="Server1\nWeb Server", fillcolo
r="#ABACBA", style=filled] Server2 [shape=triangle, label="Server2\nApp Server", fillcolor="#DDBCBC", style=filled] Server3 [shape=circle, label="Server3\nDatabase Server", fillcolor="#FFAA22",style=filled] }
中文字体问题
需要安装中文字体,否则中文将乱码,可以直接拷贝其他机器的wqy-microhei字体。
cd /usr/share/fonts/ tar zxvf wqy.tar.gz rm -f wqy.tar.gz mv usr/share/fonts/wqy-microhei/ . cd wqy-microhei/
$_GET解码问题
PHP官网明确指出:超全局变量 $_GET 和 $_REQUEST 已经被解码了。对 $_GET 或 $_REQUEST 里的元素使用 urldecode() 将会导致不可预计和危险的结果。
本文实现的API会将dot源码保持为文件,文件名使用dot源码的md5值
$gvname = md5($chl) . $cht;
由于$_GET已经经过了urldecode,所以客户端程序使用dot源码文件名时也需要urldecode,这样才能获取正确的文件名
$p = str_replace(">", ">", $texcode);
$p = str_replace("<", "<", $p);
$p = str_replace(""", "\"", $p);
$gv_md5 = md5(urldecode($p)) . $engine . ".gv";
2.38中文问题
Debian7和Centos6.5软件源里的GraphViz都是2.26版本的,目前(15年6月)最新稳定版本是2.38,手贱升级到了2.38,发现该版本子图中文显示有问题。上文演示的图片,代码如下:
digraph idp_modules{
rankdir = TB;
fontname = "Microsoft YaHei";
fontsize = 12;
node [ fontname = "Microsoft YaHei", fontsize = 12, shape = "record" ];
edge [ fontname = "Microsoft YaHei", fontsize = 12 ];
subgraph cluster_sl{
label="IDP支持层";
bgcolor="mintcream";
node [shape="Mrecord", color="skyblue", style="filled"];
network_mgr [label="网络管理器"];
log_mgr [label="日志管理器"];
module_mgr [label="模块管理器"];
conf_mgr [label="配置管理器"];
db_mgr [label="数据库管理器"];
};
subgraph cluster_md{
label="可插拔模块集";
bgcolor="lightcyan";
node [color="chartreuse2", style="filled"];
mod_dev [label="开发支持模块"];
mod_dm [label="数据建模模块"];
mod_dp [label="部署发布模块"];
};
mod_dp -> mod_dev [label="依赖..."];
mod_dp -> mod_dm [label="依赖..."];
mod_dp -> module_mgr [label="安装...", color="yellowgreen", arrowhead="none"];
mod_dev -> mod_dm [label="依赖..."];
mod_dev -> module_mgr [label="安装...", color="yellowgreen", arrowhead="none"];
mod_dm -> module_mgr [label="安装...", color="yellowgreen", arrowhead="none"];
}
使用2.38生成的图片
网上搜索的结果,一个说是引号问题
macbook darwin下安装了graphviz 2.38.0。
画有向图digraph的时候,如果label中包含中文字符,生成的图片中会缺文字。
网上的解释是fontname没有设置的原因,可设置fontname后还是会出现同样的问题。例如:
digraph Geely {
node [shape=record,fontname="SimSun.ttf"];
edge [fontname="SimSun.ttf"];jlwy [label="吉利万源"];
jlzy [label="吉利兆园"];
volv [label="沃尔沃"];jlwy -> jlzy [label="87.65%"];
jlzy -> volv [label="100%"];}
$ dot -Tpng geely.dot -o geely.png $ open geely.png生成的图像中,连接线上的百分比有,但节点中的内容是空的。
偶然原因,在引号中的中文前加了个空格,字符就能显示出来了,可能是个bug吧,总之问题解决了。
volv [label=" 沃尔沃"];
按照此方法能够正常显示图片。
另一个说是shape问题
可是子图里面的节点却依然是空(不是乱码,只是没有内容)。于是我查找半天,最终发现罪魁祸首是:
zongshu_title [label = "研究综述" shape=record]
看到了吧?就是最后这句shape=record。为什么有问题?不知道。但是把它删去,一点不改变原先的图形结构,中文却又都出来了。
按照此方法中文是可以显示了,但是形状效果都没了
参考资料
[1]. http://php.net/manual/zh/function.urldecode.php [2]. http://php.net/manual/zh/function.imagecreatefromjpeg.php [3]. http://blog.sina.com.cn/s/blog_b09d4602010195ky.html [4]. 2.38中文问题 http://wshuyi.github.io/2014/05/03/graphvizchinesewindows/ [5]. 2.38中文问题 http://blog.csdn.net/spacecraft/article/details/25163293


Pingback: Discuz插件处理大型dot源码 | 知行近思