OSDN Git Service

BugTrack/566 CVS キーワード置換調整, SKIN_DIR='./skin/'
[pukiwiki/pukiwiki.git] / plugin / attach.inc.php
index c954002..b71ff9f 100644 (file)
@@ -2,7 +2,7 @@
 /////////////////////////////////////////////////
 // PukiWiki - Yet another WikiWikiWeb clone.
 //
-//  $Id: attach.inc.php,v 1.14 2003/02/26 11:45:35 panda Exp $
+//  $Id: attach.inc.php,v 1.39 2004/03/18 10:02:13 arino Exp $
 //
 
 /*
  modified by PANDA <panda@arino.jp> http://home.arino.jp/
 */
 
-// upload dir(must set end of /)
-if (!defined('UPLOAD_DIR'))
-{
-       define('UPLOAD_DIR','./attach/');
-}
-
 // max file size for upload on PHP(PHP default 2MB)
 ini_set('upload_max_filesize','2M');
 
@@ -28,58 +22,25 @@ define('MAX_FILESIZE',1000000);
 define('ATTACH_UPLOAD_ADMIN_ONLY',FALSE); // FALSE or TRUE
 // ´ÉÍý¼Ô¤À¤±¤¬ÅºÉÕ¥Õ¥¡¥¤¥ë¤òºï½ü¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë
 define('ATTACH_DELETE_ADMIN_ONLY',FALSE); // FALSE or TRUE
+// ´ÉÍý¼Ô¤¬ÅºÉÕ¥Õ¥¡¥¤¥ë¤òºï½ü¤¹¤ë¤È¤­¤Ï¡¢¥Ð¥Ã¥¯¥¢¥Ã¥×¤òºî¤é¤Ê¤¤
+// ATTACH_DELETE_ADMIN_ONLY=TRUE¤Î¤È¤­Í­¸ú
+define('ATTACH_DELETE_ADMIN_NOBACKUP',FALSE); // FALSE or TRUE
 
 // ¥¢¥Ã¥×¥í¡¼¥É/ºï½ü»þ¤Ë¥Ñ¥¹¥ï¡¼¥É¤òÍ׵᤹¤ë(ADMIN_ONLY¤¬Í¥Àè)
 define('ATTACH_PASSWORD_REQUIRE',FALSE); // FALSE or TRUE
 
+// ¥Õ¥¡¥¤¥ë¤Î¥¢¥¯¥»¥¹¸¢
+define('ATTACH_FILE_MODE',0644);
+//define('ATTACH_FILE_MODE',0604); // for XREA.COM
+
 // file icon image
 if (!defined('FILE_ICON'))
 {
        define('FILE_ICON','<img src="./image/file.png" width="20" height="20" alt="file" style="border-width:0px" />');
 }
 
