OSDN Git Service

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