OSDN Git Service

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