upload.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <?php if (!defined('PmWiki')) exit();
  2. /* Copyright 2004-2006 Patrick R. Michaud (pmichaud@pobox.com)
  3. This file is part of PmWiki; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published
  5. by the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version. See pmwiki.php for full details.
  7. This script adds upload capabilities to PmWiki. Uploads can be
  8. enabled by setting
  9. $EnableUpload = 1;
  10. in config.php. In addition, an upload password must be set, as
  11. the default is to lock uploads. In some configurations it may also
  12. be necessary to set values for $UploadDir and $UploadUrlFmt,
  13. especially if any form of URL rewriting is being performed.
  14. See the PmWiki.UploadsAdmin page for more information.
  15. */
  16. ## $EnableUploadOverwrite determines if we allow previously uploaded
  17. ## files to be overwritten.
  18. SDV($EnableUploadOverwrite,1);
  19. ## $UploadExts contains the list of file extensions we're willing to
  20. ## accept, along with the Content-Type: value appropriate for each.
  21. SDVA($UploadExts,array(
  22. 'gif' => 'image/gif', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg',
  23. 'png' => 'image/png', 'bmp' => 'image/bmp', 'ico' => 'image/x-icon',
  24. 'wbmp' => 'image/vnd.wap.wbmp',
  25. 'mp3' => 'audio/mpeg', 'au' => 'audio/basic', 'wav' => 'audio/x-wav',
  26. 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg',
  27. 'mov' => 'video/quicktime', 'qt' => 'video/quicktime',
  28. 'wmf' => 'text/plain', 'avi' => 'video/x-msvideo',
  29. 'zip' => 'application/zip',
  30. 'gz' => 'application/x-gzip', 'tgz' => 'application/x-gzip',
  31. 'rpm' => 'application/x-rpm',
  32. 'hqx' => 'application/mac-binhex40', 'sit' => 'application/x-stuffit',
  33. 'doc' => 'application/msword', 'ppt' => 'application/vnd.ms-powerpoint',
  34. 'xls' => 'application/vnd.ms-excel', 'mdb' => 'text/plain',
  35. 'exe' => 'application/octet-stream',
  36. 'pdf' => 'application/pdf', 'psd' => 'text/plain',
  37. 'ps' => 'application/postscript', 'ai' => 'application/postscript',
  38. 'eps' => 'application/postscript',
  39. 'htm' => 'text/html', 'html' => 'text/html', 'css' => 'text/css',
  40. 'fla' => 'application/x-shockwave-flash',
  41. 'swf' => 'application/x-shockwave-flash',
  42. 'txt' => 'text/plain', 'rtf' => 'application/rtf',
  43. 'tex' => 'application/x-tex', 'dvi' => 'application/x-dvi',
  44. '' => 'text/plain'));
  45. SDV($UploadMaxSize,50000);
  46. SDV($UploadPrefixQuota,0);
  47. SDV($UploadDirQuota,0);
  48. foreach($UploadExts as $k=>$v)
  49. if (!isset($UploadExtSize[$k])) $UploadExtSize[$k]=$UploadMaxSize;
  50. SDV($UploadDir,'uploads');
  51. SDV($UploadPrefixFmt,'/$Group');
  52. SDV($UploadFileFmt,"$UploadDir$UploadPrefixFmt");
  53. $v = preg_replace('#^/(.*/)#', '', $UploadDir);
  54. SDV($UploadUrlFmt,preg_replace('#/[^/]*$#', "/$v", $PubDirUrl, 1));
  55. SDV($LinkUploadCreateFmt, "<a class='createlinktext' href='\$LinkUpload'>\$LinkText</a><a class='createlink' href='\$LinkUpload'>&nbsp;&Delta;</a>");
  56. SDV($PageUploadFmt,array("
  57. <div id='wikiupload'>
  58. <h2 class='wikiaction'>$[Attachments for] {\$FullName}</h2>
  59. <h3>\$UploadResult</h3>
  60. <form enctype='multipart/form-data' action='{\$PageUrl}' method='post'>
  61. <input type='hidden' name='n' value='{\$FullName}' />
  62. <input type='hidden' name='action' value='postupload' />
  63. <table border='0'>
  64. <tr><td align='right'>$[File to upload:]</td><td><input
  65. name='uploadfile' type='file' /></td></tr>
  66. <tr><td align='right'>$[Name attachment as:]</td>
  67. <td><input type='text' name='upname' value='\$UploadName' /><input
  68. type='submit' value=' $[Upload] ' /><br />
  69. </td></tr></table></form></div>",
  70. 'wiki:$[{$SiteGroup}/UploadQuickReference]'));
  71. XLSDV('en',array(
  72. 'ULsuccess' => 'successfully uploaded',
  73. 'ULbadname' => 'invalid attachment name',
  74. 'ULbadtype' => '\'$upext\' is not an allowed file extension',
  75. 'ULtoobig' => 'file is larger than maximum allowed by webserver',
  76. 'ULtoobigext' => 'file is larger than allowed maximum of $upmax
  77. bytes for \'$upext\' files',
  78. 'ULpartial' => 'incomplete file received',
  79. 'ULnofile' => 'no file uploaded',
  80. 'ULexists' => 'file with that name already exists',
  81. 'ULpquota' => 'group quota exceeded',
  82. 'ULtquota' => 'upload quota exceeded'));
  83. SDV($PageAttributes['passwdupload'],'$[Set new upload password:]');
  84. SDV($DefaultPasswords['upload'],'*');
  85. SDV($AuthCascade['upload'], 'read');
  86. Markup('attachlist', 'directives',
  87. '/\\(:attachlist\\s*(.*?):\\)/ei',
  88. "Keep('<ul>'.FmtUploadList('$pagename',PSS('$1')).'</ul>')");
  89. SDV($GUIButtons['attach'], array(220, 'Attach:', '', '$[file.ext]',
  90. '$GUIButtonDirUrlFmt/attach.gif"$[Attach file]"'));
  91. SDV($LinkFunctions['Attach:'], 'LinkUpload');
  92. SDV($IMap['Attach:'], '$1');
  93. SDVA($HandleActions, array('upload' => 'HandleUpload',
  94. 'postupload' => 'HandlePostUpload',
  95. 'download' => 'HandleDownload'));
  96. SDVA($HandleAuth, array('upload' => 'upload',
  97. 'postupload' => 'upload',
  98. 'download' => 'read'));
  99. SDV($UploadVerifyFunction, 'UploadVerifyBasic');
  100. function MakeUploadName($pagename,$x) {
  101. global $UploadNameChars;
  102. SDV($UploadNameChars, "-\\w. ");
  103. $x = preg_replace("/[^$UploadNameChars]/", '', $x);
  104. $x = preg_replace('/\\.[^.]*$/e', "strtolower('$0')", $x);
  105. $x = preg_replace('/^[^[:alnum:]]+/', '', $x);
  106. return preg_replace('/[^[:alnum:]_]+$/', '', $x);
  107. }
  108. function LinkUpload($pagename, $imap, $path, $title, $txt, $fmt=NULL) {
  109. global $FmtV, $UploadFileFmt, $LinkUploadCreateFmt, $UploadUrlFmt,
  110. $UploadPrefixFmt, $EnableDirectDownload;
  111. if (preg_match('!^(.*)/([^/]+)$!', $path, $match)) {
  112. $pagename = MakePageName($pagename, $match[1]);
  113. $path = $match[2];
  114. }
  115. $upname = MakeUploadName($pagename, $path);
  116. $filepath = FmtPageName("$UploadFileFmt/$upname", $pagename);
  117. $FmtV['$LinkUpload'] =
  118. FmtPageName("\$PageUrl?action=upload&amp;upname=$upname", $pagename);
  119. $FmtV['$LinkText'] = $txt;
  120. if (!file_exists($filepath))
  121. return FmtPageName($LinkUploadCreateFmt, $pagename);
  122. $path = PUE(FmtPageName(IsEnabled($EnableDirectDownload, 1)
  123. ? "$UploadUrlFmt$UploadPrefixFmt/$upname"
  124. : "{\$PageUrl}?action=download&amp;upname=$upname",
  125. $pagename));
  126. return LinkIMap($pagename, $imap, $path, $title, $txt, $fmt);
  127. }
  128. function HandleUpload($pagename, $auth = 'upload') {
  129. global $FmtV,$UploadExtMax,
  130. $HandleUploadFmt,$PageStartFmt,$PageEndFmt,$PageUploadFmt;
  131. $page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
  132. if (!$page) Abort("?cannot upload to $pagename");
  133. PCache($pagename,$page);
  134. $FmtV['$UploadName'] = MakeUploadName($pagename,@$_REQUEST['upname']);
  135. $upresult = htmlspecialchars(@$_REQUEST['upresult']);
  136. $uprname = htmlspecialchars(@$_REQUEST['uprname']);
  137. $FmtV['$upext'] = htmlspecialchars(@$_REQUEST['upext']);
  138. $FmtV['$upmax'] = htmlspecialchars(@$_REQUEST['upmax']);
  139. $FmtV['$UploadResult'] = ($upresult) ?
  140. FmtPageName("<i>$uprname</i>: $[UL$upresult]",$pagename) : '';
  141. SDV($HandleUploadFmt,array(&$PageStartFmt,&$PageUploadFmt,&$PageEndFmt));
  142. PrintFmt($pagename,$HandleUploadFmt);
  143. }
  144. function HandleDownload($pagename, $auth = 'read') {
  145. global $UploadFileFmt, $UploadExts, $DownloadDisposition;
  146. SDV($DownloadDisposition, "inline");
  147. $page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
  148. if (!$page) Abort("?cannot read $pagename");
  149. $upname = MakeUploadName($pagename, @$_REQUEST['upname']);
  150. $filepath = FmtPageName("$UploadFileFmt/$upname", $pagename);
  151. if (!$upname || !file_exists($filepath)) {
  152. header("HTTP/1.0 404 Not Found");
  153. Abort("?requested file not found");
  154. exit();
  155. }
  156. preg_match('/\\.([^.]+)$/',$filepath,$match);
  157. if ($UploadExts[@$match[1]])
  158. header("Content-Type: {$UploadExts[@$match[1]]}");
  159. header("Content-Length: ".filesize($filepath));
  160. header("Content-disposition: $DownloadDisposition; filename=$upname");
  161. $fp = fopen($filepath, "r");
  162. if ($fp) {
  163. while (!feof($fp)) echo fread($fp, 4096);
  164. fclose($fp);
  165. }
  166. exit();
  167. }
  168. function HandlePostUpload($pagename, $auth = 'upload') {
  169. global $UploadVerifyFunction, $UploadFileFmt, $LastModFile,
  170. $EnableUploadVersions, $Now;
  171. $page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
  172. if (!$page) Abort("?cannot upload to $pagename");
  173. $uploadfile = $_FILES['uploadfile'];
  174. $upname = $_REQUEST['upname'];
  175. if ($upname=='') $upname=$uploadfile['name'];
  176. $upname = MakeUploadName($pagename,$upname);
  177. if (!function_exists($UploadVerifyFunction))
  178. Abort('?no UploadVerifyFunction available');
  179. $filepath = FmtPageName("$UploadFileFmt/$upname",$pagename);
  180. $result = $UploadVerifyFunction($pagename,$uploadfile,$filepath);
  181. if ($result=='') {
  182. $filedir = preg_replace('#/[^/]*$#','',$filepath);
  183. mkdirp($filedir);
  184. if (IsEnabled($EnableUploadVersions, 0))
  185. @rename($filepath, "$filepath,$Now");
  186. if (!move_uploaded_file($uploadfile['tmp_name'],$filepath))
  187. { Abort("?cannot move uploaded file to $filepath"); return; }
  188. fixperms($filepath,0444);
  189. if ($LastModFile) { touch($LastModFile); fixperms($LastModFile); }
  190. $result = "upresult=success";
  191. }
  192. Redirect($pagename,"{\$PageUrl}?action=upload&uprname=$upname&$result");
  193. }
  194. function UploadVerifyBasic($pagename,$uploadfile,$filepath) {
  195. global $EnableUploadOverwrite,$UploadExtSize,$UploadPrefixQuota,
  196. $UploadDirQuota,$UploadDir;
  197. if (!$EnableUploadOverwrite && file_exists($filepath))
  198. return 'upresult=exists';
  199. preg_match('/\\.([^.\\/]+)$/',$filepath,$match); $ext=@$match[1];
  200. $maxsize = $UploadExtSize[$ext];
  201. if ($maxsize<=0) return "upresult=badtype&upext=$ext";
  202. if ($uploadfile['size']>$maxsize)
  203. return "upresult=toobigext&upext=$ext&upmax=$maxsize";
  204. switch (@$uploadfile['error']) {
  205. case 1: return 'upresult=toobig';
  206. case 2: return 'upresult=toobig';
  207. case 3: return 'upresult=partial';
  208. case 4: return 'upresult=nofile';
  209. }
  210. if (!is_uploaded_file($uploadfile['tmp_name'])) return 'upresult=nofile';
  211. $filedir = preg_replace('#/[^/]*$#','',$filepath);
  212. if ($UploadPrefixQuota &&
  213. (dirsize($filedir)-@filesize($filepath)+$uploadfile['size']) >
  214. $UploadPrefixQuota) return 'upresult=pquota';
  215. if ($UploadDirQuota &&
  216. (dirsize($UploadDir)-@filesize($filepath)+$uploadfile['size']) >
  217. $UploadDirQuota) return 'upresult=tquota';
  218. return '';
  219. }
  220. function dirsize($dir) {
  221. $size = 0;
  222. $dirp = @opendir($dir);
  223. if (!$dirp) return 0;
  224. while (($file=readdir($dirp)) !== false) {
  225. if ($file[0]=='.') continue;
  226. if (is_dir("$dir/$file")) $size+=dirsize("$dir/$file");
  227. else $size+=filesize("$dir/$file");
  228. }
  229. closedir($dirp);
  230. return $size;
  231. }
  232. function FmtUploadList($pagename, $args) {
  233. global $UploadDir, $UploadPrefixFmt, $UploadUrlFmt, $EnableUploadOverwrite,
  234. $TimeFmt, $EnableDirectDownload;
  235. $opt = ParseArgs($args);
  236. if (@$opt[''][0]) $pagename = MakePageName($pagename, $opt[''][0]);
  237. if (@$opt['ext'])
  238. $matchext = '/\\.('
  239. . implode('|', preg_split('/\\W+/', $opt['ext'], -1, PREG_SPLIT_NO_EMPTY))
  240. . ')$/i';
  241. $uploaddir = FmtPageName("$UploadDir$UploadPrefixFmt", $pagename);
  242. $uploadurl = FmtPageName(IsEnabled($EnableDirectDownload, 1)
  243. ? "$UploadUrlFmt$UploadPrefixFmt/"
  244. : "\$PageUrl?action=download&amp;upname=",
  245. $pagename);
  246. $dirp = @opendir($uploaddir);
  247. if (!$dirp) return '';
  248. $filelist = array();
  249. while (($file=readdir($dirp)) !== false) {
  250. if ($file{0} == '.') continue;
  251. if (@$matchext && !preg_match(@$matchext, $file)) continue;
  252. $filelist[$file] = $file;
  253. }
  254. closedir($dirp);
  255. $out = array();
  256. natcasesort($filelist);
  257. $overwrite = '';
  258. foreach($filelist as $file=>$x) {
  259. $name = PUE("$uploadurl$file");
  260. $stat = stat("$uploaddir/$file");
  261. if ($EnableUploadOverwrite)
  262. $overwrite = FmtPageName("<a class='createlink'
  263. href='\$PageUrl?action=upload&amp;upname=$file'>&nbsp;&Delta;</a>",
  264. $pagename);
  265. $out[] = "<li> <a href='$name'>$file</a>$overwrite ... ".
  266. number_format($stat['size']) . " bytes ... " .
  267. strftime($TimeFmt, $stat['mtime']) . "</li>";
  268. }
  269. return implode("\n",$out);
  270. }
  271. # this adds (:if [!]attachments:) to the markup
  272. $Conditions['attachments'] = "AttachExist(\$pagename)";
  273. function AttachExist($pagename) {
  274. global $UploadDir, $UploadPrefixFmt;
  275. $uploaddir = FmtPageName("$UploadDir$UploadPrefixFmt", $pagename);
  276. $count = 0;
  277. $dirp = @opendir($uploaddir);
  278. if ($dirp) {
  279. while (($file = readdir($dirp)) !== false)
  280. if ($file{0} != '.') $count++;
  281. closedir($dirp);
  282. }
  283. return $count;
  284. }