Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F2212
SpecialExport.php
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:04 (UTC+0)
Size
24 KB
Referenced Files
None
Subscribers
None
SpecialExport.php
View Options
<?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/
#
# 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; either version 2 of the License, or
# (at your option) any later version.
#
# 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.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# http://www.gnu.org/copyleft/gpl.html
/**
*
* @package MediaWiki
* @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
$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"
);
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
);
$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
();
// 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' {$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 />
"
);
}
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 />
"
);
}
/*
* === 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
*/
}
/**#@-*/
/**#@+
* @access private
*/
/**
* @var function
*/
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,
* provide a database connection which is not managed by
* LoadBalancer to read from: some history blob types will
* make additional queries to pull source data while the
* main query is still running.
*
* @param Database $db
* @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
)
{
$this
->
db
=&
$db
;
$this
->
history
=
$history
;
$this
->
buffer
=
$buffer
;
}
/**
* Set a callback to be called after each page in the output
* stream is closed. The callback will be passed a database row
* object with the last revision output.
*
* A set callback can be removed by passing null here.
*
* @param mixed $callback
*/
function
setPageCallback
(
$callback
)
{
$this
->
pageCallback
=
$callback
;
}
/**
* Set a callback to be called after each revision in the output
* stream is closed. The callback will be passed a database row
* object with the revision data.
*
* A set callback can be removed by passing null here.
*
* @param mixed $callback
*/
function
setRevisionCallback
(
$callback
)
{
$this
->
revCallback
=
$callback
;
}
/**
* Returns the export schema version.
* @return string
*/
function
schemaVersion
()
{
return
"0.3"
;
}
/**
* Opens the XML output stream's root <mediawiki> element.
* This does not include an xml directive, so is safe to include
* as a subelement in a larger XML stream. Namespace and XML Schema
* references are included.
*
* To capture the stream to a string, use PHP's output buffering
* functions. Output will be encoded in UTF-8.
*/
function
openStream
()
{
global
$wgContLanguageCode
;
$ver
=
$this
->
schemaVersion
();
print
wfElement
(
'mediawiki'
,
array
(
'xmlns'
=>
"http://www.mediawiki.org/xml/export-$ver/"
,
'xmlns:xsi'
=>
"http://www.w3.org/2001/XMLSchema-instance"
,
'xsi:schemaLocation'
=>
"http://www.mediawiki.org/xml/export-$ver/ "
.
"http://www.mediawiki.org/xml/export-$ver.xsd"
,
'version'
=>
$ver
,
'xml:lang'
=>
$wgContLanguageCode
),
null
)
.
"
\n
"
;
$this
->
siteInfo
();
}
function
siteInfo
()
{
$info
=
array
(
$this
->
sitename
(),
$this
->
homelink
(),
$this
->
generator
(),
$this
->
caseSetting
(),
$this
->
namespaces
()
);
print
"<siteinfo>
\n
"
;
foreach
(
$info
as
$item
)
{
print
" $item
\n
"
;
}
print
"</siteinfo>
\n
"
;
}
function
sitename
()
{
global
$wgSitename
;
return
wfElement
(
'sitename'
,
array
(),
$wgSitename
);
}
function
generator
()
{
global
$wgVersion
;
return
wfElement
(
'generator'
,
array
(),
"MediaWiki $wgVersion"
);
}
function
homelink
()
{
$page
=
Title
::
newFromText
(
wfMsgForContent
(
'mainpage'
)
);
return
wfElement
(
'base'
,
array
(),
$page
->
getFullUrl
()
);
}
function
caseSetting
()
{
global
$wgCapitalLinks
;
// "case-insensitive" option is reserved for future
$sensitivity
=
$wgCapitalLinks
?
'first-letter'
:
'case-sensitive'
;
return
wfElement
(
'case'
,
array
(),
$sensitivity
);
}
function
namespaces
()
{
global
$wgContLang
;
$spaces
=
"<namespaces>
\n
"
;
foreach
(
$wgContLang
->
getNamespaces
()
as
$ns
=>
$title
)
{
$spaces
.=
' '
.
wfElement
(
'namespace'
,
array
(
'key'
=>
$ns
),
str_replace
(
'_'
,
' '
,
$title
)
)
.
"
\n
"
;
}
$spaces
.=
" </namespaces>"
;
return
$spaces
;
}
/**
* Closes the output stream with the closing root element.
* Call when finished dumping things.
*/
function
closeStream
()
{
print
"</mediawiki>
\n
"
;
}
/**
* Dumps a series of page and revision records for all pages
* in the database, either including complete history or only
* the most recent version.
*
*
* @param Database $db
*/
function
allPages
()
{
return
$this
->
dumpFrom
(
''
);
}
/**
* @param Title $title
*/
function
pageByTitle
(
$title
)
{
return
$this
->
dumpFrom
(
'page_namespace='
.
$title
->
getNamespace
()
.
' AND page_title='
.
$this
->
db
->
addQuotes
(
$title
->
getDbKey
()
)
);
}
function
pageByName
(
$name
)
{
$title
=
Title
::
newFromText
(
$name
);
if
(
is_null
(
$title
)
)
{
return
WikiError
(
"Can't export invalid title"
);
}
else
{
return
$this
->
pageByTitle
(
$title
);
}
}
function
pagesByName
(
$names
)
{
foreach
(
$names
as
$name
)
{
$this
->
pageByName
(
$name
);
}
}
// -------------------- private implementation below --------------------
/**#@+
* @access private
*/
function
dumpFrom
(
$cond
=
''
)
{
$fname
=
'WikiExporter::dumpFrom'
;
wfProfileIn
(
$fname
);
$page
=
$this
->
db
->
tableName
(
'page'
);
$revision
=
$this
->
db
->
tableName
(
'revision'
);
$text
=
$this
->
db
->
tableName
(
'text'
);
if
(
$this
->
history
==
MW_EXPORT_FULL
)
{
$join
=
'page_id=rev_page'
;
}
elseif
(
$this
->
history
==
MW_EXPORT_CURRENT
)
{
$join
=
'page_id=rev_page AND page_latest=rev_id'
;
}
else
{
wfProfileOut
(
$fname
);
return
new
WikiError
(
"$fname given invalid history dump type."
);
}
$where
=
(
$cond
==
''
)
?
''
:
"$cond AND"
;
if
(
$this
->
buffer
==
MW_EXPORT_STREAM
)
{
$prev
=
$this
->
db
->
bufferResults
(
false
);
}
if
(
$cond
==
''
)
{
// Optimization hack for full-database dump
$pageindex
=
'FORCE INDEX (PRIMARY)'
;
$revindex
=
'FORCE INDEX(page_timestamp)'
;
}
else
{
$pageindex
=
''
;
$revindex
=
''
;
}
$result
=
$this
->
db
->
query
(
"SELECT * FROM
$page $pageindex,
$revision $revindex,
$text
WHERE $where $join AND rev_text_id=old_id
ORDER BY page_id"
,
$fname
);
$wrapper
=
$this
->
db
->
resultObject
(
$result
);
$this
->
outputStream
(
$wrapper
);
if
(
$this
->
buffer
==
MW_EXPORT_STREAM
)
{
$this
->
db
->
bufferResults
(
$prev
);
}
wfProfileOut
(
$fname
);
}
/**
* Runs through a query result set dumping page and revision records.
* The result set should be sorted/grouped by page to avoid duplicate
* page records in the output.
*
* The result set will be freed once complete. Should be safe for
* streaming (non-buffered) queries, as long as it was made on a
* separate database connection not managed by LoadBalancer; some
* blob storage types will make queries to pull source data.
*
* @param ResultWrapper $resultset
*/
function
outputStream
(
$resultset
)
{
$last
=
null
;
while
(
$row
=
$resultset
->
fetchObject
()
)
{
if
(
is_null
(
$last
)
||
$last
->
page_namespace
!=
$row
->
page_namespace
||
$last
->
page_title
!=
$row
->
page_title
)
{
if
(
isset
(
$last
)
)
{
$this
->
closePage
(
$last
);
}
$this
->
openPage
(
$row
);
$last
=
$row
;
}
$this
->
dumpRev
(
$row
);
}
if
(
isset
(
$last
)
)
{
$this
->
closePage
(
$last
);
}
$resultset
->
free
();
}
/**
* Opens a <page> section on the output stream, with data
* from the given database row.
*
* @param object $row
*/
function
openPage
(
$row
)
{
print
"<page>
\n
"
;
$title
=
Title
::
makeTitle
(
$row
->
page_namespace
,
$row
->
page_title
);
print
' '
.
wfElementClean
(
'title'
,
array
(),
$title
->
getPrefixedText
()
)
.
"
\n
"
;
print
' '
.
wfElement
(
'id'
,
array
(),
$row
->
page_id
)
.
"
\n
"
;
if
(
''
!=
$row
->
page_restrictions
)
{
print
' '
.
wfElement
(
'restrictions'
,
array
(),
$row
->
page_restrictions
)
.
"
\n
"
;
}
}
/**
* Closes a <page> section on the output stream.
* If a per-page callback has been set, it will be called
* and passed the last database row used for this page.
*
* @param object $row
*/
function
closePage
(
$row
)
{
print
"</page>
\n
"
;
if
(
isset
(
$this
->
pageCallback
)
)
{
call_user_func
(
$this
->
pageCallback
,
$row
);
}
}
/**
* Dumps a <revision> section on the output stream, with
* data filled in from the given database row.
*
* @param object $row
*/
function
dumpRev
(
$row
)
{
$fname
=
'WikiExporter::dumpRev'
;
wfProfileIn
(
$fname
);
print
" <revision>
\n
"
;
print
" "
.
wfElement
(
'id'
,
null
,
$row
->
rev_id
)
.
"
\n
"
;
$ts
=
wfTimestamp2ISO8601
(
$row
->
rev_timestamp
);
print
" "
.
wfElement
(
'timestamp'
,
null
,
$ts
)
.
"
\n
"
;
print
" <contributor>"
;
if
(
$row
->
rev_user
)
{
print
wfElementClean
(
'username'
,
null
,
$row
->
rev_user_text
);
print
wfElement
(
'id'
,
null
,
$row
->
rev_user
);
}
else
{
print
wfElementClean
(
'ip'
,
null
,
$row
->
rev_user_text
);
}
print
"</contributor>
\n
"
;
if
(
$row
->
rev_minor_edit
)
{
print
" <minor/>
\n
"
;
}
if
(
$row
->
rev_comment
!=
''
)
{
print
" "
.
wfElementClean
(
'comment'
,
null
,
$row
->
rev_comment
)
.
"
\n
"
;
}
$text
=
Revision
::
getRevisionText
(
$row
);
print
" "
.
wfElementClean
(
'text'
,
array
(
'xml:space'
=>
'preserve'
),
$text
)
.
"
\n
"
;
print
" </revision>
\n
"
;
wfProfileOut
(
$fname
);
if
(
isset
(
$this
->
revCallback
)
)
{
call_user_func
(
$this
->
revCallback
,
$row
);
}
}
/**#@-*/
}
/**
* @param string $ts
* @return string
*/
function
wfTimestamp2ISO8601
(
$ts
)
{
#2003-08-05T18:30:02Z
return
preg_replace
(
'/^(....)(..)(..)(..)(..)(..)$/'
,
'$1-$2-$3T$4:$5:$6Z'
,
$ts
);
}
/*
* ==== 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
(
'/[ÄÖÜäöü]/'
,
'
\0
e'
,
$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
);
/**
* The page may contain old data which has not been properly normalized.
* Invalid UTF-8 sequences or forbidden control characters will make our
* XML output invalid, so be sure to strip them out.
*/
$string
=
UtfNormal
::
cleanUp
(
$string
);
$string
=
htmlspecialchars
(
$string
);
wfProfileOut
(
$fname
);
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-php
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1789
Default Alt Text
SpecialExport.php (24 KB)
Attached To
Mode
T5173: Add Content Disposition to XML export (proposed patch included)
Attached
Detach File
Event Timeline
Log In to Comment