-//-------- init
-function plugin_attach_init()
-{
-       $messages = array(
-               '_attach_messages'=>array(
-                       'msg_uploaded' => '$1 ¤Ë¥¢¥Ã¥×¥í¡¼¥É¤·¤Þ¤·¤¿',
-                       'msg_deleted'  => '$1 ¤«¤é¥Õ¥¡¥¤¥ë¤òºï½ü¤·¤Þ¤·¤¿',
-                       'msg_freezed'  => 'źÉÕ¥Õ¥¡¥¤¥ë¤òÅà·ë¤·¤Þ¤·¤¿¡£',
-                       'msg_unfreezed'=> 'źÉÕ¥Õ¥¡¥¤¥ë¤òÅà·ë²ò½ü¤·¤Þ¤·¤¿¡£',
-                       'msg_upload'   => '$1 ¤Ø¤ÎźÉÕ',
-                       'msg_info'     => 'źÉÕ¥Õ¥¡¥¤¥ë¤Î¾ðÊó',
-                       'msg_confirm'  => '<p>%s ¤òºï½ü¤·¤Þ¤¹¡£</p>',
-                       'msg_list'     => 'źÉÕ¥Õ¥¡¥¤¥ë°ìÍ÷',
-                       'msg_listpage' => '$1 ¤ÎźÉÕ¥Õ¥¡¥¤¥ë°ìÍ÷',
-                       'msg_listall'  => 'Á´¥Ú¡¼¥¸¤ÎźÉÕ¥Õ¥¡¥¤¥ë°ìÍ÷',
-                       'msg_file'     => 'źÉÕ¥Õ¥¡¥¤¥ë',
-                       'msg_maxsize'  => '¥¢¥Ã¥×¥í¡¼¥É²ÄǽºÇÂç¥Õ¥¡¥¤¥ë¥µ¥¤¥º¤Ï %s ¤Ç¤¹¡£',
-                       'msg_count'    => ' <span class="small">%s·ï</span>',
-                       'msg_password' => '¥Ñ¥¹¥ï¡¼¥É',
-                       'msg_adminpass'=> '´ÉÍý¼Ô¥Ñ¥¹¥ï¡¼¥É',
-                       'msg_delete'   => '¤³¤Î¥Õ¥¡¥¤¥ë¤òºï½ü¤·¤Þ¤¹¡£',
-                       'msg_freeze'   => '¤³¤Î¥Õ¥¡¥¤¥ë¤òÅà·ë¤·¤Þ¤¹¡£',
-                       'msg_unfreeze' => '¤³¤Î¥Õ¥¡¥¤¥ë¤òÅà·ë²ò½ü¤·¤Þ¤¹¡£',
-                       'msg_isfreeze' => '¤³¤Î¥Õ¥¡¥¤¥ë¤ÏÅà·ë¤µ¤ì¤Æ¤¤¤Þ¤¹¡£',
-                       'msg_require'  => '(´ÉÍý¼Ô¥Ñ¥¹¥ï¡¼¥É¤¬É¬ÍפǤ¹)',
-                       'msg_filesize' => '¥µ¥¤¥º',
-                       'msg_date'     => 'ÅÐÏ¿Æü»þ',
-                       'msg_dlcount'  => '¥¢¥¯¥»¥¹¿ô',
-                       'err_noparm'   => '$1 ¤Ø¤Ï¥¢¥Ã¥×¥í¡¼¥É¡¦ºï½ü¤Ï¤Ç¤­¤Þ¤»¤ó',
-                       'err_exceed'   => '$1 ¤Ø¤Î¥Õ¥¡¥¤¥ë¥µ¥¤¥º¤¬Â礭¤¹¤®¤Þ¤¹',
-                       'err_exists'   => '$1 ¤ËƱ¤¸¥Õ¥¡¥¤¥ë̾¤¬Â¸ºß¤·¤Þ¤¹',
-                       'err_notfound' => '$1 ¤Ë¤½¤Î¥Õ¥¡¥¤¥ë¤Ï¸«¤Ä¤«¤ê¤Þ¤»¤ó',
-                       'err_noexist'  => 'źÉÕ¥Õ¥¡¥¤¥ë¤¬¤¢¤ê¤Þ¤»¤ó¡£',
-                       'err_password' => '¥Ñ¥¹¥ï¡¼¥É¤¬°ìÃפ·¤Þ¤»¤ó¡£',
-                       'err_adminpass'=> '´ÉÍý¼Ô¥Ñ¥¹¥ï¡¼¥É¤¬°ìÃפ·¤Þ¤»¤ó¡£',
-                       'btn_upload'   => '¥¢¥Ã¥×¥í¡¼¥É',
-                       'btn_info'     => '¾ÜºÙ',
-                       'btn_submit'   => '¼Â¹Ô'
-               )
-       );
-       set_plugin_messages($messages);
-}
+// mime-type¤òµ­½Ò¤·¤¿¥Ú¡¼¥¸
+define('ATTACH_CONFIG_PAGE_MIME','plugin/attach/mime-type');
 
 //-------- convert
 function plugin_attach_convert()
