PageRenderTime 49ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/plugin/attach.inc.php

https://github.com/miya5n/pukiwiki
PHP | 856 lines | 658 code | 134 blank | 64 comment | 122 complexity | d6d41a43a559e9593a43a93222cc746c MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. // PukiWiki - Yet another WikiWikiWeb clone
  3. // $Id: attach.inc.php,v 1.92 2011/01/25 15:01:01 henoheno Exp $
  4. // Copyright (C)
  5. // 2003-2007, 2009 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
  10. //
  11. // File attach plugin
  12. // NOTE (PHP > 4.2.3):
  13. // This feature is disabled at newer version of PHP.
  14. // Set this at php.ini if you want.
  15. // Max file size for upload on PHP (PHP default: 2MB)
  16. ini_set('upload_max_filesize', '2M');
  17. // Max file size for upload on script of PukiWikiX_FILESIZE
  18. define('PLUGIN_ATTACH_MAX_FILESIZE', (1024 * 1024)); // default: 1MB
  19. // 管理者だけが添付ファイルをアップロードできるようにする
  20. define('PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY', TRUE); // FALSE or TRUE
  21. // 管理者だけが添付ファイルを削除できるようにする
  22. define('PLUGIN_ATTACH_DELETE_ADMIN_ONLY', TRUE); // FALSE or TRUE
  23. // 管理者が添付ファイルを削除するときは、バックアップを作らない
  24. // PLUGIN_ATTACH_DELETE_ADMIN_ONLY=TRUEのとき有効
  25. define('PLUGIN_ATTACH_DELETE_ADMIN_NOBACKUP', TRUE); // FALSE or TRUE
  26. // アップロード/削除時にパスワードを要求する(ADMIN_ONLYが優先)
  27. define('PLUGIN_ATTACH_PASSWORD_REQUIRE', FALSE); // FALSE or TRUE
  28. // 添付ファイル名を変更できるようにする
  29. define('PLUGIN_ATTACH_RENAME_ENABLE', TRUE); // FALSE or TRUE
  30. // ファイルのアクセス権
  31. define('PLUGIN_ATTACH_FILE_MODE', 0644);
  32. //define('PLUGIN_ATTACH_FILE_MODE', 0604); // for XREA.COM
  33. // File icon image
  34. define('PLUGIN_ATTACH_FILE_ICON', '<img src="' . IMAGE_DIR . 'file.png"' .
  35. ' width="20" height="20" alt="file"' .
  36. ' style="border-width:0px" />');
  37. // mime-typeを記述したページ
  38. define('PLUGIN_ATTACH_CONFIG_PAGE_MIME', 'plugin/attach/mime-type');
  39. //-------- convert
  40. function plugin_attach_convert()
  41. {
  42. global $vars;
  43. $page = isset($vars['page']) ? $vars['page'] : '';
  44. $nolist = $noform = FALSE;
  45. if (func_num_args() > 0) {
  46. foreach (func_get_args() as $arg) {
  47. $arg = strtolower($arg);
  48. $nolist |= ($arg == 'nolist');
  49. $noform |= ($arg == 'noform');
  50. }
  51. }
  52. $ret = '';
  53. if (! $nolist) {
  54. $obj = new AttachPages($page);
  55. $ret .= $obj->toString($page, TRUE);
  56. }
  57. if (! $noform) {
  58. $ret .= attach_form($page);
  59. }
  60. return $ret;
  61. }
  62. //-------- action
  63. function plugin_attach_action()
  64. {
  65. global $vars, $_attach_messages;
  66. // Backward compatible
  67. if (isset($vars['openfile'])) {
  68. $vars['file'] = $vars['openfile'];
  69. $vars['pcmd'] = 'open';
  70. }
  71. if (isset($vars['delfile'])) {
  72. $vars['file'] = $vars['delfile'];
  73. $vars['pcmd'] = 'delete';
  74. }
  75. $pcmd = isset($vars['pcmd']) ? $vars['pcmd'] : '';
  76. $refer = isset($vars['refer']) ? $vars['refer'] : '';
  77. $pass = isset($vars['pass']) ? $vars['pass'] : NULL;
  78. $page = isset($vars['page']) ? $vars['page'] : '';
  79. if ($refer != '' && is_pagename($refer)) {
  80. if(in_array($pcmd, array('info', 'open', 'list'))) {
  81. check_readable($refer);
  82. } else {
  83. check_editable($refer);
  84. }
  85. }
  86. // Dispatch
  87. if (isset($_FILES['attach_file'])) {
  88. // Upload
  89. return attach_upload($_FILES['attach_file'], $refer, $pass);
  90. } else {
  91. switch ($pcmd) {
  92. case 'delete': /*FALLTHROUGH*/
  93. case 'freeze':
  94. case 'unfreeze':
  95. if (PKWK_READONLY) die_message('PKWK_READONLY prohibits editing');
  96. }
  97. switch ($pcmd) {
  98. case 'info' : return attach_info();
  99. case 'delete' : return attach_delete();
  100. case 'open' : return attach_open();
  101. case 'list' : return attach_list();
  102. case 'freeze' : return attach_freeze(TRUE);
  103. case 'unfreeze' : return attach_freeze(FALSE);
  104. case 'rename' : return attach_rename();
  105. case 'upload' : return attach_showform();
  106. }
  107. if ($page == '' || ! is_page($page)) {
  108. return attach_list();
  109. } else {
  110. return attach_showform();
  111. }
  112. }
  113. }
  114. //-------- call from skin
  115. function attach_filelist()
  116. {
  117. global $vars, $_attach_messages;
  118. $page = isset($vars['page']) ? $vars['page'] : '';
  119. $obj = new AttachPages($page, 0);
  120. if (! isset($obj->pages[$page])) {
  121. return '';
  122. } else {
  123. return $_attach_messages['msg_file'] . ': ' .
  124. $obj->toString($page, TRUE) . "\n";
  125. }
  126. }
  127. //-------- 実体
  128. // ファイルアップロード
  129. // $pass = NULL : パスワードが指定されていない
  130. // $pass = TRUE : アップロード許可
  131. function attach_upload($file, $page, $pass = NULL)
  132. {
  133. global $_attach_messages, $notify, $notify_subject;
  134. if (PKWK_READONLY) die_message('PKWK_READONLY prohibits editing');
  135. // Check query-string
  136. $query = 'plugin=attach&amp;pcmd=info&amp;refer=' . rawurlencode($page) .
  137. '&amp;file=' . rawurlencode($file['name']);
  138. if (PKWK_QUERY_STRING_MAX && strlen($query) > PKWK_QUERY_STRING_MAX) {
  139. pkwk_common_headers();
  140. echo('Query string (page name and/or file name) too long');
  141. exit;
  142. } else if (! is_page($page)) {
  143. die_message('No such page');
  144. } else if ($file['tmp_name'] == '' || ! is_uploaded_file($file['tmp_name'])) {
  145. return array('result'=>FALSE);
  146. } else if ($file['size'] > PLUGIN_ATTACH_MAX_FILESIZE) {
  147. return array(
  148. 'result'=>FALSE,
  149. 'msg'=>$_attach_messages['err_exceed']);
  150. } else if (! is_pagename($page) || ($pass !== TRUE && ! is_editable($page))) {
  151. return array(
  152. 'result'=>FALSE,'
  153. msg'=>$_attach_messages['err_noparm']);
  154. } else if (PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY && $pass !== TRUE &&
  155. ($pass === NULL || ! pkwk_login($pass))) {
  156. return array(
  157. 'result'=>FALSE,
  158. 'msg'=>$_attach_messages['err_adminpass']);
  159. }
  160. $obj = new AttachFile($page, $file['name']);
  161. if ($obj->exist)
  162. return array('result'=>FALSE,
  163. 'msg'=>$_attach_messages['err_exists']);
  164. if (move_uploaded_file($file['tmp_name'], $obj->filename))
  165. chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE);
  166. if (is_page($page))
  167. pkwk_touch_file(get_filename($page));
  168. $obj->getstatus();
  169. $obj->status['pass'] = ($pass !== TRUE && $pass !== NULL) ? md5($pass) : '';
  170. $obj->putstatus();
  171. if ($notify) {
  172. $footer['ACTION'] = 'File attached';
  173. $footer['FILENAME'] = & $file['name'];
  174. $footer['FILESIZE'] = & $file['size'];
  175. $footer['PAGE'] = & $page;
  176. $footer['URI'] = get_script_uri() .
  177. //'?' . rawurlencode($page);
  178. // MD5 may heavy
  179. '?plugin=attach' .
  180. '&refer=' . rawurlencode($page) .
  181. '&file=' . rawurlencode($file['name']) .
  182. '&pcmd=info';
  183. $footer['USER_AGENT'] = TRUE;
  184. $footer['REMOTE_ADDR'] = TRUE;
  185. pkwk_mail_notify($notify_subject, "\n", $footer) or
  186. die('pkwk_mail_notify(): Failed');
  187. }
  188. return array(
  189. 'result'=>TRUE,
  190. 'msg'=>$_attach_messages['msg_uploaded']);
  191. }
  192. // 詳細フォームを表示
  193. function attach_info($err = '')
  194. {
  195. global $vars, $_attach_messages;
  196. foreach (array('refer', 'file', 'age') as $var)
  197. ${$var} = isset($vars[$var]) ? $vars[$var] : '';
  198. $obj = new AttachFile($refer, $file, $age);
  199. return $obj->getstatus() ?
  200. $obj->info($err) :
  201. array('msg'=>$_attach_messages['err_notfound']);
  202. }
  203. // 削除
  204. function attach_delete()
  205. {
  206. global $vars, $_attach_messages;
  207. foreach (array('refer', 'file', 'age', 'pass') as $var)
  208. ${$var} = isset($vars[$var]) ? $vars[$var] : '';
  209. if (is_freeze($refer) || ! is_editable($refer))
  210. return array('msg'=>$_attach_messages['err_noparm']);
  211. $obj = new AttachFile($refer, $file, $age);
  212. if (! $obj->getstatus())
  213. return array('msg'=>$_attach_messages['err_notfound']);
  214. return $obj->delete($pass);
  215. }
  216. // 凍結
  217. function attach_freeze($freeze)
  218. {
  219. global $vars, $_attach_messages;
  220. foreach (array('refer', 'file', 'age', 'pass') as $var) {
  221. ${$var} = isset($vars[$var]) ? $vars[$var] : '';
  222. }
  223. if (is_freeze($refer) || ! is_editable($refer)) {
  224. return array('msg'=>$_attach_messages['err_noparm']);
  225. } else {
  226. $obj = new AttachFile($refer, $file, $age);
  227. return $obj->getstatus() ?
  228. $obj->freeze($freeze, $pass) :
  229. array('msg'=>$_attach_messages['err_notfound']);
  230. }
  231. }
  232. // リネーム
  233. function attach_rename()
  234. {
  235. global $vars, $_attach_messages;
  236. foreach (array('refer', 'file', 'age', 'pass', 'newname') as $var) {
  237. ${$var} = isset($vars[$var]) ? $vars[$var] : '';
  238. }
  239. if (is_freeze($refer) || ! is_editable($refer)) {
  240. return array('msg'=>$_attach_messages['err_noparm']);
  241. }
  242. $obj = new AttachFile($refer, $file, $age);
  243. if (! $obj->getstatus())
  244. return array('msg'=>$_attach_messages['err_notfound']);
  245. return $obj->rename($pass, $newname);
  246. }
  247. // ダウンロード
  248. function attach_open()
  249. {
  250. global $vars, $_attach_messages;
  251. foreach (array('refer', 'file', 'age') as $var) {
  252. ${$var} = isset($vars[$var]) ? $vars[$var] : '';
  253. }
  254. $obj = new AttachFile($refer, $file, $age);
  255. return $obj->getstatus() ?
  256. $obj->open() :
  257. array('msg'=>$_attach_messages['err_notfound']);
  258. }
  259. // 一覧取得
  260. function attach_list()
  261. {
  262. global $vars, $_attach_messages;
  263. $refer = isset($vars['refer']) ? $vars['refer'] : '';
  264. $obj = new AttachPages($refer);
  265. $msg = $_attach_messages[($refer == '') ? 'msg_listall' : 'msg_listpage'];
  266. $body = ($refer == '' || isset($obj->pages[$refer])) ?
  267. $obj->toString($refer, FALSE) :
  268. $_attach_messages['err_noexist'];
  269. return array('msg'=>$msg, 'body'=>$body);
  270. }
  271. // アップロードフォームを表示 (action時)
  272. function attach_showform()
  273. {
  274. global $vars, $_attach_messages;
  275. $page = isset($vars['page']) ? $vars['page'] : '';
  276. $vars['refer'] = $page;
  277. $body = attach_form($page);
  278. return array('msg'=>$_attach_messages['msg_upload'], 'body'=>$body);
  279. }
  280. //-------- サービス
  281. // mime-typeの決定
  282. function attach_mime_content_type($filename)
  283. {
  284. $type = 'application/octet-stream'; // default
  285. if (! file_exists($filename)) return $type;
  286. $size = @getimagesize($filename);
  287. if (is_array($size)) {
  288. switch ($size[2]) {
  289. case 1: return 'image/gif';
  290. case 2: return 'image/jpeg';
  291. case 3: return 'image/png';
  292. case 4: return 'application/x-shockwave-flash';
  293. }
  294. }
  295. $matches = array();
  296. if (! preg_match('/_((?:[0-9A-F]{2})+)(?:\.\d+)?$/', $filename, $matches))
  297. return $type;
  298. $filename = decode($matches[1]);
  299. // mime-type一覧表を取得
  300. $config = new Config(PLUGIN_ATTACH_CONFIG_PAGE_MIME);
  301. $table = $config->read() ? $config->get('mime-type') : array();
  302. unset($config); // メモリ節約
  303. foreach ($table as $row) {
  304. $_type = trim($row[0]);
  305. $exts = preg_split('/\s+|,/', trim($row[1]), -1, PREG_SPLIT_NO_EMPTY);
  306. foreach ($exts as $ext) {
  307. if (preg_match("/\.$ext$/i", $filename)) return $_type;
  308. }
  309. }
  310. return $type;
  311. }
  312. // アップロードフォームの出力
  313. function attach_form($page)
  314. {
  315. global $script, $vars, $_attach_messages;
  316. $r_page = rawurlencode($page);
  317. $s_page = htmlsc($page);
  318. $navi = <<<EOD
  319. <span class="small">
  320. [<a href="$script?plugin=attach&amp;pcmd=list&amp;refer=$r_page">{$_attach_messages['msg_list']}</a>]
  321. [<a href="$script?plugin=attach&amp;pcmd=list">{$_attach_messages['msg_listall']}</a>]
  322. </span><br />
  323. EOD;
  324. if (! ini_get('file_uploads')) return '#attach(): file_uploads disabled<br />' . $navi;
  325. if (! is_page($page)) return '#attach(): No such page<br />' . $navi;
  326. $maxsize = PLUGIN_ATTACH_MAX_FILESIZE;
  327. $msg_maxsize = sprintf($_attach_messages['msg_maxsize'], number_format($maxsize/1024) . 'KB');
  328. $pass = '';
  329. if (PLUGIN_ATTACH_PASSWORD_REQUIRE || PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY) {
  330. $title = $_attach_messages[PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY ? 'msg_adminpass' : 'msg_password'];
  331. $pass = '<br />' . $title . ': <input type="password" name="pass" size="8" />';
  332. }
  333. return <<<EOD
  334. <form enctype="multipart/form-data" action="$script" method="post">
  335. <div>
  336. <input type="hidden" name="plugin" value="attach" />
  337. <input type="hidden" name="pcmd" value="post" />
  338. <input type="hidden" name="refer" value="$s_page" />
  339. <input type="hidden" name="max_file_size" value="$maxsize" />
  340. $navi
  341. <span class="small">
  342. $msg_maxsize
  343. </span><br />
  344. <label for="_p_attach_file">{$_attach_messages['msg_file']}:</label> <input type="file" name="attach_file" id="_p_attach_file" />
  345. $pass
  346. <input type="submit" value="{$_attach_messages['btn_upload']}" />
  347. </div>
  348. </form>
  349. EOD;
  350. }
  351. //-------- クラス
  352. // ファイル
  353. class AttachFile
  354. {
  355. var $page, $file, $age, $basename, $filename, $logname;
  356. var $time = 0;
  357. var $size = 0;
  358. var $time_str = '';
  359. var $size_str = '';
  360. var $status = array('count'=>array(0), 'age'=>'', 'pass'=>'', 'freeze'=>FALSE);
  361. function AttachFile($page, $file, $age = 0)
  362. {
  363. $this->page = $page;
  364. $this->file = preg_replace('#^.*/#','',$file);
  365. $this->age = is_numeric($age) ? $age : 0;
  366. $this->basename = UPLOAD_DIR . encode($page) . '_' . encode($this->file);
  367. $this->filename = $this->basename . ($age ? '.' . $age : '');
  368. $this->logname = $this->basename . '.log';
  369. $this->exist = file_exists($this->filename);
  370. $this->time = $this->exist ? filemtime($this->filename) - LOCALZONE : 0;
  371. }
  372. function gethash()
  373. {
  374. return $this->exist ? md5_file($this->filename) : '';
  375. }
  376. // ファイル情報取得
  377. function getstatus()
  378. {
  379. if (! $this->exist) return FALSE;
  380. // ログファイル取得
  381. if (file_exists($this->logname)) {
  382. $data = file($this->logname);
  383. foreach ($this->status as $key=>$value) {
  384. $this->status[$key] = chop(array_shift($data));
  385. }
  386. $this->status['count'] = explode(',', $this->status['count']);
  387. }
  388. $this->time_str = get_date('Y/m/d H:i:s', $this->time);
  389. $this->size = filesize($this->filename);
  390. $this->size_str = sprintf('%01.1f', round($this->size/1024, 1)) . 'KB';
  391. $this->type = attach_mime_content_type($this->filename);
  392. return TRUE;
  393. }
  394. // ステータス保存
  395. function putstatus()
  396. {
  397. $this->status['count'] = join(',', $this->status['count']);
  398. $fp = fopen($this->logname, 'wb') or
  399. die_message('cannot write ' . $this->logname);
  400. set_file_buffer($fp, 0);
  401. flock($fp, LOCK_EX);
  402. rewind($fp);
  403. foreach ($this->status as $key=>$value) {
  404. fwrite($fp, $value . "\n");
  405. }
  406. flock($fp, LOCK_UN);
  407. fclose($fp);
  408. }
  409. // 日付の比較関数
  410. function datecomp($a, $b) {
  411. return ($a->time == $b->time) ? 0 : (($a->time > $b->time) ? -1 : 1);
  412. }
  413. function toString($showicon, $showinfo)
  414. {
  415. global $script, $_attach_messages;
  416. $this->getstatus();
  417. $param = '&amp;file=' . rawurlencode($this->file) . '&amp;refer=' . rawurlencode($this->page) .
  418. ($this->age ? '&amp;age=' . $this->age : '');
  419. $title = $this->time_str . ' ' . $this->size_str;
  420. $label = ($showicon ? PLUGIN_ATTACH_FILE_ICON : '') . htmlsc($this->file);
  421. if ($this->age) {
  422. $label .= ' (backup No.' . $this->age . ')';
  423. }
  424. $info = $count = '';
  425. if ($showinfo) {
  426. $_title = str_replace('$1', rawurlencode($this->file), $_attach_messages['msg_info']);
  427. $info = "\n<span class=\"small\">[<a href=\"$script?plugin=attach&amp;pcmd=info$param\" title=\"$_title\">{$_attach_messages['btn_info']}</a>]</span>\n";
  428. $count = ($showicon && ! empty($this->status['count'][$this->age])) ?
  429. sprintf($_attach_messages['msg_count'], $this->status['count'][$this->age]) : '';
  430. }
  431. return "<a href=\"$script?plugin=attach&amp;pcmd=open$param\" title=\"$title\">$label</a>$count$info";
  432. }
  433. // 情報表示
  434. function info($err)
  435. {
  436. global $script, $_attach_messages;
  437. $r_page = rawurlencode($this->page);
  438. $s_page = htmlsc($this->page);
  439. $s_file = htmlsc($this->file);
  440. $s_err = ($err == '') ? '' : '<p style="font-weight:bold">' . $_attach_messages[$err] . '</p>';
  441. $msg_rename = '';
  442. if ($this->age) {
  443. $msg_freezed = '';
  444. $msg_delete = '<input type="radio" name="pcmd" id="_p_attach_delete" value="delete" />' .
  445. '<label for="_p_attach_delete">' . $_attach_messages['msg_delete'] .
  446. $_attach_messages['msg_require'] . '</label><br />';
  447. $msg_freeze = '';
  448. } else {
  449. if ($this->status['freeze']) {
  450. $msg_freezed = "<dd>{$_attach_messages['msg_isfreeze']}</dd>";
  451. $msg_delete = '';
  452. $msg_freeze = '<input type="radio" name="pcmd" id="_p_attach_unfreeze" value="unfreeze" />' .
  453. '<label for="_p_attach_unfreeze">' . $_attach_messages['msg_unfreeze'] .
  454. $_attach_messages['msg_require'] . '</label><br />';
  455. } else {
  456. $msg_freezed = '';
  457. $msg_delete = '<input type="radio" name="pcmd" id="_p_attach_delete" value="delete" />' .
  458. '<label for="_p_attach_delete">' . $_attach_messages['msg_delete'];
  459. if (PLUGIN_ATTACH_DELETE_ADMIN_ONLY || $this->age)
  460. $msg_delete .= $_attach_messages['msg_require'];
  461. $msg_delete .= '</label><br />';
  462. $msg_freeze = '<input type="radio" name="pcmd" id="_p_attach_freeze" value="freeze" />' .
  463. '<label for="_p_attach_freeze">' . $_attach_messages['msg_freeze'] .
  464. $_attach_messages['msg_require'] . '</label><br />';
  465. if (PLUGIN_ATTACH_RENAME_ENABLE) {
  466. $msg_rename = '<input type="radio" name="pcmd" id="_p_attach_rename" value="rename" />' .
  467. '<label for="_p_attach_rename">' . $_attach_messages['msg_rename'] .
  468. $_attach_messages['msg_require'] . '</label><br />&nbsp;&nbsp;&nbsp;&nbsp;' .
  469. '<label for="_p_attach_newname">' . $_attach_messages['msg_newname'] .
  470. ':</label> ' .
  471. '<input type="text" name="newname" id="_p_attach_newname" size="40" value="' .
  472. $this->file . '" /><br />';
  473. }
  474. }
  475. }
  476. $info = $this->toString(TRUE, FALSE);
  477. $hash = $this->gethash();
  478. $retval = array('msg'=>sprintf($_attach_messages['msg_info'], htmlsc($this->file)));
  479. $retval['body'] = <<< EOD
  480. <p class="small">
  481. [<a href="$script?plugin=attach&amp;pcmd=list&amp;refer=$r_page">{$_attach_messages['msg_list']}</a>]
  482. [<a href="$script?plugin=attach&amp;pcmd=list">{$_attach_messages['msg_listall']}</a>]
  483. </p>
  484. <dl>
  485. <dt>$info</dt>
  486. <dd>{$_attach_messages['msg_page']}:$s_page</dd>
  487. <dd>{$_attach_messages['msg_filename']}:{$this->filename}</dd>
  488. <dd>{$_attach_messages['msg_md5hash']}:$hash</dd>
  489. <dd>{$_attach_messages['msg_filesize']}:{$this->size_str} ({$this->size} bytes)</dd>
  490. <dd>Content-type:{$this->type}</dd>
  491. <dd>{$_attach_messages['msg_date']}:{$this->time_str}</dd>
  492. <dd>{$_attach_messages['msg_dlcount']}:{$this->status['count'][$this->age]}</dd>
  493. $msg_freezed
  494. </dl>
  495. <hr />
  496. $s_err
  497. <form action="$script" method="post">
  498. <div>
  499. <input type="hidden" name="plugin" value="attach" />
  500. <input type="hidden" name="refer" value="$s_page" />
  501. <input type="hidden" name="file" value="$s_file" />
  502. <input type="hidden" name="age" value="{$this->age}" />
  503. $msg_delete
  504. $msg_freeze
  505. $msg_rename
  506. <br />
  507. <label for="_p_attach_password">{$_attach_messages['msg_password']}:</label>
  508. <input type="password" name="pass" id="_p_attach_password" size="8" />
  509. <input type="submit" value="{$_attach_messages['btn_submit']}" />
  510. </div>
  511. </form>
  512. EOD;
  513. return $retval;
  514. }
  515. function delete($pass)
  516. {
  517. global $_attach_messages, $notify, $notify_subject;
  518. if ($this->status['freeze']) return attach_info('msg_isfreeze');
  519. if (! pkwk_login($pass)) {
  520. if (PLUGIN_ATTACH_DELETE_ADMIN_ONLY || $this->age) {
  521. return attach_info('err_adminpass');
  522. } else if (PLUGIN_ATTACH_PASSWORD_REQUIRE &&
  523. md5($pass) !== $this->status['pass']) {
  524. return attach_info('err_password');
  525. }
  526. }
  527. // バックアップ
  528. if ($this->age ||
  529. (PLUGIN_ATTACH_DELETE_ADMIN_ONLY && PLUGIN_ATTACH_DELETE_ADMIN_NOBACKUP)) {
  530. @unlink($this->filename);
  531. } else {
  532. do {
  533. $age = ++$this->status['age'];
  534. } while (file_exists($this->basename . '.' . $age));
  535. if (! rename($this->basename,$this->basename . '.' . $age)) {
  536. // 削除失敗 why?
  537. return array('msg'=>$_attach_messages['err_delete']);
  538. }
  539. $this->status['count'][$age] = $this->status['count'][0];
  540. $this->status['count'][0] = 0;
  541. $this->putstatus();
  542. }
  543. if (is_page($this->page))
  544. touch(get_filename($this->page));
  545. if ($notify) {
  546. $footer['ACTION'] = 'File deleted';
  547. $footer['FILENAME'] = & $this->file;
  548. $footer['PAGE'] = & $this->page;
  549. $footer['URI'] = get_script_uri() .
  550. '?' . rawurlencode($this->page);
  551. $footer['USER_AGENT'] = TRUE;
  552. $footer['REMOTE_ADDR'] = TRUE;
  553. pkwk_mail_notify($notify_subject, "\n", $footer) or
  554. die('pkwk_mail_notify(): Failed');
  555. }
  556. return array('msg'=>$_attach_messages['msg_deleted']);
  557. }
  558. function rename($pass, $newname)
  559. {
  560. global $_attach_messages, $notify, $notify_subject;
  561. if ($this->status['freeze']) return attach_info('msg_isfreeze');
  562. if (! pkwk_login($pass)) {
  563. if (PLUGIN_ATTACH_DELETE_ADMIN_ONLY || $this->age) {
  564. return attach_info('err_adminpass');
  565. } else if (PLUGIN_ATTACH_PASSWORD_REQUIRE &&
  566. md5($pass) !== $this->status['pass']) {
  567. return attach_info('err_password');
  568. }
  569. }
  570. $newbase = UPLOAD_DIR . encode($this->page) . '_' . encode($newname);
  571. if (file_exists($newbase)) {
  572. return array('msg'=>$_attach_messages['err_exists']);
  573. }
  574. if (! PLUGIN_ATTACH_RENAME_ENABLE || ! rename($this->basename, $newbase)) {
  575. return array('msg'=>$_attach_messages['err_rename']);
  576. }
  577. return array('msg'=>$_attach_messages['msg_renamed']);
  578. }
  579. function freeze($freeze, $pass)
  580. {
  581. global $_attach_messages;
  582. if (! pkwk_login($pass)) return attach_info('err_adminpass');
  583. $this->getstatus();
  584. $this->status['freeze'] = $freeze;
  585. $this->putstatus();
  586. return array('msg'=>$_attach_messages[$freeze ? 'msg_freezed' : 'msg_unfreezed']);
  587. }
  588. function open()
  589. {
  590. $this->getstatus();
  591. $this->status['count'][$this->age]++;
  592. $this->putstatus();
  593. $filename = $this->file;
  594. // Care for Japanese-character-included file name
  595. if (LANG == 'ja') {
  596. switch(UA_NAME . '/' . UA_PROFILE){
  597. case 'Opera/default':
  598. // Care for using _auto-encode-detecting_ function
  599. $filename = mb_convert_encoding($filename, 'UTF-8', 'auto');
  600. break;
  601. case 'MSIE/default':
  602. $filename = mb_convert_encoding($filename, 'SJIS', 'auto');
  603. break;
  604. }
  605. }
  606. $filename = htmlsc($filename);
  607. ini_set('default_charset', '');
  608. mb_http_output('pass');
  609. pkwk_common_headers();
  610. header('Content-Disposition: inline; filename="' . $filename . '"');
  611. header('Content-Length: ' . $this->size);
  612. header('Content-Type: ' . $this->type);
  613. @readfile($this->filename);
  614. exit;
  615. }
  616. }
  617. // ファイルコンテナ
  618. class AttachFiles
  619. {
  620. var $page;
  621. var $files = array();
  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. global $_title_cannotread;
  634. if (! check_readable($this->page, FALSE, FALSE)) {
  635. return str_replace('$1', make_pagelink($this->page), $_title_cannotread);
  636. } else if ($flat) {
  637. return $this->to_flat();
  638. }
  639. $ret = '';
  640. $files = array_keys($this->files);
  641. sort($files, SORT_STRING);
  642. foreach ($files as $file) {
  643. $_files = array();
  644. foreach (array_keys($this->files[$file]) as $age) {
  645. $_files[$age] = $this->files[$file][$age]->toString(FALSE, TRUE);
  646. }
  647. if (! isset($_files[0])) {
  648. $_files[0] = htmlsc($file);
  649. }
  650. ksort($_files, SORT_NUMERIC);
  651. $_file = $_files[0];
  652. unset($_files[0]);
  653. $ret .= " <li>$_file\n";
  654. if (count($_files)) {
  655. $ret .= "<ul>\n<li>" . join("</li>\n<li>", $_files) . "</li>\n</ul>\n";
  656. }
  657. $ret .= " </li>\n";
  658. }
  659. return make_pagelink($this->page) . "\n<ul>\n$ret</ul>\n";
  660. }
  661. // ファイル一覧を取得(inline)
  662. function to_flat()
  663. {
  664. $ret = '';
  665. $files = array();
  666. foreach (array_keys($this->files) as $file) {
  667. if (isset($this->files[$file][0])) {
  668. $files[$file] = & $this->files[$file][0];
  669. }
  670. }
  671. uasort($files, array('AttachFile', 'datecomp'));
  672. foreach (array_keys($files) as $file) {
  673. $ret .= $files[$file]->toString(TRUE, TRUE) . ' ';
  674. }
  675. return $ret;
  676. }
  677. }
  678. // ページコンテナ
  679. class AttachPages
  680. {
  681. var $pages = array();
  682. function AttachPages($page = '', $age = NULL)
  683. {
  684. $dir = opendir(UPLOAD_DIR) or
  685. die('directory ' . UPLOAD_DIR . ' is not exist or not readable.');
  686. $page_pattern = ($page == '') ? '(?:[0-9A-F]{2})+' : preg_quote(encode($page), '/');
  687. $age_pattern = ($age === NULL) ?
  688. '(?:\.([0-9]+))?' : ($age ? "\.($age)" : '');
  689. $pattern = "/^({$page_pattern})_((?:[0-9A-F]{2})+){$age_pattern}$/";
  690. $matches = array();
  691. while (($file = readdir($dir)) !== FALSE) {
  692. if (! preg_match($pattern, $file, $matches)) continue;
  693. $_page = decode($matches[1]);
  694. $_file = decode($matches[2]);
  695. $_age = isset($matches[3]) ? $matches[3] : 0;
  696. if (! isset($this->pages[$_page])) {
  697. $this->pages[$_page] = new AttachFiles($_page);
  698. }
  699. $this->pages[$_page]->add($_file, $_age);
  700. }
  701. closedir($dir);
  702. }
  703. function toString($page = '', $flat = FALSE)
  704. {
  705. if ($page != '') {
  706. if (! isset($this->pages[$page])) {
  707. return '';
  708. } else {
  709. return $this->pages[$page]->toString($flat);
  710. }
  711. }
  712. $ret = '';
  713. $pages = array_keys($this->pages);
  714. sort($pages, SORT_STRING);
  715. foreach ($pages as $page) {
  716. if (check_non_list($page)) continue;
  717. $ret .= '<li>' . $this->pages[$page]->toString($flat) . '</li>' . "\n";
  718. }
  719. return "\n" . '<ul>' . "\n" . $ret . '</ul>' . "\n";
  720. }
  721. }
  722. ?>