OSDN Git Service

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