2 // PukiWiki - Yet another WikiWikiWeb clone
4 // Copyright 2003-2022 PukiWiki Development 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;
75 } else if (is_a($_obj, 'Link_autoalias')) {
76 $_alias = get_autoalias_right_link($_obj->name);
77 if (is_pagename($_alias)) {
78 $rel_auto[] = $_alias;
81 $rel_new[] = $_obj->name;
84 $rel_new = array_unique($rel_new);
86 // autolinkしか向いていないページ
87 $rel_auto = array_diff(array_unique($rel_auto), $rel_new);
90 $rel_new = array_merge($rel_new, $rel_auto);
92 // .rel:$pageが参照しているページの一覧
95 if (! empty($rel_new)) {
96 $fp = fopen($rel_file, 'w')
97 or die_message('cannot write ' . htmlsc($rel_file));
98 fputs($fp, join("\t", $rel_new));
103 // .ref:$_pageを参照しているページの一覧
104 links_add($page, array_diff($rel_new, $rel_old), $rel_auto);
105 links_delete($page, array_diff($rel_old, $rel_new));
107 global $WikiName, $autolink, $nowikiname;
109 // $pageが新規作成されたページで、AutoLinkの対象となり得る場合
110 if ($time && ! $rel_file_exist && $autolink
111 && (preg_match("/^$WikiName$/", $page) ? $nowikiname : strlen($page) >= $autolink))
113 // $pageを参照していそうなページを一斉更新する(おい)
114 $pages = links_do_search_page($page);
115 foreach ($pages as $_page) {
116 if ($_page !== $page)
117 links_update($_page);
120 $ref_file = CACHE_DIR . encode($page) . '.ref';
123 if (! $time && file_exists($ref_file)) {
124 foreach (file($ref_file) as $line) {
125 list($ref_page, $ref_auto) = explode("\t", rtrim($line));
127 // $pageをAutoLinkでしか参照していないページを一斉更新する(おいおい)
129 links_delete($ref_page, array($page));
134 // Init link cache (Called from link plugin)
135 function links_init()
139 if (PKWK_READONLY) return; // Do nothing
141 if (ini_get('safe_mode') == '0') set_time_limit(0);
144 foreach (get_existfiles(CACHE_DIR, '.ref') as $cache)
146 foreach (get_existfiles(CACHE_DIR, '.rel') as $cache)
149 $ref = array(); // 参照元
150 foreach (get_existpages() as $page) {
151 if ($page == $whatsnew) continue;
153 $rel = array(); // 参照先
154 $links = links_get_objects($page);
155 foreach ($links as $_obj) {
156 if (! isset($_obj->type) || $_obj->type != 'pagename' ||
157 $_obj->name == $page || $_obj->name == '') {
160 $_name = $_obj->name;
161 if (is_a($_obj, 'Link_autoalias')) {
162 $_alias = get_autoalias_right_link($_name);
163 if (! is_pagename($_alias)) {
164 continue; // not PageName
169 if (! isset($ref[$_name][$page])) {
170 $ref[$_name][$page] = 1;
172 if (! is_a($_obj, 'Link_autolink')) {
173 $ref[$_name][$page] = 0;
176 $rel = array_unique($rel);
178 $fp = fopen(CACHE_DIR . encode($page) . '.rel', 'w')
179 or die_message('cannot write ' . htmlsc(CACHE_DIR . encode($page) . '.rel'));
180 fputs($fp, join("\t", $rel));
185 foreach ($ref as $page=>$arr) {
186 $fp = fopen(CACHE_DIR . encode($page) . '.ref', 'w')
187 or die_message('cannot write ' . htmlsc(CACHE_DIR . encode($page) . '.ref'));
188 foreach ($arr as $ref_page=>$ref_auto)
189 fputs($fp, $ref_page . "\t" . $ref_auto . "\n");
194 function links_add($page, $add, $rel_auto)
196 if (PKWK_READONLY) return; // Do nothing
198 $rel_auto = array_flip($rel_auto);
200 foreach ($add as $_page) {
201 $all_auto = isset($rel_auto[$_page]);
202 $is_page = is_page($_page);
203 $ref = $page . "\t" . ($all_auto ? 1 : 0) . "\n";
205 $ref_file = CACHE_DIR . encode($_page) . '.ref';
206 if (file_exists($ref_file)) {
207 foreach (file($ref_file) as $line) {
208 list($ref_page, $ref_auto) = explode("\t", rtrim($line));
209 if (! $ref_auto) $all_auto = FALSE;
210 if ($ref_page !== $page) $ref .= $line;
215 if (! is_pagename_bytes_within_soft_limit($_page)) {
219 if ($is_page || ! $all_auto) {
220 $fp = fopen($ref_file, 'w')
221 or die_message('cannot write ' . htmlsc($ref_file));
228 function links_delete($page, $del)
230 if (PKWK_READONLY) return; // Do nothing
232 foreach ($del as $_page) {
233 $ref_file = CACHE_DIR . encode($_page) . '.ref';
234 if (! file_exists($ref_file)) continue;
237 $is_page = is_page($_page);
240 foreach (file($ref_file) as $line) {
241 list($ref_page, $ref_auto) = explode("\t", rtrim($line));
242 if ($ref_page !== $page) {
243 if (! $ref_auto) $all_auto = FALSE;
248 if (($is_page || ! $all_auto) && $ref != '') {
249 $fp = fopen($ref_file, 'w')
250 or die_message('cannot write ' . htmlsc($ref_file));
257 function & links_get_objects($page, $refresh = FALSE)
261 if (! isset($obj) || $refresh)
262 $obj = new InlineConverter(NULL, array('note'));
264 $result = $obj->get_objects(join('', preg_grep('/^(?!\/\/|\s)./', get_source($page))), $page);
269 * Search function for AutoLink updating
271 * @param $word page name
272 * @return list of page name that contains $word
274 function links_do_search_page($word)
278 $keys = get_search_words(preg_split('/\s+/', $word, -1, PREG_SPLIT_NO_EMPTY));
279 foreach ($keys as $key=>$value)
280 $keys[$key] = '/' . $value . '/S';
281 $pages = get_existpages();
282 $pages = array_flip($pages);
283 unset($pages[$whatsnew]);
284 $count = count($pages);
285 foreach (array_keys($pages) as $page) {
287 // Search for page contents
288 foreach ($keys as $key) {
289 $body = get_source($page, TRUE, TRUE, TRUE);
290 $b_match = preg_match($key, remove_author_header($body));
291 if (! $b_match) break; // OR
293 if ($b_match) continue;
294 unset($pages[$page]); // Miss
296 return array_keys($pages);