MediaWiki扩展:使用服务器的本地图片
天下维客,你可以修改的网络知识库
本文取自元维基,欢迎共同翻译、整理与大家共享,促进中文wiki发展^_^
| Template:If | |
| Type: | Special Page |
|---|---|
| Maturity: | Alpha |
| MediaWiki: | 1.5.6 |
| Version: | 1.0alpha |
| Last Update: | 2006-03-23 |
| Description: | Hooks in files residing on the server, streamlining mass uploading and upload of large files. |
| MediaWiki extensions | |
Special:UploadLocal is a special page written by User:Ambush Commander that allows the "hooking in" of files residing on the server into MediaWiki. This has numerous practical applications, notably the streamlining of the upload of large files, renaming of image files, and the upload of many files (aka. mass upload).
目录 |
Installation
There are two files, both confusingly namedSpecialUploadLocal.php. The one that has the comment
//Special:Uploadlocal specific configgoes inside your
extension/directory, while the other goes in your
includes/
directory.
Create a folder calleduploadlocalin your extensions folder, and
chmod it 777.
Then, in LocalSettings, add these lines:
require_once( "extensions/SpecialUploadLocal.php" );
It should be installed. There are a few more settings:
$wgUploadLocalDirectorysets the absolute path for the directory where
uploaded files reside, so you can set it to whatever you want. The default is:
$wgUploadLocalDirectory = $IP . '/extensions/uploadlocal';Also, the extension adds a new right called
uploadlocaland a new user
group, uploader, along with sysop, are allowed to use this extension. You can change this however you want, although remember, in order for the extension to be useful, the user must also have FTP access.
Using it
Upload files into the directory specified by$wgUploadLocalDirectory
(default is the new directory you created during the installation). Then surf to Special:UploadLocal and you should see the files you uploaded listed there. Follow the instructions.
Known bugs
The result page will randomnly spit out stuff you inserted in the summary. This is largely unavoidable due to the nature of the extension (aka: it is a hack).
Also, files with single quotes in their names will not be renamed or given summaries unless magic_quotes is off or the patch is applied. Patching stuff is as easy as executing the command:
patch -p0 < Magic_quotes_2.patch
from the directory where MediaWiki is installed (but you need shell). I haven't made a drop-dead easy installation script yet.
License
Special:UploadLocal, a special page for MediaWiki Copyright (C) 2006 Edward Z. Yang This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Code
I will make a tarball available soon. Make sure you verify that no one has been twiddling with the code before you copy and paste.
extension/SpecialUploadLocal.php
<?php
if (!defined('MEDIAWIKI')) die();
//Special:Uploadlocal specific config
$wgExtensionFunctions[] = "wfExtensionSpecialUploadLocal";
function wfExtensionSpecialUploadLocal() {
global $wgMessageCache;
// I'd like to try adding these messages on demand, and only have the
// essentials here
$messages = array(
'uploadlocal' => 'Upload local files'
,'uploadlocal_directory_readonly' => 'The local upload directory ($1) is'.
' not writeable by the webserver.'
,'uploadlocaltext' => 'Use this form to mass upload files already on the'.
' server in the upload local directory. You can find out more'.
' general information at [[Special:Upload|the regular upload file'.
' page]].'
,'uploadlocalbtn' => 'Upload local files'
,'nolocalfiles' => 'There are no files in the local upload folder. Try'.
' placing some files in "<code>$1</code>."'
,'uploadednolocalfiles' => 'You did not upload any files.'
,'allfilessuccessful' => 'All files uploaded successfully'
,'uploadlocalerrors' => 'Some files had errors'
,'allfilessuccessfultext' => 'All files uploaded successfully. Return to'.
' [[Main Page]].'
,'uploadlocal_descriptions_append' => 'Append to description: '
,'uploadlocal_descriptions_prepend' => 'Prepend to description: '
,'uploadlocal_dest_file_append' => 'Append to dest. filename: '
,'uploadlocal_dest_file_prepend' => 'Prepend to dest. filename: '
,'uploadlocal_file_list' => 'Files ready for upload'
,'uploadlocal_file_list_explanation' => '\'\'\'X\'\'\' indicates'.
' whether or not you want the file to be uploaded (uncheck to'.
' prevent a file from being processed). \'\'\'W\'\'\' indicates'.
' whether you want the file added to your watchlist.'
,'uploadlocal_global_params' => 'Global parameters'
,'uploadlocal_global_params_explanation' => 'What is entered here will'.
' automatically get added to the entries listed above. This helps'.
' remove repetitive text such as categories and metadata. To \'\'\''.
'append\'\'\' is to add to the end of text, while to \'\'\'prepend'.
'\'\'\' means to add to the beginning of text. Especially for'.
' descriptions, make sure you give a few linebreaks before/after'.
' the text.'
);
$wgMessageCache->addMessages($messages);
SpecialPage::addPage( new SpecialPage( 'UploadLocal', 'uploadlocal' ) );
}
$wgUploadLocalDirectory = $IP . '/extensions/uploadlocal';
$wgAvailableRights[] = 'uploadlocal';
$wgGroupPermissions['uploader']['uploadlocal'] = true;
$wgGroupPermissions['sysop'] ['uploadlocal'] = true;
?>
includes/SpecialUploadLocal.php
<?php
require_once('SpecialUpload.php');
/*
TODO:
* Considered more advanced file scanning regexps/recursive searching
* Allow unzipping without telnetting
BUGS:
* Figure out how to get image overwrites to work properly or fail gracefully
* Extra output from the new page function... need a wgOut decorator to mute it
* & is accepted, but MediaWiki doesn't seem to like it
* Really easy to make mistake with description appends: force a newline
* Filename append is useless, add it right before the period
* Rewrite form so that all array keys are integers
WARNINGS:
* Files with single quotes in them will lose information when magic_quotes
is on, as per bug 4381. There is a patch available to fix this, but beware!
*/
function wfSpecialUploadLocal() {
global $wgRequest, $wgUploadLocalDirectory, $wgMessageCache;
$directory =& new UploadLocalDirectory($wgRequest, $wgUploadLocalDirectory);
$directory->execute();
}
class UploadLocalDirectory
{
var $_directory;
var $_was_posted;
var $_available_files;
function UploadLocalDirectory($request, $directory) {
$this->_directory = $directory;
$this->_was_posted = $request->wasPosted();
$this->_available_files = $this->getFilenamesOfFilesInDirectory($directory);
}
function execute() {
global $wgOut, $wgRequest, $wgUser, $wgEnableUploads,
$wgUploadDirectory;
// a bit of this is stolen from the SpecialUpload code, duplication
// is bad but there was no way to meaningfully integrate it into
// this code.
if(! $wgEnableUploads ) {
$wgOut->addWikiText( wfMsg( 'uploaddisabled' ) );
return;
}
// uses extension specific permission "uploadlocal"
if (!$wgUser->isAllowed( 'uploadlocal' ) || $wgUser->isBlocked() ) {
$wgOut->errorpage( 'uploadnologin', 'uploadnologintext' );
return;
}
if( wfReadOnly() ) {
$wgOut->readOnlyPage();
return;
}
// check if both relevant directories are writeable
if (!is_writeable( $wgUploadDirectory ) ) {
$wgOut->addWikiText( wfMsg( 'upload_directory_read_only', $wgUploadDirectory ) );
return;
}
if (!is_writeable($this->_directory) ) {
$wgOut->addWikiText( wfMsg( 'upload_directory_read_only', $this->_directory ) );
return;
}
// check if there are any files to upload
if (empty($this->_available_files)) {
$wgOut->addWikitext( wfMsg( 'uploadlocaltext' ) );
$wgOut->addWikitext( wfMsg( 'nolocalfiles', htmlentities($this->_directory) ) );
return;
}
if ($this->_was_posted) {
$this->processUploads($wgRequest);
} else {
$this->showForm();
}
}
function showForm() {
global $wgOut;
$wgOut->addWikitext( wfMsg( 'uploadlocaltext' ) );
$titleObj = Title::makeTitle( NS_SPECIAL, 'UploadLocal' );
$action = $titleObj->escapeLocalURL();
$wgOut->addHTML('<form id="uploadlocal" method="post"'.
' enctype="multipart/form-data" action="'.$action.'">');
$wgOut->addWikitext('==' . wfMsg('uploadlocal_file_list') . '==');
$wgOut->addWikitext(wfMsg('uploadlocal_file_list_explanation'));
$html = '';
$html .= '<table border="0" cellspacing="0" style="width:100%;">';
$html .= '<theader>'.
'<tr><th style="width:1em;">X</th>'.
'<th style="width:1em;">W</th>'.
'<th style="width:10em;text-align:left;">'.wfMsg('sourcefilename').'</th>'.
'<th style="width:10em;text-align:left;">'.wfMsg('destfilename').'</th>'.
'<th style="text-align:left;">'.wfMsg('filedesc').'</th></tr></theader>';
$html .= '<tbody>';
$i = 1;
foreach ($this->_available_files as $file) {
$html_file = htmlentities($file);
$html .= '<tr' .
($i % 2? ' style="background-color:#EEE;"': '') .
'>'.
'<td><input type="checkbox" checked="checked"'.
' name="wpUploadFiles[]" value="'.$html_file.'" /></td>'.
'<td><input type="checkbox" checked="checked"'.
' name="wpWatchThese[]" value="'.$html_file.'" /></td>'.
'<td>'.$html_file.'</td>'.
'<td><input type="text" name="wpDestFiles['.$html_file.']"'.
' value="'.$html_file.'" /></td>'.
'<td style="width:50%;"><textarea name="wpUploadDescriptions['.
$html_file.
']" cols="60" rows="2" style="width:100%;"></textarea></td>'.
'</tr>';
$i++;
}
$html .= '</tbody></table>';
$wgOut->addHTML($html);
$wgOut->addWikitext('==' . wfMsg('uploadlocal_global_params') . '==');
$wgOut->addWikitext(wfMsg('uploadlocal_global_params_explanation'));
$html = '';
$html .= '<table border="0" style="width:100%;">';
$html .= '<tbody>'.
'<tr><th style="text-align:right;width:25%;">'.wfMsg('uploadlocal_descriptions_prepend').'</th>'.
'<td><textarea cols="70" rows="3" style="width:100%;" name="wpUploadDescriptionsPrepend"></textarea></td></tr>'.
'<tr><th style="text-align:right;">'.wfMsg('uploadlocal_descriptions_append').'</th>'.
'<td><textarea cols="70" rows="3" style="width:100%;" name="wpUploadDescriptionsAppend"></textarea></td></tr>'.
'<tr><th style="text-align:right;">'.wfMsg('uploadlocal_dest_file_prepend').'</th>'.
'<td><input type="text" style="width:100%;" name="wpDestFilesPrepend" /></td></tr>'.
'<tr><th style="text-align:right;">'.wfMsg('uploadlocal_dest_file_append').'</th>'.
'<td><input type="text" style="width:100%;" name="wpDestFilesAppend" /></td></tr>'.
'</tbody>';
$html .= '</table>';
$html .= '<input type="submit" name="wpUploadLocal" value="'.wfMsg('uploadlocalbtn').'" /></form>';
$wgOut->addHTML($html);
}
function getFilenamesOfFilesInDirectory($directory) {
if (!is_dir($directory)) return array();
if ($directory[strlen($directory)-1]!== '/') $directory .= '/';
$dh = opendir($directory);
$filenames = array();
while (($file = readdir($dh))!== false) {
if ($file == '.' || $file == '..') continue;
// check if it's a directory
if (is_dir($directory . $file)) continue;
// check if it's a hidden file - regexp: /\.[^.]+/
if ($file[0] == '.' && strpos($file,'.',1) === false) {
continue;
}
$filenames[] = $file;
}
closedir($dh);
return $filenames;
}
function processUploads($request) {
global $wgOut, $wgContLang;
$r_files = $request->getArray('wpUploadFiles', array());
$r_descriptions = $request->getArray('wpUploadDescriptions', array());
$r_watch_these = $request->getArray('wpWatchThese', array());
$r_dest_files = $request->getArray('wpDestFiles', array());
$r_descriptions_prepend = $request->getVal('wpUploadDescriptionsPrepend' , '');
$r_descriptions_append = $request->getVal('wpUploadDescriptionsAppend', '');
$r_dest_files_prepend = $request->getVal('wpDestFilesPrepend', '');
$r_dest_files_append = $request->getVal('wpDestFilesAppend', '');
$files_to_process = array();
$forms = array();
foreach ($r_files as $file) {
if (!in_array($file, $this->_available_files)) continue;
// this is really convoluted
// also, we'd like the appending for filenames to be smart and
// come before the period, otherwise it's pretty useless
$forms[] =& new UploadLocalForm(
$file,
$r_descriptions_prepend . (isset($r_descriptions[$file])? $r_descriptions[$file]: '') . $r_descriptions_append,
in_array($file, $r_watch_these),
$r_dest_files_prepend . (isset($r_dest_files[$file])? $r_dest_files[$file]: $file) . $r_dest_files_append
);
}
if (empty($forms)) {
$wgOut->addWikitext( wfMsg( 'uploadednolocalfiles' ) );
return;
}
$no_error = true;
$errors = array();
foreach($forms as $key => $value) {
$forms[$key]->processUpload();
if ($forms[$key]->getError()) {
$errors[$forms[$key]->getFilename()] = $forms[$key]->getError();
unset($forms[$key]);
}
}
//ugly hack to stop the thing from redirecting. Really annoying.
$wgOut->redirect('');
if (empty($errors)) {
$wgOut->setPageTitle(wfMsg('allfilessuccessful'));
$wgOut->addWikitext(wfMsg('allfilessuccessfultext'));
} else {
$wgOut->setPageTitle(wfMsg('uploadlocalerrors'));
$wgOut->addHTML('<ul>');
foreach ($errors as $name => $error) {
$wgOut->addHTML('<li>'.$name.' - '.$error.'</li>');
}
$wgOut->addHTML('</ul>');
}
$links_to_images = '';
foreach($forms as $key => $form) {
// language-neutral namespacing thanks to Eric Lemoine
$links_to_images .= '* [[:'.$wgContLang->getNsText( NS_IMAGE ).':'.$forms[$key]->getUploadSaveName().']]'."\n";
}
$wgOut->addWikitext($links_to_images);
}
}
class UploadLocalForm extends UploadForm
{
var $_error = '';
var $_filename;
//overload form initialization: we're not dealing with any http uploads
function UploadLocalForm($filename, $description, $watch, $dest) {
global $wgUploadLocalDirectory;
$this->_filename = $filename;
$directory = $wgUploadLocalDirectory;
if ($directory[strlen($directory)-1]!== '/') $directory .= '/';
$this->mUploadTempName = $directory . $filename;
// there is no "real" old name, as it's already on the server
$this->mOname = $directory . $filename;
$this->mUploadSize = filesize($this->mUploadTempName);
$this->mDestFile = $dest;
// should check every time, since there are no fresh/stale uploads
$this->mStashed = false;
$this->mIgnoreWarning = true; //ignore warnings... don't wanna deal with 'em
//however, this attitude means that it's
//extremely easy to accidently overwrite
//files. Solution?
$this->mSessionKey = true; //makes it think that it is locally stored
$this->mUploadDescription = $description;
$this->mUploadCopyStatus = ''; //not supported yet
$this->mUploadSource = ''; //not supported yet
$this->mWatchthis = $watch;
}
function getFilename() {return $this->_filename;}
function getUploadSaveName() {return $this->mUploadSaveName;}
function mainUploadForm($error) {$this->_error = $error;}
function uploadError($error) {$this->_error = $error;}
function showSuccess() {}
function getError() {return $this->_error;}
}
?>
Magic_quotes_2.patch
--- C:/Documents and Settings/Edward/My Documents/My Webs/jpsband/mediawiki/t/includes/WebRequest.php (revision 454)
+++ includes/WebRequest.php (revision 526)
@@ -48,9 +48,15 @@
/**
* Recursively strips slashes from the given array;
* used for undoing the evil that is magic_quotes_gpc.
+ *
+ * Abandoned in favor of more accurate fix_magic_quotes_4 and 5, which
+ * were based largely on comments in
+ * http://us3.php.net/manual/en/function.get-magic-quotes-gpc.php
+ *
* @param array &$arr will be modified
* @return array the original array
* @private
+ * @deprecated
*/
function &fix_magic_quotes( &$arr ) {
foreach( $arr as $key => $val ) {
@@ -63,6 +69,35 @@
return $arr;
}
+ function fix_magic_quotes_4($array, $is_top = true) {
+ $return = array();
+ foreach ($array as $key => $value) {
+ $clean_key =!$is_top? stripslashes($key): $key;
+ if (is_array($value)) {
+ $clean_value = $this->fix_magic_quotes_4($value, false);
+ } else {
+ $clean_value = stripslashes($value);
+ }
+ $return[$clean_key] = $clean_value;
+ }
+ return $return;
+ }
+
+ function fix_magic_quotes_5($array, $is_top = true) {
+ $return = array();
+ foreach ($array as $key => $value) {
+ if (is_array($value)) {
+ $clean_key =!$is_top? stripslashes($key): $key;
+ $clean_value = $this->fix_magic_quotes_5($value, false);
+ } else {
+ $clean_key = stripslashes($key);
+ $clean_value = stripslashes($value);
+ }
+ $return[$clean_key] = $clean_value;
+ }
+ return $return;
+ }
+
/**
* If magic_quotes_gpc option is on, run the global arrays
* through fix_magic_quotes to strip out the stupid slashes.
@@ -72,12 +107,27 @@
*/
function checkMagicQuotes() {
if ( get_magic_quotes_gpc() ) {
- $this->fix_magic_quotes( $_COOKIE );
- $this->fix_magic_quotes( $_ENV );
- $this->fix_magic_quotes( $_GET );
- $this->fix_magic_quotes( $_POST );
- $this->fix_magic_quotes( $_REQUEST );
- $this->fix_magic_quotes( $_SERVER );
+ //I would rather do it this way, but supposedly, version_compare
+ //is more accurate:
+ //$php_version = substr(PHP_VERSION,0,strpos(PHP_VERSION,'.'));
+ if (version_compare(PHP_VERSION, '4', '>=') && version_compare(PHP_VERSION, '5', '<')) {
+ //it is PHP4
+ $_COOKIE = $this->fix_magic_quotes_4( $_COOKIE );
+ $_ENV = $this->fix_magic_quotes_4( $_ENV );
+ $_GET = $this->fix_magic_quotes_4( $_GET );
+ $_POST = $this->fix_magic_quotes_4( $_POST );
+ $_REQUEST = $this->fix_magic_quotes_4( $_REQUEST );
+ $_SERVER = $this->fix_magic_quotes_4( $_SERVER );
+ } elseif (version_compare(PHP_VERSION, '5', '>=') && version_compare(PHP_VERSION, '6', '<')) {
+ //it is PHP5
+ $_COOKIE = $this->fix_magic_quotes_5( $_COOKIE );
+ $_ENV = $this->fix_magic_quotes_5( $_ENV );
+ $_GET = $this->fix_magic_quotes_5( $_GET );
+ $_POST = $this->fix_magic_quotes_5( $_POST );
+ $_REQUEST = $this->fix_magic_quotes_5( $_REQUEST );
+ $_SERVER = $this->fix_magic_quotes_5( $_SERVER );
+ }
+ //behavior for PHP3 and PHP6 is undefined, so don't do any fixing
}
}
原文参见: SpecialUploadLocal


