4 * PukiWiki - Yet another WikiWikiWeb clone.
10 * @package org.pukiwiki
14 * @version $Id: backup.php,v 1.13 2011/01/25 15:01:01 henoheno Exp $
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
26 * @param String $page ページ名
27 * @param Boolean $delete TRUE:バックアップを削除する
32 function make_backup($page, $delete = FALSE)
34 global $cycle, $maxage;
35 global $do_backup, $del_backup;
38 if (PKWK_READONLY || ! $do_backup) return;
40 if ($del_backup && $delete) {
41 _backup_delete($page);
45 if (! is_page($page)) return;
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);
55 if (preg_match('/^\s*#author\("([^"]+)","([^"]+)","([^"]*)"\)/m', $last_content, $m)) {
57 $simple_author =preg_replace('/^[^:]:/', '', $prev_author);
58 if ($simple_author !== $auth_user) {
59 $is_author_differ = true;
63 if ($need_backup_by_time || $is_author_differ)
65 $backups = get_backup($page);
66 $count = count($backups) + 1;
68 // 直後に1件追加するので、(最大件数 - 1)を超える要素を捨てる
70 array_splice($backups, 0, $count - $maxage);
73 foreach($backups as $age=>$data) {
74 $strout .= PKWK_SPLITTER . ' ' . $data['time'] . "\n"; // Splitter format
75 $strout .= join('', $data['data']);
76 unset($backups[$age]);
78 $strout = preg_replace("/([^\n])\n*$/", "$1\n", $strout);
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);
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);
97 * $age = 0または省略 : 全てのバックアップデータを配列で取得する
98 * $age > 0 : 指定した世代のバックアップデータを取得する
101 * @param String $page ページ名
102 * @param Integer $age バックアップの世代番号 省略時は全て
104 * @return String バックアップ ($age != 0)
105 * Array バックアップの配列 ($age == 0)
107 function get_backup($page, $age = 0)
109 $lines = _backup_file($page);
110 if (! is_array($lines)) return array();
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
119 if ($age > 0 && $_age > $age)
120 return $retvars[$age];
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;
130 // The first ... the last line of the data
131 $retvars[$_age]['data'][] = $line;
133 unset($lines[$index]);
140 * _backup_get_filename
144 * @param String $page ページ名
146 * @return String バックアップのファイル名
148 function _backup_get_filename($page)
150 return BACKUP_DIR . encode($page) . BACKUP_EXT;
154 * _backup_file_exists
158 * @param String $page ページ名
160 * @return Boolean TRUE:ある FALSE:ない
162 function _backup_file_exists($page)
164 return file_exists(_backup_get_filename($page));
168 * _backup_get_filetime
172 * @param String $page ページ名
174 * @return Integer ファイルの更新時刻(GMT)
177 function _backup_get_filetime($page)
179 return _backup_file_exists($page) ?
180 filemtime(_backup_get_filename($page)) - LOCALZONE : 0;
188 * @param String $page ページ名
190 * @return Boolean FALSE:失敗
192 function _backup_delete($page)
194 return unlink(_backup_get_filename($page));
197 /////////////////////////////////////////////////
199 if (extension_loaded('zlib')) {
202 define('BACKUP_EXT', '.gz');
209 * @param String $page ページ名
210 * @param String $mode モード
212 * @return Boolean FALSE:失敗
214 function _backup_fopen($page, $mode)
216 return gzopen(_backup_get_filename($page), $mode);
224 * @param Integer $zp ファイルポインタ
225 * @param String $str 文字列
227 * @return Boolean FALSE:失敗 その他:書き込んだバイト数
229 function _backup_fputs($zp, $str)
231 return gzputs($zp, $str);
239 * @param Integer $zp ファイルポインタ
241 * @return Boolean FALSE:失敗
243 function _backup_fclose($zp)
253 * @param String $page ページ名
255 * @return Array ファイルの内容
257 function _backup_file($page)
259 return _backup_file_exists($page) ?
260 gzfile(_backup_get_filename($page)) :
264 /////////////////////////////////////////////////
268 define('BACKUP_EXT', '.txt');
275 * @param String $page ページ名
276 * @param String $mode モード
278 * @return Boolean FALSE:失敗
280 function _backup_fopen($page, $mode)
282 return fopen(_backup_get_filename($page), $mode);
290 * @param Integer $zp ファイルポインタ
291 * @param String $str 文字列
293 * @return Boolean FALSE:失敗 その他:書き込んだバイト数
295 function _backup_fputs($zp, $str)
297 return fputs($zp, $str);
305 * @param Integer $zp ファイルポインタ
307 * @return Boolean FALSE:失敗
309 function _backup_fclose($zp)
319 * @param String $page ページ名
321 * @return Array ファイルの内容
323 function _backup_file($page)
325 return _backup_file_exists($page) ?
326 file(_backup_get_filename($page)) :