@@ -106,7 +67,7 @@ function plugin_attach_convert()
        if (!$nolist)
        {
                $obj = &new AttachPages($vars['page']);
-               $ret .= $obj->to_string($vars['page'],TRUE);
+               $ret .= $obj->toString($vars['page'],TRUE);
        }
        if (!$noform)
        {
@@ -119,8 +80,9 @@ function plugin_attach_convert()
 //-------- action
 function plugin_attach_action()
 {
-       global $vars,$HTTP_POST_FILES;
+       global $vars;
        
+       // backward compatible
        if (array_key_exists('openfile',$vars))
        {
                $vars['pcmd'] = 'open';
@@ -131,20 +93,30 @@ function plugin_attach_action()
                $vars['pcmd'] = 'delete';
                $vars['file'] = $vars['delfile'];
        }
-       if (array_key_exists('attach_file',$HTTP_POST_FILES) and
-               is_uploaded_file($HTTP_POST_FILES['attach_file']['tmp_name']))
-       {
-               return attach_upload();
-       }
        
        $age = array_key_exists('age',$vars) ? $vars['age'] : 0;
        $pcmd = array_key_exists('pcmd',$vars) ? $vars['pcmd'] : '';
        
+       // Authentication
+       if (array_key_exists('refer',$vars) and is_pagename($vars['refer']))
+       {
+               $read_cmds = array('info','open','list');
+               in_array($pcmd,$read_cmds) ?
+                       check_readable($vars['refer']) : check_editable($vars['refer']);
+       }
+       
+       // Upload
+       if (array_key_exists('attach_file',$_FILES))
+       {
+               $pass = array_key_exists('pass',$vars) ? md5($vars['pass']) : NULL;
+               return attach_upload($_FILES['attach_file'],$vars['refer'],$pass);
+       }
+       
        switch ($pcmd)
        {
                case 'info':    return attach_info();
                case 'delete':  return attach_delete();
-               case 'open':    return attach_open($vars['refer'],$vars['file'],$age);
+               case 'open':    return attach_open();
                case 'list':    return attach_list();
                case 'freeze':  return attach_freeze(TRUE);
                case 'unfreeze':return attach_freeze(FALSE);
@@ -162,244 +134,123 @@ function attach_filelist()
 {
        global $vars,$_attach_messages;
        
-       plugin_attach_init();
-       
        $obj = &new AttachPages($vars['page'],0);
 
        if (!array_key_exists($vars['page'],$obj->pages))
        {
                return '';
        }
-       return $_attach_messages['msg_file'].': '.$obj->to_string($vars['page'],TRUE)."\n";
+       return $_attach_messages['msg_file'].': '.$obj->toString($vars['page'],TRUE)."\n";
 }
 //-------- ¼ÂÂÎ
 //¥Õ¥¡¥¤¥ë¥¢¥Ã¥×¥í¡¼¥É
-function attach_upload()
+function attach_upload($file,$page,$pass=NULL)
 {
-       global $vars,$adminpass,$HTTP_POST_FILES;
-       global $_attach_messages;
+// $pass=NULL : ¥Ñ¥¹¥ï¡¼¥É¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤¤
+// $pass=TRUE : ¥¢¥Ã¥×¥í¡¼¥Éµö²Ä
+       global $adminpass,$_attach_messages;
        
-       if ($HTTP_POST_FILES['attach_file']['size'] > MAX_FILESIZE)
+       if ($file['tmp_name'] == '' or !is_uploaded_file($file['tmp_name']))
+       {
+               return array('result'=>FALSE);
+       }               
+       if ($file['size'] > MAX_FILESIZE)
        {
-               return array('msg'=>$_attach_messages['err_exceed']);
+               return array('result'=>FALSE,'msg'=>$_attach_messages['err_exceed']);
        }
-       if (is_freeze($vars['refer']) || !is_editable($vars['refer']))
+       if (!is_pagename($page) or ($pass !== TRUE and !is_editable($page)))
        {
-               return array('msg'=>$_attach_messages['err_noparm']);
+               return array('result'=>FALSE,'msg'=>$_attach_messages['err_noparm']);
        }
-       if (ATTACH_UPLOAD_ADMIN_ONLY and md5($vars['pass']) != $adminpass)
+       if (ATTACH_UPLOAD_ADMIN_ONLY and $pass !== TRUE
+               and ($pass === NULL or $pass != $adminpass))
        {
-               return array('msg'=>$_attach_messages['err_adminpass']);
+               return array('result'=>FALSE,'msg'=>$_attach_messages['err_adminpass']);
        }
        
-       $obj = &new AttachFile($vars['refer'],$HTTP_POST_FILES['attach_file']['name']); 
+       $obj = &new AttachFile($page,$file['name']);    
        
        if ($obj->exist)
        {
-               return array('msg'=>$_attach_messages['err_exists']);
+               return array('result'=>FALSE,'msg'=>$_attach_messages['err_exists']);
+       }
+       if (move_uploaded_file($file['tmp_name'],$obj->filename))
+       {
+               chmod($obj->filename,ATTACH_FILE_MODE);
        }
-       move_uploaded_file($HTTP_POST_FILES['attach_file']['tmp_name'],$obj->filename);
        
-       if (is_page($vars['refer']))
+       if (is_page($page))
        {
-               touch(get_filename($vars['refer']));
+               touch(get_filename($page));
        }
        
        $obj->getstatus();
-       $obj->status['pass'] = array_key_exists('pass',$vars) ? md5($vars['pass']) : '';
+       $obj->status['pass'] = ($pass !== TRUE and $pass !== NULL) ? $pass : '';
        $obj->putstatus();
 
-       return array('msg'=>$_attach_messages['msg_uploaded']);
+       return array('result'=>TRUE,'msg'=>$_attach_messages['msg_uploaded']);
 }
 //¾ÜºÙ¥Õ¥©¡¼¥à¤òɽ¼¨
 function attach_info($err='')
 {
-       global $script,$vars;
-       global $_attach_messages;
-       
-       $retval = array();
-
-       $obj = &new AttachFile($vars['refer'],$vars['file'],$vars['age']);
-       $obj->getstatus();
-       
-       $s_file = htmlspecialchars($vars['file']);
-       $s_refer = htmlspecialchars($vars['refer']);
-       $r_refer = rawurlencode($vars['refer']);
-
-       $retval['msg'] = sprintf($_attach_messages['msg_info'],$s_file);
-       $retval['body'] = ($err == '') ? '' : '<p>'.$_attach_messages[$err].'</p>';
-
-       $retval['body'] .= <<<EOD
-  <span class="small">
-   [<a href="$script?plugin=attach&amp;pcmd=list&amp;refer=$r_refer">{$_attach_messages['msg_list']}</a>]
-   [<a href="$script?plugin=attach&amp;pcmd=list">{$_attach_messages['msg_listall']}</a>]
-  </span><br />
-EOD;
+       global $vars,$_attach_messages;
        
-       if ($obj->status['freeze'])
+       foreach (array('refer','file','age') as $var)
        {
-               $msg_freezed = '<dd>'.$_attach_messages['msg_isfreeze'].'</dd>';
-               $msg_delete = '';
-               $msg_freeze  = '<input type="hidden" name="pcmd" value="unfreeze" />'.$_attach_messages['msg_unfreeze'];
-       }
-       else
-       {
-               $msg_freezed = '';
-               $msg_delete = '<input type="radio" name="pcmd" value="delete" />'.$_attach_messages['msg_delete'];
-               if (ATTACH_DELETE_ADMIN_ONLY)
-               {
-                       $msg_delete .= $_attach_messages['msg_require'];
-               }
-               $msg_delete .= '<br />';
-               $msg_freeze = '<input type="radio" name="pcmd" value="freeze" />'.$_attach_messages['msg_freeze'];
-       }
-       $info = $obj->to_string(TRUE,FALSE);
-       $type = attach_mime_content_type(UPLOAD_DIR.$obj->file);
-       $retval['body'] .= <<< EOD
-<dl>
- <dt>$info</dt>
- <dd>{$_attach_messages['msg_filesize']}:{$obj->size_str} ({$obj->size} bytes)</dd>
- <dd>Content-type:$type</dd>
- <dd>{$_attach_messages['msg_date']}:{$obj->time_str}</dd>
- <dd>{$_attach_messages['msg_dlcount']}:{$obj->status['count'][0]}</dd>
-  $msg_freezed
-</dl>
-EOD;
-       if ($obj->age)
-       {
-               return $retval;
+               $$var = array_key_exists($var,$vars) ? $vars[$var] : '';
        }
-       $retval['body'] .= <<< EOD
-<hr>
-<form action="$script" method="post">
- <div>
-  <input type="hidden" name="plugin" value="attach" />
-  <input type="hidden" name="refer" value="$s_refer" />
-  <input type="hidden" name="file" value="$s_file" />
-  $msg_delete
-  $msg_freeze{$_attach_messages['msg_require']}<br />
-  {$_attach_messages['msg_password']}: <input type="password" name="pass" size="8" />
-  <input type="submit" value="{$_attach_messages['btn_submit']}" />
- </div>
-</form>
-EOD;
        
-       return $retval;
+       $obj = &new AttachFile($refer,$file,$age);
+       return $obj->getstatus() ? $obj->info($err) : array('msg'=>$_attach_messages['err_notfound']);
 }
 //ºï½ü
 function attach_delete()
 {
-       global $vars,$adminpass;
-       global $_attach_messages;
-       
-       if (is_freeze($vars['refer']) or !is_editable($vars['refer']))
-       {
-               return array('msg' => $_attach_messages['err_noparm']);
-       }
-       
-       $obj = &new AttachFile($vars['refer'],$vars['file']);
-       
-       if (!$obj->exist)
-       {
-               return array('msg' => $_attach_messages['err_notfound']);
-       }
-       
-       $obj->getstatus();
-       
-       if ($obj->status['freeze'])
-       {
-               return attach_info('msg_isfreeze');
-       }
+       global $vars,$_attach_messages;
        
-       if (md5($vars['pass']) != $adminpass)
-       {
-               if (ATTACH_DELETE_ADMIN_ONLY)
-               {
-                       return attach_info('err_adminpass');
-               }
-               else if (ATTACH_PASSWORD_REQUIRE and md5($vars['pass']) != $obj->status['pass'])
-               {
-                       return attach_info('err_password');
-               }
-       }
-       //¥Ð¥Ã¥¯¥¢¥Ã¥×
-       do
+       foreach (array('refer','file','age','pass') as $var)
        {
-               $age = ++$obj->status['age'];
+               $$var = array_key_exists($var,$vars) ? $vars[$var] : '';
        }
-       while (file_exists($obj->basename.'.'.$age));
-       
-       rename($obj->basename,$obj->basename.'.'.$age);
-       $obj->status['count'][$age] = $obj->status['count'][0];
-       $obj->status['count'][0] = 0;
-       $obj->putstatus();
        
-       if (is_page($vars['refer']))
+       if (is_freeze($refer) or !is_editable($refer))
        {
-               touch(get_filename($vars['refer']));
+               return array('msg'=>$_attach_messages['err_noparm']);
        }
        
-       return array('msg' => $_attach_messages['msg_deleted']);
+       $obj = &new AttachFile($refer,$file,$age);
+       return $obj->getstatus() ? $obj->delete($pass) : array('msg'=>$_attach_messages['err_notfound']);
 }
 //Åà·ë
 function attach_freeze($freeze)
 {
-       global $vars,$adminpass;
-       global $_attach_messages;
+       global $vars,$_attach_messages;
        
-       if (is_freeze($vars['refer']) or !is_editable($vars['refer']))
+       foreach (array('refer','file','age','pass') as $var)
        {
-               return array('msg' => $_attach_messages['err_noparm']);
+               $$var = array_key_exists($var,$vars) ? $vars[$var] : '';
        }
        
-       $obj = &new AttachFile($vars['refer'],$vars['file']);
-       
-       if (!$obj->exist)
-       {
-               return array('msg' => $_attach_messages['err_notfound']);
-       }
-       if (md5($vars['pass']) != $adminpass)
+       if (is_freeze($refer) or !is_editable($refer))
        {
-               return attach_info('err_adminpass');
+               return array('msg'=>$_attach_messages['err_noparm']);
        }
        
-       $obj->getstatus();
-       $obj->status['freeze'] = $freeze;
-       $obj->putstatus();
-       
-       return array('msg' => $_attach_messages[$freeze ? 'msg_freezed' : 'msg_unfreezed']);
+       $obj = &new AttachFile($refer,$file,$age);
+       return $obj->getstatus() ? $obj->freeze($freeze,$pass) : array('msg'=>$_attach_messages['err_notfound']);
 }
 //¥À¥¦¥ó¥í¡¼¥É
-function attach_open($page,$file,$age=0)
+function attach_open()
 {
-       global $_attach_messages;
-       
-       $obj = &new AttachFile($page,$file,$age);
-       
-       if (!$obj->exist)
-       {
-               return array('msg' => $_attach_messages['err_notfound']);
-       }
-       
-       $obj->getstatus();
-       $obj->status['count'][$age]++;
-       $obj->putstatus();
-       
-       $type = attach_mime_content_type($obj->file);
-       $name = htmlspecialchars($obj->file);
+       global $vars,$_attach_messages;
        
-       // for japanese (???)
-       if (function_exists('mb_convert_encoding'))
+       foreach (array('refer','file','age') as $var)
        {
-               $name = mb_convert_encoding($name,'SJIS','auto');
+               $$var = array_key_exists($var,$vars) ? $vars[$var] : '';
        }
        
-       header('Content-Disposition: inline; filename="'.$name.'"');
-       header('Content-Length: '.$obj->size);
-       header('Content-Type: '.$type);
-       
-       @readfile($obj->filename);
-       exit; 
+       $obj = &new AttachFile($refer,$file,$age);
+       return $obj->getstatus() ? $obj->open() : array('msg'=>$_attach_messages['err_notfound']);
 }
 //°ìÍ÷¼èÆÀ
 function attach_list()
@@ -412,8 +263,8 @@ function attach_list()
        $obj = &new AttachPages($refer);
        
        $msg = $_attach_messages[$refer == '' ? 'msg_listall' : 'msg_listpage'];
-       $body = array_key_exists($refer,$obj->pages) ?
-               $obj->to_string($refer,FALSE) :
+       $body = ($refer == '' or array_key_exists($refer,$obj->pages)) ?
+               $obj->toString($refer,FALSE) :
                $_attach_messages['err_noexist'];
        return array('msg'=>$msg,'body'=>$body);
 }
@@ -434,9 +285,12 @@ function attach_showform()
 function attach_mime_content_type($filename)
 {
        $type = 'application/octet-stream'; //default
-       $config = ':config/plugin/attach/mime-type';
        
-       $size = getimagesize($filename);
+       if (!file_exists($filename))
+       {
+               return $type;
+       }
+       $size = @getimagesize($filename);
        if (is_array($size))
        {
                switch ($size[2])
@@ -452,26 +306,21 @@ function attach_mime_content_type($filename)
                }
        }
        
-       if (!is_page($config))
-       {
-               return $type;
-       }
-       
-       if (!preg_match('/_([0-9A-Z]+)$/',$filename,$matches))
+       if (!preg_match('/_((?:[0-9A-F]{2})+)(?:\.\d+)?$/',$filename,$matches))
        {
                return $type;
        }
        $filename = decode($matches[1]);
        
-       foreach (get_source($config) as $line)
+       // mime-type°ìÍ÷ɽ¤ò¼èÆÀ
+       $config = new Config(ATTACH_CONFIG_PAGE_MIME);
+       $table = $config->read() ? $config->get('mime-type') : array();
+       unset($config); // ¥á¥â¥êÀáÌó
+       
+       foreach ($table as $row)
        {
-               if (!preg_match('/\|(.+)\|/',$line,$matches))
-               {
-                       continue;
-               }
-               $cells = explode('|',$matches[1]);
-               $_type = trim($cells[0]);
-               $exts = preg_split('/\s+|,/',trim($cells[1]),-1,PREG_SPLIT_NO_EMPTY);
+               $_type = trim($row[0]);
+               $exts = preg_split('/\s+|,/',trim($row[1]),-1,PREG_SPLIT_NO_EMPTY);
                
                foreach ($exts as $ext)
                {
@@ -536,23 +385,32 @@ EOD;
 class AttachFile
 {
        var $page,$file,$age,$basename,$filename,$logname;
-       var $time,$size,$time_str,$size_str;
+       var $time = 0;
+       var $size = 0;
+       var $time_str = '';
+       var $size_str = '';
        var $status = array('count'=>array(0),'age'=>'','pass'=>'','freeze'=>FALSE);
        
        function AttachFile($page,$file,$age=0)
        {
                $this->page = $page;
-               $this->file = $file;
-               $this->age = $age;
+               $this->file = basename($file);
+               $this->age = is_numeric($age) ? $age : 0;
                
-               $this->basename = UPLOAD_DIR.encode($page).'_'.encode($file);
+               $this->basename = UPLOAD_DIR.encode($page).'_'.encode($this->file);
                $this->filename = $this->basename . ($age ? '.'.$age : '');
                $this->logname = $this->basename.'.log';
                $this->exist = file_exists($this->filename);
+               $this->time = $this->exist ? filemtime($this->filename) - LOCALZONE : 0;
+               $this->md5hash = $this->exist ? md5_file($this->filename) : '';
        }
        // ¥Õ¥¡¥¤¥ë¾ðÊó¼èÆÀ
        function getstatus()
        {
+               if (!$this->exist)
+               {
+                       return FALSE;
+               }
                // ¥í¥°¥Õ¥¡¥¤¥ë¼èÆÀ
                if (file_exists($this->logname))
                {
@@ -563,28 +421,35 @@ class AttachFile
                        }
                        $this->status['count'] = explode(',',$this->status['count']);
                }
-               $this->time = filemtime($this->filename) - LOCALZONE;
                $this->time_str = get_date('Y/m/d H:i:s',$this->time);
                $this->size = filesize($this->filename);
                $this->size_str = sprintf('%01.1f',round($this->size)/1000,1).'KB';
-       }               
+               $this->type = attach_mime_content_type($this->filename);
+               
+               return TRUE;
+       }
        //¥¹¥Æ¡¼¥¿¥¹Êݸ
        function putstatus()
        {
                $this->status['count'] = join(',',$this->status['count']);
                $fp = fopen($this->logname,'wb')
                        or die_message('cannot write '.$this->logname);
+               set_file_buffer($fp, 0);
+               flock($fp,LOCK_EX);
+               rewind($fp);
                foreach ($this->status as $key=>$value)
                {
                        fwrite($fp,$value."\n");
                }
+               flock($fp,LOCK_UN);
                fclose($fp);
        }
+       // ÆüÉÕ¤ÎÈæ³Ó´Ø¿ô
        function datecomp($a,$b)
        {
-               return ($a->filetime == $b->filetime) ? 0 : (($a->filetime > $b->filetime) ? -1 : 1);
+               return ($a->time == $b->time) ? 0 : (($a->time > $b->time) ? -1 : 1);
        }
-       function to_string($showicon,$showinfo)
+       function toString($showicon,$showinfo)
        {
                global $script,$date_format,$time_format,$weeklabels;
                global $_attach_messages;
@@ -608,6 +473,166 @@ class AttachFile
                }
                return "<a href=\"$script?plugin=attach&amp;pcmd=open$param\" title=\"$title\">$label</a>$count$info";
        }
+       // ¾ðÊóɽ¼¨
+       function info($err)
+       {
+               global $script,$_attach_messages;
+               
+               $r_page = rawurlencode($this->page);
+               $s_page = htmlspecialchars($this->page);
+               $s_file = htmlspecialchars($this->file);
+               $s_err = ($err == '') ? '' : '<p style="font-weight:bold">'.$_attach_messages[$err].'</p>';
+               
+               if ($this->age)
+               {
+                       $msg_freezed = '';
+                       $msg_delete  = '<input type="radio" name="pcmd" value="delete" />'.$_attach_messages['msg_delete'];
+                       $msg_delete .= $_attach_messages['msg_require'];
+                       $msg_delete .= '<br />';
+                       $msg_freeze  = '';
+               }
+               else
+               {
+                       if ($this->status['freeze'])
+                       {
+                               $msg_freezed = "<dd>{$_attach_messages['msg_isfreeze']}</dd>";
+                               $msg_delete = '';
+                               $msg_freeze  = '<input type="radio" name="pcmd" value="unfreeze" />'.$_attach_messages['msg_unfreeze'];
+                               $msg_freeze .= $_attach_messages['msg_require'].'<br />';
+                       }
+                       else
+                       {
+                               $msg_freezed = '';
+                               $msg_delete = '<input type="radio" name="pcmd" value="delete" />'.$_attach_messages['msg_delete'];
+                               if (ATTACH_DELETE_ADMIN_ONLY or $this->age)
+                               {
+                                       $msg_delete .= $_attach_messages['msg_require'];
+                               }
+                               $msg_delete .= '<br />';
+                               $msg_freeze  = '<input type="radio" name="pcmd" value="freeze" />'.$_attach_messages['msg_freeze'];
+                               $msg_freeze .= "{$_attach_messages['msg_require']}<br />";
+                       }
+               }
+               $info = $this->toString(TRUE,FALSE);
+               
+               $retval = array('msg'=>sprintf($_attach_messages['msg_info'],htmlspecialchars($this->file)));
+               $retval['body'] = <<< EOD
+<p class="small">
+ [<a href="$script?plugin=attach&amp;pcmd=list&amp;refer=$r_page">{$_attach_messages['msg_list']}</a>]
+ [<a href="$script?plugin=attach&amp;pcmd=list">{$_attach_messages['msg_listall']}</a>]
+</p>
+<dl>
+ <dt>$info</dt>
+ <dd>{$_attach_messages['msg_page']}:$s_page</dd>
+ <dd>{$_attach_messages['msg_filename']}:{$this->filename}</dd>
+ <dd>{$_attach_messages['msg_md5hash']}:{$this->md5hash}</dd>
+ <dd>{$_attach_messages['msg_filesize']}:{$this->size_str} ({$this->size} bytes)</dd>
+ <dd>Content-type:{$this->type}</dd>
+ <dd>{$_attach_messages['msg_date']}:{$this->time_str}</dd>
+ <dd>{$_attach_messages['msg_dlcount']}:{$this->status['count'][$this->age]}</dd>
+ $msg_freezed
+</dl>
+<hr />
+$s_err
+<form action="$script" method="post">
+ <div>
+  <input type="hidden" name="plugin" value="attach" />
+  <input type="hidden" name="refer" value="$s_page" />
+  <input type="hidden" name="file" value="$s_file" />
+  <input type="hidden" name="age" value="{$this->age}" />
+  $msg_delete
+  $msg_freeze
+  {$_attach_messages['msg_password']}: <input type="password" name="pass" size="8" />
+  <input type="submit" value="{$_attach_messages['btn_submit']}" />
+ </div>
+</form>
+EOD;
+               return $retval;
+       }
+       function delete($pass)
+       {
+               global $adminpass,$_attach_messages;
+                               
+               if ($this->status['freeze'])
+               {
+                       return attach_info('msg_isfreeze');
+               }
+               
+               if (md5($pass) != $adminpass)
+               {
+                       if (ATTACH_DELETE_ADMIN_ONLY or $this->age)
+                       {
+                               return attach_info('err_adminpass');
+                       }
+                       else if (ATTACH_PASSWORD_REQUIRE and md5($pass) != $this->status['pass'])
+                       {
+                               return attach_info('err_password');
+                       }
+               }
+               //¥Ð¥Ã¥¯¥¢¥Ã¥×
+               if ($this->age or
+                       (ATTACH_DELETE_ADMIN_ONLY and ATTACH_DELETE_ADMIN_NOBACKUP))
+               {
+                       @unlink($this->filename);
+               }
+               else
+               {
+                       do
+                       {
+                               $age = ++$this->status['age'];
+                       }
+                       while (file_exists($this->basename.'.'.$age));
+                       
+                       if (!rename($this->basename,$this->basename.'.'.$age))
+                       {
+                               // ºï½ü¼ºÇÔ why?
+                               return array('msg'=>$_attach_messages['err_delete']);
+                       }
+                       
+                       $this->status['count'][$age] = $this->status['count'][0];
+                       $this->status['count'][0] = 0;
+                       $this->putstatus();
+               }
+               if (is_page($this->page))
+               {
+                       touch(get_filename($this->page));
+               }
+               
+               return array('msg'=>$_attach_messages['msg_deleted']);
+       }
+       function freeze($freeze,$pass)
+       {
+               global $adminpass;
+               
+               if (md5($pass) != $adminpass)
+               {
+                       return attach_info('err_adminpass');
+               }
+               
+               $this->getstatus();
+               $this->status['freeze'] = $freeze;
+               $this->putstatus();
+               
+               return array('msg'=>$_attach_messages[$freeze ? 'msg_freezed' : 'msg_unfreezed']);
+       }
+       function open()
+       {
+               $this->getstatus();
+               $this->status['count'][$this->age]++;
+               $this->putstatus();
+               
+               // for japanese (???)
+               $filename = htmlspecialchars(mb_convert_encoding($this->file,'SJIS','auto'));
+               
+               ini_set('default_charset','');
+               mb_http_output('pass');
+               
+               header('Content-Disposition: inline; filename="'.$filename.'"');
+               header('Content-Length: '.$this->size);
+               header('Content-Type: '.$this->type);
+               @readfile($this->filename);
+               exit;
+       }
 }
 
 // ¥Õ¥¡¥¤¥ë¥³¥ó¥Æ¥Ê
@@ -625,8 +650,14 @@ class AttachFiles
                $this->files[$file][$age] = &new AttachFile($this->page,$file,$age);
        }
        // ¥Õ¥¡¥¤¥ë°ìÍ÷¤ò¼èÆÀ
