'image/gif', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg',
'png' => 'image/png', 'apng' => 'image/apng', 'bmp' => 'image/bmp', 'ico' => 'image/x-icon',
'wbmp'=> 'image/vnd.wap.wbmp', 'xcf' => 'image/x-xcf', 'webp' => 'image/webp',
'avif'=> 'image/avif', 'avifs' => 'image/avif',
'mp3' => 'audio/mpeg', 'm4a' => 'audio/mp4', 'au' => 'audio/basic', 'wav' => 'audio/x-wav',
'ogg' => 'audio/ogg', 'flac' => 'audio/x-flac', 'opus' => 'audio/opus',
'ogv' => 'video/ogg', 'mp4' => 'video/mp4', 'webm' => 'video/webm',
'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg', 'mkv' => 'video/x-matroska',
'm4v' => 'video/x-m4v', '3gp' => 'video/3gpp',
'mov' => 'video/quicktime', 'qt' => 'video/quicktime',
'wmf' => 'image/wmf', 'avi' => 'video/x-msvideo',
'zip' => 'application/zip', '7z' => 'application/x-7z-compressed',
'gz' => 'application/x-gzip', 'tgz' => 'application/x-gzip',
'rpm' => 'application/x-rpm',
'hqx' => 'application/mac-binhex40', 'sit' => 'application/x-stuffit',
'csv' => 'text/csv', 'xls' => 'application/vnd.ms-excel', 'mdb' => 'application/x-msaccess',
'doc' => 'application/msword', 'ppt' => 'application/vnd.ms-powerpoint',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'exe' => 'application/octet-stream',
'pdf' => 'application/pdf', 'psd' => 'image/vnd.adobe.photoshop',
'ps' => 'application/postscript', 'ai' => 'application/postscript',
'eps' => 'application/postscript',
'txt' => 'text/plain', 'rtf' => 'application/rtf',
'tex' => 'application/x-tex', 'dvi' => 'application/x-dvi',
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'odg' => 'application/vnd.oasis.opendocument.graphics',
'kml' => 'application/vnd.google-earth.kml+xml',
'kmz' => 'application/vnd.google-earth.kmz',
'vtt' => 'text/vtt',
));
# Array containing forbidden strings in a filename, array('.php', '.cgi')
SDV($UploadBlacklist, array());
SDV($UploadMaxSize,50000);
SDV($UploadPrefixQuota,0);
SDV($UploadDirQuota,0);
foreach($UploadExts as $k=>$v)
if (!isset($UploadExtSize[$k])) $UploadExtSize[$k]=$UploadMaxSize;
elseif ($UploadExtSize[$k] <= 0) unset($UploadExts[$k]);
SDV($UploadDir,'uploads');
SDV($UploadPermAdd,0444);
SDV($UploadPermSet,0);
SDV($UploadPrefixFmt,'/$Group');
SDV($UploadFileFmt,"$UploadDir$UploadPrefixFmt");
$v = preg_replace('#^/(.*/)#', '', $UploadDir);
SDV($UploadUrlFmt,preg_replace('#/[^/]*$#', "/$v", $PubDirUrl, 1));
SDV($LinkUploadCreateFmt, "\$LinkText Δ");
SDVA($ActionTitleFmt, array('upload' => '| $[Attach]'));
if ($EnablePostAuthorRequired)
SDV($EnableUploadAuthorRequired, $EnablePostAuthorRequired);
SDV($PageUploadFmt,array("
$[Attachments for] {\$FullName}
\$UploadResult
",
'wiki:$[{$SiteGroup}/UploadQuickReference]'));
XLSDV('en',array(
'ULby' => 'uploaded by',
'ULsuccess' => 'successfully uploaded',
'ULdroplabel' => 'Drop files to upload:',
'ULinvalidtoken' => 'Token invalid or missing.',
'ULmimemismatch' => 'extension \'$upext\' doesn\'t match file type \'$upmime\'',
'ULfileinfo' => 'EnableUploadMimeMatch requires PHP Fileinfo functions to be enabled, see https://php.net/fileinfo.installation',
'ULauthorrequired' => 'An author name is required.',
'ULbadname' => 'invalid attachment name',
'ULbadtype' => '\'$upext\' is not an allowed file extension',
'ULtoobig' => 'file is larger than maximum allowed by webserver',
'ULtoobigext' => 'file is larger than allowed maximum of $upmax
bytes for \'$upext\' files',
'ULpartial' => 'incomplete file received',
'ULnofile' => 'no file uploaded',
'ULexists' => 'file with that name already exists',
'ULpquota' => 'group quota exceeded',
'ULtquota' => 'upload quota exceeded'));
SDV($PageAttributes['passwdupload'],'$[Set new upload password:]');
SDV($DefaultPasswords['upload'],'@lock');
SDV($AuthCascade['upload'], 'read');
SDV($FmtPV['$PasswdUpload'], 'PasswdVar($pn, "upload")');
Markup('attachlist', 'directives',
'/\\(:attachlist\\s*(.*?):\\)/i',
"MarkupFmtUploadList");
function MarkupFmtUploadList($m) {
extract($GLOBALS["MarkupToHTML"]); # get $pagename
return Keep(''.FmtUploadList($pagename,$m[1]).'
');
}
SDV($GUIButtons['attach'], array(220, 'Attach:', '', '$[file.ext]',
'$GUIButtonDirUrlFmt/attach.gif"$[Attach file]"'));
SDV($LinkFunctions['Attach:'], 'LinkUpload');
SDV($IMap['Attach:'], '$1');
SDVA($HandleActions, array('upload' => 'HandleUpload',
'postupload' => 'HandlePostUpload',
'download' => 'HandleDownload'));
SDVA($HandleAuth, array('upload' => 'upload',
'download' => 'read'));
SDV($HandleAuth['postupload'], $HandleAuth['upload']);
SDV($UploadVerifyFunction, 'UploadVerifyBasic');
function MakeUploadName($pagename,$x) {
global $UploadNameChars, $MakeUploadNamePatterns;
SDV($UploadNameChars, "-\\w. ");
SDV($MakeUploadNamePatterns, array(
"/[^$UploadNameChars]/" => '',
'/(\\.[^.]*)$/' => 'cb_tolower',
'/^[^[:alnum:]_]+/' => '',
'/[^[:alnum:]_]+$/' => ''));
return PPRA($MakeUploadNamePatterns, MarkupRestore($x));
}
## This helper function returns the public URL for an attached file
function DownloadUrl($pagename, $path) {
global $FmtV, $UploadFileFmt,
$UploadUrlFmt, $UploadPrefixFmt, $EnableDirectDownload;
$path = MarkupRestore($path);
if (preg_match('!^(.*)/([^/]+)$!', $path, $match)) {
$pagename = MakePageName($pagename, $match[1]);
$path = $match[2];
}
$upname = MakeUploadName($pagename, $path);
$encname = rawurlencode($upname);
$filepath = FmtPageName("$UploadFileFmt/$upname", $pagename);
$FmtV['$PathUpload'] = $filepath;
$FmtV['$LinkUpload'] =
FmtPageName("\$PageUrl?action=upload&upname=$encname", $pagename);
$FmtV['$LinkDownload'] = PUE(FmtPageName(IsEnabled($EnableDirectDownload, 1)
? "$UploadUrlFmt$UploadPrefixFmt/$encname"
: "{\$PageUrl}?action=download&upname=$encname",
$pagename));
if (!file_exists($filepath)) return false;
return $FmtV['$LinkDownload'];
}
function LinkUpload($pagename, $imap, $path, $alt, $txt, $fmt=NULL) {
global $FmtV, $LinkUploadCreateFmt, $ImgExtPattern, $ImgDarkSuffix;
$FmtV['$LinkText'] = $txt;
$url = DownloadUrl($pagename, $path);
if ($url && $fmt && IsEnabled($ImgDarkSuffix) && substr($fmt,0,5)=='
"$ImgDarkSuffix$0");
$darkpath = PPRA($ra, $FmtV['$PathUpload']);
if (file_exists($darkpath)) {
$darkurl = PPRA($ra, $url);
$fmt = preg_replace('/^
1,'msg'=>$msg));
Abort($msg);
}
if ($cache) PCache($pn_upload,$page);
return true;
}
function UploadSetVars($pagename) {
global $Author, $FmtV, $UploadExtMax, $EnableReadOnly,
$EnablePostAuthorRequired, $EnableUploadAuthorRequired;
$FmtV['$UploadName'] = MakeUploadName($pagename,@$_REQUEST['upname']);
$FmtV['$UploadAuthor'] = PHSC($Author, ENT_QUOTES);
$upresult = PHSC(@$_REQUEST['upresult']);
$uprname = PHSC(@$_REQUEST['uprname']);
$FmtV['$upext'] = PHSC(@$_REQUEST['upext']);
$FmtV['$upmax'] = PHSC(@$_REQUEST['upmax']);
$FmtV['$upmime'] = PHSC(@$_REQUEST['upmime']);
pmtoken();
$FmtV['$UploadResult'] = ($upresult) ?
FmtPageName("$uprname: $[UL$upresult]",$pagename) :
(@$EnableReadOnly ? XL('Cannot modify site -- $EnableReadOnly is set'): '');
$FmtV['$UploadAuthorRequired'] = @$EnableUploadAuthorRequired ?
'required="required"' : '';
}
function HandleUpload($pagename, $auth = 'upload') {
global $HandleUploadFmt,$PageStartFmt,$PageEndFmt,$PageUploadFmt;
UploadAuth($pagename, $auth, 1);
UploadSetVars($pagename);
SDV($HandleUploadFmt,array(&$PageStartFmt,&$PageUploadFmt,&$PageEndFmt));
PrintFmt($pagename,$HandleUploadFmt);
}
function HandleDownload($pagename, $auth = 'read') {
global $UploadFileFmt;
UploadAuth($pagename, $auth);
$upname = MakeUploadName($pagename, @$_REQUEST['upname']);
$filepath = FmtPageName("$UploadFileFmt/$upname", $pagename);
return ServeDownload($filepath, $upname);
}
function ServeDownload($filepath, $upname = null) {
global $UploadExts, $DownloadDisposition, $EnableIMSCaching, $EnableDownloadRanges;
SDV($DownloadDisposition, "inline");
if (is_null($upname)) $upname = preg_replace('!^.*/!', '', $filepath);
if (!$upname || !file_exists($filepath)) {
header("HTTP/1.0 404 Not Found");
Abort("?requested file not found");
exit();
}
if (IsEnabled($EnableIMSCaching, 0)) {
header('Cache-Control: private');
header('Expires: ');
$filelastmod = gmdate('D, d M Y H:i:s \G\M\T', filemtime($filepath));
if (@$_SERVER['HTTP_IF_MODIFIED_SINCE'] == $filelastmod)
{ header("HTTP/1.0 304 Not Modified"); exit(); }
header("Last-Modified: $filelastmod");
}
preg_match('/\\.([^.]+)$/',strtolower($filepath),$match);
if ($UploadExts[@$match[1]])
header("Content-Type: {$UploadExts[@$match[1]]}");
$fsize = $length = filesize($filepath);
$end = $fsize-1;
$ranges = IsEnabled($EnableDownloadRanges, 1);
if ($ranges) header("Accept-Ranges: bytes");
if ($ranges && @$_SERVER['HTTP_RANGE']) {
if (! preg_match('/^\\s*bytes\\s*=\\s*(\\d*)\\s*-\\s*(\\d*)\\s*$/i', $_SERVER['HTTP_RANGE'], $r)
|| intval($r[1])>$end
|| intval($r[2])>$end
|| ($r[2] && intval($r[1])>intval($r[2]))
) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes 0-$end/$fsize");
exit;
}
if ($r[2]=='') $r[2] = $end;
if ($r[1]=='') $r[1] = $end - $r[2];
$length = $r[2] - $r[1] + 1;
header('HTTP/1.1 206 Partial Content');
header("Content-Range: bytes $r[1]-$r[2]/$fsize");
}
else {
$r = array( null, 0, $end);
}
header("Content-Length: $length");
header("Content-Disposition: $DownloadDisposition; filename=\"$upname\"");
$fp = fopen($filepath, "rb");
if ($fp) {
$bf = 8192;
fseek($fp, $r[1]);
while (!feof($fp) && ($pos = ftell($fp)) <= $r[2]) {
$bf = max($bf, $r[2] - $pos + 1);
echo fread($fp, $bf);
flush();
}
fclose($fp);
}
exit();
}
function HandlePostUpload($pagename, $auth = 'upload') {
global $UploadVerifyFunction, $UploadFileFmt, $LastModFile, $Now,
$EnableUploadVersions, $EnableRecentUploads, $RecentUploadsFmt,
$FmtV, $NotifyItemUploadFmt, $NotifyItemFmt, $IsUploadPosted,
$UploadRedirectFunction, $UploadPermAdd, $UploadPermSet,
$EnableReadOnly;
if (IsEnabled($EnableReadOnly, 0))
Abort('Cannot modify site -- $EnableReadOnly is set', 'readonly');
UploadAuth($pagename, $auth);
$uploadfile = @$_FILES['uploadfile'];
$upname = @$_REQUEST['upname'];
if ($upname=='') $upname=strval(@$uploadfile['name']);
$upname = MakeUploadName($pagename,$upname);
if (!function_exists($UploadVerifyFunction))
Abort('?no UploadVerifyFunction available');
$filepath = FmtPageName("$UploadFileFmt/$upname",$pagename);
$result = $UploadVerifyFunction($pagename,$uploadfile,$filepath,$upname);
if ($result=='') {
$filedir = preg_replace('#/[^/]*$#','',$filepath);
mkdirp($filedir);
if (IsEnabled($EnableUploadVersions, 0))
@rename($filepath, "$filepath,$Now");
if (!move_uploaded_file($uploadfile['tmp_name'],$filepath))
{ Abort("?cannot move uploaded file to $filepath"); return; }
fixperms($filepath, $UploadPermAdd, $UploadPermSet);
if ($LastModFile) { touch($LastModFile); fixperms($LastModFile); }
$result = "upresult=success";
$FmtV['$filepath'] = $filepath;
$FmtV['$upname'] = $upname;
$FmtV['$upsize'] = $uploadfile['size'];
$FmtV['$upurl'] = DownloadUrl($pagename, $upname);
if (IsEnabled($EnableRecentUploads, 0)) {
SDV($RecentUploadsFmt, array( # not SDVA
'$SiteGroup.AllRecentChanges' =>
'* [[(Attach:){$FullName}/$upname]] . . . $CurrentLocalTime'
. ' $[ULby] $AuthorLink ($upsize $[bytes])'
));
}
if (IsEnabled($RecentUploadsFmt, 0)) {
Lock(2);
PostRecentChanges($pagename, '', '', $RecentUploadsFmt);
Lock(0);
}
if (IsEnabled($NotifyItemUploadFmt, 0) && function_exists('NotifyUpdate')) {
$NotifyItemFmt = $NotifyItemUploadFmt;
$IsUploadPosted = 1;
register_shutdown_function('NotifyUpdate', $pagename, getcwd());
}
}
$FmtV['$upresult'] = $result;
if (@$_POST['pmdrop']) {
$out = array('uprname'=>$upname);
preg_match('/^upresult=([a-zA-Z]+)(.*)$/', $result, $m);
$out['msg'] = "$upname: ".FmtPageName(XL("UL{$m[1]}"), $pagename);
if ($m[1] != 'success') $out['error'] = 1;
else $out['href'] = $FmtV['$upurl'];
PrintJSON($pagename, $out);
exit;
}
SDV($UploadRedirectFunction, 'Redirect');
$UploadRedirectFunction($pagename,"{\$PageUrl}?action=upload&uprname=$upname&$result");
}
function UploadVerifyBasic($pagename,$uploadfile,&$filepath,&$upname=null) {
global $EnableUploadOverwrite, $UploadExtSize, $UploadPrefixQuota,
$EnableUploadVersions, $UploadDirQuota, $UploadDir, $UploadBlacklist,
$Author, $EnablePostAuthorRequired, $EnableUploadAuthorRequired,
$UploadExts, $EnableUploadMimeMatch, $Now, $FmtV;
if (! pmtoken(1)) {
return 'upresult=invalidtoken';
}
if (!is_uploaded_file(strval(@$uploadfile['tmp_name']))) return 'upresult=nofile';
if (IsEnabled($EnableUploadAuthorRequired,0) && !$Author)
return 'upresult=authorrequired';
if (count($UploadBlacklist)) {
if (is_null($upname)) { # call from old recipe
$tmp = explode("/", $filepath);
$upname = strtolower(end($tmp));
}
foreach($UploadBlacklist as $needle) {
if (stripos($upname, $needle)!==false) return 'upresult=badname';
}
}
if (IsEnabled($EnableUploadVersions, 0)==2 && file_exists($filepath)) {
if (preg_match('!^(.*/([^/]+))(\\.[a-z0-9]+)$!i', $filepath, $m)) {
$stamp36 = base_convert($Now, 10, 36);
$filepath = "{$m[1]}-$stamp36{$m[3]}";
$upname = "{$m[2]}-$stamp36{$m[3]}";
}
}
if (!$EnableUploadOverwrite && file_exists($filepath))
return 'upresult=exists';
preg_match('/\\.([^.\\/]+)$/',$filepath,$match); $ext=@$match[1];
$FmtV['$upext'] = $ext;
if (!isset($UploadExtSize[$ext]))
return "upresult=badtype&upext=$ext";
$maxsize = $UploadExtSize[$ext];
$FmtV['$upmax'] = $maxsize;
if ($maxsize<=0) return "upresult=badtype&upext=$ext";
if (intval(@$uploadfile['size'])>$maxsize)
return "upresult=toobigext&upext=$ext&upmax=$maxsize";
switch (@$uploadfile['error']) {
case 1: return 'upresult=toobig';
case 2: return 'upresult=toobig';
case 3: return 'upresult=partial';
case 4: return 'upresult=nofile';
}
if (IsEnabled($EnableUploadMimeMatch,0)) {
if (! function_exists('mime_content_type'))
return "upresult=fileinfo";
$mime = mime_content_type($uploadfile['tmp_name']);
$FmtV['$upmime'] = $mime;
if ($mime != $UploadExts[$ext]) {
if (!is_array($EnableUploadMimeMatch)
|| !isset($EnableUploadMimeMatch[$ext])
|| !preg_match($EnableUploadMimeMatch[$ext], $mime)) {
return "upresult=mimemismatch&upext=$ext&upmime=$mime";
}
}
}
$filedir = preg_replace('#/[^/]*$#','',$filepath);
if ($UploadPrefixQuota &&
(dirsize($filedir)-@filesize($filepath)+$uploadfile['size']) >
$UploadPrefixQuota) return 'upresult=pquota';
if ($UploadDirQuota &&
(dirsize($UploadDir)-@filesize($filepath)+$uploadfile['size']) >
$UploadDirQuota) return 'upresult=tquota';
return '';
}
function dirsize($dir) {
$size = 0;
$dirp = @opendir($dir);
if (!$dirp) return 0;
while (($file=readdir($dirp)) !== false) {
if ($file[0]=='.') continue;
if (is_dir("$dir/$file")) $size+=dirsize("$dir/$file");
else $size+=filesize("$dir/$file");
}
closedir($dirp);
return $size;
}
function FmtUploadList($pagename, $args) {
global $UploadDir, $UploadPrefixFmt, $UploadUrlFmt, $EnableUploadOverwrite,
$TimeFmt, $EnableDirectDownload, $IMapLinkFmt, $UrlLinkFmt, $FmtV;
$opt = ParseArgs($args);
if (@$opt[''][0]) $pagename = MakePageName($pagename, $opt[''][0]);
$matchfnames = '';
if (@$opt['names'] ) $matchfnames = $opt['names'];
if (@$opt['ext'])
$matchfnames .= FixGlob($opt['ext'], '$1*.$2');
$uploaddir = FmtPageName("$UploadDir$UploadPrefixFmt", $pagename);
$uploadurl = FmtPageName(IsEnabled($EnableDirectDownload, 1)
? "$UploadUrlFmt$UploadPrefixFmt/"
: "\$PageUrl?action=download&upname=",
$pagename);
$dirp = @opendir($uploaddir);
if (!$dirp) return '';
$filelist = array();
while (($file=readdir($dirp)) !== false) {
if ($file[0] == '.') continue;
if ($matchfnames && ! MatchNames($file, $matchfnames)) continue;
$filelist[$file] = rawurlencode($file);
}
closedir($dirp);
$out = array();
natcasesort($filelist);
$overwrite = '';
$fmt = IsEnabled($IMapLinkFmt['Attach:'], $UrlLinkFmt);
foreach($filelist as $file=>$encfile) {
$FmtV['$LinkUrl'] = PUE("$uploadurl$encfile");
$FmtV['$LinkText'] = $file;
$FmtV['$LinkUpload'] =
FmtPageName("\$PageUrl?action=upload&upname=$encfile", $pagename);
$stat = stat("$uploaddir/$file");
if ($EnableUploadOverwrite)
$overwrite = FmtPageName(" Δ",
$pagename);
$lnk = FmtPageName($fmt, $pagename);
$out[] = " $lnk$overwrite ... ".
number_format($stat['size']) . " bytes ... " .
PSFT($TimeFmt, $stat['mtime']) . "";
}
return implode("\n",$out);
}
# this adds (:if [!]attachments filepattern pagename:) to the markup
$Conditions['attachments'] = "AttachExist(\$pagename, \$condparm)";
function AttachExist($pagename, $condparm='*') {
global $UploadFileFmt;
@list($fpat, $pn) = explode(' ', $condparm, 2);
$pn = ($pn > '') ? MakePageName($pagename, $pn) : $pagename;
$uploaddir = FmtPageName($UploadFileFmt, $pn);
$flist = array();
$dirp = @opendir($uploaddir);
if ($dirp) {
while (($file = readdir($dirp)) !== false)
if ($file[0] != '.') $flist[] = $file;
closedir($dirp);
$flist = MatchNames($flist, $fpat);
}
return count($flist);
}