OSDN Git Service

4fb0d0854f1cf75becd981671f85115766dcd3e6
[pukiwiki/pukiwiki.git] / plugin / attach.inc.php
1 <?php
2 // PukiWiki - Yet another WikiWikiWeb clone
3 // $Id: attach.inc.php,v 1.80 2005/12/18 15:27:43 henoheno Exp $
4 // Copyright (C)
5 //   2003-2005 PukiWiki Developers Team
6 //   2002-2003 PANDA <panda@arino.jp> http://home.arino.jp/
7 //   2002      Y.MASUI <masui@hisec.co.jp> http://masui.net/pukiwiki/
8 //   2001-2002 Originally written by yu-ji
9 // License: GPL v2 or (at your option) any later version
10 //
11 // File attach plugin
12
13 // NOTE (PHP > 4.2.3):
14 //    This feature is disabled at newer version of PHP.
15 //    Set this at php.ini if you want.
16 // Max file size for upload on PHP (PHP default: 2MB)
17 ini_set('upload_max_filesize', '2M');
18
19 // Max file size for upload on script of PukiWikiX_FILESIZE
20 define('PLUGIN_ATTACH_MAX_FILESIZE', (1024 * 1024)); // default: 1MB
21
22 // ´ÉÍý¼Ô¤À¤±¤¬ÅºÉÕ¥Õ¥¡¥¤¥ë¤ò¥¢¥Ã¥×¥í¡¼¥É¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë
23 define('PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY', TRUE); // FALSE or TRUE
24
25 // ´ÉÍý¼Ô¤À¤±¤¬ÅºÉÕ¥Õ¥¡¥¤¥ë¤òºï½ü¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë
26 define('PLUGIN_ATTACH_DELETE_ADMIN_ONLY', TRUE); // FALSE or TRUE
27
28 // ´ÉÍý¼Ô¤¬ÅºÉÕ¥Õ¥¡¥¤¥ë¤òºï½ü¤¹¤ë¤È¤­¤Ï¡¢¥Ð¥Ã¥¯¥¢¥Ã¥×¤òºî¤é¤Ê¤¤
29 // PLUGIN_ATTACH_DELETE_ADMIN_ONLY=TRUE¤Î¤È¤­Í­¸ú
30 define('PLUGIN_ATTACH_DELETE_ADMIN_NOBACKUP', TRUE); // FALSE or TRUE
31
32 // ¥¢¥Ã¥×¥í¡¼¥É/ºï½ü»þ¤Ë¥Ñ¥¹¥ï¡¼¥É¤òÍ׵᤹¤ë(ADMIN_ONLY¤¬Í¥Àè)
33 define('PLUGIN_ATTACH_PASSWORD_REQUIRE', FALSE); // FALSE or TRUE
34
35 // ¥Õ¥¡¥¤¥ë¤Î¥¢¥¯¥»¥¹¸¢
36 define('PLUGIN_ATTACH_FILE_MODE', 0644);
37 //define('PLUGIN_ATTACH_FILE_MODE', 0604); // for XREA.COM
38
39 // File icon image
40 define('PLUGIN_ATTACH_FILE_ICON', '<img src="' . IMAGE_DIR .  'file.png"' .
41         ' width="20" height="20" alt="file"' .
42         ' style="border-width:0px" />');
43
44 // mime-type¤òµ­½Ò¤·¤¿¥Ú¡¼¥¸
45 define('PLUGIN_ATTACH_CONFIG_PAGE_MIME', 'plugin/attach/mime-type');
46
47 //-------- convert
48 function plugin_attach_convert()
49 {
50         global $vars;
51
52         $page = isset($vars['page']) ? $vars['page'] : '';
53
54         $nolist = $noform = FALSE;
55         if (func_num_args() > 0) {
56                 foreach (func_get_args() as $arg) {
57                         $arg = strtolower($arg);
58                         $nolist |= ($arg == 'nolist');
59                         $noform |= ($arg == 'noform');
60                 }
61         }
62
63         $ret = '';
64         if (! $nolist) {
65                 $obj  = & new AttachPages($page);
66                 $ret .= $obj->toString($page, TRUE);
67         }
68         if (! $noform) {
69                 $ret .= attach_form($page);
70         }
71
72         return $ret;
73 }
74
75 //-------- action
76 function plugin_attach_action()
77 {
78         global $vars, $_attach_messages;
79
80         // Backward compatible
81         if (isset($vars['openfile'])) {
82                 $vars['file'] = $vars['openfile'];
83                 $vars['pcmd'] = 'open';
84         }
85         if (isset($vars['delfile'])) {
86                 $vars['file'] = $vars['delfile'];
87                 $vars['pcmd'] = 'delete';
88         }
89
90         $pcmd  = isset($vars['pcmd'])  ? $vars['pcmd']  : '';
91         $refer = isset($vars['refer']) ? $vars['refer'] : '';
92         $pass  = isset($vars['pass'])  ? $vars['pass']  : NULL;
93         $page  = isset($vars['page'])  ? $vars['page']  : '';
94
95         if ($refer != '' && is_pagename($refer)) {
96                 if(in_array($pcmd, array('info', 'open', 'list'))) {
97                         check_readable($refer);
98                 } else {
99                         check_editable($refer);
100                 }
101         }
102
103         // Dispatch
104         if (isset($_FILES['attach_file'])) {
105                 // Upload
106                 return attach_upload($_FILES['attach_file'], $refer, $pass);
107         } else {
108                 switch ($pcmd) {
109                 case 'delete':  /*FALLTHROUGH*/
110                 case 'freeze':
111                 case 'unfreeze':
112                         if (PKWK_READONLY) die_message('PKWK_READONLY prohibits editing');
113                 }
114                 switch ($pcmd) {
115                 case 'info'     : return attach_info();
116                 case 'delete'   : return attach_delete();
117                 case 'open'     : return attach_open();
118                 case 'list'     : return attach_list();
119                 case 'freeze'   : return attach_freeze(TRUE);
120                 case 'unfreeze' : return attach_freeze(FALSE);
121                 case 'upload'   : return attach_showform();
122                 }
123                 if ($page == '' || ! is_page($page)) {
124                         return attach_list();
125                 } else {
126                         return attach_showform();
127                 }
128         }
129 }
130
131 //-------- call from skin
132 function attach_filelist()
133 {
134         global $vars, $_attach_messages;
135
136         $page = isset($vars['page']) ? $vars['page'] : '';
137
138         $obj = & new AttachPages($page, 0);
139
140         if (! isset($obj->pages[$page])) {
141                 return '';
142         } else {
143                 return $_attach_messages['msg_file'] . ': ' .
144                 $obj->toString($page, TRUE) . "\n";
145         }
146 }
147
148 //-------- ¼ÂÂÎ
149 // ¥Õ¥¡¥¤¥ë¥¢¥Ã¥×¥í¡¼¥É
150 // $pass = NULL : ¥Ñ¥¹¥ï¡¼¥É¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤¤
151 // $pass = TRUE : ¥¢¥Ã¥×¥í¡¼¥Éµö²Ä
152 function attach_upload($file, $page, $pass = NULL)
153 {
154         global $_attach_messages, $notify, $notify_subject;
155
156         if (PKWK_READONLY) die_message('PKWK_READONLY prohibits editing');
157
158         // Check query-string
159         $query = 'plugin=attach&amp;pcmd=info&amp;refer=' . rawurlencode($page) .
160                 '&amp;file=' . rawurlencode($file['name']);
161
162         if (PKWK_QUERY_STRING_MAX && strlen($query) > PKWK_QUERY_STRING_MAX) {
163                 pkwk_common_headers();
164                 echo('Query string (page name and/or file name) too long');
165                 exit;
166         } else if (! is_page($page)) {
167                 die_message('No such page');
168         } else if ($file['tmp_name'] == '' || ! is_uploaded_file($file['tmp_name'])) {
169                 return array('result'=>FALSE);
170         } else if ($file['size'] > PLUGIN_ATTACH_MAX_FILESIZE) {
171                 return array(
172                         'result'=>FALSE,
173                         'msg'=>$_attach_messages['err_exceed']);
174         } else if (! is_pagename($page) || ($pass !== TRUE && ! is_editable($page))) {
175                 return array(
176                         'result'=>FALSE,'
177                         msg'=>$_attach_messages['err_noparm']);
178         } else if (PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY && $pass !== TRUE &&
179                   ($pass === NULL || ! pkwk_login($pass))) {
180                 return array(
181                         'result'=>FALSE,
182                         'msg'=>$_attach_messages['err_adminpass']);
183         }
184
185         $obj = & new AttachFile($page, $file['name']);
186         if ($obj->exist)
187                 return array('result'=>FALSE,
188                         'msg'=>$_attach_messages['err_exists']);
189
190         if (move_uploaded_file($file['tmp_name'], $obj->filename))
191                 chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE);
192
193         if (is_page($page))
194                 touch(get_filename($page));
195
196         $obj->getstatus();
197         $obj->status['pass'] = ($pass !== TRUE && $pass !== NULL) ? md5($pass) : '';
198         $obj->putstatus();
199
200         if ($notify) {
201                 $footer['ACTION']   = 'File attached';
202                 $footer['FILENAME'] = & $file['name'];
203                 $footer['FILESIZE'] = & $file['size'];
204                 $footer['PAGE']     = & $page;
205
206                 $footer['URI']      = get_script_uri() .
207                         //'?' . rawurlencode($page);
208
209                         // MD5 may heavy
210                         '?plugin=attach' .
211                                 '&refer=' . rawurlencode($page) .
212                                 '&file='  . rawurlencode($file['name']) .
213                                 '&pcmd=info';
214
215                 $footer['USER_AGENT']  = TRUE;
216                 $footer['REMOTE_ADDR'] = TRUE;
217
218                 pkwk_mail_notify($notify_subject, "\n", $footer) or
219                         die('pkwk_mail_notify(): Failed');
220         }
221
222         return array(
223                 'result'=>TRUE,
224                 'msg'=>$_attach_messages['msg_uploaded']);
225 }
226
227 // ¾ÜºÙ¥Õ¥©¡¼¥à¤òɽ¼¨
228 function attach_info($err = '')
229 {
230         global $vars, $_attach_messages;
231
232         foreach (array('refer', 'file', 'age') as $var)
233                 ${$var} = isset($vars[$var]) ? $vars[$var] : '';
234
235         $obj = & new AttachFile($refer, $file, $age);
236         return $obj->getstatus() ?
237                 $obj->info($err) :
238                 array('msg'=>$_attach_messages['err_notfound']);
239 }
240
241 // ºï½ü
242 function attach_delete()
243 {
244         global $vars, $_attach_messages;
245
246         foreach (array('refer', 'file', 'age', 'pass') as $var)
247                 ${$var} = isset($vars[$var]) ? $vars[$var] : '';
248
249         if (is_freeze($refer) || ! is_editable($refer))
250                 return array('msg'=>$_attach_messages['err_noparm']);
251
252         $obj = & new AttachFile($refer, $file, $age);
253         if (! $obj->getstatus())
254                 return array('msg'=>$_attach_messages['err_notfound']);
255                 
256         return $obj->delete($pass);
257 }
258
259 // Åà·ë
260 function attach_freeze($freeze)
261 {
262         global $vars, $_attach_messages;
263
264         foreach (array('refer', 'file', 'age', 'pass') as $var) {
265                 ${$var} = isset($vars[$var]) ? $vars[$var] : '';
266         }
267
268         if (is_freeze($refer) || ! is_editable($refer)) {
269                 return array('msg'=>$_attach_messages['err_noparm']);
270         } else {
271                 $obj = & new AttachFile($refer, $file, $age);
272                 return $obj->getstatus() ?
273                         $obj->freeze($freeze, $pass) :
274                         array('msg'=>$_attach_messages['err_notfound']);
275         }
276 }
277
278 // ¥À¥¦¥ó¥í¡¼¥É
279 function attach_open()
280 {
281         global $vars, $_attach_messages;
282
283         foreach (array('refer', 'file', 'age') as $var) {
284                 ${$var} = isset($vars[$var]) ? $vars[$var] : '';
285         }
286
287         $obj = & new AttachFile($refer, $file, $age);
288         return $obj->getstatus() ?
289                 $obj->open() :
290                 array('msg'=>$_attach_messages['err_notfound']);
291 }
292
293 // °ìÍ÷¼èÆÀ
294 function attach_list()
295 {
296         global $vars, $_attach_messages;
297
298         $refer = isset($vars['refer']) ? $vars['refer'] : '';
299
300         $obj = & new AttachPages($refer);
301
302         $msg = $_attach_messages[($refer == '') ? 'msg_listall' : 'msg_listpage'];
303         $body = ($refer == '' || isset($obj->pages[$refer])) ?
304                 $obj->toString($refer, FALSE) :
305                 $_attach_messages['err_noexist'];
306
307         return array('msg'=>$msg, 'body'=>$body);
308 }
309
310 // ¥¢¥Ã¥×¥í¡¼¥É¥Õ¥©¡¼¥à¤òɽ¼¨ (action»þ)
311 function attach_showform()
312 {
313         global $vars, $_attach_messages;
314
315         $page = isset($vars['page']) ? $vars['page'] : '';
316         $vars['refer'] = $page;
317         $body = attach_form($page);
318
319         return array('msg'=>$_attach_messages['msg_upload'], 'body'=>$body);
320 }
321
322 //-------- ¥µ¡¼¥Ó¥¹
323 // mime-type¤Î·èÄê
324 function attach_mime_content_type($filename)
325 {
326         $type = 'application/octet-stream'; // default
327
328         if (! file_exists($filename)) return $type;
329
330         $size = @getimagesize($filename);
331         if (is_array($size)) {
332                 switch ($size[2]) {
333                         case 1: return 'image/gif';
334                         case 2: return 'image/jpeg';
335                         case 3: return 'image/png';
336                         case 4: return 'application/x-shockwave-flash';
337                 }
338         }
339
340         $matches = array();
341         if (! preg_match('/_((?:[0-9A-F]{2})+)(?:\.\d+)?$/', $filename, $matches))
342                 return $type;
343
344         $filename = decode($matches[1]);
345
346         // mime-type°ìÍ÷ɽ¤ò¼èÆÀ
347         $config = new Config(PLUGIN_ATTACH_CONFIG_PAGE_MIME);
348         $table = $config->read() ? $config->get('mime-type') : array();
349         unset($config); // ¥á¥â¥êÀáÌó
350
351         foreach ($table as $row) {
352                 $_type = trim($row[0]);
353                 $exts = preg_split('/\s+|,/', trim($row[1]), -1, PREG_SPLIT_NO_EMPTY);
354                 foreach ($exts as $ext) {
355                         if (preg_match("/\.$ext$/i", $filename)) return $_type;
356                 }
357         }
358
359         return $type;
360 }
361
362 // ¥¢¥Ã¥×¥í¡¼¥É¥Õ¥©¡¼¥à¤Î½ÐÎÏ
363 function attach_form($page)
364 {
365         global $script, $vars, $_attach_messages;
366
367         $r_page = rawurlencode($page);
368         $s_page = htmlspecialchars($page);
369         $navi = <<<EOD
370   <span class="small">
371    [<a href="$script?plugin=attach&amp;pcmd=list&amp;refer=$r_page">{$_attach_messages['msg_list']}</a>]
372    [<a href="$script?plugin=attach&amp;pcmd=list">{$_attach_messages['msg_listall']}</a>]
373   </span><br />
374 EOD;
375
376         if (! ini_get('file_uploads')) return '#attach(): file_uploads disabled<br />' . $navi;
377         if (! is_page($page))          return '#attach(): No such page<br />'          . $navi;
378
379         $maxsize = PLUGIN_ATTACH_MAX_FILESIZE;
380         $msg_maxsize = sprintf($_attach_messages['msg_maxsize'], number_format($maxsize/1024) . 'KB');
381
382         $pass = '';
383         if (PLUGIN_ATTACH_PASSWORD_REQUIRE || PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY) {
384                 $title = $_attach_messages[PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY ? 'msg_adminpass' : 'msg_password'];
385                 $pass = '<br />' . $title . ': <input type="password" name="pass" size="8" />';
386         }
387         return <<<EOD
388 <form enctype="multipart/form-data" action="$script" method="post">
389  <div>
390   <input type="hidden" name="plugin" value="attach" />
391   <input type="hidden" name="pcmd"   value="post" />
392   <input type="hidden" name="refer"  value="$s_page" />
393   <input type="hidden" name="max_file_size" value="$maxsize" />
394   $navi
395   <span class="small">
396    $msg_maxsize
397   </span><br />
398   <label for="_p_attach_file">{$_attach_messages['msg_file']}:</label> <input type="file" name="attach_file" id="_p_attach_file" />
399   $pass
400   <input type="submit" value="{$_attach_messages['btn_upload']}" />
401  </div>
402 </form>
403 EOD;
404 }
405
406 //-------- ¥¯¥é¥¹
407 // ¥Õ¥¡¥¤¥ë
408 class AttachFile
409 {
410         var $page, $file, $age, $basename, $filename, $logname;
411         var $time = 0;
412         var $size = 0;
413         var $time_str = '';
414         var $size_str = '';
415         var $status = array('count'=>array(0), 'age'=>'', 'pass'=>'', 'freeze'=>FALSE);
416
417         function AttachFile($page, $file, $age = 0)
418         {
419                 $this->page = $page;
420                 $this->file = preg_replace('#^.*/#','',$file);
421                 $this->age  = is_numeric($age) ? $age : 0;
422
423                 $this->basename = UPLOAD_DIR . encode($page) . '_' . encode($this->file);
424                 $this->filename = $this->basename . ($age ? '.' . $age : '');
425                 $this->logname  = $this->basename . '.log';
426                 $this->exist    = file_exists($this->filename);
427                 $this->time     = $this->exist ? filemtime($this->filename) - LOCALZONE : 0;
428                 $this->md5hash  = $this->exist ? md5_file($this->filename) : '';
429         }
430
431         // ¥Õ¥¡¥¤¥ë¾ðÊó¼èÆÀ
432         function getstatus()
433         {
434                 if (! $this->exist) return FALSE;
435
436                 // ¥í¥°¥Õ¥¡¥¤¥ë¼èÆÀ
437                 if (file_exists($this->logname)) {
438                         $data = file($this->logname);
439                         foreach ($this->status as $key=>$value) {
440                                 $this->status[$key] = chop(array_shift($data));
441                         }
442                         $this->status['count'] = explode(',', $this->status['count']);
443                 }
444                 $this->time_str = get_date('Y/m/d H:i:s', $this->time);
445                 $this->size     = filesize($this->filename);
446                 $this->size_str = sprintf('%01.1f', round($this->size/1024, 1)) . 'KB';
447                 $this->type     = attach_mime_content_type($this->filename);
448
449                 return TRUE;
450         }
451
452         // ¥¹¥Æ¡¼¥¿¥¹Êݸ
453         function putstatus()
454         {
455                 $this->status['count'] = join(',', $this->status['count']);
456                 $fp = fopen($this->logname, 'wb') or
457                         die_message('cannot write ' . $this->logname);
458                 set_file_buffer($fp, 0);
459                 flock($fp, LOCK_EX);
460                 rewind($fp);
461                 foreach ($this->status as $key=>$value) {
462                         fwrite($fp, $value . "\n");
463                 }
464                 flock($fp, LOCK_UN);
465                 fclose($fp);
466         }
467
468         // ÆüÉÕ¤ÎÈæ³Ó´Ø¿ô
469         function datecomp($a, $b) {
470                 return ($a->time == $b->time) ? 0 : (($a->time > $b->time) ? -1 : 1);
471         }
472
473         function toString($showicon, $showinfo)
474         {
475                 global $script, $_attach_messages;
476
477                 $this->getstatus();
478                 $param  = '&amp;file=' . rawurlencode($this->file) . '&amp;refer=' . rawurlencode($this->page) .
479                         ($this->age ? '&amp;age=' . $this->age : '');
480                 $title = $this->time_str . ' ' . $this->size_str;
481                 $label = ($showicon ? PLUGIN_ATTACH_FILE_ICON : '') . htmlspecialchars($this->file);
482                 if ($this->age) {
483                         $label .= ' (backup No.' . $this->age . ')';
484                 }
485                 $info = $count = '';
486                 if ($showinfo) {
487                         $_title = str_replace('$1', rawurlencode($this->file), $_attach_messages['msg_info']);
488                         $info = "\n<span class=\"small\">[<a href=\"$script?plugin=attach&amp;pcmd=info$param\" title=\"$_title\">{$_attach_messages['btn_info']}</a>]</span>\n";
489                         $count = ($showicon && ! empty($this->status['count'][$this->age])) ?
490                                 sprintf($_attach_messages['msg_count'], $this->status['count'][$this->age]) : '';
491                 }
492                 return "<a href=\"$script?plugin=attach&amp;pcmd=open$param\" title=\"$title\">$label</a>$count$info";
493         }
494
495         // ¾ðÊóɽ¼¨
496         function info($err)
497         {
498                 global $script, $_attach_messages;
499
500                 $r_page = rawurlencode($this->page);
501                 $s_page = htmlspecialchars($this->page);
502                 $s_file = htmlspecialchars($this->file);
503                 $s_err = ($err == '') ? '' : '<p style="font-weight:bold">' . $_attach_messages[$err] . '</p>';
504
505                 if ($this->age) {
506                         $msg_freezed = '';
507                         $msg_delete  = '<input type="radio" name="pcmd" id="_p_attach_delete" value="delete" />' .
508                                 '<label for="_p_attach_delete">' .  $_attach_messages['msg_delete'] .
509                                 $_attach_messages['msg_require'] . '</label><br />';
510                         $msg_freeze  = '';
511                 } else {
512                         if ($this->status['freeze']) {
513                                 $msg_freezed = "<dd>{$_attach_messages['msg_isfreeze']}</dd>";
514                                 $msg_delete  = '';
515                                 $msg_freeze  = '<input type="radio" name="pcmd" id="_p_attach_unfreeze" value="unfreeze" />' .
516                                         '<label for="_p_attach_unfreeze">' .  $_attach_messages['msg_unfreeze'] .
517                                         $_attach_messages['msg_require'] . '</label><br />';
518                         } else {
519                                 $msg_freezed = '';
520                                 $msg_delete = '<input type="radio" name="pcmd" id="_p_attach_delete" value="delete" />' .
521                                         '<label for="_p_attach_delete">' . $_attach_messages['msg_delete'];
522                                 if (PLUGIN_ATTACH_DELETE_ADMIN_ONLY || $this->age)
523                                         $msg_delete .= $_attach_messages['msg_require'];
524                                 $msg_delete .= '</label><br />';
525                                 $msg_freeze  = '<input type="radio" name="pcmd" id="_p_attach_freeze" value="freeze" />' .
526                                         '<label for="_p_attach_freeze">' .  $_attach_messages['msg_freeze'] .
527                                         $_attach_messages['msg_require'] . '</label><br />';
528                         }
529                 }
530                 $info = $this->toString(TRUE, FALSE);
531
532                 $retval = array('msg'=>sprintf($_attach_messages['msg_info'], htmlspecialchars($this->file)));
533                 $retval['body'] = <<< EOD
534 <p class="small">
535  [<a href="$script?plugin=attach&amp;pcmd=list&amp;refer=$r_page">{$_attach_messages['msg_list']}</a>]
536  [<a href="$script?plugin=attach&amp;pcmd=list">{$_attach_messages['msg_listall']}</a>]
537 </p>
538 <dl>
539  <dt>$info</dt>
540  <dd>{$_attach_messages['msg_page']}:$s_page</dd>
541  <dd>{$_attach_messages['msg_filename']}:{$this->filename}</dd>
542  <dd>{$_attach_messages['msg_md5hash']}:{$this->md5hash}</dd>
543  <dd>{$_attach_messages['msg_filesize']}:{$this->size_str} ({$this->size} bytes)</dd>
544  <dd>Content-type:{$this->type}</dd>
545  <dd>{$_attach_messages['msg_date']}:{$this->time_str}</dd>
546  <dd>{$_attach_messages['msg_dlcount']}:{$this->status['count'][$this->age]}</dd>
547  $msg_freezed
548 </dl>
549 <hr />
550 $s_err
551 <form action="$script" method="post">
552  <div>
553   <input type="hidden" name="plugin" value="attach" />
554   <input type="hidden" name="refer" value="$s_page" />
555   <input type="hidden" name="file" value="$s_file" />
556   <input type="hidden" name="age" value="{$this->age}" />
557   $msg_delete
558   $msg_freeze
559   <label for="_p_attach_password">{$_attach_messages['msg_password']}:</label>
560   <input type="password" name="pass" id="_p_attach_password" size="8" />
561   <input type="submit" value="{$_attach_messages['btn_submit']}" />
562  </div>
563 </form>
564 EOD;
565                 return $retval;
566         }
567
568         function delete($pass)
569         {
570                 global $_attach_messages, $notify, $notify_subject;
571
572                 if ($this->status['freeze']) return attach_info('msg_isfreeze');
573
574                 if (! pkwk_login($pass)) {
575                         if (PLUGIN_ATTACH_DELETE_ADMIN_ONLY || $this->age) {
576                                 return attach_info('err_adminpass');
577                         } else if (PLUGIN_ATTACH_PASSWORD_REQUIRE &&
578                                 md5($pass) != $this->status['pass']) {
579                                 return attach_info('err_password');
580                         }
581                 }
582
583                 // ¥Ð¥Ã¥¯¥¢¥Ã¥×
584                 if ($this->age ||
585                         (PLUGIN_ATTACH_DELETE_ADMIN_ONLY && PLUGIN_ATTACH_DELETE_ADMIN_NOBACKUP)) {
586                         @unlink($this->filename);
587                 } else {
588                         do {
589                                 $age = ++$this->status['age'];
590                         } while (file_exists($this->basename . '.' . $age));
591
592                         if (! rename($this->basename,$this->basename . '.' . $age)) {
593                                 // ºï½ü¼ºÇÔ why?
594                                 return array('msg'=>$_attach_messages['err_delete']);
595                         }
596
597                         $this->status['count'][$age] = $this->status['count'][0];
598                         $this->status['count'][0] = 0;
599                         $this->putstatus();
600                 }
601
602                 if (is_page($this->page))
603                         touch(get_filename($this->page));
604
605                 if ($notify) {
606                         $footer['ACTION']   = 'File deleted';
607                         $footer['FILENAME'] = & $this->file;
608                         $footer['PAGE']     = & $this->page;
609                         $footer['URI']      = get_script_uri() .
610                                 '?' . rawurlencode($this->page);
611                         $footer['USER_AGENT']  = TRUE;
612                         $footer['REMOTE_ADDR'] = TRUE;
613                         pkwk_mail_notify($notify_subject, "\n", $footer) or
614                                 die('pkwk_mail_notify(): Failed');
615                 }
616
617                 return array('msg'=>$_attach_messages['msg_deleted']);
618         }
619
620         function freeze($freeze, $pass)
621         {
622                 global $_attach_messages;
623
624                 if (! pkwk_login($pass)) return attach_info('err_adminpass');
625
626                 $this->getstatus();
627                 $this->status['freeze'] = $freeze;
628                 $this->putstatus();
629
630                 return array('msg'=>$_attach_messages[$freeze ? 'msg_freezed' : 'msg_unfreezed']);
631         }
632
633         function open()
634         {
635                 $this->getstatus();
636                 $this->status['count'][$this->age]++;
637                 $this->putstatus();
638                 $filename = $this->file;
639
640                 // Care for Japanese-character-included file name
641                 if (LANG == 'ja') {
642                         switch(UA_NAME . '/' . UA_PROFILE){
643                         case 'Opera/default':
644                                 // Care for using _auto-encode-detecting_ function
645                                 $filename = mb_convert_encoding($filename, 'UTF-8', 'auto');
646                                 break;
647                         case 'MSIE/default':
648                                 $filename = mb_convert_encoding($filename, 'SJIS', 'auto');
649                                 break;
650                         }
651                 }
652                 $filename = htmlspecialchars($filename);
653
654                 ini_set('default_charset', '');
655                 mb_http_output('pass');
656
657                 pkwk_common_headers();
658                 header('Content-Disposition: inline; filename="' . $filename . '"');
659                 header('Content-Length: ' . $this->size);
660                 header('Content-Type: '   . $this->type);
661
662                 @readfile($this->filename);
663                 exit;
664         }
665 }
666
667 // ¥Õ¥¡¥¤¥ë¥³¥ó¥Æ¥Ê
668 class AttachFiles
669 {
670         var $page;
671         var $files = array();
672
673         function AttachFiles($page)
674         {
675                 $this->page = $page;
676         }
677
678         function add($file, $age)
679         {
680                 $this->files[$file][$age] = & new AttachFile($this->page, $file, $age);
681         }
682
683         // ¥Õ¥¡¥¤¥ë°ìÍ÷¤ò¼èÆÀ
684         function toString($flat)
685         {
686                 global $_title_cannotread;
687
688                 if (! check_readable($this->page, FALSE, FALSE)) {
689                         return str_replace('$1', make_pagelink($this->page), $_title_cannotread);
690                 } else if ($flat) {
691                         return $this->to_flat();
692                 }
693
694                 $ret = '';
695                 $files = array_keys($this->files);
696                 sort($files);
697
698                 foreach ($files as $file) {
699                         $_files = array();
700                         foreach (array_keys($this->files[$file]) as $age) {
701                                 $_files[$age] = $this->files[$file][$age]->toString(FALSE, TRUE);
702                         }
703                         if (! isset($_files[0])) {
704                                 $_files[0] = htmlspecialchars($file);
705                         }
706                         ksort($_files);
707                         $_file = $_files[0];
708                         unset($_files[0]);
709                         $ret .= " <li>$_file\n";
710                         if (count($_files)) {
711                                 $ret .= "<ul>\n<li>" . join("</li>\n<li>", $_files) . "</li>\n</ul>\n";
712                         }
713                         $ret .= " </li>\n";
714                 }
715                 return make_pagelink($this->page) . "\n<ul>\n$ret</ul>\n";
716         }
717
718         // ¥Õ¥¡¥¤¥ë°ìÍ÷¤ò¼èÆÀ(inline)
719         function to_flat()
720         {
721                 $ret = '';
722                 $files = array();
723                 foreach (array_keys($this->files) as $file) {
724                         if (isset($this->files[$file][0])) {
725                                 $files[$file] = & $this->files[$file][0];
726                         }
727                 }
728                 uasort($files, array('AttachFile', 'datecomp'));
729                 foreach (array_keys($files) as $file) {
730                         $ret .= $files[$file]->toString(TRUE, TRUE) . ' ';
731                 }
732
733                 return $ret;
734         }
735 }
736
737 // ¥Ú¡¼¥¸¥³¥ó¥Æ¥Ê
738 class AttachPages
739 {
740         var $pages = array();
741
742         function AttachPages($page = '', $age = NULL)
743         {
744
745                 $dir = opendir(UPLOAD_DIR) or
746                         die('directory ' . UPLOAD_DIR . ' is not exist or not readable.');
747
748                 $page_pattern = ($page == '') ? '(?:[0-9A-F]{2})+' : preg_quote(encode($page), '/');
749                 $age_pattern = ($age === NULL) ?
750                         '(?:\.([0-9]+))?' : ($age ?  "\.($age)" : '');
751                 $pattern = "/^({$page_pattern})_((?:[0-9A-F]{2})+){$age_pattern}$/";
752
753                 $matches = array();
754                 while ($file = readdir($dir)) {
755                         if (! preg_match($pattern, $file, $matches))
756                                 continue;
757
758                         $_page = decode($matches[1]);
759                         $_file = decode($matches[2]);
760                         $_age  = isset($matches[3]) ? $matches[3] : 0;
761                         if (! isset($this->pages[$_page])) {
762                                 $this->pages[$_page] = & new AttachFiles($_page);
763                         }
764                         $this->pages[$_page]->add($_file, $_age);
765                 }
766                 closedir($dir);
767         }
768
769         function toString($page = '', $flat = FALSE)
770         {
771                 if ($page != '') {
772                         if (! isset($this->pages[$page])) {
773                                 return '';
774                         } else {
775                                 return $this->pages[$page]->toString($flat);
776                         }
777                 }
778                 $ret = '';
779
780                 $pages = array_keys($this->pages);
781                 sort($pages);
782
783                 foreach ($pages as $page) {
784                         if (check_non_list($page)) continue;
785                         $ret .= '<li>' . $this->pages[$page]->toString($flat) . '</li>' . "\n";
786                 }
787                 return "\n" . '<ul>' . "\n" . $ret . '</ul>' . "\n";
788         }
789 }
790 ?>