-       function to_string($flat)
+       function toString($flat)
        {
+               global $_title_cannotread;
+               
+               if (!check_readable($this->page,FALSE,FALSE))
+               {
+                       return str_replace('$1',make_pagelink($this->page),$_title_cannotread);
+               }
                if ($flat)
                {
                        return $this->to_flat();
@@ -639,7 +670,7 @@ class AttachFiles
                        $_files = array();
                        foreach (array_keys($this->files[$file]) as $age)
                        {
-                               $_files[$age] = $this->files[$file][$age]->to_string(FALSE,TRUE);
+                               $_files[$age] = $this->files[$file][$age]->toString(FALSE,TRUE);
                        }
                        if (!array_key_exists(0,$_files))
                        {
@@ -672,7 +703,7 @@ class AttachFiles
                uasort($files,array('AttachFile','datecomp'));
                foreach (array_keys($files) as $file)
                {
-                       $ret .= $files[$file]->to_string(TRUE,TRUE).' ';
+                       $ret .= $files[$file]->toString(TRUE,TRUE).' ';
                }
                
                return $ret;
@@ -689,10 +720,10 @@ class AttachPages
                $dir = opendir(UPLOAD_DIR)
                        or die('directory '.UPLOAD_DIR.' is not exist or not readable.');
                
-               $page_pattern = ($page == '') ? '[0-9A-F]+' : preg_quote(encode($page),'/');
+               $page_pattern = ($page == '') ? '(?:[0-9A-F]{2})+' : preg_quote(encode($page),'/');
                $age_pattern = ($age === NULL) ?
                        '(?:\.([0-9]+))?' : ($age ?  "\.($age)" : '');
-               $pattern = "/^({$page_pattern})_([0-9A-F]+){$age_pattern}$/";
+               $pattern = "/^({$page_pattern})_((?:[0-9A-F]{2})+){$age_pattern}$/";
                
                while ($file = readdir($dir))
                {
@@ -711,7 +742,7 @@ class AttachPages
                }
                closedir($dir);
        }
-       function to_string($page='',$flat=FALSE)
+       function toString($page='',$flat=FALSE)
        {
                if ($page != '')
                {
@@ -719,14 +750,14 @@ class AttachPages
                        {
                                return '';
                        }
-                       return $this->pages[$page]->to_string($flat);
+                       return $this->pages[$page]->toString($flat);
                }
                $ret = '';
                $pages = array_keys($this->pages);
                sort($pages);
                foreach ($pages as $page)
                {
-                       $ret .= '<li>'.$this->pages[$page]->to_string($flat)."</li>\n";
+                       $ret .= '<li>'.$this->pages[$page]->toString($flat)."</li>\n";
                }
                return "\n<ul>\n".$ret."</ul>\n";