OSDN Git Service

a15e84864cbfd08fc55b0c12006a151d066c7eb4
[pukiwiki/pukiwiki.git] / lib / backup.php
1 <?php
2 /**
3  *
4  * PukiWiki - Yet another WikiWikiWeb clone.
5  *
6  * backup.php
7  *
8  * バックアップを管理する
9  *
10  * @package org.pukiwiki
11  * @access  public
12  * @author
13  * @create
14  * @version $Id: backup.php,v 1.13 2011/01/25 15:01:01 henoheno Exp $
15  * Copyright (C)
16  *   2002-2016 PukiWiki Development Team
17  *   2001-2002 Originally written by yu-ji
18  * License: GPL v2 or (at your option) any later version
19  **/
20
21 /**
22  * make_backup
23  * バックアップを作成する
24  *
25  * @access    public
26  * @param     String    $page        ページ名
27  * @param     Boolean   $delete      TRUE:バックアップを削除する
28  *
29  * @return    Void
30  */
31
32 function make_backup($page, $delete = FALSE)
33 {
34         global $cycle, $maxage;
35         global $do_backup, $del_backup;
36         global $auth_user;
37
38         if (PKWK_READONLY || ! $do_backup) return;
39
40         if ($del_backup && $delete) {
41                 _backup_delete($page);
42                 return;
43         }
44
45         if (! is_page($page)) return;
46
47         $lastmod = _backup_get_filetime($page);
48         $backups = get_backup($page);
49         $is_author_differ = false;
50         $need_backup_by_time = $lastmod == 0 || UTIME - $lastmod > 60 * 60 * $cycle;
51         if (!$need_backup_by_time) {
52                 // Backup file is saved recently, but the author may differ.
53                 $last_content = get_source($page, FALSE, TRUE);
54                 $m = array();
55                 if (preg_match('/^\s*#author\("([^"]+)","([^"]+)","([^"]*)"\)/m', $last_content, $m)) {
56                         $prev_author = $m[2];
57                         $simple_author =preg_replace('/^[^:]:/', '', $prev_author);
58                         if ($simple_author !== $auth_user) {
59                                 $is_author_differ = true;
60                         }
61                 }
62         }
63         if ($need_backup_by_time || $is_author_differ)
64         {
65                 $backups = get_backup($page);
66                 $count   = count($backups) + 1;
67
68                 // 直後に1件追加するので、(最大件数 - 1)を超える要素を捨てる
69                 if ($count > $maxage)
70                         array_splice($backups, 0, $count - $maxage);
71
72                 $strout = '';
73                 foreach($backups as $age=>$data) {
74                         $strout .= PKWK_SPLITTER . ' ' . $data['time'] . "\n"; // Splitter format
75                         $strout .= join('', $data['data']);
76                         unset($backups[$age]);
77                 }
78                 $strout = preg_replace("/([^\n])\n*$/", "$1\n", $strout);
79
80                 // Escape 'lines equal to PKWK_SPLITTER', by inserting a space
81                 $body = preg_replace('/^(' . preg_quote(PKWK_SPLITTER) . "\s\d+)$/", '$1 ', get_source($page));
82                 $body = PKWK_SPLITTER . ' ' . get_filetime($page) . "\n" . join('', $body);
83                 $body = preg_replace("/\n*$/", "\n", $body);
84
85                 $fp = _backup_fopen($page, 'wb')
86                         or die_message('Cannot open ' . htmlsc(_backup_get_filename($page)) .
87                         '<br />Maybe permission is not writable or filename is too long');
88                 _backup_fputs($fp, $strout);
89                 _backup_fputs($fp, $body);
90                 _backup_fclose($fp);
91         }
92 }
93
94 /**
95  * get_backup
96  * バックアップを取得する
97  * $age = 0または省略 : 全てのバックアップデータを配列で取得する
98  * $age > 0           : 指定した世代のバックアップデータを取得する
99  *
100  * @access    public
101  * @param     String    $page        ページ名
102  * @param     Integer   $age         バックアップの世代番号 省略時は全て
103  *
104  * @return    String    バックアップ       ($age != 0)
105  *            Array     バックアップの配列 ($age == 0)
106  */
107 function get_backup($page, $age = 0)
108 {
109         $lines = _backup_file($page);
110         if (! is_array($lines)) return array();
111
112         $_age = 0;
113         $retvars = $match = array();
114         $regex_splitter = '/^' . preg_quote(PKWK_SPLITTER) . '\s(\d+)$/';
115         foreach($lines as $index => $line) {
116                 if (preg_match($regex_splitter, $line, $match)) {
117                         // A splitter, tells new data of backup will come
118                         ++$_age;
119                         if ($age > 0 && $_age > $age)
120                                 return $retvars[$age];
121
122                         // Allocate
123                         $retvars[$_age] = array('time'=>$match[1], 'data'=>array());
124                 } else if (preg_match('/^\s*#author\("([^"]+)","([^"]+)","([^"]*)"\)/', $line, $match)) {
125                         $retvars[$_age]['author_datetime'] = $match[1];
126                         $retvars[$_age]['author'] = $match[2];
127                         $retvars[$_age]['author_fullname'] = $match[3];
128                         $retvars[$_age]['data'][] = $line;
129                 } else {
130                         // The first ... the last line of the data
131                         $retvars[$_age]['data'][] = $line;
132                 }
133                 unset($lines[$index]);
134         }
135
136         return $retvars;
137 }
138
139 /**
140  * _backup_get_filename
141  * バックアップファイル名を取得する
142  *
143  * @access    private
144  * @param     String    $page        ページ名
145  *
146  * @return    String    バックアップのファイル名
147  */
148 function _backup_get_filename($page)
149 {
150         return BACKUP_DIR . encode($page) . BACKUP_EXT;
151 }
152
153 /**
154  * _backup_file_exists
155  * バックアップファイルが存在するか
156  *
157  * @access    private
158  * @param     String    $page        ページ名
159  *
160  * @return    Boolean   TRUE:ある FALSE:ない
161  */
162 function _backup_file_exists($page)
163 {
164         return file_exists(_backup_get_filename($page));
165 }
166
167 /**
168  * _backup_get_filetime
169  * バックアップファイルの更新時刻を得る
170  *
171  * @access    private
172  * @param     String    $page        ページ名
173  *
174  * @return    Integer   ファイルの更新時刻(GMT)
175  */
176
177 function _backup_get_filetime($page)
178 {
179         return _backup_file_exists($page) ?
180                 filemtime(_backup_get_filename($page)) - LOCALZONE : 0;
181 }
182
183 /**
184  * _backup_delete
185  * バックアップファイルを削除する
186  *
187  * @access    private
188  * @param     String    $page        ページ名
189  *
190  * @return    Boolean   FALSE:失敗
191  */
192 function _backup_delete($page)
193 {
194         return unlink(_backup_get_filename($page));
195 }
196
197 /////////////////////////////////////////////////
198
199 if (extension_loaded('zlib')) {
200         // ファイルシステム関数
201         // zlib関数を使用
202         define('BACKUP_EXT', '.gz');
203
204 /**
205  * _backup_fopen
206  * バックアップファイルを開く
207  *
208  * @access    private
209  * @param     String    $page        ページ名
210  * @param     String    $mode        モード
211  *
212  * @return    Boolean   FALSE:失敗
213  */
214         function _backup_fopen($page, $mode)
215         {
216                 return gzopen(_backup_get_filename($page), $mode);
217         }
218
219 /**
220  * _backup_fputs
221  * バックアップファイルに書き込む
222  *
223  * @access    private
224  * @param     Integer   $zp          ファイルポインタ
225  * @param     String    $str         文字列
226  *
227  * @return    Boolean   FALSE:失敗 その他:書き込んだバイト数
228  */
229         function _backup_fputs($zp, $str)
230         {
231                 return gzputs($zp, $str);
232         }
233
234 /**
235  * _backup_fclose
236  * バックアップファイルを閉じる
237  *
238  * @access    private
239  * @param     Integer   $zp          ファイルポインタ
240  *
241  * @return    Boolean   FALSE:失敗
242  */
243         function _backup_fclose($zp)
244         {
245                 return gzclose($zp);
246         }
247
248 /**
249  * _backup_file
250  * バックアップファイルの内容を取得する
251  *
252  * @access    private
253  * @param     String    $page        ページ名
254  *
255  * @return    Array     ファイルの内容
256  */
257         function _backup_file($page)
258         {
259                 return _backup_file_exists($page) ?
260                         gzfile(_backup_get_filename($page)) :
261                         array();
262         }
263 }
264 /////////////////////////////////////////////////
265 else
266 {
267         // ファイルシステム関数
268         define('BACKUP_EXT', '.txt');
269
270 /**
271  * _backup_fopen
272  * バックアップファイルを開く
273  *
274  * @access    private
275  * @param     String    $page        ページ名
276  * @param     String    $mode        モード
277  *
278  * @return    Boolean   FALSE:失敗
279  */
280         function _backup_fopen($page, $mode)
281         {
282                 return fopen(_backup_get_filename($page), $mode);
283         }
284
285 /**
286  * _backup_fputs
287  * バックアップファイルに書き込む
288  *
289  * @access    private
290  * @param     Integer   $zp          ファイルポインタ
291  * @param     String    $str         文字列
292  *
293  * @return    Boolean   FALSE:失敗 その他:書き込んだバイト数
294  */
295         function _backup_fputs($zp, $str)
296         {
297                 return fputs($zp, $str);
298         }
299
300 /**
301  * _backup_fclose
302  * バックアップファイルを閉じる
303  *
304  * @access    private
305  * @param     Integer   $zp          ファイルポインタ
306  *
307  * @return    Boolean   FALSE:失敗
308  */
309         function _backup_fclose($zp)
310         {
311                 return fclose($zp);
312         }
313
314 /**
315  * _backup_file
316  * バックアップファイルの内容を取得する
317  *
318  * @access    private
319  * @param     String    $page        ページ名
320  *
321  * @return    Array     ファイルの内容
322  */
323         function _backup_file($page)
324         {
325                 return _backup_file_exists($page) ?
326                         file(_backup_get_filename($page)) :
327                         array();
328         }
329 }