]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/UpLoad.php
Translate message
[SourceForge/phpwiki.git] / lib / plugin / UpLoad.php
1 <?php
2 /*
3  * Copyright 2003,2004,2007 $ThePhpWikiProgrammingTeam
4  * Copyright 2008-2009 Marc-Etienne Vargenau, Alcatel-Lucent
5  *
6  * This file is part of PhpWiki.
7  *
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.
12  *
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.
17  *
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.
21  */
22
23 /**
24  * UpLoad:  Allow Administrator to upload files to a special directory,
25  *          which should preferably be added to the InterWikiMap
26  * Usage:   <<UpLoad>>
27  * Author:  NathanGass <gass@iogram.ch>
28  * Changes: ReiniUrban <rurban@x-ray.at>,
29  *          qubit <rtryon@dartmouth.edu>
30  *          Marc-Etienne Vargenau, Alcatel-Lucent
31  */
32
33 class WikiPlugin_UpLoad
34     extends WikiPlugin
35 {
36     public $allowed_extensions;
37     public $disallowed_extensions;
38     // TODO: use PagePerms instead
39     public $only_authenticated = true; // allow only authenticated users may upload.
40
41     function getDescription()
42     {
43         return _("Upload files to the local InterWiki [[Upload:filename]]");
44     }
45
46     function getDefaultArguments()
47     {
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)
51             'autolink' => true,
52             'page' => '[pagename]',
53             'mode' => 'actionpage', // or edit
54         );
55     }
56
57     /**
58      * @param WikiDB $dbi
59      * @param string $argstr
60      * @param WikiRequest $request
61      * @param string $basepage
62      * @return mixed
63      */
64     function run($dbi, $argstr, &$request, $basepage)
65     {
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}\}"
76
77         $args = $this->getArgs($argstr, $request);
78         extract($args);
79
80         $file_dir = getUploadFilePath();
81
82         $form = HTML::form(array('action' => $request->getPostURL(),
83             'enctype' => 'multipart/form-data',
84             'method' => 'post'));
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',
91             'type' => 'file')));
92         if ($mode == 'edit') {
93             $contents->pushContent(HTML::input(array('name' => 'action',
94                 'type' => 'hidden',
95                 'value' => 'edit')));
96             $contents->pushContent(HTML::raw(" "));
97             $contents->pushContent(HTML::input(array('value' => _("Upload"),
98                 'name' => 'edit[upload]',
99                 'type' => 'submit')));
100         } else {
101             $contents->pushContent(HTML::raw(" "));
102             $contents->pushContent(HTML::input(array('value' => _("Upload"),
103                 'type' => 'submit')));
104         }
105         $form->pushContent($contents);
106
107         $message = HTML();
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.")),
115                         HTML::ul(
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."))
119                         )
120                     ));
121                 } else {
122                     $message->pushContent(HTML::p(array('class' => 'error'),
123                         _("ACCESS DENIED: You must log in to upload files.")));
124                 }
125                 return HTML($message, $form);
126             }
127         }
128
129         $userfile = $request->getUploadedFile('userfile');
130         if ($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;
136                 $file_dir .= "/";
137                 // $userfile_name = $request->_user->_userid . "/" . $userfile_name;
138             }
139             $trimmed_file_dir = rtrim($file_dir, '/');
140
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);
144             }
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);
148             }
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);
152             }
153
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);
161             }
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);
168             }
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);
173             }
174
175             $sanified_userfile_name = sanify_filename($userfile_name);
176
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);
181             }
182
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);
187             }
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]]");
193                 } else {
194                     $link = $interwiki->link("[[Upload:$sanified_userfile_name]]");
195                 }
196                 if ($sanified_userfile_name != $userfile_name) {
197                     $message->pushContent(HTML::div(array('class' => 'feedback'),
198                         HTML::p(_("File successfully uploaded.")),
199                         HTML::p($link),
200                         HTML::p(_("Note: some forbidden characters in filename have been replaced by dash."))));
201                 } else {
202                     $message->pushContent(HTML::div(array('class' => 'feedback'),
203                         HTML::p(_("File successfully uploaded.")),
204                         HTML::p($link)));
205                 }
206                 // the upload was a success and we need to mark this event in the "upload log"
207                 if ($logfile) {
208                     $upload_log = $file_dir . basename($logfile);
209                     $this->log($userfile, $upload_log, $message);
210                 }
211                 if ($autolink) {
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]]";
221                         } else {
222                             $newtext = $text . "\n* [[Upload:$sanified_userfile_name]]";
223                         }
224                         $meta = $current->_data;
225                         if (UPLOAD_USERDIR) {
226                             $meta['summary'] = sprintf(_("uploaded %s"), $username.'/'.$sanified_userfile_name);
227                         } else {
228                             $meta['summary'] = sprintf(_("uploaded %s"), $sanified_userfile_name);
229                         }
230                         $pagehandle->save($newtext, $version + 1, $meta);
231                     }
232                 }
233             } else {
234                 $err_header->pushContent(HTML::p(_("Uploading failed.")));
235                 $message->pushContent($err_header);
236             }
237         }
238
239         return HTML($message, $form);
240     }
241
242     private function log($userfile, $upload_log, &$message)
243     {
244         global $WikiTheme;
245         /**
246          * @var WikiRequest $request
247          */
248         global $request;
249
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 = "&lt; 0.1";
259             }
260             $userfile_name = $userfile->getName();
261             fwrite($log_handle,
262                 "\n"
263                     . "<tr><td><a href=\"$userfile_name\">$userfile_name</a></td>"
264                     . "<td class=\"align-right\">$file_size kB</td>"
265                     . "<td>&nbsp;&nbsp;" . $WikiTheme->formatDate(time()) . "</td>"
266                     . "<td>&nbsp;&nbsp;<em>" . $user->getId() . "</em></td></tr>");
267             fclose($log_handle);
268         }
269         return;
270     }
271 }
272
273 // Local Variables:
274 // mode: php
275 // tab-width: 8
276 // c-basic-offset: 4
277 // c-hanging-comment-ender-p: nil
278 // indent-tabs-mode: nil
279 // End: