• R/O
  • SSH
  • HTTPS

y2pukiwiki: Commit


Commit MetaInfo

Revision125 (tree)
Time2010-04-21 10:30:20
Authory2katayama

Log Message

graphvizプラグイン追加

Change Summary

Incremental Difference

--- pukiwiki-1.4.7_notb_utf8/plugin/graphviz.inc.php (nonexistent)
+++ pukiwiki-1.4.7_notb_utf8/plugin/graphviz.inc.php (revision 125)
@@ -0,0 +1,983 @@
1+<?php
2+/*
3+ * graphvizを用いてグラフを表示するプラグイン
4+ *
5+ * Copyright (C) 2004-2005 Takashi Matsuda <matsu at users.sourceforge.net>
6+ *
7+ * このプログラムはPukiWiki本体と同様のライセンスで配布します。
8+ *
9+ * 変更履歴:
10+ * 2006-05-18: Rev 1.8
11+ * 2006-05-18: actionのtransfers2引数にはプロトコルのバージョンを入れるようにした。
12+ * 2006-05-17: base64しただけだとURLセーフで無い問題に対応。
13+ * 2006-01-23: Rev 1.7
14+ * 2006-01-23: 位置揃えの指定機能を追加。
15+ * 2005-03-02: キャッシュの廃棄機能を追加。
16+ * 2005-03-02: charsetが指定されない場合はbase64_decode()しないようにした。
17+ * 2005-02-25: Rev 1.6
18+ * 2005-02-25: 委譲時に意図しない文字コード変換が生じていたバグを修正。
19+ * 2005-02-25: globを使わないようにした。
20+ * 2005-02-24: Rev 1.5
21+ * 2005-02-24: テスト用のコードが残っていたので削除。
22+ * 2005-02-24: インライン型が機能していなかったバグ修正。
23+ * 2005-02-23: Rev 1.4
24+ * 2005-02-23: 文字コード変換を実装。
25+ * 2005-02-23: マクロ機能を実装。
26+ * 2005-02-23: 委譲をPOSTメソッドで実装し直し。
27+ * 2004-12-01: 画像生成を別サーバに委譲する機能を追加。
28+ * 2004-10-28: CACHE_DIRを直接見せないように変更(1.4.4対応)
29+ * 2004-10-22: 初稿
30+ *
31+ * $Id: graphviz.inc.php,v 1.27 2006/05/18 00:25:14 matsuda Exp $
32+ */
33+
34+// イメージの代りに使用される文字列。
35+define('PLUGIN_GRAPHVIZ_ALT', 'a graph image');
36+
37+// キャッシュに保存されるファイル名の接頭辞。
38+define('PLUGIN_GRAPHVIZ_PREFIX', 'graphviz.');
39+
40+// キャッシュに保存される画像のファイル名の拡張子。
41+define('PLUGIN_GRAPHVIZ_SUFFIX', '.png');
42+// キャッシュに保存されるエラーのファイル名の拡張子。
43+define('PLUGIN_GRAPHVIZ_ERRSUFFIX', '.err');
44+
45+// デフォルトのgraphvizプログラム。
46+define('PLUGIN_GRAPHVIZ_PROG', 'dot');
47+
48+// デフォルトのグラフサイズ。
49+define('PLUGIN_GRAPHVIZ_OPT', 'small');
50+
51+// イメージのバックグラウンドを透明にする。
52+define('PLUGIN_GRAPHVIZ_TRANSPARENT', TRUE);
53+
54+// これ以上古くなったキャッシュファイルは削除する。(単位:日)
55+define('PLUGIN_GRAPHVIZ_EXPIRE_DATE', 30);
56+
57+// pukiwiki.php?plugin=graphvizの呼び出しで、イメージの生成を許すか
58+define('PLUGIN_GRAPHVIZ_ACCEPT_TRANSFER',FALSE);
59+define('PLUGIN_GRAPHVIZ_ACCEPT_TRANSFER2',FALSE);
60+
61+// イメージの生成を委譲する場合、委譲先PukiWikiのアドレスを指定する。
62+define('PLUGIN_GRAPHVIZ_TRANSFER_URL', '');
63+
64+// 使用するgraphvizプログラムのパス。
65+define('PLUGIN_GRAPHVIZ_DOT', '/usr/bin/dot');
66+define('PLUGIN_GRAPHVIZ_NEATO', '/usr/bin/neato');
67+define('PLUGIN_GRAPHVIZ_TWOPI', '/usr/bin/twopi');
68+define('PLUGIN_GRAPHVIZ_CIRCO', '/usr/bin/circo');
69+define('PLUGIN_GRAPHVIZ_FDP', '/usr/bin/fdp');
70+
71+// graphvizプログラムの起動に簡易的な方法を使う。
72+// 制限事項:
73+// ・エラーメッセージの取得はできない。
74+// ・背景色の透過は行わない。
75+// ・画像生成の委譲を受けることはできない。
76+define('PLUGIN_GRAPHVIZ_SIMPLE_EXEC', FALSE);
77+
78+define('PLUGIN_GRAPHVIZ_COMMON_OPTION', '-Tpng');
79+
80+// graphvizのプログラムに与えるdotスクリプトのエンコーディング
81+define('PLUGIN_GRAPHVIZ_CHARSET', 'UTF-8');
82+
83+// デフォルトのマクロ設定
84+define('PLUGIN_GRAPHVIZ_MACRO_PAGE', 'rankdir=LR;');
85+define('PLUGIN_GRAPHVIZ_MACRO_FONTNAME','"Times-Roman"');
86+define('PLUGIN_GRAPHVIZ_MACRO_FONT', 'fontname=@fontname@; node [ fontname=@fontname@ ]; edge [ fontname=@fontname@ ];');
87+define('PLUGIN_GRAPHVIZ_MACRO_LARGE', '@page@ @font@ node [ fontsize=20 ]; edge [ fontsize=20 ];');
88+define('PLUGIN_GRAPHVIZ_MACRO_NORMAL', '@page@ @font@ node [ fontsize=14 ]; edge [ fontsize=14 ];');
89+define('PLUGIN_GRAPHVIZ_MACRO_SMALL', '@page@ @font@ node [ fontsize=8, height=0.3, width=0.5 ]; edge [ fontsize=8 ];');
90+define('PLUGIN_GRAPHVIZ_MACRO_TINY', '@page@ @font@ node [ fontsize=6, height=0.2, width=0.4 ]; edge [ fontsize=6 ];');
91+
92+// イメージのバックグラウンドを透明にするためのフィルタ。
93+define('PLUGIN_GRAPHVIZ_TRANSP_CMD', '/usr/bin/convert -transparent white png:- png:-');
94+
95+// イメージのContent-Type
96+define('PLUGIN_GRAPHVIZ_CONTENT_TYPE', 'image/png');
97+
98+function plugin_graphviz_init()
99+{
100+ $messages = array(
101+ '_graphviz_messages' => array(
102+ 'plugin_title' => 'graphviz',
103+ 'macro_table_label' => 'ラベル',
104+ 'macro_table_string' => '文字列',
105+ ),
106+ );
107+ set_plugin_messages($messages);
108+}
109+
110+function plugin_graphviz_action()
111+{
112+ global $vars;
113+
114+ if (isset($vars['image'])) {
115+ graphviz_send_cacheimage($vars['image']);
116+ }
117+
118+ if (isset($vars['transfer2'])) {
119+ if (PLUGIN_GRAPHVIZ_SIMPLE_EXEC || !PLUGIN_GRAPHVIZ_ACCEPT_TRANSFER2) {
120+ graphviz_send_message("plugin graphviz: error: disabled feature");
121+ }
122+
123+ if ((int) $vars['transfer2'] < 3)
124+ {
125+ graphviz_send_message("plugin graphviz: error: unsupported transfer2 protocol version.");
126+ }
127+
128+ // get default arguments
129+ $args = graphviz_parse_args_draw_image();
130+ //
131+ static $keys = array("prog", "size", "transp", "dotscript", "charset");
132+ foreach ($keys as $key) {
133+ if (isset($vars[$key])) {
134+ $args[$key] = urldecode($vars[$key]);
135+ }
136+ }
137+ if (isset($vars['charset'])) {
138+ $args['dotscript'] = graphviz_urlsafe_decode($args['dotscript']);
139+ } else {
140+ if (isset($vars['encoding_hint']) && $vars['encoding_hint'] != '') {
141+ $args['charset'] = mb_detect_encoding($vars['encoding_hint']);
142+ }
143+ if (!isset($args['charset'])) {
144+ $args['charset'] = mb_detect_encoding($vars['dotscript']);
145+ }
146+ }
147+
148+ $size = $args['size'];
149+ graphviz_preprocess_dotscript($args, TRUE);
150+ $image = graphviz_draw_image($args, $error);
151+ if ($image === FALSE || $image == "") {
152+ graphviz_send_message("plugin graphviz: error: graphviz failed\n" . $error);
153+ }
154+
155+ graphviz_send_image($image);
156+ }
157+
158+ // obsolete feature
159+ if (isset($vars['transfer'])) {
160+ if (!PLUGIN_GRAPHVIZ_ACCEPT_TRANSFER) {
161+ graphviz_send_message("plugin graphviz: error: disabled feature");
162+ }
163+
164+ $args = array();
165+ for ($num = 1; isset($vars["arg$num"]); $num++) {
166+ $args[] = urldecode($vars["arg$num"]);
167+ }
168+ $args = graphviz_parse_args_draw_image($args);
169+
170+ mb_convert_variables(PLUGIN_GRAPHVIZ_CHARSET, 'auto', $args['dotscript']);
171+ $args['charset'] = PLUGIN_GRAPHVIZ_CHARSET;
172+
173+ $digest = graphviz_query_image($args, $error, FALSE); // get image without ransfer
174+ if ($digest === FALSE || !file_exists(graphviz_imagepath($digest))) {
175+ graphviz_send_message("plugin graphviz: error: graphviz failed\n" . $error);
176+ }
177+ graphviz_send_cacheimage($digest);
178+ }
179+
180+ // expire cache
181+
182+ $pass = isset($vars['pass'])? $vars['pass'] : NULL;
183+
184+ $msg = graphviz_get_message("plugin_title");
185+ $body = '';
186+ if ($pass !== NULL && pkwk_login($pass)) {
187+ graphviz_expire_cache(TRUE);
188+ $body = graphviz_get_message("cache is expired.");
189+ }
190+ else {
191+ if ($pass === NULL) {
192+ $body = '';
193+ } else {
194+ $body = '<p>' . graphviz_get_message('invalid password.') . "</p>\n";
195+ }
196+ $_msg_expire = graphviz_get_message('to expire cache, enter admin password.');
197+ $_btn_expire = graphviz_get_message('expire');
198+ $body .= <<<EOD
199+<p>$_msg_expire</p>
200+<form action="$script" method="post">
201+ <div>
202+ <input type="hidden" name="plugin" value="graphviz" />
203+ <input type="password" name="pass" size="12" />
204+ <input type="submit" name="ok" value="$_btn_expire" />
205+ </div>
206+</form>
207+EOD;
208+ }
209+ return array('msg' => $msg, 'body' => $body);
210+}
211+
212+function plugin_graphviz_convert()
213+{
214+ global $vars;
215+ global $script;
216+
217+ $args = func_get_args();
218+
219+ if (count($args) > 0 && trim($args[0]) == 'define') {
220+ array_shift($args);
221+ if (count($args) >= 2 && strlen($label = trim(array_shift($args))) > 0) {
222+ graphviz_add_macro($label, strtr(join(",", $args), "\r", "\n"));
223+ return "";
224+ } else {
225+ $msg = graphviz_get_message("error: wrong use of 'define' option.");
226+ $msg = sprintf(graphviz_get_message("[plugin graphviz: %s]"), $msg);
227+ return "<p class='plugin_graphviz'>$msg</p>";
228+ }
229+ }
230+
231+ else if (count($args) > 0 && trim($args[0]) == 'showmacro') {
232+ $table = graphviz_get_macro_table();
233+ $macro_table_label = graphviz_get_message('macro_table_label');
234+ $macro_table_string = graphviz_get_message('macro_table_string');
235+ $body = <<<EOD
236+<table class="plugin_graphviz style_table" cellspacing="1" border="0">
237+ <thead>
238+ <tr>
239+ <td class="style_td">$macro_table_label</td>
240+ <td class="style_td">$macro_table_string</td>
241+ </tr>
242+ </thead>
243+ <tbody>
244+EOD;
245+ foreach ($table as $label => $string) {
246+ $s_label = htmlspecialchars($label);
247+ $s_string = htmlspecialchars($string);
248+ $body .= <<<EOD
249+ <tr>
250+ <td class="style_td">$s_label</td>
251+ <td class="style_td">$s_string</td>
252+ </tr>
253+EOD;
254+ }
255+ $body .= <<<EOD
256+ </tbody>
257+</table>
258+EOD;
259+ return $body;
260+ }
261+
262+ else if (count($args) > 0 && trim($args[0]) == 'form') {
263+ if (PLUGIN_GRAPHVIZ_TRANSFER_URL !== FALSE &&
264+ PLUGIN_GRAPHVIZ_TRANSFER_URL != '') {
265+ $url = PLUGIN_GRAPHVIZ_TRANSFER_URL;
266+ } else {
267+ $url = $script;
268+ }
269+ return <<<EOD
270+<div class="plugin_graphviz">
271+ <form action="$url" method="post">
272+ <input type="hidden" name="plugin" value="graphviz" />
273+ <input type="hidden" name="transfer2" value="transfer2" />
274+ <textarea name="dotscript"></textarea><br />
275+ <input type="submit" name="post" value="ポスト" />
276+ </form>
277+</div>
278+EOD;
279+ }
280+
281+ else if (count($args) > 0 && trim($args[0]) == 'include') {
282+ array_shift($args);
283+ if (count($args) == 0) {
284+ $msg = graphviz_get_message("error: 'include' needs at least one page reference.");
285+ $msg = sprintf(graphviz_get_message("[plugin graphviz: %s]"), $msg);
286+ return "<p class='plugin_graphviz'>$msg</p>";
287+ }
288+ $body = '';
289+ foreach ($args as $page) {
290+ $page = strip_bracket(trim($page));
291+ $f_page = get_fullname($page, $vars['page']);
292+ if (file_exists(get_filename($f_page)) && check_readable($f_page, true, true)) {
293+ graphviz_include_macro($f_page);
294+ } else {
295+ $s_page = htmlspecialchars($page);
296+ $msg = sprintf(graphviz_get_message("error: can not read page '%s'."), $s_page);
297+ $msg = sprintf(graphviz_get_message("[plugin graphviz: %s]"), $msg);
298+ $body .= "<div class='plugin_graphviz'><p>$msg</p></div>";
299+ }
300+ }
301+ return $body;
302+ }
303+
304+ else {
305+ $args = graphviz_parse_args_draw_image($args);
306+ $error = "";
307+ $digest = graphviz_query_image($args, $error);
308+
309+ $alt = PLUGIN_GRAPHVIZ_ALT;
310+ $style = "";
311+ if (isset($args['align'])) {
312+ $style .= " align='" . $args['align'] . "'";
313+ }
314+ $body = "";
315+ if ($digest !== FALSE) {
316+ $url = graphviz_download_url($digest);
317+ $body .= "<p class='plugin_graphviz'$style><img src=\"$url\" alt=\"$alt\" /></p>";
318+ }
319+ if ($error != "") {
320+ $body .= "<pre class='plugin_graphviz' style='overflow:auto;'>graphviz:\n" . htmlspecialchars($error) . "</pre>";
321+ }
322+ return $body;
323+ }
324+}
325+
326+function plugin_graphviz_inline()
327+{
328+
329+ $args = func_get_args();
330+
331+ $args = graphviz_parse_args_draw_image($args);
332+ $args['charset'] = SOURCE_ENCODING;
333+ $error = "";
334+ $digest = graphviz_query_image($args, $error);
335+ $alt = PLUGIN_GRAPHVIZ_ALT;
336+ $body = "";
337+ if ($digest !== FALSE) {
338+ $url = graphviz_download_url($digest);
339+ $body .= "<img class='plugin_graphviz' src='$url' alt='$alt' />";
340+ }
341+ if ($error != "") {
342+ $body .= "<span class='plugin_graphviz'>graphviz: " . htmlspecialchars($error) . "</span>";
343+ }
344+ return $body;
345+}
346+
347+//
348+// エラーメッセージを送信する。
349+//
350+// @param $message メッセージ文字列
351+//
352+function graphviz_send_message($message)
353+{
354+ header('Content-Type: text/plain');
355+ echo($message);
356+ exit;
357+}
358+
359+//
360+// イメージをクライアントに送信する。
361+//
362+// @param $image イメージ(文字列)
363+//
364+function graphviz_send_image($image)
365+{
366+ header('Content-Disposition: inline');
367+ header('Content-Length: ' . strlen($image));
368+ header('Content-Type: ' . PLUGIN_GRAPHVIZ_CONTENT_TYPE);
369+ echo($image);
370+ exit;
371+}
372+
373+//
374+// キャッシングされているイメージをクライアントに送信する。
375+//
376+// @param $digest イメージのダイジェスト値
377+//
378+function graphviz_send_cacheimage($digest)
379+{
380+ $file = graphviz_imagepath($digest);
381+
382+ if (!file_exists($file)) {
383+ graphviz_send_message("plugin graphviz: error: no cached image");
384+ exit;
385+ }
386+ $size = filesize($file);
387+ header('Content-Disposition: inline');
388+ header('Content-Length: ' . $size);
389+ header('Content-Type: ' . PLUGIN_GRAPHVIZ_CONTENT_TYPE);
390+ @readfile($file);
391+ exit;
392+}
393+
394+//
395+// メッセージ文字列の取得
396+//
397+// $labelに対応する文字列が定義されていない場合には、$label自身を返す。
398+//
399+// @return
400+// メッセージ文字列
401+//
402+// @param $label ラベル
403+//
404+function graphviz_get_message($label)
405+{
406+ global $_graphviz_messages;
407+
408+ if (isset($_graphviz_messages[$label])) {
409+ return $_graphviz_messages[$label];
410+ } else {
411+ return $label;
412+ }
413+}
414+
415+//
416+// 生成済イメージをダウンロードするURLを生成
417+//
418+// @return イメージのURL
419+//
420+// @param $digest イメージのダイジェスト名
421+//
422+function graphviz_download_url($digest)
423+{
424+ global $script;
425+ return "$script?plugin=graphviz&image=$digest";
426+}
427+
428+//
429+// キャッシュされた生成済イメージのパスを得る。
430+//
431+// @return パス
432+//
433+// @param $digest イメージのダイジェスト名
434+//
435+function graphviz_imagepath($digest)
436+{
437+ return CACHE_DIR.PLUGIN_GRAPHVIZ_PREFIX.$digest.PLUGIN_GRAPHVIZ_SUFFIX;
438+}
439+
440+//
441+// キャッシュされたエラーメッセージファイルのパスを得る。
442+//
443+// @return
444+// パス(文字列)
445+//
446+// @param $digest イメージのダイジェスト名
447+//
448+function graphviz_errorpath($digest)
449+{
450+ return CACHE_DIR.PLUGIN_GRAPHVIZ_PREFIX.$digest.PLUGIN_GRAPHVIZ_ERRSUFFIX;
451+}
452+
453+//
454+// イメージ生成用引数の解析
455+//
456+// @param $args 引数リスト
457+//
458+// 戻り値
459+// パース済引数
460+//
461+function graphviz_parse_args_draw_image($args = array())
462+{
463+ static $cmds = array(
464+ 'dot',
465+ 'neato',
466+ 'twopi',
467+ 'circo',
468+ 'fdp',
469+ );
470+
471+ static $opts = array(
472+ 'normal',
473+ 'small',
474+ 'tiny',
475+ 'large',
476+ );
477+
478+ static $transp = array(
479+ 'transp',
480+ 'notransp',
481+ );
482+
483+ static $align = array(
484+ 'left',
485+ 'center',
486+ 'right',
487+ );
488+
489+ $result = array(
490+ 'prog' => PLUGIN_GRAPHVIZ_PROG,
491+ 'size' => PLUGIN_GRAPHVIZ_OPT,
492+ 'transp' => PLUGIN_GRAPHVIZ_TRANSPARENT? "transp" : "notransp",
493+ 'dotscript' => '',
494+ 'charset' => SOURCE_ENCODING,
495+ );
496+
497+ if (count($args) > 0 && in_array(trim($args[0]), $cmds)) {
498+ $result['prog'] = trim(array_shift($args));
499+ }
500+
501+ if (count($args) > 0 && in_array(trim($args[0]), $opts)) {
502+ $result['size'] = trim(array_shift($args));
503+ }
504+
505+ if (count($args) > 0 && in_array(trim($args[0]), $transp)) {
506+ $result['transp'] = trim(array_shift($args));
507+ }
508+
509+ if (count($args) > 0 && in_array(trim($args[0]), $align)) {
510+ $result['align'] = trim(array_shift($args));
511+ }
512+
513+ $result['dotscript'] = strtr(join(",", $args), "\r", "\n");
514+
515+ return $result;
516+}
517+
518+//
519+// イメージのダイジェスト値を生成する
520+//
521+// @return
522+// ダイジェスト値(文字列)
523+//
524+// @param $args イメージ生成用に正規化された引数
525+//
526+function graphviz_make_digest($args)
527+{
528+ return md5(join('+', array($args['prog'], $args['size'], $args['transp'], $args['dotscript'])));
529+}
530+
531+//
532+// イメージの生成
533+//
534+// @return
535+// イメージのダイジェスト値を返す。
536+//
537+// @param $args (in) 画像生成引数
538+// @param $error (out) エラーメッセージ
539+// @param $transfer (in) 委譲機能を使うか
540+//
541+function graphviz_query_image($args, &$error, $transfer = TRUE)
542+{
543+ $do_transfer = ($transfer && !PLUGIN_GRAPHVIZ_SIMPLE_EXEC && FALSE !== PLUGIN_GRAPHVIZ_TRANSFER_URL && '' != PLUGIN_GRAPHVIZ_TRANSFER_URL);
544+
545+ if ($do_transfer) {
546+ graphviz_preprocess_dotscript($args);
547+ } else {
548+ $size = $args['size'];
549+ graphviz_preprocess_dotscript($args, TRUE);
550+ }
551+
552+ $digest = graphviz_make_digest($args);
553+ $image_path = graphviz_imagepath($digest);
554+ $err_path = graphviz_errorpath($digest);
555+
556+ if (file_exists($image_path) || file_exists($err_path)) {
557+ if (file_exists($err_path)) {
558+ touch($err_path);
559+ $error = join(file($err_path));
560+ }
561+ if (file_exists($image_path)) {
562+ touch($image_path);
563+ return $digest;
564+ } else {
565+ return FALSE;
566+ }
567+ } else {
568+ graphviz_expire_cache();
569+ if (PLUGIN_GRAPHVIZ_SIMPLE_EXEC) {
570+ $digest = graphviz_draw_image_simple($args, $error);
571+ if ($error != "") {
572+ graphviz_write_file($err_path, $error);
573+ }
574+ return $digest;
575+ } else {
576+ if ($do_transfer) {
577+ $image = graphviz_request_image(PLUGIN_GRAPHVIZ_TRANSFER_URL, $args, $error);
578+ } else {
579+ $image = graphviz_draw_image($args, $error);
580+ }
581+ if ($error != "") {
582+ graphviz_write_file($err_path, $error);
583+ }
584+ if ($image !== FALSE && $image != "" && graphviz_write_file($image_path, $image)) {
585+ return $digest;
586+ } else {
587+ return FALSE;
588+ }
589+ }
590+ }
591+}
592+
593+//
594+// ファイルへの書き込み
595+//
596+// @return
597+// 書き込みに成功したらTRUEを返す。
598+//
599+function graphviz_write_file($filename, $content)
600+{
601+ if ($fp = fopen($filename, "wb")) {
602+ fwrite($fp, $content);
603+ fclose($fp);
604+ return TRUE;
605+ } else {
606+ return FALSE;
607+ }
608+}
609+
610+//
611+// イメージの生成
612+//
613+// @return
614+// イメージ(文字列)を返す。
615+//
616+// @param $args (in) プラグイン引数
617+// @param $error (out) エラーメッセージ
618+//
619+function graphviz_draw_image($args, &$error)
620+{
621+ static $cmds = array(
622+ 'dot' => PLUGIN_GRAPHVIZ_DOT,
623+ 'neato' => PLUGIN_GRAPHVIZ_NEATO,
624+ 'twopi' => PLUGIN_GRAPHVIZ_TWOPI,
625+ 'circo' => PLUGIN_GRAPHVIZ_CIRCO,
626+ 'fdp' => PLUGIN_GRAPHVIZ_FDP,
627+ );
628+
629+ $transp = ($args['transp'] == 'transp');
630+ $command = $cmds[$args['prog']] . " " . PLUGIN_GRAPHVIZ_COMMON_OPTION;
631+
632+ $retval = graphviz_exec_process($command, $args['dotscript'], $image, $error);
633+ if ($image === FALSE || $image == "") {
634+ return FALSE;
635+ }
636+
637+ if ($transp) {
638+ $command = PLUGIN_GRAPHVIZ_TRANSP_CMD;
639+ $retval = graphviz_exec_process($command, $image, $image2, $error2);
640+ // 透過処理中のエラーは無視
641+ if ($retval == 0) {
642+ $image = $image2;
643+ }
644+ }
645+
646+ return $image;
647+}
648+
649+//
650+// イメージ生成
651+//
652+// プログラム実行に高度な制御を行えない環境用に、シンプルにコマンドを実行する。
653+// イメージを生成して直接ファイルに出力させる。
654+//
655+// @return
656+// ダイジェスト値
657+//
658+function graphviz_draw_image_simple($args, &$error)
659+{
660+ static $cmds = array(
661+ 'dot' => PLUGIN_GRAPHVIZ_DOT,
662+ 'neato' => PLUGIN_GRAPHVIZ_NEATO,
663+ 'twopi' => PLUGIN_GRAPHVIZ_TWOPI,
664+ 'circo' => PLUGIN_GRAPHVIZ_CIRCO,
665+ 'fdp' => PLUGIN_GRAPHVIZ_FDP,
666+ );
667+
668+ $command = $cmds[$args['prog']] . " " . PLUGIN_GRAPHVIZ_COMMON_OPTION;
669+
670+ $digest = graphviz_make_digest($args);
671+ $image_path = graphviz_imagepath($digest);
672+
673+ $command .= " -o $image_path";
674+ if (FALSE === ($fp = popen($command, "w"))) {
675+ $msg = graphviz_get_message("error: graphviz failed.");
676+ $msg = sprintf(graphviz_get_message("[plugin graphviz: %s]"), $msg);
677+ $error = $msg;
678+ return FALSE;
679+ }
680+ fwrite($fp, $args['dotscript']);
681+ if (!fclose($fp)) {
682+ $msg = graphviz_get_message("error: graphviz failed.");
683+ $msg = sprintf(graphviz_get_message("[plugin graphviz: %s]"), $msg);
684+ $error = $msg;
685+ return FALSE;
686+ }
687+
688+ return $digest;
689+}
690+
691+//
692+// 有効期限の過ぎたキャッシュファイルをすべて削除する。
693+//
694+// @param $all TRUEの場合、有効期限に関わらず全てのキャッシュファイルを削除。
695+//
696+function graphviz_expire_cache($all = FALSE)
697+{
698+ $limit = time() - PLUGIN_GRAPHVIZ_EXPIRE_DATE * 3600 * 24;
699+
700+ if (!($dir = opendir(CACHE_DIR))) {
701+ return;
702+ }
703+ $prefix_len = strlen(PLUGIN_GRAPHVIZ_PREFIX);
704+ $imgsuffix_len = strlen(PLUGIN_GRAPHVIZ_SUFFIX);
705+ $errsuffix_len = strlen(PLUGIN_GRAPHVIZ_ERRSUFFIX);
706+ while (($filename = readdir($dir)) !== FALSE) {
707+ $fullpath = CACHE_DIR . $filename;
708+ if (!is_file($fullpath)) {
709+ continue;
710+ }
711+ if (0 != strncmp($filename, PLUGIN_GRAPHVIZ_PREFIX, $prefix_len)) {
712+ continue;
713+ }
714+ if (substr($filename, -$imgsuffix_len) != PLUGIN_GRAPHVIZ_SUFFIX &&
715+ substr($filename, -$errsuffix_len) != PLUGIN_GRAPHVIZ_ERRSUFFIX) {
716+ continue;
717+ }
718+ if ($all || filemtime($fullpath) < $limit) {
719+ unlink($fullpath);
720+ }
721+ }
722+ closedir($dir);
723+}
724+
725+//
726+// コマンドを実行し、標準出力と標準エラー出力を得る。
727+//
728+// @return プロセスの実行結果
729+//
730+// @param $command (in) 実行すべきコマンド
731+// @param $input (in) コマンドの標準入力に与える文字列
732+// @param $output (out) コマンドの標準出力に出力された文字列
733+// @param $error (out) コマンドの標準エラー出力に出力された文字列
734+//
735+function graphviz_exec_process($command, $input, &$output, &$error)
736+{
737+ $output = "";
738+ $error = "";
739+
740+ $descspec = array(
741+ 0 => array("pipe", "r"),
742+ 1 => array("pipe", "w"),
743+ 2 => array("pipe", "w")
744+ );
745+ $process = proc_open($command, $descspec, $pipes);
746+ if ($process === FALSE) {
747+ return FALSE;
748+ }
749+ fwrite($pipes[0], $input);
750+ fclose($pipes[0]);
751+ while (TRUE) {
752+ $r = array();
753+ if (!feof($pipes[1])) {
754+ $r[] = $pipes[1];
755+ }
756+ if (!feof($pipes[2])) {
757+ $r[] = $pipes[2];
758+ }
759+ if (count($r) == 0) {
760+ break;
761+ }
762+ $num_changed = stream_select($r, $w = NULL, $e = NULL, 5);
763+ if (FALSE === $num_changed) {
764+ $error .= "internal error (stream_select returned FALSE)";
765+ break;
766+ }
767+ foreach ($r as $stream) {
768+ if ($stream == $pipes[1]) {
769+ $output .= fread($stream, 1000);
770+ } else if ($stream == $pipes[2]) {
771+ $error .= fread($stream, 1000);
772+ }
773+ }
774+ }
775+ fclose($pipes[1]);
776+ fclose($pipes[2]);
777+ return proc_close($process);
778+}
779+
780+//
781+// スクリプト内のマクロを展開する。
782+//
783+// @param $table array(label => string)
784+//
785+// @return
786+// マクロ展開された文字列。
787+//
788+function graphviz_expand_macro(&$args, $table, $max_nest = 10)
789+{
790+ $dotscript = $args['dotscript'];
791+ for ($i = 0; $i < $max_nest; $i++) {
792+ $prev_dotscript = $dotscript;
793+ foreach ($table as $label => $string) {
794+ $dotscript = str_replace($label, $string, $dotscript);
795+ }
796+ if ($dotscript == $prev_dotscript) {
797+ break;
798+ }
799+ }
800+ $args['dotscript'] = $dotscript;
801+}
802+
803+//
804+// マクロテーブルの取得
805+//
806+// 処理対象のページが変わったら、テーブルを初期化しなおす。
807+//
808+// @return
809+// マクロテーブル(array)
810+//
811+function graphviz_get_macro_table()
812+{
813+ global $graphviz_macro_table;
814+ global $graphviz_current_page;
815+ global $vars;
816+
817+ if (!isset($graphviz_macro_table)) {
818+ $graphviz_macro_table = array();
819+ }
820+
821+ $page = $vars['page'];
822+ if (!isset($graphviz_macro_table[$page])) {
823+ $graphviz_macro_table[$page] = array();
824+ graphviz_add_macro("@page@", PLUGIN_GRAPHVIZ_MACRO_PAGE);
825+ graphviz_add_macro("@fontname@", PLUGIN_GRAPHVIZ_MACRO_FONTNAME);
826+ graphviz_add_macro("@font@", PLUGIN_GRAPHVIZ_MACRO_FONT);
827+ graphviz_add_macro("@large@", PLUGIN_GRAPHVIZ_MACRO_LARGE);
828+ graphviz_add_macro("@normal@", PLUGIN_GRAPHVIZ_MACRO_NORMAL);
829+ graphviz_add_macro("@small@", PLUGIN_GRAPHVIZ_MACRO_SMALL);
830+ graphviz_add_macro("@tiny@", PLUGIN_GRAPHVIZ_MACRO_TINY);
831+ }
832+ return $graphviz_macro_table[$page];
833+}
834+
835+//
836+// マクロの追加
837+//
838+// @param label ラベル
839+// @param string 定義
840+//
841+function graphviz_add_macro($label, $string)
842+{
843+ global $graphviz_macro_table;
844+ global $vars;
845+
846+ // initialize
847+ graphviz_get_macro_table();
848+
849+ $page = $vars['page'];
850+ $label = mb_convert_encoding($label, PLUGIN_GRAPHVIZ_CHARSET, SOURCE_ENCODING);
851+ $string = mb_convert_encoding($string, PLUGIN_GRAPHVIZ_CHARSET, SOURCE_ENCODING);
852+ $graphviz_macro_table[$page][$label] = $string;
853+}
854+
855+//
856+// dotスクリプトの前処理
857+//
858+// 標準属性の設定とマクロ展開を行う。
859+//
860+// @param $args 画像生成用引数
861+// @param $process_size サイズ指定を処理するか
862+//
863+function graphviz_preprocess_dotscript(&$args, $process_size = FALSE)
864+{
865+ if ($charset = mb_convert_variables(PLUGIN_GRAPHVIZ_CHARSET, $args['charset'], $args['dotscript'])) {
866+ $args['charset'] = PLUGIN_GRAPHVIZ_CHARSET;
867+ }
868+ $macro = graphviz_get_macro_table();
869+ if ($process_size) {
870+ $label = '@' . $args['size'] . '@';
871+ $args['dotscript'] = preg_replace('/(^|\s)(di)?graph[^{]*{/', '${0} ' . $label, $args['dotscript']);
872+ }
873+ graphviz_expand_macro($args, $macro);
874+}
875+
876+//
877+// 指定ページに記述されたマクロをカレントページのマクロテーブルにマージする。
878+//
879+// マクロは整形済テキストとして1行単位で定義する。
880+// label = string ...
881+//
882+// @param $page ページ名(fullname)
883+//
884+function graphviz_include_macro($page)
885+{
886+ foreach (get_source($page) as $line) {
887+ if (preg_match('/^ ([^=]+)=/', $line, $matches)) {
888+ $label = trim($matches[1]);
889+ $script = trim(substr($line, strlen($matches[0])));
890+ graphviz_add_macro($label, $script);
891+ }
892+ }
893+}
894+
895+//
896+// サーバにdotスクリプトを送信し、イメージを取得する。
897+//
898+// $urlのプロトコルにはhttpのみ指定可能。
899+//
900+// @return
901+// 画像(文字列)またはFALSE
902+//
903+// @param $url 委譲先PukiWikiサイトのURL
904+// @param $script dotスクリプト
905+// @param $error エラー文字列
906+//
907+function graphviz_request_image($url, $args, &$error)
908+{
909+ $url = parse_url($url);
910+
911+ if (isset($url['query'])) {
912+ $url['query'] = "?".$url['query'];
913+ } else {
914+ $url['query'] = "";
915+ }
916+
917+ if (!isset($url['port'])) {
918+ $url['port'] = 80;
919+ }
920+
921+ $request = "";
922+ $request .= "POST " . $url['path'] . $url['query'] . " HTTP/1.0\r\n";
923+ $request .= "Host: " . $url['host'] . "\r\n";
924+ $request .= "User-Agent: PHP/" . phpversion() . "\r\n";
925+
926+ if (isset($url['user']) && isset($url['pass'])) {
927+ $encoded = base64_encode($url['user'] . ":" . $url['pass']);
928+ $request .= "Authorization: Basic " . $encoded . "\r\n";
929+ }
930+ $postdata = array();
931+ $postdata[] = "plugin=graphviz";
932+ $postdata[] = "transfer2=3";
933+ // prevent unexpected charset conversion
934+ $args['dotscript'] = graphviz_urlsafe_encode($args['dotscript']);
935+ foreach ($args as $key => $value) {
936+ $postdata[] = $key . "=" . urlencode($value);
937+ }
938+ $postdata = implode("&", $postdata);
939+ $request .= "Content-Type: application/x-www-form-urlencoded\r\n";
940+ $request .= "Content-Length: " . strlen($postdata) . "\r\n";
941+ $request .= "\r\n";
942+ $request .= $postdata;
943+
944+ $fp = fsockopen($url['host'], $url['port']);
945+ if (!$fp) {
946+ return FALSE;
947+ }
948+
949+ fputs($fp, $request);
950+
951+ $response = "";
952+ while (!feof($fp)) {
953+ $response .= fgets($fp, 1024);
954+ }
955+
956+ fclose($fp);
957+
958+ $getdata = split("\r\n\r\n", $response, 2);
959+
960+ if (preg_match('#Content-Type:\s*' . PLUGIN_GRAPHVIZ_CONTENT_TYPE . '#i', $getdata[0])) {
961+ return $getdata[1];
962+ }
963+
964+ if (preg_match('#Content-Type:\s*text/plain#i', $getdata[0])) {
965+ $error = $getdata[1];
966+ }
967+
968+ return FALSE;
969+}
970+
971+// URL safe encoding
972+function graphviz_urlsafe_encode($str)
973+{
974+ return str_replace(array('+', '/', '='), array('-', '_', '.'), base64_encode($str));
975+}
976+
977+// URL safe decoding
978+function graphviz_urlsafe_decode($str)
979+{
980+ return base64_decode(str_replace(array('-', '_', '.'), array('+', '/', '='), $str));
981+}
982+
983+?>
Show on old repository browser