2 // PukiWiki - Yet another WikiWikiWeb clone
3 // $Id: link.php,v 1.20 2011/01/25 15:01:01 henoheno Exp $
4 // Copyright (C) 2003-2007 PukiWiki Developers Team
5 // License: GPL v2 or (at your option) any later version
7 // Backlinks / AutoLinks related functions
9 // ------------------------------------------------------------
10 // DATA STRUCTURE of *.ref and *.rel files
12 // CACHE_DIR/encode('foobar').ref
13 // ---------------------------------
14 // Page-name1<tab>0<\n>
15 // Page-name2<tab>1<\n>
17 // Page-nameN<tab>0<\n>
19 // 0 = Added when link(s) to 'foobar' added clearly at this page
20 // 1 = Added when the sentence 'foobar' found from the page
21 // by AutoLink feature
23 // CACHE_DIR/encode('foobar').rel
24 // ---------------------------------
25 // Page-name1<tab>Page-name2<tab> ... <tab>Page-nameN
27 // List of page-names linked from 'foobar'
29 // ------------------------------------------------------------
33 function links_get_related_db($page)
35 $ref_name = CACHE_DIR . encode($page) . '.ref';
36 if (! file_exists($ref_name)) return array();
39 foreach (file($ref_name) as $line) {
40 list($_page) = explode("\t", rtrim($line));
41 $time = get_filetime($_page);
42 if($time != 0) $times[$_page] = $time;
48 function links_update($page)
50 if (PKWK_READONLY) return; // Do nothing
52 if (ini_get('safe_mode') == '0') set_time_limit(0);
54 $time = is_page($page, TRUE) ? get_filetime($page) : 0;
57 $rel_file = CACHE_DIR . encode($page) . '.rel';
58 $rel_file_exist = file_exists($rel_file);
59 if ($rel_file_exist === TRUE) {
60 $lines = file($rel_file);
63 $rel_old = explode("\t", rtrim($lines[0]));
65 $rel_new = array(); // 参照先
66 $rel_auto = array(); // オートリンクしている参照先
67 $links = links_get_objects($page, TRUE);
68 foreach ($links as $_obj) {
69 if (! isset($_obj->type) || $_obj->type != 'pagename' ||
70 $_obj->name === $page || $_obj->name == '')
73 if (is_a($_obj, 'Link_autolink')) { // 行儀が悪い
74 $rel_auto[] = $_obj->name;
76 $rel_new[] = $_obj->name;
79 $rel_new = array_unique($rel_new);
81 // autolinkしか向いていないページ
82 $rel_auto = array_diff(array_unique($rel_auto), $rel_new);
85 $rel_new = array_merge($rel_new, $rel_auto);
87 // .rel:$pageが参照しているページの一覧
90 if (! empty($rel_new)) {
91 $fp = fopen($rel_file, 'w')
92 or die_message('cannot write ' . htmlsc($rel_file));
93 fputs($fp, join("\t", $rel_new));
98 // .ref:$_pageを参照しているページの一覧
99 links_add($page, array_diff($rel_new, $rel_old), $rel_auto);
100 links_delete($page, array_diff($rel_old, $rel_new));
102 global $WikiName, $autolink, $nowikiname;
104 // $pageが新規作成されたページで、AutoLinkの対象となり得る場合
105 if ($time && ! $rel_file_exist && $autolink
106 && (preg_match("/^$WikiName$/", $page) ? $nowikiname : strlen($page) >= $autolink))
108 // $pageを参照していそうなページを一斉更新する(おい)
109 $pages = links_do_search_page($page);
110 foreach ($pages as $_page) {
111 if ($_page !== $page)
112 links_update($_page);
115 $ref_file = CACHE_DIR . encode($page) . '.ref';
118 if (! $time && file_exists($ref_file)) {
119 foreach (file($ref_file) as $line) {
120 list($ref_page, $ref_auto) = explode("\t", rtrim($line));
122 // $pageをAutoLinkでしか参照していないページを一斉更新する(おいおい)
124 links_delete($ref_page, array($page));
129 // Init link cache (Called from link plugin)
130 function links_init()
134 if (PKWK_READONLY) return; // Do nothing
136 if (ini_get('safe_mode') == '0') set_time_limit(0);
139 foreach (get_existfiles(CACHE_DIR, '.ref') as $cache)
141 foreach (get_existfiles(CACHE_DIR, '.rel') as $cache)
144 $ref = array(); // 参照元
145 foreach (get_existpages() as $page) {
146 if ($page == $whatsnew) continue;
148 $rel = array(); // 参照先
149 $links = links_get_objects($page);
150 foreach ($links as $_obj) {
151 if (! isset($_obj->type) || $_obj->type != 'pagename' ||
152 $_obj->name == $page || $_obj->name == '')
155 $rel[] = $_obj->name;
156 if (! isset($ref[$_obj->name][$page]))
157 $ref[$_obj->name][$page] = 1;
158 if (! is_a($_obj, 'Link_autolink'))
159 $ref[$_obj->name][$page] = 0;
161 $rel = array_unique($rel);
163 $fp = fopen(CACHE_DIR . encode($page) . '.rel', 'w')
164 or die_message('cannot write ' . htmlsc(CACHE_DIR . encode($page) . '.rel'));
165 fputs($fp, join("\t", $rel));
170 foreach ($ref as $page=>$arr) {
171 $fp = fopen(CACHE_DIR . encode($page) . '.ref', 'w')
172 or die_message('cannot write ' . htmlsc(CACHE_DIR . encode($page) . '.ref'));
173 foreach ($arr as $ref_page=>$ref_auto)
174 fputs($fp, $ref_page . "\t" . $ref_auto . "\n");
179 function links_add($page, $add, $rel_auto)
181 if (PKWK_READONLY) return; // Do nothing
183 $rel_auto = array_flip($rel_auto);
185 foreach ($add as $_page) {
186 $all_auto = isset($rel_auto[$_page]);
187 $is_page = is_page($_page);
188 $ref = $page . "\t" . ($all_auto ? 1 : 0) . "\n";
190 $ref_file = CACHE_DIR . encode($_page) . '.ref';
191 if (file_exists($ref_file)) {
192 foreach (file($ref_file) as $line) {
193 list($ref_page, $ref_auto) = explode("\t", rtrim($line));
194 if (! $ref_auto) $all_auto = FALSE;
195 if ($ref_page !== $page) $ref .= $line;
199 if ($is_page || ! $all_auto) {
200 $fp = fopen($ref_file, 'w')
201 or die_message('cannot write ' . htmlsc($ref_file));
208 function links_delete($page, $del)
210 if (PKWK_READONLY) return; // Do nothing
212 foreach ($del as $_page) {
213 $ref_file = CACHE_DIR . encode($_page) . '.ref';
214 if (! file_exists($ref_file)) continue;
217 $is_page = is_page($_page);
220 foreach (file($ref_file) as $line) {
221 list($ref_page, $ref_auto) = explode("\t", rtrim($line));
222 if ($ref_page !== $page) {
223 if (! $ref_auto) $all_auto = FALSE;
228 if (($is_page || ! $all_auto) && $ref != '') {
229 $fp = fopen($ref_file, 'w')
230 or die_message('cannot write ' . htmlsc($ref_file));
237 function & links_get_objects($page, $refresh = FALSE)
241 if (! isset($obj) || $refresh)
242 $obj = new InlineConverter(NULL, array('note'));
244 $result = $obj->get_objects(join('', preg_grep('/^(?!\/\/|\s)./', get_source($page))), $page);
249 * Search function for AutoLink updating
251 * @param $word page name
252 * @return list of page name that contains $word
254 function links_do_search_page($word)
258 $keys = get_search_words(preg_split('/\s+/', $word, -1, PREG_SPLIT_NO_EMPTY));
259 foreach ($keys as $key=>$value)
260 $keys[$key] = '/' . $value . '/S';
261 $pages = get_existpages();
262 $pages = array_flip($pages);
263 unset($pages[$whatsnew]);
264 $count = count($pages);
265 foreach (array_keys($pages) as $page) {
267 // Search for page contents
268 foreach ($keys as $key) {
269 $lines = remove_author_lines(get_source($page, TRUE, FALSE));
270 $b_match = preg_match($key, join('', $lines));
271 if (! $b_match) break; // OR
273 if ($b_match) continue;
274 unset($pages[$page]); // Miss
276 return array_keys($pages);