OSDN Git Service

BugTrack/2260 Use get_base_uri() instead of $script
[pukiwiki/pukiwiki.git] / plugin / rename.inc.php
1 <?php
2 // PukiWiki - Yet another WikiWikiWeb clone
3 // rename.inc.php
4 // Copyright 2002-2017 PukiWiki Development Team
5 // License: GPL v2 or (at your option) any later version
6 //
7 // Rename plugin: Rename page-name and related data
8 //
9 // Usage: http://path/to/pukiwikiphp?plugin=rename[&refer=page_name]
10
11 define('PLUGIN_RENAME_LOGPAGE', ':RenameLog');
12
13 if (file_exists(PLUGIN_DIR . 'counter.inc.php'))
14         require_once(PLUGIN_DIR . 'counter.inc.php');
15
16 function plugin_rename_action()
17 {
18         global $whatsnew;
19
20         if (PKWK_READONLY) die_message('PKWK_READONLY prohibits this');
21
22         $method = plugin_rename_getvar('method');
23         if ($method == 'regex') {
24                 $src = plugin_rename_getvar('src');
25                 if ($src == '') return plugin_rename_phase1();
26
27                 $src_pattern = '/' . preg_quote($src, '/') . '/';
28                 $arr0 = preg_grep($src_pattern, get_existpages());
29                 if (! is_array($arr0) || empty($arr0))
30                         return plugin_rename_phase1('nomatch');
31
32                 $dst = plugin_rename_getvar('dst');
33                 $arr1 = preg_replace($src_pattern, $dst, $arr0);
34                 foreach ($arr1 as $page)
35                         if (! is_pagename($page))
36                                 return plugin_rename_phase1('notvalid');
37
38                 return plugin_rename_regex($arr0, $arr1);
39
40         } else {
41                 // $method == 'page'
42                 $page  = plugin_rename_getvar('page');
43                 $refer = plugin_rename_getvar('refer');
44
45                 if ($refer == '') {
46                         return plugin_rename_phase1();
47
48                 } else if (! is_page($refer)) {
49                         return plugin_rename_phase1('notpage', $refer);
50
51                 } else if ($refer === $whatsnew) {
52                         return plugin_rename_phase1('norename', $refer);
53
54                 } else if ($page == '' || $page === $refer) {
55                         return plugin_rename_phase2();
56
57                 } else if (! is_pagename($page)) {
58                         return plugin_rename_phase2('notvalid');
59
60                 } else {
61                         return plugin_rename_refer();
62                 }
63         }
64 }
65
66 // 変数を取得する
67 function plugin_rename_getvar($key)
68 {
69         global $vars;
70         return isset($vars[$key]) ? $vars[$key] : '';
71 }
72
73 // エラーメッセージを作る
74 function plugin_rename_err($err, $page = '')
75 {
76         global $_rename_messages;
77
78         if ($err == '') return '';
79
80         $body = $_rename_messages['err_' . $err];
81         if (is_array($page)) {
82                 $tmp = '';
83                 foreach ($page as $_page) $tmp .= '<br />' . $_page;
84                 $page = $tmp;
85         }
86         if ($page != '') $body = sprintf($body, htmlsc($page));
87
88         $msg = sprintf($_rename_messages['err'], $body);
89         return $msg;
90 }
91
92 //第一段階:ページ名または正規表現の入力
93 function plugin_rename_phase1($err = '', $page = '')
94 {
95         global $_rename_messages;
96
97         $script = get_base_uri();
98         $msg    = plugin_rename_err($err, $page);
99         $refer  = plugin_rename_getvar('refer');
100         $method = plugin_rename_getvar('method');
101
102         $radio_regex = $radio_page = '';
103         if ($method == 'regex') {
104                 $radio_regex = ' checked="checked"';
105         } else {
106                 $radio_page  = ' checked="checked"';
107         }
108         $select_refer = plugin_rename_getselecttag($refer);
109
110         $s_src = htmlsc(plugin_rename_getvar('src'));
111         $s_dst = htmlsc(plugin_rename_getvar('dst'));
112
113         $ret = array();
114         $ret['msg']  = $_rename_messages['msg_title'];
115         $ret['body'] = <<<EOD
116 $msg
117 <form action="$script" method="post">
118  <div>
119   <input type="hidden" name="plugin" value="rename" />
120   <input type="radio"  name="method" id="_p_rename_page" value="page"$radio_page />
121   <label for="_p_rename_page">{$_rename_messages['msg_page']}:</label>$select_refer<br />
122   <input type="radio"  name="method" id="_p_rename_regex" value="regex"$radio_regex />
123   <label for="_p_rename_regex">{$_rename_messages['msg_regex']}:</label><br />
124   <label for="_p_rename_from">From:</label><br />
125   <input type="text" name="src" id="_p_rename_from" size="80" value="$s_src" /><br />
126   <label for="_p_rename_to">To:</label><br />
127   <input type="text" name="dst" id="_p_rename_to"   size="80" value="$s_dst" /><br />
128   <input type="submit" value="{$_rename_messages['btn_next']}" /><br />
129  </div>
130 </form>
131 EOD;
132         return $ret;
133 }
134
135 //第二段階:新しい名前の入力
136 function plugin_rename_phase2($err = '')
137 {
138         global $_rename_messages;
139
140         $script = get_base_uri();
141         $msg   = plugin_rename_err($err);
142         $page  = plugin_rename_getvar('page');
143         $refer = plugin_rename_getvar('refer');
144         if ($page == '') $page = $refer;
145
146         $msg_related = '';
147         $related = plugin_rename_getrelated($refer);
148         if (! empty($related))
149                 $msg_related = '<label for="_p_rename_related">' . $_rename_messages['msg_do_related'] . '</label>' .
150                 '<input type="checkbox" name="related" id="_p_rename_related" value="1" checked="checked" /><br />';
151
152         $msg_rename = sprintf($_rename_messages['msg_rename'], make_pagelink($refer));
153         $s_page  = htmlsc($page);
154         $s_refer = htmlsc($refer);
155
156         $ret = array();
157         $ret['msg']  = $_rename_messages['msg_title'];
158         $ret['body'] = <<<EOD
159 $msg
160 <form action="$script" method="post">
161  <div>
162   <input type="hidden" name="plugin" value="rename" />
163   <input type="hidden" name="refer"  value="$s_refer" />
164   $msg_rename<br />
165   <label for="_p_rename_newname">{$_rename_messages['msg_newname']}:</label>
166   <input type="text" name="page" id="_p_rename_newname" size="80" value="$s_page" /><br />
167   $msg_related
168   <input type="submit" value="{$_rename_messages['btn_next']}" /><br />
169  </div>
170 </form>
171 EOD;
172         if (! empty($related)) {
173                 $ret['body'] .= '<hr /><p>' . $_rename_messages['msg_related'] . '</p><ul>';
174                 sort($related, SORT_STRING);
175                 foreach ($related as $name)
176                         $ret['body'] .= '<li>' . make_pagelink($name) . '</li>';
177                 $ret['body'] .= '</ul>';
178         }
179         return $ret;
180 }
181
182 //ページ名と関連するページを列挙し、phase3へ
183 function plugin_rename_refer()
184 {
185         $page  = plugin_rename_getvar('page');
186         $refer = plugin_rename_getvar('refer');
187
188         $pages[encode($refer)] = encode($page);
189         if (plugin_rename_getvar('related') != '') {
190                 $from = strip_bracket($refer);
191                 $to   = strip_bracket($page);
192                 foreach (plugin_rename_getrelated($refer) as $_page)
193                         $pages[encode($_page)] = encode(str_replace($from, $to, $_page));
194         }
195         return plugin_rename_phase3($pages);
196 }
197
198 //正規表現でページを置換
199 function plugin_rename_regex($arr_from, $arr_to)
200 {
201         $exists = array();
202         foreach ($arr_to as $page)
203                 if (is_page($page))
204                         $exists[] = $page;
205
206         if (! empty($exists)) {
207                 return plugin_rename_phase1('already', $exists);
208         } else {
209                 $pages = array();
210                 foreach ($arr_from as $refer)
211                         $pages[encode($refer)] = encode(array_shift($arr_to));
212                 return plugin_rename_phase3($pages);
213         }
214 }
215
216 function plugin_rename_phase3($pages)
217 {
218         global $_rename_messages;
219
220         $script = get_base_uri();
221         $msg = $input = '';
222         $files = plugin_rename_get_files($pages);
223
224         $exists = array();
225         foreach ($files as $_page=>$arr)
226                 foreach ($arr as $old=>$new)
227                         if (file_exists($new))
228                                 $exists[$_page][$old] = $new;
229
230         $pass = plugin_rename_getvar('pass');
231         if ($pass != '' && pkwk_login($pass)) {
232                 return plugin_rename_proceed($pages, $files, $exists);
233         } else if ($pass != '') {
234                 $msg = plugin_rename_err('adminpass');
235         }
236
237         $method = plugin_rename_getvar('method');
238         if ($method == 'regex') {
239                 $s_src = htmlsc(plugin_rename_getvar('src'));
240                 $s_dst = htmlsc(plugin_rename_getvar('dst'));
241                 $msg   .= $_rename_messages['msg_regex'] . '<br />';
242                 $input .= '<input type="hidden" name="method" value="regex" />';
243                 $input .= '<input type="hidden" name="src"    value="' . $s_src . '" />';
244                 $input .= '<input type="hidden" name="dst"    value="' . $s_dst . '" />';
245         } else {
246                 $s_refer   = htmlsc(plugin_rename_getvar('refer'));
247                 $s_page    = htmlsc(plugin_rename_getvar('page'));
248                 $s_related = htmlsc(plugin_rename_getvar('related'));
249                 $msg   .= $_rename_messages['msg_page'] . '<br />';
250                 $input .= '<input type="hidden" name="method"  value="page" />';
251                 $input .= '<input type="hidden" name="refer"   value="' . $s_refer   . '" />';
252                 $input .= '<input type="hidden" name="page"    value="' . $s_page    . '" />';
253                 $input .= '<input type="hidden" name="related" value="' . $s_related . '" />';
254         }
255
256         if (! empty($exists)) {
257                 $msg .= $_rename_messages['err_already_below'] . '<ul>';
258                 foreach ($exists as $page=>$arr) {
259                         $msg .= '<li>' . make_pagelink(decode($page));
260                         $msg .= $_rename_messages['msg_arrow'];
261                         $msg .= htmlsc(decode($pages[$page]));
262                         if (! empty($arr)) {
263                                 $msg .= '<ul>' . "\n";
264                                 foreach ($arr as $ofile=>$nfile)
265                                         $msg .= '<li>' . $ofile .
266                                         $_rename_messages['msg_arrow'] . $nfile . '</li>' . "\n";
267                                 $msg .= '</ul>';
268                         }
269                         $msg .= '</li>' . "\n";
270                 }
271                 $msg .= '</ul><hr />' . "\n";
272
273                 $input .= '<input type="radio" name="exist" value="0" checked="checked" />' .
274                         $_rename_messages['msg_exist_none'] . '<br />';
275                 $input .= '<input type="radio" name="exist" value="1" />' .
276                         $_rename_messages['msg_exist_overwrite'] . '<br />';
277         }
278
279         $ret = array();
280         $ret['msg'] = $_rename_messages['msg_title'];
281         $ret['body'] = <<<EOD
282 <p>$msg</p>
283 <form action="$script" method="post">
284  <div>
285   <input type="hidden" name="plugin" value="rename" />
286   $input
287   <label for="_p_rename_adminpass">{$_rename_messages['msg_adminpass']}</label>
288   <input type="password" name="pass" id="_p_rename_adminpass" value="" />
289   <input type="submit" value="{$_rename_messages['btn_submit']}" />
290  </div>
291 </form>
292 <p>{$_rename_messages['msg_confirm']}</p>
293 EOD;
294
295         ksort($pages, SORT_STRING);
296         $ret['body'] .= '<ul>' . "\n";
297         foreach ($pages as $old=>$new)
298                 $ret['body'] .= '<li>' .  make_pagelink(decode($old)) .
299                         $_rename_messages['msg_arrow'] .
300                         htmlsc(decode($new)) .  '</li>' . "\n";
301         $ret['body'] .= '</ul>' . "\n";
302         return $ret;
303 }
304
305 function plugin_rename_get_files($pages)
306 {
307         $files = array();
308         $dirs  = array(BACKUP_DIR, DIFF_DIR, DATA_DIR);
309         if (exist_plugin_convert('attach'))  $dirs[] = UPLOAD_DIR;
310         if (exist_plugin_convert('counter')) $dirs[] = COUNTER_DIR;
311         // and more ...
312
313         $matches = array();
314         foreach ($dirs as $path) {
315                 $dir = opendir($path);
316                 if (! $dir) continue;   // TODO: !== FALSE or die()?
317                 while (($file = readdir($dir)) !== FALSE) {
318                         if ($file == '.' || $file == '..') continue;
319                         foreach ($pages as $from => $to) {
320                                 // TODO: preg_quote()?
321                                 $pattern = '/^' . str_replace('/', '\/', $from) . '([._].+)$/';
322                                 if (preg_match($pattern, $file, $matches)) {
323                                         $newfile = $to . $matches[1];
324                                         $files[$from][$path . $file] = $path . $newfile;
325                                 }
326                         }
327                 }
328         }
329
330         return $files;
331 }
332
333 function plugin_rename_proceed($pages, $files, $exists)
334 {
335         global $now, $_rename_messages;
336
337         if (plugin_rename_getvar('exist') == '')
338                 foreach ($exists as $key=>$arr)
339                         unset($files[$key]);
340
341         set_time_limit(0);
342         foreach ($files as $page=>$arr) {
343                 foreach ($arr as $old=>$new) {
344                         if (isset($exists[$page][$old]) && $exists[$page][$old])
345                                 unlink($new);
346                         rename($old, $new);
347
348                         // linkデータベースを更新する BugTrack/327 arino
349                         links_update($old);
350                         links_update($new);
351                 }
352         }
353         // Rename counter
354         $pages_decoded = array();
355         foreach ($pages as $old=>$new) {
356                 $pages_decoded[decode($old)] = decode($new);
357         }
358         plugin_counter_page_rename($pages_decoded);
359
360         $postdata = get_source(PLUGIN_RENAME_LOGPAGE);
361         $postdata[] = '*' . $now . "\n";
362         if (plugin_rename_getvar('method') == 'regex') {
363                 $postdata[] = '-' . $_rename_messages['msg_regex'] . "\n";
364                 $postdata[] = '--From:[[' . plugin_rename_getvar('src') . ']]' . "\n";
365                 $postdata[] = '--To:[['   . plugin_rename_getvar('dst') . ']]' . "\n";
366         } else {
367                 $postdata[] = '-' . $_rename_messages['msg_page'] . "\n";
368                 $postdata[] = '--From:[[' . plugin_rename_getvar('refer') . ']]' . "\n";
369                 $postdata[] = '--To:[['   . plugin_rename_getvar('page')  . ']]' . "\n";
370         }
371
372         if (! empty($exists)) {
373                 $postdata[] = "\n" . $_rename_messages['msg_result'] . "\n";
374                 foreach ($exists as $page=>$arr) {
375                         $postdata[] = '-' . decode($page) .
376                                 $_rename_messages['msg_arrow'] . decode($pages[$page]) . "\n";
377                         foreach ($arr as $ofile=>$nfile)
378                                 $postdata[] = '--' . $ofile .
379                                         $_rename_messages['msg_arrow'] . $nfile . "\n";
380                 }
381                 $postdata[] = '----' . "\n";
382         }
383
384         foreach ($pages as $old=>$new)
385                 $postdata[] = '-' . decode($old) .
386                         $_rename_messages['msg_arrow'] . decode($new) . "\n";
387
388         // 更新の衝突はチェックしない。
389
390         // ファイルの書き込み
391         page_write(PLUGIN_RENAME_LOGPAGE, join('', $postdata));
392
393         // Refresh RecentChanges / Delete cache/recent.dat
394         delete_recent_changes_cache();
395
396         //リダイレクト
397         $page = plugin_rename_getvar('page');
398         if ($page == '') $page = PLUGIN_RENAME_LOGPAGE;
399
400         pkwk_headers_sent();
401         header('Location: ' . get_page_uri($page, PKWK_URI_ROOT));
402         exit;
403 }
404
405 function plugin_rename_getrelated($page)
406 {
407         $related = array();
408         $pages = get_existpages();
409         $pattern = '/(?:^|\/)' . preg_quote(strip_bracket($page), '/') . '(?:\/|$)/';
410         foreach ($pages as $name) {
411                 if ($name === $page) continue;
412                 if (preg_match($pattern, $name)) $related[] = $name;
413         }
414         return $related;
415 }
416
417 function plugin_rename_getselecttag($page)
418 {
419         global $whatsnew;
420
421         $pages = array();
422         foreach (get_existpages() as $_page) {
423                 if ($_page === $whatsnew) continue;
424
425                 $selected = ($_page === $page) ? ' selected' : '';
426                 $s_page = htmlsc($_page);
427                 $pages[$_page] = '<option value="' . $s_page . '"' . $selected . '>' .
428                         $s_page . '</option>';
429         }
430         ksort($pages, SORT_STRING);
431         $list = join("\n" . ' ', $pages);
432
433         return <<<EOD
434 <select name="refer">
435  <option value=""></option>
436  $list
437 </select>
438 EOD;
439
440 }