Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F2217
SpecialExport.diff
Public
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Authored By
•
bzimport
Nov 21 2014, 8:45 PM
2014-11-21 20:45:05 (UTC+0)
Size
17 KB
Referenced Files
None
Subscribers
None
SpecialExport.diff
View Options
--- mediawiki-1.5beta4/includes/SpecialExport.php 2005-07-13 03:59:12.000000000 +0200
+++ mwMM/applic/includes/SpecialExport.php 2005-08-20 17:45:52.867577320 +0200
@@ -1,4 +1,18 @@
<?php
+/*
+* ==== comments to be removed when patch is accepted :
+* this patch also assumes small patches in :
+* - Defines.php
+* - DefaultSettings.php
+** $wgSpecialExportDownload = MW_EXPORT_DISPO_SUGGESTED ;
+** $wgSpecialExportFilename = MW_EXPORT_FILENAME_DEFAULT ;
+** $wgSpecialExportPrefix = MW_EXPORT_DEFAULT_PREFIX ;
+* - Language.php (+ LanguageFr.php, De, etc)
+** exportpromptdisposition
+** exportpromptfilename
+** exportsubmit
+*/
+
# Copyright (C) 2003 Brion Vibber <brion@pobox.com>
# http://www.mediawiki.org/
#
@@ -22,64 +36,349 @@
* @subpackage SpecialPage
*/
+# This is not a valid entry point, perform no further processing unless MEDIAWIKI is defined
+if( !defined( 'MEDIAWIKI' ) ) {
+ die( "This file is part of MediaWiki and is not a valid entry point\n" );
+}
+
/** */
require_once( 'Revision.php' );
+/*
+* ==== comment to be removed after patch acceptance ====
+* why not just boolean's for the related parameters ?
+* do we expect other values ?
+*/
+define( 'MW_EXPORT_FULL', 0 );
+define( 'MW_EXPORT_CURRENT', 1 );
+
+define( 'MW_EXPORT_BUFFER', 0 );
+define( 'MW_EXPORT_STREAM', 1 );
+
+/*
+* ==== comment to be removed after patch acceptance ===
+* wfSpecialExport does 4 things :
+* 1 - process the request and/or the config parameters
+* 2 - send HTTP header(s)
+* 3 - send the XML output
+* 4 - build the form
+* Because this patch increases a little bit tasks 1, 2 and 4,
+* it seems more convenient to leave task 1 here,
+* but to move tasks 2, 3 and 4 in separate functions.
+* In order to avoid wfXxx name space pollution, these 3 functions
+* are created as static function of class WikiExporter
+* doHeaders() , doExport() , doForm
+*/
+
/**
- *
+ * Entry point
+ * @param $page string
*/
function wfSpecialExport( $page = '' ) {
- global $wgOut, $wgLang, $wgRequest;
+ global $wgRequest;
+
+ // config parameters :
+
+ $wgSpecialExportFilename = is_integer($wgSpecialExportFilename) ?
+ $wgSpecialExportFilename : MW_EXPORT_FILENAME_DEFAULT ;
+ $wgSpecialExportDownload = is_integer($wgSpecialExportDownload) ?
+ $wgSpecialExportDownload : MW_EXPORT_DISPO_DEFAULT ;
+ $wgSpecialExportPrefix = is_string($wgSpecialExportPrefix) ?
+ $wgSpecialExportPrefix : MW_EXPORT_DEFAULT_PREFIX ;
+
+ // proceed/prepare request :
if( $wgRequest->getVal( 'action' ) == 'submit') {
$page = $wgRequest->getText( 'pages' );
$curonly = $wgRequest->getCheck( 'curonly' );
+ $szRequesXmlFileName = $wgRequest->getText( 'szXmlFileName' );
+ $zRequestDispo = $wgRequest->getCheck( 'zDispo' );
} else {
# Pre-check the 'current version only' box in the UI
$curonly = true;
}
if( $page != '' ) {
+
+ // output HTTP header(s) :
+
+ WikiExporter::doHeaders(
+ // $zXmlDisposition = true // shall we use Content-Disposition ?
+ (( $wgSpecialExportDownload == MW_EXPORT_DISPO_ALLWAYS) || $zRequestDispo )
+ // , $szSuggestedPrefix = MW_EXPORT_DEFAULT_PREFIX
+ , $wgSpecialExportPrefix
+ // , $zDate = true
+ , (($wgSpecialExportFilename == MW_EXPORT_FILENAME_ASK_ELSE_TIMESTAMP)
+ || ($wgSpecialExportFilename == MW_EXPORT_FILENAME_TIMESTAMP))
+ , $szXmlFileName
+ // , $zRelyOnFileName = false
+ // , $uMaxLength = 250 // RARELY USED !
+ // , $zGerman = true // RARELY USED !
+ ) ;
+
+ // output XML :
+
+ WikiExporter::doExport(
+ $page
+ // , $history = MW_EXPORT_CURRENT
+ , ( $curonly ? MW_EXPORT_CURRENT : MW_EXPORT_FULL )
+ // , $buffer = MW_EXPORT_BUFFER
+ ) ;
+
+ } else {
+
+ // prepare the form :
+
+ WikiExporter::doForm(
+ // $zCurOnly = true // preset value of the 'current v. all' checkbox
+ $curonly
+ // , $zDisposition = true // preset value for the 'download' checkbox
+ , (($wgSpecialExportDownload == MW_EXPORT_DISPO_SUGGESTED) || $zRequestDispo)
+ // , $szXmlDispositionFileName = '' // preset value for the file name
+ , $szXmlFileName
+ // , $zAskFilename = true // shall we prompt the user for a filename?
+ , (($wgSpecialExportFilename == MW_EXPORT_FILENAME_ASK_ELSE_TIMESTAMP)
+ || ($wgSpecialExportFilename == MW_EXPORT_FILENAME_ASK_ELSE_RANDOM))
+ // , $zAskDisposition = true // shall we prompt the user for download?
+ , (($wgSpecialExportDownload == MW_EXPORT_DISPO_PERHAPS)
+ || ($wgSpecialExportDownload == MW_EXPORT_DISPO_SUGGESTED))
+ // , $szSuggestedPrefix = MW_EXPORT_DEFAULT_PREFIX
+ , $wgSpecialExportPrefix
+ // , $zDate = true
+ , (($wgSpecialExportFilename == MW_EXPORT_FILENAME_ASK_ELSE_TIMESTAMP)
+ || ($wgSpecialExportFilename == MW_EXPORT_FILENAME_TIMESTAMP))
+ // , $zRelyOnFileName = false
+ // , $uMaxLength = 250 // RARELY USED !
+ // , $zGerman = true // RARELY USED !
+ ) ;
+ }
+}
+
+/**
+ * @package MediaWiki
+ * @subpackage SpecialPage
+ */
+class WikiExporter {
+ /**#@+
+ * @access public
+ * @static
+ */
+
+ /**
+ * @param boolean $zXmlDisposition : shall we use Content-Disposition ?
+ * @param string $szSuggestedPrefix
+ * @param boolean $zDate : use a timestamp (otherwise use a random value)
+ * @param string $szXmlDispositionFileName
+ * @param boolean $zRelyOnFileName (turn on if you are sure file name is ok, probably beacause it was generated automatically)
+ * @param unsigned $uMaxLength (RARE) Maximum filename length. Default is 250 characters.
+ * @param boolean $zGerman (RARE) proceed also german characters
+ */
+ function doHeaders(
+ $zXmlDisposition = true // shall we use Content-Disposition ?
+ , $szSuggestedPrefix = MW_EXPORT_DEFAULT_PREFIX
+ , $zDate = true
+ , $szXmlDispositionFileName = ''
+ , $zRelyOnFileName = false
+ , $uMaxLength = 250 // RARELY USED !
+ , $zGerman = true // RARELY USED !
+ )
+ {
+ global $wgOut ;
$wgOut->disable();
header( "Content-type: application/xml; charset=utf-8" );
- $pages = explode( "\n", $page );
+ if($zXmlDisposition)
+ {
+ if( ! $zRelyOnFileName )
+ {
+ $szXmlDispositionFileName = wfUnixFileName(
+ $szXmlDispositionFileName,$uMaxLength,$zGerman) ;
+ }
+ if(! $szXmlDispositionFileName)
+ {
+ $szXmlDispositionFileName = wfSuggestFileName(
+ $szSuggestedPrefix,$zDate,$uMaxLength) ;
+ }
+ header("Content-Disposition: attachment; filename=\"{$szXmlDispositionFileName}\"'");
+ }
+ }
+ /**
+ * factorize and run...
+ *
+ * @param string $page
+ * @param unsigned $history one of MW_EXPORT_FULL or MW_EXPORT_CURRENT
+ * @param unsigned $buffer one of MW_EXPORT_BUFFER or MW_EXPORT_STREAM
+ */
+ function doExport(
+ $page
+ /*
+ * ==== comment to be removed after patch acceptance ====
+ * why not just boolean's for these 2 parameters ?
+ */
+ , $history = MW_EXPORT_CURRENT
+ , $buffer = MW_EXPORT_BUFFER
+ )
+ {
+ $pages = explode( "\n", $page );
$db =& wfGetDB( DB_SLAVE );
- $history = $curonly ? MW_EXPORT_CURRENT : MW_EXPORT_FULL;
- $exporter = new WikiExporter( $db, $history );
+ $exporter = new WikiExporter(
+ $db
+ , $history = MW_EXPORT_CURRENT
+ , $buffer = MW_EXPORT_BUFFER
+ );
+ /*
+ * ==== comment to be removed after patch acceptance ====
+ * Mind that openStream() and closeStream() are, in fact, static functions
+ */
$exporter->openStream();
+ // WikiExporter::openStream(); //...
$exporter->pagesByName( $pages );
$exporter->closeStream();
- return;
+ // WikiExporter::closeStream(); //...
}
+ /**
+ * write down the Export form on $wgOut
+ *
+ * @param boolean $curonly ($zCurOnly) preset value of the 'current v. all' checkbox
+ * @param boolean $zDisposition preset value for the 'download' checkbox
+ * @param string $szXmlDispositionFileName preset value for the file name
+ * @param boolean $zAskFilename shall we prompt the user for a filename?
+ * @param boolean $zAskDisposition shall we prompt the user for download?
+ * @param boolean $zDate use time stamp if we need to generate a file name
+ * @param boolean $zRelyOnFileName (turn on if you are sure file name is ok, probably beacause it was generated automatically)
+ * @param unsigned $uMaxLength (rarely used)
+ * @param boolean $zGerman (rarely used)
+ */
+ function doForm(
+ $zCurOnly = true // preset value of the 'current v. all' checkbox
+ , $zDisposition = true // preset value for the 'download' checkbox
+ , $szXmlDispositionFileName = '' // preset value for the file name
+ , $zAskFilename = true // shall we prompt the user for a filename?
+ , $zAskDisposition = true // shall we prompt the user for download?
+ , $szSuggestedPrefix = MW_EXPORT_DEFAULT_PREFIX
+ , $zDate = true
+ , $zRelyOnFileName = false
+ , $uMaxLength = 250 // RARELY USED !
+ , $zGerman = true // RARELY USED !
+ )
+ {
+ global $wgOut ;
+
$wgOut->addWikiText( wfMsg( "exporttext" ) );
$titleObj = Title::makeTitle( NS_SPECIAL, "Export" );
$action = $titleObj->escapeLocalURL( 'action=submit' );
+ /*
+ * === comment to be removed after patch acceptance :
+ * there was a minor bug here : $curonly was ignored
+ */
+ $szCurOnlyChecked = $zCurOnly ? " checked='checked' " : '' ;
+ $szPromptCurOnly = wfMsg( "exportcuronly" ) ;
$wgOut->addHTML( "
<form method='post' action=\"$action\">
<input type='hidden' name='action' value='submit' />
<textarea name='pages' cols='40' rows='10'></textarea><br />
-<label><input type='checkbox' name='curonly' value='true' checked='checked' />
-" . wfMsg( "exportcuronly" ) . "</label><br />
-<input type='submit' />
-</form>
+<label><input type='checkbox' name='curonly' value='true' {$szCurOnlyChecked} />
+{$szPromptCurOnly}</label><br />
+" ) ;
+
+ if($zAskDisposition)
+ {
+ /*
+ * === comment to be removed after patch acceptance :
+ * === Mind that 'exportpromptdisposition' is a NEW message.
+ */
+ $szPromptDisposition = wfMsg('exportpromptdisposition') ;
+ $szDispositionChecked = $zDisposition ? " checked='checked' " : '' ;
+ $wgOut->addHTML( "
+<label><input type='checkbox' name='zDispo' value='true' {$szDispositionChecked} />
+{$szPromptDisposition}</label><br />
" );
-}
+ }
-define( 'MW_EXPORT_FULL', 0 );
-define( 'MW_EXPORT_CURRENT', 1 );
+ if($zAskFilename)
+ {
+ /*
+ * === comment to be removed after patch acceptance :
+ * === Mind that 'exportpromptfilename' is a NEW message.
+ */
+ $szPromptFilename = wfMsg('exportpromptfilename') ;
+ if( ! $zRelyOnFileName )
+ {
+ /*
+ $szXmlDispositionFileName may perfectly be empty.
+ However, if it is provided, then it MUST be ok!
+ It is probably already builded automatically and correct.
+ Anyway, we still make an ultimate checking.
+ */
+ $szXmlDispositionFileName = trim($szXmlDispositionFileName) ;
+ if($szXmlDispositionFileName)
+ {
+ $szXmlDispositionFileName = wfUnixFileName($szXmlDispositionFileName,$uMaxLength,$zGerman) ;
+ }
+ }
+ if(! $szXmlDispositionFileName)
+ {
+ $szXmlDispositionFileName = wfSuggestFileName($szSuggestedPrefix,$zDate,$uMaxLength) ;
+ }
+ $wgOut->addHTML( "
+<label>{$szPromptFilename}</label>
+<input type='text' name='szXmlFileName' value='{$szXmlDispositionFileName}' size='40' />
+<br />
+" );
+ }
-define( 'MW_EXPORT_BUFFER', 0 );
-define( 'MW_EXPORT_STREAM', 1 );
+ /*
+ * === comment to be removed after patch acceptance :
+ * === Mind that 'exportsubmit' is a NEW message.
+ * The reason is that, at least in french, standard words often used on submit buttons
+ * such as 'submit', 'send', 'apply', 'transmit' are very ambiguous.
+ * 'Send' is generally translated by 'Envoyer'.
+ * But what means 'envoyer'? From where/who? To where/who?
+ * Why not 'receive' or 'recevoir' ? etc
+ * An *explicit* word such as 'Export', 'Import', 'Download', 'Upload'
+ * must absolutely be used (at least in some languages)...
+ */
+ $szSubmit = wfMsg('exportsubmit') ;
+ $wgOut->addHTML( "
+<input type='submit' value='{$szSubmit}' />
+</form>
+" );
+ /*
+ * ==== comments to be removed when patch is accepted :
+ * Mind the 3 new messages (see Language.php)
+ * - exportpromptdisposition
+ * - exportpromptfilename
+ * - exportsubmit
+ */
+ }
-/**
- * @package MediaWiki
- * @subpackage SpecialPage
+ /**#@-*/
+
+ /**#@+
+ * @access private
+ */
+ /**
+ * @var function
*/
-class WikiExporter {
var $pageCallback = null;
+ /**
+ * @var function
+ */
var $revCallback = null;
+ /**
+ * @var unsigned mode
+ */
+ var $history ;
+ /**
+ * @var unsigned mode
+ */
+ var $buffer ;
+ /**
+ * @var Database
+ */
+ var $db ;
+ /**#@-*/
/**
* If using MW_EXPORT_STREAM to stream a large amount of data,
@@ -89,11 +388,14 @@
* main query is still running.
*
* @param Database $db
- * @param int $history one of MW_EXPORT_FULL or MW_EXPORT_CURRENT
- * @param int $buffer one of MW_EXPORT_BUFFER or MW_EXPORT_STREAM
+ * @param unsigned $history one of MW_EXPORT_FULL or MW_EXPORT_CURRENT
+ * @param unsigned $buffer one of MW_EXPORT_BUFFER or MW_EXPORT_STREAM
*/
- function WikiExporter( &$db, $history = MW_EXPORT_CURRENT,
- $buffer = MW_EXPORT_BUFFER ) {
+ function WikiExporter(
+ &$db
+ , $history = MW_EXPORT_CURRENT
+ , $buffer = MW_EXPORT_BUFFER
+ ) {
$this->db =& $db;
$this->history = $history;
$this->buffer = $buffer;
@@ -251,6 +553,10 @@
// -------------------- private implementation below --------------------
+ /**#@+
+ * @access private
+ */
+
function dumpFrom( $cond = '' ) {
$fname = 'WikiExporter::dumpFrom';
wfProfileIn( $fname );
@@ -308,7 +614,6 @@
* blob storage types will make queries to pull source data.
*
* @param ResultWrapper $resultset
- * @access private
*/
function outputStream( $resultset ) {
$last = null;
@@ -335,7 +640,6 @@
* from the given database row.
*
* @param object $row
- * @access private
*/
function openPage( $row ) {
print "<page>\n";
@@ -354,7 +658,6 @@
* and passed the last database row used for this page.
*
* @param object $row
- * @access private
*/
function closePage( $row ) {
print "</page>\n";
@@ -368,7 +671,6 @@
* data filled in from the given database row.
*
* @param object $row
- * @access private
*/
function dumpRev( $row ) {
$fname = 'WikiExporter::dumpRev';
@@ -409,14 +711,111 @@
}
}
+ /**#@-*/
}
+/**
+* @param string $ts
+* @return string
+*/
function wfTimestamp2ISO8601( $ts ) {
#2003-08-05T18:30:02Z
return preg_replace( '/^(....)(..)(..)(..)(..)(..)$/', '$1-$2-$3T$4:$5:$6Z', $ts );
}
-function xmlsafe( $string ) {
+/*
+* ==== comment to be removed after patch acceptance ====
+* The next 3 global functions are, in my personal implementation,
+* located, for reusability, in includes/GlobalFunctions.php rather than here
+* because they can be usefull eveywhere there is a need to build a filename.
+* Mind that we voluntary divide into 3 functions as to improve reability.
+* I suggest to move these 3 functions into GlobalFunctions.php
+*/
+
+/**
+* Generates a unique file name e.g. for a downloaded file
+*
+* @param string $szSuggestedPrefix
+* @param boolean $zDate : use a timestamp (otherwise use a random value)
+* @param unsigned $uMaxLength Maximum filename length. Default is 250 characters.
+* @return string generated file name
+*/
+function wfSuggestFileName(
+$szPrefix = MW_EXPORT_DEFAULT_PREFIX
+, $zDate = true
+, $uMaxLength = 250
+)
+{
+ $szName = $szPrefix . '-' . ( $zDate ? date("Y-m-d-H-i-s") : mt_rand(1234567,9876543) ) ;
+ // still verify : illegal prefix ? length ?
+ return wfUnixFileName($szName,$uMaxLength) ;
+}
+
+/**
+* Generates an usefull Unix filename besides the original one.
+*
+* @param string $szName The filename to be processed.
+* @param unsigned $uMaxLength Maximum filename length. Default is 250 characters.
+* @param boolean $zGerman proceed also german characters
+* @return string
+*/
+function wfUnixFileName(
+$szName
+, $uMaxLength = 250
+, $zGerman= true
+)
+{
+ $uMaxLength = max(1,min(250,$uMaxLength)) ;
+ // remove accents :
+ $szName = wfRemoveAccents($szName,$zGerman) ;
+ // Replace any remaining special characters with an underscore.
+ $szName = preg_replace('/[^a-z0-9.-]+/i', '_', $szName);
+ // Remove any useless underscores, e.g. _a_a_._a_ becomes a_a.a
+ $szName = preg_replace('/_*\b_*/', '', $szName);
+ // Crop the filename if it's too long.
+ while (strlen($szName) > $uMaxLength)
+ $szName = preg_replace('/.\b/', '', $szName, 1);
+ return $szName;
+}
+
+/**
+* wfRemoveAccents replaces some special 'european' characters
+* so that a name may be used e.g. to build a file name.
+*
+* Mind that the returned string has the same length of the original
+* if $zGerman==false, but may have a different length otherwise.
+*
+* @param string $szName a name with accents
+* @param boolean $zGerman proceed also german characters
+* @return string the name with accents removed (replacing)
+*/
+function wfRemoveAccents($szName, $zGerman=true)
+{
+ if($zGerman)
+ {
+ // Replace German umlauts and other special characters.
+ $szName = str_replace("ß", "ss", $szName);
+ $szName = preg_replace('/[ÄÖÜäöü]/', '\0e', $szName);
+ }
+ // Proceed accents, etc
+ $szName = strtr($szName,
+ "ÀÁÂÃÄÅÆÈÉÊËÌÍÎÏÒÓÔÕÖØÙÚÛÜàáâãäåæèéêëìíîïòóôõöøùúûüçÇß",
+ "AAAAAAAEEEEIIIIOOOOOOUUUUaaaaaaaeeeeiiiioooooouuuucCs");
+ /*
+ * Mind that the process of "ß", "ü", etc is different if 'german' is on or off!
+ */
+ return $szName ;
+}
+
+/**
+* Function 'xmlsafe' UNUSED, renamed to wfXmlSafe to stick to mw conventions
+*
+* @param string $string
+* @return string $string
+* @todo move function into WikiExporter class or decide to rename as wfXmlSafe
+* @todo this function is currently unused...
+*/
+function wfXmlSafe( $string ) {
$fname = 'xmlsafe';
wfProfileIn( $fname );
@@ -432,4 +831,11 @@
return $string;
}
+/**
+* ==== comment to be removed after patch acceptance ====
+* I systematically destroy whitespaces after the final ? >
+* These caracters are generally harmless.
+* However, in some applications (cookies, headers) they are dangerous.
+* So, it's a matter of principle : just delete them eveywhere
+*/
?>
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1794
Default Alt Text
SpecialExport.diff (17 KB)
Attached To
Mode
T5173: Add Content Disposition to XML export (proposed patch included)
Attached
Detach File
Event Timeline
Log In to Comment