Index: trunk/extensions/SpecialUploadLocal/SpecialUploadLocal.php |
— | — | @@ -0,0 +1,91 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +if (!defined('MEDIAWIKI')) die(); |
| 5 | + |
| 6 | +/* |
| 7 | + |
| 8 | +TODO: |
| 9 | + * Considered more advanced file scanning regexps/recursive searching |
| 10 | + * Allow unzipping without ssh'ing (need a tar library or shell) |
| 11 | + * Migrate repository to Mercurial so we can easily push changes |
| 12 | + |
| 13 | +BUGS: |
| 14 | + * Figure out how to get image overwrites to work properly or fail gracefully |
| 15 | + * Warn when filename contains ampersand. (Apache doesn't like that) |
| 16 | + |
| 17 | +ENHANCEMENTS: |
| 18 | + * Mute extra output from the new page function. |
| 19 | + * Remove debugging info. |
| 20 | + * Dry run capability. |
| 21 | + |
| 22 | +*/ |
| 23 | + |
| 24 | +$wgExtensionFunctions[] = "wfSetupUploadLocal"; |
| 25 | +$wgExtensionCredits['specialpage'][] = array( |
| 26 | + 'name' => 'UploadLocal', |
| 27 | + 'description' => 'allows users to link in files already on the server' |
| 28 | +); |
| 29 | + |
| 30 | +$wgUploadLocalDirectory = $IP . '/extensions/SpecialUploadLocal/data'; |
| 31 | + |
| 32 | +$wgAvailableRights[] = 'uploadlocal'; |
| 33 | +$wgGroupPermissions['uploader']['uploadlocal'] = true; |
| 34 | +$wgGroupPermissions['sysop'] ['uploadlocal'] = true; |
| 35 | + |
| 36 | +function wfSetupUploadLocal() { |
| 37 | + require_once( 'SpecialPage.php' ); |
| 38 | + |
| 39 | + global $wgMessageCache; |
| 40 | + |
| 41 | + $messages = array( |
| 42 | + 'uploadlocal' => 'Upload local files' |
| 43 | + ,'uploadlocal_directory_readonly' => 'The local upload directory ($1) is'. |
| 44 | + ' not writeable by the webserver.' |
| 45 | + ,'uploadlocaltext' => 'Use this form to mass upload files already on the'. |
| 46 | + ' server in the upload local directory. You can find out more'. |
| 47 | + ' general information at [[Special:Upload|the regular upload file'. |
| 48 | + ' page]].' |
| 49 | + ,'uploadlocalbtn' => 'Upload local files' |
| 50 | + ,'nolocalfiles' => 'There are no files in the local upload folder. Try'. |
| 51 | + ' placing some files in "<code>$1</code>."' |
| 52 | + ,'uploadednolocalfiles' => 'You did not upload any files.' |
| 53 | + ,'allfilessuccessful' => 'All files uploaded successfully' |
| 54 | + ,'uploadlocalerrors' => 'Some files had errors' |
| 55 | + ,'allfilessuccessfultext' => 'All files uploaded successfully. Return to'. |
| 56 | + ' [[Main Page]].' |
| 57 | + ,'uploadlocal_descriptions_append' => 'Append to description: ' |
| 58 | + ,'uploadlocal_descriptions_prepend' => 'Prepend to description: ' |
| 59 | + ,'uploadlocal_dest_file_append' => 'Append to dest. filename: ' |
| 60 | + ,'uploadlocal_dest_file_prepend' => 'Prepend to dest. filename: ' |
| 61 | + ,'uploadlocal_file_list' => 'Files ready for upload' |
| 62 | + ,'uploadlocal_file_list_explanation' => '\'\'\'X\'\'\' indicates'. |
| 63 | + ' whether or not you want the file to be uploaded (uncheck to'. |
| 64 | + ' prevent a file from being processed). \'\'\'W\'\'\' indicates'. |
| 65 | + ' whether you want the file added to your watchlist.' |
| 66 | + ,'uploadlocal_global_params' => 'Global parameters' |
| 67 | + ,'uploadlocal_global_params_explanation' => 'What is entered here will'. |
| 68 | + ' automatically get added to the entries listed above. This helps'. |
| 69 | + ' remove repetitive text such as categories and metadata. To \'\'\''. |
| 70 | + 'append\'\'\' is to add to the end of text, while to \'\'\'prepend'. |
| 71 | + '\'\'\' means to add to the beginning of text. Especially for'. |
| 72 | + ' descriptions, make sure you give a few linebreaks before/after'. |
| 73 | + ' the text.' |
| 74 | + ); |
| 75 | + $wgMessageCache->addMessages($messages); |
| 76 | + SpecialPage::addPage( new SpecialPage( 'UploadLocal', 'uploadlocal', |
| 77 | + /*listed*/ true, /*function*/ false, /*file*/ false ) ); |
| 78 | + |
| 79 | +} |
| 80 | + |
| 81 | +function wfSpecialUploadLocal() { |
| 82 | + global $wgRequest, $wgUploadLocalDirectory, $wgMessageCache; |
| 83 | + |
| 84 | + $prefix = 'extensions/SpecialUploadLocal/'; |
| 85 | + require($prefix . 'UploadLocalDirectory.php'); |
| 86 | + require($prefix . 'UploadLocalForm.php'); |
| 87 | + |
| 88 | + $directory =& new UploadLocalDirectory($wgRequest, $wgUploadLocalDirectory); |
| 89 | + $directory->execute(); |
| 90 | +} |
| 91 | + |
| 92 | +?> |
\ No newline at end of file |
Property changes on: trunk/extensions/SpecialUploadLocal/SpecialUploadLocal.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 93 | + native |
Index: trunk/extensions/SpecialUploadLocal/UploadLocalForm.php |
— | — | @@ -0,0 +1,59 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +require_once('SpecialUpload.php'); |
| 5 | + |
| 6 | +class UploadLocalForm extends UploadForm |
| 7 | +{ |
| 8 | + |
| 9 | + var $_error = ''; |
| 10 | + var $_filename; |
| 11 | + |
| 12 | + /** |
| 13 | + * With our parameters, simulate a request |
| 14 | + */ |
| 15 | + function UploadLocalForm($filename, $description, $watch, $dest) { |
| 16 | + global $wgUploadLocalDirectory; |
| 17 | + |
| 18 | + // Prepare our directory |
| 19 | + $dir = $wgUploadLocalDirectory; |
| 20 | + if ($dir[strlen($dir)-1] !== '/') $dir .= '/'; |
| 21 | + |
| 22 | + // Create faux request object with basic parameters. |
| 23 | + $request = new FauxRequest(array( |
| 24 | + 'wpDestFile' => $dest, |
| 25 | + 'wpIgnoreWarning' => true, |
| 26 | + 'wpUploadDescription' => $description, |
| 27 | + 'wpUpload' => true, |
| 28 | + 'wpWatchthis' => $this->watch, |
| 29 | + ), true); |
| 30 | + |
| 31 | + // Instantiate private variables with those values, also note |
| 32 | + // initializeFromUpload() call will fail, but we don't have any |
| 33 | + // way of overriding that, and the failure is silent. |
| 34 | + parent::UploadForm($request); |
| 35 | + |
| 36 | + // initializeFromLocalFile() style functionality |
| 37 | + $this->mTempPath = $dir . $filename; |
| 38 | + $this->mFileSize = filesize($dir . $filename); |
| 39 | + $this->mSrcName = $dir . $filename; |
| 40 | + $this->mCurlError = false; |
| 41 | + $this->mSessionKey = false; |
| 42 | + $this->mStashed = false; |
| 43 | + // Our files are not under PHP's jurisdiction, so we need to remove |
| 44 | + // it ourselves. |
| 45 | + $this->mRemoveTempFile = true; |
| 46 | + |
| 47 | + } |
| 48 | + |
| 49 | + function getFilename() {return $this->_filename;} |
| 50 | + function getUploadSaveName() {return $this->mDesiredDestName;} |
| 51 | + |
| 52 | + function mainUploadForm($error) {$this->_error = $error;} |
| 53 | + function uploadError($error) {$this->_error = $error;} |
| 54 | + function showSuccess() {} |
| 55 | + |
| 56 | + function getError() {return $this->_error;} |
| 57 | + |
| 58 | +} |
| 59 | + |
| 60 | +?> |
\ No newline at end of file |
Property changes on: trunk/extensions/SpecialUploadLocal/UploadLocalForm.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 61 | + native |
Index: trunk/extensions/SpecialUploadLocal/data/.htaccess |
— | — | @@ -0,0 +1 @@ |
| 2 | +Deny from all |
Property changes on: trunk/extensions/SpecialUploadLocal/data/.htaccess |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 3 | + native |
Index: trunk/extensions/SpecialUploadLocal/UploadLocalDirectory.php |
— | — | @@ -0,0 +1,236 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class UploadLocalDirectory |
| 5 | +{ |
| 6 | + |
| 7 | + var $_directory; |
| 8 | + var $_was_posted; |
| 9 | + var $_available_files; |
| 10 | + |
| 11 | + function UploadLocalDirectory($request, $directory) { |
| 12 | + $this->_directory = $directory; |
| 13 | + $this->_was_posted = $request->wasPosted(); |
| 14 | + $this->_available_files = $this->getFilenamesOfFilesInDirectory($directory); |
| 15 | + } |
| 16 | + |
| 17 | + function execute() { |
| 18 | + global $wgOut, $wgRequest, $wgUser, $wgEnableUploads, |
| 19 | + $wgUploadDirectory; |
| 20 | + |
| 21 | + // a bit of this is stolen from the SpecialUpload code, duplication |
| 22 | + // is bad but there was no way to meaningfully integrate it into |
| 23 | + // this code. |
| 24 | + |
| 25 | + if( ! $wgEnableUploads ) { |
| 26 | + $wgOut->addWikiText( wfMsg( 'uploaddisabled' ) ); |
| 27 | + return; |
| 28 | + } |
| 29 | + |
| 30 | + // uses extension specific permission "uploadlocal" |
| 31 | + if (!$wgUser->isAllowed( 'uploadlocal' ) || $wgUser->isBlocked() ) { |
| 32 | + $wgOut->errorpage( 'uploadnologin', 'uploadnologintext' ); |
| 33 | + return; |
| 34 | + } |
| 35 | + |
| 36 | + if( wfReadOnly() ) { |
| 37 | + $wgOut->readOnlyPage(); |
| 38 | + return; |
| 39 | + } |
| 40 | + |
| 41 | + // check if both relevant directories are writeable |
| 42 | + if ( !is_writeable( $wgUploadDirectory ) ) { |
| 43 | + $wgOut->addWikiText( wfMsg( 'upload_directory_read_only', $wgUploadDirectory ) ); |
| 44 | + return; |
| 45 | + } |
| 46 | + if ( !is_writeable($this->_directory) ) { |
| 47 | + $wgOut->addWikiText( wfMsg( 'upload_directory_read_only', $this->_directory ) ); |
| 48 | + return; |
| 49 | + } |
| 50 | + |
| 51 | + // check if there are any files to upload |
| 52 | + if (empty($this->_available_files)) { |
| 53 | + $wgOut->addWikitext( wfMsg( 'uploadlocaltext' ) ); |
| 54 | + $wgOut->addWikitext( wfMsg( 'nolocalfiles', htmlentities($this->_directory) ) ); |
| 55 | + return; |
| 56 | + } |
| 57 | + |
| 58 | + if ($this->_was_posted) { |
| 59 | + $this->processUploads($wgRequest); |
| 60 | + } else { |
| 61 | + $this->showForm(); |
| 62 | + } |
| 63 | + |
| 64 | + } |
| 65 | + |
| 66 | + function showForm() { |
| 67 | + global $wgOut; |
| 68 | + |
| 69 | + $wgOut->addWikitext( wfMsg( 'uploadlocaltext' ) ); |
| 70 | + |
| 71 | + $titleObj = Title::makeTitle( NS_SPECIAL, 'UploadLocal' ); |
| 72 | + $action = $titleObj->escapeLocalURL(); |
| 73 | + |
| 74 | + $wgOut->addHTML('<form id="uploadlocal" method="post"'. |
| 75 | + ' enctype="multipart/form-data" action="'.$action.'">'); |
| 76 | + |
| 77 | + $wgOut->addWikitext('==' . wfMsg('uploadlocal_file_list') . '=='); |
| 78 | + $wgOut->addWikitext(wfMsg('uploadlocal_file_list_explanation')); |
| 79 | + |
| 80 | + $html = ''; |
| 81 | + |
| 82 | + $html .= '<table border="0" cellspacing="0" style="width:100%;">'; |
| 83 | + $html .= '<theader>'. |
| 84 | + '<tr><th style="width:1em;">X</th>'. |
| 85 | + '<th style="width:1em;">W</th>'. |
| 86 | + '<th style="width:10em;text-align:left;">'.wfMsg('sourcefilename').'</th>'. |
| 87 | + '<th style="width:10em;text-align:left;">'.wfMsg('destfilename').'</th>'. |
| 88 | + '<th style="text-align:left;">'.wfMsg('filedesc').'</th></tr></theader>'; |
| 89 | + $html .= '<tbody>'; |
| 90 | + $i = 1; |
| 91 | + foreach ($this->_available_files as $file) { |
| 92 | + $html_file = htmlentities($file); |
| 93 | + $html .= '<tr' . |
| 94 | + ($i % 2 ? ' style="background-color:#EEE;"' : '') . |
| 95 | + '>'. |
| 96 | + '<td><input type="checkbox" checked="checked"'. |
| 97 | + ' name="wpUploadFiles['.$i.']" value="'.$html_file.'" /></td>'. |
| 98 | + '<td><input type="checkbox" checked="checked"'. |
| 99 | + ' name="wpWatchThese['.$i.']" value="'.$html_file.'" /></td>'. |
| 100 | + '<td>'.$html_file.'</td>'. |
| 101 | + '<td><input type="text" name="wpDestFiles['.$i.']"'. |
| 102 | + ' value="'.$html_file.'" /></td>'. |
| 103 | + '<td style="width:50%;">'. |
| 104 | + '<textarea name="wpUploadDescriptions['.$i.']" cols="60" '. |
| 105 | + 'rows="2" style="width:100%;"></textarea></td>'. |
| 106 | + '</tr>'; |
| 107 | + $i++; |
| 108 | + } |
| 109 | + $html .= '</tbody></table>'; |
| 110 | + |
| 111 | + $wgOut->addHTML($html); |
| 112 | + $wgOut->addWikitext('==' . wfMsg('uploadlocal_global_params') . '=='); |
| 113 | + $wgOut->addWikitext(wfMsg('uploadlocal_global_params_explanation')); |
| 114 | + $html = ''; |
| 115 | + |
| 116 | + $html .= '<table border="0" style="width:100%;">'; |
| 117 | + $html .= '<tbody>'. |
| 118 | + '<tr><th style="text-align:right;width:25%;">'.wfMsg('uploadlocal_descriptions_prepend').'</th>'. |
| 119 | + '<td><textarea cols="70" rows="3" style="width:100%;" name="wpUploadDescriptionsPrepend"></textarea></td></tr>'. |
| 120 | + |
| 121 | + '<tr><th style="text-align:right;">'.wfMsg('uploadlocal_descriptions_append').'</th>'. |
| 122 | + '<td><textarea cols="70" rows="3" style="width:100%;" name="wpUploadDescriptionsAppend"></textarea></td></tr>'. |
| 123 | + |
| 124 | + '<tr><th style="text-align:right;">'.wfMsg('uploadlocal_dest_file_prepend').'</th>'. |
| 125 | + '<td><input type="text" style="width:100%;" name="wpDestFilesPrepend" /></td></tr>'. |
| 126 | + |
| 127 | + '<tr><th style="text-align:right;">'.wfMsg('uploadlocal_dest_file_append').'</th>'. |
| 128 | + '<td><input type="text" style="width:100%;" name="wpDestFilesAppend" /></td></tr>'. |
| 129 | + |
| 130 | + '</tbody>'; |
| 131 | + $html .= '</table>'; |
| 132 | + |
| 133 | + $html .= '<input type="submit" name="wpUploadLocal" value="'.wfMsg('uploadlocalbtn').'" /></form>'; |
| 134 | + |
| 135 | + $wgOut->addHTML($html); |
| 136 | + } |
| 137 | + |
| 138 | + function getFilenamesOfFilesInDirectory($directory) { |
| 139 | + if (!is_dir($directory)) return array(); |
| 140 | + if ($directory[strlen($directory)-1] !== '/') $directory .= '/'; |
| 141 | + $dh = opendir($directory); |
| 142 | + $filenames = array(); |
| 143 | + while (($file = readdir($dh)) !== false) { |
| 144 | + if ($file == '.' || $file == '..') continue; |
| 145 | + // check if it's a directory |
| 146 | + if (is_dir($directory . $file)) continue; |
| 147 | + // check if it's a hidden file - regexp: /\.[^.]+/ |
| 148 | + if ($file[0] == '.' && strpos($file,'.',1) === false) { |
| 149 | + continue; |
| 150 | + } |
| 151 | + $filenames[] = $file; |
| 152 | + } |
| 153 | + closedir($dh); |
| 154 | + return $filenames; |
| 155 | + } |
| 156 | + |
| 157 | + function processUploads($request) { |
| 158 | + |
| 159 | + global $wgOut, $wgContLang; |
| 160 | + |
| 161 | + $r_files = $request->getArray('wpUploadFiles', array()); |
| 162 | + $r_descriptions = $request->getArray('wpUploadDescriptions', array()); |
| 163 | + $r_watch_these = $request->getArray('wpWatchThese', array()); |
| 164 | + $r_dest_files = $request->getArray('wpDestFiles', array()); |
| 165 | + |
| 166 | + $r_descriptions_prepend = $request->getVal('wpUploadDescriptionsPrepend' , ''); |
| 167 | + $r_descriptions_append = $request->getVal('wpUploadDescriptionsAppend', ''); |
| 168 | + $r_dest_files_prepend = $request->getVal('wpDestFilesPrepend', ''); |
| 169 | + $r_dest_files_append = $request->getVal('wpDestFilesAppend', ''); |
| 170 | + |
| 171 | + $files_to_process = array(); |
| 172 | + $forms = array(); |
| 173 | + |
| 174 | + foreach ($r_files as $i => $file) { |
| 175 | + if (!in_array($file, $this->_available_files)) continue; |
| 176 | + // Build destination filename |
| 177 | + $r_dest_file = $r_dest_files_prepend . (isset($r_dest_files[$i]) ? |
| 178 | + $r_dest_files[$i] : $file); |
| 179 | + $p = strrpos($r_dest_file, '.'); |
| 180 | + if ($p !== false) { |
| 181 | + $r_dest_file = substr($r_dest_file, 0, $p) . $r_dest_files_append |
| 182 | + . substr($r_dest_file, $p); |
| 183 | + } else { |
| 184 | + $r_dest_file = $r_dest_file . $r_dest_files_append; |
| 185 | + } |
| 186 | + $forms[] =& new UploadLocalForm( |
| 187 | + $file, |
| 188 | + $r_descriptions_prepend . ($r_descriptions_prepend ? "\n" : '') . |
| 189 | + (isset($r_descriptions[$i]) ? $r_descriptions[$i] : '') . |
| 190 | + ($r_descriptions_append ? "\n" : '') . $r_descriptions_append, |
| 191 | + in_array($file, $r_watch_these), |
| 192 | + $r_dest_file |
| 193 | + ); |
| 194 | + |
| 195 | + } |
| 196 | + |
| 197 | + if (empty($forms)) { |
| 198 | + $wgOut->addWikitext( wfMsg( 'uploadednolocalfiles' ) ); |
| 199 | + return; |
| 200 | + } |
| 201 | + $no_error = true; |
| 202 | + $errors = array(); |
| 203 | + |
| 204 | + foreach($forms as $key => $value) { |
| 205 | + $forms[$key]->processUpload(); |
| 206 | + if ($forms[$key]->getError()) { |
| 207 | + $errors[$forms[$key]->getFilename()] = $forms[$key]->getError(); |
| 208 | + unset($forms[$key]); |
| 209 | + } |
| 210 | + } |
| 211 | + //ugly hack to stop the thing from redirecting. Really annoying. |
| 212 | + $wgOut->redirect(''); |
| 213 | + |
| 214 | + if (empty($errors)) { |
| 215 | + $wgOut->setPageTitle(wfMsg('allfilessuccessful')); |
| 216 | + $wgOut->addWikitext(wfMsg('allfilessuccessfultext')); |
| 217 | + } else { |
| 218 | + $wgOut->setPageTitle(wfMsg('uploadlocalerrors')); |
| 219 | + $wgOut->addHTML('<ul>'); |
| 220 | + foreach ($errors as $name => $error) { |
| 221 | + $wgOut->addHTML('<li>'.$name.' - '.$error.'</li>'); |
| 222 | + } |
| 223 | + $wgOut->addHTML('</ul>'); |
| 224 | + } |
| 225 | + |
| 226 | + $links_to_images = ''; |
| 227 | + foreach($forms as $key => $form) { |
| 228 | + // language-neutral namespacing thanks to Eric Lemoine |
| 229 | + $links_to_images .= '* [[:'.$wgContLang->getNsText( NS_IMAGE ).':'.$forms[$key]->getUploadSaveName().']]'."\n"; |
| 230 | + } |
| 231 | + $wgOut->addWikitext($links_to_images); |
| 232 | + |
| 233 | + } |
| 234 | + |
| 235 | +} |
| 236 | + |
| 237 | +?> |
\ No newline at end of file |
Property changes on: trunk/extensions/SpecialUploadLocal/UploadLocalDirectory.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 238 | + native |