Extension:SpecialMultiUploadViaZip

Special:MultiUploadViaZip is a special page written by User:dme26 that closely resembles the Special:Upload page but accepts a ZIP file rather than target media directly. This ZIP file is decompressed on the server and passed file by file into the existing MediaWiki Special:Upload page. It effects multiple file uploads (aka mass upload, bulk upload, etc).

Because its implementation is so simple (i.e. it's a complete hack!), it does not provide useful feedback about which files from the ZIP file that might not have been successfully accepted. Indeed, when a MultiUploadViaZip invocation is successful, the web-page returned will be that of the final file passed successfully through the MediaWiki Special:Upload page.

I don't generally need this feedback, and can't currently spend the time to learn about the right parts of the Mediawiki internals to fix this, but it is definitely something that would need to be improved were this script to be used widely.

The Special:MultiUploadViaZip page includes a prefix field that prepends the provided string onto all filenames expanded from the ZIP file.

Internally this special page extends the Special:Upload classes to facilitate its script-driven uploads. Some of the fields the Upload form accepts, notably the description field, are passed identically to the Upload form for each file decompressed from the ZIP file. I usually insert a category tag into this description field, so that the collection of uploaded images are grouped in terms of MediaWiki categories.

The usual PHP upload limits will be applied to uploaded ZIP files.

NOTE: There is currently no check against the size of files during the decompression process. This could fairly easily lead to DoS attacks. As Erik Moeller helpfully points out, this could be quite simply defeated by adding a check against the  variable in the code below. I haven't done this yet, but please feel free to do so, or I'll eventually do it - the file-size limit should presumably be the same as one of the existing PHP configuration variables.

Motivation
This approach has many rough edges - my guess is that this function will quickly appear in the core MediaWiki release developed by those with a far better roadmap of MediaWiki internals than I have. I needed the function right away, though, so thought I should provide it anyway for whatever interest or convenience it might raise.

Note that I only run this extension on intranet wikis, and only then after authenticating users. Many aspects of its implementation could be easily and usefully improved.

In the code the marker "dme26" is used to identify code modifications I've made within long blocks of source copied from existing files - in these cases the original class hierarchy did not allow me to selectively override what I needed to.

I recently discovered SpecialUploadLocal (and used its description to structure this page). It strikes me these two approaches could be easily and usefully merged if they haven't been already...

Alternative solution
See Uploadmultiple.py for a Python script that allows you to mass-upload images using a bot.

Installation
Place  into your directory. As usual for extensions, place within your  file the line:

You will need to ensure your PHP installation includes Zip file functions. On Windows machines one needs to ensure  is appropriately included through your. The Unix managed hosts I've used seem generally to have this support out of the box.

Known issues

 * Output from this special page is lost, and no feedback is provided regarding the success of intermediate file uploads. I use the description field on the Special:MultiUploadViaZip page, passed to each upload form, to add a category tag, and thus can browse the category to check all files were successfully uploaded.

License
License details are in the source files (nothing surprising - GPL of course).

Code
For now the code is only provided here. I'd eyeball this page's change log to ensure that you agree with subsequent edits (i.e. those that appear to add code to email your secret data to random-looking IP addresses, etc).

SpecialMultiUploadViaZip.php for MediaWiki 1.6.3
\n" ); }

/**  * Displays the main upload form, optionally with a highlighted * error message up at the top. *  * @param string $msg as HTML * @access private */ function mainUploadForm( $msg='' ) { global $wgOut, $wgUser; global $wgUseCopyrightUpload;

$cols = intval($wgUser->getOption( 'cols' )); $ew = $wgUser->getOption( 'editwidth' ); if ( $ew ) $ew = " style=\"width:100%\""; else $ew = '';

if ( '' != $msg ) { $sub = wfMsgHtml( 'uploaderror' ); $wgOut->addHTML( " {$sub} \n" .       " {$msg} \n" ); }   $wgOut->addHTML( ' ' ); $wgOut->addWikiText( wfMsg( 'uploadtext' ) ); $wgOut->addHTML( ' ' ); $sk = $wgUser->getSkin;

$sourcefilename = wfMsgHtml( 'sourcefilename' ); $destfilename = wfMsgHtml( 'destfilename' ); $fileprefix = wfMsgWikiHtml( 'fromzipfileprefix' ); //dme26 $summary = wfMsgWikiHtml( 'fromzipdescription' ); //dme26

$licenses = new Licenses; $license = wfMsgHtml( 'license' ); $nolicense = wfMsgHtml( 'nolicense' ); $licenseshtml = $licenses->getHtml;

$ulb = wfMsgHtml( 'uploadbtn' );

$titleObj = Title::makeTitle( NS_SPECIAL, 'MultiUploadViaZip' ); $action = $titleObj->escapeLocalURL;

$encDestFile = htmlspecialchars( $this->mDestFile );

$watchChecked = $wgUser->getOption( 'watchdefault' ) ? 'checked="checked"' : '';

$wgOut->addHTML( "   " ); }

}

function wfSpecialMultiUploadViaZip { // Use an UploadZIPForm to acquire a zip file. Then push each file // in the ZIP through an instance of a normal UploadForm.

global $wgRequest; $form = new UploadZIPForm( $wgRequest ); $form->execute; }

SpecialMultiUploadViaZip.php for MediaWiki 1.12
\n" );   }

/**    * Displays the main upload form, optionally with a highlighted * error message up at the top. *    * @param string $msg as HTML * @access private */   function mainUploadForm( $msg='' ) { global $wgOut, $wgUser; global $wgUseCopyrightUpload;

$cols = intval($wgUser->getOption( 'cols' )); $ew = $wgUser->getOption( 'editwidth' ); if ( $ew ) $ew = " style=\"width:100%\""; else $ew = '';

if ( '' != $msg ) { $sub = wfMsgHtml( 'uploaderror' ); $wgOut->addHTML( " {$sub} \n" .       " {$msg} \n" ); }       $wgOut->addHTML( ' ' ); $wgOut->addWikiText( wfMsg( 'uploadtext' ) ); $wgOut->addHTML( ' ' ); $sk = $wgUser->getSkin;

$sourcefilename = wfMsgHtml( 'sourcefilename' ); $destfilename = wfMsgHtml( 'destfilename' ); $fileprefix = wfMsgWikiHtml( 'fromzipfileprefix' ); //dme26 $summary = wfMsgWikiHtml( 'fromzipdescription' ); //dme26

$licenses = new Licenses; $license = wfMsgHtml( 'license' ); $nolicense = wfMsgHtml( 'nolicense' ); $licenseshtml = $licenses->getHtml;

$ulb = wfMsgHtml( 'uploadbtn' );

$titleObj = Title::makeTitle( NS_SPECIAL, 'MultiUploadViaZip' ); $action = $titleObj->escapeLocalURL;

$encDestFile = htmlspecialchars( $this->mDesiredDestName );

$watchChecked = $wgUser->getOption( 'watchdefault' ) ? 'checked="checked"' : '';

$wgOut->addHTML( "         " ); }

}

function wfSpecialMultiUploadViaZip { // Use an UploadZIPForm to acquire a zip file. Then push each file // in the ZIP through an instance of a normal UploadForm.

global $wgRequest; $form = new UploadZIPForm( $wgRequest ); $form->execute; }