2 // PukiWiki - Yet another WikiWikiWeb clone
3 // $Id: attach.inc.php,v 1.80 2005/12/18 15:27:43 henoheno Exp $
5 // 2003-2005 PukiWiki Developers Team
6 // 2002-2003 PANDA <panda@arino.jp> http://home.arino.jp/
7 // 2002 Y.MASUI <masui@hisec.co.jp> http://masui.net/pukiwiki/
8 // 2001-2002 Originally written by yu-ji
9 // License: GPL v2 or (at your option) any later version
13 // NOTE (PHP > 4.2.3):
14 // This feature is disabled at newer version of PHP.
15 // Set this at php.ini if you want.
16 // Max file size for upload on PHP (PHP default: 2MB)
17 ini_set('upload_max_filesize', '2M');
19 // Max file size for upload on script of PukiWikiX_FILESIZE
20 define('PLUGIN_ATTACH_MAX_FILESIZE', (1024 * 1024)); // default: 1MB
22 // ´ÉÍý¼Ô¤À¤±¤¬ÅºÉÕ¥Õ¥¡¥¤¥ë¤ò¥¢¥Ã¥×¥í¡¼¥É¤Ç¤¤ë¤è¤¦¤Ë¤¹¤ë
23 define('PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY', TRUE); // FALSE or TRUE
25 // ´ÉÍý¼Ô¤À¤±¤¬ÅºÉÕ¥Õ¥¡¥¤¥ë¤òºï½ü¤Ç¤¤ë¤è¤¦¤Ë¤¹¤ë
26 define('PLUGIN_ATTACH_DELETE_ADMIN_ONLY', TRUE); // FALSE or TRUE
28 // ´ÉÍý¼Ô¤¬ÅºÉÕ¥Õ¥¡¥¤¥ë¤òºï½ü¤¹¤ë¤È¤¤Ï¡¢¥Ð¥Ã¥¯¥¢¥Ã¥×¤òºî¤é¤Ê¤¤
29 // PLUGIN_ATTACH_DELETE_ADMIN_ONLY=TRUE¤Î¤È¤Í¸ú
30 define('PLUGIN_ATTACH_DELETE_ADMIN_NOBACKUP', TRUE); // FALSE or TRUE
32 // ¥¢¥Ã¥×¥í¡¼¥É/ºï½ü»þ¤Ë¥Ñ¥¹¥ï¡¼¥É¤òÍ׵᤹¤ë(ADMIN_ONLY¤¬Í¥Àè)
33 define('PLUGIN_ATTACH_PASSWORD_REQUIRE', FALSE); // FALSE or TRUE
35 // ¥Õ¥¡¥¤¥ë¤Î¥¢¥¯¥»¥¹¸¢
36 define('PLUGIN_ATTACH_FILE_MODE', 0644);
37 //define('PLUGIN_ATTACH_FILE_MODE', 0604); // for XREA.COM
40 define('PLUGIN_ATTACH_FILE_ICON', '<img src="' . IMAGE_DIR . 'file.png"' .
41 ' width="20" height="20" alt="file"' .
42 ' style="border-width:0px" />');
44 // mime-type¤òµ½Ò¤·¤¿¥Ú¡¼¥¸
45 define('PLUGIN_ATTACH_CONFIG_PAGE_MIME', 'plugin/attach/mime-type');
48 function plugin_attach_convert()
52 $page = isset($vars['page']) ? $vars['page'] : '';
54 $nolist = $noform = FALSE;
55 if (func_num_args() > 0) {
56 foreach (func_get_args() as $arg) {
57 $arg = strtolower($arg);
58 $nolist |= ($arg == 'nolist');
59 $noform |= ($arg == 'noform');
65 $obj = & new AttachPages($page);
66 $ret .= $obj->toString($page, TRUE);
69 $ret .= attach_form($page);
76 function plugin_attach_action()
78 global $vars, $_attach_messages;
80 // Backward compatible
81 if (isset($vars['openfile'])) {
82 $vars['file'] = $vars['openfile'];
83 $vars['pcmd'] = 'open';
85 if (isset($vars['delfile'])) {
86 $vars['file'] = $vars['delfile'];
87 $vars['pcmd'] = 'delete';
90 $pcmd = isset($vars['pcmd']) ? $vars['pcmd'] : '';
91 $refer = isset($vars['refer']) ? $vars['refer'] : '';
92 $pass = isset($vars['pass']) ? $vars['pass'] : NULL;
93 $page = isset($vars['page']) ? $vars['page'] : '';
95 if ($refer != '' && is_pagename($refer)) {
96 if(in_array($pcmd, array('info', 'open', 'list'))) {
97 check_readable($refer);
99 check_editable($refer);
104 if (isset($_FILES['attach_file'])) {
106 return attach_upload($_FILES['attach_file'], $refer, $pass);
109 case 'delete': /*FALLTHROUGH*/
112 if (PKWK_READONLY) die_message('PKWK_READONLY prohibits editing');
115 case 'info' : return attach_info();
116 case 'delete' : return attach_delete();
117 case 'open' : return attach_open();
118 case 'list' : return attach_list();
119 case 'freeze' : return attach_freeze(TRUE);
120 case 'unfreeze' : return attach_freeze(FALSE);
121 case 'upload' : return attach_showform();
123 if ($page == '' || ! is_page($page)) {
124 return attach_list();
126 return attach_showform();
131 //-------- call from skin
132 function attach_filelist()
134 global $vars, $_attach_messages;
136 $page = isset($vars['page']) ? $vars['page'] : '';
138 $obj = & new AttachPages($page, 0);
140 if (! isset($obj->pages[$page])) {
143 return $_attach_messages['msg_file'] . ': ' .
144 $obj->toString($page, TRUE) . "\n";
149 // ¥Õ¥¡¥¤¥ë¥¢¥Ã¥×¥í¡¼¥É
150 // $pass = NULL : ¥Ñ¥¹¥ï¡¼¥É¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤¤
151 // $pass = TRUE : ¥¢¥Ã¥×¥í¡¼¥Éµö²Ä
152 function attach_upload($file, $page, $pass = NULL)
154 global $_attach_messages, $notify, $notify_subject;
156 if (PKWK_READONLY) die_message('PKWK_READONLY prohibits editing');
158 // Check query-string
159 $query = 'plugin=attach&pcmd=info&refer=' . rawurlencode($page) .
160 '&file=' . rawurlencode($file['name']);
162 if (PKWK_QUERY_STRING_MAX && strlen($query) > PKWK_QUERY_STRING_MAX) {
163 pkwk_common_headers();
164 echo('Query string (page name and/or file name) too long');
166 } else if (! is_page($page)) {
167 die_message('No such page');
168 } else if ($file['tmp_name'] == '' || ! is_uploaded_file($file['tmp_name'])) {
169 return array('result'=>FALSE);
170 } else if ($file['size'] > PLUGIN_ATTACH_MAX_FILESIZE) {
173 'msg'=>$_attach_messages['err_exceed']);
174 } else if (! is_pagename($page) || ($pass !== TRUE && ! is_editable($page))) {
177 msg'=>$_attach_messages['err_noparm']);
178 } else if (PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY && $pass !== TRUE &&
179 ($pass === NULL || ! pkwk_login($pass))) {
182 'msg'=>$_attach_messages['err_adminpass']);
185 $obj = & new AttachFile($page, $file['name']);
187 return array('result'=>FALSE,
188 'msg'=>$_attach_messages['err_exists']);
190 if (move_uploaded_file($file['tmp_name'], $obj->filename))
191 chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE);
194 touch(get_filename($page));
197 $obj->status['pass'] = ($pass !== TRUE && $pass !== NULL) ? md5($pass) : '';
201 $footer['ACTION'] = 'File attached';
202 $footer['FILENAME'] = & $file['name'];
203 $footer['FILESIZE'] = & $file['size'];
204 $footer['PAGE'] = & $page;
206 $footer['URI'] = get_script_uri() .
207 //'?' . rawurlencode($page);
211 '&refer=' . rawurlencode($page) .
212 '&file=' . rawurlencode($file['name']) .
215 $footer['USER_AGENT'] = TRUE;
216 $footer['REMOTE_ADDR'] = TRUE;
218 pkwk_mail_notify($notify_subject, "\n", $footer) or
219 die('pkwk_mail_notify(): Failed');
224 'msg'=>$_attach_messages['msg_uploaded']);
227 // ¾ÜºÙ¥Õ¥©¡¼¥à¤òɽ¼¨
228 function attach_info($err = '')
230 global $vars, $_attach_messages;
232 foreach (array('refer', 'file', 'age') as $var)
233 ${$var} = isset($vars[$var]) ? $vars[$var] : '';
235 $obj = & new AttachFile($refer, $file, $age);
236 return $obj->getstatus() ?
238 array('msg'=>$_attach_messages['err_notfound']);
242 function attach_delete()
244 global $vars, $_attach_messages;
246 foreach (array('refer', 'file', 'age', 'pass') as $var)
247 ${$var} = isset($vars[$var]) ? $vars[$var] : '';
249 if (is_freeze($refer) || ! is_editable($refer))
250 return array('msg'=>$_attach_messages['err_noparm']);
252 $obj = & new AttachFile($refer, $file, $age);
253 if (! $obj->getstatus())
254 return array('msg'=>$_attach_messages['err_notfound']);
256 return $obj->delete($pass);
260 function attach_freeze($freeze)
262 global $vars, $_attach_messages;
264 foreach (array('refer', 'file', 'age', 'pass') as $var) {
265 ${$var} = isset($vars[$var]) ? $vars[$var] : '';
268 if (is_freeze($refer) || ! is_editable($refer)) {
269 return array('msg'=>$_attach_messages['err_noparm']);
271 $obj = & new AttachFile($refer, $file, $age);
272 return $obj->getstatus() ?
273 $obj->freeze($freeze, $pass) :
274 array('msg'=>$_attach_messages['err_notfound']);
279 function attach_open()
281 global $vars, $_attach_messages;
283 foreach (array('refer', 'file', 'age') as $var) {
284 ${$var} = isset($vars[$var]) ? $vars[$var] : '';
287 $obj = & new AttachFile($refer, $file, $age);
288 return $obj->getstatus() ?
290 array('msg'=>$_attach_messages['err_notfound']);
294 function attach_list()
296 global $vars, $_attach_messages;
298 $refer = isset($vars['refer']) ? $vars['refer'] : '';
300 $obj = & new AttachPages($refer);
302 $msg = $_attach_messages[($refer == '') ? 'msg_listall' : 'msg_listpage'];
303 $body = ($refer == '' || isset($obj->pages[$refer])) ?
304 $obj->toString($refer, FALSE) :
305 $_attach_messages['err_noexist'];
307 return array('msg'=>$msg, 'body'=>$body);
310 // ¥¢¥Ã¥×¥í¡¼¥É¥Õ¥©¡¼¥à¤òɽ¼¨ (action»þ)
311 function attach_showform()
313 global $vars, $_attach_messages;
315 $page = isset($vars['page']) ? $vars['page'] : '';
316 $vars['refer'] = $page;
317 $body = attach_form($page);
319 return array('msg'=>$_attach_messages['msg_upload'], 'body'=>$body);
324 function attach_mime_content_type($filename)
326 $type = 'application/octet-stream'; // default
328 if (! file_exists($filename)) return $type;
330 $size = @getimagesize($filename);
331 if (is_array($size)) {
333 case 1: return 'image/gif';
334 case 2: return 'image/jpeg';
335 case 3: return 'image/png';
336 case 4: return 'application/x-shockwave-flash';
341 if (! preg_match('/_((?:[0-9A-F]{2})+)(?:\.\d+)?$/', $filename, $matches))
344 $filename = decode($matches[1]);
346 // mime-type°ìÍ÷ɽ¤ò¼èÆÀ
347 $config = new Config(PLUGIN_ATTACH_CONFIG_PAGE_MIME);
348 $table = $config->read() ? $config->get('mime-type') : array();
349 unset($config); // ¥á¥â¥êÀáÌó
351 foreach ($table as $row) {
352 $_type = trim($row[0]);
353 $exts = preg_split('/\s+|,/', trim($row[1]), -1, PREG_SPLIT_NO_EMPTY);
354 foreach ($exts as $ext) {
355 if (preg_match("/\.$ext$/i", $filename)) return $_type;
362 // ¥¢¥Ã¥×¥í¡¼¥É¥Õ¥©¡¼¥à¤Î½ÐÎÏ
363 function attach_form($page)
365 global $script, $vars, $_attach_messages;
367 $r_page = rawurlencode($page);
368 $s_page = htmlspecialchars($page);
371 [<a href="$script?plugin=attach&pcmd=list&refer=$r_page">{$_attach_messages['msg_list']}</a>]
372 [<a href="$script?plugin=attach&pcmd=list">{$_attach_messages['msg_listall']}</a>]
376 if (! ini_get('file_uploads')) return '#attach(): file_uploads disabled<br />' . $navi;
377 if (! is_page($page)) return '#attach(): No such page<br />' . $navi;
379 $maxsize = PLUGIN_ATTACH_MAX_FILESIZE;
380 $msg_maxsize = sprintf($_attach_messages['msg_maxsize'], number_format($maxsize/1024) . 'KB');
383 if (PLUGIN_ATTACH_PASSWORD_REQUIRE || PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY) {
384 $title = $_attach_messages[PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY ? 'msg_adminpass' : 'msg_password'];
385 $pass = '<br />' . $title . ': <input type="password" name="pass" size="8" />';
388 <form enctype="multipart/form-data" action="$script" method="post">
390 <input type="hidden" name="plugin" value="attach" />
391 <input type="hidden" name="pcmd" value="post" />
392 <input type="hidden" name="refer" value="$s_page" />
393 <input type="hidden" name="max_file_size" value="$maxsize" />
398 <label for="_p_attach_file">{$_attach_messages['msg_file']}:</label> <input type="file" name="attach_file" id="_p_attach_file" />
400 <input type="submit" value="{$_attach_messages['btn_upload']}" />
410 var $page, $file, $age, $basename, $filename, $logname;
415 var $status = array('count'=>array(0), 'age'=>'', 'pass'=>'', 'freeze'=>FALSE);
417 function AttachFile($page, $file, $age = 0)
420 $this->file = preg_replace('#^.*/#','',$file);
421 $this->age = is_numeric($age) ? $age : 0;
423 $this->basename = UPLOAD_DIR . encode($page) . '_' . encode($this->file);
424 $this->filename = $this->basename . ($age ? '.' . $age : '');
425 $this->logname = $this->basename . '.log';
426 $this->exist = file_exists($this->filename);
427 $this->time = $this->exist ? filemtime($this->filename) - LOCALZONE : 0;
428 $this->md5hash = $this->exist ? md5_file($this->filename) : '';
434 if (! $this->exist) return FALSE;
437 if (file_exists($this->logname)) {
438 $data = file($this->logname);
439 foreach ($this->status as $key=>$value) {
440 $this->status[$key] = chop(array_shift($data));
442 $this->status['count'] = explode(',', $this->status['count']);
444 $this->time_str = get_date('Y/m/d H:i:s', $this->time);
445 $this->size = filesize($this->filename);
446 $this->size_str = sprintf('%01.1f', round($this->size/1024, 1)) . 'KB';
447 $this->type = attach_mime_content_type($this->filename);
455 $this->status['count'] = join(',', $this->status['count']);
456 $fp = fopen($this->logname, 'wb') or
457 die_message('cannot write ' . $this->logname);
458 set_file_buffer($fp, 0);
461 foreach ($this->status as $key=>$value) {
462 fwrite($fp, $value . "\n");
469 function datecomp($a, $b) {
470 return ($a->time == $b->time) ? 0 : (($a->time > $b->time) ? -1 : 1);
473 function toString($showicon, $showinfo)
475 global $script, $_attach_messages;
478 $param = '&file=' . rawurlencode($this->file) . '&refer=' . rawurlencode($this->page) .
479 ($this->age ? '&age=' . $this->age : '');
480 $title = $this->time_str . ' ' . $this->size_str;
481 $label = ($showicon ? PLUGIN_ATTACH_FILE_ICON : '') . htmlspecialchars($this->file);
483 $label .= ' (backup No.' . $this->age . ')';
487 $_title = str_replace('$1', rawurlencode($this->file), $_attach_messages['msg_info']);
488 $info = "\n<span class=\"small\">[<a href=\"$script?plugin=attach&pcmd=info$param\" title=\"$_title\">{$_attach_messages['btn_info']}</a>]</span>\n";
489 $count = ($showicon && ! empty($this->status['count'][$this->age])) ?
490 sprintf($_attach_messages['msg_count'], $this->status['count'][$this->age]) : '';
492 return "<a href=\"$script?plugin=attach&pcmd=open$param\" title=\"$title\">$label</a>$count$info";
498 global $script, $_attach_messages;
500 $r_page = rawurlencode($this->page);
501 $s_page = htmlspecialchars($this->page);
502 $s_file = htmlspecialchars($this->file);
503 $s_err = ($err == '') ? '' : '<p style="font-weight:bold">' . $_attach_messages[$err] . '</p>';
507 $msg_delete = '<input type="radio" name="pcmd" id="_p_attach_delete" value="delete" />' .
508 '<label for="_p_attach_delete">' . $_attach_messages['msg_delete'] .
509 $_attach_messages['msg_require'] . '</label><br />';
512 if ($this->status['freeze']) {
513 $msg_freezed = "<dd>{$_attach_messages['msg_isfreeze']}</dd>";
515 $msg_freeze = '<input type="radio" name="pcmd" id="_p_attach_unfreeze" value="unfreeze" />' .
516 '<label for="_p_attach_unfreeze">' . $_attach_messages['msg_unfreeze'] .
517 $_attach_messages['msg_require'] . '</label><br />';
520 $msg_delete = '<input type="radio" name="pcmd" id="_p_attach_delete" value="delete" />' .
521 '<label for="_p_attach_delete">' . $_attach_messages['msg_delete'];
522 if (PLUGIN_ATTACH_DELETE_ADMIN_ONLY || $this->age)
523 $msg_delete .= $_attach_messages['msg_require'];
524 $msg_delete .= '</label><br />';
525 $msg_freeze = '<input type="radio" name="pcmd" id="_p_attach_freeze" value="freeze" />' .
526 '<label for="_p_attach_freeze">' . $_attach_messages['msg_freeze'] .
527 $_attach_messages['msg_require'] . '</label><br />';
530 $info = $this->toString(TRUE, FALSE);
532 $retval = array('msg'=>sprintf($_attach_messages['msg_info'], htmlspecialchars($this->file)));
533 $retval['body'] = <<< EOD
535 [<a href="$script?plugin=attach&pcmd=list&refer=$r_page">{$_attach_messages['msg_list']}</a>]
536 [<a href="$script?plugin=attach&pcmd=list">{$_attach_messages['msg_listall']}</a>]
540 <dd>{$_attach_messages['msg_page']}:$s_page</dd>
541 <dd>{$_attach_messages['msg_filename']}:{$this->filename}</dd>
542 <dd>{$_attach_messages['msg_md5hash']}:{$this->md5hash}</dd>
543 <dd>{$_attach_messages['msg_filesize']}:{$this->size_str} ({$this->size} bytes)</dd>
544 <dd>Content-type:{$this->type}</dd>
545 <dd>{$_attach_messages['msg_date']}:{$this->time_str}</dd>
546 <dd>{$_attach_messages['msg_dlcount']}:{$this->status['count'][$this->age]}</dd>
551 <form action="$script" method="post">
553 <input type="hidden" name="plugin" value="attach" />
554 <input type="hidden" name="refer" value="$s_page" />
555 <input type="hidden" name="file" value="$s_file" />
556 <input type="hidden" name="age" value="{$this->age}" />
559 <label for="_p_attach_password">{$_attach_messages['msg_password']}:</label>
560 <input type="password" name="pass" id="_p_attach_password" size="8" />
561 <input type="submit" value="{$_attach_messages['btn_submit']}" />
568 function delete($pass)
570 global $_attach_messages, $notify, $notify_subject;
572 if ($this->status['freeze']) return attach_info('msg_isfreeze');
574 if (! pkwk_login($pass)) {
575 if (PLUGIN_ATTACH_DELETE_ADMIN_ONLY || $this->age) {
576 return attach_info('err_adminpass');
577 } else if (PLUGIN_ATTACH_PASSWORD_REQUIRE &&
578 md5($pass) != $this->status['pass']) {
579 return attach_info('err_password');
585 (PLUGIN_ATTACH_DELETE_ADMIN_ONLY && PLUGIN_ATTACH_DELETE_ADMIN_NOBACKUP)) {
586 @unlink($this->filename);
589 $age = ++$this->status['age'];
590 } while (file_exists($this->basename . '.' . $age));
592 if (! rename($this->basename,$this->basename . '.' . $age)) {
594 return array('msg'=>$_attach_messages['err_delete']);
597 $this->status['count'][$age] = $this->status['count'][0];
598 $this->status['count'][0] = 0;
602 if (is_page($this->page))
603 touch(get_filename($this->page));
606 $footer['ACTION'] = 'File deleted';
607 $footer['FILENAME'] = & $this->file;
608 $footer['PAGE'] = & $this->page;
609 $footer['URI'] = get_script_uri() .
610 '?' . rawurlencode($this->page);
611 $footer['USER_AGENT'] = TRUE;
612 $footer['REMOTE_ADDR'] = TRUE;
613 pkwk_mail_notify($notify_subject, "\n", $footer) or
614 die('pkwk_mail_notify(): Failed');
617 return array('msg'=>$_attach_messages['msg_deleted']);
620 function freeze($freeze, $pass)
622 global $_attach_messages;
624 if (! pkwk_login($pass)) return attach_info('err_adminpass');
627 $this->status['freeze'] = $freeze;
630 return array('msg'=>$_attach_messages[$freeze ? 'msg_freezed' : 'msg_unfreezed']);
636 $this->status['count'][$this->age]++;
638 $filename = $this->file;
640 // Care for Japanese-character-included file name
642 switch(UA_NAME . '/' . UA_PROFILE){
643 case 'Opera/default':
644 // Care for using _auto-encode-detecting_ function
645 $filename = mb_convert_encoding($filename, 'UTF-8', 'auto');
648 $filename = mb_convert_encoding($filename, 'SJIS', 'auto');
652 $filename = htmlspecialchars($filename);
654 ini_set('default_charset', '');
655 mb_http_output('pass');
657 pkwk_common_headers();
658 header('Content-Disposition: inline; filename="' . $filename . '"');
659 header('Content-Length: ' . $this->size);
660 header('Content-Type: ' . $this->type);
662 @readfile($this->filename);
671 var $files = array();
673 function AttachFiles($page)
678 function add($file, $age)
680 $this->files[$file][$age] = & new AttachFile($this->page, $file, $age);
683 // ¥Õ¥¡¥¤¥ë°ìÍ÷¤ò¼èÆÀ
684 function toString($flat)
686 global $_title_cannotread;
688 if (! check_readable($this->page, FALSE, FALSE)) {
689 return str_replace('$1', make_pagelink($this->page), $_title_cannotread);
691 return $this->to_flat();
695 $files = array_keys($this->files);
698 foreach ($files as $file) {
700 foreach (array_keys($this->files[$file]) as $age) {
701 $_files[$age] = $this->files[$file][$age]->toString(FALSE, TRUE);
703 if (! isset($_files[0])) {
704 $_files[0] = htmlspecialchars($file);
709 $ret .= " <li>$_file\n";
710 if (count($_files)) {
711 $ret .= "<ul>\n<li>" . join("</li>\n<li>", $_files) . "</li>\n</ul>\n";
715 return make_pagelink($this->page) . "\n<ul>\n$ret</ul>\n";
718 // ¥Õ¥¡¥¤¥ë°ìÍ÷¤ò¼èÆÀ(inline)
723 foreach (array_keys($this->files) as $file) {
724 if (isset($this->files[$file][0])) {
725 $files[$file] = & $this->files[$file][0];
728 uasort($files, array('AttachFile', 'datecomp'));
729 foreach (array_keys($files) as $file) {
730 $ret .= $files[$file]->toString(TRUE, TRUE) . ' ';
740 var $pages = array();
742 function AttachPages($page = '', $age = NULL)
745 $dir = opendir(UPLOAD_DIR) or
746 die('directory ' . UPLOAD_DIR . ' is not exist or not readable.');
748 $page_pattern = ($page == '') ? '(?:[0-9A-F]{2})+' : preg_quote(encode($page), '/');
749 $age_pattern = ($age === NULL) ?
750 '(?:\.([0-9]+))?' : ($age ? "\.($age)" : '');
751 $pattern = "/^({$page_pattern})_((?:[0-9A-F]{2})+){$age_pattern}$/";
754 while ($file = readdir($dir)) {
755 if (! preg_match($pattern, $file, $matches))
758 $_page = decode($matches[1]);
759 $_file = decode($matches[2]);
760 $_age = isset($matches[3]) ? $matches[3] : 0;
761 if (! isset($this->pages[$_page])) {
762 $this->pages[$_page] = & new AttachFiles($_page);
764 $this->pages[$_page]->add($_file, $_age);
769 function toString($page = '', $flat = FALSE)
772 if (! isset($this->pages[$page])) {
775 return $this->pages[$page]->toString($flat);
780 $pages = array_keys($this->pages);
783 foreach ($pages as $page) {
784 if (check_non_list($page)) continue;
785 $ret .= '<li>' . $this->pages[$page]->toString($flat) . '</li>' . "\n";
787 return "\n" . '<ul>' . "\n" . $ret . '</ul>' . "\n";