OSDN Git Service

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