OSDN Git Service

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