4 * PukiWiki - Yet another WikiWikiWeb clone.
10 * @package org.pukiwiki
15 * 2002-2016 PukiWiki Development Team
16 * 2001-2002 Originally written by yu-ji
17 * License: GPL v2 or (at your option) any later version
25 * @param String $page ページ名
26 * @param Boolean $delete TRUE:バックアップを削除する
31 function make_backup($page, $is_delete, $wikitext)
33 global $cycle, $maxage;
34 global $do_backup, $del_backup;
37 if (PKWK_READONLY || ! $do_backup) return;
39 if ($del_backup && $is_delete) {
40 _backup_delete($page);
44 if (! is_page($page)) return;
46 $lastmod = _backup_get_filetime($page);
47 $backups = get_backup($page);
48 $is_author_differ = false;
49 $need_backup_by_time = $lastmod == 0 || UTIME - $lastmod > 60 * 60 * $cycle;
50 if (!$need_backup_by_time) {
51 // Backup file is saved recently, but the author may differ.
52 $last_content = get_source($page, TRUE, TRUE);
55 if (preg_match('/^#author\("([^"]+)","([^"]*)","([^"]*)"\)/m', $last_content, $m)) {
56 $prev_author = preg_replace('/^[^:]+:/', '', $m[2]);
58 if ($prev_author !== $auth_user) {
59 $is_author_differ = true;
62 if ($need_backup_by_time || $is_author_differ || $is_delete)
64 $backups = get_backup($page);
65 $count = count($backups) + 1;
66 // 直後に1件追加するので、(最大件数 - 1)を超える要素を捨てる
68 array_splice($backups, 0, $count - $maxage);
71 foreach($backups as $age=>$data) {
72 $strout .= PKWK_SPLITTER . ' ' . $data['time'] . "\n"; // Splitter format
73 $strout .= join('', $data['data']);
74 unset($backups[$age]);
76 $strout = preg_replace("/([^\n])\n*$/", "$1\n", $strout);
78 // Escape 'lines equal to PKWK_SPLITTER', by inserting a space
79 $body = preg_replace('/^(' . preg_quote(PKWK_SPLITTER) . "\s\d+)$/", '$1 ', get_source($page));
80 $body = PKWK_SPLITTER . ' ' . get_filetime($page) . "\n" . join('', $body);
81 $body = preg_replace("/\n*$/", "\n", $body);
84 $body_on_delete = PKWK_SPLITTER . ' ' . UTIME . "\n" . $wikitext;
85 $body_on_delete = preg_replace("/\n*$/", "\n", $body_on_delete);
87 $fp = _backup_fopen($page, 'wb')
88 or die_message('Cannot open ' . htmlsc(_backup_get_filename($page)) .
89 '<br />Maybe permission is not writable or filename is too long');
90 _backup_fputs($fp, $strout);
91 _backup_fputs($fp, $body);
92 _backup_fputs($fp, $body_on_delete);
100 * $age = 0または省略 : 全てのバックアップデータを配列で取得する
101 * $age > 0 : 指定した世代のバックアップデータを取得する
104 * @param String $page ページ名
105 * @param Integer $age バックアップの世代番号 省略時は全て
107 * @return String バックアップ ($age != 0)
108 * Array バックアップの配列 ($age == 0)
110 function get_backup($page, $age = 0)
112 $lines = _backup_file($page);
113 if (! is_array($lines)) return array();
116 $retvars = $match = array();
117 $regex_splitter = '/^' . preg_quote(PKWK_SPLITTER) . '\s(\d+)$/';
118 foreach($lines as $index => $line) {
119 if (preg_match($regex_splitter, $line, $match)) {
120 // A splitter, tells new data of backup will come
122 if ($age > 0 && $_age > $age)
123 return $retvars[$age];
126 $retvars[$_age] = array('time'=>$match[1], 'data'=>array());
127 } else if (preg_match('/^\s*#author\("([^"]+)","([^"]+)","([^"]*)"\)/', $line, $match)) {
128 $retvars[$_age]['author_datetime'] = $match[1];
129 $retvars[$_age]['author'] = $match[2];
130 $retvars[$_age]['author_fullname'] = $match[3];
131 $retvars[$_age]['data'][] = $line;
133 // The first ... the last line of the data
134 $retvars[$_age]['data'][] = $line;
136 unset($lines[$index]);
143 * _backup_get_filename
147 * @param String $page ページ名
149 * @return String バックアップのファイル名
151 function _backup_get_filename($page)
153 return BACKUP_DIR . encode($page) . BACKUP_EXT;
157 * _backup_file_exists
161 * @param String $page ページ名
163 * @return Boolean TRUE:ある FALSE:ない
165 function _backup_file_exists($page)
167 return file_exists(_backup_get_filename($page));
171 * _backup_get_filetime
175 * @param String $page ページ名
177 * @return Integer ファイルの更新時刻(GMT)
180 function _backup_get_filetime($page)
182 return _backup_file_exists($page) ?
183 filemtime(_backup_get_filename($page)) - LOCALZONE : 0;
191 * @param String $page ページ名
193 * @return Boolean FALSE:失敗
195 function _backup_delete($page)
197 return unlink(_backup_get_filename($page));
200 /////////////////////////////////////////////////
202 if (extension_loaded('zlib')) {
205 define('BACKUP_EXT', '.gz');
212 * @param String $page ページ名
213 * @param String $mode モード
215 * @return Boolean FALSE:失敗
217 function _backup_fopen($page, $mode)
219 return gzopen(_backup_get_filename($page), $mode);
227 * @param Integer $zp ファイルポインタ
228 * @param String $str 文字列
230 * @return Boolean FALSE:失敗 その他:書き込んだバイト数
232 function _backup_fputs($zp, $str)
234 return gzputs($zp, $str);
242 * @param Integer $zp ファイルポインタ
244 * @return Boolean FALSE:失敗
246 function _backup_fclose($zp)
256 * @param String $page ページ名
258 * @return Array ファイルの内容
260 function _backup_file($page)
262 return _backup_file_exists($page) ?
263 gzfile(_backup_get_filename($page)) :
267 /////////////////////////////////////////////////
271 define('BACKUP_EXT', '.txt');
278 * @param String $page ページ名
279 * @param String $mode モード
281 * @return Boolean FALSE:失敗
283 function _backup_fopen($page, $mode)
285 return fopen(_backup_get_filename($page), $mode);
293 * @param Integer $zp ファイルポインタ
294 * @param String $str 文字列
296 * @return Boolean FALSE:失敗 その他:書き込んだバイト数
298 function _backup_fputs($zp, $str)
300 return fputs($zp, $str);
308 * @param Integer $zp ファイルポインタ
310 * @return Boolean FALSE:失敗
312 function _backup_fclose($zp)
322 * @param String $page ページ名
324 * @return Array ファイルの内容
326 function _backup_file($page)
328 return _backup_file_exists($page) ?
329 file(_backup_get_filename($page)) :