2 /////////////////////////////////////////////////
3 // PukiWiki - Yet another WikiWikiWeb clone.
5 // $Id: attach.inc.php,v 1.42 2004/07/31 03:09:20 henoheno Exp $
11 changed by Y.MASUI <masui@hisec.co.jp> http://masui.net/pukiwiki/
12 modified by PANDA <panda@arino.jp> http://home.arino.jp/
15 // max file size for upload on PHP(PHP default 2MB)
16 ini_set('upload_max_filesize','2M');
18 // max file size for upload on script of PukiWiki(default 1MB)
19 define('MAX_FILESIZE',1000000);
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
29 // ¥¢¥Ã¥×¥í¡¼¥É/ºï½ü»þ¤Ë¥Ñ¥¹¥ï¡¼¥É¤òÍ׵᤹¤ë(ADMIN_ONLY¤¬Í¥Àè)
30 define('ATTACH_PASSWORD_REQUIRE',FALSE); // FALSE or TRUE
32 // ¥Õ¥¡¥¤¥ë¤Î¥¢¥¯¥»¥¹¸¢
33 define('ATTACH_FILE_MODE',0644);
34 //define('ATTACH_FILE_MODE',0604); // for XREA.COM
37 if (!defined('FILE_ICON'))
39 define('FILE_ICON','<img src="' . IMAGE_DIR . 'file.png" width="20" height="20" alt="file" style="border-width:0px" />');
42 // mime-type¤òµ½Ò¤·¤¿¥Ú¡¼¥¸
43 define('ATTACH_CONFIG_PAGE_MIME','plugin/attach/mime-type');
46 function plugin_attach_convert()
50 if (!ini_get('file_uploads'))
52 return 'file_uploads disabled';
55 $nolist = $noform = FALSE;
57 if (func_num_args() > 0)
59 foreach (func_get_args() as $arg)
61 $arg = strtolower($arg);
62 $nolist |= ($arg == 'nolist');
63 $noform |= ($arg == 'noform');
69 $obj = &new AttachPages($vars['page']);
70 $ret .= $obj->toString($vars['page'],TRUE);
74 $ret .= attach_form($vars['page']);
81 function plugin_attach_action()
85 // backward compatible
86 if (array_key_exists('openfile',$vars))
88 $vars['pcmd'] = 'open';
89 $vars['file'] = $vars['openfile'];
91 if (array_key_exists('delfile',$vars))
93 $vars['pcmd'] = 'delete';
94 $vars['file'] = $vars['delfile'];
97 $age = array_key_exists('age',$vars) ? $vars['age'] : 0;
98 $pcmd = array_key_exists('pcmd',$vars) ? $vars['pcmd'] : '';
101 if (array_key_exists('refer',$vars) and is_pagename($vars['refer']))
103 $read_cmds = array('info','open','list');
104 in_array($pcmd,$read_cmds) ?
105 check_readable($vars['refer']) : check_editable($vars['refer']);
109 if (array_key_exists('attach_file',$_FILES))
111 $pass = isset($vars['pass']) ? $vars['pass'] : NULL;
112 return attach_upload($_FILES['attach_file'], $vars['refer'], $pass);
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();
125 if ($vars['page'] == '' or !is_page($vars['page']))
127 return attach_list();
130 return attach_showform();
132 //-------- call from skin
133 function attach_filelist()
135 global $vars,$_attach_messages;
137 $obj = &new AttachPages($vars['page'],0);
139 if (!array_key_exists($vars['page'],$obj->pages))
143 return $_attach_messages['msg_file'].': '.$obj->toString($vars['page'],TRUE)."\n";
146 //¥Õ¥¡¥¤¥ë¥¢¥Ã¥×¥í¡¼¥É
147 function attach_upload($file,$page,$pass=NULL)
149 // $pass=NULL : ¥Ñ¥¹¥ï¡¼¥É¤¬»ØÄꤵ¤ì¤Æ¤¤¤Ê¤¤
150 // $pass=TRUE : ¥¢¥Ã¥×¥í¡¼¥Éµö²Ä
151 global $_attach_messages;
153 if ($file['tmp_name'] == '' or !is_uploaded_file($file['tmp_name']))
155 return array('result'=>FALSE);
157 if ($file['size'] > MAX_FILESIZE)
159 return array('result'=>FALSE,'msg'=>$_attach_messages['err_exceed']);
161 if (!is_pagename($page) or ($pass !== TRUE and !is_editable($page)))
163 return array('result'=>FALSE,'msg'=>$_attach_messages['err_noparm']);
165 if (ATTACH_UPLOAD_ADMIN_ONLY and $pass !== TRUE
166 and ($pass === NULL or ! pkwk_login($pass)))
168 return array('result'=>FALSE,'msg'=>$_attach_messages['err_adminpass']);
171 $obj = &new AttachFile($page,$file['name']);
175 return array('result'=>FALSE,'msg'=>$_attach_messages['err_exists']);
177 if (move_uploaded_file($file['tmp_name'],$obj->filename))
179 chmod($obj->filename,ATTACH_FILE_MODE);
184 touch(get_filename($page));
188 $obj->status['pass'] = ($pass !== TRUE and $pass !== NULL) ? $pass : '';
191 return array('result'=>TRUE,'msg'=>$_attach_messages['msg_uploaded']);
194 function attach_info($err='')
196 global $vars,$_attach_messages;
198 foreach (array('refer','file','age') as $var)
200 $$var = array_key_exists($var,$vars) ? $vars[$var] : '';
203 $obj = &new AttachFile($refer,$file,$age);
204 return $obj->getstatus() ? $obj->info($err) : array('msg'=>$_attach_messages['err_notfound']);
207 function attach_delete()
209 global $vars,$_attach_messages;
211 foreach (array('refer','file','age','pass') as $var)
213 $$var = array_key_exists($var,$vars) ? $vars[$var] : '';
216 if (is_freeze($refer) or !is_editable($refer))
218 return array('msg'=>$_attach_messages['err_noparm']);
221 $obj = &new AttachFile($refer,$file,$age);
222 return $obj->getstatus() ? $obj->delete($pass) : array('msg'=>$_attach_messages['err_notfound']);
225 function attach_freeze($freeze)
227 global $vars,$_attach_messages;
229 foreach (array('refer','file','age','pass') as $var)
231 $$var = array_key_exists($var,$vars) ? $vars[$var] : '';
234 if (is_freeze($refer) or !is_editable($refer))
236 return array('msg'=>$_attach_messages['err_noparm']);
239 $obj = &new AttachFile($refer,$file,$age);
240 return $obj->getstatus() ? $obj->freeze($freeze,$pass) : array('msg'=>$_attach_messages['err_notfound']);
243 function attach_open()
245 global $vars,$_attach_messages;
247 foreach (array('refer','file','age') as $var)
249 $$var = array_key_exists($var,$vars) ? $vars[$var] : '';
252 $obj = &new AttachFile($refer,$file,$age);
253 return $obj->getstatus() ? $obj->open() : array('msg'=>$_attach_messages['err_notfound']);
256 function attach_list()
259 global $_attach_messages;
261 $refer = array_key_exists('refer',$vars) ? $vars['refer'] : '';
263 $obj = &new AttachPages($refer);
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);
271 //¥¢¥Ã¥×¥í¡¼¥É¥Õ¥©¡¼¥à¤òɽ¼¨
272 function attach_showform()
275 global $_attach_messages;
277 $vars['refer'] = $vars['page'];
278 $body = ini_get('file_uploads') ? attach_form($vars['page']) : 'file_uploads disabled.';
280 return array('msg'=>$_attach_messages['msg_upload'],'body'=>$body);
285 function attach_mime_content_type($filename)
287 $type = 'application/octet-stream'; //default
289 if (!file_exists($filename))
293 $size = @getimagesize($filename);
305 return 'application/x-shockwave-flash';
309 if (!preg_match('/_((?:[0-9A-F]{2})+)(?:\.\d+)?$/',$filename,$matches))
313 $filename = decode($matches[1]);
315 // mime-type°ìÍ÷ɽ¤ò¼èÆÀ
316 $config = new Config(ATTACH_CONFIG_PAGE_MIME);
317 $table = $config->read() ? $config->get('mime-type') : array();
318 unset($config); // ¥á¥â¥êÀáÌó
320 foreach ($table as $row)
322 $_type = trim($row[0]);
323 $exts = preg_split('/\s+|,/',trim($row[1]),-1,PREG_SPLIT_NO_EMPTY);
325 foreach ($exts as $ext)
327 if (preg_match("/\.$ext$/i",$filename))
336 //¥¢¥Ã¥×¥í¡¼¥É¥Õ¥©¡¼¥à
337 function attach_form($page)
339 global $script,$vars;
340 global $_attach_messages;
342 $r_page = rawurlencode($page);
343 $s_page = htmlspecialchars($page);
346 [<a href="$script?plugin=attach&pcmd=list&refer=$r_page">{$_attach_messages['msg_list']}</a>]
347 [<a href="$script?plugin=attach&pcmd=list">{$_attach_messages['msg_listall']}</a>]
351 if (!(bool)ini_get('file_uploads'))
356 $maxsize = MAX_FILESIZE;
357 $msg_maxsize = sprintf($_attach_messages['msg_maxsize'],number_format($maxsize/1000)."KB");
360 if (ATTACH_PASSWORD_REQUIRE or ATTACH_UPLOAD_ADMIN_ONLY)
362 $title = $_attach_messages[ATTACH_UPLOAD_ADMIN_ONLY ? 'msg_adminpass' : 'msg_password'];
363 $pass = '<br />'.$title.': <input type="password" name="pass" size="8" />';
366 <form enctype="multipart/form-data" action="$script" method="post">
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" />
376 {$_attach_messages['msg_file']}: <input type="file" name="attach_file" />
378 <input type="submit" value="{$_attach_messages['btn_upload']}" />
387 var $page,$file,$age,$basename,$filename,$logname;
392 var $status = array('count'=>array(0),'age'=>'','pass'=>'','freeze'=>FALSE);
394 function AttachFile($page,$file,$age=0)
397 $this->file = basename($file);
398 $this->age = is_numeric($age) ? $age : 0;
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) : '';
415 if (file_exists($this->logname))
417 $data = file($this->logname);
418 foreach ($this->status as $key=>$value)
420 $this->status[$key] = chop(array_shift($data));
422 $this->status['count'] = explode(',',$this->status['count']);
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);
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);
440 foreach ($this->status as $key=>$value)
442 fwrite($fp,$value."\n");
448 function datecomp($a,$b)
450 return ($a->time == $b->time) ? 0 : (($a->time > $b->time) ? -1 : 1);
452 function toString($showicon,$showinfo)
454 global $script,$date_format,$time_format,$weeklabels;
455 global $_attach_messages;
458 $param = '&file='.rawurlencode($this->file).'&refer='.rawurlencode($this->page).
459 ($this->age ? '&age='.$this->age : '');
460 $title = $this->time_str.' '.$this->size_str;
461 $label = ($showicon ? FILE_ICON : '').htmlspecialchars($this->file);
464 $label .= ' (backup No.'.$this->age.')';
469 $_title = str_replace('$1',rawurlencode($this->file),$_attach_messages['msg_info']);
470 $info = "\n<span class=\"small\">[<a href=\"$script?plugin=attach&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]) : '';
474 return "<a href=\"$script?plugin=attach&pcmd=open$param\" title=\"$title\">$label</a>$count$info";
479 global $script,$_attach_messages;
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>';
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 />';
496 if ($this->status['freeze'])
498 $msg_freezed = "<dd>{$_attach_messages['msg_isfreeze']}</dd>";
500 $msg_freeze = '<input type="radio" name="pcmd" value="unfreeze" />'.$_attach_messages['msg_unfreeze'];
501 $msg_freeze .= $_attach_messages['msg_require'].'<br />';
506 $msg_delete = '<input type="radio" name="pcmd" value="delete" />'.$_attach_messages['msg_delete'];
507 if (ATTACH_DELETE_ADMIN_ONLY or $this->age)
509 $msg_delete .= $_attach_messages['msg_require'];
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 />";
516 $info = $this->toString(TRUE,FALSE);
518 $retval = array('msg'=>sprintf($_attach_messages['msg_info'],htmlspecialchars($this->file)));
519 $retval['body'] = <<< EOD
521 [<a href="$script?plugin=attach&pcmd=list&refer=$r_page">{$_attach_messages['msg_list']}</a>]
522 [<a href="$script?plugin=attach&pcmd=list">{$_attach_messages['msg_listall']}</a>]
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>
537 <form action="$script" method="post">
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}" />
545 {$_attach_messages['msg_password']}: <input type="password" name="pass" size="8" />
546 <input type="submit" value="{$_attach_messages['btn_submit']}" />
552 function delete($pass)
554 global $_attach_messages;
556 if ($this->status['freeze'])
558 return attach_info('msg_isfreeze');
561 if (! pkwk_login($pass))
563 if (ATTACH_DELETE_ADMIN_ONLY or $this->age)
565 return attach_info('err_adminpass');
567 else if (ATTACH_PASSWORD_REQUIRE and md5($pass) != $this->status['pass'])
569 return attach_info('err_password');
574 (ATTACH_DELETE_ADMIN_ONLY and ATTACH_DELETE_ADMIN_NOBACKUP))
576 @unlink($this->filename);
582 $age = ++$this->status['age'];
584 while (file_exists($this->basename.'.'.$age));
586 if (!rename($this->basename,$this->basename.'.'.$age))
589 return array('msg'=>$_attach_messages['err_delete']);
592 $this->status['count'][$age] = $this->status['count'][0];
593 $this->status['count'][0] = 0;
596 if (is_page($this->page))
598 touch(get_filename($this->page));
601 return array('msg'=>$_attach_messages['msg_deleted']);
603 function freeze($freeze,$pass)
605 if (! pkwk_login($pass))
607 return attach_info('err_adminpass');
611 $this->status['freeze'] = $freeze;
614 return array('msg'=>$_attach_messages[$freeze ? 'msg_freezed' : 'msg_unfreezed']);
619 $this->status['count'][$this->age]++;
622 // for japanese (???)
623 $filename = htmlspecialchars(mb_convert_encoding($this->file,'SJIS','auto'));
625 ini_set('default_charset','');
626 mb_http_output('pass');
628 header('Content-Disposition: inline; filename="'.$filename.'"');
629 header('Content-Length: '.$this->size);
630 header('Content-Type: '.$this->type);
631 @readfile($this->filename);
640 var $files = array();
642 function AttachFiles($page)
646 function add($file,$age)
648 $this->files[$file][$age] = &new AttachFile($this->page,$file,$age);
650 // ¥Õ¥¡¥¤¥ë°ìÍ÷¤ò¼èÆÀ
651 function toString($flat)
653 global $_title_cannotread;
655 if (!check_readable($this->page,FALSE,FALSE))
657 return str_replace('$1',make_pagelink($this->page),$_title_cannotread);
661 return $this->to_flat();
664 $files = array_keys($this->files);
666 foreach ($files as $file)
669 foreach (array_keys($this->files[$file]) as $age)
671 $_files[$age] = $this->files[$file][$age]->toString(FALSE,TRUE);
673 if (!array_key_exists(0,$_files))
675 $_files[0] = htmlspecialchars($file);
680 $ret .= " <li>$_file\n";
683 $ret .= "<ul>\n<li>".join("</li>\n<li>",$_files)."</li>\n</ul>\n";
687 return make_pagelink($this->page)."\n<ul>\n$ret</ul>\n";
689 // ¥Õ¥¡¥¤¥ë°ìÍ÷¤ò¼èÆÀ(inline)
694 foreach (array_keys($this->files) as $file)
696 if (array_key_exists(0,$this->files[$file]))
698 $files[$file] = &$this->files[$file][0];
701 uasort($files,array('AttachFile','datecomp'));
702 foreach (array_keys($files) as $file)
704 $ret .= $files[$file]->toString(TRUE,TRUE).' ';
713 var $pages = array();
715 function AttachPages($page='',$age=NULL)
718 $dir = opendir(UPLOAD_DIR)
719 or die('directory '.UPLOAD_DIR.' is not exist or not readable.');
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}$/";
726 while ($file = readdir($dir))
728 if (!preg_match($pattern,$file,$matches))
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))
737 $this->pages[$_page] = &new AttachFiles($_page);
739 $this->pages[$_page]->add($_file,$_age);
743 function toString($page='',$flat=FALSE)
747 if (!array_key_exists($page,$this->pages))
751 return $this->pages[$page]->toString($flat);
754 $pages = array_keys($this->pages);
756 foreach ($pages as $page)
758 $ret .= '<li>'.$this->pages[$page]->toString($flat)."</li>\n";
760 return "\n<ul>\n".$ret."</ul>\n";