3 * Copyright 2003,2004,2007 $ThePhpWikiProgrammingTeam
4 * Copyright 2008-2009 Marc-Etienne Vargenau, Alcatel-Lucent
6 * This file is part of PhpWiki.
8 * PhpWiki is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * PhpWiki is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * UpLoad: Allow Administrator to upload files to a special directory,
25 * which should preferably be added to the InterWikiMap
27 * Author: NathanGass <gass@iogram.ch>
28 * Changes: ReiniUrban <rurban@x-ray.at>,
29 * qubit <rtryon@dartmouth.edu>
30 * Marc-Etienne Vargenau, Alcatel-Lucent
33 class WikiPlugin_UpLoad
36 public $allowed_extensions;
37 public $disallowed_extensions;
38 // TODO: use PagePerms instead
39 public $only_authenticated = true; // allow only authenticated users may upload.
41 function getDescription()
43 return _("Upload files to the local InterWiki [[Upload:filename]]");
46 function getDefaultArguments()
48 return array('logfile' => 'phpwiki-upload.log',
49 // add a link of the fresh file automatically to the
50 // end of the page (or current page)
52 'page' => '[pagename]',
53 'mode' => 'actionpage', // or edit
59 * @param string $argstr
60 * @param WikiRequest $request
61 * @param string $basepage
64 function run($dbi, $argstr, &$request, $basepage)
66 $this->allowed_extensions = explode(",",
67 "7z,avi,bmp,bz2,c,cfg,diff,doc,docx,flv,gif,h,ics,ini,".
68 "jpeg,jpg,kmz,mp3,odg,odp,ods,odt,ogg,patch,pdf,png,ppt,".
69 "pptx,rar,svg,tar,tar.gz,txt,xls,xlsx,xml,xsd,zip");
70 $this->disallowed_extensions = explode(",",
71 "ad[ep],asd,ba[st],chm,cmd,com,cgi,cpl,crt,dll,eml,exe,".
72 "hlp,hta,in[fs],isp,jse?,lnk,md[betw],ms[cipt],nws,ocx,".
73 "ops,pcd,p[ir]f,php\d?,phtml,pl,py,reg,sc[frt],sh[bsm]?,".
74 "url,vb[esx]?,vxd,ws[cfh]");
75 //removed "\{[[:xdigit:]]{8}(?:-[[:xdigit:]]{4}){3}-[[:xdigit:]]{12}\}"
77 $args = $this->getArgs($argstr, $request);
80 $file_dir = getUploadFilePath();
82 $form = HTML::form(array('action' => $request->getPostURL(),
83 'enctype' => 'multipart/form-data',
85 $contents = HTML::div(array('class' => 'wikiaction'));
86 $contents->pushContent(HTML::input(array('type' => 'hidden',
87 'name' => 'MAX_FILE_SIZE',
88 'value' => MAX_UPLOAD_SIZE)));
89 $contents->pushContent(HTML::input(array('name' => 'userfile',
90 'required' => 'required',
92 if ($mode == 'edit') {
93 $contents->pushContent(HTML::input(array('name' => 'action',
96 $contents->pushContent(HTML::raw(" "));
97 $contents->pushContent(HTML::input(array('value' => _("Upload"),
98 'name' => 'edit[upload]',
99 'type' => 'submit')));
101 $contents->pushContent(HTML::raw(" "));
102 $contents->pushContent(HTML::input(array('value' => _("Upload"),
103 'type' => 'submit')));
105 $form->pushContent($contents);
108 if ($request->isPost() and $this->only_authenticated) {
109 // Make sure that the user is logged in.
110 $user = $request->getUser();
111 if (!$user->isAuthenticated()) {
112 if (defined('FUSIONFORGE') && FUSIONFORGE) {
113 $message->pushContent(HTML::div(array('class' => 'error'),
114 HTML::p(_("You cannot upload files.")),
116 HTML::li(_("Check you are logged in.")),
117 HTML::li(_("Check you are in the right project.")),
118 HTML::li(_("Check you are a member of the current project."))
122 $message->pushContent(HTML::p(array('class' => 'error'),
123 _("ACCESS DENIED: You must log in to upload files.")));
125 return HTML($message, $form);
129 $userfile = $request->getUploadedFile('userfile');
131 $userfile_name = $userfile->getName();
132 $userfile_name = trim(basename($userfile_name));
133 if (UPLOAD_USERDIR) {
134 $username = $request->_user->_userid;
135 $file_dir .= $username;
137 // $userfile_name = $request->_user->_userid . "/" . $userfile_name;
139 $trimmed_file_dir = rtrim($file_dir, '/');
141 if (file_exists($trimmed_file_dir) && !is_dir($trimmed_file_dir)) {
142 $message->pushContent(HTML::p(array('class' => 'error'), fmt("Cannot upload, “%s” is not a directory.", $trimmed_file_dir)));
143 return HTML($message, $form);
145 if (!file_exists($trimmed_file_dir) && !@mkdir($file_dir, 0775)) {
146 $message->pushContent(HTML::p(array('class' => 'error'), fmt("Cannot create upload directory “%s”.", $file_dir)));
147 return HTML($message, $form);
149 if (!is_writable($trimmed_file_dir)) {
150 $message->pushContent(HTML::p(array('class' => 'error'), fmt("Cannot upload, “%s” is not writable.", $file_dir)));
151 return HTML($message, $form);
154 $userfile_tmpname = $userfile->getTmpName();
155 $err_header = HTML::div(array('class' => 'error'), HTML::p(fmt("Error uploading “%s”", $userfile_name)));
156 if (preg_match("/(\." . join("|\.", $this->disallowed_extensions) . ")(\.|\$)/i", $userfile_name)) {
157 $err_header->pushContent(HTML::p(fmt("Files with extension %s are not allowed.",
158 join(", ", $this->disallowed_extensions))));
159 $message->pushContent($err_header);
160 return HTML($message, $form);
162 if (!DISABLE_UPLOAD_ONLY_ALLOWED_EXTENSIONS and
163 !preg_match("/(\." . join("|\.", $this->allowed_extensions) . ")\$/i", $userfile_name)) {
164 $err_header->pushContent(HTML::p(fmt("Only files with the extension %s are allowed.",
165 join(", ", $this->allowed_extensions))));
166 $message->pushContent($err_header);
167 return HTML($message, $form);
169 if ($userfile->getSize() > (MAX_UPLOAD_SIZE)) {
170 $err_header->pushContent(HTML::p(_("Sorry but this file is too big.")));
171 $message->pushContent($err_header);
172 return HTML($message, $form);
175 $sanified_userfile_name = sanify_filename($userfile_name);
177 if (preg_match("/[^._a-zA-Z0-9- ]/", strip_accents($sanified_userfile_name))) {
178 $err_header->pushContent(HTML::p(_("Invalid filename.")));
179 $message->pushContent($err_header);
180 return HTML($message, $form);
183 if (file_exists($file_dir . $sanified_userfile_name)) {
184 $err_header->pushContent(HTML::p(fmt("There is already a file with name “%s” uploaded.", $sanified_userfile_name)));
185 $message->pushContent($err_header);
186 return HTML($message, $form);
188 if (move_uploaded_file($userfile_tmpname, $file_dir . $sanified_userfile_name) or
189 (IsWindows() and rename($userfile_tmpname, $file_dir . $sanified_userfile_name))) {
190 $interwiki = new PageType_interwikimap();
191 if (UPLOAD_USERDIR) {
192 $link = $interwiki->link("[[Upload:$username/$sanified_userfile_name]]");
194 $link = $interwiki->link("[[Upload:$sanified_userfile_name]]");
196 if ($sanified_userfile_name != $userfile_name) {
197 $message->pushContent(HTML::div(array('class' => 'feedback'),
198 HTML::p(_("File successfully uploaded.")),
200 HTML::p(_("Note: some forbidden characters in filename have been replaced by dash."))));
202 $message->pushContent(HTML::div(array('class' => 'feedback'),
203 HTML::p(_("File successfully uploaded.")),
206 // the upload was a success and we need to mark this event in the "upload log"
208 $upload_log = $file_dir . basename($logfile);
209 $this->log($userfile, $upload_log, $message);
212 require_once 'lib/loadsave.php';
213 $pagehandle = $dbi->getPage($page);
214 if ($pagehandle->exists()) { // don't replace default contents
215 $current = $pagehandle->getCurrentRevision();
216 $version = $current->getVersion();
217 $text = $current->getPackedContent();
218 // don't inline images
219 if (UPLOAD_USERDIR) {
220 $newtext = $text . "\n* [[Upload:$username/$sanified_userfile_name]]";
222 $newtext = $text . "\n* [[Upload:$sanified_userfile_name]]";
224 $meta = $current->_data;
225 if (UPLOAD_USERDIR) {
226 $meta['summary'] = sprintf(_("uploaded %s"), $username.'/'.$sanified_userfile_name);
228 $meta['summary'] = sprintf(_("uploaded %s"), $sanified_userfile_name);
230 $pagehandle->save($newtext, $version + 1, $meta);
234 $err_header->pushContent(HTML::p(_("Uploading failed.")));
235 $message->pushContent($err_header);
239 return HTML($message, $form);
242 private function log($userfile, $upload_log, &$message)
246 * @var WikiRequest $request
250 $user = $request->_user;
251 if (file_exists($upload_log) and (!is_writable($upload_log))) {
252 trigger_error(_("The upload logfile exists but is not writable."), E_USER_WARNING);
253 } elseif (!$log_handle = fopen($upload_log, "a")) {
254 trigger_error(_("Can't open the upload logfile."), E_USER_WARNING);
255 } else { // file size in KB; precision of 0.1
256 $file_size = round(($userfile->getSize()) / 1024, 1);
257 if ($file_size <= 0) {
258 $file_size = "< 0.1";
260 $userfile_name = $userfile->getName();
263 . "<tr><td><a href=\"$userfile_name\">$userfile_name</a></td>"
264 . "<td class=\"align-right\">$file_size kB</td>"
265 . "<td> " . $WikiTheme->formatDate(time()) . "</td>"
266 . "<td> <em>" . $user->getId() . "</em></td></tr>");
277 // c-hanging-comment-ender-p: nil
278 // indent-tabs-mode: nil