Update to MediaWiki 1.35.0

This commit is contained in:
Jakub Klinkovský 2020-10-26 13:23:55 +01:00 committed by Pierre Schmitz
parent 8b665f5f37
commit 1848986dac
15042 changed files with 1515243 additions and 330942 deletions

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
root = true
[*]
indent_style = tab
indent_size = tab
tab_width = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

16
.eslintignore Normal file
View File

@ -0,0 +1,16 @@
# Upstream code
/resources/lib/
/resources/src/jquery.tipsy/
/resources/src/mediawiki.libs.jpegmeta/
# Skip function
/resources/src/skip-Promise.js
# Build tooling
/docs/
/vendor/
/tests/coverage/
/tests/phpunit/data/registration/duplicate_keys.json
# Nested projects
/extensions/
/skins/

18
.eslintrc.json Normal file
View File

@ -0,0 +1,18 @@
{
"extends": [
"wikimedia/client",
"wikimedia/jquery",
"wikimedia/mediawiki",
"wikimedia/jsduck"
],
"globals": {
"require": "readonly",
"module": "readonly"
},
"rules": {
"max-len": "off",
"mediawiki/valid-package-file-require": "off",
"no-jquery/no-global-selector": "off",
"no-shadow": "error"
}
}

55
.fresnel.yml Normal file
View File

@ -0,0 +1,55 @@
warmup: true
runs: 7
scenarios:
Read a page:
# The only page that exists by default is the main page.
# But its actual name is configurable/unknown (T216791).
# Omit 'title' to let MediaWiki show the default (which is the main page),
# and a query string to prevent a normalization redirect.
url: "{MW_SERVER}{MW_SCRIPT_PATH}/index.php?noredirectplz"
viewport:
width: 1100
height: 700
reports:
- navtiming
- paint
- transfer
probes:
- screenshot
- trace
Load the editor:
url: "{MW_SERVER}{MW_SCRIPT_PATH}/index.php?action=edit"
viewport:
width: 1100
height: 700
reports:
- navtiming
- paint
- transfer
probes:
- screenshot
- trace
View history of a page:
url: "{MW_SERVER}{MW_SCRIPT_PATH}/index.php?action=history"
viewport:
width: 1100
height: 700
reports:
- navtiming
- paint
- transfer
probes:
- screenshot
- trace
View recent changes:
url: "{MW_SERVER}{MW_SCRIPT_PATH}/index.php?title=Special:RecentChanges"
viewport:
width: 1100
height: 700
reports:
- navtiming
- paint
- transfer
probes:
- screenshot
- trace

513
.mailmap Normal file
View File

@ -0,0 +1,513 @@
# Map author and committer names and email addresses to canonical real names
# and email addresses.
#
# To update the CREDITS file, run maintenance/updateCredits.php
#
# Two types of entries are useful here. The first sets a canonical author
# name for a given email address:
#
# Canonical Author Name <author email>
#
# The second allows collecting alternate email addresses into a single
# canonical author name and email address:
#
# Canonical Author Name <author email> <alternate email>
#
# Mappings are only needed for authors who have used multiple author names
# and/or author emails for revisions over time. Author names beginning with
# "[BOT]" will be omitted from the CREDITS file.
#
# See also: https://git-scm.com/docs/git-shortlog#_mapping_authors
#
[BOT] Gerrit Code Review <gerrit@wikimedia.org>
[BOT] Gerrit Patch Uploader <gerritpatchuploader@gmail.com>
[BOT] jenkins-bot <jenkins-bot@gerrit.wikimedia.org>
[BOT] jenkins-bot <jenkins-bot@gerrit.wikimedia.org> <jenkins-bot@wikimedia.org>
[BOT] Translation updater bot <l10n-bot@translatewiki.net>
[BOT] libraryupgrader <tools.libraryupgrader@tools.wmflabs.org>
Aaron Schulz <aschulz@wikimedia.org>
Aaron Schulz <aschulz@wikimedia.org> <aaron@users.mediawiki.org>
Adam Roses Wight <adam.wight@wikimedia.de>
Adam Roses Wight <adam.wight@wikimedia.de> <awight@wikimedia.org>
Adam Roses Wight <adam.wight@wikimedia.de> <spam@ludd.net>
addshore <addshorewiki@gmail.com>
addshore <addshorewiki@gmail.com> <adamshorland@gmail.com>
Aditya Sastry <ganeshaditya1@gmail.com>
Adrian Heine <adrian.heine@wikimedia.de>
Alangi Derick <alangiderick@gmail.com>
Alex Z. <mrzmanwiki@gmail.com> <mrzman@users.mediawiki.org>
Aleksey Bekh-Ivanov <aleksey.bekh-ivanov@wikimedia.de>
Alexandre Emsenhuber <ialex.wiki@gmail.com>
Alexandre Emsenhuber <ialex.wiki@gmail.com> <ialex@users.mediawiki.org>
Alexandre Emsenhuber <ialex.wiki@gmail.com> <mediawiki@emsenhuber.ch>
Alexander Monk <krenair@gmail.com>
Alexander Monk <krenair@gmail.com> <alex@wikimedia.org>
Alexander Monk <krenair@gmail.com> <krenair@wikimedia.org>
Alexia E. Smith <washuu@gmail.com>
AlQaholic007 <soham.parekh1998@gmail.com>
Amir E. Aharoni <amir.aharoni@mail.huji.ac.il>
Amir E. Aharoni <amir.aharoni@mail.huji.ac.il> <amire80@users.mediawiki.org>
Amir Sarabadani <ladsgroup@gmail.com> <Ladsgroup@gmail.com>
Anders Wegge Jakobsen <awegge@gmail.com> <wegge@users.mediawiki.org>
Andre Engels <andreengels@gmail.com> <a_engels@users.mediawiki.org>
Andrew Garrett <agarrett@wikimedia.org>
Andrew Garrett <agarrett@wikimedia.org> <werdna@users.mediawiki.org>
Andrew Otto <acotto@gmail.com>
Angela Beesley Starling <wiki@nge.la> <angelab@users.mediawiki.org>
Antoine Musso <hashar@free.fr>
Antoine Musso <hashar@free.fr> <hashar@users.mediawiki.org>
Aran Dunkley <aran@organicdesign.co.nz> <nad@users.mediawiki.org>
Ariel Glenn <ariel@wikimedia.org> <ariel@users.mediawiki.org>
Ariel Glenn <ariel@wikimedia.org> <ariel@wikimedia.org>
Arlo Breault <abreault@wikimedia.org>
ArtBaltai <art.baltai@speedandfunction.com>
Arthur Richards <arichards@wikimedia.org>
Arthur Richards <arichards@wikimedia.org> <awjrichards@users.mediawiki.org>
Aryeh Gregor <ayg@aryeh.name> <simetrical@users.mediawiki.org>
Asher Feldman <afeldman@wikimedia.org>
Asher Feldman <afeldman@wikimedia.org> <asher@users.mediawiki.org>
aude <aude.wiki@gmail.com>
Audrey Tang <audreyt@audreyt.org>
Audrey Tang <audreyt@audreyt.org> <au@localhost>
ayush_garg <ayush.ce13@iitp.ac.in>
Bae Junehyeon <devunt@gmail.com>
Bahodir Mansurov <bmansurov@wikimedia.org>
Bartosz Dziewoński <matma.rex@gmail.com>
Bartosz Dziewoński <matma.rex@gmail.com> <bdziewonski@wikimedia.org>
Bartosz Dziewoński <matma.rex@gmail.com> <matmarex@wikimedia.org>
Ben Hartshorne <bhartshorne@wikimedia.org> <ben@users.mediawiki.org>
Bene <benestar.wikimedia@gmail.com>
Bene <benestar.wikimedia@gmail.com> <benestar.wikimedia@googlemail.com>
Benny Situ <bsitu@wikimedia.org>
Benny Situ <bsitu@wikimedia.org> <bsitu@users.mediawiki.org>
Bertrand Grondin <bertrand.grondin@tiscali.fr> <grondin@users.mediawiki.org>
Brad Jorsch <bjorsch@wikimedia.org>
Brad Jorsch <bjorsch@wikimedia.org> <anomie.wikipedia@gmail.com>
Brandon Harris <bharris@wikimedia.org> <bharris@users.mediawiki.org>
Brian Wolff <bawolff+wn@gmail.com>
Brian Wolff <bawolff+wn@gmail.com> <bawolff+svn@gmail.com>
Brian Wolff <bawolff+wn@gmail.com> <bawolff@users.mediawiki.org>
Brion Vibber <brion@wikimedia.org>
Brion Vibber <brion@wikimedia.org> <brion@pobox.com>
Brion Vibber <brion@wikimedia.org> <brion@users.mediawiki.org>
Bryan Davis <bd808@wikimedia.org>
Bryan Davis <bd808@wikimedia.org> <bd808@bd808.com>
Bryan Tong Minh <bryan.tongminh@gmail.com>
Bryan Tong Minh <bryan.tongminh@gmail.com> <btongminh@users.mediawiki.org>
C. Scott Ananian <cscott@cscott.net>
C. Scott Ananian <cscott@cscott.net> <cananian@wikimedia.org>
Cacycle <cacyclewp@gmail.com>
cenarium <cenarium.sysop@gmail.com>
Chad Horohoe <chadh@wikimedia.org>
Chad Horohoe <chadh@wikimedia.org> <demon@users.mediawiki.org>
Charles Melbye <charlie@yourwiki.net> <charlie@users.mediawiki.org>
Chiefwei <chiefwei1989@gmail.com>
Chris Koerner <ckoerner@wikimedia.org>
Chris McMahon <cmcmahon@wikimedia.org>
Chris Steipp <csteipp@wikimedia.org>
Christian Aistleitner <christian@quelltextlich.at>
Christian Aistleitner <christian@quelltextlich.at> <qchris@users.mediawiki.org>
Christian Williams <orbit@framezero.com>
Christian Williams <orbit@framezero.com> <christian@localhost>
Christian Williams <orbit@framezero.com> <christian@wikia-inc.com>
Christoph Jauera <christoph.jauera@wikimedia.de>
Christoph Jauera <christoph.jauera@wikimedia.de> <christoph.fischer@wikimedia.de>
Christopher Johnson <root@bugzilla.wmde.de>
church of emacs <churchofemacs@users.mediawiki.org>
Cindy Cicalese <ccicalese@wikimedia.org>
Cindy Cicalese <ccicalese@wikimedia.org> <cicalese@mitre.org>
Cindy Cicalese <ccicalese@wikimedia.org> <cindom@gmail.com>
ckoerner <nobelx@gmail.com>
Conrad Irwin <conrad.irwin+wiki@gmail.com> <conrad@users.mediawiki.org>
Dan Duvall <dduvall@wikimedia.org>
dan-nl <d_entous@yahoo.com>
Daniel A. R. Werner <daniel.a.r.werner@gmail.com>
Daniel Cannon <cannon.danielc@gmail.com> <amidaniel@users.mediawiki.org>
Daniel Friesen <mediawiki@danielfriesen.name>
Daniel Friesen <mediawiki@danielfriesen.name> <daniel@nadir-seen-fire.com>
Daniel Friesen <mediawiki@danielfriesen.name> <dantman@users.mediawiki.org>
Daniel Friesen <mediawiki@danielfriesen.name> <pub-github@nadir-seen-fire.com>
Daniel Kinzler <dkinzler@wikimedia.org>
Daniel Kinzler <dkinzler@wikimedia.org> <daniel.kinzler@wikimedia.de>
Daniel Kinzler <dkinzler@wikimedia.org> <daniel@users.mediawiki.org>
Daniel Renfro <bluecurio@gmail.com> <drenfro@vistaprint.com>
Danny B. <Wikipedia.Danny.B@email.cz>
Danny B. <Wikipedia.Danny.B@email.cz> <danny.b@email.cz>
Danny B. <Wikipedia.Danny.B@email.cz> <danny_b@users.mediawiki.org>
Danny B. <Wikipedia.Danny.B@email.cz> <wikimedia.danny.b@email.cz>
Darian Anthony Patrick <dpatrick@wikimedia.org>
Darkdragon09 <ubuntu@ip-172-31-39-38.us-west-2.compute.internal>
David Barratt <dbarratt@wikimedia.org>
David Causse <dcausse@wikimedia.org>
David Chan <david@sheetmusic.org.uk>
Dayllan Maza <dmaza@wikimedia.org>
Dayllan Maza <dmaza@wikimedia.org> <dayllan.maza@gmail.com>
Dereckson <dereckson@espace-win.org>
Derk-Jan Hartman <hartman@videolan.org>
Derk-Jan Hartman <hartman@videolan.org> <hartman.wiki@gmail.com>
Derk-Jan Hartman <hartman@videolan.org> <hartman@users.mediawiki.org>
Devi Krishnan <devikrishnan67@gmail.com>
Diederik van Liere <dvanliere@gmail.com> <diederik@users.mediawiki.org>
Domas Mituzas <domas.mituzas@gmail.com> <midom@users.mediawiki.org>
Douglas Gardner <douglas@chippy.ch>
DPStokesNZ <duncan.stokes@gmail.com>
Ebrahim Byagowi <ebrahim@gnu.org>
Ed Sanders <esanders@wikimedia.org>
Elliott Eggleston <eeggleston@wikimedia.org>
Elliott Eggleston <eeggleston@wikimedia.org> <ejegg@ejegg.com>
Emad Elwany <emadelwany@hotmail.com>
Emmanuel Engelhart <kelson@kiwix.org> <kelson42@users.mediawiki.org>
Emufarmers <emufarmers@gmail.com>
Emufarmers <emufarmers@gmail.com> <emufarmers@users.mediawiki.org>
Entlinkt <entlinkt@gmx-topmail.de>
Eranroz <eranroz89@gmail.com>
Erik Bernhardson <ebernhardson@wikimedia.org>
Erik Moeller <erik@wikimedia.org>
Erik Moeller <erik@wikimedia.org> <erik@users.mediawiki.org>
Erwin Dokter <erwin@darcoury.nl>
Evan McIntire <mcintire.evan@gmail.com>
Evan Prodromou <evanprodromou@users.mediawiki.org> <evan@users.mediawiki.org>
Federico Leva <federicoleva@tiscali.it>
Fenzik Joseph <fenzik@gmail.com> <fenzik@users.mediawiki.org>
Florian Schmidt <florian.schmidt.welzow@t-online.de>
Florian Schmidt <florian.schmidt.welzow@t-online.de> <florian.schmidt.stargatewissen@gmail.com>
fomafix <fomafix@googlemail.com>
Fran Rogers <fran@dumetella.net>
Fran Rogers <fran@dumetella.net> <krimpet@users.mediawiki.org>
freakolowsky <freak@drajv.si>
FunPika <funpikawiki@gmail.com>
Gabriel Wicke <gwicke@wikimedia.org>
Gabriel Wicke <gwicke@wikimedia.org> <gwicke@users.mediawiki.org>
Gabriel Wicke <gwicke@wikimedia.org> <wicke@wikidev.net>
Geoffrey Mon <geofbot@gmail.com>
Geoffrey Trang <geoffreytrang@gmail.com>
Gergő Tisza <gtisza@wikimedia.org>
Gergő Tisza <gtisza@wikimedia.org> <tgr.huwiki@gmail.com>
Giftpflanze <gifti@tools.wmflabs.org>
Gilles Dubuc <gdubuc@wikimedia.org> <gilles@wikimedia.org>
Gilles Dubuc <gdubuc@wikimedia.org>
gladoscc <admin@glados.cc>
glaisher <glaisher.wiki@gmail.com>
Greg Sabino Mullane <greg@turnstep.com>
Greg Sabino Mullane <greg@turnstep.com> <greg@endpoint.com>
Greg Sabino Mullane <greg@turnstep.com> <greg@users.mediawiki.org>
Grunny <mwgrunny@gmail.com>
Guy Van den Broeck <guyvdb@gmail.com> <guyvdb@users.mediawiki.org>
Happy-melon <happy-melon@live.com> <happy-melon@users.mediawiki.org>
Helder <he7d3r@gmail.com>
Helder <he7d3r@gmail.com> <helder.wiki@gmail.com>
Hoo man <hoo@online.de>
Huji <huji.huji@gmail.com>
Huji <huji.huji@gmail.com> <huji@users.mediawiki.org>
Ian Baker <ibaker@wikimedia.org> <raindrift@users.mediawiki.org>
Ilmari Karonen <nospam@vyznev.net> <vyznev@users.mediawiki.org>
Inez Korczyński <inez@wikia-inc.com>
Inez Korczyński <inez@wikia-inc.com> <inez@users.mediawiki.org>
isarra <s@zaori.org>
isarra <s@zaori.org> <zhorishna@gmail.com>
Ivan Lanin <ivanlanin@gmail.com> <ivanlanin@users.mediawiki.org>
Jack Phoenix <jack@countervandalism.net>
Jack Phoenix <jack@countervandalism.net> <ashley@users.mediawiki.org>
Jackmcbarn <jackmcbarn@gmail.com>
Jackmcbarn <jackmcbarn@gmail.com> <jackmcbarn@users.noreply.github.com>
jagori <jagori79@gmail.com>
James D. Forrester <jforrester@wikimedia.org>
Jaime Crespo <jcrespo@wikimedia.org>
Jan Gerber <j@thing.net> <j@users.mediawiki.org>
Jan Luca Naumann <jan@jans-seite.de>
Jan Luca Naumann <jan@jans-seite.de> <jan@users.mediawiki.org>
Jan Paul Posma <jp.posma@gmail.com> <janpaul123@users.mediawiki.org>
Jan Zerebecki <jan.wikimedia@zerebecki.de>
Jared Flores <jaredflores2000@gmail.com>
Jaroslav Škarvada <jskarvad@redhat.com>
jarrettmunton <jmuntjmunt@gmail.com>
Jason Richey <jasonr@wikia.com>
Jason Richey <jasonr@wikia.com> <jasonr@users.mediawiki.org>
Jason Richey <jasonr@wikia.com> <urichj00@users.mediawiki.org>
Jeff Hall <jeffreyehall@gmail.com>
Jeff Hall <jeffreyehall@gmail.com> <jhall@wikimedia.org>
Jeff Hobson <jhobson@wikimedia.org>
Jeff Janes <jeff.janes@gmail.com>
Jeremy Baron <jeremy@tuxmachine.com>
Jeremy Postlethwaite <jpostlethwaite@wikimedia.org> <jpostlethwaite@users.mediawiki.org>
Jeroen De Dauw <jeroendedauw@gmail.com>
Jeroen De Dauw <jeroendedauw@gmail.com> <jeroendedauw@users.mediawiki.org>
Jesús Martínez Novo <martineznovo@gmail.com>
Jiabao <jiabao.foss@gmail.com>
Jimmy Collins <jimmy.collins@web.de> <collinj@users.mediawiki.org>
Joel Sahleen <jsahleen@wikimedia.org>
John Du Hart <john@compwhizii.net> <johnduhart@users.mediawiki.org>
John Erling Blad <john.blad@wikimedia.de>
Jon Harald Søby <jhsoby@gmail.com> <jhsoby@users.mediawiki.org>
Jon Harald Søby <jhsoby@gmail.com>
Jon Robson <jrobson@wikimedia.org>
Jon Robson <jrobson@wikimedia.org> <jdlrobson@gmail.com>
Juliusz Gonera <jgonera@gmail.com>
Juliusz Gonera <jgonera@gmail.com> <jgonera@wikimedia.org>
Jure Kajzer <freak@drajv.si>
Jure Kajzer <freak@drajv.si> <freakolowsky@users.mediawiki.org>
Justin Du <justin.d128@gmail.com>
Kai Nissen <kai.nissen@wikimedia.de>
Karun Dambiec <karun.84@gmx.de>
Katie Filbert <aude.wiki@gmail.com>
Katie Filbert <aude.wiki@gmail.com> <aude@users.mediawiki.org>
Kevin Israel <pleasestand@live.com>
Kosta Harlan <kharlan@wikimedia.org>
Kosta Harlan <kharlan@wikimedia.org> <kosta@fastmail.com>
Kunal Grover <kunalgrover05@gmail.com>
Kunal Mehta <legoktm@member.fsf.org>
Kunal Mehta <legoktm@member.fsf.org> <legoktm.wikipedia@gmail.com>
Kunal Mehta <legoktm@member.fsf.org> <legoktm@gmail.com>
Kwan Ting Chan <ktc@ktchan.info> <ktchan@users.mediawiki.org>
lekshmi <andnlnbn18@gmail.com>
Leo Koppelkamm <diebuche@gmail.com> <diebuche@users.mediawiki.org>
Leon Liesener <leon.liesener@wikipedia.de>
Leon Weber <leon@vserver152.masterssystems.com> <leon@users.mediawiki.org>
Leonardo Gregianin <leogregianin@googlemail.com> <leogregianin@users.mediawiki.org>
Leons Petrazickis <leons.petrazickis.haveyouconsiderednotincludingthisphrase@gmail.com> <leonsp@users.mediawiki.org>
liangent <liangent@gmail.com>
Lisa Ridley <lhridley@gmail.com> <lhridley@users.mediawiki.org>
Ljudusika <plo2000@i.ua>
Lucas Werkmeister <lucas.werkmeister@wikimedia.de>
Luis Felipe Schenone <schenonef@gmail.com>
Luke Welling <lwelling@wikimedia.org>
Lupo <lupo.bugzilla@gmail.com>
m4tx <m4tx@m4tx.pl>
Madman <madman.enwiki@gmail.com>
Magnus Manske <magnusmanske@googlemail.com> <magnusmanske@users.mediawiki.org>
Manuel Schneider <manuel.schneider@wikimedia.ch> <80686@users.mediawiki.org>
Marc-André Pelletier <marc@uberbox.org>
Marcin Cieślak <saper@saper.info>
Marcin Cieślak <saper@saper.info> <saper@users.mediawiki.org>
Marco Falke <maic23@live.de>
MarcoAurelio <strigiwm@gmail.com>
MarcoAurelio <strigiwm@gmail.com> <maurelio@tools.wmflabs.org>
Marielle Volz <marielle.volz@gmail.com>
Marius Hoch <hoo@online.de>
Mark Clements <mediawiki@kennel17.co.uk> <happydog@users.mediawiki.org>
Mark Hershberger <mah@everybody.org>
Mark Hershberger <mah@everybody.org> <mah@nichework.com>
Mark Hershberger <mah@everybody.org> <mah@users.mediawiki.org>
Mark Hershberger <mah@everybody.org> <mhershberger@wikimedia.org>
Mark Holmquist <mtraceur@member.fsf.org>
Mark Holmquist <mtraceur@member.fsf.org> <mholmquist@wikimedia.org>
Marko Obrovac <mobrovac@wikimedia.org>
Markus Glaser <glaser@hallowelt.biz>
Markus Glaser <glaser@hallowelt.biz> <mglaser@users.mediawiki.org>
Martin Urbanec <martin.urbanec@wikimedia.cz>
Matt Johnston <mattj@emazestudios.com> <mattj@users.mediawiki.org>
Matthew Britton <hugglegurch@gmail.com> <gurch@users.mediawiki.org>
Matthew Bowker <matthewrbowker.bugs@gmail.com>
Matthew Flaschen <mflaschen@wikimedia.org>
Matthew Walker <mwalker@wikimedia.org>
MatthiasDD <Matthias_K2@gmx.de>
Matthias Mullie <git@mullie.eu>
Matthias Mullie <git@mullie.eu> <mmullie@wikimedia.org>
Matěj Grabovský <mgrabovsky@yahoo.com> <mgrabovsky@users.mediawiki.org>
Matěj Suchánek <matejsuchanek97@gmail.com>
Max Semenik <maxsem.wiki@gmail.com>
Max Semenik <maxsem.wiki@gmail.com> <maxsem@users.mediawiki.org>
Max Semenik <maxsem.wiki@gmail.com> <semenik@gmail.com>
mgooley <g0013y@gmail.com>
Michael Dale <mdale@wikimedia.org> <dale@users.mediawiki.org>
mjbmr <mjbmri@gmail.com>
Mohamed Magdy <mohamedmk@gmail.com> <alnokta@users.mediawiki.org>
Moriel Schottlender <mschottlender@wikimedia.org>
Moriel Schottlender <mschottlender@wikimedia.org> <moriel@gmail.com>
Mormegil <mormegil@centrum.cz>
MrBlueSky <mrbluesky@wikipedia.be>
MrBlueSky <mrbluesky@wikipedia.be> <mrbluesky@localhost>
Mukunda Modell <mmodell@wikimedia.org>
MZMcBride <g@mzmcbride.com>
nadeesha <nadeesha@calcey.com> <nadeesha@users.mediawiki.org>
Namit <namit.ohri@gmail.com>
Nathan Larson <nathanlarson3141@gmail.com>
Nathan Larson <nathanlarson3141@gmail.com> <tjlsangria@gmail.com>
Nathaniel Herman <redwwjd@yahoo.com> <pinky@users.mediawiki.org>
Neil Kandalgaonkar <neilk@wikimedia.org> <neilk@users.mediawiki.org>
Nemo bis <federicoleva@tiscali.it>
nephele <nephele@skyhighway.com> <nephele@users.mediawiki.org>
Nick Jenkins <nickpj@gmail.com> <nickj@users.mediawiki.org>
Niharika Kohli <nkohli@wikimedia.org>
Nik Everett <neverett@wikimedia.org>
Niklas Laxström <niklas.laxstrom@gmail.com>
Niklas Laxström <niklas.laxstrom@gmail.com> <nikerabbit@users.mediawiki.org>
Nimish Gautam <nimishg@wikimedia.org> <nimishg@users.mediawiki.org>
Nuria Ruiz <nuria@wikimedia.org>
Ori Livneh <ori@wikimedia.org>
Ori Livneh <ori@wikimedia.org> <ori.livneh@gmail.com>
OverlordQ <wikipedia@thedarkcitadel.com> <overlordq@users.mediawiki.org>
Owen Davis <owen@wikia-inc.com>
Owen Davis <owen@wikia-inc.com> <owen@users.mediawiki.org>
paladox <thomasmulhall410@yahoo.com>
Patricio Molina <patriciomolina@gmail.com>
Patrick Reilly <preilly@wikimedia.org>
Patrick Reilly <preilly@wikimedia.org> <preilly@users.mediawiki.org>
Patrick Westerhoff <PatrickWesterhoff@gmail.com>
Paul Copperman <paul.copperman@gmail.com> <pcopp@users.mediawiki.org>
Petar Petković <ppetkovic@wikimedia.org>
Peter Coombe <pcoombe@wikimedia.org>
Peter Coti <petercoti@gmail.com>
Peter Potrowl <peter017@gmail.com> <peter17@users.mediawiki.org>
Petr Kadlec <mormegil@centrum.cz>
Philip Tzou <philip.npc@gmail.com> <philip@users.mediawiki.org>
physikerwelt (Moritz Schubotz) <wiki@physikerwelt.de>
PiRSquared17 <pirsquared@tools.wmflabs.org>
Platonides <platonides@gmail.com> <platonides@users.mediawiki.org>
pppery <mapreader@olum.org>
PranavK <pranavmk98@gmail.com>
Prateek Saxena <psaxena@wikimedia.org>
Prateek Saxena <psaxena@wikimedia.org> <prtksxna@gmail.com>
Priyanka Dhanda <pdhanda@wikimedia.org> <pdhanda@users.mediawiki.org>
Purodha Blissenbach <purodha@blissenbach.org>
Purodha Blissenbach <purodha@blissenbach.org> <publi@web.de>
Purodha Blissenbach <purodha@blissenbach.org> <purodha@users.mediawiki.org>
Pwirth <wirth@hallowelt.biz>
Raimond Spekking <raimond.spekking@gmail.com>
Raimond Spekking <raimond.spekking@gmail.com> <raymond@users.mediawiki.org>
Remember the dot <rememberthedot@gmail.com> <rememberthedot@users.mediawiki.org>
Reza <reza.energy@gmail.com>
Ricordisamoa <ricordisamoa@openmailbox.org>
rillke <rillke@wikipedia.de>
rillke <rillke@wikipedia.de> <rainerrillke@hotmail.com>
River Tarnell <river@wikimedia.org> <kateturner@users.mediawiki.org>
River Tarnell <river@wikimedia.org> <river@users.mediawiki.org>
Roan Kattouw <roan.kattouw@gmail.com>
Roan Kattouw <roan.kattouw@gmail.com> <catrope@users.mediawiki.org>
Roan Kattouw <roan.kattouw@gmail.com> <roan@wikimedia.org>
Rob Church <robchur@gmail.com> <robchurch@users.mediawiki.org>
Rob Lanphier <robla@robla.net>
Rob Lanphier <robla@robla.net> <robla@users.mediawiki.org>
Rob Lanphier <robla@robla.net> <robla@wikimedia.org>
Rob Moen <rmoen@mediawiki.org>
Rob Moen <rmoen@mediawiki.org> <rmoen@users.mediawiki.org>
Rob Moen <rmoen@mediawiki.org> <rmoen@wikimedia.org>
Robert Hoenig <indielives010@gmail.com>
Robert Leverington <robert@rhl.me.uk> <roberthl@users.mediawiki.org>
Robert Rohde <rarohde@gmail.com> <rarohde@users.mediawiki.org>
Robert Stojnić <rainmansr@gmail.com> <rainman@users.mediawiki.org>
Robert Vogel <vogel@hallowelt.biz>
Robin Pepermans <robinp.1273@gmail.com>
Robin Pepermans <robinp.1273@gmail.com> <robin@users.mediawiki.org>
robinhood701 <robinhood70@live.ca>
Rohan <rohan1395@yahoo.com>
Rotem Liss <rotemliss@gmail.com> <rotem@users.mediawiki.org>
Rummana Yasmeen <ryasmeen@wikimedia.org>
Russ Nelson <russnelson@gmail.com> <nelson@users.mediawiki.org>
Ryan Kaldari <rkaldari@wikimedia.org>
Ryan Kaldari <rkaldari@wikimedia.org> <kaldari@gmail.com>
Ryan Kaldari <rkaldari@wikimedia.org> <kaldari@users.mediawiki.org>
Ryan Lane <rlane32@gmail.com>
Ryan Lane <rlane32@gmail.com> <laner@users.mediawiki.org>
Ryan Lane <rlane32@gmail.com> <rlane@wikimedia.org>
Ryan Schmidt <skizzerz@gmail.com>
Ryan Schmidt <skizzerz@gmail.com> <skizzerz@skizzerz.net>
Ryan Schmidt <skizzerz@gmail.com> <skizzerz@users.mediawiki.org>
S Page <spage@wikimedia.org>
SBassett <sbassett@wikimedia.org>
Sakretsu <sakretsu.wiki@gmail.com>
Sam Reed <reedy@wikimedia.org>
Sam Reed <reedy@wikimedia.org> <sam@reedyboy.net>
Sam Reed <reedy@wikimedia.org> <Reedy reedy@wikimedia.org>
Sam Reed <reedy@wikimedia.org> <reedy@formey.wikimedia.org>
Sam Reed <reedy@wikimedia.org> <reedy@users.mediawiki.org>
Sam Smith <git@samsmith.io>
Santhosh Thottingal <santhosh.thottingal@gmail.com>
Santhosh Thottingal <santhosh.thottingal@gmail.com> <santhosh@users.mediawiki.org>
Schnark (Michael M.) <listenleser@gmail.com>
Scimonster <tehalmightyscimonster@gmail.com>
Sean Colombo <sean.colombo@gmail.com> <sean_colombo@users.mediawiki.org>
Sean Pringle <springle@wikimedia.org>
Seb35 <seb35wikipedia@gmail.com>
Sergio Santoro <santoro.srg@gmail.com>
Shahyar <shahyar@gmail.com>
Shinjiman <shinjiman@gmail.com>
Shinjiman <shinjiman@gmail.com> <shinjiman@users.mediawiki.org>
shirayuki <shirayuking@gmail.com>
Siebrand Mazeland <s.mazeland@xs4all.nl>
Siebrand Mazeland <s.mazeland@xs4all.nl> <siebrand@kitano.nl>
Siebrand Mazeland <s.mazeland@xs4all.nl> <siebrand@users.mediawiki.org>
Siebrand Mazeland <s.mazeland@xs4all.nl> <siebrand@wikimedia.org>
Smriti Singh <smritis.31095@gmail.com>
Sorawee Porncharoenwase <nullzero.free@gmail.com>
Southparkfan <southparkfan223@hotmail.com>
SQL <sxwiki@gmail.com> <sql@users.mediawiki.org>
Stanislav Malyshev <smalyshev@gmail.com>
Stephan Gambke <s7eph4n@gmail.com>
Stephane Bisson <sbisson@wikimedia.org>
Stephen Liang <github@stephenliang.pw>
Steve Sanbeg <ffnaort@jro.qr> <sanbeg@users.mediawiki.org>
Steven Roddis <StevenRoddis@users.noreply.github.com>
Steven Walling <swalling@wikimedia.org>
Subramanya Sastry <ssastry@wikimedia.org>
Sucheta Ghoshal <sghoshal@wikimedia.org>
Sumit Asthana <asthana.sumit23@gmail.com>
Taavi Väänänen <hi@tassu.me>
tacsipacsi <tacsipacsi@jnet.hu>
TerraCodes <terracodes@tools.wmflabs.org>
Thalia Chan <thalia@cantorion.org>
Thalia Chan <thalia@cantorion.org> <thalia.e.chan@googlemail.com>
Thiemo Kreuz <thiemo.kreuz@wikimedia.de>
Thiemo Kreuz <thiemo.kreuz@wikimedia.de> <thiemo.maettig@wikimedia.de>
Thiemo Kreuz <thiemo.kreuz@wikimedia.de> <mr.heat@gmx.de>
This, that and the other <at.light@live.com.au>
tholam <t.lam@lamsinfosystem.com>
Thomas Bleher <ThomasBleher@gmx.de> <tbleher@users.mediawiki.org>
Thomas Dalton <thomas.dalton@gmail.com> <tango@users.mediawiki.org>
Thomas Gries <mail@tgries.de> <wikinaut@users.mediawiki.org>
Tim Landscheidt <tim@tim-landscheidt.de>
Tim Laqua <t.laqua@gmail.com> <tlaqua@users.mediawiki.org>
Tim Starling <tstarling@wikimedia.org>
Tim Starling <tstarling@wikimedia.org> <tstarling@users.mediawiki.org>
Timo Tijhof <krinklemail@gmail.com>
Timo Tijhof <krinklemail@gmail.com> <krinkle@users.mediawiki.org>
Timo Tijhof <krinklemail@gmail.com> <timo@wikimedia.org>
Timo Tijhof <krinklemail@gmail.com> <ttijhof@wikimedia.org>
Tina Johnson <tinajohnson.1234@gmail.com>
Tom Maaswinkel <tom.maaswinkel@12wiki.eu> <thedevilonline@users.mediawiki.org>
Tomasz Finc <tfinc@wikimedia.org> <tomasz@users.mediawiki.org>
Tomasz W. Kozlowski <tomasz@twkozlowski.com>
Tomasz W. Kozlowski <tomasz@twkozlowski.com> <tomasz@twkozlowski.net>
Tomasz W. Kozlowski <tomasz@twkozlowski.com> <twkozlowski@gmail.com>
Tony Thomas <01tonythomas@gmail.com>
Tpt <thomaspt@hotmail.fr>
Trevor Parscal <trevorparscal@gmail.com>
Trevor Parscal <trevorparscal@gmail.com> <tparscal@users.mediawiki.org>
Trevor Parscal <trevorparscal@gmail.com> <tparscal@wikimedia.org>
Trey Jones <tjones@wikimedia.org>
Tyler Cipriani <tcipriani@wikimedia.org>
Tyler Romeo <tylerromeo@gmail.com>
Umherirrender <umherirrender_de.wp@web.de>
Victor Barbu <victorbarbu08@gmail.com>
Victor Vasiliev <vasilvv@mit.edu>
Victor Vasiliev <vasilvv@mit.edu> <vasilievvv@users.mediawiki.org>
Victor Vasiliev <vasilvv@mit.edu> <vasilvv@gmail.com>
Vikas S Yaligar <vikasyaligar.it@gmail.com>
Vivek Ghaisas <v.a.ghaisas@gmail.com>
Volker E <volker.e@wikimedia.org>
wctaiwan <wctaiwan@gmail.com>
withoutaname <drevitchi@gmail.com>
X! <soxred93@gmail.com> <soxred93@users.mediawiki.org>
Yaron Koren <yaron57@gmail.com>
Yaron Koren <yaron57@gmail.com> <yaron@users.mediawiki.org>
Yaroslav Melnychuk <yaroslavmelnuchuk@gmail.com>
Yongmin Hong <revi@pobox.com>
Yongmin Hong <revi@pobox.com> <revi@member.fsf.org>
Yongmin Hong <revi@pobox.com> <reviwiki@gmail.com>
Yuri Astrakhan <yurik@wikimedia.org>
Yuri Astrakhan <yurik@wikimedia.org> <yuriastrakhan@gmail.com>
Yuri Astrakhan <yurik@wikimedia.org> <yurik@users.mediawiki.org>
Yuriy Shnitkovskiy <bmp2558@gmail.com>
Yusuke Matsubara <whym@whym.org>
Yuvi Panda <yuvipanda@gmail.com>
Zak Greant <zak+mediawiki@fooassociates.com> <zak@users.mediawiki.org>
Zhengzhu Feng <zhengzhu@gmail.com>
Zhengzhu Feng <zhengzhu@gmail.com> <zhengzhu@users.mediawiki.org>
Zoranzoki21 <zorandori4444@gmail.com>
Zppix <support@zppixballee.com>
Ævar Arnfjörð Bjarmason <avarab@gmail.com> <avar@users.mediawiki.org>
Étienne Beaulé <beauleetienne0@gmail.com>
Željko Filipin <zeljko.filipin@gmail.com>
Željko Filipin <zeljko.filipin@gmail.com> <zfilipin@wikimedia.org>
星耀晨曦 <razesoldier@outlook.com>
星耀晨曦 <razesoldier@outlook.com> <liguangjie4399@hotmail.com>

View File

@ -18,19 +18,14 @@
* @file
*/
$disableTaintCheck = true;
$cfg = require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php';
$cfg['file_list'] = array_merge(
$cfg['file_list'],
function_exists( 'register_postsend_function' ) ? [] : [ '.phan/stubs/hhvm.php' ],
function_exists( 'wikidiff2_do_diff' ) ? [] : [ '.phan/stubs/wikidiff.php' ],
class_exists( PEAR::class ) ? [] : [ '.phan/stubs/mail.php' ],
defined( 'PASSWORD_ARGON2I' ) ? [] : [ '.phan/stubs/password.php' ],
// Per composer.json, PHPUnit 6 is used for PHP 7.0+, PHPUnit 4 otherwise.
// Load the interface for the version of PHPUnit that isn't installed.
// Phan only supports PHP 7.0+ (and not HHVM), so we only need to stub PHPUnit 4.
class_exists( PHPUnit_TextUI_Command::class ) ? [] : [ '.phan/stubs/phpunit4.php' ],
class_exists( ProfilerExcimer::class ) ? [] : [ '.phan/stubs/excimer.php' ],
defined( 'PASSWORD_ARGON2ID' ) ? [] : [ '.phan/stubs/password.php' ],
class_exists( ValueError::class ) ? [] : [ '.phan/stubs/ValueError.php' ],
[
// This makes constants and globals known to Phan before processing all other files.
// You can check the parser order with --dump-parsed-file-list
@ -56,6 +51,7 @@ $cfg['analyzed_file_extensions'] = array_merge(
$cfg['autoload_internal_extension_signatures'] = [
'dom' => '.phan/internal_stubs/dom.phan_php',
'excimer' => '.phan/internal_stubs/excimer.php',
'imagick' => '.phan/internal_stubs/imagick.phan_php',
'intl' => '.phan/internal_stubs/intl.phan_php',
'memcached' => '.phan/internal_stubs/memcached.phan_php',
@ -66,6 +62,7 @@ $cfg['autoload_internal_extension_signatures'] = [
'sockets' => '.phan/internal_stubs/sockets.phan_php',
'sqlsrv' => '.phan/internal_stubs/sqlsrv.phan_php',
'tideways' => '.phan/internal_stubs/tideways.phan_php',
'wikidiff2' => '.phan/internal_stubs/wikidiff.php'
];
$cfg['directory_list'] = [
@ -75,7 +72,7 @@ $cfg['directory_list'] = [
'mw-config/',
'resources/',
'vendor/',
'.phan/stubs/',
// Do NOT add .phan/stubs/ here: stubs are conditionally loaded in file_list
];
$cfg['exclude_analysis_directory_list'] = [
@ -92,21 +89,11 @@ $cfg['exclude_analysis_directory_list'] = [
'includes/libs/objectcache/utils/MemcachedClient.php',
];
// NOTE: If you're facing an issue which you cannot easily fix, DO NOT add it here. Suppress it
// either in-line with @phan-suppress-next-line and similar, at block-level (via @suppress), or at
// file-level (with @phan-file-suppress), so that it stays enabled for the rest of the codebase.
$cfg['suppress_issue_types'] = array_merge( $cfg['suppress_issue_types'], [
// approximate error count: 19
"PhanParamReqAfterOpt", // False positives with nullables (phan issue #3159). Use real nullables
//after dropping HHVM
// approximate error count: 110
"PhanParamTooMany", // False positives with variargs. Unsuppress after dropping HHVM
] );
// This helps a lot in discovering bad code, but unfortunately it will always fail for
// hooks + pass by reference, see phan issue #2943.
// @todo Enable when the issue above is resolved and we update our config!
$cfg['redundant_condition_detection'] = false;
// These are too spammy for now. TODO enable
$cfg['null_casts_as_any_type'] = true;
$cfg['scalar_implicit_cast'] = true;
$cfg['suppress_issue_types'][] = 'PhanTypePossiblyInvalidDimOffset';
$cfg['suppress_issue_types'][] = 'PhanPossiblyUndeclaredVariable';
// Do not use aliases in core.
// Use the correct name, because we don't need backward compatibility

View File

@ -1,6 +1,6 @@
<?php
// These stubs were generated by the phan stub generator.
// @phan-stub-for-extension redis@3.1.1
// @phan-stub-for-extension redis@5.1.1
namespace {
class Redis {
@ -12,15 +12,21 @@ class Redis {
const REDIS_LIST = 3;
const REDIS_ZSET = 4;
const REDIS_HASH = 5;
const REDIS_STREAM = 6;
const PIPELINE = 2;
const ATOMIC = 0;
const MULTI = 1;
const OPT_SERIALIZER = 1;
const OPT_PREFIX = 2;
const OPT_READ_TIMEOUT = 3;
const OPT_TCP_KEEPALIVE = 6;
const OPT_COMPRESSION = 7;
const OPT_REPLY_LITERAL = 8;
const OPT_COMPRESSION_LEVEL = 9;
const SERIALIZER_NONE = 0;
const SERIALIZER_PHP = 1;
const SERIALIZER_IGBINARY = 2;
const SERIALIZER_JSON = 4;
const COMPRESSION_NONE = 0;
const OPT_SCAN = 4;
const SCAN_RETRY = 1;
const SCAN_NORETRY = 0;
@ -30,248 +36,272 @@ class Redis {
// methods
public function __construct() {}
public function __destruct() {}
public function connect() {}
public function pconnect() {}
public function close() {}
public function ping() {}
public function echo() {}
public function get() {}
public function set() {}
public function setex() {}
public function psetex() {}
public function setnx() {}
public function getSet() {}
public function randomKey() {}
public function renameKey() {}
public function renameNx() {}
public function getMultiple() {}
public function exists() {}
public function delete() {}
public function incr() {}
public function incrBy() {}
public function incrByFloat() {}
public function decr() {}
public function decrBy() {}
public function type() {}
public function append() {}
public function getRange() {}
public function setRange() {}
public function getBit() {}
public function setBit() {}
public function strlen() {}
public function getKeys() {}
public function sort() {}
public function sortAsc() {}
public function sortAscAlpha() {}
public function sortDesc() {}
public function sortDescAlpha() {}
public function lPush() {}
public function rPush() {}
public function lPushx() {}
public function rPushx() {}
public function lPop() {}
public function rPop() {}
public function blPop() {}
public function brPop() {}
public function lSize() {}
public function lRemove() {}
public function listTrim() {}
public function lGet() {}
public function lGetRange() {}
public function lSet() {}
public function lInsert() {}
public function sAdd() {}
public function sAddArray() {}
public function sSize() {}
public function sRemove() {}
public function sMove() {}
public function sPop() {}
public function sRandMember() {}
public function sContains() {}
public function sMembers() {}
public function sInter() {}
public function sInterStore() {}
public function sUnion() {}
public function sUnionStore() {}
public function sDiff() {}
public function sDiffStore() {}
public function setTimeout() {}
public function save() {}
public function _prefix($key) {}
public function _serialize($value) {}
public function _unserialize($value) {}
public function append($key, $value) {}
public function auth($password) {}
public function bgSave() {}
public function lastSave() {}
public function flushDB() {}
public function flushAll() {}
public function dbSize() {}
public function auth() {}
public function ttl() {}
public function pttl() {}
public function persist() {}
public function info() {}
public function select() {}
public function move() {}
public function bgrewriteaof() {}
public function slaveof() {}
public function object() {}
public function bitop() {}
public function bitcount() {}
public function bitpos() {}
public function mset() {}
public function msetnx() {}
public function rpoplpush() {}
public function brpoplpush() {}
public function zAdd() {}
public function zDelete() {}
public function zRange() {}
public function zRevRange() {}
public function zRangeByScore() {}
public function zRevRangeByScore() {}
public function zRangeByLex() {}
public function zRevRangeByLex() {}
public function zLexCount() {}
public function zRemRangeByLex() {}
public function zCount() {}
public function zDeleteRangeByScore() {}
public function zDeleteRangeByRank() {}
public function zCard() {}
public function zScore() {}
public function zRank() {}
public function zRevRank() {}
public function zInter() {}
public function zUnion() {}
public function zIncrBy() {}
public function expireAt() {}
public function pexpire() {}
public function pexpireAt() {}
public function hGet() {}
public function hSet() {}
public function hSetNx() {}
public function hDel() {}
public function hLen() {}
public function hKeys() {}
public function hVals() {}
public function hGetAll() {}
public function hExists() {}
public function hIncrBy() {}
public function hIncrByFloat() {}
public function hMset() {}
public function hMget() {}
public function multi() {}
public function discard() {}
public function exec() {}
public function pipeline() {}
public function watch() {}
public function unwatch() {}
public function publish() {}
public function subscribe() {}
public function psubscribe() {}
public function unsubscribe() {}
public function punsubscribe() {}
public function time() {}
public function role() {}
public function eval() {}
public function evalsha() {}
public function script() {}
public function debug() {}
public function dump() {}
public function restore() {}
public function migrate() {}
public function getLastError() {}
public function bitcount($key) {}
public function bitop($operation, $ret_key, $key, ...$other_keys) {}
public function bitpos($key, $bit, $start = null, $end = null) {}
public function blPop($key, $timeout_or_key, ...$extra_args) {}
public function brPop($key, $timeout_or_key, ...$extra_args) {}
public function brpoplpush($src, $dst, $timeout) {}
public function bzPopMax($key, $timeout_or_key, ...$extra_args) {}
public function bzPopMin($key, $timeout_or_key, ...$extra_args) {}
public function clearLastError() {}
public function _prefix() {}
public function _serialize() {}
public function _unserialize() {}
public function client() {}
public function command() {}
public function scan(&$i_iterator, $str_pattern = null, $i_count = null) {}
public function hscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function zscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function sscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function pfadd() {}
public function pfcount() {}
public function pfmerge() {}
public function getOption() {}
public function setOption() {}
public function config() {}
public function slowlog() {}
public function rawcommand() {}
public function geoadd() {}
public function geohash() {}
public function geopos() {}
public function geodist() {}
public function georadius() {}
public function georadiusbymember() {}
public function getHost() {}
public function getPort() {}
public function getDBNum() {}
public function getTimeout() {}
public function getReadTimeout() {}
public function getPersistentID() {}
public function client($cmd, ...$args) {}
public function close() {}
public function command(...$args) {}
public function config($cmd, $key, $value = null) {}
public function connect($host, $port = null, $timeout = null, $retry_interval = null) {}
public function dbSize() {}
public function debug($key) {}
public function decr($key) {}
public function decrBy($key, $value) {}
public function del($key, ...$other_keys) {}
public function discard() {}
public function dump($key) {}
public function echo($msg) {}
public function eval($script, $args = null, $num_keys = null) {}
public function evalsha($script_sha, $args = null, $num_keys = null) {}
public function exec() {}
public function exists($key, ...$other_keys) {}
public function expire($key, $timeout) {}
public function expireAt($key, $timestamp) {}
public function flushAll($async = null) {}
public function flushDB($async = null) {}
public function geoadd($key, $lng, $lat, $member, ...$other_triples) {}
public function geodist($key, $src, $dst, $unit = null) {}
public function geohash($key, $member, ...$other_members) {}
public function geopos($key, $member, ...$other_members) {}
public function georadius($key, $lng, $lan, $radius, $unit, array $opts = null) {}
public function georadius_ro($key, $lng, $lan, $radius, $unit, array $opts = null) {}
public function georadiusbymember($key, $member, $radius, $unit, array $opts = null) {}
public function georadiusbymember_ro($key, $member, $radius, $unit, array $opts = null) {}
public function get($key) {}
public function getAuth() {}
public function isConnected() {}
public function getBit($key, $offset) {}
public function getDBNum() {}
public function getHost() {}
public function getLastError() {}
public function getMode() {}
public function wait() {}
public function pubsub() {}
public function open() {}
public function popen() {}
public function lLen() {}
public function sGetMembers() {}
public function mget() {}
public function expire() {}
public function zunionstore() {}
public function zinterstore() {}
public function zRemove() {}
public function zRem() {}
public function zRemoveRangeByScore() {}
public function zRemRangeByScore() {}
public function zRemRangeByRank() {}
public function zSize() {}
public function substr() {}
public function rename() {}
public function del() {}
public function keys() {}
public function lrem() {}
public function ltrim() {}
public function lindex() {}
public function lrange() {}
public function scard() {}
public function srem() {}
public function sismember() {}
public function zReverseRange() {}
public function sendEcho() {}
public function evaluate() {}
public function evaluateSha() {}
public function getOption($option) {}
public function getPersistentID() {}
public function getPort() {}
public function getRange($key, $start, $end) {}
public function getReadTimeout() {}
public function getSet($key, $value) {}
public function getTimeout() {}
public function hDel($key, $member, ...$other_members) {}
public function hExists($key, $member) {}
public function hGet($key, $member) {}
public function hGetAll($key) {}
public function hIncrBy($key, $member, $value) {}
public function hIncrByFloat($key, $member, $value) {}
public function hKeys($key) {}
public function hLen($key) {}
public function hMget($key, array $keys) {}
public function hMset($key, array $pairs) {}
public function hSet($key, $member, $value) {}
public function hSetNx($key, $member, $value) {}
public function hStrLen($key, $member) {}
public function hVals($key) {}
public function hscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function incr($key) {}
public function incrBy($key, $value) {}
public function incrByFloat($key, $value) {}
public function info($option = null) {}
public function isConnected() {}
public function keys($pattern) {}
public function lInsert($key, $position, $pivot, $value) {}
public function lLen($key) {}
public function lPop($key) {}
public function lPush($key, $value) {}
public function lPushx($key, $value) {}
public function lSet($key, $index, $value) {}
public function lastSave() {}
public function lindex($key, $index) {}
public function lrange($key, $start, $end) {}
public function lrem($key, $value, $count) {}
public function ltrim($key, $start, $stop) {}
public function mget(array $keys) {}
public function migrate($host, $port, $key, $db, $timeout, $copy = null, $replace = null) {}
public function move($key, $dbindex) {}
public function mset(array $pairs) {}
public function msetnx(array $pairs) {}
public function multi($mode = null) {}
public function object($field, $key) {}
public function pconnect($host, $port = null, $timeout = null) {}
public function persist($key) {}
public function pexpire($key, $timestamp) {}
public function pexpireAt($key, $timestamp) {}
public function pfadd($key, array $elements) {}
public function pfcount($key) {}
public function pfmerge($dstkey, array $keys) {}
public function ping() {}
public function pipeline() {}
public function psetex($key, $expire, $value) {}
public function psubscribe(array $patterns, $callback) {}
public function pttl($key) {}
public function publish($channel, $message) {}
public function pubsub($cmd, ...$args) {}
public function punsubscribe($pattern, ...$other_patterns) {}
public function rPop($key) {}
public function rPush($key, $value) {}
public function rPushx($key, $value) {}
public function randomKey() {}
public function rawcommand($cmd, ...$args) {}
public function rename($key, $newkey) {}
public function renameNx($key, $newkey) {}
public function restore($ttl, $key, $value) {}
public function role() {}
public function rpoplpush($src, $dst) {}
public function sAdd($key, $value) {}
public function sAddArray($key, array $options) {}
public function sDiff($key, ...$other_keys) {}
public function sDiffStore($dst, $key, ...$other_keys) {}
public function sInter($key, ...$other_keys) {}
public function sInterStore($dst, $key, ...$other_keys) {}
public function sMembers($key) {}
public function sMove($src, $dst, $value) {}
public function sPop($key) {}
public function sRandMember($key, $count = null) {}
public function sUnion($key, ...$other_keys) {}
public function sUnionStore($dst, $key, ...$other_keys) {}
public function save() {}
public function scan(&$i_iterator, $str_pattern = null, $i_count = null) {}
public function scard($key) {}
public function script($cmd, ...$args) {}
public function select($dbindex) {}
public function set($key, $value, $opts = null) {}
public function setBit($key, $offset, $value) {}
public function setOption($option, $value) {}
public function setRange($key, $offset, $value) {}
public function setex($key, $expire, $value) {}
public function setnx($key, $value) {}
public function sismember($key, $value) {}
public function slaveof($host = null, $port = null) {}
public function slowlog($arg, $option = null) {}
public function sort($key, array $options = null) {}
public function sortAsc($key, $pattern = null, $get = null, $start = null, $end = null, $getList = null) {}
public function sortAscAlpha($key, $pattern = null, $get = null, $start = null, $end = null, $getList = null) {}
public function sortDesc($key, $pattern = null, $get = null, $start = null, $end = null, $getList = null) {}
public function sortDescAlpha($key, $pattern = null, $get = null, $start = null, $end = null, $getList = null) {}
public function srem($key, $member, ...$other_members) {}
public function sscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function strlen($key) {}
public function subscribe(array $channels, $callback) {}
public function swapdb($srcdb, $dstdb) {}
public function time() {}
public function ttl($key) {}
public function type($key) {}
public function unlink($key, ...$other_keys) {}
public function unsubscribe($channel, ...$other_channels) {}
public function unwatch() {}
public function wait($numslaves, $timeout) {}
public function watch($key, ...$other_keys) {}
public function xack($str_key, $str_group, array $arr_ids) {}
public function xadd($str_key, $str_id, array $arr_fields, $i_maxlen = null, $boo_approximate = null) {}
public function xclaim($str_key, $str_group, $str_consumer, $i_min_idle, array $arr_ids, array $arr_opts = null) {}
public function xdel($str_key, array $arr_ids) {}
public function xgroup($str_operation, $str_key = null, $str_arg1 = null, $str_arg2 = null, $str_arg3 = null) {}
public function xinfo($str_cmd, $str_key = null, $str_group = null) {}
public function xlen($key) {}
public function xpending($str_key, $str_group, $str_start = null, $str_end = null, $i_count = null, $str_consumer = null) {}
public function xrange($str_key, $str_start, $str_end, $i_count = null) {}
public function xread(array $arr_streams, $i_count = null, $i_block = null) {}
public function xreadgroup($str_group, $str_consumer, array $arr_streams, $i_count = null, $i_block = null) {}
public function xrevrange($str_key, $str_start, $str_end, $i_count = null) {}
public function xtrim($str_key, $i_maxlen, $boo_approximate = null) {}
public function zAdd($key, $score, $value) {}
public function zCard($key) {}
public function zCount($key, $min, $max) {}
public function zIncrBy($key, $value, $member) {}
public function zLexCount($key, $min, $max) {}
public function zPopMax($key) {}
public function zPopMin($key) {}
public function zRange($key, $start, $end, $scores = null) {}
public function zRangeByLex($key, $min, $max, $offset = null, $limit = null) {}
public function zRangeByScore($key, $start, $end, array $options = null) {}
public function zRank($key, $member) {}
public function zRem($key, $member, ...$other_members) {}
public function zRemRangeByLex($key, $min, $max) {}
public function zRemRangeByRank($key, $start, $end) {}
public function zRemRangeByScore($key, $min, $max) {}
public function zRevRange($key, $start, $end, $scores = null) {}
public function zRevRangeByLex($key, $min, $max, $offset = null, $limit = null) {}
public function zRevRangeByScore($key, $start, $end, array $options = null) {}
public function zRevRank($key, $member) {}
public function zScore($key, $member) {}
public function zinterstore($key, array $keys, ?array $weights = null, $aggregate = null) {}
public function zscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function zunionstore($key, array $keys, ?array $weights = null, $aggregate = null) {}
public function delete($key, ...$other_keys) {}
public function evaluate($script, $args = null, $num_keys = null) {}
public function evaluateSha($script_sha, $args = null, $num_keys = null) {}
public function getKeys($pattern) {}
public function getMultiple(array $keys) {}
public function lGet($key, $index) {}
public function lGetRange($key, $start, $end) {}
public function lRemove($key, $value, $count) {}
public function lSize($key) {}
public function listTrim($key, $start, $stop) {}
public function open($host, $port = null, $timeout = null, $retry_interval = null) {}
public function popen($host, $port = null, $timeout = null) {}
public function renameKey($key, $newkey) {}
public function sContains($key, $value) {}
public function sGetMembers($key) {}
public function sRemove($key, $member, ...$other_members) {}
public function sSize($key) {}
public function sendEcho($msg) {}
public function setTimeout($key, $timeout) {}
public function substr($key, $start, $end) {}
public function zDelete($key, $member, ...$other_members) {}
public function zDeleteRangeByRank($key, $min, $max) {}
public function zDeleteRangeByScore($key, $min, $max) {}
public function zInter($key, array $keys, ?array $weights = null, $aggregate = null) {}
public function zRemove($key, $member, ...$other_members) {}
public function zRemoveRangeByScore($key, $min, $max) {}
public function zReverseRange($key, $start, $end, $scores = null) {}
public function zSize($key) {}
public function zUnion($key, array $keys, ?array $weights = null, $aggregate = null) {}
}
class RedisArray {
// methods
public function __construct() {}
public function __call($function_name, $arguments) {}
public function _hosts() {}
public function _target() {}
public function _instance() {}
public function _function() {}
public function __construct($name_or_hosts, array $options = null) {}
public function _continuum() {}
public function _distributor() {}
public function _rehash() {}
public function select() {}
public function info() {}
public function ping() {}
public function flushdb() {}
public function flushall() {}
public function mget() {}
public function mset() {}
public function del() {}
public function getOption() {}
public function setOption() {}
public function keys() {}
public function save() {}
public function _function() {}
public function _hosts() {}
public function _instance($host) {}
public function _rehash($callable = null) {}
public function _target($key) {}
public function bgsave() {}
public function multi() {}
public function exec() {}
public function del($keys) {}
public function discard() {}
public function exec() {}
public function flushall($async = null) {}
public function flushdb($async = null) {}
public function getOption($opt) {}
public function info() {}
public function keys($pattern) {}
public function mget($keys) {}
public function mset($pairs) {}
public function multi($host, $mode = null) {}
public function ping() {}
public function save() {}
public function select($index) {}
public function setOption($opt, $value) {}
public function unlink() {}
public function unwatch() {}
public function delete() {}
public function getMultiple() {}
public function delete($keys) {}
public function getMultiple($keys) {}
}
class RedisCluster {
@ -283,14 +313,20 @@ class RedisCluster {
const REDIS_LIST = 3;
const REDIS_ZSET = 4;
const REDIS_HASH = 5;
const REDIS_STREAM = 6;
const ATOMIC = 0;
const MULTI = 1;
const OPT_SERIALIZER = 1;
const OPT_PREFIX = 2;
const OPT_READ_TIMEOUT = 3;
const OPT_TCP_KEEPALIVE = 6;
const OPT_COMPRESSION = 7;
const OPT_REPLY_LITERAL = 8;
const OPT_COMPRESSION_LEVEL = 9;
const SERIALIZER_NONE = 0;
const SERIALIZER_PHP = 1;
const SERIALIZER_IGBINARY = 2;
const SERIALIZER_JSON = 4;
const COMPRESSION_NONE = 0;
const OPT_SCAN = 4;
const SCAN_RETRY = 1;
const SCAN_NORETRY = 0;
@ -303,173 +339,194 @@ class RedisCluster {
const BEFORE = 'before';
// methods
public function __construct() {}
public function close() {}
public function get() {}
public function set() {}
public function mget() {}
public function mset() {}
public function msetnx() {}
public function del() {}
public function setex() {}
public function psetex() {}
public function setnx() {}
public function getset() {}
public function exists() {}
public function keys() {}
public function type() {}
public function lpop() {}
public function rpop() {}
public function lset() {}
public function spop() {}
public function lpush() {}
public function rpush() {}
public function blpop() {}
public function brpop() {}
public function rpushx() {}
public function lpushx() {}
public function linsert() {}
public function lindex() {}
public function lrem() {}
public function brpoplpush() {}
public function rpoplpush() {}
public function llen() {}
public function scard() {}
public function smembers() {}
public function sismember() {}
public function sadd() {}
public function saddarray() {}
public function srem() {}
public function sunion() {}
public function sunionstore() {}
public function sinter() {}
public function sinterstore() {}
public function sdiff() {}
public function sdiffstore() {}
public function srandmember() {}
public function strlen() {}
public function persist() {}
public function ttl() {}
public function pttl() {}
public function zcard() {}
public function zcount() {}
public function zremrangebyscore() {}
public function zscore() {}
public function zadd() {}
public function zincrby() {}
public function hlen() {}
public function hkeys() {}
public function hvals() {}
public function hget() {}
public function hgetall() {}
public function hexists() {}
public function hincrby() {}
public function hset() {}
public function hsetnx() {}
public function hmget() {}
public function hmset() {}
public function hdel() {}
public function hincrbyfloat() {}
public function dump() {}
public function zrank() {}
public function zrevrank() {}
public function incr() {}
public function decr() {}
public function incrby() {}
public function decrby() {}
public function incrbyfloat() {}
public function expire() {}
public function pexpire() {}
public function expireat() {}
public function pexpireat() {}
public function append() {}
public function getbit() {}
public function setbit() {}
public function bitop() {}
public function bitpos() {}
public function bitcount() {}
public function lget() {}
public function getrange() {}
public function ltrim() {}
public function lrange() {}
public function zremrangebyrank() {}
public function publish() {}
public function rename() {}
public function renamenx() {}
public function pfcount() {}
public function pfadd() {}
public function pfmerge() {}
public function setrange() {}
public function restore() {}
public function smove() {}
public function zrange() {}
public function zrevrange() {}
public function zrangebyscore() {}
public function zrevrangebyscore() {}
public function zrangebylex() {}
public function zrevrangebylex() {}
public function zlexcount() {}
public function zremrangebylex() {}
public function zunionstore() {}
public function zinterstore() {}
public function zrem() {}
public function sort() {}
public function object() {}
public function subscribe() {}
public function psubscribe() {}
public function unsubscribe() {}
public function punsubscribe() {}
public function eval() {}
public function evalsha() {}
public function scan(&$i_iterator, $str_node, $str_pattern = null, $i_count = null) {}
public function sscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function zscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function hscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function getmode() {}
public function getlasterror() {}
public function clearlasterror() {}
public function getoption() {}
public function setoption() {}
public function _prefix() {}
public function _serialize() {}
public function _unserialize() {}
public function __construct($name, array $seeds = null, $timeout = null, $read_timeout = null, $persistent = null, $auth = null) {}
public function _masters() {}
public function _prefix($key) {}
public function _redir() {}
public function multi() {}
public function exec() {}
public function _serialize($value) {}
public function _unserialize($value) {}
public function append($key, $value) {}
public function bgrewriteaof($key_or_address) {}
public function bgsave($key_or_address) {}
public function bitcount($key) {}
public function bitop($operation, $ret_key, $key, ...$other_keys) {}
public function bitpos($key, $bit, $start = null, $end = null) {}
public function blpop($key, $timeout_or_key, ...$extra_args) {}
public function brpop($key, $timeout_or_key, ...$extra_args) {}
public function brpoplpush($src, $dst, $timeout) {}
public function clearlasterror() {}
public function bzpopmax($key, $timeout_or_key, ...$extra_args) {}
public function bzpopmin($key, $timeout_or_key, ...$extra_args) {}
public function client($key_or_address, $arg = null, ...$other_args) {}
public function close() {}
public function cluster($key_or_address, $arg = null, ...$other_args) {}
public function command(...$args) {}
public function config($key_or_address, $arg = null, ...$other_args) {}
public function dbsize($key_or_address) {}
public function decr($key) {}
public function decrby($key, $value) {}
public function del($key, ...$other_keys) {}
public function discard() {}
public function watch() {}
public function unwatch() {}
public function save() {}
public function bgsave() {}
public function flushdb() {}
public function flushall() {}
public function dbsize() {}
public function bgrewriteaof() {}
public function lastsave() {}
public function info() {}
public function dump($key) {}
public function echo($msg) {}
public function eval($script, $args = null, $num_keys = null) {}
public function evalsha($script_sha, $args = null, $num_keys = null) {}
public function exec() {}
public function exists($key) {}
public function expire($key, $timeout) {}
public function expireat($key, $timestamp) {}
public function flushall($key_or_address, $async = null) {}
public function flushdb($key_or_address, $async = null) {}
public function geoadd($key, $lng, $lat, $member, ...$other_triples) {}
public function geodist($key, $src, $dst, $unit = null) {}
public function geohash($key, $member, ...$other_members) {}
public function geopos($key, $member, ...$other_members) {}
public function georadius($key, $lng, $lan, $radius, $unit, array $opts = null) {}
public function georadius_ro($key, $lng, $lan, $radius, $unit, array $opts = null) {}
public function georadiusbymember($key, $member, $radius, $unit, array $opts = null) {}
public function georadiusbymember_ro($key, $member, $radius, $unit, array $opts = null) {}
public function get($key) {}
public function getbit($key, $offset) {}
public function getlasterror() {}
public function getmode() {}
public function getoption($option) {}
public function getrange($key, $start, $end) {}
public function getset($key, $value) {}
public function hdel($key, $member, ...$other_members) {}
public function hexists($key, $member) {}
public function hget($key, $member) {}
public function hgetall($key) {}
public function hincrby($key, $member, $value) {}
public function hincrbyfloat($key, $member, $value) {}
public function hkeys($key) {}
public function hlen($key) {}
public function hmget($key, array $keys) {}
public function hmset($key, array $pairs) {}
public function hscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function hset($key, $member, $value) {}
public function hsetnx($key, $member, $value) {}
public function hstrlen($key, $member) {}
public function hvals($key) {}
public function incr($key) {}
public function incrby($key, $value) {}
public function incrbyfloat($key, $value) {}
public function info($key_or_address, $option = null) {}
public function keys($pattern) {}
public function lastsave($key_or_address) {}
public function lget($key, $index) {}
public function lindex($key, $index) {}
public function linsert($key, $position, $pivot, $value) {}
public function llen($key) {}
public function lpop($key) {}
public function lpush($key, $value) {}
public function lpushx($key, $value) {}
public function lrange($key, $start, $end) {}
public function lrem($key, $value) {}
public function lset($key, $index, $value) {}
public function ltrim($key, $start, $stop) {}
public function mget(array $keys) {}
public function mset(array $pairs) {}
public function msetnx(array $pairs) {}
public function multi() {}
public function object($field, $key) {}
public function persist($key) {}
public function pexpire($key, $timestamp) {}
public function pexpireat($key, $timestamp) {}
public function pfadd($key, array $elements) {}
public function pfcount($key) {}
public function pfmerge($dstkey, array $keys) {}
public function ping($key_or_address) {}
public function psetex($key, $expire, $value) {}
public function psubscribe(array $patterns, $callback) {}
public function pttl($key) {}
public function publish($channel, $message) {}
public function pubsub($key_or_address, $arg = null, ...$other_args) {}
public function punsubscribe($pattern, ...$other_patterns) {}
public function randomkey($key_or_address) {}
public function rawcommand($cmd, ...$args) {}
public function rename($key, $newkey) {}
public function renamenx($key, $newkey) {}
public function restore($ttl, $key, $value) {}
public function role() {}
public function rpop($key) {}
public function rpoplpush($src, $dst) {}
public function rpush($key, $value) {}
public function rpushx($key, $value) {}
public function sadd($key, $value) {}
public function saddarray($key, array $options) {}
public function save($key_or_address) {}
public function scan(&$i_iterator, $str_node, $str_pattern = null, $i_count = null) {}
public function scard($key) {}
public function script($key_or_address, $arg = null, ...$other_args) {}
public function sdiff($key, ...$other_keys) {}
public function sdiffstore($dst, $key, ...$other_keys) {}
public function set($key, $value, $opts = null) {}
public function setbit($key, $offset, $value) {}
public function setex($key, $expire, $value) {}
public function setnx($key, $value) {}
public function setoption($option, $value) {}
public function setrange($key, $offset, $value) {}
public function sinter($key, ...$other_keys) {}
public function sinterstore($dst, $key, ...$other_keys) {}
public function sismember($key, $value) {}
public function slowlog($key_or_address, $arg = null, ...$other_args) {}
public function smembers($key) {}
public function smove($src, $dst, $value) {}
public function sort($key, array $options = null) {}
public function spop($key) {}
public function srandmember($key, $count = null) {}
public function srem($key, $value) {}
public function sscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function strlen($key) {}
public function subscribe(array $channels, $callback) {}
public function sunion($key, ...$other_keys) {}
public function sunionstore($dst, $key, ...$other_keys) {}
public function time() {}
public function randomkey() {}
public function ping() {}
public function echo() {}
public function command() {}
public function rawcommand() {}
public function cluster() {}
public function client() {}
public function config() {}
public function pubsub() {}
public function script() {}
public function slowlog() {}
public function geoadd() {}
public function geohash() {}
public function geopos() {}
public function geodist() {}
public function georadius() {}
public function georadiusbymember() {}
public function ttl($key) {}
public function type($key) {}
public function unsubscribe($channel, ...$other_channels) {}
public function unlink($key, ...$other_keys) {}
public function unwatch() {}
public function watch($key, ...$other_keys) {}
public function xack($str_key, $str_group, array $arr_ids) {}
public function xadd($str_key, $str_id, array $arr_fields, $i_maxlen = null, $boo_approximate = null) {}
public function xclaim($str_key, $str_group, $str_consumer, $i_min_idle, array $arr_ids, array $arr_opts = null) {}
public function xdel($str_key, array $arr_ids) {}
public function xgroup($str_operation, $str_key = null, $str_arg1 = null, $str_arg2 = null, $str_arg3 = null) {}
public function xinfo($str_cmd, $str_key = null, $str_group = null) {}
public function xlen($key) {}
public function xpending($str_key, $str_group, $str_start = null, $str_end = null, $i_count = null, $str_consumer = null) {}
public function xrange($str_key, $str_start, $str_end, $i_count = null) {}
public function xread(array $arr_streams, $i_count = null, $i_block = null) {}
public function xreadgroup($str_group, $str_consumer, array $arr_streams, $i_count = null, $i_block = null) {}
public function xrevrange($str_key, $str_start, $str_end, $i_count = null) {}
public function xtrim($str_key, $i_maxlen, $boo_approximate = null) {}
public function zadd($key, $score, $value) {}
public function zcard($key) {}
public function zcount($key, $min, $max) {}
public function zincrby($key, $value, $member) {}
public function zinterstore($key, array $keys, ?array $weights = null, $aggregate = null) {}
public function zlexcount($key, $min, $max) {}
public function zpopmax($key) {}
public function zpopmin($key) {}
public function zrange($key, $start, $end, $scores = null) {}
public function zrangebylex($key, $min, $max, $offset = null, $limit = null) {}
public function zrangebyscore($key, $start, $end, array $options = null) {}
public function zrank($key, $member) {}
public function zrem($key, $member, ...$other_members) {}
public function zremrangebylex($key, $min, $max) {}
public function zremrangebyrank($key, $min, $max) {}
public function zremrangebyscore($key, $min, $max) {}
public function zrevrange($key, $start, $end, $scores = null) {}
public function zrevrangebylex($key, $min, $max, $offset = null, $limit = null) {}
public function zrevrangebyscore($key, $start, $end, array $options = null) {}
public function zrevrank($key, $member) {}
public function zscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) {}
public function zscore($key, $member) {}
public function zunionstore($key, array $keys, ?array $weights = null, $aggregate = null) {}
}
class RedisClusterException extends \RuntimeException {
class RedisClusterException extends \Exception {
// properties
protected $message;
@ -478,7 +535,7 @@ class RedisClusterException extends \RuntimeException {
protected $line;
}
class RedisException extends \RuntimeException {
class RedisException extends \Exception {
// properties
protected $message;

View File

@ -0,0 +1,47 @@
<?php
/**
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*/
// phpcs:ignoreFile
/**
* @param string $text1
* @param string $text2
* @param int $numContextLines
* @param int $movedParagraphDetectionCutoff
* @return string
*/
function wikidiff2_do_diff( $text1, $text2, $numContextLines, $movedParagraphDetectionCutoff = 0 ) {
}
/**
* @param string $text1
* @param string $text2
* @param int $numContextLines
* @return string
*/
function wikidiff2_inline_diff( $text1, $text2, $numContextLines ) {
}
/**
* @param string $text1
* @param string $text2
* @param int $numContextLines
* @return string
*/
function wikidiff2_inline_json_diff( $text1, $text2, $numContextLines ) {
}

View File

@ -0,0 +1,6 @@
<?php
// Stub for PHP 8's ValueError exception
class ValueError extends Error {
}

View File

@ -1,28 +0,0 @@
<?php
/**
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*/
// phpcs:ignoreFile
define( 'HHVM_VERSION', '3.18.6-dev' );
/**
* @param callable $callback
* @param mixed ...$parameters
*/
function register_postsend_function( $callback ) {
}

View File

@ -8,4 +8,3 @@ const PASSWORD_ARGON2ID = 3;
const PASSWORD_ARGON2_DEFAULT_MEMORY_COST = 1024;
const PASSWORD_ARGON2_DEFAULT_THREADS = 2;
const PASSWORD_ARGON2_DEFAULT_TIME_COST = 2;

View File

@ -1,11 +0,0 @@
<?php
/**
* Some old classes from PHPUnit 4 that MediaWiki (conditionally) references.
*
* phpcs:ignoreFile
*/
class PHPUnit_TextUI_Command {
}

View File

@ -1,39 +0,0 @@
<?php
/**
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*/
// phpcs:ignoreFile
/**
* @param string $text1
* @param string $text2
* @param int $numContextLines
* @param int $movedParagraphDetectionCutoff
* @return string
*/
function wikidiff2_do_diff( $text1, $text2, $numContextLines, $movedParagraphDetectionCutoff = 0 ) {
}
/**
* @param string $text1
* @param string $text2
* @param int $numContextLines
* @param int $maxMovedLines
* @return string
*/
function wikidiff2_inline_diff( $text1, $text2, $numContextLines, $maxMovedLines = 25 ) {
}

253
.phpcs.xml Normal file
View File

@ -0,0 +1,253 @@
<?xml version="1.0"?>
<ruleset name="MediaWiki">
<rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki">
<exclude name="Generic.ControlStructures.InlineControlStructure" />
<exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationPrivate" />
<exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationProtected" />
<exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic" />
<exclude name="MediaWiki.ControlStructures.AssignmentInControlStructures.AssignmentInControlStructures" />
<exclude name="MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName" />
<exclude name="MediaWiki.Usage.DbrQueryUsage.DbrQueryFound" />
<exclude name="MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgContLang" />
<exclude name="MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgMemc" />
<exclude name="MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgTitle" />
<exclude name="MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgUser" />
<exclude name="MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgVersion" />
<exclude name="MediaWiki.Usage.ForbiddenFunctions.passthru" />
<exclude name="MediaWiki.WhiteSpace.SpaceBeforeSingleLineComment.NewLineComment" />
</rule>
<!-- TODO Still to be done -->
<rule ref="MediaWiki.Commenting.FunctionComment.WrongStyle">
<exclude-pattern>includes/</exclude-pattern>
</rule>
<!-- See T238572 -->
<rule ref="MediaWiki.Commenting.FunctionComment.MissingParamTag">
<exclude-pattern>tests/</exclude-pattern>
</rule>
<rule ref="MediaWiki.NamingConventions.PrefixedGlobalFunctions">
<properties>
<!--
includes/GlobalFunctions.php
* mimeTypeMatch
maintenance/language/transstat.php
* showUsage
maintenance/mcc.php
* mccGetHelp
* mccShowUsage
maintenance/storage/moveToExternal.php
* moveToExternal
maintenance/storage/resolveStubs.php
* resolveStub
* resolveStubs
tests/phpunit/includes/HooksTest.php
* NothingFunction
* NothingFunctionData
tests/qunit/data/styleTest.css.php
* cssfilter
-->
<property name="ignoreList" type="array" value="cssfilter,mccGetHelp,mccShowUsage,mimeTypeMatch,moveToExternal,NothingFunction,NothingFunctionData,resolveStub,resolveStubs,showUsage" />
</properties>
</rule>
<rule ref="MediaWiki.NamingConventions.ValidGlobalName">
<properties>
<property name="ignoreList" type="array" value="$IP" />
</properties>
</rule>
<rule ref="MediaWiki.NamingConventions.ValidGlobalName.allowedPrefix">
<exclude-pattern>maintenance/language/checkLanguage\.inc</exclude-pattern>
<exclude-pattern>maintenance/doMaintenance\.php</exclude-pattern>
<exclude-pattern>maintenance/mergeMessageFileList\.php</exclude-pattern>
<exclude-pattern>maintenance/commandLine\.inc</exclude-pattern>
<exclude-pattern>tests/phpunit/MediaWikiIntegrationTestCase\.php</exclude-pattern>
</rule>
<rule ref="Generic.Files.LineLength">
<exclude-pattern>*/languages/messages/Messages*\.php</exclude-pattern>
</rule>
<rule ref="MediaWiki.Files.ClassMatchesFilename.NotMatch">
<!--
Whitelist existing violations, but enable the sniff to prevent
any new occurrences.
-->
<exclude-pattern>*/includes/specials/SpecialMostimages\.php</exclude-pattern>
<exclude-pattern>*/includes/specials/SpecialMovepage\.php</exclude-pattern>
<exclude-pattern>*/includes/specials/SpecialRandompage\.php</exclude-pattern>
<exclude-pattern>*/includes/specials/SpecialUserrights\.php</exclude-pattern>
<exclude-pattern>*/includes/specials/SpecialWantedfiles\.php</exclude-pattern>
<exclude-pattern>*/includes/specials/SpecialWantedpages\.php</exclude-pattern>
<exclude-pattern>*/maintenance/CodeCleanerGlobalsPass.inc</exclude-pattern>
<exclude-pattern>*/maintenance/archives/upgradeLogging\.php</exclude-pattern>
<exclude-pattern>*/maintenance/benchmarks/bench_HTTP_HTTPS\.php</exclude-pattern>
<exclude-pattern>*/maintenance/benchmarks/bench_Wikimedia_base_convert\.php</exclude-pattern>
<exclude-pattern>*/maintenance/benchmarks/bench_delete_truncate\.php</exclude-pattern>
<exclude-pattern>*/maintenance/benchmarks/bench_if_switch\.php</exclude-pattern>
<exclude-pattern>*/maintenance/benchmarks/bench_utf8_title_check\.php</exclude-pattern>
<exclude-pattern>*/maintenance/benchmarks/bench_wfIsWindows\.php</exclude-pattern>
<exclude-pattern>*/maintenance/cleanupTable.inc</exclude-pattern>
<exclude-pattern>*/maintenance/cleanupTitles\.php</exclude-pattern>
<exclude-pattern>*/maintenance/commandLine.inc</exclude-pattern>
<exclude-pattern>*/maintenance/edit\.php</exclude-pattern>
<exclude-pattern>*/maintenance/findDeprecated\.php</exclude-pattern>
<exclude-pattern>*/maintenance/getText\.php</exclude-pattern>
<exclude-pattern>*/maintenance/importDump\.php</exclude-pattern>
<exclude-pattern>*/maintenance/install\.php</exclude-pattern>
<exclude-pattern>*/maintenance/invalidateUserSessions\.php</exclude-pattern>
<exclude-pattern>*/maintenance/jsparse\.php</exclude-pattern>
<exclude-pattern>*/maintenance/lag\.php</exclude-pattern>
<exclude-pattern>*/maintenance/language/StatOutputs\.php</exclude-pattern>
<exclude-pattern>*/maintenance/language/checkLanguage.inc</exclude-pattern>
<exclude-pattern>*/maintenance/language/date-formats\.php</exclude-pattern>
<exclude-pattern>*/maintenance/language/languages.inc</exclude-pattern>
<exclude-pattern>*/maintenance/minify\.php</exclude-pattern>
<exclude-pattern>*/maintenance/mysql\.php</exclude-pattern>
<exclude-pattern>*/maintenance/parse\.php</exclude-pattern>
<exclude-pattern>*/maintenance/preprocessorFuzzTest\.php</exclude-pattern>
<exclude-pattern>*/maintenance/rebuildImages\.php</exclude-pattern>
<exclude-pattern>*/maintenance/renderDump\.php</exclude-pattern>
<exclude-pattern>*/maintenance/shell\.php</exclude-pattern>
<exclude-pattern>*/maintenance/sql\.php</exclude-pattern>
<exclude-pattern>*/maintenance/sqlite.inc</exclude-pattern>
<exclude-pattern>*/maintenance/sqlite\.php</exclude-pattern>
<exclude-pattern>*/maintenance/term/MWTerm\.php</exclude-pattern>
<exclude-pattern>*/maintenance/update\.php</exclude-pattern>
<exclude-pattern>*/maintenance/userDupes.inc</exclude-pattern>
<exclude-pattern>*/maintenance/userOptions\.php</exclude-pattern>
<exclude-pattern>*/maintenance/view\.php</exclude-pattern>
<!-- Language converters use the pattern of 2 classes in one file -->
<exclude-pattern>*/languages/*\.php</exclude-pattern>
<!-- Skip violations in some tests for now -->
<exclude-pattern>*/tests/parser/*\.php</exclude-pattern>
<exclude-pattern>*/tests/phan/*\.php</exclude-pattern>
<exclude-pattern>*/tests/phpunit/maintenance/*\.php</exclude-pattern>
<exclude-pattern>*/tests/phpunit/bootstrap\.php</exclude-pattern>
<exclude-pattern>*/tests/phpunit/phpunit\.php</exclude-pattern>
</rule>
<rule ref="MediaWiki.Files.ClassMatchesFilename.WrongCase">
<!--
Whitelist existing violations, but enable the sniff to prevent
any new occurrences.
-->
<exclude-pattern>*/maintenance/language/alltrans\.php</exclude-pattern>
<exclude-pattern>*/maintenance/language/digit2html\.php</exclude-pattern>
<exclude-pattern>*/maintenance/language/langmemusage\.php</exclude-pattern>
<exclude-pattern>*/maintenance/mctest\.php</exclude-pattern>
<exclude-pattern>*/maintenance/mergeMessageFileList\.php</exclude-pattern>
<exclude-pattern>*/maintenance/mwdocgen\.php</exclude-pattern>
<exclude-pattern>*/maintenance/rebuildall\.php</exclude-pattern>
<exclude-pattern>*/maintenance/rebuildmessages\.php</exclude-pattern>
<exclude-pattern>*/maintenance/rebuildrecentchanges\.php</exclude-pattern>
<exclude-pattern>*/maintenance/rebuildtextindex\.php</exclude-pattern>
<exclude-pattern>*/maintenance/storage/checkStorage\.php</exclude-pattern>
<exclude-pattern>*/maintenance/storage/recompressTracked\.php</exclude-pattern>
<exclude-pattern>*/maintenance/storage/trackBlobs\.php</exclude-pattern>
<!-- Skip violations in some tests for now -->
<exclude-pattern>*/tests/phpunit/unit/includes/GlobalFunctions/*\.php</exclude-pattern>
<exclude-pattern>*/tests/phpunit/includes/GlobalFunctions/*\.php</exclude-pattern>
<exclude-pattern>*/tests/phpunit/maintenance/*\.php</exclude-pattern>
<exclude-pattern>*/tests/phpunit/integration/includes/GlobalFunctions/*\.php</exclude-pattern>
</rule>
<rule ref="Generic.PHP.NoSilencedErrors.Discouraged">
<!--
Our normal policy of using Wikimedia\AtEase does not always make sense tests.
AtEase cannot be cleanly used in tests that also use expectException() as
the restoreWarnings() call would never be reached:
$this->expectException( PasswordError::class );
AtEase::suppressWarnings();
$password->crypt( 'whatever' );
AtEase::restoreWarnings();
The above will stop at crypt(), as expected, and leave AtEase in a dirty
state for unrelated tests.
TODO: Stop using PHPUnit TestCase directly. Require with a structure test
or with a high-level check in our run() hook, that all test cases use either
MediaWikiUnitTestCase or MediaWikiIntegrationTestCase. Otherwise the check
in MediaWikiTestCaseTrait can still be bypassed and cause a random failures.
-->
<exclude-pattern>*/tests/*\.php</exclude-pattern>
</rule>
<rule ref="Generic.Files.OneObjectStructurePerFile.MultipleFound">
<!--
Whitelist existing violations, but enable the sniff to prevent
any new occurrences.
-->
<exclude-pattern>*/maintenance/dumpIterator\.php</exclude-pattern>
<exclude-pattern>*/maintenance/findDeprecated\.php</exclude-pattern>
<exclude-pattern>*/maintenance/storage/recompressTracked\.php</exclude-pattern>
<exclude-pattern>*/maintenance/preprocessorFuzzTest\.php</exclude-pattern>
<exclude-pattern>*/maintenance/language/languages.inc</exclude-pattern>
<exclude-pattern>*/maintenance/language/StatOutputs\.php</exclude-pattern>
<exclude-pattern>*/maintenance/language/checkLanguage.inc</exclude-pattern>
<exclude-pattern>*/maintenance/language/generateCollationData\.php</exclude-pattern>
<exclude-pattern>*/maintenance/term/MWTerm\.php</exclude-pattern>
<!-- Language converters use the pattern of 2 classes in one file -->
<exclude-pattern>*/languages/*\.php</exclude-pattern>
<!-- We don't care that much about violations in tests -->
<exclude-pattern>*/tests/*\.php</exclude-pattern>
</rule>
<rule ref="PSR2.Methods.MethodDeclaration.Underscore">
<exclude-pattern>*/includes/StubObject\.php</exclude-pattern>
<exclude-pattern>*/includes/StubUserLang\.php</exclude-pattern>
</rule>
<rule ref="MediaWiki.Usage.AssignmentInReturn.AssignmentInReturn">
<exclude-pattern>*/tests/phpunit/*\.php</exclude-pattern>
</rule>
<rule ref="MediaWiki.Usage.ForbiddenFunctions.escapeshellarg">
<!--
Whitelist existing violations, but enable the sniff to prevent
any new occurrences.
-->
<exclude-pattern>*/includes/libs/filebackend/FSFileBackend\.php</exclude-pattern>
<exclude-pattern>*/includes/shell/Command\.php</exclude-pattern>
<exclude-pattern>*/includes/shell/Shell\.php</exclude-pattern>
</rule>
<rule ref="MediaWiki.Usage.ForbiddenFunctions.popen">
<!--
Whitelist existing violations, but enable the sniff to prevent
any new occurrences.
-->
<exclude-pattern>*/includes/GlobalFunctions\.php</exclude-pattern>
<exclude-pattern>*/includes/libs/filebackend/FSFileBackend\.php</exclude-pattern>
<exclude-pattern>*/maintenance/includes/SevenZipStream\.php</exclude-pattern>
<exclude-pattern>*/maintenance/populateImageSha1\.php</exclude-pattern>
</rule>
<rule ref="MediaWiki.Usage.ForbiddenFunctions.proc_open">
<!--
Whitelist existing violations, but enable the sniff to prevent
any new occurrences.
-->
<exclude-pattern>includes/export/DumpPipeOutput\.php</exclude-pattern>
<exclude-pattern>includes/resourceloader/ResourceLoaderImage\.php</exclude-pattern>
<exclude-pattern>includes/shell/Command\.php</exclude-pattern>
<exclude-pattern>maintenance/includes/TextPassDumper\.php</exclude-pattern>
<exclude-pattern>maintenance/mysql\.php</exclude-pattern>
<exclude-pattern>maintenance/storage/recompressTracked\.php</exclude-pattern>
<exclude-pattern>tests/parser/editTests\.php</exclude-pattern>
</rule>
<rule ref="MediaWiki.Usage.ForbiddenFunctions.shell_exec">
<!--
Whitelist existing violations, but enable the sniff to prevent
any new occurrences.
-->
<exclude-pattern>*/maintenance/mwdocgen\.php</exclude-pattern>
<exclude-pattern>*/maintenance/updateCredits\.php</exclude-pattern>
</rule>
<rule ref="MediaWiki.Usage.ForbiddenFunctions.system">
<!--
Whitelist existing violations, but enable the sniff to prevent
any new occurrences.
-->
<exclude-pattern>*/maintenance/mwdocgen\.php</exclude-pattern>
</rule>
<rule ref="MediaWiki.Commenting.MissingCovers.MissingCovers">
<exclude-pattern>tests/phpunit/structure/*</exclude-pattern>
</rule>
<file>.</file>
<arg name="encoding" value="UTF-8"/>
<arg name="extensions" value="php,php5,inc,sample"/>
<exclude-pattern type="relative">^extensions/</exclude-pattern>
<exclude-pattern type="relative">^skins/</exclude-pattern>
<exclude-pattern>LocalSettings\.php</exclude-pattern>
</ruleset>

View File

@ -1,5 +1,5 @@
version: v4
base: docker-registry.wikimedia.org/dev/stretch-php72-fpm-apache2
base: docker-registry.wikimedia.org/dev/stretch-php72-fpm-apache2-blubber
lives:
in: /var/www/html

View File

@ -2,7 +2,8 @@ pipelines:
publish:
blubberfile: blubber.yaml
stages:
- name: publish
- name: dev
build: dev
publish:
image: true
image:
tags: [dev]

View File

@ -1,12 +1,14 @@
#!/bin/sh
#!/bin/bash
mkdir /tmp/php
set -eo pipefail
mkdir -p /tmp/php
mkdir -p extensions
git clone --depth 1 https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor.git /var/www/html/extensions/VisualEditor
git clone --depth 1 https://gerrit.wikimedia.org/r/mediawiki/skins/Vector /var/www/html/skins/Vector
cd /var/www/html/extensions/VisualEditor
git submodule update --depth 1 --init
git submodule update --depth 10 --init
cd /var/www/html
composer install

8
.stylelintrc.json Normal file
View File

@ -0,0 +1,8 @@
{
"extends": "stylelint-config-wikimedia",
"rules": {
"selector-class-pattern": "^((mw|oo-ui)-|(wikitable|(toc(|toggle|hidden))|client-(no)?js)$)",
"no-descending-specificity": null,
"selector-max-id": null
}
}

48
CREDITS
View File

@ -1,5 +1,5 @@
{{int:version-credits-summary}} <!--
MediaWiki 1.34 is a collaborative project released under the
MediaWiki 1.35 is a collaborative project released under the
GNU General Public License v2. We would like to recognize the
following names for their contribution to the product.
@ -8,12 +8,15 @@ The following list can be found parsed under Special:Version/Credits -->
== Contributors ==
<!-- Updates to this list made with maintenance/updateCredits.php -->
<!-- BEGIN CONTRIBUTOR LIST -->
* 4shadoww
* aalekhN
* Aaron Ball
* Aaron Pramana
* Aaron S. Hawley
* Aaron Schulz
* Aarti Dwivedi
* Aashaka Shah
* Abbe98
* abhinand
* Abhishek Das
* Abián
@ -27,11 +30,13 @@ The following list can be found parsed under Special:Version/Credits -->
* Adrian Heine
* Adrian Lang
* Ævar Arnfjörð Bjarmason
* Aezell
* Aftab
* Agabi10
* Agbad
* Ahmad Sherif
* Ajayrahul P
* Akinwale Alagbe
* Alangi Derick
* Albert221
* Alejandro Mery
@ -48,6 +53,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Alexander Sigachov
* Alexandre Emsenhuber
* Alexia E. Smith
* AlQaholic007
* Amalthea
* Amir E. Aharoni
* Amir Sarabadani
@ -69,6 +75,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Andrius R
* andymw
* Angela Beesley Starling
* ankit
* ankur
* Antoine Musso
* Antoni Siek
@ -79,10 +86,15 @@ The following list can be found parsed under Special:Version/Credits -->
* Aran Dunkley
* Arash Boostani
* Arcane21
* arcayn
* Ariel Glenn
* Arlo Breault
* Arne Heizmann
* AronDemian
* ArtBaltai
* Arthur Richards
* arttsymbar
* Arturek1
* Aryeh Gregor
* Asher Feldman
* Asier Lostalé
@ -108,6 +120,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Billinghurst
* billm
* Bjornskjald
* bkudiess-msft
* blackspirit96
* blotmandroid
* Bogdan Stancescu
@ -116,6 +129,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Brad Jorsch
* Brandon Black
* Brandon Harris
* BrandonXLF
* brendajerop
* Brennen Bearnes
* Brent G
@ -152,6 +166,8 @@ The following list can be found parsed under Special:Version/Credits -->
* ckoerner
* Clara Andrew-Wani
* clarakosi
* cobaltcigs
* Cole White
* Conrad Irwin
* Cormac Parle
* cryptocoryne
@ -180,6 +196,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Darkdragon09
* DaSch
* datguy
* Dave Pifke
* David Barratt
* David Baumgarten
* David Causse
@ -284,6 +301,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Hagar Shilo
* Haikal Izzuddin
* HakanIST
* Hank Hulet
* Happy-melon
* haritha28
* Harry Burt
@ -291,6 +309,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Hector A Escobedo
* Helder
* Henning Snater
* hmonroy
* Hojjat
* Holger Knust
* Hoto Cocoa
@ -298,11 +317,13 @@ The following list can be found parsed under Special:Version/Credits -->
* Hydriz
* Ian Baker
* Ian Marlier
* IijimaYun
* Ilmari Karonen
* Inez Korczyński
* IoannisKydonis
* Ireas
* isarra
* Itamar Givon
* Ivan Lanin
* Jack D. Pond
* Jack Phoenix
@ -331,6 +352,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Jason Richey
* JasonCoombs
* Jayprakash12345
* Jeena Huneidi
* Jeff Hobson
* Jeff Janes
* jeff303
@ -380,6 +402,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Katie Filbert
* KeerthanaS
* Kevin Israel
* kevinbazira
* Kghbln
* Kim Eik
* Kim Hyun-Joon
@ -399,7 +422,9 @@ The following list can be found parsed under Special:Version/Credits -->
* Lee Worden
* Lejonel
* lekshmi
* lens0021
* Leo Koppelkamm
* leo60228
* Leon Liesener
* Leon Weber
* Leonardo Gregianin
@ -427,6 +452,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Lupin
* Lupo
* lwelling
* lziad
* m4tx
* Madman
* madurangasiriwardena
@ -434,6 +460,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Mahuton
* mainframe98
* Mako Bates
* Manuel Alcaraz Zambrano
* Manuel Menal
* Manuel Schneider
* Marc Ordinas i Llopis
@ -477,6 +504,7 @@ The following list can be found parsed under Special:Version/Credits -->
* mayankmadan
* Mehmet Mert Yıldıran
* Melos
* Memmie Lenglet
* Meno25
* merl
* Merlijn S. van Deen
@ -503,6 +531,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Mogmog123
* Mohamed Magdy
* Molly White
* montehurd
* Moriel Schottlender
* Moritz Oberhauser
* Mormegil
@ -510,6 +539,7 @@ The following list can be found parsed under Special:Version/Credits -->
* MR70
* MrBlueSky
* MrPete
* mszabo-wikia
* Mukunda Modell
* MusikAnimal
* Mwalker
@ -536,6 +566,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Niharika Kohli
* Nik Everett
* Nikita Rana
* Nikki Nikkhoui
* Niklas Laxström
* Nikola Kovacs
* Nikola Smolenski
@ -579,6 +610,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Peter Coombe
* Peter Gehres
* Peter Hedenskog
* Peter Ovchyn
* Peter Potrowl
* Petr Bena
* Petr Kadlec
@ -587,6 +619,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Phantom42
* Philip Tzou
* physikerwelt (Moritz Schubotz)
* Pierre Boutet
* PieRRoMaN
* Pikne
* Piotr Miazga
@ -619,6 +652,7 @@ The following list can be found parsed under Special:Version/Credits -->
* René Kijewski
* Reza
* rgcjonas
* RhinosF1
* Ricordisamoa
* rillke
* River Tarnell
@ -641,6 +675,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Roman Tsukanov
* Rotem Liss
* Rowan Collins
* Ruben Barkow-Kuder
* runntb
* Russ Nelson
* Russell Blau
@ -654,7 +689,9 @@ The following list can be found parsed under Special:Version/Credits -->
* Ryan Schmidt
* ryan10145
* S Page
* Sahajsk`
* Saint Johann
* Sakretsu
* Salvatore Ingala
* Sam Reed
* Sam Smith
@ -683,6 +720,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Shane Gibbons
* Shane King
* shanika
* shcherba
* Shinjiman
* shirayuki
* Shreyas Minocha
@ -692,6 +730,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Simon Legner
* Simon Walker
* Smriti Singh
* Sohom Datta
* Solitarius
* Sorawee Porncharoenwase
* Søren Løvborg
@ -716,6 +755,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Strainu
* Subin Siby
* Subramanya Sastry
* suecarmol
* Sumit Asthana
* superyetkin
* Suriyaa Kudo
@ -723,6 +763,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Szymon Świerkosz
* T. Bayer
* T.D. Corell
* Taavi Väänänen
* tacsipacsi
* Tarquin
* TerraCodes
@ -750,6 +791,7 @@ The following list can be found parsed under Special:Version/Credits -->
* tjlsangria
* Tjones
* TK-999
* Tobi_406
* Tobias Gritschacher
* Tom Arrow
* Tom Gilder
@ -775,11 +817,14 @@ The following list can be found parsed under Special:Version/Credits -->
* utkarsh95
* Valerio Bozzolan
* Van de Bugger
* Varun Das
* Vas Jaremchuk
* Vedmaka
* Viačeslav
* Victor Barbu
* Victor Porton
* Victor Vasiliev
* vidhi-mody
* Ville Stadista
* Vincent Privat
* vinithegit
@ -816,6 +861,7 @@ The following list can be found parsed under Special:Version/Credits -->
* Zhuyifei1999
* Zoranzoki21
* Zppix
* Þjarkur
* محمد شعیب
* 星耀晨曦
<!-- END CONTRIBUTOR LIST -->

230
DEVELOPERS.md Normal file
View File

@ -0,0 +1,230 @@
# MediaWiki Developers
Welcome to the MediaWiki community! Please see [How to become a MediaWiki
hacker](https://www.mediawiki.org/wiki/How_to_become_a_MediaWiki_hacker) for
general information on contributing to MediaWiki.
## Docker Developer Environment
MediaWiki provides an extendable local development environment based on
Docker Compose.
The default environment provides PHP, Apache, XDebug and a SQLite database.
(**Do not run this stack in production! Bad things might happen!**)
More documentation as well as example overrides and configuration recipes
are available at [mediawiki.org/wiki/MediaWiki-Docker][mw-docker].
Support is available on the [Freenode IRC network][freenode] at `#mediawiki`
and on Wikimedia Phabricator at [#MediaWiki-Docker][mw-docker-phab].
[mw-docker]: https://www.mediawiki.org/wiki/MediaWiki-Docker
[mw-docker-phab]: https://phabricator.wikimedia.org/project/profile/3094/
[freenode]: https://freenode.net/
### Requirements
You'll need a locally running Docker and Docker Compose:
- [Docker installation instructions][docker-install]
- [Docker Compose installation instructions][docker-compose]
[docker-install]: https://docs.docker.com/install/
[docker-compose]: https://docs.docker.com/compose/install/
---
**Linux users**
* We recommend installing `docker-compose` by [downloading the binary release](https://docs.docker.com/compose/install/#install-compose-on-linux-systems). You can also use `pip`, your OS package manager, or even run it in a container, but downloading the binary release is the easiest method.
* Follow the instructions to ["Manage Docker as a non-root user"](https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user)
---
### Quickstart
Using a text editor, create a `.env` file in the root of the MediaWiki core repository, and copy these contents into that file:
```bash
MW_DOCKER_PORT=8080
MW_SCRIPT_PATH=/
MW_SERVER=http://localhost:8080
MEDIAWIKI_USER=Admin
MEDIAWIKI_PASSWORD=dockerpass
XDEBUG_CONFIG=''
```
#### Linux users
If you are on a Linux system, first create a
`docker-compose.override.yml` containing the following:
```yaml
version: '3.7'
services:
mediawiki:
# On Linux, these lines ensure file ownership is set to your host user/group
user: "${MW_DOCKER_UID}:${MW_DOCKER_GID}"
```
Run the following command to add your user ID and group ID to your `.env` file:
```bash
echo "MW_DOCKER_UID=$(id -u)
MW_DOCKER_GID=$(id -g)" >> .env
```
#### Start environment and install MediaWiki
Start the environment:
```sh
# -d is detached mode - runs containers in the background:
docker-compose up -d
```
Install Composer dependencies:
```sh
docker-compose exec mediawiki composer update
```
Install MediaWiki in the environment:
```sh
docker-compose exec mediawiki /bin/bash /docker/install.sh
```
##### Re-install
Remove or rename `LocalSettings.php`, delete the `cache/sqlite` directory, then
re-run the installation command above. Copy over any changes from your previous
`LocalSettings.php` and then run `maintenance/update.php`.
### Usage
#### Running commands
You can use `docker-compose exec mediawiki bash` to open a bash shell in the
MediaWiki container, or you can run commands in the container from your host,
for example: `docker-compose exec mediawiki php maintenance/update.php`
#### Running tests
##### PHPUnit
Run all tests:
```sh
docker-compose exec mediawiki php tests/phpunit/phpunit.php
```
Run a single test:
```sh
docker-compose exec mediawiki php tests/phpunit/phpunit.php /path/to/test
```
See [PHPUnit Testing][phpunit-testing] on MediaWiki.org for more help.
[phpunit-testing]: https://www.mediawiki.org/wiki/Manual:PHP_unit_testing/Running_the_unit_tests
##### Selenium
You can use [Fresh][fresh] to run [Selenium in a dedicated
container][selenium-dedicated]. Example usage:
```sh
export MW_SERVER=http://localhost:8080
export MW_SCRIPT_PATH=/
export MEDIAWIKI_USER=Admin
export MEDIAWIKI_PASSWORD=dockerpass
fresh-node -env -net
npm ci
npm run selenium
```
[selenium-dedicated]: https://www.mediawiki.org/wiki/Selenium/Node.js/Target_Local_MediaWiki_(Container)
#### API Testing
You can use [Fresh][fresh] to run [API tests in a dedicated
container][api-dedicated]. Example usage:
```sh
export MW_SERVER=http://localhost:8080/
export MW_SCRIPT_PATH=/
export MEDIAWIKI_USER=Admin
export MEDIAWIKI_PASSWORD=dockerpass
fresh-node -env -net
# Create .api-testing.config.json as documented on
# https://www.mediawiki.org/wiki/MediaWiki_API_integration_tests
npm ci
npm run api-testing
```
[fresh]: https://github.com/wikimedia/fresh
[api-dedicated]: https://www.mediawiki.org/wiki/MediaWiki_API_integration_tests
### Modifying the development environment
You can override the default services with a `docker-compose.override.yml`
file, and configure those overrides with changes to `LocalSettings.php`.
Example overrides and configurations can be found at [MediaWiki-Docker](https://www.mediawiki.org/wiki/MediaWiki-Docker)
After updating `docker-compose.override.yml`, run `docker-compose down`
followed by `docker-compose up -d` for changes to take effect.
#### Installing extra packages
If you need root on the container to install packages for troubleshooting,
you can open a shell as root with `docker-compose exec --user root mediawiki
bash`.
#### Use Vector skin
Clone the skin to `skins/Vector`:
```sh
git clone "https://gerrit.wikimedia.org/r/mediawiki/skins/Vector" skins/Vector
```
Configure MediaWiki to use the skin:
```sh
echo "wfLoadSkin( 'Vector' );" >> LocalSettings.php
```
#### XDebug
You can override the XDebug configuration included with the default image by
passing `XDEBUG_CONFIG={your config}` in the `.env` file at the root of the MediaWiki repository:
```
XDEBUG_CONFIG=remote_enable=1 remote_host=172.17.0.1 remote_log=/tmp/xdebug.log remote_port=9009
```
##### Troubleshooting
###### Port conflicts
If you installed php-fpm on your host, that is listening on port 9000 and
will conflict with XDebug. The workaround is to tell your IDE to listen on a
different port (e.g. 9009) and to set the configuration in your
`.env` file: `XDEBUG_CONFIG=remote_port=9009`
###### Linux desktop, host not found
The image uses `host.docker.internal` as the `remote_host` value which
should work for Docker for Mac/Windows. On Linux hosts, you need to specify
the hostname or IP address of your host. The IP address works more reliably.
You can obtain it by running e.g. `ip -4 addr show docker0` and copying the
IP address into the config, like `XDEBUG_CONFIG=remote_host=172.17.0.1`
###### Generating logs
Switching on the remote log for XDebug comes at a performance cost so only
use it while troubleshooting. You can enable it like so: `XDEBUG_CONFIG=remote_log=/tmp/xdebug.log`

View File

@ -1,7 +1,5 @@
/* eslint-env node */
module.exports = function ( grunt ) {
var wgServer = process.env.MW_SERVER,
wgScriptPath = process.env.MW_SCRIPT_PATH,
karmaProxy = {};
@ -21,24 +19,11 @@ module.exports = function ( grunt ) {
grunt.initConfig( {
eslint: {
options: {
reportUnusedDisableDirectives: true,
extensions: [ '.js', '.json' ],
cache: true
extensions: [ '.js', '.json', '.vue' ],
cache: true,
fix: grunt.option( 'fix' )
},
all: [
'**/*.{js,json}',
'!docs/**',
'!node_modules/**',
'!resources/lib/**',
'!resources/src/jquery.tipsy/**',
'!resources/src/mediawiki.libs.jpegmeta/**',
// Third-party code of PHPUnit coverage report
'!tests/coverage/**',
'!vendor/**',
// Explicitly say "**/*.js" here in case of symlinks
'!extensions/**/*.js{,on}',
'!skins/**/*.js{,on}'
]
all: '.'
},
banana: {
options: {
@ -48,10 +33,12 @@ module.exports = function ( grunt ) {
core: 'languages/i18n/',
exif: 'languages/i18n/exif/',
api: 'includes/api/i18n/',
installer: 'includes/installer/i18n/'
rest: 'includes/Rest/i18n/',
installer: 'includes/installer/i18n/',
paramvalidator: 'includes/libs/ParamValidator/i18n/'
},
stylelint: {
src: '{resources/src,mw-config}/**/*.{css,less}'
src: '{resources/src,mw-config}/**/*.{css,less,vue}'
},
svgmin: {
options: {
@ -102,12 +89,8 @@ module.exports = function ( grunt ) {
ChromeCustom: {
base: 'ChromeHeadless',
// Chrome requires --no-sandbox in Docker/CI.
// Newer CI images expose CHROMIUM_FLAGS which sets this (and
// anything else it might need) automatically. Older CI images,
// (including Quibble for MW) don't set it yet.
flags: ( process.env.CHROMIUM_FLAGS ||
( process.env.ZUUL_PROJECT ? '--no-sandbox' : '' )
).split( ' ' )
// WMF CI images expose CHROMIUM_FLAGS which sets that.
flags: ( process.env.CHROMIUM_FLAGS || '' ).split( ' ' )
}
},
proxies: karmaProxy,
@ -148,16 +131,19 @@ module.exports = function ( grunt ) {
} );
grunt.registerTask( 'assert-mw-env', function () {
var ok = true;
if ( !process.env.MW_SERVER ) {
grunt.log.error( 'Environment variable MW_SERVER must be set.\n' +
'Set this like $wgServer, e.g. "http://localhost"'
);
ok = false;
}
if ( !process.env.MW_SCRIPT_PATH ) {
grunt.log.error( 'Environment variable MW_SCRIPT_PATH must be set.\n' +
'Set this like $wgScriptPath, e.g. "/w"' );
ok = false;
}
return !!( process.env.MW_SERVER && process.env.MW_SCRIPT_PATH );
return ok;
} );
grunt.registerTask( 'minify', 'svgmin' );

1010
HISTORY

File diff suppressed because it is too large Load Diff

View File

@ -5,9 +5,9 @@ Installing MediaWiki
Starting with MediaWiki 1.2.0, it's possible to install and configure the wiki
"in-place", as long as you have the necessary prerequisites available.
Required software as of MediaWiki 1.34.0:
Required software as of MediaWiki 1.35.0:
* Web server with PHP 7.2.9 or higher, plus the following extensions:
* Web server with PHP 7.3.19 or higher, plus the following extensions:
** ctype
** dom
** fileinfo

33
README
View File

@ -1,33 +0,0 @@
== MediaWiki ==
MediaWiki is a free and open-source wiki software package written in PHP. It
serves as the platform for Wikipedia and the other Wikimedia projects, used
by hundreds of millions of people each month. MediaWiki is localised in over
350 languages and its reliability and robust feature set have earned it a large
and vibrant community of third-party users and developers.
MediaWiki is:
* feature-rich and extensible, both on-wiki and with hundreds of extensions;
* scalable and suitable for both small and large sites;
* simple to install, working on most hardware/software combinations; and
* available in your language.
For system requirements, installation, and upgrade details, see the files
RELEASE-NOTES, INSTALL, and UPGRADE.
* Ready to get started?
** https://www.mediawiki.org/wiki/Special:MyLanguage/Download
* Looking for the technical manual?
** https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents
* Seeking help from a person?
** https://www.mediawiki.org/wiki/Special:MyLanguage/Communication
* Looking to file a bug report or a feature request?
** https://bugs.mediawiki.org/
* Interested in helping out?
** https://www.mediawiki.org/wiki/Special:MyLanguage/How_to_contribute
MediaWiki is the result of global collaboration and cooperation. The CREDITS
file lists technical contributors to the project. The COPYING file explains
MediaWiki's copyright and license (GNU General Public License, version 2 or
later). Many thanks to the Wikimedia community for testing and suggestions.

33
README.md Normal file
View File

@ -0,0 +1,33 @@
# MediaWiki
MediaWiki is a free and open-source wiki software package written in PHP. It
serves as the platform for Wikipedia and the other Wikimedia projects, used
by hundreds of millions of people each month. MediaWiki is localised in over
350 languages and its reliability and robust feature set have earned it a large
and vibrant community of third-party users and developers.
MediaWiki is:
* feature-rich and extensible, both on-wiki and with hundreds of extensions;
* scalable and suitable for both small and large sites;
* simple to install, working on most hardware/software combinations; and
* available in your language.
For system requirements, installation, and upgrade details, see the files
RELEASE-NOTES, INSTALL, and UPGRADE.
* Ready to get started?
** https://www.mediawiki.org/wiki/Special:MyLanguage/Download
* Looking for the technical manual?
** https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents
* Seeking help from a person?
** https://www.mediawiki.org/wiki/Special:MyLanguage/Communication
* Looking to file a bug report or a feature request?
** https://bugs.mediawiki.org/
* Interested in helping out?
** https://www.mediawiki.org/wiki/Special:MyLanguage/How_to_contribute
MediaWiki is the result of global collaboration and cooperation. The CREDITS
file lists technical contributors to the project. The COPYING file explains
MediaWiki's copyright and license (GNU General Public License, version 2 or
later). Many thanks to the Wikimedia community for testing and suggestions.

View File

@ -1,772 +0,0 @@
= MediaWiki 1.34 =
== MediaWiki 1.34.1 ==
This is a security and maintenance release of the MediaWiki 1.34 branch.
=== Changes since MediaWiki 1.34.0 ===
* (T211450) User: better error message when getActorId fails.
* (T241340) Don't redefine MW_ENTRY_POINT in thumb.php if already defined.
* (T236444) User: Allow newSystemUser() to create over anonymous actors.
* (T238483) Fix NewPagesPager "hide registered users" option.
* (T245072) mediawiki.language: Rename languageData back to languageNames.
* Use proper SemVer comparison in CheckComposerLockUpToDate.
* (T212738) Add the MW_VERSION constant, global $wgVersion is soft deprecated.
* (T246127) Fix error when initialising updateCollation.php.
* Update comment about PHP versions supported by The PHP Group.
* (T247215) Fix output of RecountCategories::doWork().
* Add check for page existence to view.php maintenance script.
* (T245149) Fix fetching login token from action=query&meta=tokens on private
wikis.
* (T236509) SECURITY: Fix HTML escaping in UserGroupMembership::getLink().
* (T232932) SECURITY: User content can redirect the logout button to different URL.
* (T246602) SECURITY: jquery.makeCollapsible allows applying event handler to any
CSS selector.
== MediaWiki 1.34.0 ==
=== Changes since MediaWiki 1.34.0-rc.1 ===
* $wgDiffEngine (T237049) This configuration can be used to specify which
difference engine to use. MediaWiki continues to default to automatically
choosing the first of $wgExternalDiffEngine, wikidiff2, or php that is
usable.
* (T231866) SqlBlobStore no longer needs Language object.
* (T236735) WikiExporter: Remove unnecessary check for SCHEMA_COMPAT_WRITE_OLD
flag.
* (T231673) Set MCR migration stage to SCHEMA_COMPAT_NEW.
* (T229601) Make sure DBLoadBalancerFactory service is not disabled.
* (T232866) Fix support for HTTP/2 in MultiHttpClient.
* (T231866) LocalisationCache: Don't instantiate ResourceLoader.
* (T227461) Stop calling deprecated Redis delete functions.
* (T239561) Mark options as requiring parameters in addSite.php.
* (T232866) Mimic CURLOPT_POST in GuzzleHttpRequest.
* (T239734) Replace deprecated lSize with lLen in Redis code.
* (T192134) SECURITY: Do not allow user scripts on Special:PasswordReset.
* (T239428) ApiEditPage: Test for bad redirect targets.
* (T233342) rdbms: Log debug message traces as 'exception.trace' instead of
'trace'.
* (T226751) media: Log and fail gracefully on invalid EXIF coordinates.
* (T240924) NewPagesPager: Fix namespace query conditions.
* (T212067) Tests for an old PHP bug in parse_url.
== MediaWiki 1.34.0-rc.1 ==
=== Changes since MediaWiki 1.34.0-rc.0 ===
* (T231742) rdbms: Restore debug toolbar "Queries" feature.
* (T231366) The ProfilerOutputDb class, 'profiling' table, and profileinfo.php
entry point had been deprecated.
* (T234361) localisation: Add debug message for backend of MessageCache.
* (T234361) session: Add debug message for the used store class.
* (T235559) Fix example Kask configuration in RESTBagOStuff class comment.
* (T235137) Don't apply styling for Special:Contributions on other pages.
* Upgrade mediawiki-codesniffer from 26.0.0 to 28.0.0 (dev-only).
* (T219604) The "jquery.ui.*" and "jquery.effects.*" modules are now
deprecated as aliases for the "jquery.ui" module.
* (T235392) Deprecate setting Parser::mTitle to null.
* Supporting commits for T235392 were also backported to prevent divergence
from master (MediaWiki 1.35).
* (T234581) The 'jquery.tabIndex' module is deprecated.
* Fix docs for GetUserBlock hooks.
* Parser: Hard deprecate getConverterLanguage.
* (T236810) A number of public methods of Parser were exposed only for
historical reasons and have been deprecated: doMagicLinks,
doDoubleUnderscore, doHeadings, doAllQuotes, replaceExternalLinks,
replaceInternalLinks, replaceInternalLinks2, getVariableValue,
initialiseVariables, formatHeadings, testPst, testPreprocess, testSrvus,
areSubpagesAllowed, maybeDoSubpageLink, splitWhitespace, createAssocArgs,
armorLinks, makeKnownLinkHolder, getImageParams, parseLinkParameter,
stripAltText, replaceLinkHolders, replaceLinkHoldersText, armorLinks,
makeKnownLinkHolder, getImageParams, parseLinkParameter, stripAltText.
* (T30798) $wgServer must now always be set in LocalSettings.php. This is most
likely the case already for any wiki installed after 1.18. The autodetection
system was informally deprecated since 1.18 and vulnerable to cache poisoning
attacks. Older wikis may need to update their LocalSettings.php file.
* (T232169) Hard deprecate $wgSysopEmailBans.
* (T236628) Fix for ArticleRevisionViewCustom hook in DifferenceEngine.php.
* (T181658) Do not insert page titles into querycache.qc_value.
* ParamValidator has been flagged as unstable.
* Hard deprecate Parser::disableCache().
== MediaWiki 1.34.0-rc.0 ==
== Upgrading notes for 1.34 ==
1.34 has several database changes since 1.33, and will not work without schema
updates. Note that due to changes to some very large tables like the revision
table, the schema update may take quite long (minutes on a medium sized site,
many hours on a large site).
Don't forget to always back up your database before upgrading!
See the file UPGRADE for more detailed upgrade instructions, including
important information when upgrading from versions prior to 1.11.
Some specific notes for MediaWiki 1.34 upgrades are below:
* MediaWiki now requires PHP 7.2.9 or above.
* MediaWiki no longer supports HHVM.
For notes on 1.33.x and older releases, see HISTORY.
=== Configuration changes for system administrators in 1.34 ===
In an effort to enforce best practices for passwords, MediaWiki will now warn
users, and suggest that they change their password, if it is in the list of
100,000 commonly used passwords that are considered bad passwords. If you want
to disable this for your users, please add the following to your local settings:
$wgPasswordPolicy['policies']['default']['PasswordNotInLargeBlacklist'] = false;
==== New configuration ====
* $wgAllowExternalReqID (T201409) - This configuration setting controls whether
Mediawiki accepts the request ID set by the incoming request via the
`X-Request-Id` header. If set to `true`, that value will be used throughout
the code as the request identificator. Otherwise, the sent header will be
ignored and the request ID will either be taken from Apache's mod_unique
module or will be generated by Mediawiki itself (depending on the set-up).
* $wgEnableSpecialMute (T218265) - This configuration controls whether
Special:Mute is available and whether to include a link to it on emails
originating from Special:Email.
* editmyuserjsredirect user right users without this right now cannot edit JS
redirects in their userspace unless the target of the redirect is also in
their userspace. By default, this right is given to everyone.
* (T226733) Add rate limiter to Special:ConfirmEmail.
* $wgDiffEngine (T237049) This configuration can be used to specify which
difference engine to use. MediaWiki continues to default to automatically
choosing the first of $wgExternalDiffEngine, wikidiff2, or php that is
usable.
==== Changed configuration ====
* $wgUseCdn, $wgCdnServers, $wgCdnServersNoPurge, and $wgCdnMaxAge  These four
CDN-related config variables have been renamed from being specific to Squid
they were previously $wgUseSquid, $wgSquidServers, $wgSquidServersNoPurge, and
$wgSquidMaxage respectively. This aligns them with the related existing
variable $wgCdnMaxageLagged. The previous configuration variable names are
deprecated, but will be used as the fall back if they are still set.
Note that wgSquidPurgeUseHostHeader has not been renamed, as it is deprecated.
* (T27707) File type checks for image uploads have been relaxed to allow files
containing some HTML markup in metadata. As a result, the $wgAllowTitlesInSVG
setting is no longer applied and is now always true. Note that MSIE 7 may
still be able to misinterpret certain malformed PNG files as HTML.
* (T30798) $wgServer must now always be set in LocalSettings.php. This is most
likely the case already for any wiki installed after 1.18. The autodetection
system was informally deprecated since 1.18 and vulnerable to cache poisoning
attacks. Older wikis may need to update their LocalSettings.php file.
* Introduced $wgVerifyMimeTypeIE to allow disabling the MSIE 6/7 file type
detection heuristic on upload, which is more conservative than the checks
that were changed above.
* $wgExternalDiffEngine — Setting this to a string value of 'wikidiff',
'wikidiff2', or 'wikidiff3' will no longer work. This legacy behaviour was
deprecated in MediaWiki 1.27, 1.32, and 1.27, respectively.
* $wgSkipSkin — Setting this instead of $wgSkipSkins, deprecated in 1.23, is now
hard-deprecated.
* $wgLocalInterwiki — Setting this instead of $wgLocalInterwikis, deprecated in
1.23, is now hard-deprecated.
* $wgProfileOnly — Setting this, deprecated in 1.23, is now hard-deprecated.
Instead, set the log file in $wgDebugLogGroups['profileoutput'].
* $wgProxyList — Setting this to an array with IP addresses in the array keys,
which was deprecated in 1.30, no longer works. Instead, $wgProxyList should be
an array with IP addresses as the values, or a string path to a file
containing one IP address per line.
* $wgCookieSetOnAutoblock and $wgCookieSetOnIpBlock are now enabled by default.
==== Removed configuration ====
* $wgWikiDiff2MovedParagraphDetectionCutoff — If you still want a custom change
size threshold, please specify in php.ini, using the configuration variable
wikidiff2.moved_paragraph_detection_cutoff.
* $wgUseESI - This experimental setting, deprecated in 1.33, is now removed.
* $wgDebugPrintHttpHeaders - The default of including HTTP headers in the
debug log channel is no longer configurable. The debug log itself remains
configurable via $wgDebugLogFile.
* $wgMsgCacheExpiry - The MessageCache uses 24 hours as the expiry for values
stored in WANObjectCache. This is no longer configurable.
* $wgPasswordSalt  This setting, used for migrating exceptionally old, insecure
password setups and deprecated since 1.24, is now removed.
* $wgDBOracleDRCP - If you must use persistent connections, set DBO_PERSISTENT
in the 'flags' field for servers in $wgDBServers (or $wgLBFactoryConf).
* $wgMemCachedDebug - Set the cache "debug" field in $wgObjectCaches instead.
* $wgActorTableSchemaMigrationStage has been removed. Extension code for
MediaWiki 1.31+ finding it unset should treat it as being SCHEMA_COMPAT_NEW.
=== New user-facing features in 1.34 ===
* Special:Mute has been added as a quick way for users to block unwanted emails
from other users originating from Special:EmailUser.
* (T207577) Special:NewSection has been created as a shortcut to creating a new
section on a page. When linked to, its subpage is used as the target
([[Special:NewSection/Test]] redirects to creating a new section in "Test").
Otherwise, it displays a basic interface to allow the end user to specify
the target manually.
* (T220447) Special:Contributions/newbies has been removed for performance and
usefulness reasons. Use Special:RecentChanges?userExpLevel=newcomer instead.
* Special:NewFiles/newbies has been removed for performance and usefulness
reasons. Use Special:RecentChanges?userExpLevel=newcomer&namespace=6 instead.
=== New developer features in 1.34 ===
* The ImgAuthModifyHeaders hook was added to img_auth.php to allow modification
of headers in private wikis.
* Language::formatTimePeriod now supports the new 'avoidhours' option to output
strings like "5 days ago" instead of "5 days 13 hours ago".
* (T220163) Added SpecialMuteModifyFormFields hook to allow extensions
to add fields to Special:Mute.
* (T100896) Skin authors can define custom OOUI themes using OOUIThemePaths.
See <https://www.mediawiki.org/wiki/OOUI/Themes> for details.
* (T229035) The GetUserBlock hook was added. Use this instead of
GetBlockedStatus.
* ObjectFactory is available as a service. When used as a service, the object
specs can now specify needed DI services.
* (T222388) Special pages can now be specified as an ObjectFactory spec,
allowing the construction of special pages that require services to be
injected in their constructor.
* (T222388) API modules can now be specified as an ObjectFactory spec,
allowing the construction of modules that require services to be injected
in their constructor.
* (T117736) The function signature of SpecialContributions::getForm::filters
has changed. It now expects definitions of additional filter fields as array
rather than string.
=== External library changes in 1.34 ===
==== Changed external libraries ====
* Updated Mustache from 1.0.0 to v3.0.1.
* Updated OOUI from v0.31.3 to v0.34.0.
* Updated OOjs from v2.2.2 to v3.0.0.
* Updated composer/semver from 1.4.2 to 1.5.0.
* Updated composer/spdx-licenses from 1.4.0 to 1.5.1 (dev-only).
* Updated mediawiki/codesniffer from 25.0.0 to 28.0.0 (dev-only).
* Updated cssjanus/cssjanus from 1.2.1 to 1.3.0.
* Updated wikimedia/at-ease from 1.2.0 to 2.0.0.
* Updated wikimedia/remex-html from 2.0.1 to 2.1.0.
* Updated monolog/monolog from 1.22.1 to 1.24.0 (dev-only).
* Updated wikimedia/object-factory from 1.0.0 to 2.1.0.
* Updated wikimedia/timestamp from 2.2.0 to 3.0.0.
* Updated wikimedia/xmp-reader from 0.6.2 to 0.6.3.
* Updated mediawiki/mediawiki-phan-config from 0.6.0 to 0.6.1 (dev-only).
* Updated wikimedia/avro from 1.8.0 to 1.9.0 (dev-only).
==== Removed external libraries ====
* The jquery.async module, deprecated in 1.33, was removed.
=== Bug fixes in 1.34 ===
* (T222529) If a log entry or page revision is recorded in the database with an
empty username, attempting to display it will log an error and return a "no
username available" to the user instead of silently displaying nothing or
invalid links.
=== Action API changes in 1.34 ===
* The 'recenteditcount' response property from action=query list=allusers,
deprecated in 1.25, has been removed.
* (T60993) action=query list=filearchive, list=alldeletedrevisions and
prop=deletedrevisions no longer require the 'deletedhistory' user right.
* In the response to queries that use 'prop=imageinfo', entries for
non-existing files (indicated by the 'filemissing' field) now omit the
following fields, since they are meaningless in this context:
'timestamp', 'userhidden', 'user', 'userid', 'anon', 'size', 'width',
'height', 'pagecount', 'duration', 'commenthidden', 'parsedcomment',
'comment', 'thumburl', 'thumbwidth', 'thumbheight', 'thumbmime',
'thumberror', 'url', 'sha1', 'metadata', 'extmetadata', 'commonmetadata',
'mime', 'mediadtype', 'bitdepth'.
Clients that process these fields should first check if 'filemissing' is
set. Fields that are supported even if the file is missing include:
'canonicaltitle', 'archivename' (deleted files only), 'descriptionurl',
'descriptionshorturl'.
* The 'blockexpiry' result property in list=users and list=allusers will now be
returned in the same format used by the rest of the API: ISO 8601 for
expiring blocks, and "infinite" for non-expiring blocks.
=== Action API internal changes in 1.34 ===
* The exception thrown in ApiModuleManager::getModule has been changed
from an MWException to an UnexpectedValueException, thrown by ObjectFactory.
ApiModuleManager::getModule now also throws InvalidArgumentExceptions when
ObjectFactory is presented with an invalid spec or incorrectly constructed
objects.
* Added ApiQueryBlockInfoTrait.
=== Languages updated in 1.34 ===
MediaWiki supports over 350 languages. Many localisations are updated regularly.
Below only new and removed languages are listed, as well as changes to languages
because of Phabricator reports.
* (T152908) Added language support for N'Ko (nqo).
=== Breaking changes in 1.34 ===
* The global functions wfSuppressWarnings and wfRestoreWarnings, deprecated in
1.26, have been removed. Use Wikimedia\AtEase\AtEase::suppressWarnings() and
Wikimedia\AtEase\AtEase::restoreWarnings() directly.
* Preferences class, deprecated in 1.31, has been removed.
* The following parts of code, deprecated in 1.32, were removed in favor of
built-in PHP functions:
* CryptRand class
* CryptRand service
* Functions of the MWCryptRand class: singleton(), wasStrong() and generate().
* Various Special Page PHP Classes were renamed (mostly casing changes):
* SpecialAncientpages => SpecialAncientPages
* SpecialConfirmemail => SpecialConfirmEmail
* SpecialDeadendpages => SpecialDeadendPages
* SpecialFewestrevisions => SpecialFewestRevisions
* SpecialListredirects => SpecialListRedirects
* SpecialLonelypages => SpecialLonelyPages
* SpecialLongpages => SpecialLongPages
* SpecialMIMEsearch => SpecialMIMESearch
* SpecialMostcategories => SpecialMostCategories
* SpecialMostinterwikis => SpecialMostInterwikis
* SpecialMostlinked => SpecialMostLinked
* SpecialMostlinkedcategories => SpecialMostLinkedCategories
* SpecialMostlinkedtemplates => SpecialMostLinkedTemplates
* SpecialMostrevisions => SpecialMostRevisions
* SpecialNewimages => SpecialNewFiles
* SpecialShortpages => SpecialShortPages
* SpecialUncategorizedcategories => SpecialUncategorizedCategories
* SpecialUncategorizedimages => SpecialUncategorizedImages
* SpecialUncategorizedpages => SpecialUncategorizedPages
* SpecialUncategorizedtemplates => SpecialUncategorizedTemplates
* SpecialUnusedcategories => SpecialUnusedCategories
* SpecialUnusedimages => SpecialUnusedImages
* SpecialUnusedtemplates => SpecialUnusedTemplates
* SpecialUnwatchedpages => SpecialUnwatchedPages
* SpecialWantedcategories => SpecialWantedCategories
* SpecialWantedtemplates => SpecialWantedTemplates
* SpecialWithoutinterwiki => SpecialWithoutInterwiki
* Language::setCode, deprecated in 1.32, was removed. Use Language::factory to
create a new Language object with a different language code.
* MWNamespace::clearCaches() has been removed. So has the $rebuild parameter
to MWNamespace::getCanonicalNamespaces(), which was deprecated since 1.31.
Instead, reset services, such as by calling $this->overrideMwServices() (if
your test extends MediaWikiTestCase). Services will generally not pick up
configuration changes from after they were created, so you must reset
services after any configuration change. Even if your code works now, it is
likely to break in future versions as more code is moved to services.
* The ill-defined "DatabaseOraclePostInit" hook has been removed.
* PreferencesFormLegacy and PreferencesForm classes, deprecated in 1.32, have
been removed.
* ObjectFactory class, deprecated in 1.31, has been removed.
* HWLDFWordAccumudlator class, deprecated in 1.28, has been removed.
* XMPInfo, XMPReader and XMPValidate, deprecated in 1.32, have been removed.
* The RedirectSpecialPage::execute method could sometimes return a Title object.
This behavior was removed, and the method now matches the parent signature
(SpecialPage::execute) which is to return HTML string or void.
To obtain the destination title, use RedirectSpecialPage::getRedirect.
* The 'recenteditcount' response property from action API action=query
list=allusers, deprecated in 1.25, has been removed.
* SearchEngine::userNamespaces(), SearchEngine::namespacesAsText(),
SearchEngine::create(), SearchEngine::getSearchTypes() and
SearchEngine::getNearMatch(), methods deprecated in 1.27, have been removed.
* FileRepo::streamFile(), deprecated in 1.26, has been removed.
* User::randomPassword() method, deprecated in 1.27, have been removed.
* MWNamespace::canTalk(), deprecated in 1.30, have been removed.
* Parser class property $mUniqPrefix, deprecated in 1.26, has been removed.
* wfArrayFilter() and wfArrayFilterByKey(), deprecated in 1.32, have been
removed.
* wfMakeUrlIndexes() function, deprecated in 1.33, have been removed.
* Method signatures in WatchedItemQueryServiceExtension have changed from taking
User objects to taking UserIdentity objects. Extensions implementing this
interface need to be changed accordingly.
* User::getGroupPage() and ::makeGroupLinkHTML(), deprecated in 1.29, have been
removed. Use UserGroupMembership::getGroupPage and ::getLink instead.
* User::makeGroupLinkWiki(), deprecated in 1.29, has been removed. Use
UserGroupMembership::getLink() instead.
* SavepointPostgres, deprecated in 1.31, has been removed.
* OutputPage::enableSectionEditLinks(), OutputPage::sectionEditLinksEnabled(),
ParserOptions::getEditSection(), ParserOptions::setEditSection(), and
ParserOutput::getEditSectionTokens, ::getTOCEnabled, ::setEditSectionTokens,
and ::setTOCEnabled, deprecated in 1.31, have been removed.
* EditPage::safeUnicodeInput() and ::safeUnicodeOutput(), deprecated in 1.30,
have been removed.
* Four methods in OutputPage, deprecated in 1.32, have been removed. You should
use OutputPage::showFatalError or throw a FatalError instead. The methods are
::showFileCopyError(), ::showFileRenameError(), ::showFileDeleteError(), and
::showFileNotFoundError().
* ApiBase::truncateArray(), deprecated in 1.32, has been removed.
* IcuCollation::getICUVersion(), deprecated in 1.32, has been removed. Use PHP's
INTL_ICU_VERSION constant directly.
* HTMLForm::setSubmitProgressive(), deprecated in 1.32, has been removed.
* ResourceLoaderStartUpModules::getStartupModules() and ::getLegacyModules(),
both deprecated in 1.32, have been removed.
* BaseTemplate::msgHtml() and QuickTemplate::msgHtml(), deprecated in 1.32, have
been removed. Use ->msg() or ->getMsg() instead.
* WatchAction::getUnwatchToken(), deprecated in 1.32, has been removed. Instead,
use WatchAction::getWatchToken() with action 'unwatch' directly.
* Language::initEncoding(), ::recodeForEdit(), and recodeInput(), deprecated in
1.28, have been removed.
* PageArchive::getTextFromRow(), ::listAllPages(), and ::getLastRevisionText(),
deprecated in 1.32, have been removed.
* OutputPage::getModuleScripts(), ParserOutput::getModuleScripts(), deprecated
in 1.33, have been removed.
* User::getPasswordValidity(), deprecated in 1.33, has been removed.
* ApiQueryBase::prepareUrlQuerySearchString(), deprecated in 1.33, has been
removed.
* ChangeTags::purgeTagUsageCache(), deprecated in 1.33, has been removed.
* JobQueueGroup::pushLazyJobs(), deprecated in 1.33, has been removed.
* MediaWikiTestCase::stashMwGlobals(), deprecated in 1.32, has been removed.
* SearchEngine::transformSearchTerm(), deprecated in 1.32, has been removed.
* The Block typehint only refers to blocks stored in the database. It should be
updated to AbstractBlock in cases where any type of block could be expected.
* FileRepoStatus, deprecated in 1.25, has been removed.
* The LegacyHookPreAuthenticationProvider class, deprecated since its creation
in 1.27, has been removed.
* IP::isValidBlock(), deprecated in 1.30, has been removed.
* WikiPage::prepareContentForEdit now doesn't accept an integer for $revision,
was deprecated in 1.25.
* The jquery.byteLength module, deprecated in 1.31, was removed.
Use the mediawiki.String module instead.
* mw.language.specialCharacters, deprecated in 1.33, has been removed.
Use require( 'mediawiki.language.specialCharacters' ) instead.
* The jquery.colorUtil module was removed. Use jquery.color instead.
* The jquery.checkboxShiftClick module was removed. The functionality
is provided by mediawiki.page.ready instead (T232688).
* The 'jquery.accessKeyLabel' module has been removed. This jQuery
plugin now ships as part of the 'mediawiki.util' module bundle.
* EditPage::submit(), deprecated in 1.29, has been removed. Use $this->edit()
directly.
* HTMLForm::getErrors(), deprecated in 1.28, has been removed. Use
getErrorsOrWarnings() instead.
* SpecialPage::getTitle(), deprecated in 1.23, has been removed. Use
SpecialPage::getPageTitle() instead.
* jquery.ui.effect-bounce, jquery.ui.effect-explode, jquery.ui.effect-fold
jquery.ui.effect-pulsate, jquery.ui.effect-slide, jquery.ui.effect-transfer,
which are no longer used, have now been removed.
* SpecialEmailUser::validateTarget(), ::getTarget() without a sender/user
specified, deprecated in 1.30, have been removed.
* BufferingStatsdDataFactory::getBuffer(), deprecated in 1.30, has been removed.
* The constant DB_SLAVE, deprecated in 1.28, has been removed. Use DB_REPLICA.
* The constants NS_IMAGE and NS_IMAGE_TALK, deprecated in 1.14, have been
removed. Use NS_FILE and NS_FILE_TALK respectively.
* Replacer, DoubleReplacer, HashtableReplacer and RegexlikeReplacer
(deprecated in 1.32) have been removed. Closures should be used instead.
* OutputPage::addWikiText(), ::addWikiTextWithTitle(), ::addWikiTextTitleTidy(),
::addWikiTextTidy(), ::addWikiTextTitle(), deprecated in 1.32, have been
removed.
* The $wgUseKeyHeader configuration option and the OutputPage::getKeyHeader()
method, deprecated in 1.32, have been removed.
* WebInstallerOutput::addWikiText(), deprecated in 1.32, has been removed.
* Parser::fetchFile(), deprecated in 1.32, has been removed. Use the method
Parser::fetchFileAndTitle() instead.
* The global function wfBCP47, deprecated in 1.31, has been removed.
* wfCountDown() function, deprecated in 1.31, has been removed. Use
\Maintenance::countDown() method instead.
* OutputPage::wrapWikiMsg() no longer accepts an options parameter. This was
deprecated since 1.20.
* Skin::outputPage() no longer accepts a context. This was deprecated in 1.20.
* Linker::link() no longer accepts a string for the query array, as was
deprecated in 1.20.
* PrefixSearch::titleSearch(), deprecated in 1.23, has been removed. Use the
SearchEngine::defaultPrefixSearch or ::completionSearch() methods instead.
* The UserRights hook, deprecated in 1.26, has been removed. Instead, use the
UserGroupsChanged hook.
* Skin::getDefaultInstance(), deprecated in 1.27, has been removed. Get the
instance from MediaWikiServices instead.
* The UserLoadFromSession hook, deprecated in 1.27, has been removed.
* The wfResetSessionID global function, deprecated in 1.27, has been removed.
Use MediaWiki\Session\SessionManager instead.
* The wfGetLBFactory global function, deprecated in 1.27, has been removed.
Use MediaWikiServices::getInstance()->getDBLoadBalancerFactory().
* The internal method OutputPage->addScriptFile() will no longer silently drop
calls that use an invalid path (i.e., something other than an absolute path,
protocol-relative URL, or full scheme URL), and will instead pass them to the
client where they will likely 404. This usage was deprecated in 1.24.
* Database::reportConnectionError, deprecated in 1.32, has been removed.
* APIEditBeforeSave hook, deprecated in 1.28, has been removed. Please see
EditFilterMergedContent hook for an alternative way to use this feature.
* API module methods getDescription(), getParamDescription(), & getExamples(),
all deprecated in 1.25 and ignored, have been removed.
* The API module method getDescriptionMessage(), deprecated in 1.30, has been
removed.
* The JavaScript global variable wgLoadScript has been removed. Use
mw.util.wikiScript( 'load' ) instead.
* ResourceLoader no longer creates the 'mw.legacy' placeholder object. It has
been unused since 1.16 and was deprecated in 1.22. To deprecate a property
in JavaScript, use mw.log.deprecate() instead.
* The 'user.groups' module, deprecated in 1.28, was removed.
Use the 'user' module instead.
* The ResourceLoaderContext::expandModuleNames method, deprecated in 1.33, was
removed. Use ResourceLoader::expandModuleNames instead.
* The ability to override User::$mRights has been removed. Use
PermissionManager::addTemporaryUserRights() instead.
* Previously, when iterating ResultWrapper with foreach() or a similar
construct, the range of the index was 1..numRows. This has been fixed to be
0..(numRows-1).
* The ChangePasswordForm hook, deprecated in 1.27, has been removed. Use the
AuthChangeFormFields hook or security levels instead.
* WikiMap::getWikiIdFromDomain(), deprecated in 1.33, has been removed.
Use WikiMap::getWikiIdFromDbDomain() instead.
* The config variables $wgHtml5, $wgJsMimeType, and $wgXhtmlDefaultNamespace,
which were deprecated and ignored by core since 1.22, are no longer set to any
value, and SkinTemplate no longer emits a 'jsmimetype' key. Any extensions not
updated since 2013 to cope with this deprecation may now break.
* (T222637) Passing ResourceLoaderModule objects to ResourceLoader::register()
or $wgResourceModules is no longer supported.
Use the 'class' or 'factory' option of the array format instead.
* The parameter $lang of the functions generateTOC and tocList in Linker and
DummyLinker must be in type Language when present. Other types are
deprecated since 1.33.
* The static properties mw.Api.errors and mw.Api.warnings, deprecated in 1.29,
have been removed.
* ParserOption::getSpeculativeRevIdCallback(), deprecated in 1.28, has been
removed.
* The UploadVerification hook, deprecated in 1.28, has been removed. Instead,
use the UploadVerifyFile hook.
* UploadBase:: and UploadFromChunks::stashFileGetKey() and stashSession(),
deprecated in 1.28, have been removed. Instead, please use the getFileKey()
method on the response from doStashFile().
* LBFactory::setDomainPrefix() and LoadBalancer::setDomainPrefix(), deprecated
in 1.33, have been removed. Use setLocalDomainPrefix() instead.
* IDatabase::implicitGroupby(), deprecated in 1.30, has been removed.
* IDatabase::doneWrites(), deprecated in 1.31, has been removed.
Use IDatabase::lastDoneWrites() instead.
* Database::reportConnectionError(), deprecated in 1.32, has been removed.
* LoadBalancer::laggedSlaveUsed(), deprecated in 1.28, has been removed.
Use LoadBalancer::laggedReplicaUsed() instead.
* Database::getProperty(), deprecated in 1.28, has been removed.
* IDatabase::getWikiId(), deprecated in 1.30, has been removed.
Use IDatabase::getDomainID() instead.
* (T191231) Support for using Oracle or MSSQL as database backends has been
dropped.
* MessageCache::destroyInstance() has been removed. Instead, call
MediaWikiTestCase::resetServices().
* SearchResult protected field $searchEngine is removed and no longer
initialized after calling SearchResult::initFromTitle().
* The UserIsBlockedFrom hook is only called if a block is found first, and
should only be used to unblock a blocked user.
* Parameters for index.php from PATH_INFO, such as the title, are no longer
written to $_GET.
* The selectFields() methods on classes LocalFile, ArchivedFile, OldLocalFile,
DatabaseBlock, and RecentChange, deprecated in 1.31, have been removed. Use
the corresponding getQueryInfo() methods instead.
* The following methods on Revision, deprecated since 1.31, have been removed.
Use RevisionStore::getQueryInfo() or RevisionStore::getArchiveQueryInfo()
instead.
* Revision::userJoinCond()
* Revision::pageJoinCond()
* Revision::selectFields()
* Revision::selectArchiveFields()
* Revision::selectTextFields()
* Revision::selectPageFields()
* Revision::selectUserFields()
* User::setNewpassword(), deprecated in 1.27 has been removed.
* The ObjectCache::getMainWANInstance and ObjectCache::getMainStashInstance
functions, deprecated since 1.28, have been removed.
* Language::$dataCache has been removed (without prior deprecation, for
practical reasons). Use MediaWikiServices instead to get a LocalisationCache.
=== Deprecations in 1.34 ===
* The MWNamespace class is deprecated. Use NamespaceInfo.
* ExtensionRegistry->load() is deprecated, as it breaks dependency checking.
Instead, use ->queue().
* User::isBlocked() is deprecated since it does not tell you if the user is
blocked from editing a particular page. Use User::getBlock() or
PermissionManager::isBlockedFrom() or PermissionManager::userCan() instead.
* User::isLocallyBlockedProxy and User::inDnsBlacklist are deprecated and moved
to the BlockManager as private helper methods.
* User::isDnsBlacklisted is deprecated. Use BlockManager::isDnsBlacklisted
instead.
* The Config argument to ChangesListSpecialPage::checkStructuredFilterUiEnabled
is deprecated. Pass only the User argument.
* WatchedItem::getUser is deprecated. Use getUserIdentity.
* Passing a Title as the first parameter to the getTimestampById method of
RevisionStore is deprecated. Omit it, passing only the remaining parameters.
* Title::getPreviousRevisionId and Title::getNextRevisionId are deprecated. Use
RevisionLookup::getPreviousRevision and RevisionLookup::getNextRevision.
* The Title parameter to RevisionLookup::getPreviousRevision and
RevisionLookup::getNextRevision is deprecated and should be omitted.
* MWHttpRequest::factory is deprecated. Use HttpRequestFactory.
* The Http class is deprecated. For the request, get, and post methods, use
HttpRequestFactory. For isValidURI, use MWHttpRequest::isValidURI. For
getProxy, use (string)$wgHTTPProxy. For createMultiClient, construct a
MultiHttpClient directly.
* Http::$httpEngine is deprecated and has no replacement. The default 'guzzle'
engine will eventually be made the only engine for HTTP requests.
* RepoGroup::singleton(), RepoGroup::destroySingleton(),
RepoGroup::setSingleton(), wfFindFile(), and wfLocalFile() are all
deprecated. Use MediaWikiServices instead.
* The getSubjectPage, getTalkPage, and getOtherPage of Title are deprecated.
Use NamespaceInfo's getSubjectPage, getTalkPage, and getAssociatedPage.
* MWMessagePack class, no longer used, has been deprecated in 1.34.
* The Block class is separated into DatabaseBlock (for blocks stored in the
database), and SystemBlock (for temporary blocks created by the system).
SystemBlock should be used when creating any temporary blocks. Block is
a deprecated alias for DatabaseBlock.
* Parser::$mConf is deprecated. It will be removed entirely in a later version.
Some context can be found at T224165.
* Constructing Parser directly is deprecated. Obtain one from ParserFactory.
* Title::moveSubpages is deprecated. Use MovePage::moveSubpages or
MovePage::moveSubpagesIfAllowed.
* The MWNamespace class is deprecated. Use MediaWikiServices::getNamespaceInfo.
* (T62260) Hard deprecate Language::getExtraUserToggles() method.
* Language::viewPrevNext function is deprecated, use
PrevNextNavigationRenderer::buildPrevNextNavigation instead
* User::trackBlockWithCookie and DatabaseBlock::clearCookie are deprecated. Use
BlockManager::trackBlockWithCookie and BlockManager::clearCookie instead.
* DatabaseBlock::setCookie, DatabaseBlock::getCookieValue,
DatabaseBlock::getIdFromCookieValue and AbstractBlock::shouldTrackWithCookie
are moved to internal helper methods for BlockManager::trackBlockWithCookie.
* ResourceLoaderContext::getConfig and ResourceLoaderContext::getLogger have
been deprecated. Inside ResourceLoaderModule subclasses, use the local methods
instead. Elsewhere, use the methods from the ResourceLoader class.
* The Profiler::setTemplated and Profiler::getTemplated methods have been
deprecated. Use Profiler::setAllowOutput and Profiler::getAllowOutput
instead.
* The ProfilerOutputDb class, 'profiling' table, and profileinfo.php entry
point had been deprecated (T231366).
* The Preprocessor_DOM implementation has been deprecated. It will be
removed in a future release. Use the Preprocessor_Hash implementation
instead.
* Sanitizer::attributeWhitelist() and Sanitizer::setupAttributeWhitelist()
have been deprecated; they will be made private in the future.
* SearchResult::termMatches() method is deprecated. It was unreliable because
only populated by few search engine implementations. Use
SqlSearchResult::getTermMatches() if really needed.
* SearchResult::getTextSnippet( $terms ) the $terms param is being deprecated
and should no longer be passed. Search engine implemenations should be
responsible for carrying relevant information needed for highlighting with
their own SearchResultSet/SearchResult sub-classes.
* SearchResultSet::free() method is deprecated.
* SearchEngine::$searchTerms protected field is deprecated. Moved to
SearchDatabase.
* The use of the $terms param in the ShowSearchHit and ShowSearchHitTitle
hooks is highly discouraged as it's only populated by SearchDatabase search
engines.
* Skin::escapeSearchLink() is deprecated. Use Skin::getSearchLink() or the skin
template option 'searchaction' instead.
* Skin::getRevisionId() and Skin::isRevisionCurrent() have been deprecated.
Use OutputPage::getRevisionId() and OutputPage::isRevisionCurrent() instead.
* LoadBalancer::haveIndex() and LoadBalancer::isNonZeroLoad() have
been deprecated.
* FileBackend::getWikiId() has been deprecated.
Use FileBackend::getDomainId() instead.
* User::getRights() and User::$mRights have been deprecated. Use
PermissionManager::getUserPermissions() instead.
* The LocalisationCacheRecache hook no longer allows purging of message blobs
to be prevented. Modifying the $purgeBlobs parameter now has no effect.
* SVGMetadataExtractor::getMetadata has been deprecated. Instead, you should
use SVGReader->getMetadata() directly.
* The following public properties on AbstractBlock are deprecated: $mReason,
$mTimestamp, $mExpiry, $mHideName. Use the getters/setters instead.
* The following public properties on DatabaseBlock are deprecated: $mAuto,
$mParentBlockId. To check for an autoblock use DatabaseBlock::getType; to
check for the parent ID, use DatabaseBlock::getParentBlockId.
* SearchEngine::userHighlightPrefs() is deprecated, simply stop passing
$contextlines and $contextchars to the SearchHighlighter methods, they will
use proper defaults defined in SearchHighlighter::DEFAULT_CONTEXT_LINES and
DEFAULT_CONTEXT_CHARS.
* SearchUpdate constructor: passing a string as the title param and or a boolean
or a string as the content will produce a deprecation warning.
* SearchEngine::getTextFromContent() is deprecated, use getTextForSearchIndex()
directly from the Content object.
* SearchEngine::textAlreadyUpdatedForIndex() is deprecated, given the
deprecation above this method is no longer needed/called and should not be
implemented by SearchEngine implementation.
* IDatabase::bufferResults() has been deprecated. Use query batching instead.
* MessageCache::singleton() is deprecated. Use
MediaWikiServices::getMessageCache().
* ObjectCache::getWANInstance() is deprecated. Use
MediaWikiServices::getMainWANObjectCache() instead.
* ObjectCache::newWANCacheFromParams() is deprecated. Use
MediaWikiServices::getMainWANObjectCache() instead.
* Constructing MovePage directly is deprecated. Use MovePageFactory.
* TempFSFile::factory() has been deprecated. Use TempFSFileFactory instead.
* wfIsBadImage() is deprecated. Use the BadFileLookup service instead.
* Building a new SearchResult is hard-deprecated, always call
SearchResult::newFromTitle(). This class is being refactored into an abstract
class. If you extend this class please be sure to override all its methods
or extend RevisionSearchResult.
* Skin::getSkinNameMessages() is deprecated and no longer used.
* The mediawiki.RegExp module is deprecated; use mw.util.escapeRegExp() instead.
* Specifying a SpecialPage object for the list of special pages (either through
the SpecialPage_initList hook or by adding to $wgSpecialPages) is now
deprecated.
* The 'jquery.tabIndex' module is deprecated.
* WebInstaller::getInfoBox(), getWarningBox() and getErrorBox() are deprecated.
Use Html::errorBox() or Html::warningBox() instead.
* Use of ActorMigration with 'ar_user', 'img_user', 'oi_user', 'fa_user',
'rc_user', 'log_user', and 'ipb_by' is deprecated. Queries should be adjusted
to use the corresponding actor fields directly. Note that use with
'rev_user' is *not* deprecated at this time.
* Specifying both the class and factory parameters for
ApiModuleManager::addModule is now deprecated. The ObjectFactory spec should
be used instead.
* The UserIsHidden hook is deprecated. Use GetUserBlock instead, and add a
system block that hides the user.
* The GetBlockedStatus hook is deprecated. Use GetUserBlock instead, to add or
remove a block.
* $wgContentHandlerUseDB is deprecated and should always be true.
* StreamFile::send404Message() and StreamFile::parseRange() are now deprecated.
Use HTTPFileStreamer::send404Message() and HTTPFileStreamer::parseRange()
respectively instead.
* Global variable $wgSysopEmailBans is deprecated; to allow sysops to ban
users from sending emails, use
$wgGroupPermissions['sysop']['blockemail'] = true;
* ApiQueryBase::showHiddenUsersAddBlockInfo() is deprecated. Use
ApiQueryBlockInfoTrait instead.
* PasswordReset is now a service, its direct instantiation is deprecated.
* RESTBagOStuff users should specify either "JSON" or "PHP" serialization type.
* The global function wfIsHHVM() is deprecated and will now always return false
regardless of the runtime environment. This is part of the continuing work to
remove HHVM support from MediaWiki, which started in MediaWiki 1.31.
* Language::getLocalisationCache() is deprecated. Use MediaWikiServices
instead.
* The following Language methods are deprecated: isSupportedLanguage,
isValidCode, isValidBuiltInCode, isKnownLanguageTag, fetchLanguageNames,
fetchLanguageName, getFileName, getMessagesFileName, getJsonMessagesFileName.
Use the new LanguageNameUtils class instead. (Note that fetchLanguageName(s)
are called getLanguageName(s) in the new class.)
* Using the Parser without initializing its $mTitle property to non-null has
been deprecated. In a future release Parser::getTitle() will throw a
TypeError if $mTitle is uninitialized.
* A number of public methods of Parser were exposed only for historical
reasons and have been deprecated: doMagicLinks, doDoubleUnderscore,
doHeadings, doAllQuotes, replaceExternalLinks, replaceInternalLinks,
replaceInternalLinks2, getVariableValue, initialiseVariables, formatHeadings,
testPst, testPreprocess, testSrvus, areSubpagesAllowed, maybeDoSubpageLink,
splitWhitespace, createAssocArgs, armorLinks, makeKnownLinkHolder,
getImageParams, parseLinkParameter, stripAltText, replaceLinkHolders,
replaceLinkHoldersText, armorLinks, makeKnownLinkHolder, getImageParams,
parseLinkParameter, stripAltText.
=== Other changes in 1.34 ===
* Added option to specify "Various authors" as author in extension credits using
"..." as the only author name. If the "author" array contains more than one
entry and "..." is one of the entries in the array, "..." will be parsed as
"others" (version-poweredby-others i18n message) like previously.
* (T232563) Browser support ("Grade C") for Internet Explorer 6 and 7
was discontinued. Basic content and security features may no longer
work correctly in these browsers.
== Compatibility ==
MediaWiki 1.34 requires PHP 7.2.9 or later, and the following PHP extensions:
* ctype
* dom
* fileinfo
* iconv
* json
* mbstring
* xml
MySQL/MariaDB is the recommended DBMS. PostgreSQL or SQLite can also be used,
but support for them is somewhat less mature.
The supported versions are:
* MySQL 5.5.8 or later
* PostgreSQL 9.2 or later
* SQLite 3.8.0 or later
== Online documentation ==
Documentation for both end-users and site administrators is available on
MediaWiki.org, and is covered under the GNU Free Documentation License (except
for pages that explicitly state that their contents are in the public domain):
https://www.mediawiki.org/wiki/Special:MyLanguage/Documentation
== Mailing list ==
A mailing list is available for MediaWiki user support and discussion:
https://lists.wikimedia.org/mailman/listinfo/mediawiki-l
A low-traffic announcements-only list is also available:
https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce
It's highly recommended that you sign up for one of these lists if you're
going to run a public MediaWiki, so you can be notified of security fixes.
== IRC help ==
There's usually someone online in #mediawiki on irc.freenode.net.

1584
RELEASE-NOTES-1.35 Normal file

File diff suppressed because it is too large Load Diff

View File

@ -241,17 +241,9 @@ have customized them, please compare the new format using Special:Allmessages or
the relevant LanguageXX.php files:
* copyrightwarning
* dberrortext
* editingcomment (was named commentedit)
* editingsection (was named sectionedit)
* numauthors
* numedits
* numtalkauthors
* numtalkedits
* numwatchers
* protectedarticle
* searchresulttext
* showhideminor
* unprotectedarticle
Note that the 1.3 beta releases included a potential vulnerability if PHP is

158
api.php
View File

@ -1,6 +1,11 @@
<?php
/**
* This file is the entry point for all API queries.
* The web entry point for all %Action API queries, handled by ApiMain
* and ApiBase subclasses.
*
* This is used by bots to fetch content and information about the wiki,
* its pages, and its users. See <https://www.mediawiki.org/wiki/API> for more
* information.
*
* It begins by constructing a new ApiMain using the parameter passed to it
* as an argument in the URL ('?action='). It then invokes "execute()" on the
@ -25,6 +30,8 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup entrypoint
* @ingroup API
*/
use MediaWiki\Logger\LegacyLogger;
@ -35,90 +42,85 @@ define( 'MW_ENTRY_POINT', 'api' );
require __DIR__ . '/includes/WebStart.php';
$starttime = microtime( true );
wfApiMain();
// URL safety checks
if ( !$wgRequest->checkUrlExtension() ) {
return;
}
function wfApiMain() {
global $wgRequest, $wgTitle, $wgAPIRequestLog;
// PATH_INFO can be used for stupid things. We don't support it for api.php at
// all, so error out if it's present.
if ( isset( $_SERVER['PATH_INFO'] ) && $_SERVER['PATH_INFO'] != '' ) {
$correctUrl = wfAppendQuery( wfScript( 'api' ), $wgRequest->getQueryValuesOnly() );
$correctUrl = wfExpandUrl( $correctUrl, PROTO_CANONICAL );
header( "Location: $correctUrl", true, 301 );
echo 'This endpoint does not support "path info", i.e. extra text between "api.php"'
. 'and the "?". Remove any such text and try again.';
die( 1 );
}
$starttime = microtime( true );
// Set a dummy $wgTitle, because $wgTitle == null breaks various things
// In a perfect world this wouldn't be necessary
$wgTitle = Title::makeTitle( NS_SPECIAL, 'Badtitle/dummy title for API calls set in api.php' );
// RequestContext will read from $wgTitle, but it will also whine about it.
// In a perfect world this wouldn't be necessary either.
RequestContext::getMain()->setTitle( $wgTitle );
try {
// Construct an ApiMain with the arguments passed via the URL. What we get back
// is some form of an ApiMain, possibly even one that produces an error message,
// but we don't care here, as that is handled by the constructor.
$processor = new ApiMain( RequestContext::getMain(), true );
// Last chance hook before executing the API
Hooks::run( 'ApiBeforeMain', [ &$processor ] );
if ( !$processor instanceof ApiMain ) {
throw new MWException( 'ApiBeforeMain hook set $processor to a non-ApiMain class' );
// PATH_INFO can be used for stupid things. We don't support it for api.php at
// all, so error out if it's present. (T128209)
if ( isset( $_SERVER['PATH_INFO'] ) && $_SERVER['PATH_INFO'] != '' ) {
$correctUrl = wfAppendQuery( wfScript( 'api' ), $wgRequest->getQueryValuesOnly() );
$correctUrl = wfExpandUrl( $correctUrl, PROTO_CANONICAL );
header( "Location: $correctUrl", true, 301 );
echo 'This endpoint does not support "path info", i.e. extra text between "api.php"'
. 'and the "?". Remove any such text and try again.';
die( 1 );
}
} catch ( Exception $e ) { // @todo Remove this block when HHVM is no longer supported
// Crap. Try to report the exception in API format to be friendly to clients.
ApiMain::handleApiBeforeMainException( $e );
$processor = false;
} catch ( Throwable $e ) {
// Crap. Try to report the exception in API format to be friendly to clients.
ApiMain::handleApiBeforeMainException( $e );
$processor = false;
}
// Process data & print results
if ( $processor ) {
$processor->execute();
}
// Set a dummy $wgTitle, because $wgTitle == null breaks various things
// In a perfect world this wouldn't be necessary
$wgTitle = Title::makeTitle( NS_SPECIAL, 'Badtitle/dummy title for API calls set in api.php' );
// Log what the user did, for book-keeping purposes.
$endtime = microtime( true );
// RequestContext will read from $wgTitle, but it will also whine about it.
// In a perfect world this wouldn't be necessary either.
RequestContext::getMain()->setTitle( $wgTitle );
// Log the request
if ( $wgAPIRequestLog ) {
$items = [
wfTimestamp( TS_MW ),
$endtime - $starttime,
$wgRequest->getIP(),
$wgRequest->getHeader( 'User-agent' )
];
$items[] = $wgRequest->wasPosted() ? 'POST' : 'GET';
try {
// Construct an ApiMain with the arguments passed via the URL. What we get back
// is some form of an ApiMain, possibly even one that produces an error message,
// but we don't care here, as that is handled by the constructor.
$processor = new ApiMain( RequestContext::getMain(), true );
// Last chance hook before executing the API
Hooks::runner()->onApiBeforeMain( $processor );
if ( !$processor instanceof ApiMain ) {
throw new MWException( 'ApiBeforeMain hook set $processor to a non-ApiMain class' );
}
} catch ( Throwable $e ) {
// Crap. Try to report the exception in API format to be friendly to clients.
ApiMain::handleApiBeforeMainException( $e );
$processor = false;
}
// Process data & print results
if ( $processor ) {
try {
$manager = $processor->getModuleManager();
$module = $manager->getModule( $wgRequest->getVal( 'action' ), 'action' );
} catch ( Exception $ex ) { // @todo Remove this block when HHVM is no longer supported
$module = null;
} catch ( Throwable $ex ) {
$module = null;
}
if ( !$module || $module->mustBePosted() ) {
$items[] = "action=" . $wgRequest->getVal( 'action' );
} else {
$items[] = wfArrayToCgi( $wgRequest->getValues() );
}
} else {
$items[] = "failed in ApiBeforeMain";
$processor->execute();
}
LegacyLogger::emit( implode( ',', $items ) . "\n", $wgAPIRequestLog );
wfDebug( "Logged API request to $wgAPIRequestLog\n" );
}
$mediawiki = new MediaWiki();
$mediawiki->doPostOutputShutdown( 'fast' );
// Log what the user did, for book-keeping purposes.
$endtime = microtime( true );
// Log the request
if ( $wgAPIRequestLog ) {
$items = [
wfTimestamp( TS_MW ),
$endtime - $starttime,
$wgRequest->getIP(),
$wgRequest->getHeader( 'User-agent' )
];
$items[] = $wgRequest->wasPosted() ? 'POST' : 'GET';
if ( $processor ) {
try {
$manager = $processor->getModuleManager();
$module = $manager->getModule( $wgRequest->getVal( 'action' ), 'action' );
} catch ( Throwable $ex ) {
$module = null;
}
if ( !$module || $module->mustBePosted() ) {
$items[] = "action=" . $wgRequest->getVal( 'action' );
} else {
$items[] = wfArrayToCgi( $wgRequest->getValues() );
}
} else {
$items[] = "failed in ApiBeforeMain";
}
LegacyLogger::emit( implode( ',', $items ) . "\n", $wgAPIRequestLog );
wfDebug( "Logged API request to $wgAPIRequestLog" );
}
$mediawiki = new MediaWiki();
$mediawiki->doPostOutputShutdown();
}

View File

@ -4,7 +4,6 @@
global $wgAutoloadLocalClasses;
$wgAutoloadLocalClasses = [
'APCBagOStuff' => __DIR__ . '/includes/libs/objectcache/APCBagOStuff.php',
'APCUBagOStuff' => __DIR__ . '/includes/libs/objectcache/APCUBagOStuff.php',
'AbkhazUppercaseCollation' => __DIR__ . '/includes/collation/AbkhazUppercaseCollation.php',
'AbstractContent' => __DIR__ . '/includes/content/AbstractContent.php',
@ -28,6 +27,7 @@ $wgAutoloadLocalClasses = [
'ApiBlockInfoTrait' => __DIR__ . '/includes/api/ApiBlockInfoTrait.php',
'ApiCSPReport' => __DIR__ . '/includes/api/ApiCSPReport.php',
'ApiChangeAuthenticationData' => __DIR__ . '/includes/api/ApiChangeAuthenticationData.php',
'ApiChangeContentModel' => __DIR__ . '/includes/api/ApiChangeContentModel.php',
'ApiCheckToken' => __DIR__ . '/includes/api/ApiCheckToken.php',
'ApiClearHasMsg' => __DIR__ . '/includes/api/ApiClearHasMsg.php',
'ApiClientLogin' => __DIR__ . '/includes/api/ApiClientLogin.php',
@ -156,6 +156,7 @@ $wgAutoloadLocalClasses = [
'ApiUserrights' => __DIR__ . '/includes/api/ApiUserrights.php',
'ApiValidatePassword' => __DIR__ . '/includes/api/ApiValidatePassword.php',
'ApiWatch' => __DIR__ . '/includes/api/ApiWatch.php',
'ApiWatchlistTrait' => __DIR__ . '/includes/api/ApiWatchlistTrait.php',
'ArchivedFile' => __DIR__ . '/includes/filerepo/file/ArchivedFile.php',
'Argon2Password' => __DIR__ . '/includes/password/Argon2Password.php',
'ArrayDiffFormatter' => __DIR__ . '/includes/diff/ArrayDiffFormatter.php',
@ -190,7 +191,6 @@ $wgAutoloadLocalClasses = [
'BenchHttpHttps' => __DIR__ . '/maintenance/benchmarks/bench_HTTP_HTTPS.php',
'BenchIfSwitch' => __DIR__ . '/maintenance/benchmarks/bench_if_switch.php',
'BenchUtf8TitleCheck' => __DIR__ . '/maintenance/benchmarks/bench_utf8_title_check.php',
'BenchWfIsWindows' => __DIR__ . '/maintenance/benchmarks/bench_wfIsWindows.php',
'BenchWikimediaBaseConvert' => __DIR__ . '/maintenance/benchmarks/bench_Wikimedia_base_convert.php',
'BenchmarkCSSMin' => __DIR__ . '/maintenance/benchmarks/benchmarkCSSMin.php',
'BenchmarkDeleteTruncate' => __DIR__ . '/maintenance/benchmarks/bench_delete_truncate.php',
@ -204,7 +204,7 @@ $wgAutoloadLocalClasses = [
'BenchmarkStringReplacement' => __DIR__ . '/maintenance/benchmarks/benchmarkStringReplacement.php',
'BenchmarkTidy' => __DIR__ . '/maintenance/benchmarks/benchmarkTidy.php',
'BenchmarkTitleValue' => __DIR__ . '/maintenance/benchmarks/benchmarkTitleValue.php',
'Benchmarker' => __DIR__ . '/maintenance/benchmarks/Benchmarker.php',
'Benchmarker' => __DIR__ . '/maintenance/includes/Benchmarker.php',
'BitmapHandler' => __DIR__ . '/includes/media/BitmapHandler.php',
'BitmapHandler_ClientOnly' => __DIR__ . '/includes/media/BitmapHandler_ClientOnly.php',
'BitmapMetadataHandler' => __DIR__ . '/includes/media/BitmapMetadataHandler.php',
@ -213,6 +213,7 @@ $wgAutoloadLocalClasses = [
'BlockLevelPass' => __DIR__ . '/includes/parser/BlockLevelPass.php',
'BlockListPager' => __DIR__ . '/includes/specials/pagers/BlockListPager.php',
'BlockLogFormatter' => __DIR__ . '/includes/logging/BlockLogFormatter.php',
'BlockUsers' => __DIR__ . '/maintenance/blockUsers.php',
'BmpHandler' => __DIR__ . '/includes/media/BmpHandler.php',
'BotPassword' => __DIR__ . '/includes/user/BotPassword.php',
'BufferingStatsdDataFactory' => __DIR__ . '/includes/libs/stats/BufferingStatsdDataFactory.php',
@ -258,9 +259,7 @@ $wgAutoloadLocalClasses = [
'CheckBadRedirects' => __DIR__ . '/maintenance/checkBadRedirects.php',
'CheckComposerLockUpToDate' => __DIR__ . '/maintenance/checkComposerLockUpToDate.php',
'CheckDependencies' => __DIR__ . '/maintenance/checkDependencies.php',
'CheckExtensionsCLI' => __DIR__ . '/maintenance/language/checkLanguage.inc',
'CheckImages' => __DIR__ . '/maintenance/checkImages.php',
'CheckLanguageCLI' => __DIR__ . '/maintenance/language/checkLanguage.inc',
'CheckLess' => __DIR__ . '/maintenance/checkLess.php',
'CheckStorage' => __DIR__ . '/maintenance/storage/checkStorage.php',
'CheckUsernames' => __DIR__ . '/maintenance/checkUsernames.php',
@ -311,6 +310,7 @@ $wgAutoloadLocalClasses = [
'ConstantDependency' => __DIR__ . '/includes/cache/dependency/ConstantDependency.php',
'Content' => __DIR__ . '/includes/content/Content.php',
'ContentHandler' => __DIR__ . '/includes/content/ContentHandler.php',
'ContentModelChange' => __DIR__ . '/includes/content/ContentModelChange.php',
'ContentModelLogFormatter' => __DIR__ . '/includes/logging/ContentModelLogFormatter.php',
'ContentSecurityPolicy' => __DIR__ . '/includes/ContentSecurityPolicy.php',
'ContextSource' => __DIR__ . '/includes/context/ContextSource.php',
@ -324,13 +324,14 @@ $wgAutoloadLocalClasses = [
'CopyFileBackend' => __DIR__ . '/maintenance/copyFileBackend.php',
'CopyFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/CopyFileOp.php',
'CopyJobQueue' => __DIR__ . '/maintenance/copyJobQueue.php',
'CoreMagicVariables' => __DIR__ . '/includes/parser/CoreMagicVariables.php',
'CoreParserFunctions' => __DIR__ . '/includes/parser/CoreParserFunctions.php',
'CoreTagHooks' => __DIR__ . '/includes/parser/CoreTagHooks.php',
'CreateAndPromote' => __DIR__ . '/maintenance/createAndPromote.php',
'CreateCommonPasswordCdb' => __DIR__ . '/maintenance/createCommonPasswordCdb.php',
'CreateBotPassword' => __DIR__ . '/maintenance/createBotPassword.php',
'CreateFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/CreateFileOp.php',
'CreditsAction' => __DIR__ . '/includes/actions/CreditsAction.php',
'CrhConverter' => __DIR__ . '/languages/classes/LanguageCrh.php',
'CrhConverter' => __DIR__ . '/includes/language/converters/CrhConverter.php',
'CryptHKDF' => __DIR__ . '/includes/libs/CryptHKDF.php',
'CssContent' => __DIR__ . '/includes/content/CssContent.php',
'CssContentHandler' => __DIR__ . '/includes/content/CssContentHandler.php',
@ -372,6 +373,7 @@ $wgAutoloadLocalClasses = [
'DeferrableUpdate' => __DIR__ . '/includes/deferred/DeferrableUpdate.php',
'DeferredStringifier' => __DIR__ . '/includes/libs/DeferredStringifier.php',
'DeferredUpdates' => __DIR__ . '/includes/deferred/DeferredUpdates.php',
'Deflate' => __DIR__ . '/includes/libs/Deflate.php',
'DeleteAction' => __DIR__ . '/includes/actions/DeleteAction.php',
'DeleteArchivedFiles' => __DIR__ . '/maintenance/deleteArchivedFiles.php',
'DeleteArchivedRevisions' => __DIR__ . '/maintenance/deleteArchivedRevisions.php',
@ -387,6 +389,7 @@ $wgAutoloadLocalClasses = [
'DeleteOrphanedRevisions' => __DIR__ . '/maintenance/deleteOrphanedRevisions.php',
'DeletePageJob' => __DIR__ . '/includes/jobqueue/jobs/DeletePageJob.php',
'DeleteSelfExternals' => __DIR__ . '/maintenance/deleteSelfExternals.php',
'DeleteTag' => __DIR__ . '/maintenance/deleteTag.php',
'DeletedContribsPager' => __DIR__ . '/includes/specials/pagers/DeletedContribsPager.php',
'DependencyWrapper' => __DIR__ . '/includes/cache/dependency/DependencyWrapper.php',
'DeprecatedGlobal' => __DIR__ . '/includes/DeprecatedGlobal.php',
@ -439,7 +442,7 @@ $wgAutoloadLocalClasses = [
'DumpStringOutput' => __DIR__ . '/includes/export/DumpStringOutput.php',
'DumpUploads' => __DIR__ . '/maintenance/dumpUploads.php',
'DuplicateJob' => __DIR__ . '/includes/jobqueue/jobs/DuplicateJob.php',
'EasyDeflate' => __DIR__ . '/includes/libs/EasyDeflate.php',
'EasyDeflate' => __DIR__ . '/includes/libs/Deflate.php',
'EditAction' => __DIR__ . '/includes/actions/EditAction.php',
'EditCLI' => __DIR__ . '/maintenance/edit.php',
'EditPage' => __DIR__ . '/includes/EditPage.php',
@ -449,7 +452,7 @@ $wgAutoloadLocalClasses = [
'EmaillingJob' => __DIR__ . '/includes/jobqueue/jobs/EmaillingJob.php',
'EmptyBagOStuff' => __DIR__ . '/includes/libs/objectcache/EmptyBagOStuff.php',
'EmptyUserGroup' => __DIR__ . '/maintenance/emptyUserGroup.php',
'EnConverter' => __DIR__ . '/languages/classes/LanguageEn.php',
'EnConverter' => __DIR__ . '/includes/language/converters/EnConverter.php',
'EncryptedPassword' => __DIR__ . '/includes/password/EncryptedPassword.php',
'EnhancedChangesList' => __DIR__ . '/includes/changes/EnhancedChangesList.php',
'EnotifNotifyJob' => __DIR__ . '/includes/jobqueue/jobs/EnotifNotifyJob.php',
@ -472,7 +475,6 @@ $wgAutoloadLocalClasses = [
'ExtensionDependencyError' => __DIR__ . '/includes/registration/ExtensionDependencyError.php',
'ExtensionJsonValidationError' => __DIR__ . '/includes/registration/ExtensionJsonValidationError.php',
'ExtensionJsonValidator' => __DIR__ . '/includes/registration/ExtensionJsonValidator.php',
'ExtensionLanguages' => __DIR__ . '/maintenance/language/languages.inc',
'ExtensionProcessor' => __DIR__ . '/includes/registration/ExtensionProcessor.php',
'ExtensionRegistry' => __DIR__ . '/includes/registration/ExtensionRegistry.php',
'ExternalStore' => __DIR__ . '/includes/externalstore/ExternalStore.php',
@ -492,12 +494,14 @@ $wgAutoloadLocalClasses = [
'FSFileBackendList' => __DIR__ . '/includes/libs/filebackend/fileiteration/FSFileBackendList.php',
'FSFileOpHandle' => __DIR__ . '/includes/libs/filebackend/fileophandle/FSFileOpHandle.php',
'FSLockManager' => __DIR__ . '/includes/libs/lockmanager/FSLockManager.php',
'FakeConverter' => __DIR__ . '/languages/FakeConverter.php',
'FakeMaintenance' => __DIR__ . '/maintenance/Maintenance.php',
'FakeConverter' => __DIR__ . '/includes/language/TrivialLanguageConverter.php',
'FakeMaintenance' => __DIR__ . '/maintenance/includes/FakeMaintenance.php',
'FakeResultWrapper' => __DIR__ . '/includes/libs/rdbms/database/resultwrapper/FakeResultWrapper.php',
'FatalError' => __DIR__ . '/includes/exception/FatalError.php',
'FauxRequest' => __DIR__ . '/includes/FauxRequest.php',
'FauxResponse' => __DIR__ . '/includes/FauxResponse.php',
'FauxSearchResult' => __DIR__ . '/includes/search/FauxSearchResult.php',
'FauxSearchResultSet' => __DIR__ . '/includes/search/FauxSearchResultSet.php',
'FeedItem' => __DIR__ . '/includes/changes/FeedItem.php',
'FeedUtils' => __DIR__ . '/includes/FeedUtils.php',
'FetchText' => __DIR__ . '/maintenance/fetchText.php',
@ -514,7 +518,6 @@ $wgAutoloadLocalClasses = [
'FileBackendStoreShardDirIterator' => __DIR__ . '/includes/libs/filebackend/fileiteration/FileBackendStoreShardDirIterator.php',
'FileBackendStoreShardFileIterator' => __DIR__ . '/includes/libs/filebackend/fileiteration/FileBackendStoreShardFileIterator.php',
'FileBackendStoreShardListIterator' => __DIR__ . '/includes/libs/filebackend/fileiteration/FileBackendStoreShardListIterator.php',
'FileBasedSiteLookup' => __DIR__ . '/includes/site/FileBasedSiteLookup.php',
'FileCacheBase' => __DIR__ . '/includes/cache/FileCacheBase.php',
'FileContentHandler' => __DIR__ . '/includes/content/FileContentHandler.php',
'FileContentsHasher' => __DIR__ . '/includes/utils/FileContentsHasher.php',
@ -525,8 +528,9 @@ $wgAutoloadLocalClasses = [
'FileOpBatch' => __DIR__ . '/includes/libs/filebackend/FileOpBatch.php',
'FileOpPerfTest' => __DIR__ . '/maintenance/fileOpPerfTest.php',
'FileRepo' => __DIR__ . '/includes/filerepo/FileRepo.php',
'FindBadBlobs' => __DIR__ . '/maintenance/findBadBlobs.php',
'FindDeprecated' => __DIR__ . '/maintenance/findDeprecated.php',
'FindHooks' => __DIR__ . '/maintenance/findHooks.php',
'FindMissingActors' => __DIR__ . '/maintenance/findMissingActors.php',
'FindMissingFiles' => __DIR__ . '/maintenance/findMissingFiles.php',
'FindOrphanedFiles' => __DIR__ . '/maintenance/findOrphanedFiles.php',
'FixDefaultJsonContentPages' => __DIR__ . '/maintenance/fixDefaultJsonContentPages.php',
@ -553,13 +557,14 @@ $wgAutoloadLocalClasses = [
'FormlessAction' => __DIR__ . '/includes/actions/FormlessAction.php',
'GIFHandler' => __DIR__ . '/includes/media/GIFHandler.php',
'GIFMetadataExtractor' => __DIR__ . '/includes/media/GIFMetadataExtractor.php',
'GanConverter' => __DIR__ . '/languages/classes/LanguageGan.php',
'GanConverter' => __DIR__ . '/includes/language/converters/GanConverter.php',
'GenderCache' => __DIR__ . '/includes/cache/GenderCache.php',
'GenerateCollationData' => __DIR__ . '/maintenance/language/generateCollationData.php',
'GenerateJsonI18n' => __DIR__ . '/maintenance/generateJsonI18n.php',
'GenerateNormalizerDataAr' => __DIR__ . '/maintenance/language/generateNormalizerDataAr.php',
'GenerateNormalizerDataMl' => __DIR__ . '/maintenance/language/generateNormalizerDataMl.php',
'GeneratePhpCharToUpperMappings' => __DIR__ . '/maintenance/mediawiki.Title/generatePhpCharToUpperMappings.php',
'GenerateSchemaSql' => __DIR__ . '/maintenance/generateSchemaSql.php',
'GenerateSitemap' => __DIR__ . '/maintenance/generateSitemap.php',
'GenerateUcfirstOverrides' => __DIR__ . '/maintenance/language/generateUcfirstOverrides.php',
'GenerateUpperCharTable' => __DIR__ . '/maintenance/language/generateUpperCharTable.php',
@ -573,7 +578,6 @@ $wgAutoloadLocalClasses = [
'GlobalDependency' => __DIR__ . '/includes/cache/dependency/GlobalDependency.php',
'GlobalVarConfig' => __DIR__ . '/includes/config/GlobalVarConfig.php',
'GuzzleHttpRequest' => __DIR__ . '/includes/http/GuzzleHttpRequest.php',
'HHVMMakeRepo' => __DIR__ . '/maintenance/hhvm/makeRepo.php',
'HTMLApiField' => __DIR__ . '/includes/htmlform/fields/HTMLApiField.php',
'HTMLAutoCompleteSelectField' => __DIR__ . '/includes/htmlform/fields/HTMLAutoCompleteSelectField.php',
'HTMLButtonField' => __DIR__ . '/includes/htmlform/fields/HTMLButtonField.php',
@ -633,6 +637,8 @@ $wgAutoloadLocalClasses = [
'Hooks' => __DIR__ . '/includes/Hooks.php',
'Html' => __DIR__ . '/includes/Html.php',
'HtmlArmor' => __DIR__ . '/includes/libs/HtmlArmor.php',
'HtmlCacheUpdater' => __DIR__ . '/includes/cache/HtmlCacheUpdater.php',
'HtmlFileCacheUpdate' => __DIR__ . '/includes/deferred/HtmlFileCacheUpdate.php',
'Http' => __DIR__ . '/includes/http/Http.php',
'HttpError' => __DIR__ . '/includes/exception/HttpError.php',
'HttpStatus' => __DIR__ . '/includes/libs/HttpStatus.php',
@ -643,12 +649,12 @@ $wgAutoloadLocalClasses = [
'IDBAccessObject' => __DIR__ . '/includes/dao/IDBAccessObject.php',
'IDatabase' => __DIR__ . '/includes/libs/rdbms/database/IDatabase.php',
'IEContentAnalyzer' => __DIR__ . '/includes/libs/mime/IEContentAnalyzer.php',
'IEUrlExtension' => __DIR__ . '/includes/libs/IEUrlExtension.php',
'IExpiringStore' => __DIR__ . '/includes/libs/objectcache/IExpiringStore.php',
'IExpiringStore' => __DIR__ . '/includes/libs/objectcache/utils/IExpiringStore.php',
'IJobSpecification' => __DIR__ . '/includes/jobqueue/IJobSpecification.php',
'ILanguageConverter' => __DIR__ . '/includes/language/ILanguageConverter.php',
'ILocalizedException' => __DIR__ . '/includes/exception/ILocalizedException.php',
'IMaintainableDatabase' => __DIR__ . '/includes/libs/rdbms/database/IMaintainableDatabase.php',
'IP' => __DIR__ . '/includes/libs/IP.php',
'IP' => __DIR__ . '/includes/compat/IP.php',
'IPTC' => __DIR__ . '/includes/media/IPTC.php',
'IRCColourfulRCFeedFormatter' => __DIR__ . '/includes/rcfeed/IRCColourfulRCFeedFormatter.php',
'ISearchResultSet' => __DIR__ . '/includes/search/ISearchResultSet.php',
@ -691,7 +697,7 @@ $wgAutoloadLocalClasses = [
'InvalidPassword' => __DIR__ . '/includes/password/InvalidPassword.php',
'InvalidateUserSesssions' => __DIR__ . '/maintenance/invalidateUserSessions.php',
'IteratorDecorator' => __DIR__ . '/includes/libs/iterators/IteratorDecorator.php',
'IuConverter' => __DIR__ . '/languages/classes/LanguageIu.php',
'IuConverter' => __DIR__ . '/includes/language/converters/IuConverter.php',
'JSCompilerContext' => __DIR__ . '/includes/libs/jsminplus.php',
'JSMinPlus' => __DIR__ . '/includes/libs/jsminplus.php',
'JSNode' => __DIR__ . '/includes/libs/jsminplus.php',
@ -720,8 +726,8 @@ $wgAutoloadLocalClasses = [
'JpegMetadataExtractor' => __DIR__ . '/includes/media/JpegMetadataExtractor.php',
'JsonContent' => __DIR__ . '/includes/content/JsonContent.php',
'JsonContentHandler' => __DIR__ . '/includes/content/JsonContentHandler.php',
'KkConverter' => __DIR__ . '/languages/classes/LanguageKk.php',
'KuConverter' => __DIR__ . '/languages/classes/LanguageKu.php',
'KkConverter' => __DIR__ . '/includes/language/converters/KkConverter.php',
'KuConverter' => __DIR__ . '/includes/language/converters/KuConverter.php',
'LCStore' => __DIR__ . '/includes/cache/localisation/LCStore.php',
'LCStoreCDB' => __DIR__ . '/includes/cache/localisation/LCStoreCDB.php',
'LCStoreDB' => __DIR__ . '/includes/cache/localisation/LCStoreDB.php',
@ -735,7 +741,7 @@ $wgAutoloadLocalClasses = [
'LanguageBs' => __DIR__ . '/languages/classes/LanguageBs.php',
'LanguageCode' => __DIR__ . '/includes/language/LanguageCode.php',
'LanguageConverter' => __DIR__ . '/languages/LanguageConverter.php',
'LanguageCrh' => __DIR__ . '/languages/classes/LanguageCrh.php',
'LanguageConverterSpecific' => __DIR__ . '/languages/LanguageConverterSpecific.php',
'LanguageCu' => __DIR__ . '/languages/classes/LanguageCu.php',
'LanguageDsb' => __DIR__ . '/languages/classes/LanguageDsb.php',
'LanguageEn' => __DIR__ . '/languages/classes/LanguageEn.php',
@ -745,31 +751,24 @@ $wgAutoloadLocalClasses = [
'LanguageHsb' => __DIR__ . '/languages/classes/LanguageHsb.php',
'LanguageHu' => __DIR__ . '/languages/classes/LanguageHu.php',
'LanguageHy' => __DIR__ . '/languages/classes/LanguageHy.php',
'LanguageIu' => __DIR__ . '/languages/classes/LanguageIu.php',
'LanguageJa' => __DIR__ . '/languages/classes/LanguageJa.php',
'LanguageKaa' => __DIR__ . '/languages/classes/LanguageKaa.php',
'LanguageKk' => __DIR__ . '/languages/classes/LanguageKk.php',
'LanguageKk_cyrl' => __DIR__ . '/languages/classes/LanguageKk_cyrl.php',
'LanguageKm' => __DIR__ . '/languages/classes/LanguageKm.php',
'LanguageKsh' => __DIR__ . '/languages/classes/LanguageKsh.php',
'LanguageKu' => __DIR__ . '/languages/classes/LanguageKu.php',
'LanguageLa' => __DIR__ . '/languages/classes/LanguageLa.php',
'LanguageMl' => __DIR__ . '/languages/classes/LanguageMl.php',
'LanguageMy' => __DIR__ . '/languages/classes/LanguageMy.php',
'LanguageOs' => __DIR__ . '/languages/classes/LanguageOs.php',
'LanguageQqx' => __DIR__ . '/languages/classes/LanguageQqx.php',
'LanguageShi' => __DIR__ . '/languages/classes/LanguageShi.php',
'LanguageSl' => __DIR__ . '/languages/classes/LanguageSl.php',
'LanguageSr' => __DIR__ . '/languages/classes/LanguageSr.php',
'LanguageTg' => __DIR__ . '/languages/classes/LanguageTg.php',
'LanguageTr' => __DIR__ . '/languages/classes/LanguageTr.php',
'LanguageTyv' => __DIR__ . '/languages/classes/LanguageTyv.php',
'LanguageUz' => __DIR__ . '/languages/classes/LanguageUz.php',
'LanguageWa' => __DIR__ . '/languages/classes/LanguageWa.php',
'LanguageYue' => __DIR__ . '/languages/classes/LanguageYue.php',
'LanguageZh' => __DIR__ . '/languages/classes/LanguageZh.php',
'LanguageZh_hans' => __DIR__ . '/languages/classes/LanguageZh_hans.php',
'Languages' => __DIR__ . '/maintenance/language/languages.inc',
'LayeredParameterizedPassword' => __DIR__ . '/includes/password/LayeredParameterizedPassword.php',
'LegacyLogFormatter' => __DIR__ . '/includes/logging/LegacyLogFormatter.php',
'License' => __DIR__ . '/includes/specials/helpers/License.php',
@ -805,7 +804,7 @@ $wgAutoloadLocalClasses = [
'LogPage' => __DIR__ . '/includes/logging/LogPage.php',
'LogPager' => __DIR__ . '/includes/logging/LogPager.php',
'LoggedOutEditToken' => __DIR__ . '/includes/user/LoggedOutEditToken.php',
'LoggedUpdateMaintenance' => __DIR__ . '/maintenance/Maintenance.php',
'LoggedUpdateMaintenance' => __DIR__ . '/maintenance/includes/LoggedUpdateMaintenance.php',
'LoginHelper' => __DIR__ . '/includes/specials/helpers/LoginHelper.php',
'LoginSignupSpecialPage' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
'MSCompoundFileReader' => __DIR__ . '/includes/libs/mime/MSCompoundFileReader.php',
@ -825,7 +824,6 @@ $wgAutoloadLocalClasses = [
'MWGrants' => __DIR__ . '/includes/MWGrants.php',
'MWHttpRequest' => __DIR__ . '/includes/http/MWHttpRequest.php',
'MWLBFactory' => __DIR__ . '/includes/db/MWLBFactory.php',
'MWMessagePack' => __DIR__ . '/includes/libs/MWMessagePack.php',
'MWNamespace' => __DIR__ . '/includes/MWNamespace.php',
'MWOldPassword' => __DIR__ . '/includes/password/MWOldPassword.php',
'MWRestrictions' => __DIR__ . '/includes/utils/MWRestrictions.php',
@ -840,7 +838,7 @@ $wgAutoloadLocalClasses = [
'MailAddress' => __DIR__ . '/includes/mail/MailAddress.php',
'MainConfigDependency' => __DIR__ . '/includes/cache/dependency/MainConfigDependency.php',
'MaintainableDBConnRef' => __DIR__ . '/includes/libs/rdbms/database/MaintainableDBConnRef.php',
'Maintenance' => __DIR__ . '/maintenance/Maintenance.php',
'Maintenance' => __DIR__ . '/maintenance/includes/Maintenance.php',
'MakeTestEdits' => __DIR__ . '/maintenance/makeTestEdits.php',
'MalformedTitleException' => __DIR__ . '/includes/title/MalformedTitleException.php',
'ManageForeignResources' => __DIR__ . '/maintenance/manageForeignResources.php',
@ -852,6 +850,7 @@ $wgAutoloadLocalClasses = [
'McTest' => __DIR__ . '/maintenance/mctest.php',
'McrRestoreAction' => __DIR__ . '/includes/actions/McrRestoreAction.php',
'McrUndoAction' => __DIR__ . '/includes/actions/McrUndoAction.php',
'MediaFileTrait' => __DIR__ . '/includes/filerepo/file/MediaFileTrait.php',
'MediaHandler' => __DIR__ . '/includes/media/MediaHandler.php',
'MediaHandlerFactory' => __DIR__ . '/includes/media/MediaHandlerFactory.php',
'MediaTransformError' => __DIR__ . '/includes/media/MediaTransformError.php',
@ -862,62 +861,254 @@ $wgAutoloadLocalClasses = [
'MediaWikiSite' => __DIR__ . '/includes/site/MediaWikiSite.php',
'MediaWikiTitleCodec' => __DIR__ . '/includes/title/MediaWikiTitleCodec.php',
'MediaWikiVersionFetcher' => __DIR__ . '/includes/MediaWikiVersionFetcher.php',
'MediaWiki\\BadFileLookup' => __DIR__ . '/includes/BadFileLookup.php',
'MediaWiki\\ChangeTags\\Taggable' => __DIR__ . '/includes/changetags/Taggable.php',
'MediaWiki\\Config\\ConfigRepository' => __DIR__ . '/includes/config/ConfigRepository.php',
'MediaWiki\\Config\\ServiceOptions' => __DIR__ . '/includes/config/ServiceOptions.php',
'MediaWiki\\DB\\PatchFileLocation' => __DIR__ . '/includes/db/PatchFileLocation.php',
'MediaWiki\\Diff\\ComplexityException' => __DIR__ . '/includes/diff/ComplexityException.php',
'MediaWiki\\Diff\\WordAccumulator' => __DIR__ . '/includes/diff/WordAccumulator.php',
'MediaWiki\\Debug\\DeprecatablePropertyArray' => __DIR__ . '/includes/debug/DeprecatablePropertyArray.php',
'MediaWiki\\FileBackend\\FSFile\\TempFSFileFactory' => __DIR__ . '/includes/libs/filebackend/fsfile/TempFSFileFactory.php',
'MediaWiki\\FileBackend\\LockManager\\LockManagerGroupFactory' => __DIR__ . '/includes/filebackend/lockmanager/LockManagerGroupFactory.php',
'MediaWiki\\HeaderCallback' => __DIR__ . '/includes/HeaderCallback.php',
'MediaWiki\\Http\\HttpRequestFactory' => __DIR__ . '/includes/http/HttpRequestFactory.php',
'MediaWiki\\Installer\\InstallException' => __DIR__ . '/includes/installer/InstallException.php',
'MediaWiki\\Interwiki\\ClassicInterwikiLookup' => __DIR__ . '/includes/interwiki/ClassicInterwikiLookup.php',
'MediaWiki\\Interwiki\\InterwikiLookup' => __DIR__ . '/includes/interwiki/InterwikiLookup.php',
'MediaWiki\\Interwiki\\InterwikiLookupAdapter' => __DIR__ . '/includes/interwiki/InterwikiLookupAdapter.php',
'MediaWiki\\Interwiki\\NullInterwikiLookup' => __DIR__ . '/includes/interwiki/NullInterwikiLookup.php',
'MediaWiki\\Hook\\AbortEmailNotificationHook' => __DIR__ . '/includes/changes/Hook/AbortEmailNotificationHook.php',
'MediaWiki\\Hook\\AbortTalkPageEmailNotificationHook' => __DIR__ . '/includes/mail/Hook/AbortTalkPageEmailNotificationHook.php',
'MediaWiki\\Hook\\ActionBeforeFormDisplayHook' => __DIR__ . '/includes/actions/Hook/ActionBeforeFormDisplayHook.php',
'MediaWiki\\Hook\\ActionModifyFormFieldsHook' => __DIR__ . '/includes/actions/Hook/ActionModifyFormFieldsHook.php',
'MediaWiki\\Hook\\AddNewAccountHook' => __DIR__ . '/includes/specials/Hook/AddNewAccountHook.php',
'MediaWiki\\Hook\\AfterImportPageHook' => __DIR__ . '/includes/import/Hook/AfterImportPageHook.php',
'MediaWiki\\Hook\\AfterParserFetchFileAndTitleHook' => __DIR__ . '/includes/parser/Hook/AfterParserFetchFileAndTitleHook.php',
'MediaWiki\\Hook\\AlternateUserMailerHook' => __DIR__ . '/includes/mail/Hook/AlternateUserMailerHook.php',
'MediaWiki\\Hook\\AncientPagesQueryHook' => __DIR__ . '/includes/specials/Hook/AncientPagesQueryHook.php',
'MediaWiki\\Hook\\ArticleRevisionVisibilitySetHook' => __DIR__ . '/includes/revisiondelete/Hook/ArticleRevisionVisibilitySetHook.php',
'MediaWiki\\Hook\\BaseTemplateAfterPortletHook' => __DIR__ . '/includes/skins/Hook/BaseTemplateAfterPortletHook.php',
'MediaWiki\\Hook\\BaseTemplateToolboxHook' => __DIR__ . '/includes/skins/Hook/BaseTemplateToolboxHook.php',
'MediaWiki\\Hook\\BeforeParserFetchFileAndTitleHook' => __DIR__ . '/includes/parser/Hook/BeforeParserFetchFileAndTitleHook.php',
'MediaWiki\\Hook\\BeforeParserFetchTemplateAndtitleHook' => __DIR__ . '/includes/parser/Hook/BeforeParserFetchTemplateAndtitleHook.php',
'MediaWiki\\Hook\\BeforeParserrenderImageGalleryHook' => __DIR__ . '/includes/parser/Hook/BeforeParserrenderImageGalleryHook.php',
'MediaWiki\\Hook\\BeforeResetNotificationTimestampHook' => __DIR__ . '/includes/watcheditem/Hook/BeforeResetNotificationTimestampHook.php',
'MediaWiki\\Hook\\BeforeWelcomeCreationHook' => __DIR__ . '/includes/specials/Hook/BeforeWelcomeCreationHook.php',
'MediaWiki\\Hook\\BitmapHandlerCheckImageAreaHook' => __DIR__ . '/includes/media/Hook/BitmapHandlerCheckImageAreaHook.php',
'MediaWiki\\Hook\\BitmapHandlerTransformHook' => __DIR__ . '/includes/media/Hook/BitmapHandlerTransformHook.php',
'MediaWiki\\Hook\\BlockIpCompleteHook' => __DIR__ . '/includes/specials/Hook/BlockIpCompleteHook.php',
'MediaWiki\\Hook\\BlockIpHook' => __DIR__ . '/includes/specials/Hook/BlockIpHook.php',
'MediaWiki\\Hook\\BookInformationHook' => __DIR__ . '/includes/specials/Hook/BookInformationHook.php',
'MediaWiki\\Hook\\CanonicalNamespacesHook' => __DIR__ . '/includes/title/Hook/CanonicalNamespacesHook.php',
'MediaWiki\\Hook\\ChangeUserGroupsHook' => __DIR__ . '/includes/specials/Hook/ChangeUserGroupsHook.php',
'MediaWiki\\Hook\\ChangesListInitRowsHook' => __DIR__ . '/includes/changes/Hook/ChangesListInitRowsHook.php',
'MediaWiki\\Hook\\ChangesListInsertArticleLinkHook' => __DIR__ . '/includes/changes/Hook/ChangesListInsertArticleLinkHook.php',
'MediaWiki\\Hook\\Collation__factoryHook' => __DIR__ . '/includes/collation/Hook/Collation__factoryHook.php',
'MediaWiki\\Hook\\ContribsPager__getQueryInfoHook' => __DIR__ . '/includes/specials/Hook/ContribsPager__getQueryInfoHook.php',
'MediaWiki\\Hook\\ContribsPager__reallyDoQueryHook' => __DIR__ . '/includes/specials/Hook/ContribsPager__reallyDoQueryHook.php',
'MediaWiki\\Hook\\ContributionsLineEndingHook' => __DIR__ . '/includes/specials/Hook/ContributionsLineEndingHook.php',
'MediaWiki\\Hook\\ContributionsToolLinksHook' => __DIR__ . '/includes/specials/Hook/ContributionsToolLinksHook.php',
'MediaWiki\\Hook\\CustomEditorHook' => __DIR__ . '/includes/actions/Hook/CustomEditorHook.php',
'MediaWiki\\Hook\\DeletedContribsPager__reallyDoQueryHook' => __DIR__ . '/includes/specials/Hook/DeletedContribsPager__reallyDoQueryHook.php',
'MediaWiki\\Hook\\DeletedContributionsLineEndingHook' => __DIR__ . '/includes/specials/Hook/DeletedContributionsLineEndingHook.php',
'MediaWiki\\Hook\\EmailUserCCHook' => __DIR__ . '/includes/specials/Hook/EmailUserCCHook.php',
'MediaWiki\\Hook\\EmailUserCompleteHook' => __DIR__ . '/includes/specials/Hook/EmailUserCompleteHook.php',
'MediaWiki\\Hook\\EmailUserFormHook' => __DIR__ . '/includes/specials/Hook/EmailUserFormHook.php',
'MediaWiki\\Hook\\EmailUserHook' => __DIR__ . '/includes/specials/Hook/EmailUserHook.php',
'MediaWiki\\Hook\\EmailUserPermissionsErrorsHook' => __DIR__ . '/includes/specials/Hook/EmailUserPermissionsErrorsHook.php',
'MediaWiki\\Hook\\EnhancedChangesListModifyBlockLineDataHook' => __DIR__ . '/includes/changes/Hook/EnhancedChangesListModifyBlockLineDataHook.php',
'MediaWiki\\Hook\\EnhancedChangesListModifyLineDataHook' => __DIR__ . '/includes/changes/Hook/EnhancedChangesListModifyLineDataHook.php',
'MediaWiki\\Hook\\EnhancedChangesList__getLogTextHook' => __DIR__ . '/includes/changes/Hook/EnhancedChangesList__getLogTextHook.php',
'MediaWiki\\Hook\\ExtensionTypesHook' => __DIR__ . '/includes/specials/Hook/ExtensionTypesHook.php',
'MediaWiki\\Hook\\FetchChangesListHook' => __DIR__ . '/includes/changes/Hook/FetchChangesListHook.php',
'MediaWiki\\Hook\\FileTransformedHook' => __DIR__ . '/includes/filerepo/Hook/FileTransformedHook.php',
'MediaWiki\\Hook\\FileUndeleteCompleteHook' => __DIR__ . '/includes/specials/Hook/FileUndeleteCompleteHook.php',
'MediaWiki\\Hook\\FileUploadHook' => __DIR__ . '/includes/filerepo/Hook/FileUploadHook.php',
'MediaWiki\\Hook\\GalleryGetModesHook' => __DIR__ . '/includes/gallery/Hook/GalleryGetModesHook.php',
'MediaWiki\\Hook\\GetExtendedMetadataHook' => __DIR__ . '/includes/media/Hook/GetExtendedMetadataHook.php',
'MediaWiki\\Hook\\GetHumanTimestampHook' => __DIR__ . '/includes/language/Hook/GetHumanTimestampHook.php',
'MediaWiki\\Hook\\GetLangPreferredVariantHook' => __DIR__ . '/includes/language/Hook/GetLangPreferredVariantHook.php',
'MediaWiki\\Hook\\GetLinkColoursHook' => __DIR__ . '/includes/parser/Hook/GetLinkColoursHook.php',
'MediaWiki\\Hook\\GetLogTypesOnUserHook' => __DIR__ . '/includes/specials/Hook/GetLogTypesOnUserHook.php',
'MediaWiki\\Hook\\GetMetadataVersionHook' => __DIR__ . '/includes/media/Hook/GetMetadataVersionHook.php',
'MediaWiki\\Hook\\GetNewMessagesAlertHook' => __DIR__ . '/includes/skins/Hook/GetNewMessagesAlertHook.php',
'MediaWiki\\Hook\\HistoryPageToolLinksHook' => __DIR__ . '/includes/actions/Hook/HistoryPageToolLinksHook.php',
'MediaWiki\\Hook\\HistoryRevisionToolsHook' => __DIR__ . '/includes/actions/Hook/HistoryRevisionToolsHook.php',
'MediaWiki\\Hook\\HistoryToolsHook' => __DIR__ . '/includes/actions/Hook/HistoryToolsHook.php',
'MediaWiki\\Hook\\IRCLineURLHook' => __DIR__ . '/includes/rcfeed/Hook/IRCLineURLHook.php',
'MediaWiki\\Hook\\ImportHandleLogItemXMLTagHook' => __DIR__ . '/includes/import/Hook/ImportHandleLogItemXMLTagHook.php',
'MediaWiki\\Hook\\ImportHandlePageXMLTagHook' => __DIR__ . '/includes/import/Hook/ImportHandlePageXMLTagHook.php',
'MediaWiki\\Hook\\ImportHandleRevisionXMLTagHook' => __DIR__ . '/includes/import/Hook/ImportHandleRevisionXMLTagHook.php',
'MediaWiki\\Hook\\ImportHandleToplevelXMLTagHook' => __DIR__ . '/includes/import/Hook/ImportHandleToplevelXMLTagHook.php',
'MediaWiki\\Hook\\ImportHandleUploadXMLTagHook' => __DIR__ . '/includes/import/Hook/ImportHandleUploadXMLTagHook.php',
'MediaWiki\\Hook\\ImportLogInterwikiLinkHook' => __DIR__ . '/includes/specials/Hook/ImportLogInterwikiLinkHook.php',
'MediaWiki\\Hook\\ImportSourcesHook' => __DIR__ . '/includes/specials/Hook/ImportSourcesHook.php',
'MediaWiki\\Hook\\InfoActionHook' => __DIR__ . '/includes/actions/Hook/InfoActionHook.php',
'MediaWiki\\Hook\\InternalParseBeforeLinksHook' => __DIR__ . '/includes/parser/Hook/InternalParseBeforeLinksHook.php',
'MediaWiki\\Hook\\InternalParseBeforeSanitizeHook' => __DIR__ . '/includes/parser/Hook/InternalParseBeforeSanitizeHook.php',
'MediaWiki\\Hook\\IsUploadAllowedFromUrlHook' => __DIR__ . '/includes/upload/Hook/IsUploadAllowedFromUrlHook.php',
'MediaWiki\\Hook\\IsValidEmailAddrHook' => __DIR__ . '/includes/parser/Hook/IsValidEmailAddrHook.php',
'MediaWiki\\Hook\\LanguageGetNamespacesHook' => __DIR__ . '/includes/language/Hook/LanguageGetNamespacesHook.php',
'MediaWiki\\Hook\\LanguageSelectorHook' => __DIR__ . '/includes/specials/Hook/LanguageSelectorHook.php',
'MediaWiki\\Hook\\LinksUpdateAfterInsertHook' => __DIR__ . '/includes/deferred/Hook/LinksUpdateAfterInsertHook.php',
'MediaWiki\\Hook\\LinksUpdateCompleteHook' => __DIR__ . '/includes/deferred/Hook/LinksUpdateCompleteHook.php',
'MediaWiki\\Hook\\LinksUpdateConstructedHook' => __DIR__ . '/includes/deferred/Hook/LinksUpdateConstructedHook.php',
'MediaWiki\\Hook\\LinksUpdateHook' => __DIR__ . '/includes/deferred/Hook/LinksUpdateHook.php',
'MediaWiki\\Hook\\LocalFilePurgeThumbnailsHook' => __DIR__ . '/includes/filerepo/Hook/LocalFilePurgeThumbnailsHook.php',
'MediaWiki\\Hook\\LocalFile__getHistoryHook' => __DIR__ . '/includes/filerepo/Hook/LocalFile__getHistoryHook.php',
'MediaWiki\\Hook\\LocalisationCacheRecacheFallbackHook' => __DIR__ . '/includes/cache/localisation/Hook/LocalisationCacheRecacheFallbackHook.php',
'MediaWiki\\Hook\\LocalisationCacheRecacheHook' => __DIR__ . '/includes/cache/localisation/Hook/LocalisationCacheRecacheHook.php',
'MediaWiki\\Hook\\LogEventsListGetExtraInputsHook' => __DIR__ . '/includes/logging/Hook/LogEventsListGetExtraInputsHook.php',
'MediaWiki\\Hook\\LogEventsListLineEndingHook' => __DIR__ . '/includes/logging/Hook/LogEventsListLineEndingHook.php',
'MediaWiki\\Hook\\LogEventsListShowLogExtractHook' => __DIR__ . '/includes/logging/Hook/LogEventsListShowLogExtractHook.php',
'MediaWiki\\Hook\\LogExceptionHook' => __DIR__ . '/includes/exception/Hook/LogExceptionHook.php',
'MediaWiki\\Hook\\LogLineHook' => __DIR__ . '/includes/logging/Hook/LogLineHook.php',
'MediaWiki\\Hook\\LoginFormValidErrorMessagesHook' => __DIR__ . '/includes/specials/Hook/LoginFormValidErrorMessagesHook.php',
'MediaWiki\\Hook\\LonelyPagesQueryHook' => __DIR__ . '/includes/specials/Hook/LonelyPagesQueryHook.php',
'MediaWiki\\Hook\\ManualLogEntryBeforePublishHook' => __DIR__ . '/includes/logging/Hook/ManualLogEntryBeforePublishHook.php',
'MediaWiki\\Hook\\MarkPatrolledCompleteHook' => __DIR__ . '/includes/changes/Hook/MarkPatrolledCompleteHook.php',
'MediaWiki\\Hook\\MarkPatrolledHook' => __DIR__ . '/includes/changes/Hook/MarkPatrolledHook.php',
'MediaWiki\\Hook\\ModifyExportQueryHook' => __DIR__ . '/includes/export/Hook/ModifyExportQueryHook.php',
'MediaWiki\\Hook\\NamespaceIsMovableHook' => __DIR__ . '/includes/title/Hook/NamespaceIsMovableHook.php',
'MediaWiki\\Hook\\NewPagesLineEndingHook' => __DIR__ . '/includes/specials/Hook/NewPagesLineEndingHook.php',
'MediaWiki\\Hook\\OldChangesListRecentChangesLineHook' => __DIR__ . '/includes/changes/Hook/OldChangesListRecentChangesLineHook.php',
'MediaWiki\\Hook\\OtherAutoblockLogLinkHook' => __DIR__ . '/includes/specials/Hook/OtherAutoblockLogLinkHook.php',
'MediaWiki\\Hook\\OtherBlockLogLinkHook' => __DIR__ . '/includes/specials/Hook/OtherBlockLogLinkHook.php',
'MediaWiki\\Hook\\PageHistoryBeforeListHook' => __DIR__ . '/includes/actions/Hook/PageHistoryBeforeListHook.php',
'MediaWiki\\Hook\\PageHistoryLineEndingHook' => __DIR__ . '/includes/actions/Hook/PageHistoryLineEndingHook.php',
'MediaWiki\\Hook\\PageHistoryPager__doBatchLookupsHook' => __DIR__ . '/includes/actions/Hook/PageHistoryPager__doBatchLookupsHook.php',
'MediaWiki\\Hook\\PageHistoryPager__getQueryInfoHook' => __DIR__ . '/includes/actions/Hook/PageHistoryPager__getQueryInfoHook.php',
'MediaWiki\\Hook\\PageRenderingHashHook' => __DIR__ . '/includes/parser/Hook/PageRenderingHashHook.php',
'MediaWiki\\Hook\\ParserAfterParseHook' => __DIR__ . '/includes/parser/Hook/ParserAfterParseHook.php',
'MediaWiki\\Hook\\ParserAfterStripHook' => __DIR__ . '/includes/parser/Hook/ParserAfterStripHook.php',
'MediaWiki\\Hook\\ParserAfterTidyHook' => __DIR__ . '/includes/parser/Hook/ParserAfterTidyHook.php',
'MediaWiki\\Hook\\ParserBeforeInternalParseHook' => __DIR__ . '/includes/parser/Hook/ParserBeforeInternalParseHook.php',
'MediaWiki\\Hook\\ParserBeforePreprocessHook' => __DIR__ . '/includes/parser/Hook/ParserBeforePreprocessHook.php',
'MediaWiki\\Hook\\ParserBeforeStripHook' => __DIR__ . '/includes/parser/Hook/ParserBeforeStripHook.php',
'MediaWiki\\Hook\\ParserBeforeTidyHook' => __DIR__ . '/includes/parser/Hook/ParserBeforeTidyHook.php',
'MediaWiki\\Hook\\ParserCacheSaveCompleteHook' => __DIR__ . '/includes/parser/Hook/ParserCacheSaveCompleteHook.php',
'MediaWiki\\Hook\\ParserClearStateHook' => __DIR__ . '/includes/parser/Hook/ParserClearStateHook.php',
'MediaWiki\\Hook\\ParserClonedHook' => __DIR__ . '/includes/parser/Hook/ParserClonedHook.php',
'MediaWiki\\Hook\\ParserFetchTemplateHook' => __DIR__ . '/includes/parser/Hook/ParserFetchTemplateHook.php',
'MediaWiki\\Hook\\ParserFirstCallInitHook' => __DIR__ . '/includes/parser/Hook/ParserFirstCallInitHook.php',
'MediaWiki\\Hook\\ParserGetVariableValueSwitchHook' => __DIR__ . '/includes/parser/Hook/ParserGetVariableValueSwitchHook.php',
'MediaWiki\\Hook\\ParserGetVariableValueTsHook' => __DIR__ . '/includes/parser/Hook/ParserGetVariableValueTsHook.php',
'MediaWiki\\Hook\\ParserGetVariableValueVarCacheHook' => __DIR__ . '/includes/parser/Hook/ParserGetVariableValueVarCacheHook.php',
'MediaWiki\\Hook\\ParserLimitReportFormatHook' => __DIR__ . '/includes/parser/Hook/ParserLimitReportFormatHook.php',
'MediaWiki\\Hook\\ParserLimitReportPrepareHook' => __DIR__ . '/includes/parser/Hook/ParserLimitReportPrepareHook.php',
'MediaWiki\\Hook\\ParserMakeImageParamsHook' => __DIR__ . '/includes/parser/Hook/ParserMakeImageParamsHook.php',
'MediaWiki\\Hook\\ParserOptionsRegisterHook' => __DIR__ . '/includes/parser/Hook/ParserOptionsRegisterHook.php',
'MediaWiki\\Hook\\ParserOutputPostCacheTransformHook' => __DIR__ . '/includes/parser/Hook/ParserOutputPostCacheTransformHook.php',
'MediaWiki\\Hook\\ParserPreSaveTransformCompleteHook' => __DIR__ . '/includes/parser/Hook/ParserPreSaveTransformCompleteHook.php',
'MediaWiki\\Hook\\ParserSectionCreateHook' => __DIR__ . '/includes/parser/Hook/ParserSectionCreateHook.php',
'MediaWiki\\Hook\\PasswordPoliciesForUserHook' => __DIR__ . '/includes/password/Hook/PasswordPoliciesForUserHook.php',
'MediaWiki\\Hook\\PersonalUrlsHook' => __DIR__ . '/includes/skins/Hook/PersonalUrlsHook.php',
'MediaWiki\\Hook\\PostLoginRedirectHook' => __DIR__ . '/includes/specials/Hook/PostLoginRedirectHook.php',
'MediaWiki\\Hook\\PreferencesGetLegendHook' => __DIR__ . '/includes/specials/Hook/PreferencesGetLegendHook.php',
'MediaWiki\\Hook\\PrefsEmailAuditHook' => __DIR__ . '/includes/specials/Hook/PrefsEmailAuditHook.php',
'MediaWiki\\Hook\\RandomPageQueryHook' => __DIR__ . '/includes/specials/Hook/RandomPageQueryHook.php',
'MediaWiki\\Hook\\RawPageViewBeforeOutputHook' => __DIR__ . '/includes/actions/Hook/RawPageViewBeforeOutputHook.php',
'MediaWiki\\Hook\\RecentChange_saveHook' => __DIR__ . '/includes/changes/Hook/RecentChange_saveHook.php',
'MediaWiki\\Hook\\RecentChangesPurgeRowsHook' => __DIR__ . '/includes/jobqueue/jobs/Hook/RecentChangesPurgeRowsHook.php',
'MediaWiki\\Hook\\RejectParserCacheValueHook' => __DIR__ . '/includes/parser/Hook/RejectParserCacheValueHook.php',
'MediaWiki\\Hook\\RequestContextCreateSkinHook' => __DIR__ . '/includes/context/Hook/RequestContextCreateSkinHook.php',
'MediaWiki\\Hook\\SendWatchlistEmailNotificationHook' => __DIR__ . '/includes/mail/Hook/SendWatchlistEmailNotificationHook.php',
'MediaWiki\\Hook\\ShortPagesQueryHook' => __DIR__ . '/includes/specials/Hook/ShortPagesQueryHook.php',
'MediaWiki\\Hook\\SidebarBeforeOutputHook' => __DIR__ . '/includes/skins/Hook/SidebarBeforeOutputHook.php',
'MediaWiki\\Hook\\SiteNoticeAfterHook' => __DIR__ . '/includes/skins/Hook/SiteNoticeAfterHook.php',
'MediaWiki\\Hook\\SiteNoticeBeforeHook' => __DIR__ . '/includes/skins/Hook/SiteNoticeBeforeHook.php',
'MediaWiki\\Hook\\SkinAddFooterLinksHook' => __DIR__ . '/includes/skins/Hook/SkinAddFooterLinksHook.php',
'MediaWiki\\Hook\\SkinAfterBottomScriptsHook' => __DIR__ . '/includes/skins/Hook/SkinAfterBottomScriptsHook.php',
'MediaWiki\\Hook\\SkinAfterContentHook' => __DIR__ . '/includes/skins/Hook/SkinAfterContentHook.php',
'MediaWiki\\Hook\\SkinBuildSidebarHook' => __DIR__ . '/includes/skins/Hook/SkinBuildSidebarHook.php',
'MediaWiki\\Hook\\SkinCopyrightFooterHook' => __DIR__ . '/includes/skins/Hook/SkinCopyrightFooterHook.php',
'MediaWiki\\Hook\\SkinEditSectionLinksHook' => __DIR__ . '/includes/skins/Hook/SkinEditSectionLinksHook.php',
'MediaWiki\\Hook\\SkinGetPoweredByHook' => __DIR__ . '/includes/skins/Hook/SkinGetPoweredByHook.php',
'MediaWiki\\Hook\\SkinPreloadExistenceHook' => __DIR__ . '/includes/skins/Hook/SkinPreloadExistenceHook.php',
'MediaWiki\\Hook\\SkinSubPageSubtitleHook' => __DIR__ . '/includes/skins/Hook/SkinSubPageSubtitleHook.php',
'MediaWiki\\Hook\\SkinTemplateBuildNavUrlsNav_urlsAfterPermalinkHook' => __DIR__ . '/includes/skins/Hook/SkinTemplateBuildNavUrlsNav_urlsAfterPermalinkHook.php',
'MediaWiki\\Hook\\SkinTemplateGetLanguageLinkHook' => __DIR__ . '/includes/skins/Hook/SkinTemplateGetLanguageLinkHook.php',
'MediaWiki\\Hook\\SkinTemplateNavigationHook' => __DIR__ . '/includes/skins/Hook/SkinTemplateNavigationHook.php',
'MediaWiki\\Hook\\SkinTemplateNavigation__SpecialPageHook' => __DIR__ . '/includes/skins/Hook/SkinTemplateNavigation__SpecialPageHook.php',
'MediaWiki\\Hook\\SkinTemplateNavigation__UniversalHook' => __DIR__ . '/includes/skins/Hook/SkinTemplateNavigation__UniversalHook.php',
'MediaWiki\\Hook\\SkinTemplateOutputPageBeforeExecHook' => __DIR__ . '/includes/skins/Hook/SkinTemplateOutputPageBeforeExecHook.php',
'MediaWiki\\Hook\\SkinTemplatePreventOtherActiveTabsHook' => __DIR__ . '/includes/skins/Hook/SkinTemplatePreventOtherActiveTabsHook.php',
'MediaWiki\\Hook\\SkinTemplateTabActionHook' => __DIR__ . '/includes/skins/Hook/SkinTemplateTabActionHook.php',
'MediaWiki\\Hook\\SkinTemplateToolboxEndHook' => __DIR__ . '/includes/skins/Hook/SkinTemplateToolboxEndHook.php',
'MediaWiki\\Hook\\SoftwareInfoHook' => __DIR__ . '/includes/specials/Hook/SoftwareInfoHook.php',
'MediaWiki\\Hook\\SpecialBlockModifyFormFieldsHook' => __DIR__ . '/includes/specials/Hook/SpecialBlockModifyFormFieldsHook.php',
'MediaWiki\\Hook\\SpecialContributionsBeforeMainOutputHook' => __DIR__ . '/includes/specials/Hook/SpecialContributionsBeforeMainOutputHook.php',
'MediaWiki\\Hook\\SpecialContributions__formatRow__flagsHook' => __DIR__ . '/includes/specials/Hook/SpecialContributions__formatRow__flagsHook.php',
'MediaWiki\\Hook\\SpecialContributions__getForm__filtersHook' => __DIR__ . '/includes/specials/Hook/SpecialContributions__getForm__filtersHook.php',
'MediaWiki\\Hook\\SpecialListusersDefaultQueryHook' => __DIR__ . '/includes/specials/Hook/SpecialListusersDefaultQueryHook.php',
'MediaWiki\\Hook\\SpecialListusersFormatRowHook' => __DIR__ . '/includes/specials/Hook/SpecialListusersFormatRowHook.php',
'MediaWiki\\Hook\\SpecialListusersHeaderFormHook' => __DIR__ . '/includes/specials/Hook/SpecialListusersHeaderFormHook.php',
'MediaWiki\\Hook\\SpecialListusersHeaderHook' => __DIR__ . '/includes/specials/Hook/SpecialListusersHeaderHook.php',
'MediaWiki\\Hook\\SpecialListusersQueryInfoHook' => __DIR__ . '/includes/specials/Hook/SpecialListusersQueryInfoHook.php',
'MediaWiki\\Hook\\SpecialLogAddLogSearchRelationsHook' => __DIR__ . '/includes/specials/Hook/SpecialLogAddLogSearchRelationsHook.php',
'MediaWiki\\Hook\\SpecialMovepageAfterMoveHook' => __DIR__ . '/includes/specials/Hook/SpecialMovepageAfterMoveHook.php',
'MediaWiki\\Hook\\SpecialMuteModifyFormFieldsHook' => __DIR__ . '/includes/specials/Hook/SpecialMuteModifyFormFieldsHook.php',
'MediaWiki\\Hook\\SpecialMuteSubmitHook' => __DIR__ . '/includes/specials/Hook/SpecialMuteSubmitHook.php',
'MediaWiki\\Hook\\SpecialNewPagesFiltersHook' => __DIR__ . '/includes/specials/Hook/SpecialNewPagesFiltersHook.php',
'MediaWiki\\Hook\\SpecialNewpagesConditionsHook' => __DIR__ . '/includes/specials/Hook/SpecialNewpagesConditionsHook.php',
'MediaWiki\\Hook\\SpecialRandomGetRandomTitleHook' => __DIR__ . '/includes/specials/Hook/SpecialRandomGetRandomTitleHook.php',
'MediaWiki\\Hook\\SpecialRecentChangesPanelHook' => __DIR__ . '/includes/specials/Hook/SpecialRecentChangesPanelHook.php',
'MediaWiki\\Hook\\SpecialResetTokensTokensHook' => __DIR__ . '/includes/specials/Hook/SpecialResetTokensTokensHook.php',
'MediaWiki\\Hook\\SpecialSearchCreateLinkHook' => __DIR__ . '/includes/specials/Hook/SpecialSearchCreateLinkHook.php',
'MediaWiki\\Hook\\SpecialSearchGoResultHook' => __DIR__ . '/includes/specials/Hook/SpecialSearchGoResultHook.php',
'MediaWiki\\Hook\\SpecialSearchNogomatchHook' => __DIR__ . '/includes/specials/Hook/SpecialSearchNogomatchHook.php',
'MediaWiki\\Hook\\SpecialSearchProfilesHook' => __DIR__ . '/includes/specials/Hook/SpecialSearchProfilesHook.php',
'MediaWiki\\Hook\\SpecialSearchResultsAppendHook' => __DIR__ . '/includes/specials/Hook/SpecialSearchResultsAppendHook.php',
'MediaWiki\\Hook\\SpecialSearchResultsHook' => __DIR__ . '/includes/specials/Hook/SpecialSearchResultsHook.php',
'MediaWiki\\Hook\\SpecialSearchResultsPrependHook' => __DIR__ . '/includes/specials/Hook/SpecialSearchResultsPrependHook.php',
'MediaWiki\\Hook\\SpecialSearchSetupEngineHook' => __DIR__ . '/includes/specials/Hook/SpecialSearchSetupEngineHook.php',
'MediaWiki\\Hook\\SpecialStatsAddExtraHook' => __DIR__ . '/includes/specials/Hook/SpecialStatsAddExtraHook.php',
'MediaWiki\\Hook\\SpecialTrackingCategories__generateCatLinkHook' => __DIR__ . '/includes/specials/Hook/SpecialTrackingCategories__generateCatLinkHook.php',
'MediaWiki\\Hook\\SpecialTrackingCategories__preprocessHook' => __DIR__ . '/includes/specials/Hook/SpecialTrackingCategories__preprocessHook.php',
'MediaWiki\\Hook\\SpecialUploadCompleteHook' => __DIR__ . '/includes/specials/Hook/SpecialUploadCompleteHook.php',
'MediaWiki\\Hook\\SpecialVersionVersionUrlHook' => __DIR__ . '/includes/specials/Hook/SpecialVersionVersionUrlHook.php',
'MediaWiki\\Hook\\SpecialWatchlistGetNonRevisionTypesHook' => __DIR__ . '/includes/specials/Hook/SpecialWatchlistGetNonRevisionTypesHook.php',
'MediaWiki\\Hook\\ThumbnailBeforeProduceHTMLHook' => __DIR__ . '/includes/media/Hook/ThumbnailBeforeProduceHTMLHook.php',
'MediaWiki\\Hook\\UnblockUserCompleteHook' => __DIR__ . '/includes/specials/Hook/UnblockUserCompleteHook.php',
'MediaWiki\\Hook\\UnblockUserHook' => __DIR__ . '/includes/specials/Hook/UnblockUserHook.php',
'MediaWiki\\Hook\\UndeleteForm__showHistoryHook' => __DIR__ . '/includes/specials/Hook/UndeleteForm__showHistoryHook.php',
'MediaWiki\\Hook\\UndeleteForm__showRevisionHook' => __DIR__ . '/includes/specials/Hook/UndeleteForm__showRevisionHook.php',
'MediaWiki\\Hook\\UndeleteForm__undeleteHook' => __DIR__ . '/includes/specials/Hook/UndeleteForm__undeleteHook.php',
'MediaWiki\\Hook\\UndeletePageToolLinksHook' => __DIR__ . '/includes/skins/Hook/UndeletePageToolLinksHook.php',
'MediaWiki\\Hook\\UndeleteShowRevisionHook' => __DIR__ . '/includes/specials/Hook/UndeleteShowRevisionHook.php',
'MediaWiki\\Hook\\UnwatchArticleCompleteHook' => __DIR__ . '/includes/actions/Hook/UnwatchArticleCompleteHook.php',
'MediaWiki\\Hook\\UnwatchArticleHook' => __DIR__ . '/includes/actions/Hook/UnwatchArticleHook.php',
'MediaWiki\\Hook\\UpdateUserMailerFormattedPageStatusHook' => __DIR__ . '/includes/mail/Hook/UpdateUserMailerFormattedPageStatusHook.php',
'MediaWiki\\Hook\\UploadCompleteHook' => __DIR__ . '/includes/upload/Hook/UploadCompleteHook.php',
'MediaWiki\\Hook\\UploadCreateFromRequestHook' => __DIR__ . '/includes/upload/Hook/UploadCreateFromRequestHook.php',
'MediaWiki\\Hook\\UploadFormInitDescriptorHook' => __DIR__ . '/includes/specials/Hook/UploadFormInitDescriptorHook.php',
'MediaWiki\\Hook\\UploadFormSourceDescriptorsHook' => __DIR__ . '/includes/specials/Hook/UploadFormSourceDescriptorsHook.php',
'MediaWiki\\Hook\\UploadForm_BeforeProcessingHook' => __DIR__ . '/includes/specials/Hook/UploadForm_BeforeProcessingHook.php',
'MediaWiki\\Hook\\UploadForm_getInitialPageTextHook' => __DIR__ . '/includes/specials/Hook/UploadForm_getInitialPageTextHook.php',
'MediaWiki\\Hook\\UploadForm_initialHook' => __DIR__ . '/includes/specials/Hook/UploadForm_initialHook.php',
'MediaWiki\\Hook\\UploadStashFileHook' => __DIR__ . '/includes/upload/Hook/UploadStashFileHook.php',
'MediaWiki\\Hook\\UploadVerifyFileHook' => __DIR__ . '/includes/upload/Hook/UploadVerifyFileHook.php',
'MediaWiki\\Hook\\UploadVerifyUploadHook' => __DIR__ . '/includes/upload/Hook/UploadVerifyUploadHook.php',
'MediaWiki\\Hook\\UserGetLanguageObjectHook' => __DIR__ . '/includes/context/Hook/UserGetLanguageObjectHook.php',
'MediaWiki\\Hook\\UserLoginCompleteHook' => __DIR__ . '/includes/specials/Hook/UserLoginCompleteHook.php',
'MediaWiki\\Hook\\UserLogoutCompleteHook' => __DIR__ . '/includes/specials/Hook/UserLogoutCompleteHook.php',
'MediaWiki\\Hook\\UserMailerChangeReturnPathHook' => __DIR__ . '/includes/mail/Hook/UserMailerChangeReturnPathHook.php',
'MediaWiki\\Hook\\UserMailerSplitToHook' => __DIR__ . '/includes/mail/Hook/UserMailerSplitToHook.php',
'MediaWiki\\Hook\\UserMailerTransformContentHook' => __DIR__ . '/includes/mail/Hook/UserMailerTransformContentHook.php',
'MediaWiki\\Hook\\UserMailerTransformMessageHook' => __DIR__ . '/includes/mail/Hook/UserMailerTransformMessageHook.php',
'MediaWiki\\Hook\\UsersPagerDoBatchLookupsHook' => __DIR__ . '/includes/specials/Hook/UsersPagerDoBatchLookupsHook.php',
'MediaWiki\\Hook\\ValidateExtendedMetadataCacheHook' => __DIR__ . '/includes/media/Hook/ValidateExtendedMetadataCacheHook.php',
'MediaWiki\\Hook\\WantedPages__getQueryInfoHook' => __DIR__ . '/includes/specials/Hook/WantedPages__getQueryInfoHook.php',
'MediaWiki\\Hook\\WatchArticleCompleteHook' => __DIR__ . '/includes/actions/Hook/WatchArticleCompleteHook.php',
'MediaWiki\\Hook\\WatchArticleHook' => __DIR__ . '/includes/actions/Hook/WatchArticleHook.php',
'MediaWiki\\Hook\\WatchedItemQueryServiceExtensionsHook' => __DIR__ . '/includes/watcheditem/Hook/WatchedItemQueryServiceExtensionsHook.php',
'MediaWiki\\Hook\\WatchlistEditorBeforeFormRenderHook' => __DIR__ . '/includes/specials/Hook/WatchlistEditorBeforeFormRenderHook.php',
'MediaWiki\\Hook\\WatchlistEditorBuildRemoveLineHook' => __DIR__ . '/includes/specials/Hook/WatchlistEditorBuildRemoveLineHook.php',
'MediaWiki\\Hook\\WhatLinksHerePropsHook' => __DIR__ . '/includes/specials/Hook/WhatLinksHerePropsHook.php',
'MediaWiki\\Hook\\WikiExporter__dumpStableQueryHook' => __DIR__ . '/includes/export/Hook/WikiExporter__dumpStableQueryHook.php',
'MediaWiki\\Hook\\XmlDumpWriterOpenPageHook' => __DIR__ . '/includes/export/Hook/XmlDumpWriterOpenPageHook.php',
'MediaWiki\\Hook\\XmlDumpWriterWriteRevisionHook' => __DIR__ . '/includes/export/Hook/XmlDumpWriterWriteRevisionHook.php',
'MediaWiki\\Languages\\Data\\CrhExceptions' => __DIR__ . '/languages/data/CrhExceptions.php',
'MediaWiki\\Languages\\Data\\Names' => __DIR__ . '/languages/data/Names.php',
'MediaWiki\\Languages\\Data\\ZhConversion' => __DIR__ . '/languages/data/ZhConversion.php',
'MediaWiki\\Languages\\Hook\\LanguageGetTranslatedLanguageNamesHook' => __DIR__ . '/includes/language/Hook/LanguageGetTranslatedLanguageNamesHook.php',
'MediaWiki\\Languages\\Hook\\Language__getMessagesFileNameHook' => __DIR__ . '/includes/language/Hook/Language__getMessagesFileNameHook.php',
'MediaWiki\\Languages\\LanguageConverterFactory' => __DIR__ . '/includes/language/LanguageConverterFactory.php',
'MediaWiki\\Languages\\LanguageFactory' => __DIR__ . '/includes/language/LanguageFactory.php',
'MediaWiki\\Languages\\LanguageFallback' => __DIR__ . '/includes/language/LanguageFallback.php',
'MediaWiki\\Languages\\LanguageNameUtils' => __DIR__ . '/includes/language/LanguageNameUtils.php',
'MediaWiki\\Logger\\ConsoleLogger' => __DIR__ . '/includes/debug/logger/ConsoleLogger.php',
'MediaWiki\\Logger\\ConsoleSpi' => __DIR__ . '/includes/debug/logger/ConsoleSpi.php',
'MediaWiki\\Logger\\LegacyLogger' => __DIR__ . '/includes/debug/logger/LegacyLogger.php',
'MediaWiki\\Logger\\LegacySpi' => __DIR__ . '/includes/debug/logger/LegacySpi.php',
'MediaWiki\\Logger\\LogCapturingSpi' => __DIR__ . '/includes/debug/logger/LogCapturingSpi.php',
'MediaWiki\\Logger\\LoggerFactory' => __DIR__ . '/includes/debug/logger/LoggerFactory.php',
'MediaWiki\\Logger\\MonologSpi' => __DIR__ . '/includes/debug/logger/MonologSpi.php',
'MediaWiki\\Logger\\Monolog\\AvroFormatter' => __DIR__ . '/includes/debug/logger/monolog/AvroFormatter.php',
'MediaWiki\\Logger\\Monolog\\BufferHandler' => __DIR__ . '/includes/debug/logger/monolog/BufferHandler.php',
'MediaWiki\\Logger\\Monolog\\CeeFormatter' => __DIR__ . '/includes/debug/logger/monolog/CeeFormatter.php',
'MediaWiki\\Logger\\Monolog\\KafkaHandler' => __DIR__ . '/includes/debug/logger/monolog/KafkaHandler.php',
'MediaWiki\\Logger\\Monolog\\LegacyFormatter' => __DIR__ . '/includes/debug/logger/monolog/LegacyFormatter.php',
'MediaWiki\\Logger\\Monolog\\LegacyHandler' => __DIR__ . '/includes/debug/logger/monolog/LegacyHandler.php',
'MediaWiki\\Logger\\Monolog\\LineFormatter' => __DIR__ . '/includes/debug/logger/monolog/LineFormatter.php',
'MediaWiki\\Logger\\Monolog\\LogstashFormatter' => __DIR__ . '/includes/debug/logger/monolog/LogstashFormatter.php',
'MediaWiki\\Logger\\Monolog\\MwlogHandler' => __DIR__ . '/includes/debug/logger/monolog/MwlogHandler.php',
'MediaWiki\\Logger\\Monolog\\SyslogHandler' => __DIR__ . '/includes/debug/logger/monolog/SyslogHandler.php',
'MediaWiki\\Logger\\Monolog\\WikiProcessor' => __DIR__ . '/includes/debug/logger/monolog/WikiProcessor.php',
'MediaWiki\\Logger\\NullSpi' => __DIR__ . '/includes/debug/logger/NullSpi.php',
'MediaWiki\\Logger\\Spi' => __DIR__ . '/includes/debug/logger/Spi.php',
'MediaWiki\\MediaWikiServices' => __DIR__ . '/includes/MediaWikiServices.php',
'MediaWiki\\Navigation\\PrevNextNavigationRenderer' => __DIR__ . '/includes/Navigation/PrevNextNavigationRenderer.php',
'MediaWiki\\OutputHandler' => __DIR__ . '/includes/OutputHandler.php',
'MediaWiki\\Page\\MovePageFactory' => __DIR__ . '/includes/page/MovePageFactory.php',
'MediaWiki\\Mail\\Emailer' => __DIR__ . '/includes/mail/Emailer.php',
'MediaWiki\\Mail\\IEmailer' => __DIR__ . '/includes/mail/IEmailer.php',
'MediaWiki\\ProcOpenError' => __DIR__ . '/includes/exception/ProcOpenError.php',
'MediaWiki\\Search\\ParserOutputSearchDataExtractor' => __DIR__ . '/includes/search/ParserOutputSearchDataExtractor.php',
'MediaWiki\\Services\\CannotReplaceActiveServiceException' => __DIR__ . '/includes/libs/services/CannotReplaceActiveServiceException.php',
'MediaWiki\\Services\\ContainerDisabledException' => __DIR__ . '/includes/libs/services/ContainerDisabledException.php',
'MediaWiki\\Services\\DestructibleService' => __DIR__ . '/includes/libs/services/DestructibleService.php',
'MediaWiki\\Services\\NoSuchServiceException' => __DIR__ . '/includes/libs/services/NoSuchServiceException.php',
'MediaWiki\\Services\\SalvageableService' => __DIR__ . '/includes/libs/services/SalvageableService.php',
'MediaWiki\\Services\\ServiceAlreadyDefinedException' => __DIR__ . '/includes/libs/services/ServiceAlreadyDefinedException.php',
'MediaWiki\\Services\\ServiceContainer' => __DIR__ . '/includes/libs/services/ServiceContainer.php',
'MediaWiki\\Services\\ServiceDisabledException' => __DIR__ . '/includes/libs/services/ServiceDisabledException.php',
'MediaWiki\\ShellDisabledError' => __DIR__ . '/includes/exception/ShellDisabledError.php',
'MediaWiki\\Site\\MediaWikiPageNameNormalizer' => __DIR__ . '/includes/site/MediaWikiPageNameNormalizer.php',
'MediaWiki\\Skins\\Hook\\SkinAfterPortletHook' => __DIR__ . '/includes/skins/Hook/SkinAfterPortletHook.php',
'MediaWiki\\Skins\\Hook\\SkinPageReadyConfigHook' => __DIR__ . '/includes/skins/Hook/SkinPageReadyConfigHook.php',
'MediaWiki\\Special\\SpecialPageFactory' => __DIR__ . '/includes/specialpage/SpecialPageFactory.php',
'MediaWiki\\Storage\\IncompleteRevisionException' => __DIR__ . '/includes/Revision/IncompleteRevisionException.php',
'MediaWiki\\Storage\\MutableRevisionRecord' => __DIR__ . '/includes/Revision/MutableRevisionRecord.php',
@ -932,35 +1123,6 @@ $wgAutoloadLocalClasses = [
'MediaWiki\\Storage\\RevisionStoreRecord' => __DIR__ . '/includes/Revision/RevisionStoreRecord.php',
'MediaWiki\\Storage\\SlotRecord' => __DIR__ . '/includes/Revision/SlotRecord.php',
'MediaWiki\\Storage\\SuppressedDataException' => __DIR__ . '/includes/Revision/SuppressedDataException.php',
'MediaWiki\\User\\UserIdentity' => __DIR__ . '/includes/user/UserIdentity.php',
'MediaWiki\\User\\UserIdentityValue' => __DIR__ . '/includes/user/UserIdentityValue.php',
'MediaWiki\\Widget\\CheckMatrixWidget' => __DIR__ . '/includes/widget/CheckMatrixWidget.php',
'MediaWiki\\Widget\\ComplexNamespaceInputWidget' => __DIR__ . '/includes/widget/ComplexNamespaceInputWidget.php',
'MediaWiki\\Widget\\ComplexTitleInputWidget' => __DIR__ . '/includes/widget/ComplexTitleInputWidget.php',
'MediaWiki\\Widget\\DateInputWidget' => __DIR__ . '/includes/widget/DateInputWidget.php',
'MediaWiki\\Widget\\DateTimeInputWidget' => __DIR__ . '/includes/widget/DateTimeInputWidget.php',
'MediaWiki\\Widget\\ExpiryInputWidget' => __DIR__ . '/includes/widget/ExpiryInputWidget.php',
'MediaWiki\\Widget\\NamespaceInputWidget' => __DIR__ . '/includes/widget/NamespaceInputWidget.php',
'MediaWiki\\Widget\\NamespacesMultiselectWidget' => __DIR__ . '/includes/widget/NamespacesMultiselectWidget.php',
'MediaWiki\\Widget\\PendingTextInputWidget' => __DIR__ . '/includes/widget/PendingTextInputWidget.php',
'MediaWiki\\Widget\\SearchInputWidget' => __DIR__ . '/includes/widget/SearchInputWidget.php',
'MediaWiki\\Widget\\Search\\BasicSearchResultSetWidget' => __DIR__ . '/includes/widget/search/BasicSearchResultSetWidget.php',
'MediaWiki\\Widget\\Search\\DidYouMeanWidget' => __DIR__ . '/includes/widget/search/DidYouMeanWidget.php',
'MediaWiki\\Widget\\Search\\FullSearchResultWidget' => __DIR__ . '/includes/widget/search/FullSearchResultWidget.php',
'MediaWiki\\Widget\\Search\\InterwikiSearchResultSetWidget' => __DIR__ . '/includes/widget/search/InterwikiSearchResultSetWidget.php',
'MediaWiki\\Widget\\Search\\InterwikiSearchResultWidget' => __DIR__ . '/includes/widget/search/InterwikiSearchResultWidget.php',
'MediaWiki\\Widget\\Search\\SearchFormWidget' => __DIR__ . '/includes/widget/search/SearchFormWidget.php',
'MediaWiki\\Widget\\Search\\SearchResultSetWidget' => __DIR__ . '/includes/widget/search/SearchResultSetWidget.php',
'MediaWiki\\Widget\\Search\\SearchResultWidget' => __DIR__ . '/includes/widget/search/SearchResultWidget.php',
'MediaWiki\\Widget\\Search\\SimpleSearchResultSetWidget' => __DIR__ . '/includes/widget/search/SimpleSearchResultSetWidget.php',
'MediaWiki\\Widget\\Search\\SimpleSearchResultWidget' => __DIR__ . '/includes/widget/search/SimpleSearchResultWidget.php',
'MediaWiki\\Widget\\SelectWithInputWidget' => __DIR__ . '/includes/widget/SelectWithInputWidget.php',
'MediaWiki\\Widget\\SizeFilterWidget' => __DIR__ . '/includes/widget/SizeFilterWidget.php',
'MediaWiki\\Widget\\TagMultiselectWidget' => __DIR__ . '/includes/widget/TagMultiselectWidget.php',
'MediaWiki\\Widget\\TitleInputWidget' => __DIR__ . '/includes/widget/TitleInputWidget.php',
'MediaWiki\\Widget\\TitlesMultiselectWidget' => __DIR__ . '/includes/widget/TitlesMultiselectWidget.php',
'MediaWiki\\Widget\\UserInputWidget' => __DIR__ . '/includes/widget/UserInputWidget.php',
'MediaWiki\\Widget\\UsersMultiselectWidget' => __DIR__ . '/includes/widget/UsersMultiselectWidget.php',
'MediumSpecificBagOStuff' => __DIR__ . '/includes/libs/objectcache/MediumSpecificBagOStuff.php',
'MemcLockManager' => __DIR__ . '/includes/libs/lockmanager/MemcLockManager.php',
'MemcachedBagOStuff' => __DIR__ . '/includes/libs/objectcache/MemcachedBagOStuff.php',
@ -1039,7 +1201,6 @@ $wgAutoloadLocalClasses = [
'PHPVersionCheck' => __DIR__ . '/includes/PHPVersionCheck.php',
'PNGHandler' => __DIR__ . '/includes/media/PNGHandler.php',
'PNGMetadataExtractor' => __DIR__ . '/includes/media/PNGMetadataExtractor.php',
'PPCustomFrame_DOM' => __DIR__ . '/includes/parser/PPCustomFrame_DOM.php',
'PPCustomFrame_Hash' => __DIR__ . '/includes/parser/PPCustomFrame_Hash.php',
'PPDPart' => __DIR__ . '/includes/parser/PPDPart.php',
'PPDPart_Hash' => __DIR__ . '/includes/parser/PPDPart_Hash.php',
@ -1048,18 +1209,15 @@ $wgAutoloadLocalClasses = [
'PPDStackElement_Hash' => __DIR__ . '/includes/parser/PPDStackElement_Hash.php',
'PPDStack_Hash' => __DIR__ . '/includes/parser/PPDStack_Hash.php',
'PPFrame' => __DIR__ . '/includes/parser/PPFrame.php',
'PPFrame_DOM' => __DIR__ . '/includes/parser/PPFrame_DOM.php',
'PPFrame_Hash' => __DIR__ . '/includes/parser/PPFrame_Hash.php',
'PPFuzzTest' => __DIR__ . '/maintenance/preprocessorFuzzTest.php',
'PPFuzzTester' => __DIR__ . '/maintenance/preprocessorFuzzTest.php',
'PPFuzzUser' => __DIR__ . '/maintenance/preprocessorFuzzTest.php',
'PPNode' => __DIR__ . '/includes/parser/PPNode.php',
'PPNode_DOM' => __DIR__ . '/includes/parser/PPNode_DOM.php',
'PPNode_Hash_Array' => __DIR__ . '/includes/parser/PPNode_Hash_Array.php',
'PPNode_Hash_Attr' => __DIR__ . '/includes/parser/PPNode_Hash_Attr.php',
'PPNode_Hash_Text' => __DIR__ . '/includes/parser/PPNode_Hash_Text.php',
'PPNode_Hash_Tree' => __DIR__ . '/includes/parser/PPNode_Hash_Tree.php',
'PPTemplateFrame_DOM' => __DIR__ . '/includes/parser/PPTemplateFrame_DOM.php',
'PPTemplateFrame_Hash' => __DIR__ . '/includes/parser/PPTemplateFrame_Hash.php',
'PackedHoverImageGallery' => __DIR__ . '/includes/gallery/PackedHoverImageGallery.php',
'PackedImageGallery' => __DIR__ . '/includes/gallery/PackedImageGallery.php',
@ -1076,7 +1234,6 @@ $wgAutoloadLocalClasses = [
'ParameterizedPassword' => __DIR__ . '/includes/password/ParameterizedPassword.php',
'Parser' => __DIR__ . '/includes/parser/Parser.php',
'ParserCache' => __DIR__ . '/includes/parser/ParserCache.php',
'ParserDiffTest' => __DIR__ . '/includes/parser/ParserDiffTest.php',
'ParserFactory' => __DIR__ . '/includes/parser/ParserFactory.php',
'ParserOptions' => __DIR__ . '/includes/parser/ParserOptions.php',
'ParserOutput' => __DIR__ . '/includes/parser/ParserOutput.php',
@ -1094,7 +1251,6 @@ $wgAutoloadLocalClasses = [
'PerRowAugmentor' => __DIR__ . '/includes/search/PerRowAugmentor.php',
'PermissionsError' => __DIR__ . '/includes/exception/PermissionsError.php',
'PhpHttpRequest' => __DIR__ . '/includes/http/PhpHttpRequest.php',
'PhpXmlBugTester' => __DIR__ . '/includes/installer/PhpXmlBugTester.php',
'Pingback' => __DIR__ . '/includes/Pingback.php',
'PoolCounter' => __DIR__ . '/includes/poolcounter/PoolCounter.php',
'PoolCounterNull' => __DIR__ . '/includes/poolcounter/PoolCounterNull.php',
@ -1106,7 +1262,6 @@ $wgAutoloadLocalClasses = [
'PopulateBacklinkNamespace' => __DIR__ . '/maintenance/populateBacklinkNamespace.php',
'PopulateCategory' => __DIR__ . '/maintenance/populateCategory.php',
'PopulateChangeTagDef' => __DIR__ . '/maintenance/populateChangeTagDef.php',
'PopulateContentModel' => __DIR__ . '/maintenance/populateContentModel.php',
'PopulateContentTables' => __DIR__ . '/maintenance/populateContentTables.php',
'PopulateExternallinksIndex60' => __DIR__ . '/maintenance/populateExternallinksIndex60.php',
'PopulateFilearchiveSha1' => __DIR__ . '/maintenance/populateFilearchiveSha1.php',
@ -1128,14 +1283,12 @@ $wgAutoloadLocalClasses = [
'PrefixingStatsdDataFactoryProxy' => __DIR__ . '/includes/libs/stats/PrefixingStatsdDataFactoryProxy.php',
'PreprocessDump' => __DIR__ . '/maintenance/preprocessDump.php',
'Preprocessor' => __DIR__ . '/includes/parser/Preprocessor.php',
'Preprocessor_DOM' => __DIR__ . '/includes/parser/Preprocessor_DOM.php',
'Preprocessor_Hash' => __DIR__ . '/includes/parser/Preprocessor_Hash.php',
'ProcessCacheLRU' => __DIR__ . '/includes/libs/ProcessCacheLRU.php',
'Processor' => __DIR__ . '/includes/registration/Processor.php',
'Profiler' => __DIR__ . '/includes/profiler/Profiler.php',
'ProfilerExcimer' => __DIR__ . '/includes/profiler/ProfilerExcimer.php',
'ProfilerOutput' => __DIR__ . '/includes/profiler/output/ProfilerOutput.php',
'ProfilerOutputDb' => __DIR__ . '/includes/profiler/output/ProfilerOutputDb.php',
'ProfilerOutputDump' => __DIR__ . '/includes/profiler/output/ProfilerOutputDump.php',
'ProfilerOutputStats' => __DIR__ . '/includes/profiler/output/ProfilerOutputStats.php',
'ProfilerOutputText' => __DIR__ . '/includes/profiler/output/ProfilerOutputText.php',
@ -1154,7 +1307,9 @@ $wgAutoloadLocalClasses = [
'PurgeAction' => __DIR__ . '/includes/actions/PurgeAction.php',
'PurgeChangedFiles' => __DIR__ . '/maintenance/purgeChangedFiles.php',
'PurgeChangedPages' => __DIR__ . '/maintenance/purgeChangedPages.php',
'PurgeExpiredBlocks' => __DIR__ . '/maintenance/purgeExpiredBlocks.php',
'PurgeExpiredUserrights' => __DIR__ . '/maintenance/purgeExpiredUserrights.php',
'PurgeExpiredWatchlistItems' => __DIR__ . '/maintenance/purgeExpiredWatchlistItems.php',
'PurgeJobUtils' => __DIR__ . '/includes/jobqueue/utils/PurgeJobUtils.php',
'PurgeList' => __DIR__ . '/maintenance/purgeList.php',
'PurgeModuleDeps' => __DIR__ . '/maintenance/purgeModuleDeps.php',
@ -1202,10 +1357,12 @@ $wgAutoloadLocalClasses = [
'RefreshImageMetadata' => __DIR__ . '/maintenance/refreshImageMetadata.php',
'RefreshLinks' => __DIR__ . '/maintenance/refreshLinks.php',
'RefreshLinksJob' => __DIR__ . '/includes/jobqueue/jobs/RefreshLinksJob.php',
'RefreshSecondaryDataUpdate' => __DIR__ . '/includes/deferred/RefreshSecondaryDataUpdate.php',
'RemexStripTagHandler' => __DIR__ . '/includes/parser/RemexStripTagHandler.php',
'RemoveInvalidEmails' => __DIR__ . '/maintenance/removeInvalidEmails.php',
'RemoveUnusedAccounts' => __DIR__ . '/maintenance/removeUnusedAccounts.php',
'RenameDbPrefix' => __DIR__ . '/maintenance/renameDbPrefix.php',
'RenameRestrictions' => __DIR__ . '/maintenance/renameRestrictions.php',
'RenderAction' => __DIR__ . '/includes/actions/RenderAction.php',
'ReplacementArray' => __DIR__ . '/includes/libs/ReplacementArray.php',
'ReplicatedBagOStuff' => __DIR__ . '/includes/libs/objectcache/ReplicatedBagOStuff.php',
@ -1228,6 +1385,7 @@ $wgAutoloadLocalClasses = [
'ResourceLoaderLanguageDataModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderLanguageDataModule.php',
'ResourceLoaderLessVarFileModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderLessVarFileModule.php',
'ResourceLoaderModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderModule.php',
'ResourceLoaderMwUrlModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderMwUrlModule.php',
'ResourceLoaderOOUIFileModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderOOUIFileModule.php',
'ResourceLoaderOOUIIconPackModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderOOUIIconPackModule.php',
'ResourceLoaderOOUIImageModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderOOUIImageModule.php',
@ -1240,7 +1398,6 @@ $wgAutoloadLocalClasses = [
'ResourceLoaderUserModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserModule.php',
'ResourceLoaderUserOptionsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserOptionsModule.php',
'ResourceLoaderUserStylesModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserStylesModule.php',
'ResourceLoaderUserTokensModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserTokensModule.php',
'ResourceLoaderWikiModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderWikiModule.php',
'RestbaseVirtualRESTService' => __DIR__ . '/includes/libs/virtualrest/RestbaseVirtualRESTService.php',
'ResultAugmentor' => __DIR__ . '/includes/search/ResultAugmentor.php',
@ -1309,9 +1466,10 @@ $wgAutoloadLocalClasses = [
'SearchUpdate' => __DIR__ . '/includes/deferred/SearchUpdate.php',
'SectionProfileCallback' => __DIR__ . '/includes/profiler/SectionProfileCallback.php',
'SectionProfiler' => __DIR__ . '/includes/profiler/SectionProfiler.php',
'SendPasswordResetEmailUpdate' => __DIR__ . '/includes/deferred/SendPasswordResetEmailUpdate.php',
'SerializedValueContainer' => __DIR__ . '/includes/libs/objectcache/serialized/SerializedValueContainer.php',
'SevenZipStream' => __DIR__ . '/maintenance/includes/SevenZipStream.php',
'ShiConverter' => __DIR__ . '/languages/classes/LanguageShi.php',
'ShiConverter' => __DIR__ . '/includes/language/converters/ShiConverter.php',
'ShowJobs' => __DIR__ . '/maintenance/showJobs.php',
'ShowSiteStats' => __DIR__ . '/maintenance/showSiteStats.php',
'Site' => __DIR__ . '/includes/site/Site.php',
@ -1326,11 +1484,10 @@ $wgAutoloadLocalClasses = [
'SiteStore' => __DIR__ . '/includes/site/SiteStore.php',
'Skin' => __DIR__ . '/includes/skins/Skin.php',
'SkinApi' => __DIR__ . '/includes/skins/SkinApi.php',
'SkinApiTemplate' => __DIR__ . '/includes/skins/SkinApiTemplate.php',
'SkinException' => __DIR__ . '/includes/skins/SkinException.php',
'SkinFactory' => __DIR__ . '/includes/skins/SkinFactory.php',
'SkinFallback' => __DIR__ . '/includes/skins/SkinFallback.php',
'SkinFallbackTemplate' => __DIR__ . '/includes/skins/SkinFallbackTemplate.php',
'SkinMustache' => __DIR__ . '/includes/skins/SkinMustache.php',
'SkinTemplate' => __DIR__ . '/includes/skins/SkinTemplate.php',
'SlideshowImageGallery' => __DIR__ . '/includes/gallery/SlideshowImageGallery.php',
'SlotDiffRenderer' => __DIR__ . '/includes/diff/SlotDiffRenderer.php',
@ -1362,6 +1519,7 @@ $wgAutoloadLocalClasses = [
'SpecialDeletedContributions' => __DIR__ . '/includes/specials/SpecialDeletedContributions.php',
'SpecialDiff' => __DIR__ . '/includes/specials/SpecialDiff.php',
'SpecialDoubleRedirects' => __DIR__ . '/includes/specials/SpecialDoubleRedirects.php',
'SpecialEditPage' => __DIR__ . '/includes/specials/SpecialEditPage.php',
'SpecialEditTags' => __DIR__ . '/includes/specials/SpecialEditTags.php',
'SpecialEditWatchlist' => __DIR__ . '/includes/specials/SpecialEditWatchlist.php',
'SpecialEmailInvalidate' => __DIR__ . '/includes/specials/SpecialEmailInvalidate.php',
@ -1410,6 +1568,8 @@ $wgAutoloadLocalClasses = [
'SpecialPageAction' => __DIR__ . '/includes/actions/SpecialPageAction.php',
'SpecialPageData' => __DIR__ . '/includes/specials/SpecialPageData.php',
'SpecialPageFactory' => __DIR__ . '/includes/specialpage/SpecialPageFactory_deprecated.php',
'SpecialPageHistory' => __DIR__ . '/includes/specials/SpecialPageHistory.php',
'SpecialPageInfo' => __DIR__ . '/includes/specials/SpecialPageInfo.php',
'SpecialPageLanguage' => __DIR__ . '/includes/specials/SpecialPageLanguage.php',
'SpecialPagesWithProp' => __DIR__ . '/includes/specials/SpecialPagesWithProp.php',
'SpecialPasswordPolicies' => __DIR__ . '/includes/specials/SpecialPasswordPolicies.php',
@ -1419,6 +1579,7 @@ $wgAutoloadLocalClasses = [
'SpecialPrefixindex' => __DIR__ . '/includes/specials/SpecialPrefixindex.php',
'SpecialProtectedpages' => __DIR__ . '/includes/specials/SpecialProtectedpages.php',
'SpecialProtectedtitles' => __DIR__ . '/includes/specials/SpecialProtectedtitles.php',
'SpecialPurge' => __DIR__ . '/includes/specials/SpecialPurge.php',
'SpecialRandomInCategory' => __DIR__ . '/includes/specials/SpecialRandomInCategory.php',
'SpecialRandomredirect' => __DIR__ . '/includes/specials/SpecialRandomredirect.php',
'SpecialRandomrootpage' => __DIR__ . '/includes/specials/SpecialRandomrootpage.php',
@ -1426,6 +1587,7 @@ $wgAutoloadLocalClasses = [
'SpecialRecentChangesLinked' => __DIR__ . '/includes/specials/SpecialRecentChangesLinked.php',
'SpecialRedirect' => __DIR__ . '/includes/specials/SpecialRedirect.php',
'SpecialRedirectToSpecial' => __DIR__ . '/includes/specialpage/SpecialRedirectToSpecial.php',
'SpecialRedirectWithAction' => __DIR__ . '/includes/specialpage/SpecialRedirectWithAction.php',
'SpecialRemoveCredentials' => __DIR__ . '/includes/specials/SpecialRemoveCredentials.php',
'SpecialResetTokens' => __DIR__ . '/includes/specials/SpecialResetTokens.php',
'SpecialRevisionDelete' => __DIR__ . '/includes/specials/SpecialRevisionDelete.php',
@ -1468,7 +1630,7 @@ $wgAutoloadLocalClasses = [
'SqliteUpdater' => __DIR__ . '/includes/installer/SqliteUpdater.php',
'SquidPurgeClient' => __DIR__ . '/includes/clientpool/SquidPurgeClient.php',
'SquidPurgeClientPool' => __DIR__ . '/includes/clientpool/SquidPurgeClientPool.php',
'SrConverter' => __DIR__ . '/languages/classes/LanguageSr.php',
'SrConverter' => __DIR__ . '/includes/language/converters/SrConverter.php',
'StatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php',
'StatsdAwareInterface' => __DIR__ . '/includes/libs/stats/StatsdAwareInterface.php',
'Status' => __DIR__ . '/includes/Status.php',
@ -1504,7 +1666,7 @@ $wgAutoloadLocalClasses = [
'TextPassDumper' => __DIR__ . '/maintenance/includes/TextPassDumper.php',
'TextSlotDiffRenderer' => __DIR__ . '/includes/diff/TextSlotDiffRenderer.php',
'TextStatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php',
'TgConverter' => __DIR__ . '/languages/classes/LanguageTg.php',
'TgConverter' => __DIR__ . '/includes/language/converters/TgConverter.php',
'ThrottledError' => __DIR__ . '/includes/exception/ThrottledError.php',
'ThumbnailImage' => __DIR__ . '/includes/media/ThumbnailImage.php',
'ThumbnailRenderJob' => __DIR__ . '/includes/jobqueue/jobs/ThumbnailRenderJob.php',
@ -1515,6 +1677,7 @@ $wgAutoloadLocalClasses = [
'TitleArray' => __DIR__ . '/includes/TitleArray.php',
'TitleArrayFromResult' => __DIR__ . '/includes/TitleArrayFromResult.php',
'TitleCleanup' => __DIR__ . '/maintenance/cleanupTitles.php',
'TitleFactory' => __DIR__ . '/includes/TitleFactory.php',
'TitleFormatter' => __DIR__ . '/includes/title/TitleFormatter.php',
'TitleParser' => __DIR__ . '/includes/title/TitleParser.php',
'TitlePrefixSearch' => __DIR__ . '/includes/search/TitlePrefixSearch.php',
@ -1527,6 +1690,7 @@ $wgAutoloadLocalClasses = [
'TransformParameterError' => __DIR__ . '/includes/media/TransformParameterError.php',
'TransformTooBigImageAreaError' => __DIR__ . '/includes/media/TransformTooBigImageAreaError.php',
'TransformationalImageHandler' => __DIR__ . '/includes/media/TransformationalImageHandler.php',
'TrivialLanguageConverter' => __DIR__ . '/includes/language/TrivialLanguageConverter.php',
'UDPRCFeedEngine' => __DIR__ . '/includes/rcfeed/UDPRCFeedEngine.php',
'UDPTransport' => __DIR__ . '/includes/libs/UDPTransport.php',
'UIDGenerator' => __DIR__ . '/includes/utils/UIDGenerator.php',
@ -1592,7 +1756,7 @@ $wgAutoloadLocalClasses = [
'UserRightsProxy' => __DIR__ . '/includes/user/UserRightsProxy.php',
'UserrightsPage' => __DIR__ . '/includes/specials/SpecialUserrights.php',
'UsersPager' => __DIR__ . '/includes/specials/pagers/UsersPager.php',
'UzConverter' => __DIR__ . '/languages/classes/LanguageUz.php',
'UzConverter' => __DIR__ . '/includes/language/converters/UzConverter.php',
'VFormHTMLForm' => __DIR__ . '/includes/htmlform/VFormHTMLForm.php',
'ValidateRegistrationFile' => __DIR__ . '/maintenance/validateRegistrationFile.php',
'VersionChecker' => __DIR__ . '/includes/registration/VersionChecker.php',
@ -1600,6 +1764,7 @@ $wgAutoloadLocalClasses = [
'ViewCLI' => __DIR__ . '/maintenance/view.php',
'VirtualRESTService' => __DIR__ . '/includes/libs/virtualrest/VirtualRESTService.php',
'VirtualRESTServiceClient' => __DIR__ . '/includes/libs/virtualrest/VirtualRESTServiceClient.php',
'VueComponentParser' => __DIR__ . '/includes/resourceloader/VueComponentParser.php',
'WANCacheReapUpdate' => __DIR__ . '/includes/deferred/WANCacheReapUpdate.php',
'WANObjectCache' => __DIR__ . '/includes/libs/objectcache/wancache/WANObjectCache.php',
'WANObjectCacheReaper' => __DIR__ . '/includes/libs/objectcache/wancache/WANObjectCacheReaper.php',
@ -1612,6 +1777,7 @@ $wgAutoloadLocalClasses = [
'WatchedItemQueryServiceExtension' => __DIR__ . '/includes/watcheditem/WatchedItemQueryServiceExtension.php',
'WatchedItemStore' => __DIR__ . '/includes/watcheditem/WatchedItemStore.php',
'WatchedItemStoreInterface' => __DIR__ . '/includes/watcheditem/WatchedItemStoreInterface.php',
'WatchlistExpiryJob' => __DIR__ . '/includes/jobqueue/jobs/WatchlistExpiryJob.php',
'WebInstaller' => __DIR__ . '/includes/installer/WebInstaller.php',
'WebInstallerComplete' => __DIR__ . '/includes/installer/WebInstallerComplete.php',
'WebInstallerCopying' => __DIR__ . '/includes/installer/WebInstallerCopying.php',
@ -1625,7 +1791,6 @@ $wgAutoloadLocalClasses = [
'WebInstallerOptions' => __DIR__ . '/includes/installer/WebInstallerOptions.php',
'WebInstallerOutput' => __DIR__ . '/includes/installer/WebInstallerOutput.php',
'WebInstallerPage' => __DIR__ . '/includes/installer/WebInstallerPage.php',
'WebInstallerReadme' => __DIR__ . '/includes/installer/WebInstallerReadme.php',
'WebInstallerReleaseNotes' => __DIR__ . '/includes/installer/WebInstallerReleaseNotes.php',
'WebInstallerRestart' => __DIR__ . '/includes/installer/WebInstallerRestart.php',
'WebInstallerUpgrade' => __DIR__ . '/includes/installer/WebInstallerUpgrade.php',
@ -1645,8 +1810,14 @@ $wgAutoloadLocalClasses = [
'WikiRevision' => __DIR__ . '/includes/import/WikiRevision.php',
'WikiStatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php',
'WikiTextStructure' => __DIR__ . '/includes/content/WikiTextStructure.php',
'Wikimedia\\Http\\HttpAcceptNegotiator' => __DIR__ . '/includes/libs/http/HttpAcceptNegotiator.php',
'Wikimedia\\Http\\HttpAcceptParser' => __DIR__ . '/includes/libs/http/HttpAcceptParser.php',
'Wikimedia\\DependencyStore\\DependencyStore' => __DIR__ . '/includes/resourceloader/dependencystore/DependencyStore.php',
'Wikimedia\\DependencyStore\\DependencyStoreException' => __DIR__ . '/includes/resourceloader/dependencystore/DependencyStoreException.php',
'Wikimedia\\DependencyStore\\KeyValueDependencyStore' => __DIR__ . '/includes/resourceloader/dependencystore/KeyValueDependencyStore.php',
'Wikimedia\\DependencyStore\\SqlModuleDependencyStore' => __DIR__ . '/includes/resourceloader/dependencystore/SqlModuleDependencyStore.php',
'Wikimedia\\LightweightObjectStore\\ExpirationAwareness' => __DIR__ . '/includes/libs/objectcache/utils/ExpirationAwareness.php',
'Wikimedia\\LightweightObjectStore\\StorageAwareness' => __DIR__ . '/includes/libs/objectcache/utils/StorageAwareness.php',
'Wikimedia\\Mime\\MimeMap' => __DIR__ . '/includes/libs/mime/MimeMap.php',
'Wikimedia\\Mime\\MimeMapMinimal' => __DIR__ . '/includes/libs/mime/MimeMapMinimal.php',
'Wikimedia\\Rdbms\\AtomicSectionIdentifier' => __DIR__ . '/includes/libs/rdbms/database/utils/AtomicSectionIdentifier.php',
'Wikimedia\\Rdbms\\Blob' => __DIR__ . '/includes/libs/rdbms/encasing/Blob.php',
'Wikimedia\\Rdbms\\ChronologyProtector' => __DIR__ . '/includes/libs/rdbms/ChronologyProtector.php',
@ -1673,6 +1844,8 @@ $wgAutoloadLocalClasses = [
'Wikimedia\\Rdbms\\DatabaseMysqli' => __DIR__ . '/includes/libs/rdbms/database/DatabaseMysqli.php',
'Wikimedia\\Rdbms\\DatabasePostgres' => __DIR__ . '/includes/libs/rdbms/database/DatabasePostgres.php',
'Wikimedia\\Rdbms\\DatabaseSqlite' => __DIR__ . '/includes/libs/rdbms/database/DatabaseSqlite.php',
'Wikimedia\\Rdbms\\DoctrineSchemaBuilder' => __DIR__ . '/includes/libs/rdbms/database/DoctrineSchemaBuilder.php',
'Wikimedia\\Rdbms\\DoctrineSchemaBuilderFactory' => __DIR__ . '/includes/libs/rdbms/database/DoctrineSchemaBuilderFactory.php',
'Wikimedia\\Rdbms\\FakeResultWrapper' => __DIR__ . '/includes/libs/rdbms/database/resultwrapper/FakeResultWrapper.php',
'Wikimedia\\Rdbms\\Field' => __DIR__ . '/includes/libs/rdbms/field/Field.php',
'Wikimedia\\Rdbms\\GeneralizedSql' => __DIR__ . '/includes/libs/rdbms/database/utils/GeneralizedSql.php',
@ -1683,6 +1856,8 @@ $wgAutoloadLocalClasses = [
'Wikimedia\\Rdbms\\ILoadMonitor' => __DIR__ . '/includes/libs/rdbms/loadmonitor/ILoadMonitor.php',
'Wikimedia\\Rdbms\\IMaintainableDatabase' => __DIR__ . '/includes/libs/rdbms/database/IMaintainableDatabase.php',
'Wikimedia\\Rdbms\\IResultWrapper' => __DIR__ . '/includes/libs/rdbms/database/resultwrapper/IResultWrapper.php',
'Wikimedia\\Rdbms\\JoinGroup' => __DIR__ . '/includes/libs/rdbms/querybuilder/JoinGroup.php',
'Wikimedia\\Rdbms\\JoinGroupBase' => __DIR__ . '/includes/libs/rdbms/querybuilder/JoinGroupBase.php',
'Wikimedia\\Rdbms\\LBFactory' => __DIR__ . '/includes/libs/rdbms/lbfactory/LBFactory.php',
'Wikimedia\\Rdbms\\LBFactoryMulti' => __DIR__ . '/includes/libs/rdbms/lbfactory/LBFactoryMulti.php',
'Wikimedia\\Rdbms\\LBFactorySimple' => __DIR__ . '/includes/libs/rdbms/lbfactory/LBFactorySimple.php',
@ -1701,10 +1876,11 @@ $wgAutoloadLocalClasses = [
'Wikimedia\\Rdbms\\PostgresField' => __DIR__ . '/includes/libs/rdbms/field/PostgresField.php',
'Wikimedia\\Rdbms\\ResultWrapper' => __DIR__ . '/includes/libs/rdbms/database/resultwrapper/ResultWrapper.php',
'Wikimedia\\Rdbms\\SQLiteField' => __DIR__ . '/includes/libs/rdbms/field/SQLiteField.php',
'Wikimedia\\Rdbms\\SchemaBuilder' => __DIR__ . '/includes/libs/rdbms/database/SchemaBuilder.php',
'Wikimedia\\Rdbms\\SelectQueryBuilder' => __DIR__ . '/includes/libs/rdbms/querybuilder/SelectQueryBuilder.php',
'Wikimedia\\Rdbms\\SessionConsistentConnectionManager' => __DIR__ . '/includes/libs/rdbms/connectionmanager/SessionConsistentConnectionManager.php',
'Wikimedia\\Rdbms\\Subquery' => __DIR__ . '/includes/libs/rdbms/encasing/Subquery.php',
'Wikimedia\\Rdbms\\TransactionProfiler' => __DIR__ . '/includes/libs/rdbms/TransactionProfiler.php',
'Wikimedia\\StaticArrayWriter' => __DIR__ . '/includes/libs/StaticArrayWriter.php',
'WikitextContent' => __DIR__ . '/includes/content/WikitextContent.php',
'WikitextContentHandler' => __DIR__ . '/includes/content/WikitextContentHandler.php',
'WikitextLogFormatter' => __DIR__ . '/includes/logging/WikitextLogFormatter.php',
@ -1715,16 +1891,15 @@ $wgAutoloadLocalClasses = [
'XMLRCFeedFormatter' => __DIR__ . '/includes/rcfeed/XMLRCFeedFormatter.php',
'Xhprof' => __DIR__ . '/includes/libs/Xhprof.php',
'XhprofData' => __DIR__ . '/includes/libs/XhprofData.php',
'Xml' => __DIR__ . '/includes/Xml.php',
'Xml' => __DIR__ . '/includes/xml/Xml.php',
'XmlDumpWriter' => __DIR__ . '/includes/export/XmlDumpWriter.php',
'XmlJsCode' => __DIR__ . '/includes/XmlJsCode.php',
'XmlSelect' => __DIR__ . '/includes/XmlSelect.php',
'XmlJsCode' => __DIR__ . '/includes/xml/XmlJsCode.php',
'XmlSelect' => __DIR__ . '/includes/xml/XmlSelect.php',
'XmlTypeCheck' => __DIR__ . '/includes/libs/mime/XmlTypeCheck.php',
'ZhConverter' => __DIR__ . '/languages/classes/LanguageZh.php',
'ZhConverter' => __DIR__ . '/includes/language/converters/ZhConverter.php',
'ZipDirectoryReader' => __DIR__ . '/includes/utils/ZipDirectoryReader.php',
'ZipDirectoryReaderError' => __DIR__ . '/includes/utils/ZipDirectoryReaderError.php',
'concatenatedgziphistoryblob' => __DIR__ . '/includes/historyblob/ConcatenatedGzipHistoryBlob.php',
'historyblobcurstub' => __DIR__ . '/includes/historyblob/HistoryBlobCurStub.php',
'historyblobstub' => __DIR__ . '/includes/historyblob/HistoryBlobStub.php',
'profile_point' => __DIR__ . '/profileinfo.php',
];

View File

@ -16,8 +16,9 @@
"irc": "irc://irc.freenode.net/mediawiki",
"wiki": "https://www.mediawiki.org/"
},
"prefer-stable": true,
"require": {
"composer/semver": "1.5.0",
"composer/semver": "1.5.1",
"cssjanus/cssjanus": "1.3.0",
"ext-ctype": "*",
"ext-dom": "*",
@ -26,60 +27,66 @@
"ext-json": "*",
"ext-mbstring": "*",
"ext-xml": "*",
"guzzlehttp/guzzle": "6.3.3",
"guzzlehttp/guzzle": "6.5.4",
"liuggio/statsd-php-client": "1.0.18",
"oojs/oojs-ui": "0.34.1",
"oojs/oojs-ui": "0.39.3",
"pear/mail": "1.4.1",
"pear/mail_mime": "1.10.2",
"pear/net_smtp": "1.8.1",
"php": ">=7.2.9",
"pear/mail_mime": "1.10.8",
"pear/net_smtp": "1.9.1",
"php": ">=7.3.19",
"psr/container": "1.0.0",
"psr/log": "1.0.2",
"wikimedia/assert": "0.2.2",
"psr/log": "1.1.3",
"ralouphie/getallheaders": "3.0.3",
"wikimedia/assert": "0.5.0",
"wikimedia/at-ease": "2.0.0",
"wikimedia/base-convert": "2.0.0",
"wikimedia/base-convert": "2.0.1",
"wikimedia/cdb": "1.4.1",
"wikimedia/cldr-plural-rule-parser": "1.0.0",
"wikimedia/common-passwords": "0.2.0",
"wikimedia/composer-merge-plugin": "1.4.1",
"wikimedia/html-formatter": "1.0.2",
"wikimedia/ip-set": "2.1.0",
"wikimedia/less.php": "1.8.0",
"wikimedia/ip-utils": "1.0.0",
"wikimedia/less.php": "3.0.0",
"wikimedia/object-factory": "2.1.0",
"wikimedia/password-blacklist": "0.1.4",
"wikimedia/parsoid": "0.12.0",
"wikimedia/php-session-serializer": "1.0.7",
"wikimedia/purtle": "1.0.7",
"wikimedia/relpath": "2.1.1",
"wikimedia/remex-html": "2.1.0",
"wikimedia/remex-html": "2.2.0",
"wikimedia/running-stat": "1.2.1",
"wikimedia/scoped-callback": "3.0.0",
"wikimedia/services": "2.0.1",
"wikimedia/utfnormal": "2.0.0",
"wikimedia/timestamp": "3.0.0",
"wikimedia/wait-condition-loop": "1.0.1",
"wikimedia/wrappedstring": "3.0.1",
"wikimedia/xmp-reader": "0.6.3",
"zordius/lightncandy": "0.23"
"wikimedia/wrappedstring": "3.2.0",
"wikimedia/xmp-reader": "0.7.0",
"zordius/lightncandy": "1.2.5"
},
"require-dev": {
"cache/integration-tests": "0.16.0",
"composer/spdx-licenses": "1.5.1",
"composer/spdx-licenses": "1.5.3",
"doctrine/dbal": "2.10.2",
"doctrine/sql-formatter": "1.1.0",
"giorgiosironi/eris": "^0.10.0",
"hamcrest/hamcrest-php": "^2.0",
"jakub-onderka/php-console-highlighter": "0.3.2",
"jakub-onderka/php-parallel-lint": "0.9.2",
"johnkary/phpunit-speedtrap": "^3.1",
"justinrainbow/json-schema": "~5.2",
"mediawiki/mediawiki-codesniffer": "28.0.0",
"monolog/monolog": "~1.24.0",
"nikic/php-parser": "3.1.5",
"seld/jsonlint": "1.7.1",
"mediawiki/mediawiki-codesniffer": "31.0.0",
"mediawiki/mediawiki-phan-config": "0.10.2",
"monolog/monolog": "~1.25.3",
"nikic/php-parser": "4.4.0",
"nmred/kafka-php": "0.1.5",
"phpunit/phpunit": "4.8.36 || ^6.5",
"psy/psysh": "0.9.9",
"php-parallel-lint/php-console-highlighter": "0.5",
"php-parallel-lint/php-parallel-lint": "1.2.0",
"phpunit/phpunit": "^8.5",
"pimple/pimple": "3.3.0",
"psy/psysh": "0.10.4",
"seld/jsonlint": "1.7.1",
"symfony/yaml": "~3.4|~4.3|~5.0.5",
"wikimedia/avro": "1.9.0",
"wikimedia/testing-access-wrapper": "~1.0",
"wmde/hamcrest-html-matchers": "^0.1.0",
"mediawiki/mediawiki-phan-config": "0.7.1",
"symfony/yaml": "3.4.28",
"johnkary/phpunit-speedtrap": "^1.0 | ^2.0"
"wmde/hamcrest-html-matchers": "^0.1.0"
},
"replace": {
"symfony/polyfill-ctype": "1.99",
@ -111,7 +118,7 @@
"scripts": {
"lint": "parallel-lint --exclude vendor",
"phpcs": "phpcs -p -s",
"fix": "phpcbf",
"fix": "phpcbf -p",
"pre-install-cmd": "ComposerHookHandler::onPreInstall",
"pre-update-cmd": "ComposerHookHandler::onPreUpdate",
"post-install-cmd": "ComposerVendorHtaccessCreator::onEvent",

33
docker-compose.yml Normal file
View File

@ -0,0 +1,33 @@
# Please see DEVELOPERS.md for help
#
# Contributions to this file are welcome but please note that this file is
# minimal by design, with the idea to make it easily extensible via
# docker-compose.override.yml. For help with doing that, please see
# DEVELOPERS.md
version: '3.7'
services:
mediawiki:
image: docker-registry.wikimedia.org/dev/stretch-php72-fpm-apache2-xdebug:0.4.0
ports:
- "${MW_DOCKER_PORT:-8080}:8080"
volumes:
- ./:/var/www/html:cached
environment:
COMPOSER_CACHE_DIR: '/var/www/html/cache/composer'
MW_SERVER: 'http://localhost:${MW_DOCKER_PORT:-8080}'
MW_SCRIPT_PATH: ''
MW_DBPATH: '/var/www/html/cache/sqlite'
MW_DBTYPE: 'sqlite'
MW_LANG: 'en'
MW_USER: 'admin'
MW_PASS: 'dockerpass'
MW_SITENAME: 'MediaWiki'
MW_LOG_DIR: /var/www/html/cache
XDEBUG_CONFIG: ${XDEBUG_CONFIG}
mediawiki-jobrunner:
image: docker-registry.wikimedia.org/dev/stretch-php72-jobrunner:0.0.1
volumes:
- ./:/var/www/html:cached
environment:
MW_LOG_DIR: /var/www/html/cache
MW_INSTALL_PATH: /var/www/html

250
docs/Hooks.md Normal file
View File

@ -0,0 +1,250 @@
Hooks
=====
## Introduction
Hooks allow MediaWiki Core to call extensions or allow one extension to call
another extension. For more information and a list of hooks, see
https://www.mediawiki.org/wiki/Manual:Hooks
Starting in MediaWiki 1.35, each hook called by MediaWiki Core has an
associated interface with a single method. To call the hook, obtain a "hook
runner" object, which implements the relevant interface, and call the relevant
method. To handle a hook event in an extension, create a handler object which
implements the interface.
The name of the interface is the name of the hook with "Hook" added to the end.
Interfaces are typically placed in the namespace of their primary caller.
The method name for the hook is the name of the hook, prefixed with "on".
Several hooks had colons in their name, which are invalid in an interface or
method name. These hooks have interfaces and method names in which the colons
are replaced with underscores.
For example, if the hook is called `Mash`, we might have the interface:
interface MashHook {
public function onMash( $banana );
}
Hooks can be defined and called by extensions. The extension should define a
hook interface for each hook, as described above.
## HookContainer
HookContainer is a service which is responsible for maintaining a list of hook
handlers and calling those handlers when requested. HookContainer is not aware
of hook interfaces or parameter types.
HookContainer provides hook metadata. For example, `isRegistered()` tells us
whether there are any handlers for a given hook event.
A HookContainer instance can be obtained from the global service locator with
MediaWikiServices::getHookContainer(). When implementing a service that needs
to call a hook, a HookContainer object should be passed to the constructor of
the service.
## Hook runner classes
A hook runner is a class which implements hook interfaces, proxying the calls
to `HookContainer::run()`.
MediaWiki has two hook runner classes: HookRunner and ApiHookRunner.
ApiHookRunner has proxy methods for all hooks which are called by the Action
API. HookRunner has proxy methods for all hooks which are called by other parts
of Core. Some hooks are implemented in both classes.
Extensions which call hooks should create their own hook runner class, by
analogy with the ones in Core. Hook runner classes are effectively internal
to the module which calls the relevant hooks. Reorganisation of the hook
calling code may lead to methods being removed from hook runner classes. Thus,
it is safer for extensions to define their own hook runner classes even if
they are calling Core hooks.
New code should typically be written in a service which takes a HookContainer
as a constructor parameter. However, for the convenience of existing static
functions in MediaWiki Core, `Hooks::runner()` may be used to obtain a
HookRunner instance. This is equivalent to
new HookRunner( MediaWikiServices::getInstance()->getHookContainer() )
For example, to call the hook `Mash`, as defined above, in static code:
Hooks::runner()->onMash( $banana );
## How to handle a hook event in an extension
In extension.json, there is a new attribute called `HookHandlers`. This is
an object mapping the handler name to an ObjectFactory specification describing
how to create the handler object. The specification will typically have a
`class` member with the name of the handler class. For example, in an extension
called `FoodProcessor`, we may have:
"HookHandlers": {
"main": {
"class": "MediaWiki\\Extension\\FoodProcessor\\HookHandler"
}
}
Then in the Hooks attribute, instead of a function name, the value will be the
handler name:
"Hooks": {
"Mash": "main"
}
Or more explicitly, by using an object instead of a string for the handler:
"Hooks": {
"Mash": {
"handler": "main"
}
}
Note that while your HookHandler class will implement an interface that ends
with the word "Hook", in `extension.json` you should omit the word "Hook"
from the key in the `Hooks` definition. For example, in the definitions above,
the key must be "Mash", not "MashHook".
Then the extension will define a handler class:
namespace MediaWiki\Extension\FoodProcessor;
class HookHandler implements MashHook {
public function onMash( $banana ) {
// Implementation goes here
}
}
## Returning and aborting
If a hook handler returns false, HookContainer will stop iterating through the
list of handlers and will immediately return false.
If a hook handler returns true, or if there is no return value (causing it to
effectively return null), then HookContainer will continue to call any other
remaining handlers. Eventually HookContainer::run() will return true.
If there were no registered handlers, HookContainer::run() will return true.
Some hooks are declared to be "not abortable". If a handler for a non-abortable
hook returns false, an exception will be thrown. A hook is declared to be not
abortable by passing `[ "abortable" => false ]` in the $options parameter to
HookContainer::run().
Aborting is properly used to enforce a convention that only one extension
may handle a given hook call.
Aborting is sometimes used as a generic return value, to indicate that the
caller should stop performing some action.
Most hook callers do not check the return value from HookContainer::run() and
there is no real concept of aborting. The only effect of returning `false` from
a handler of these hooks is to break other extensions.
Theoretically, extensions which are registered first in LocalSettings.php will
be called first, and thus will have the first opportunity to abort a hook call.
This behaviour should not be relied upon. In the new hook system, handlers
registered in the legacy way are called first, before handlers registered in
the new way.
## Parameters passed by reference
The typical way for a handler to return data to the caller is by modifying a
parameter which was passed by reference. This is sometimes called "replacement".
Reference parameters were somewhat overused in early versions of MediaWiki. You
may find that some parameters passed by reference cannot reasonably be modified.
Replacement either has no effect on the caller or would cause unexpected or
inconsistent effects. Handlers should generally only replace a parameter when it
is clear from the documentation that replacement is expected.
## How to define a new hook
* Create a hook interface, typically in a subnamespace called `Hook` relative
to the caller namespace. For example, if the caller is in a namespace called
`MediaWiki\Foo`, the hook interface might be placed in `MediaWiki\Foo\Hook`.
* Add an implementation to the relevant HookRunner class.
## Hook deprecation
Core hooks are deprecated by adding them to an array in the DeprecatedHooks
class. Hooks declared in extensions may be deprecated by listing them in the
`DeprecatedHooks` attribute:
"DeprecatedHooks": {
"Mash": {
"deprecatedVersion": "2.0",
"component": "FoodProcessor"
}
}
If the `component` is not specified, it defaults to the name of the extension.
The hook interface should be marked as deprecated by adding @deprecated to the
interface doc comment. The interface doc comment is a better place for
@deprecated than the method doc comment, because this causes the interface to
be deprecated for implementation. Deprecating the method only causes calling
to be deprecated, not handling.
Deprecating a hook in this way activates a migration system called
**call filtering**. Extensions opt in to call filtering of deprecated hooks by
**acknowledging** deprecation. An extension acknowledges deprecation with the
`deprecated` parameter in the `Hooks` attribute:
"Hooks": {
"Mash": {
"handler": "main",
"deprecated": "true"
}
}
If deprecation is acknowledged by the extension:
* If MediaWiki knows that the hook is deprecated, the handler will not be
called. The call to the handler is filtered.
* If MediaWiki does not have the hook in its list of deprecated hooks, the
handler will be called anyway.
Deprecation acknowledgement is a way for the extension to say that it has made
some other arrangement for implementing the relevant functionality and does
not need the handler for the deprecated hook to be called.
### Call filtering example
Suppose the hook `Mash` is deprecated in MediaWiki 2.0, and is replaced by a
new one called `Slice`. In our example extension FoodProcessor 1.0, the
`Mash` hook is handled. In FoodProcessor 2.0, both `Mash` and `Slice` have
handlers, but deprecation of `Mash` is acknowledged. Thus:
* With MediaWiki 2.0 and FoodProcessor 1.0, `onMash` is called but raises a
deprecation warning.
* With MediaWiki 2.0 and FoodProcessor 2.0, `onMash` is filtered, and `onSlice`
is called.
* With MediaWiki 1.0 and FoodProcessor 2.0, `onMash` is called, since it is not
yet deprecated in Core. `onSlice` is not called since it does not yet exist
in Core.
So the call filtering system provides both forwards and backwards compatibility.
### Silent deprecation
Developers sometimes use two stages of deprecation: "soft" deprecation in which
the deprecated entity is merely discouraged in documentation, and "hard"
deprecation in which a warning is raised. When you soft-deprecate a hook, it is
important to register it as deprecated so that call filtering is activated.
Activating call filtering simplifies the task of migrating extensions to the
new hook.
To deprecate a hook without raising deprecation warnings, use the "silent" flag:
"DeprecatedHooks": {
"Mash": {
"deprecatedVersion": "2.0",
"component": "FoodProcessor",
"silent": true
}
}
As with hard deprecation, @deprecated should be added to the interface.

316
docs/Injection.md Normal file
View File

@ -0,0 +1,316 @@
Dependency Injection
=======
This is an overview of how MediaWiki makes use of dependency injection.
The design described here grew from the discussion of RFC
[T384](https://phabricator.wikimedia.org/T384).
The term "dependency injection" (DI) refers to a pattern on object oriented
programming that tries to improve modularity by reducing strong coupling
between classes. In practical terms, this means that anything an object needs
to operate should be injected from the outside, the object itself should only
know narrow interfaces, no concrete implementation of the logic it relies on.
The requirement to inject everything typically results in an architecture that
based on two main types of objects: simple value objects with no business logic
(and often immutable), and essentially stateless service objects that use
other service objects to operate on the value objects.
As of the beginning of 2016 (MW version 1.27), MediaWiki is only starting to
use the DI approach. Much of the code still relies on global state or direct
instantiation, resulting in a highly cyclical dependency graph.
## Overview
The heart of the DI in MediaWiki is the central service locator,
MediaWikiServices, which acts as the top level factory for services in
MediaWiki. `MediaWikiServices::getInstance()` returns the default service
locator instance, which can be used to gain access to default instances of
various services. MediaWikiServices however also allows new services to be
defined and default services to be redefined. Services are defined or
redefined by providing a callback function, the "instantiator" function,
that will return a new instance of the service.
When `MediaWikiServices::getInstance()` is first called, it will create an
instance of MediaWikiServices and populate it with the services defined
in the files listed by `$wgServiceWiringFiles`, thereby "bootstrapping" the
DI framework. Per default, `$wgServiceWiringFiles` lists
includes/ServiceWiring.php, which defines all default service
implementations, and specifies how they depend on each other ("wiring").
When a new service is added to MediaWiki core, an instantiator function
that will create the appropriate default instance for that service must
be added to ServiceWiring.php. This makes the service available through
the generic getService() method on the service locator returned by
`MediaWikiServices::getInstance()`.
Extensions can add their own wiring files to `$wgServiceWiringFiles`, in order
to define their own service. Extensions may also use the 'MediaWikiServices'
hook to define or redefined services by calling methods on the default
MediaWikiServices instance.
It should be noted that the term "service locator" is often used to refer to a
top level factory that is accessed directly, throughout the code, to avoid
explicit dependency injection. In contrast, the term "DI container" is often
used to describe a top level factory that is only accessed when services
are created. We use the term "service locator" for the top level factory
because it is more descriptive than "DI container", even though application
logic is strongly discouraged from accessing MediaWikiServices directly.
`MediaWikiServices::getInstance()` should ideally be accessed only in "static
entry points" such as hook handler functions. See "Migration" below.
## Service Reset
Services get their configuration injected, and changes to global
configuration variables will not have any effect on services that were already
instantiated. This would typically be the case for low level services like
the ConfigFactory or the ObjectCacheManager, which are used during extension
registration. To address this issue, Setup.php resets the global service
locator instance by calling `MediaWikiServices::resetGlobalInstance()` once
configuration and extension registration is complete.
Note that "unmanaged" legacy services services that manage their own singleton
must not keep references to services managed by MediaWikiServices, to allow a
clean reset. After the global MediaWikiServices instance got reset, any such
references would be stale, and using a stale service will result in an error.
Services should either have all dependencies injected and be themselves managed
by MediaWikiServices, or they should use the Service Locator pattern, accessing
service instances via the global MediaWikiServices instance state when needed.
This ensures that no stale service references remain after a reset.
## Configuration
When the default MediaWikiServices instance is created, a Config object is
provided to the constructor. This Config object represents the "bootstrap"
configuration which will become available as the 'BootstrapConfig' service.
As of MW 1.27, the bootstrap config is a GlobalVarConfig object providing
access to the $wgXxx configuration variables.
The bootstrap config is then used to construct a 'ConfigFactory' service,
which in turn is used to construct the 'MainConfig' service. Application
logic should use the 'MainConfig' service (or a more specific configuration
object). 'BootstrapConfig' should only be used for bootstrapping basic
services that are needed to load the 'MainConfig'.
Note: Several well known services in MediaWiki core act as factories
themselves, e.g. ApiModuleManager, ObjectCache, SpecialPageFactory, etc.
The registries these factories are based on are currently managed as part of
the configuration. This may however change in the future.
## Migration
This section provides some recipes for improving code modularity by reducing
strong coupling. The dependency injection mechanism described above is an
essential tool in this effort.
### Migrate access to global service instances and config variables
Assume `Foo` is a class that uses the `$wgScriptPath` global and calls
`wfGetDB()` to get a database connection, in non-static methods.
* Add `$scriptPath` as a constructor parameter and use `$this->scriptPath`
instead of `$wgScriptPath`.
* Add LoadBalancer `$dbLoadBalancer` as a constructor parameter. Use
`$this->dbLoadBalancer->getConnection()` instead of `wfGetDB()`.
* Any code that calls `Foo`'s constructor would now need to provide the
`$scriptPath` and `$dbLoadBalancer`. To avoid this, avoid direct instantiation
of services all together - see below.
### Migrate services with multiple configuration variables
When a service needs multiple configuration globals injected, a ServiceOptions
object is commonly used with the service class defining a public constant
(usually `CONSTRUCTOR_OPTIONS`) with an array of settings that the class needs
access to.
```php
<?php
class DemoService {
public const CONSTRUCTOR_OPTIONS = [
'Foo',
'Bar'
];
private $options;
public function __construct( ServiceOptions $options ) {
// ServiceOptions::assertRequiredOptions ensures that all of the
// settings listed in CONSTRUCTOR_OPTIONS are available
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
$this->options = $options;
// $wgFoo is now available with $this->options->get( 'Foo' )
// $wgBar is now available with $this->options->get( 'Bar' )
}
}
```
ServiceOptions objects are constructed within ServiceWiring.php and can also
be created in tests.
```php
'DemoService' => function ( MediaWikiServices $services ) : DemoService {
return new DemoService(
new ServiceOptions(
DemoService::CONSTRUCTOR_OPTIONS,
$services->getMainConfig()
)
);
},
```
### Migrate class-level singleton getters
Assume class `Foo` has mostly non-static methods, and provides a static
`getInstance()` method that returns a singleton (or default instance).
* Add an instantiator function for `Foo` into ServiceWiring.php. The
instantiator would do exactly what `Foo::getInstance()` did. However, it
should replace any access to global state with calls to `$services->getXxx()`
to get a service, or `$services->getMainConfig()->get()` to get a
configuration setting.
* Add a `getFoo()` method to MediaWikiServices. Don't forget to add the
appropriate test cases in MediaWikiServicesTest.
* Turn `Foo::getInstance()` into a deprecated alias for
`MediaWikiServices::getInstance()->getFoo()`. Change all calls to
`Foo::getInstance()` to use injection (see above).
### Migrate direct service instantiation
Assume class `Bar` calls `new Foo()`.
* Add an instantiator function for `Foo` into ServiceWiring.php and add a
`getFoo()` method to MediaWikiServices. Don't forget to add the appropriate
test cases in MediaWikiServicesTest.
* In the instantiator, replace any access to global state with calls
to `$services->getXxx()` to get a service, or
`$services->getMainConfig()->get()` to get a configuration setting.
* The code in `Bar` that calls `Foo`'s constructor should be changed to have a
`Foo` instance injected; Eventually, the only code that instantiates `Foo` is
the instantiator in ServiceWiring.php.
* As an intermediate step, `Bar`'s constructor could initialize the `$foo`
member variable by calling `MediaWikiServices::getInstance()->getFoo()`. This
is acceptable as a stepping stone, but should be replaced by proper injection
via a constructor argument. Do not however inject the MediaWikiServices
object!
### Migrate parameterized helper instantiation
Assume class `Bar` creates some helper object by calling `new Foo( $x )`,
and `Foo` uses a global singleton of the `Xyzzy` service.
* Define a `FooFactory` class (or a `FooFactory` interface along with a
`MyFooFactory` implementation). `FooFactory` defines the method
`newFoo( $x )` or `getFoo( $x )`, depending on the desired semantics (`newFoo`
would guarantee a fresh instance). When Foo gets refactored to have `Xyzzy`
injected, `FooFactory` will need a `Xyzzy` instance, so `newFoo()` can pass it
to `new Foo()`.
* Add an instantiator function for FooFactory into ServiceWiring.php and add a
getFooFactory() method to MediaWikiServices. Don't forget to add the
appropriate test cases in MediaWikiServicesTest.
* The code in Bar that calls Foo's constructor should be changed to have a
FooFactory instance injected; Eventually, the only code that instantiates
Foo are implementations of FooFactory, and the only code that instantiates
FooFactory is the instantiator in ServiceWiring.php.
* As an intermediate step, Bar's constructor could initialize the $fooFactory
member variable by calling `MediaWikiServices::getInstance()->getFooFactory()`.
This is acceptable as a stepping stone, but should be replaced by proper
injection via a constructor argument. Do not however inject the
MediaWikiServices object!
### Migrate a handler registry
Assume class `Bar` calls `FooRegistry::getFoo( $x )` to get a specialized `Foo`
instance for handling `$x`.
* Turn `getFoo` into a non-static method.
* Add an instantiator function for `FooRegistry` into ServiceWiring.php and add
a `getFooRegistry()` method to MediaWikiServices. Don't forget to add the
appropriate test cases in MediaWikiServicesTest.
* Change all code that calls `FooRegistry::getFoo()` statically to call this
method on a `FooRegistry` instance. That is, `Bar` would have a `$fooRegistry`
member, initialized from a constructor parameter.
* As an intermediate step, Bar's constructor could initialize the `$fooRegistry`
member variable by calling
`MediaWikiServices::getInstance()->getFooRegistry()`. This is acceptable as a
stepping stone, but should be replaced by proper injection via a constructor
argument. Do not however inject the MediaWikiServices object!
### Migrate deferred service instantiation
Assume class `Bar` calls `new Foo()`, but only when needed, to avoid the cost of
instantiating Foo().
* Define a `FooFactory` interface and a `MyFooFactory` implementation of that
interface. `FooFactory` defines the method `getFoo()` with no parameters.
* Precede as for the "parameterized helper instantiation" case described above.
### Migrate a class with only static methods
Assume `Foo` is a class with only static methods, such as `frob()`, which
interacts with global state or system resources.
* Introduce a `FooService` interface and a `DefaultFoo` implementation of that
interface. `FooService` contains the public methods defined by Foo.
* Add an instantiator function for `FooService` into ServiceWiring.php and
add a `getFooService()` method to MediaWikiServices. Don't forget to
add the appropriate test cases in MediaWikiServicesTest.
* Add a private static `getFooService()` method to `Foo`. That method just
calls `MediaWikiServices::getInstance()->getFooService()`.
* Make all methods in `Foo` delegate to the `FooService` returned by
`getFooService()`. That is, `Foo::frob()` would do
`self::getFooService()->frob()`.
* Deprecate `Foo`. Inject a `FooService` into all code that calls methods
on `Foo`, and change any calls to static methods in foo to the methods
provided by the `FooService` interface.
### Migrate static hook handler functions (to allow unit testing)
Assume `MyExtHooks::onFoo` is a static hook handler function that is called with
the parameter `$x`; Further assume `MyExt::onFoo` needs service `Bar`, which is
already known to MediaWikiServices (if not, see above).
* Create a non-static `doFoo( $x )` method in `MyExtHooks` that has the same
signature as `onFoo( $x )`. Move the code from `onFoo()` into `doFoo()`,
replacing any access to global or static variables with access to instance
member variables.
* Add a constructor to `MyExtHooks` that takes a Bar service as a parameter.
* Add a static method called `newFromGlobalState()` with no parameters. It
should just return
`new MyExtHooks( MediaWikiServices::getInstance()->getBar() )`.
* The original static handler method `onFoo( $x )` is then implemented as
`self::newFromGlobalState()->doFoo( $x )`.
### Migrate a "smart record"
Assume `Thingy` is a "smart record" that "knows" how to load and store itself.
For this purpose, `Thingy` uses wfGetDB().
* Create a "dumb" value class `ThingyRecord` that contains all the information
that `Thingy` represents (e.g. the information from a database row). The value
object should not know about any service.
* Create a DAO-style service for loading and storing `ThingyRecord`s, called
`ThingyStore`. It may be useful to split the interfaces for reading and
writing, with a single class implementing both interfaces, so we in the
end have the `ThingyLookup` and `ThingyStore` interfaces, and a SqlThingyStore
implementation.
* Add instantiator functions for `ThingyLookup` and `ThingyStore` in
ServiceWiring.php. Since we want to use the same instance for both service
interfaces, the instantiator for `ThingyLookup` would return
`$services->getThingyStore()`.
* Add `getThingyLookup()` and `getThingyStore()` methods to MediaWikiServices.
Don't forget to add the appropriate test cases in MediaWikiServicesTest.
* In the old `Thingy` class, replace all member variables that represent the
record's data with a single `ThingyRecord` object.
* In the old Thingy class, replace all calls to static methods or functions,
such as wfGetDB(), with calls to the appropriate services, such as
`LoadBalancer::getConnection()`.
* In Thingy's constructor, pull in any services needed, such as the
LoadBalancer, by using `MediaWikiServices::getInstance()`. These services
cannot be injected without changing the constructor signature, which
is often impractical for "smart records" that get instantiated directly
in many places in the code base.
* Deprecate the old `Thingy` class. Replace all usages of it with one of the
three new classes: loading needs a `ThingyLookup`, storing needs a
`ThingyStore`, and reading data needs a `ThingyRecord`.
### Migrate lazy loading
Assume `Thingy` is a "smart record" as described above, but requires lazy
loading of some or all the data it represents.
* Instead of a plain object, define `ThingyRecord` to be an interface. Provide a
"simple" and "lazy" implementations, called `SimpleThingyRecord` and
`LazyThingyRecord`. `LazyThingyRecord` knows about some lower level storage
interface, like a LoadBalancer, and uses it to load information on demand.
* Any direct instantiation of a `ThingyRecord` would use the
`SimpleThingyRecord` implementation.
* `SqlThingyStore` however creates instances of `LazyThingyRecord`, and injects
whatever storage layer service `LazyThingyRecord` needs to perform lazy
loading.

View File

@ -1,6 +1,12 @@
Introduction {#mainpage}
=======
===============================
Welcome to the MediaWiki autogenerated documentation system.
If you are looking to use, install or configure your wiki, see the main site: <https://www.mediawiki.org/>.
Helpful resources
-------------------------------
- [General information](https://www.mediawiki.org/)
- [Installation guide](https://www.mediawiki.org/wiki/Manual:Installation_guide)
- [Configuration](https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:System_administration)
- [New Developers](https://www.mediawiki.org/wiki/New_Developers)

7
docs/Language.md Normal file
View File

@ -0,0 +1,7 @@
Language
=======
The Language object handles all readable text produced by the software.
See [MediaWiki.org](https://www.mediawiki.org/wiki/Localisation#General_use_.28for_developers.29)
for documentation relating to using localized messages.

25
docs/LinkCache.md Normal file
View File

@ -0,0 +1,25 @@
The LinkCache class maintains a list of article titles and the information about
whether or not the article exists in the database. This is used to mark up links
when displaying a page. If the same link appears more than once on any page,
then it only has to be looked up once. In most cases, link lookups are done in
batches with the LinkBatch class, or the equivalent in Parser::replaceLinkHolders(),
so the link cache is mostly useful for short snippets of parsed text (such as
the site notice), and for links in the navigation areas of the skin.
The link cache was formerly used to track links used in a document for the
purposes of updating the link tables. This application is now deprecated.
To create a batch, you can use the following code:
~~~{.php}
$pages = [ 'Main Page', 'Project:Help', /* ... */ ];
$titles = [];
foreach( $pages as $page ){
$titles[] = Title::newFromText( $page );
}
$linkBatchFactory = MediaWikiServices::getInstance()->getLinkBatchFactory();
$batch = $linkBatchFactory->newLinkBatch( $titles );
$batch->execute();
~~~

65
docs/Logger.md Normal file
View File

@ -0,0 +1,65 @@
MediaWiki.Logger.LoggerFactory implements a [PSR-3] compatible message logging
system.
Named Psr.Log.LoggerInterface instances can be obtained from the
MediaWiki.Logger.LoggerFactory::getInstance() static method.
MediaWiki.Logger.LoggerFactory expects a class implementing the
MediaWiki.Logger.Spi interface to act as a factory for new
Psr.Log.LoggerInterface instances.
The "Spi" in MediaWiki.Logger.Spi stands for "service provider interface". An
SPI is an API intended to be implemented or extended by a third party. This
software design pattern is intended to enable framework extension and
replaceable components. It is specifically used in the
MediaWiki.Logger.LoggerFactory service to allow alternate PSR-3 logging
implementations to be easily integrated with MediaWiki.
The service provider interface allows the backend logging library to be
implemented in multiple ways. The $wgMWLoggerDefaultSpi global provides the
classname of the default MediaWiki.Logger.Spi implementation to be loaded at
runtime. This can either be the name of a class implementing the
MediaWiki.Logger.Spi with a zero argument constructor or a callable that will
return an MediaWiki.Logger.Spi instance. Alternately the
MediaWiki.Logger.LoggerFactory::registerProvider() static method can be called
to inject an MediaWiki.Logger.Spi instance into the LoggerFactory and bypass the
use of the default configuration variable.
The MediaWiki.Logger.LegacySpi class implements a service provider to generate
MediaWiki.Logger.LegacyLogger instances. The MediaWiki.Logger.LegacyLogger class
implements the PSR-3 logger interface and provides output and configuration
equivalent to the historic logging output of wfDebug, wfDebugLog, wfLogDBError
and wfErrorLog. The MediaWiki.Logger.LegacySpi class is the default service
provider configured in DefaultSettings.php. It's usage should be transparent for
users who are not ready or do not wish to switch to a alternate logging
platform.
The MediaWiki.Logger.MonologSpi class implements a service provider to generate
Psr.Log.LoggerInterface instances that use the [Monolog] logging library. See
the PHP docs (or source) for MediaWiki.Logger.MonologSpi for details on the
configuration of this provider. The default configuration installs a null
handler that will silently discard all logging events. The documentation
provided by the class describes a more feature rich logging configuration.
# Classes
* MediaWiki.Logger.LoggerFactory: Factory for Psr.Log.LoggerInterface loggers
* MediaWiki.Logger.Spi: Service provider interface for
MediaWiki.Logger.LoggerFactory
* MediaWiki.Logger.NullSpi: MediaWiki.Logger.Spi for creating instances that
discard all log events
* MediaWiki.Logger.LegacySpi: Service provider for creating
MediaWiki.Logger.LegacyLogger instances
* MediaWiki.Logger.LegacyLogger: PSR-3 logger that mimics the historical output
and configuration of wfDebug, wfErrorLog and other global logging functions.
* MediaWiki.Logger.MonologSpi: MediaWiki.Logger.Spi for creating instances
backed by the monolog logging library
* MediaWiki.Logger.Monolog.LegacyHandler: Monolog handler that replicates the
udp2log and file logging functionality of wfErrorLog()
* MediaWiki.Logger.Monolog.WikiProcessor: Monolog log processer that adds host:
wfHostname() and wiki: wfWikiID() to all records
# Globals
* $wgMWLoggerDefaultSpi: Specification for creating the default service provider
interface to use with LoggerFactory
[PSR-3]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
[Monolog]: https://github.com/Seldaek/monolog

View File

@ -7,7 +7,7 @@ can be found at:
https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Code
https://www.mediawiki.org/wiki/Special:MyLanguage/Developer_hub
API documentation is automatically generated and updated daily at:
https://doc.wikimedia.org/mediawiki-core/master/php/html/
https://doc.wikimedia.org/mediawiki-core/master/php/
You can get a fresh version using 'make doc' or mwdocgen.php in the
../maintenance/ directory.

83
docs/Skin.md Normal file
View File

@ -0,0 +1,83 @@
Skins
=======
## Core Skins
MediaWiki includes four core skins:
* Vector: The default skin. Introduced in the 1.16 release (2010), it has been
set as the default in MediaWiki since the 1.17 release (2011), replacing
Monobook.
* Monobook: Named after the black-and-white photo of a book in the page
background. Introduced in the 2004 release of 1.3, it had been the
default skin since then, before being replaced by Vector.
* Modern: An attractive blue/grey theme with sidebar and top bar. Derived from
Monobook.
* Cologne Blue: A lightweight skin with minimal formatting. The oldest of the
currently bundled skins, largely rewritten in 2012 while keeping its
appearance.
### Legacy core skins
Several legacy skins were removed in the 1.22 release, as the burden of
supporting them became too heavy to bear. Those were:
* Standard (a.k.a. Classic): The old default skin written by Lee Crocker during
the phase 3 rewrite, in 2002.
* Nostalgia: A skin which looks like Wikipedia did in its first year (2001).
This skin is now used for the old Wikipedia snapshot at
https://nostalgia.wikipedia.org/
* Chick: A lightweight Monobook skin with no sidebar. The sidebar links were
given at the bottom of the page instead.
* Simple: A lightweight skin with a simple white-background sidebar and no top
bar.
* MySkin: Essentially Monobook without the CSS. The idea was that it could be
customised using user-specific or site-wide CSS (see below).
## Custom CSS/JS
It is possible to customise the site CSS and JavaScript without editing any
server-side source files. This is done by editing some pages on the wiki:
* `MediaWiki:Common.css` for skin-independent CSS
* `MediaWiki:Common.js` for skin-independent JavaScript
* `MediaWiki:Vector.css`, `MediaWiki:Monobook.css`, etc. for skin-dependent CSS
* `MediaWiki:Vector.js`, `MediaWiki:Monobook.js`, etc. for skin-dependent
JavaScript
These can also be customised on a per-user basis, by editing
`User:<name>/vector.css`, `User:<name>/vector.js`, etc.
## Custom skins
Several custom skins are available as of 2019. List of all skins is available at
[MediaWiki.org](https://www.mediawiki.org/wiki/Special:MyLanguage/Category:All_skins).
Installing a skin requires adding its files in a subdirectory under `skins/` and
adding an appropriate `wfLoadSkin` line to `LocalSettings.php`, similarly to
how extensions are installed.
You can then make that skin the default by adding:
```php
$wgDefaultSkin = '<name>';
```
Or disable it entirely by removing the `wfLoadSkin` line. (User settings will
not be lost if it's reenabled later.)
See https://www.mediawiki.org/wiki/Manual:Skinning for more information on
writing new skins.
### Legacy custom skins
Until MediaWiki 1.25 it used to be possible to just put a `<name>.php` file in
MediaWiki's `skins/` directory, which would be loaded and expected to contain
the `Skin<name>` class. This way has always been discouraged because of its
limitations (inability to add localisation messages, ResourceLoader modules,
etc.) and awkwardness in managing such skins. For information on migrating skins
using this old method, see
https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery.

65
docs/Title.md Normal file
View File

@ -0,0 +1,65 @@
The MediaWiki software's "Title" class represents article titles, which are used
for many purposes: as the human-readable text title of the article, in the URL
used to access the article, the wikitext link to the article, the key into the
article database, and so on. The class in instantiated from one of these forms
and can be queried for the others, and for other attributes of the title. This
is intended to be an immutable "value" class, so there are no mutator functions.
To get a new instance, call Title::newFromText(). Once instantiated, the
non-static accessor methods can be used, such as getText(), getDBkey(),
getNamespace(), etc. Note that Title::newFromText() may return false if the text
is illegal according to the rules below.
The prefix rules: a title consists of an optional interwiki prefix (such as "m:"
for meta or "de:" for German), followed by an optional namespace, followed by
the remainder of the title. Both interwiki prefixes and namespace prefixes have
the same rules: they contain only letters, digits, space, and underscore, must
start with a letter, are case insensitive, and spaces and underscores are
interchangeable. Prefixes end with a ":". A prefix is only recognized if it is
one of those specifically allowed by the software. For example, "de:name" is a
link to the article "name" in the German Wikipedia, because "de" is recognized
as one of the allowable interwikis. The title "talk:name" is a link to the
article "name" in the "talk" namespace of the current wiki, because "talk" is a
recognized namespace. Both may be present, and if so, the interwiki must
come first, for example, "m:talk:name". If a title begins with a colon as its
first character, no prefixes are scanned for, and the colon is just removed.
Note that because of these rules, it is possible to have articles with colons in
their names. "E. Coli 0157:H7" is a valid title, as is "2001: A Space Odyssey",
because "E. Coli 0157" and "2001" are not valid interwikis or namespaces.
It is not possible to have an article whose bare name includes a namespace or
interwiki prefix.
An initial colon in a title listed in wiki text may however suppress special
handling for interlanguage links, image links, and category links. It is also
used to indicate the main namespace in template inclusions.
Once prefixes have been stripped, the rest of the title processed this way:
* Spaces and underscores are treated as equivalent and each is converted to the
other in the appropriate context (underscore in URL and database keys, spaces
in plain text).
* Multiple consecutive spaces are converted to a single space.
* Leading or trailing space is removed.
* If $wgCapitalLinks is enabled (the default), the first letter is capitalised,
using the capitalisation function of the content language object.
* The unicode characters LRM (U+200E) and RLM (U+200F) are silently stripped.
* Invalid UTF-8 sequences or instances of the replacement character (U+FFFD) are
considered illegal.
* A percent sign followed by two hexadecimal characters is illegal
* Anything that looks like an XML/HTML character reference is illegal
* Any character not matched by the $wgLegalTitleChars regex is illegal
* Zero-length titles (after whitespace stripping) are illegal
All titles except special pages must be less than 255 bytes when encoded with
UTF-8, because that is the size of the database field. Special page titles may
be up to 512 bytes.
Note that Unicode Normal Form C (NFC) is enforced by MediaWiki's user interface
input functions, and so titles will typically be in this form.
getArticleID() needs some explanation: for "internal" articles, it should return
the "page_id" field if the article exists, else it returns 0. For all external
articles it returns 0. All of the IDs for all instances of Title created during
a request are cached, so they can be looked up quickly while rendering wiki text
with lots of internal links. See LinkCache.md.

121
docs/contenthandler.md Normal file
View File

@ -0,0 +1,121 @@
# ContentHandler
The *ContentHandler* facility adds support for arbitrary content types on wiki pages, instead of relying on wikitext for everything. It was introduced in MediaWiki 1.21.
Each kind of content ("content model") supported by MediaWiki is identified by unique name. The content model determines how a page's content is rendered, compared, stored, edited, and so on.
Built-in content types are:
* wikitext - wikitext, as usual
* javascript - user provided javascript code
* json - simple implementation for use by extensions, etc.
* css - user provided css code
* text - plain text
In PHP, use the corresponding `CONTENT_MODEL_XXX` constant.
A page's content model is available using the `Title::getContentModel()` method. A page's default model is determined by `ContentHandler::getDefaultModelFor($title)` as follows:
* The global setting `$wgNamespaceContentModels` specifies a content model for the given namespace.
* The hook `ContentHandlerDefaultModelFor` may be used to override the page's default model.
* Pages in `NS_MEDIAWIKI` and `NS_USER` default to the CSS or JavaScript model if they end in .css or .js, respectively. Pages in `NS_MEDIAWIKI` default to the wikitext model otherwise.
* Otherwise, the wikitext model is used.
Note that is currently no mechanism to convert a page from one content model to another, and there is no guarantee that revisions of a page will all have the same content model. Use `Revision::getContentModel()`to find it.
## Architecture
Two class hierarchies are used to provide the functionality associated with the different content models:
* Content interface (and `AbstractContent` base class) define functionality that acts on the concrete content of a page, and
* `ContentHandler` base class provides functionality specific to a content model, but not acting on concrete content.
The most important function of ContentHandler is to act as a factory for the appropriate implementation of Content. These `Content` objects are to be used by MediaWiki everywhere, instead of passing page content around as text. All manipulation and analysis of page content must be done via the appropriate methods of the Content object.
For each content model, a subclass of ContentHandler has to be registered with `$wgContentHandlers`. The ContentHandler object for a given content model can be obtained using `ContentHandler::getForModelID( $id )`. Also `Title`, `WikiPage` and `Revision` now have `getContentHandler()` methods for convenience.
`ContentHandler` objects are singletons that provide functionality specific to the content type, but not directly acting on the content of some page. `ContentHandler::makeEmptyContent()` and `ContentHandler::unserializeContent()` can be used to create a Content object of the appropriate type. However, it is recommended to instead use `WikiPage::getContent()` resp. `Revision::getContent()` to get a page's content as a Content object. These two methods should be the ONLY way in which page content is accessed.
Another important function of ContentHandler objects is to define custom action handlers for a content model, see `ContentHandler::getActionOverrides()`. This is similar to what `WikiPage::getActionOverrides()` was already doing.
## Serialization
With the ContentHandler facility, page content no longer has to be text based. Objects implementing the Content interface are used to represent and handle the content internally. For storage and data exchange, each content model supports at least one serialization format via `ContentHandler::serializeContent( $content )`. The list of supported formats for a given content model can be accessed using `ContentHandler::getSupportedFormats()`.
Content serialization formats are identified using MIME type like strings. The following formats are built in:
* text/x-wiki - wikitext
* text/javascript - for js pages
* text/css - for css pages
* text/plain - for future use, e.g. with plain text messages.
* text/html - for future use, e.g. with plain html messages.
* application/vnd.php.serialized - for future use with the api and for extensions
* application/json - for future use with the api, and for use by extensions
* application/xml - for future use with the api, and for use by extensions
In PHP, use the corresponding `CONTENT_FORMAT_XXX` constant.
Note that when using the API to access page content, especially `action=edit`, `action=parse` and `action=query&prop=revisions`, the model and format of the content should always be handled explicitly. Without that information, interpretation of the provided content is not reliable. The same applies to XML dumps generated via `maintenance/dumpBackup.php` or `Special:Export`.
Also note that the API will provide encapsulated, serialized content - so if the API was called with `format=json`, and contentformat is also json (or rather, application/json), the page content is represented as a string containing an escaped json structure. Extensions that use JSON to serialize some types of page content may provide specialized API modules that allow access to that content in a more natural form.
## Compatibility
The ContentHandler facility is introduced in a way that should allow all existing code to keep functioning at least for pages that contain wikitext or other text based content. However, a number of functions and hooks have been deprecated in favor of new versions that are aware of the page's content model, and will now generate warnings when used.
Most importantly, the following functions have been deprecated:
* `Revisions::getText()` is deprecated in favor of `Revisions::getContent()`
* `WikiPage::getText()` is deprecated in favor of `WikiPage::getContent()`
Also, the old `Article::getContent()` (which returns text) is superceded by `Article::getContentObject()`. However, both methods should be avoided since they do not provide clean access to the page's actual content. For instance, they may return a system message for non-existing pages. Use `WikiPage::getContent()` instead.
Code that relies on a textual representation of the page content should eventually be rewritten. However, `ContentHandler::getContentText()` provides a stop-gap that can be used to get text for a page. Its behavior is controlled by `$wgContentHandlerTextFallback`; per default it will return the text for text based content, and null for any other content.
For rendering page content, `Content::getParserOutput()` should be used instead of accessing the parser directly. `WikiPage::makeParserOptions()` can be used to construct appropriate options.
Besides some functions, some hooks have also been replaced by new versions (see hooks.txt for details). These hooks will now trigger a warning when used:
* `ArticleAfterFetchContent` was replaced by `ArticleAfterFetchContentObject`, later replaced by `ArticleRevisionViewCustom`
* `ArticleInsertComplete` was replaced by `PageContentInsertComplete`
* `ArticleSave` was replaced by `PageContentSave`
* `ArticleSaveComplete` was replaced by `PageContentSaveComplete`
* `ArticleViewCustom` was replaced by `ArticleContentViewCustom`, which was later removed entirely
* `EditFilterMerged` was replaced by `EditFilterMergedContent`
* `EditPageGetDiffText` was replaced by `EditPageGetDiffContent`
* `EditPageGetPreviewText` was replaced by `EditPageGetPreviewContent`
* `ShowRawCssJs` was deprecated in favor of custom rendering implemented in the respective ContentHandler object.
## Database Storage
Page content is stored in the database using the same mechanism as before. Non-text content is serialized first. The appropriate serialization and deserialization is handled by the Revision class.
Each revision's content model and serialization format is stored in the revision table (resp. in the archive table, if the revision was deleted). The page's (current) content model (that is, the content model of the latest revision) is also stored in the page table.
Note however that the content model and format is only stored if it differs from the page's default, as determined by `ContentHandler::getDefaultModelFor( $title )`. The default values are represented as `NULL` in the database, to preserve space.
## Globals
There are some new globals that can be used to control the behavior of the ContentHandler facility:
* `$wgContentHandlers` associates content model IDs with the names of the appropriate ContentHandler subclasses or callbacks that create an instance of the appropriate ContentHandler subclass.
* `$wgNamespaceContentModels` maps namespace IDs to a content model that should be the default for that namespace.
* `$wgContentHandlerTextFallback` determines how the compatibility method `ContentHandler::getContentText()` will behave for non-text content:
* `'ignore'` causes null to be returned for non-text content (default).
* `'serialize'` causes the serialized form of any non-text content to be returned (scary).
* `'fail'` causes an exception to be thrown for non-text content (strict).
## Caveats
There are some changes in behavior that might be surprising to users:
* Javascript and CSS pages are no longer parsed as wikitext (though pre-save transform is still applied). Most importantly, this means that links, including categorization links, contained in the code will not work.
* `action=edit` will fail for pages with non-text content, unless the respective ContentHandler implementation has provided a specialized handler for the edit action. This is true for the API as well.
* `action=raw` will fail for all non-text content. This seems better than serving content in other formats to an unsuspecting recipient. This will also cause client-side diffs to fail.
* File pages provide their own action overrides that do not combine gracefully with any custom handlers defined by a ContentHandler. If for example a File page used a content model with a custom revert action, this would be overridden by WikiFilePage's handler for the revert action.

View File

@ -1,182 +0,0 @@
The ContentHandler facility adds support for arbitrary content types on wiki pages, instead of relying on wikitext
for everything. It was introduced in MediaWiki 1.21.
Each kind of content ("content model") supported by MediaWiki is identified by unique name. The content model determines
how a page's content is rendered, compared, stored, edited, and so on.
Built-in content types are:
* wikitext - wikitext, as usual
* javascript - user provided javascript code
* json - simple implementation for use by extensions, etc.
* css - user provided css code
* text - plain text
In PHP, use the corresponding CONTENT_MODEL_XXX constant.
A page's content model is available using the Title::getContentModel() method. A page's default model is determined by
ContentHandler::getDefaultModelFor($title) as follows:
* The global setting $wgNamespaceContentModels specifies a content model for the given namespace.
* The hook ContentHandlerDefaultModelFor may be used to override the page's default model.
* Pages in NS_MEDIAWIKI and NS_USER default to the CSS or JavaScript model if they end in .css or .js, respectively.
Pages in NS_MEDIAWIKI default to the wikitext model otherwise.
* Otherwise, the wikitext model is used.
Note that is currently no mechanism to convert a page from one content model to another, and there is no guarantee that
revisions of a page will all have the same content model. Use Revision::getContentModel() to find it.
== Architecture ==
Two class hierarchies are used to provide the functionality associated with the different content models:
* Content interface (and AbstractContent base class) define functionality that acts on the concrete content of a page, and
* ContentHandler base class provides functionality specific to a content model, but not acting on concrete content.
The most important function of ContentHandler is to act as a factory for the appropriate implementation of Content. These
Content objects are to be used by MediaWiki everywhere, instead of passing page content around as text. All manipulation
and analysis of page content must be done via the appropriate methods of the Content object.
For each content model, a subclass of ContentHandler has to be registered with $wgContentHandlers. The ContentHandler
object for a given content model can be obtained using ContentHandler::getForModelID( $id ). Also Title, WikiPage and
Revision now have getContentHandler() methods for convenience.
ContentHandler objects are singletons that provide functionality specific to the content type, but not directly acting
on the content of some page. ContentHandler::makeEmptyContent() and ContentHandler::unserializeContent() can be used to
create a Content object of the appropriate type. However, it is recommended to instead use WikiPage::getContent() resp.
Revision::getContent() to get a page's content as a Content object. These two methods should be the ONLY way in which
page content is accessed.
Another important function of ContentHandler objects is to define custom action handlers for a content model, see
ContentHandler::getActionOverrides(). This is similar to what WikiPage::getActionOverrides() was already doing.
== Serialization ==
With the ContentHandler facility, page content no longer has to be text based. Objects implementing the Content interface
are used to represent and handle the content internally. For storage and data exchange, each content model supports
at least one serialization format via ContentHandler::serializeContent( $content ). The list of supported formats for
a given content model can be accessed using ContentHandler::getSupportedFormats().
Content serialization formats are identified using MIME type like strings. The following formats are built in:
* text/x-wiki - wikitext
* text/javascript - for js pages
* text/css - for css pages
* text/plain - for future use, e.g. with plain text messages.
* text/html - for future use, e.g. with plain html messages.
* application/vnd.php.serialized - for future use with the api and for extensions
* application/json - for future use with the api, and for use by extensions
* application/xml - for future use with the api, and for use by extensions
In PHP, use the corresponding CONTENT_FORMAT_XXX constant.
Note that when using the API to access page content, especially action=edit, action=parse and action=query&prop=revisions,
the model and format of the content should always be handled explicitly. Without that information, interpretation of
the provided content is not reliable. The same applies to XML dumps generated via maintenance/dumpBackup.php or
Special:Export.
Also note that the API will provide encapsulated, serialized content - so if the API was called with format=json, and
contentformat is also json (or rather, application/json), the page content is represented as a string containing an
escaped json structure. Extensions that use JSON to serialize some types of page content may provide specialized API
modules that allow access to that content in a more natural form.
== Compatibility ==
The ContentHandler facility is introduced in a way that should allow all existing code to keep functioning at least
for pages that contain wikitext or other text based content. However, a number of functions and hooks have been
deprecated in favor of new versions that are aware of the page's content model, and will now generate warnings when
used.
Most importantly, the following functions have been deprecated:
* Revisions::getText() is deprecated in favor Revisions::getContent()
* WikiPage::getText() is deprecated in favor WikiPage::getContent()
Also, the old Article::getContent() (which returns text) is superceded by Article::getContentObject(). However, both
methods should be avoided since they do not provide clean access to the page's actual content. For instance, they may
return a system message for non-existing pages. Use WikiPage::getContent() instead.
Code that relies on a textual representation of the page content should eventually be rewritten. However,
ContentHandler::getContentText() provides a stop-gap that can be used to get text for a page. Its behavior is controlled
by $wgContentHandlerTextFallback; per default it will return the text for text based content, and null for any other
content.
For rendering page content, Content::getParserOutput() should be used instead of accessing the parser directly.
ContentHandler::makeParserOptions() can be used to construct appropriate options.
Besides some functions, some hooks have also been replaced by new versions (see hooks.txt for details).
These hooks will now trigger a warning when used:
* ArticleAfterFetchContent was replaced by ArticleAfterFetchContentObject
* ArticleInsertComplete was replaced by PageContentInsertComplete
* ArticleSave was replaced by PageContentSave
* ArticleSaveComplete was replaced by PageContentSaveComplete
* ArticleViewCustom was replaced by ArticleContentViewCustom (also consider a custom implementation of the view action)
* EditFilterMerged was replaced by EditFilterMergedContent
* EditPageGetDiffText was replaced by EditPageGetDiffContent
* EditPageGetPreviewText was replaced by EditPageGetPreviewContent
* ShowRawCssJs was deprecated in favor of custom rendering implemented in the respective ContentHandler object.
== Database Storage ==
Page content is stored in the database using the same mechanism as before. Non-text content is serialized first. The
appropriate serialization and deserialization is handled by the Revision class.
Each revision's content model and serialization format is stored in the revision table (resp. in the archive table, if
the revision was deleted). The page's (current) content model (that is, the content model of the latest revision) is also
stored in the page table.
Note however that the content model and format is only stored if it differs from the page's default, as determined by
ContentHandler::getDefaultModelFor( $title ). The default values are represented as NULL in the database, to preserve
space.
Storage of content model and format can be disabled altogether by setting $wgContentHandlerUseDB = false. In that case,
the page's default model (and the model's default format) will be used everywhere. Attempts to store a revision of a page
using a model or format different from the default will result in an error.
== Globals ==
There are some new globals that can be used to control the behavior of the ContentHandler facility:
* $wgContentHandlers associates content model IDs with the names of the appropriate ContentHandler subclasses
or callbacks that create an instance of the appropriate ContentHandler subclass.
* $wgNamespaceContentModels maps namespace IDs to a content model that should be the default for that namespace.
* $wgContentHandlerUseDB determines whether each revision's content model should be stored in the database.
Defaults is true.
* $wgContentHandlerTextFallback determines how the compatibility method ContentHandler::getContentText() will behave for
non-text content:
'ignore' causes null to be returned for non-text content (default).
'serialize' causes the serialized form of any non-text content to be returned (scary).
'fail' causes an exception to be thrown for non-text content (strict).
== Caveats ==
There are some changes in behavior that might be surprising to users:
* Javascript and CSS pages are no longer parsed as wikitext (though pre-save transform is still applied). Most
importantly, this means that links, including categorization links, contained in the code will not work.
* With $wgContentHandlerUseDB = false, pages can not be moved in a way that would change the
default model. E.g. [[MediaWiki:foo.js]] can not be moved to [[MediaWiki:foo bar]], but can still be moved to
[[User:John/foo.js]]. Also, in this mode, changing the default content model for a page (e.g. by changing
$wgNamespaceContentModels) may cause it to become inaccessible.
* action=edit will fail for pages with non-text content, unless the respective ContentHandler implementation has
provided a specialized handler for the edit action. This is true for the API as well.
* action=raw will fail for all non-text content. This seems better than serving content in other formats to an
unsuspecting recipient. This will also cause client-side diffs to fail.
* File pages provide their own action overrides that do not combine gracefully with any custom handlers defined by a
ContentHandler. If for example a File page used a content model with a custom revert action, this would be overridden by
WikiFilePage's handler for the revert action.

98
docs/database.md Normal file
View File

@ -0,0 +1,98 @@
# Database Access
*Some information about database access in MediaWiki. By Tim Starling, January 2006.*
## Database Layout
For information about the MediaWiki database layout, such as a description of the tables and their contents, please see:
* [The manual](https://www.mediawiki.org/wiki/Manual:Database_layout)
* [https://phabricator.wikimedia.org/diffusion/MW/browse/master/maintenance/tables.sql](https://phabricator.wikimedia.org/diffusion/MW/browse/master/maintenance/tables.sql)
## API
To make a read query, something like this usually suffices:
```php
$dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select( /* ...see docs... */ );
foreach ( $res as $row ) {
...
}
```
For a write query, use something like:
```php
$dbw = wfGetDB( DB_MASTER );
$dbw->insert( /* ...see docs... */ );
```
We use the convention `$dbr` for read and `$dbw` for write to help you keep track of whether the database object is a replica (read-only) or a master (read/write). If you write to a replica, the world will explode. Or to be precise, a subsequent write query which succeeded on the master may fail when propagated to the replica due to a unique key collision. Replication will then stop and it may take hours to repair the database and get it back online. Setting `read_only` in `my.cnf` on the replica will avoid this scenario, but given the dire consequences, we prefer to have as many checks as possible.
We provide a `query()` function for raw SQL, but the wrapper functions like `select()` and `insert()` are usually more convenient. They take care of things like table prefixes and escaping for you. If you really need to make your own SQL, please read the documentation for `tableName()` and `addQuotes()`. You will need both of them.
## Basic query optimisation
MediaWiki developers who need to write DB queries should have some understanding of databases and the performance issues associated with them. Patches containing unacceptably slow features will not be accepted. Unindexed queries are generally not welcome in MediaWiki, except in special pages derived from `QueryPage`. It's a common pitfall for new developers to submit code containing SQL queries which examine huge numbers of rows. Remember that `COUNT(*)` is **O(N)**, counting rows in a table is like counting beans in a bucket.
## Replication
The largest installation of MediaWiki, Wikimedia, uses a large set of replica MySQL servers replicating writes made to a master MySQL server. It is important to understand the issues associated with this setup if you want to write code destined for Wikipedia.
It's often the case that the best algorithm to use for a given task depends on whether or not replication is in use. Due to our unabashed Wikipedia-centrism, we often just use the replication-friendly version, but if you like, you can use `LoadBalancer::getServerCount() > 1` to check to see if replication is in use.
## Lag
Lag primarily occurs when large write queries are sent to the master. Writes on the master are executed in parallel, but they are executed in serial when they are replicated to the replicas. The master writes the query to the binlog when the transaction is committed. The replicas poll the binlog and start executing the query as soon as it appears. They can service reads while they are performing a write query, but will not read anything more from the binlog and thus will perform no more writes. This means that if the write query runs for a long time, the replicas will lag behind the master for the time it takes for the write query to complete.
Lag can be exacerbated by high read load. MediaWiki's load balancer will stop sending reads to a replica when it is lagged by more than 30 seconds. If the load ratios are set incorrectly, or if there is too much load generally, this may lead to a replica permanently hovering around 30 seconds lag.
If all replicas are lagged by more than 30 seconds, MediaWiki will stop writing to the database. All edits and other write operations will be refused, with an error returned to the user. This gives the replicas a chance to catch up. Before we had this mechanism, the replicas would regularly lag by several minutes, making review of recent edits difficult.
In addition to this, MediaWiki attempts to ensure that the user sees events occurring on the wiki in chronological order. A few seconds of lag can be tolerated, as long as the user sees a consistent picture from subsequent requests. This is done by saving the master binlog position in the session, and then at the start of each request, waiting for the replica to catch up to that position before doing any reads from it. If this wait times out, reads are allowed anyway, but the request is considered to be in "lagged replica mode". Lagged replica mode can be checked by calling `LoadBalancer::getLaggedReplicaMode()`. The only practical consequence at present is a warning displayed in the page footer.
## Lag avoidance
To avoid excessive lag, queries which write large numbers of rows should be split up, generally to write one row at a time. Multi-row `INSERT ... SELECT` queries are the worst offenders should be avoided altogether. Instead do the select first and then the insert.
## Working with lag
Despite our best efforts, it's not practical to guarantee a low-lag environment. Lag will usually be less than one second, but may occasionally be up to 30 seconds. For scalability, it's very important to keep load on the master low, so simply sending all your queries to the master is not the answer. So when you have a genuine need for up-to-date data, the following approach is advised:
1) Do a quick query to the master for a sequence number or timestamp
2) Run the full query on the replica and check if it matches the data you got
from the master
3) If it doesn't, run the full query on the master
To avoid swamping the master every time the replicas lag, use of this approach should be kept to a minimum. In most cases you should just read from the replica and let the user deal with the delay.
## Lock contention
Due to the high write rate on Wikipedia (and some other wikis), MediaWiki developers need to be very careful to structure their writes to avoid long-lasting locks. By default, MediaWiki opens a transaction at the first query, and commits it before the output is sent. Locks will be held from the time when the query is done until the commit. So you can reduce lock time by doing as much processing as possible before you do your write queries.
Often this approach is not good enough, and it becomes necessary to enclose small groups of queries in their own transaction. Use the following syntax:
```php
$dbw = wfGetDB( DB_MASTER );
$dbw->begin( __METHOD__ );
/* Do queries */
$dbw->commit( __METHOD__ );
```
Use of locking reads (e.g. the `FOR UPDATE` clause) is not advised. They are poorly implemented in InnoDB and will cause regular deadlock errors. It's also surprisingly easy to cripple the wiki with lock contention.
Instead of locking reads, combine your existence checks into your write queries, by using an appropriate condition in the `WHERE` clause of an `UPDATE`, or by using unique indexes in combination with `INSERT IGNORE`. Then use the affected row count to see if the query succeeded.
## Supported DBMSs
MediaWiki is written primarily for use with MySQL. Queries are optimized for it and its schema is considered the canonical version. However, MediaWiki does support the following other DBMSs to varying degrees:
* PostgreSQL
* SQLite
More information can be found about each of these databases (known issues, level of support, extra configuration) in the `databases` subdirectory in this folder.
## Use of `GROUP BY`
MySQL supports `GROUP BY` without checking anything in the `SELECT` clause. Other DBMSs (especially Postgres) are stricter and require that all the non-aggregate items in the `SELECT` clause appear in the `GROUP BY`. For this reason, it is highly discouraged to use `SELECT *` with `GROUP BY` queries.

View File

@ -1,193 +0,0 @@
Some information about database access in MediaWiki.
By Tim Starling, January 2006.
------------------------------------------------------------------------
Database layout
------------------------------------------------------------------------
For information about the MediaWiki database layout, such as a
description of the tables and their contents, please see:
https://www.mediawiki.org/wiki/Manual:Database_layout
https://phabricator.wikimedia.org/diffusion/MW/browse/master/maintenance/tables.sql
------------------------------------------------------------------------
API
------------------------------------------------------------------------
To make a read query, something like this usually suffices:
$dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select( /* ...see docs... */ );
foreach ( $res as $row ) {
...
}
For a write query, use something like:
$dbw = wfGetDB( DB_MASTER );
$dbw->insert( /* ...see docs... */ );
We use the convention $dbr for read and $dbw for write to help you keep
track of whether the database object is a slave (read-only) or a master
(read/write). If you write to a slave, the world will explode. Or to be
precise, a subsequent write query which succeeded on the master may fail
when replicated to the slave due to a unique key collision. Replication
on the slave will stop and it may take hours to repair the database and
get it back online. Setting read_only in my.cnf on the slave will avoid
this scenario, but given the dire consequences, we prefer to have as
many checks as possible.
We provide a query() function for raw SQL, but the wrapper functions
like select() and insert() are usually more convenient. They take care
of things like table prefixes and escaping for you. If you really need
to make your own SQL, please read the documentation for tableName() and
addQuotes(). You will need both of them.
------------------------------------------------------------------------
Basic query optimisation
------------------------------------------------------------------------
MediaWiki developers who need to write DB queries should have some
understanding of databases and the performance issues associated with
them. Patches containing unacceptably slow features will not be
accepted. Unindexed queries are generally not welcome in MediaWiki,
except in special pages derived from QueryPage. It's a common pitfall
for new developers to submit code containing SQL queries which examine
huge numbers of rows. Remember that COUNT(*) is O(N), counting rows in a
table is like counting beans in a bucket.
------------------------------------------------------------------------
Replication
------------------------------------------------------------------------
The largest installation of MediaWiki, Wikimedia, uses a large set of
slave MySQL servers replicating writes made to a master MySQL server. It
is important to understand the issues associated with this setup if you
want to write code destined for Wikipedia.
It's often the case that the best algorithm to use for a given task
depends on whether or not replication is in use. Due to our unabashed
Wikipedia-centrism, we often just use the replication-friendly version,
but if you like, you can use LoadBalancer::getServerCount() > 1 to
check to see if replication is in use.
=== Lag ===
Lag primarily occurs when large write queries are sent to the master.
Writes on the master are executed in parallel, but they are executed in
serial when they are replicated to the slaves. The master writes the
query to the binlog when the transaction is committed. The slaves poll
the binlog and start executing the query as soon as it appears. They can
service reads while they are performing a write query, but will not read
anything more from the binlog and thus will perform no more writes. This
means that if the write query runs for a long time, the slaves will lag
behind the master for the time it takes for the write query to complete.
Lag can be exacerbated by high read load. MediaWiki's load balancer will
stop sending reads to a slave when it is lagged by more than 30 seconds.
If the load ratios are set incorrectly, or if there is too much load
generally, this may lead to a slave permanently hovering around 30
seconds lag.
If all slaves are lagged by more than 30 seconds, MediaWiki will stop
writing to the database. All edits and other write operations will be
refused, with an error returned to the user. This gives the slaves a
chance to catch up. Before we had this mechanism, the slaves would
regularly lag by several minutes, making review of recent edits
difficult.
In addition to this, MediaWiki attempts to ensure that the user sees
events occurring on the wiki in chronological order. A few seconds of lag
can be tolerated, as long as the user sees a consistent picture from
subsequent requests. This is done by saving the master binlog position
in the session, and then at the start of each request, waiting for the
slave to catch up to that position before doing any reads from it. If
this wait times out, reads are allowed anyway, but the request is
considered to be in "lagged slave mode". Lagged slave mode can be
checked by calling LoadBalancer::getLaggedReplicaMode(). The only
practical consequence at present is a warning displayed in the page
footer.
=== Lag avoidance ===
To avoid excessive lag, queries which write large numbers of rows should
be split up, generally to write one row at a time. Multi-row INSERT ...
SELECT queries are the worst offenders should be avoided altogether.
Instead do the select first and then the insert.
=== Working with lag ===
Despite our best efforts, it's not practical to guarantee a low-lag
environment. Lag will usually be less than one second, but may
occasionally be up to 30 seconds. For scalability, it's very important
to keep load on the master low, so simply sending all your queries to
the master is not the answer. So when you have a genuine need for
up-to-date data, the following approach is advised:
1) Do a quick query to the master for a sequence number or timestamp 2)
Run the full query on the slave and check if it matches the data you got
from the master 3) If it doesn't, run the full query on the master
To avoid swamping the master every time the slaves lag, use of this
approach should be kept to a minimum. In most cases you should just read
from the slave and let the user deal with the delay.
------------------------------------------------------------------------
Lock contention
------------------------------------------------------------------------
Due to the high write rate on Wikipedia (and some other wikis),
MediaWiki developers need to be very careful to structure their writes
to avoid long-lasting locks. By default, MediaWiki opens a transaction
at the first query, and commits it before the output is sent. Locks will
be held from the time when the query is done until the commit. So you
can reduce lock time by doing as much processing as possible before you
do your write queries.
Often this approach is not good enough, and it becomes necessary to
enclose small groups of queries in their own transaction. Use the
following syntax:
$dbw = wfGetDB( DB_MASTER );
$dbw->begin( __METHOD__ );
/* Do queries */
$dbw->commit( __METHOD__ );
Use of locking reads (e.g. the FOR UPDATE clause) is not advised. They
are poorly implemented in InnoDB and will cause regular deadlock errors.
It's also surprisingly easy to cripple the wiki with lock contention.
Instead of locking reads, combine your existence checks into your write
queries, by using an appropriate condition in the WHERE clause of an
UPDATE, or by using unique indexes in combination with INSERT IGNORE.
Then use the affected row count to see if the query succeeded.
------------------------------------------------------------------------
Supported DBMSs
------------------------------------------------------------------------
MediaWiki is written primarily for use with MySQL. Queries are optimized
for it and its schema is considered the canonical version. However,
MediaWiki does support the following other DBMSs to varying degrees.
* PostgreSQL
* SQLite
More information can be found about each of these databases (known issues,
level of support, extra configuration) in the "databases" subdirectory in
this folder.
------------------------------------------------------------------------
Use of GROUP BY
------------------------------------------------------------------------
MySQL supports GROUP BY without checking anything in the SELECT clause.
Other DBMSs (especially Postgres) are stricter and require that all the
non-aggregate items in the SELECT clause appear in the GROUP BY. For
this reason, it is highly discouraged to use SELECT * with GROUP BY
queries.

View File

@ -1,6 +1,5 @@
This document describes the state of Postgres support in MediaWiki.
== Overview ==
Support for PostgreSQL has been available since version 1.7
@ -10,14 +9,9 @@ Still, it is probably the most supported database after MySQL.
Much of the work in making MediaWiki database-agnostic came
about through the work of creating Postgres support.
== Required versions ==
The current minimum version of PostgreSQL for MediaWiki is 8.1.
It is expected that this will be raised to 8.3 at some point,
as 8.1 and 8.2 are nearing end of life.
The current minimum version of PostgreSQL for MediaWiki is 9.2
== Database schema ==
@ -80,7 +74,6 @@ referenced directly by the code (unlike sequence names). Most of
the indexes in the file as of this writing are there due to production
testing of expensive queries on a busy wiki.
== Keeping in sync with tables.sql ==
The script maintenance/postgres/compare_schemas.pl should be
@ -91,19 +84,17 @@ itself. This script has also been very useful in finding problems
in maintenance/tables.sql itself, as it is very strict in the
format it expects things to be in. :)
== MySQL differences ==
The major differences between MySQL and Postgres are represented as
methods in the Database class. For example, implicitGroupby() is
true for MySQL and false for Postgres. This means that in those
places where the code does not add all the non-aggregate items
from the SELECT clause to the GROUP BY, we can add them in, but in
a conditional manner with the above method, as simply adding them
all in to the main query may cause performance problems with
The major differences between MySQL and Postgres are represented as
methods in the Database class. For example, implicitGroupby() is
true for MySQL and false for Postgres. This means that in those
places where the code does not add all the non-aggregate items
from the SELECT clause to the GROUP BY, we can add them in, but in
a conditional manner with the above method, as simply adding them
all in to the main query may cause performance problems with
MySQL.
== Getting help ==
In addition to the normal venues (MediaWiki mailing lists

View File

@ -58,8 +58,8 @@ If you really must mess around with the directory structure, note that the
following files *must* all be web-accessible for MediaWiki to function
correctly:
* api.php, img_auth.php, index.php, load.php, opensearch_desc.php, thumb.php,
profileinfo.php. These are the entry points for normal usage. This list may be
* api.php, img_auth.php, index.php, load.php, opensearch_desc.php, thumb.php.
These are the entry points for normal usage. This list may be
incomplete and is subject to change.
* mw-config/index.php: Used for web-based installation (sets up the database,
prompts for the name of the wiki, etc.).
@ -113,16 +113,16 @@ intelligently:
== Updates ==
The correct way for updating a wiki is to update the files and then run from
The correct way for updating a wiki is to update the files and then run from
command line the maintenance/update.php script (with appropriate parameters if
files were moved). It will perform all the needed steps to update the database
files were moved). It will perform all the needed steps to update the database
schema and contents to the version from whatever old one it has.
Any package manager which replaces the files but doesn't update the db is leaving
an inconsistent wiki that may produce blank pages (php errors) when new features
an inconsistent wiki that may produce blank pages (php errors) when new features
using the changed schema would be used.
Since MediaWiki 1.17 it is possible to upgrade using the web installer by providing
an arbitrary secret value stored as $wgUpgradeKey in LocalSettings (older versions
an arbitrary secret value stored as $wgUpgradeKey in LocalSettings (older versions
needed to rename LocalSettings.php in order to upgrade using the installer).
== Documentation ==

View File

@ -26,7 +26,7 @@
Fix type for <id> within <contributor> to "nonNegativeInteger"
Version 0.8 adds support for a <model> and a <format> tag for
each revision. See contenthandler.txt.
each revision. See contenthandler.md.
Version 0.9 adds the database name to the site information.

View File

@ -26,7 +26,7 @@
Fix type for <id> within <contributor> to "nonNegativeInteger"
Version 0.8 adds support for a <model> and a <format> tag for
each revision. See contenthandler.txt.
each revision. See contenthandler.md.
Version 0.9 adds the database name to the site information.
@ -226,6 +226,7 @@
<!-- This allows deleted=deleted on non-empty elements, but XSD is not omnipotent -->
<attribute name="deleted" type="mw:DeletedFlagType" />
<attribute name="location" type="anyURI" />
<attribute name="sha1" type="string" />
<attribute name="bytes" type="nonNegativeInteger" />
</extension>
</simpleContent>

View File

@ -26,7 +26,7 @@
Fix type for <id> within <contributor> to "nonNegativeInteger"
Version 0.8 adds support for a <model> and a <format> tag for
each revision. See contenthandler.txt.
each revision. See contenthandler.md.
The canonical URL to the schema document is:
http://www.mediawiki.org/xml/export-0.8.xsd

View File

@ -26,7 +26,7 @@
Fix type for <id> within <contributor> to "nonNegativeInteger"
Version 0.8 adds support for a <model> and a <format> tag for
each revision. See contenthandler.txt.
each revision. See contenthandler.md.
Version 0.9 adds the database name to the site information.

View File

@ -55,7 +55,7 @@
},
"requires": {
"type": "object",
"description": "Indicates what versions of PHP, MediaWiki core or extensions are required. This syntax may be extended in the future, for example to check dependencies between other services.",
"description": "Indicates what versions of PHP, MediaWiki core, extensions or skins are required. This syntax may be extended in the future, for example to check dependencies between other services.",
"additionalProperties": false,
"properties": {
"MediaWiki": {
@ -272,7 +272,7 @@
},
"group": {
"type": "string",
"description": "Group which this module should be loaded together with"
"description": "Group with which this module should be loaded"
},
"deprecated": {
"type": ["object", "string", "boolean"],
@ -302,8 +302,11 @@
"description": "Whether to skip CSSJanus LTR-to-RTL flipping for this module. Recommended for styles imported from libraries that already properly handle their RTL styles. Default is false, meaning CSSJanus will be applied on RTL-mode output."
},
"packageFiles": {
"type": ["object", "array"],
"description": "Package files that can be require()d"
"type": ["string", "array"],
"description": "Package files that can be require()d",
"items": {
"type": ["string", "object"]
}
}
}
},
@ -316,7 +319,7 @@
},
"group": {
"type": "string",
"description": "Group which this module should be loaded together with"
"description": "Group with which this module should be loaded"
},
"position": {
"type": "string",
@ -335,12 +338,14 @@
},
"scripts": {
"type": "array",
"description": "A list of on-wiki pages containing JavaScript that should be loaded",
"items": {
"type": "string"
}
},
"styles": {
"type": "array",
"description": "A list of on-wiki pages containing CSS that should be loaded",
"items": {
"type": "string"
}
@ -354,6 +359,10 @@
"class": {
"enum": ["ResourceLoaderImageModule"]
},
"localBasePath": {
"type": "string",
"description": "Base path to prepend to all local paths. Defaults to $IP"
},
"defaultColor": {
"type": "string"
},
@ -390,7 +399,7 @@
}
},
{
"description": "An arbitrary ResourceLoaderModule definition",
"description": "An arbitrary ResourceLoaderModule definition by class",
"properties": {
"class": {
"type": "string",
@ -413,7 +422,89 @@
},
"QUnitTestModule": {
"type": "object",
"description": "A ResourceLoaderFileModule definition registered only when wgEnableJavaScriptTest is true."
"description": "A ResourceLoaderFileModule definition registered only when wgEnableJavaScriptTest is true.",
"additionalProperties": false,
"properties": {
"localBasePath": {
"type": "string",
"description": "Prefix for local paths to files in $options, relative to extenion directory"
},
"remoteExtPath": {
"type": "string",
"description": "Prefix for URLs to files in $options, relative to $wgExtensionAssetsPath"
},
"remoteSkinPath": {
"type": "string",
"description": "Prefix for URLs to files in $options, relative to $wgStylePath"
},
"scripts": {
"type": ["string", "array"],
"description": "Scripts to include (array of file paths)",
"items": {
"type": "string"
}
},
"packageFiles": {
"type": ["string", "array"],
"description": "Package files that can be require()d",
"items": {
"type": ["string", "object"]
}
},
"dependencies": {
"type": ["string", "array"],
"description": "Modules which must be loaded before this module",
"items": {
"type": "string"
}
},
"styles": {
"type": ["string", "array", "object"],
"description": "Styles to load",
"items": {
"type": "string"
}
},
"templates": {
"type": ["object", "array"],
"description": "Templates to be loaded for client-side usage",
"items": {
"type": "string"
}
},
"messages": {
"type": ["string", "array"],
"description": "Messages to load",
"items": {
"type": "string"
}
}
}
},
"MessagePosterModule": {
"type": "object",
"description": "Additional JavaScript files and modules that will register content models with mw.messagePoster.factory.",
"additionalProperties": false,
"properties": {
"localBasePath": {
"type": "string",
"description": "Prefix for local paths to files in $options, relative to extenion directory"
},
"scripts": {
"type": "array",
"description": "Scripts to include as array of file paths",
"items": {
"type": "string"
}
},
"dependencies": {
"type": "array",
"description": "Modules which must load before these files",
"items": {
"type": "string"
}
}
}
},
"ConfigRegistry": {
"type": "object",
@ -655,9 +746,125 @@
"AutoloadClasses": {
"type": "object"
},
"TestAutoloadNamespaces": {
"type": "object",
"description": "Mapping of PSR-4 compliant namespace to directory for autoloading to be used in tests",
"patternProperties": {
"^[A-Za-z0-9\\\\]+\\\\$": {
"type": "string"
}
},
"additionalProperties": false
},
"TestAutoloadClasses": {
"type": "object"
},
"Hooks": {
"type": [ "string", "object" ],
"description": "Hooks this extension uses (mapping of hook name to callback)"
"type": "object",
"description": "Hooks this extension uses (mapping of hook name to callback)",
"additionalProperties": {
"oneOf": [
{
"type": "string",
"description": "A global function name, static function name, or the name of a property in HookHandlers"
},
{
"type": "object",
"description": "A handler specification",
"properties": {
"handler": {
"type": "string",
"description": "The name of a property in HookHandlers"
},
"deprecated": {
"type": "boolean",
"description": "The deprecation acknowledgement flag for the handler. If this is true, calls will be filtered if the relevant hook is deprecated."
}
},
"required": [
"handler"
]
},
{
"type": "array",
"description": "An ordered array of handlers",
"items": {
"oneOf": [
{
"type": "string",
"description": "A global function name, static function name, or the name of a property in HookHandlers"
},
{
"type": "object",
"description": "A handler specification",
"properties": {
"handler": {
"type": "string",
"description": "The name of a property in HookHandlers"
},
"deprecated": {
"type": "boolean",
"description": "The deprecation acknowledgement flag for the handler. If this is true, calls will be filtered if the relevant hook is deprecated."
}
},
"required": [
"handler"
]
}
]
}
}
]
}
},
"HookHandlers": {
"type": "object",
"description": "ObjectFactory specifications for new-style hook handlers",
"additionalProperties": {
"type": "object",
"properties": {
"factory": {
"type": ["string", "array"],
"description": "A factory function to be called to create the handler for this hook"
},
"class": {
"type": "string",
"description": "The fully-qualified class name of the handler. This should be omitted if a factory is specified."
},
"args": {
"type": "array",
"description": "The arguments passed to the handler constructor or factory"
},
"services": {
"type": "array",
"description": "If supplied and non-empty, the named services are requested from the service container and prepended before 'args'."
}
}
}
},
"DeprecatedHooks": {
"type": "object",
"description": "Hooks which are defined and deprecated by the extension",
"additionalProperties": {
"type": "object",
"properties": {
"deprecatedVersion": {
"type": "string",
"description": "The version in which the hook was deprecated"
},
"component": {
"type": "string",
"description" : "The component to which the deprecated version relates. If omitted, the extension name will be used."
},
"silent": {
"type": "boolean",
"description": "If true, no warning is raised when the hook is called or when a handler is declared. However, call filtering is still activated."
}
},
"required": [
"deprecatedVersion"
]
}
},
"JobClasses": {
"type": "object",
@ -721,14 +928,16 @@
"type": "object"
},
"ValidSkinNames": {
"type": "object"
"type": "object",
"description": "Mapping of skin canonical names to PHP class name using the Object Factory specification. Or historically, the human readable name of the skin."
},
"FeedClasses": {
"type": "object",
"description": "Available feeds objects"
},
"SkinOOUIThemes": {
"type": "object"
"type": "object",
"description": "Map of skin names to OOUI themes to use. Same format as ResourceLoaderOOUIModule::$builtinSkinThemeMap."
},
"OOUIThemePaths": {
"type": "object",
@ -819,10 +1028,128 @@
"type": "array",
"description": "DEPRECATED: Parser test suite files to be run by parserTests.php when no specific filename is passed to it"
},
"SearchMappings": {
"type": "object",
"description": "Mapping of search canonical names (used in $wgSearchType and $wgSearchTypeAlternatives) using the Object Factory specification"
},
"ServiceWiringFiles": {
"type": "array",
"description": "List of service wiring files to be loaded by the default instance of MediaWikiServices"
},
"RestRoutes": {
"type": "array",
"description": "List of route specifications to be added to the REST API",
"items": {
"type": "object",
"properties": {
"method": {
"oneOf": [
{
"type": "string",
"description": "The HTTP method name"
},
{
"type": "array",
"items": {
"type": "string",
"description": "An acceptable HTTP method name"
}
}
]
},
"path": {
"type": "string",
"description": "The path template. This should start with an initial slash, designating the root of the REST API. Path parameters are enclosed in braces, for example /endpoint/{param}."
},
"factory": {
"type": ["string", "array"],
"description": "A factory function to be called to create the handler for this route"
},
"class": {
"type": "string",
"description": "The fully-qualified class name of the handler. This should be omitted if a factory is specified."
},
"args": {
"type": "array",
"description": "The arguments passed to the handler constructor or factory"
},
"services": {
"type": "array",
"description": "If supplied and non-empty, the named services are requested from the service container and prepended before 'args'."
}
}
}
},
"ParsoidModules": {
"type": "array",
"description": "List of extension modules to be registered with the Parsoid wikitext parser",
"items": {
"oneOf": [
{
"type": "string",
"description": "The fully-qualified name of a class implementing Wikimedia\\Parsoid\\Ext\\ExtensionModule"
},
{
"type": "object",
"description": "An object factory specification for a class implementing Wikimedia\\Parsoid\\Ext\\ExtensionModule",
"properties": {
"factory": {
"type": ["string", "array"],
"description": "A factory function to be called to create an ExtensionModule. This should be omitted if a class is specified."
},
"class": {
"type": "string",
"description": "The fully-qualified class name of a class implemeting Wikimedia\\Parsoid\\Ext\\ExtensionModule. This should be omitted if a factory is specified."
},
"args": {
"type": "array",
"description": "The arguments passed to the ExtensionModule constructor or factory"
}
}
},
{
"type": "object",
"description": "A Parsoid extension module configuration array",
"properties": {
"domProcessors": {
"type": "array",
"items": {
"description": "Object factory specification of a class implementing Wikimedia\\Parsoid\\Ext\\DOMProcessor"
}
},
"styles": {
"type": "array",
"items": {
"type": "string",
"description": "Additional ResourceLoader styles to include"
}
},
"tags": {
"type": "array",
"items": {
"type": "object",
"description": "An extension tag",
"properties": {
"name": {
"type": "string",
"description": "The name of the extension tag",
"required": true
},
"handler": {
"description": "An object factory specification of a class extending Wikimedia\\Parsoid\\Ext\\ExtensionTagHandler"
},
"options": {
"type": "object",
"description": "Additional Parsoid processing configuration for this extension tag"
}
}
}
}
}
}
]
}
},
"load_composer_autoloader": {
"type": "boolean",
"description": "Load the composer autoloader for this extension, if one is present"

View File

@ -62,7 +62,7 @@
},
"requires": {
"type": "object",
"description": "Indicates what versions of PHP, MediaWiki core or extensions are required. This syntax may be extended in the future, for example to check dependencies between other services.",
"description": "Indicates what versions of PHP, MediaWiki core, extensions or skins are required. This syntax may be extended in the future, for example to check dependencies between other services.",
"additionalProperties": false,
"properties": {
"MediaWiki": {
@ -295,7 +295,10 @@
},
"templates": {
"type": ["object", "array"],
"description": "Templates to be loaded for client-side usage"
"description": "Templates to be loaded for client-side usage",
"items": {
"type": "string"
}
},
"targets": {
"type": ["string", "array"],
@ -309,8 +312,11 @@
"description": "Whether to skip CSSJanus LTR-to-RTL flipping for this module. Recommended for styles imported from libraries that already properly handle their RTL styles. Default is false, meaning CSSJanus will be applied on RTL-mode output."
},
"packageFiles": {
"type": ["object", "array"],
"description": "Package files that can be require()d"
"type": ["string", "array"],
"description": "Package files that can be require()d",
"items": {
"type": ["string", "object"]
}
}
}
},
@ -363,6 +369,10 @@
"class": {
"enum": ["ResourceLoaderImageModule"]
},
"localBasePath": {
"type": "string",
"description": "Base path to prepend to all local paths. Defaults to $IP"
},
"defaultColor": {
"type": "string"
},
@ -454,6 +464,13 @@
"type": "string"
}
},
"packageFiles": {
"type": ["string", "array"],
"description": "Package files that can be require()d",
"items": {
"type": ["string", "object"]
}
},
"dependencies": {
"type": ["string", "array"],
"description": "Modules which must be loaded before this module",
@ -468,6 +485,13 @@
"type": "string"
}
},
"templates": {
"type": ["object", "array"],
"description": "Templates to be loaded for client-side usage",
"items": {
"type": "string"
}
},
"messages": {
"type": ["string", "array"],
"description": "Messages to load",
@ -477,6 +501,31 @@
}
}
},
"MessagePosterModule": {
"type": "object",
"description": "Additional JavaScript files and modules that will register content models with mw.messagePoster.factory.",
"additionalProperties": false,
"properties": {
"localBasePath": {
"type": "string",
"description": "Prefix for local paths to files in $options, relative to extenion directory"
},
"scripts": {
"type": "array",
"description": "Scripts to include as array of file paths",
"items": {
"type": "string"
}
},
"dependencies": {
"type": "array",
"description": "Modules which must load before these files",
"items": {
"type": "string"
}
}
}
},
"ConfigRegistry": {
"type": "object",
"description": "Registry of factory functions to create Config objects"
@ -725,9 +774,125 @@
"AutoloadClasses": {
"type": "object"
},
"TestAutoloadNamespaces": {
"type": "object",
"description": "Mapping of PSR-4 compliant namespace to directory for autoloading to be used in tests",
"patternProperties": {
"^[A-Za-z0-9\\\\]+\\\\$": {
"type": "string"
}
},
"additionalProperties": false
},
"TestAutoloadClasses": {
"type": "object"
},
"Hooks": {
"type": [ "string", "object" ],
"description": "Hooks this extension uses (mapping of hook name to callback)"
"type": "object",
"description": "Hooks this extension uses (mapping of hook name to callback)",
"additionalProperties": {
"oneOf": [
{
"type": "string",
"description": "A global function name, static function name, or the name of a property in HookHandlers"
},
{
"type": "object",
"description": "A handler specification",
"properties": {
"handler": {
"type": "string",
"description": "The name of a property in HookHandlers"
},
"deprecated": {
"type": "boolean",
"description": "The deprecation acknowledgement flag for the handler. If this is true, calls will be filtered if the relevant hook is deprecated."
}
},
"required": [
"handler"
]
},
{
"type": "array",
"description": "An ordered array of handlers",
"items": {
"oneOf": [
{
"type": "string",
"description": "A global function name, static function name, or the name of a property in HookHandlers"
},
{
"type": "object",
"description": "A handler specification",
"properties": {
"handler": {
"type": "string",
"description": "The name of a property in HookHandlers"
},
"deprecated": {
"type": "boolean",
"description": "The deprecation acknowledgement flag for the handler. If this is true, calls will be filtered if the relevant hook is deprecated."
}
},
"required": [
"handler"
]
}
]
}
}
]
}
},
"HookHandlers": {
"type": "object",
"description": "ObjectFactory specifications for new-style hook handlers",
"additionalProperties": {
"type": "object",
"properties": {
"factory": {
"type": ["string", "array"],
"description": "A factory function to be called to create the handler for this hook"
},
"class": {
"type": "string",
"description": "The fully-qualified class name of the handler. This should be omitted if a factory is specified."
},
"args": {
"type": "array",
"description": "The arguments passed to the handler constructor or factory"
},
"services": {
"type": "array",
"description": "If supplied and non-empty, the named services are requested from the service container and prepended before 'args'."
}
}
}
},
"DeprecatedHooks": {
"type": "object",
"description": "Hooks which are defined and deprecated by the extension",
"additionalProperties": {
"type": "object",
"properties": {
"deprecatedVersion": {
"type": "string",
"description": "The version in which the hook was deprecated"
},
"component": {
"type": "string",
"description" : "The component to which the deprecated version relates. If omitted, the extension name will be used."
},
"silent": {
"type": "boolean",
"description": "If true, no warning is raised when the hook is called or when a handler is declared. However, call filtering is still activated."
}
},
"required": [
"deprecatedVersion"
]
}
},
"JobClasses": {
"type": "object",
@ -791,7 +956,8 @@
"type": "object"
},
"ValidSkinNames": {
"type": "object"
"type": "object",
"description": "Mapping of skin canonical names to PHP class name using the Object Factory specification. Or historically, the human readable name of the skin."
},
"FeedClasses": {
"type": "object",
@ -910,6 +1076,10 @@
"type": "array",
"description": "DEPRECATED: Parser test suite files to be run by parserTests.php when no specific filename is passed to it"
},
"SearchMappings": {
"type": "object",
"description": "Mapping of search canonical names (used in $wgSearchType and $wgSearchTypeAlternatives) using the Object Factory specification"
},
"ServiceWiringFiles": {
"type": "array",
"description": "List of service wiring files to be loaded by the default instance of MediaWikiServices"
@ -950,10 +1120,84 @@
"args": {
"type": "array",
"description": "The arguments passed to the handler constructor or factory"
},
"services": {
"type": "array",
"description": "If supplied and non-empty, the named services are requested from the service container and prepended before 'args'."
}
}
}
},
"ParsoidModules": {
"type": "array",
"description": "List of extension modules to be registered with the Parsoid wikitext parser",
"items": {
"oneOf": [
{
"type": "string",
"description": "The fully-qualified name of a class implementing Wikimedia\\Parsoid\\Ext\\ExtensionModule"
},
{
"type": "object",
"description": "An object factory specification for a class implementing Wikimedia\\Parsoid\\Ext\\ExtensionModule",
"properties": {
"factory": {
"type": ["string", "array"],
"description": "A factory function to be called to create an ExtensionModule. This should be omitted if a class is specified."
},
"class": {
"type": "string",
"description": "The fully-qualified class name of a class implemeting Wikimedia\\Parsoid\\Ext\\ExtensionModule. This should be omitted if a factory is specified."
},
"args": {
"type": "array",
"description": "The arguments passed to the ExtensionModule constructor or factory"
}
}
},
{
"type": "object",
"description": "A Parsoid extension module configuration array",
"properties": {
"domProcessors": {
"type": "array",
"items": {
"description": "Object factory specification of a class implementing Wikimedia\\Parsoid\\Ext\\DOMProcessor"
}
},
"styles": {
"type": "array",
"items": {
"type": "string",
"description": "Additional ResourceLoader styles to include"
}
},
"tags": {
"type": "array",
"items": {
"type": "object",
"description": "An extension tag",
"properties": {
"name": {
"type": "string",
"description": "The name of the extension tag",
"required": true
},
"handler": {
"description": "An object factory specification of a class extending Wikimedia\\Parsoid\\Ext\\ExtensionTagHandler"
},
"options": {
"type": "object",
"description": "Additional Parsoid processing configuration for this extension tag"
}
}
}
}
}
}
]
}
},
"attributes": {
"description":"Registration information for other extensions",
"type": "object",

View File

@ -56,10 +56,11 @@ $wgContLang
Language object associated with the wiki being viewed.
$wgParser
Parser object. Parser extensions register their hooks here.
Parser object. Parser extensions used to register their hooks here;
modern code should use the ParserFirstCallInit hook.
$wgRequest
WebRequest object, to get request data
$wgMemc, $messageMemc
$wgMemc
Object caches

File diff suppressed because it is too large Load Diff

View File

@ -1,269 +0,0 @@
injection.txt
This is an overview of how MediaWiki makes use of dependency injection.
The design described here grew from the discussion of RFC T384.
The term "dependency injection" (DI) refers to a pattern on object oriented
programming that tries to improve modularity by reducing strong coupling
between classes. In practical terms, this means that anything an object needs
to operate should be injected from the outside, the object itself should only
know narrow interfaces, no concrete implementation of the logic it relies on.
The requirement to inject everything typically results in an architecture that
based on two main types of objects: simple value objects with no business logic
(and often immutable), and essentially stateless service objects that use
other service objects to operate on the value objects.
As of the beginning of 2016 (MW version 1.27), MediaWiki is only starting to
use the DI approach. Much of the code still relies on global state or direct
instantiation, resulting in a highly cyclical dependency graph.
== Overview ==
The heart of the DI in MediaWiki is the central service locator,
MediaWikiServices, which acts as the top level factory for services in
MediaWiki. MediaWikiServices::getInstance() returns the default service
locator instance, which can be used to gain access to default instances of
various services. MediaWikiServices however also allows new services to be
defined and default services to be redefined. Services are defined or
redefined by providing a callback function, the "instantiator" function,
that will return a new instance of the service.
When MediaWikiServices::getInstance() is first called, it will create an
instance of MediaWikiServices and populate it with the services defined
in the files listed by $wgServiceWiringFiles, thereby "bootstrapping" the
DI framework. Per default, $wgServiceWiringFiles lists
includes/ServiceWiring.php, which defines all default service
implementations, and specifies how they depend on each other ("wiring").
When a new service is added to MediaWiki core, an instantiator function
that will create the appropriate default instance for that service must
be added to ServiceWiring.php. This makes the service available through
the generic getService() method on the service locator returned by
MediaWikiServices::getInstance().
Extensions can add their own wiring files to $wgServiceWiringFiles, in order
to define their own service. Extensions may also use the 'MediaWikiServices'
hook to define or redefined services by calling methods on the default
MediaWikiServices instance.
It should be noted that the term "service locator" is often used to refer to a
top level factory that is accessed directly, throughout the code, to avoid
explicit dependency injection. In contrast, the term "DI container" is often
used to describe a top level factory that is only accessed when services
are created. We use the term "service locator" for the top level factory
because it is more descriptive than "DI container", even though application
logic is strongly discouraged from accessing MediaWikiServices directly.
MediaWikiServices::getInstance() should ideally be accessed only in "static
entry points" such as hook handler functions. See "Migration" below.
== Service Reset ==
Services get their configuration injected, and changes to global
configuration variables will not have any effect on services that were already
instantiated. This would typically be the case for low level services like
the ConfigFactory or the ObjectCacheManager, which are used during extension
registration. To address this issue, Setup.php resets the global service
locator instance by calling MediaWikiServices::resetGlobalInstance() once
configuration and extension registration is complete.
Note that "unmanaged" legacy services services that manage their own singleton
must not keep references to services managed by MediaWikiServices, to allow a
clean reset. After the global MediaWikiServices instance got reset, any such
references would be stale, and using a stale service will result in an error.
Services should either have all dependencies injected and be themselves managed
by MediaWikiServices, or they should use the Service Locator pattern, accessing
service instances via the global MediaWikiServices instance state when needed.
This ensures that no stale service references remain after a reset.
== Configuration ==
When the default MediaWikiServices instance is created, a Config object is
provided to the constructor. This Config object represents the "bootstrap"
configuration which will become available as the 'BootstrapConfig' service.
As of MW 1.27, the bootstrap config is a GlobalVarConfig object providing
access to the $wgXxx configuration variables.
The bootstrap config is then used to construct a 'ConfigFactory' service,
which in turn is used to construct the 'MainConfig' service. Application
logic should use the 'MainConfig' service (or a more specific configuration
object). 'BootstrapConfig' should only be used for bootstrapping basic
services that are needed to load the 'MainConfig'.
Note: Several well known services in MediaWiki core act as factories
themselves, e.g. ApiModuleManager, ObjectCache, SpecialPageFactory, etc.
The registries these factories are based on are currently managed as part of
the configuration. This may however change in the future.
== Migration ==
This section provides some recipes for improving code modularity by reducing
strong coupling. The dependency injection mechanism described above is an
essential tool in this effort.
Migrate access to global service instances and config variables:
Assume Foo is a class that uses the $wgScriptPath global and calls
wfGetDB() to get a database connection, in non-static methods.
* Add $scriptPath as a constructor parameter and use $this->scriptPath
instead of $wgScriptPath.
* Add LoadBalancer $dbLoadBalancer as a constructor parameter. Use
$this->dbLoadBalancer->getConnection() instead of wfGetDB().
* Any code that calls Foo's constructor would now need to provide the
$scriptPath and $dbLoadBalancer. To avoid this, avoid direct instantiation
of services all together - see below.
Migrate class-level singleton getters:
Assume class Foo has mostly non-static methods, and provides a static
getInstance() method that returns a singleton (or default instance).
* Add an instantiator function for Foo into ServiceWiring.php. The instantiator
would do exactly what Foo::getInstance() did. However, it should
replace any access to global state with calls to $services->getXxx() to get a
service, or $services->getMainConfig()->get() to get a configuration setting.
* Add a getFoo() method to MediaWikiServices. Don't forget to add the
appropriate test cases in MediaWikiServicesTest.
* Turn Foo::getInstance() into a deprecated alias for
MediaWikiServices::getInstance()->getFoo(). Change all calls to
Foo::getInstance() to use injection (see above).
Migrate direct service instantiation:
Assume class Bar calls new Foo().
* Add an instantiator function for Foo into ServiceWiring.php and add a getFoo()
method to MediaWikiServices. Don't forget to add the appropriate test cases
in MediaWikiServicesTest.
* In the instantiator, replace any access to global state with calls
to $services->getXxx() to get a service, or $services->getMainConfig()->get()
to get a configuration setting.
* The code in Bar that calls Foo's constructor should be changed to have a Foo
instance injected; Eventually, the only code that instantiates Foo is the
instantiator in ServiceWiring.php.
* As an intermediate step, Bar's constructor could initialize the $foo member
variable by calling MediaWikiServices::getInstance()->getFoo(). This is
acceptable as a stepping stone, but should be replaced by proper injection
via a constructor argument. Do not however inject the MediaWikiServices
object!
Migrate parameterized helper instantiation:
Assume class Bar creates some helper object by calling new Foo( $x ),
and Foo uses a global singleton of the Xyzzy service.
* Define a FooFactory class (or a FooFactory interface along with a MyFooFactory
implementation). FooFactory defines the method newFoo( $x ) or getFoo( $x ),
depending on the desired semantics (newFoo would guarantee a fresh instance).
When Foo gets refactored to have Xyzzy injected, FooFactory will need a
Xyzzy instance, so newFoo() can pass it to new Foo().
* Add an instantiator function for FooFactory into ServiceWiring.php and add a
getFooFactory() method to MediaWikiServices. Don't forget to add the
appropriate test cases in MediaWikiServicesTest.
* The code in Bar that calls Foo's constructor should be changed to have a
FooFactory instance injected; Eventually, the only code that instantiates
Foo are implementations of FooFactory, and the only code that instantiates
FooFactory is the instantiator in ServiceWiring.php.
* As an intermediate step, Bar's constructor could initialize the $fooFactory
member variable by calling MediaWikiServices::getInstance()->getFooFactory().
This is acceptable as a stepping stone, but should be replaced by proper
injection via a constructor argument. Do not however inject the
MediaWikiServices object!
Migrate a handler registry:
Assume class Bar calls FooRegistry::getFoo( $x ) to get a specialized Foo
instance for handling $x.
* Turn getFoo into a non-static method.
* Add an instantiator function for FooRegistry into ServiceWiring.php and add
a getFooRegistry() method to MediaWikiServices. Don't forget to add the
appropriate test cases in MediaWikiServicesTest.
* Change all code that calls FooRegistry::getFoo() statically to call this
method on a FooRegistry instance. That is, Bar would have a $fooRegistry
member, initialized from a constructor parameter.
* As an intermediate step, Bar's constructor could initialize the $fooRegistry
member variable by calling MediaWikiServices::getInstance()->
getFooRegistry(). This is acceptable as a stepping stone, but should be
replaced by proper injection via a constructor argument. Do not however
inject the MediaWikiServices object!
Migrate deferred service instantiation:
Assume class Bar calls new Foo(), but only when needed, to avoid the cost of
instantiating Foo().
* Define a FooFactory interface and a MyFooFactory implementation of that
interface. FooFactory defines the method getFoo() with no parameters.
* Precede as for the "parameterized helper instantiation" case described above.
Migrate a class with only static methods:
Assume Foo is a class with only static methods, such as frob(), which
interacts with global state or system resources.
* Introduce a FooService interface and a DefaultFoo implementation of that
interface. FooService contains the public methods defined by Foo.
* Add an instantiator function for FooService into ServiceWiring.php and
add a getFooService() method to MediaWikiServices. Don't forget to
add the appropriate test cases in MediaWikiServicesTest.
* Add a private static getFooService() method to Foo. That method just
calls MediaWikiServices::getInstance()->getFooService().
* Make all methods in Foo delegate to the FooService returned by
getFooService(). That is, Foo::frob() would do self::getFooService()->frob().
* Deprecate Foo. Inject a FooService into all code that calls methods
on Foo, and change any calls to static methods in foo to the methods
provided by the FooService interface.
Migrate static hook handler functions (to allow unit testing):
Assume MyExtHooks::onFoo is a static hook handler function that is called with
the parameter $x; Further assume MyExt::onFoo needs service Bar, which is
already known to MediaWikiServices (if not, see above).
* Create a non-static doFoo( $x ) method in MyExtHooks that has the same
signature as onFoo( $x ). Move the code from onFoo() into doFoo(), replacing
any access to global or static variables with access to instance member
variables.
* Add a constructor to MyExtHooks that takes a Bar service as a parameter.
* Add a static method called newFromGlobalState() with no parameters. It should
just return new MyExtHooks( MediaWikiServices::getInstance()->getBar() ).
* The original static handler method onFoo( $x ) is then implemented as
self::newFromGlobalState()->doFoo( $x ).
Migrate a "smart record":
Assume Thingy is a "smart record" that "knows" how to load and store itself.
For this purpose, Thingy uses wfGetDB().
* Create a "dumb" value class ThingyRecord that contains all the information
that Thingy represents (e.g. the information from a database row). The value
object should not know about any service.
* Create a DAO-style service for loading and storing ThingyRecords, called
ThingyStore. It may be useful to split the interfaces for reading and
writing, with a single class implementing both interfaces, so we in the
end have the ThingyLookup and ThingyStore interfaces, and a SqlThingyStore
implementation.
* Add instantiator functions for ThingyLookup and ThingyStore in
ServiceWiring.php. Since we want to use the same instance for both service
interfaces, the instantiator for ThingyLookup would return
$services->getThingyStore().
* Add getThingyLookup() and getThingyStore methods to MediaWikiServices.
Don't forget to add the appropriate test cases in MediaWikiServicesTest.
* In the old Thingy class, replace all member variables that represent the
record's data with a single ThingyRecord object.
* In the old Thingy class, replace all calls to static methods or functions,
such as wfGetDB(), with calls to the appropriate services, such as
LoadBalancer::getConnection().
* In Thingy's constructor, pull in any services needed, such as the
LoadBalancer, by using MediaWikiServices::getInstance(). These services
cannot be injected without changing the constructor signature, which
is often impractical for "smart records" that get instantiated directly
in many places in the code base.
* Deprecate the old Thingy class. Replace all usages of it with one of the
three new classes: loading needs a ThingyLookup, storing needs a ThingyStore,
and reading data needs a ThingyRecord.
Migrate lazy loading:
Assume Thingy is a "smart record" as described above, but requires lazy loading
of some or all the data it represents.
* Instead of a plain object, define ThingyRecord to be an interface. Provide a
"simple" and "lazy" implementations, called SimpleThingyRecord and
LazyThingyRecord. LazyThingyRecord knows about some lower level storage
interface, like a LoadBalancer, and uses it to load information on demand.
* Any direct instantiation of a ThingyRecord would use the SimpleThingyRecord
implementation.
* SqlThingyStore however creates instances of LazyThingyRecord, and injects
whatever storage layer service LazyThingyRecord needs to perform lazy loading.

View File

@ -1,19 +0,0 @@
MEDIAWIKI_LOAD_URL ?= http://localhost/w/load.php
kss: kssnodecheck
# Generates CSS of mediawiki.ui and mediawiki.ui.button using ResourceLoader, then applies it to the
# KSS style guide
$(eval KSS_RL_TMP := $(shell mktemp /tmp/tmp.XXXXXXXXXX))
$(eval MODULE_STR := $(shell paste -sd "|" styleGuideModules.txt))
# See ResourceLoaderClientHtml::makeLoad.
@curl -sG "${MEDIAWIKI_LOAD_URL}?modules=${MODULE_STR}&only=styles" > $(KSS_RL_TMP)
@node_modules/.bin/kss-node ../../resources/src/mediawiki.ui static/ --css $(KSS_RL_TMP) -t styleguide-template
@rm $(KSS_RL_TMP)
kssopen: kss
@echo Opening the generated style guide...
@command -v xdg-open >/dev/null 2>&1 || { open ${PWD}/static/index.html; exit 0; }
@xdg-open ${PWD}/static/index.html
kssnodecheck:
@scripts/kss-node-check.sh

View File

@ -1,21 +0,0 @@
The Makefile, package.json, scripts, styleguide-template, and
mediawiki.ui/styleguide.md files and directories here and in
resources/src/mediawiki.ui/ support the automatic generation
of CSS documentation from the source LESS files using kss for
node.js, https://github.com/kneath/kss
To build and open in your web browser, run:
MEDIAWIKI_LOAD_URL=mediawiki_hostname/w/load.php make kssopen
For example,
MEDIAWIKI_LOAD_URL=1.2.3.4/w/load.php make kssopen
If MediaWiki is running on localhost, you can omit MEDIAWIKI_LOAD_URL.
To rebuild without opening the web browser, run:
MEDIAWIKI_LOAD_URL=mediawiki_hostname/w/load.php make
When modifying styleGuideModules.txt, keep the list in strict alphabetical order (with no extra formatting), so CSS loads in the same order as ResourceLoader's addModuleStyles does; this can affect rendering.

View File

@ -1,20 +0,0 @@
#!/usr/bin/env bash
if command -v npm > /dev/null ; then
npm install
else
# If npm isn't installed, but kss-node is, exit normally.
# This allows setting it up on one machine, and running it on
# another (e.g. Tools Labs execution nodes) that doesn't have npm
# installed. However, "npm install" still needs to be run
# occasionally to keep kss updated.
KSS_NODE="${BASH_SOURCE%/*}/../node_modules/.bin/kss-node"
if ! [ -x "$KSS_NODE" ] ; then
echo "Neither kss-node nor npm are installed."
echo "To install npm, see http://nodejs.org/"
echo "When npm is installed, the Makefile can automatically"
echo "install kss-node."
exit 1
fi
fi

View File

@ -1,10 +0,0 @@
mediawiki.legacy.commonPrint
mediawiki.legacy.shared
mediawiki.ui
mediawiki.ui.anchor
mediawiki.ui.button
mediawiki.ui.checkbox
mediawiki.ui.icon
mediawiki.ui.input
mediawiki.ui.radio
mediawiki.ui.text

View File

@ -1,87 +0,0 @@
<!DOCTYPE html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="generator" content="kss-node" />
<title>MediaWiki Living Styleguide</title>
<link rel="stylesheet" href="public/kss.css">
<link rel="stylesheet" href="public/style.css">
</head>
<body><div id="kss-wrapper">
<header id="kss-header">
<div class="container">
<hgroup><h1>Mediawiki.UI</h1></hgroup>
</div>
</header>
<div class="container">
<nav>
<ul>
<li><a href="index.html"><span>0.0</span> Overview</a></li>
{{#eachRoot}}
<li>
<a href="section-{{ reference }}.html">
<span>{{ reference }}.0</span> {{ header }}
</a>
<ul>
{{#eachSection reference}}
{{#whenDepth 2}}
<li>
<a href="section-{{../../reference}}.html#section-{{ reference }}">
<span>{{ reference }}</span>
{{ header }}
</a>
</li>
{{/whenDepth}}
{{/eachSection}}
</ul>
</li>
{{/eachRoot}}
</ul>
</nav>
<div class="content">
{{#if overview}}
{{html overview}}
{{else}}
{{#eachSection rootNumber}}
<div>
{{#whenDepth 1}}
<h1>{{ reference }}.0 {{ header }}</h1>
{{else}}
{{#whenDepth 2}}
<a name="section-{{ reference }}"></a>
<h2><a href="#section-{{ reference }}">{{ reference }} {{ header }}</a></h2>
{{/whenDepth}}
{{#whenDepth 3}}
<a name="section-{{ reference }}"></a>
<h3><a href="#section-{{ reference }}">{{ reference }} {{ header }}</a></h3>
{{/whenDepth}}
{{/whenDepth}}
{{#ifAny markup modifiers}}
<div>{{html description}}</div>
<div class="example">
<pre class="prettyprint lang-html">{{markup}}</pre>
<blockquote>{{modifierMarkup}}</blockquote>
</div>
{{#eachModifier}}
<h4>{{name}}</h4>
{{html description}}
<blockquote>{{modifierMarkup}}</blockquote>
{{/eachModifier}}
{{else}}
{{#if description}}
{{html description}}
{{/if}}
{{/ifAny}}
</div>
{{/eachSection}}
{{/if}}
</div>
</div>
</div></body>
</html>

View File

@ -1,193 +0,0 @@
.container {
width: 100%;
}
nav {
display: none;
}
.content {
.example {
blockquote {
margin-top: 20px;
}
}
}
body {
margin: 0;
padding: 0;
padding-top: 3px;
padding-bottom: 40px;
// FIXME: Remove when typography module in mediawiki-ui
font-family: "Nimbus Sans L", "Liberation Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
}
.kss-no-margin {
// FIXME: Is this being used anywhere? Remove if not.
margin: 0;
}
.container {
margin: 0 auto;
display: -webkit-flex;
display: flex;
}
header {
padding: 0;
margin: 0;
border-bottom: 1px solid #eee;
hgroup {
min-width: 149px;
h1 {
padding: 16px 28px;
font-size: 15px;
text-transform: uppercase;
margin: 0;
width: 92px;
border-right: 1px solid #eee;
}
}
}
nav {
-webkit-flex: initial;
flex: initial;
min-width: 139px;
margin-top: 25px;
ul {
list-style: none;
padding: 0;
li {
margin-left: 10px;
margin-bottom: 20px;
a {
text-transform: uppercase;
color: #aaa;
font-size: 12px;
font-weight: bold;
text-decoration: none;
&:hover {
color: #538DF8;
}
span {
display: inline-block;
width: 35px;
}
}
ul {
li {
margin: 0;
}
li a {
text-transform: none;
font-weight: normal;
}
}
}
}
}
.content {
-webkit-flex: 1;
flex: 1;
h1, h2, h3, h4, h5, h6, p {
margin-left: 20px;
a {
text-decoration: none;
color: #000;
}
}
p {
width: 338px;
}
h1 {
margin-bottom: 0;
}
.example {
display: -webkit-flex;
display: flex;
flex-wrap: wrap;
pre {
-webkit-flex: initial;
flex: initial;
background: #f8f8f8;
padding: 20px;
color: #999;
word-wrap: break-word;
// word-wrap in pre not affecting Firefox, so add white-space.
white-space: pre-wrap;
float: left;
margin: 0;
margin-right: 22px;
}
blockquote {
-webkit-flex: 1;
flex: 1;
display: block;
margin: 0;
margin-left: 20px;
div {
margin-bottom: 5px;
}
}
}
}
@media (min-width: 768px) {
nav {
display: block;
width: 100px;
}
@columnWidth: (768px - 100px ) / 2;
.example {
pre,
blockquote {
width: @columnWidth;
}
}
}
@media (min-width: 980px) {
nav {
width: auto;
}
.content {
margin-left: 30px;
}
.container {
width: 980px;
}
.example {
pre {
width: 338px;
}
blockquote {
width: auto;
}
}
}

View File

@ -1,5 +0,0 @@
language.txt
The Language object handles all readable text produced by the software.
See https://www.mediawiki.org/wiki/Localisation#General_use_.28for_developers.29

View File

@ -1,24 +0,0 @@
linkcache.txt
The LinkCache class maintains a list of article titles and the information about
whether or not the article exists in the database. This is used to mark up links
when displaying a page. If the same link appears more than once on any page,
then it only has to be looked up once. In most cases, link lookups are done in
batches with the LinkBatch class, or the equivalent in Parser::replaceLinkHolders(),
so the link cache is mostly useful for short snippets of parsed text (such as
the site notice), and for links in the navigation areas of the skin.
The link cache was formerly used to track links used in a document for the
purposes of updating the link tables. This application is now deprecated.
To create a batch, you can use the following code:
$pages = [ 'Main Page', 'Project:Help', /* ... */ ];
$titles = [];
foreach( $pages as $page ){
$titles[] = Title::newFromText( $page );
}
$batch = new LinkBatch( $titles );
$batch->execute();

View File

@ -1,71 +0,0 @@
MediaWiki\Logger\LoggerFactory implements a PSR-3 [0] compatible message
logging system.
Named Psr\Log\LoggerInterface instances can be obtained from the
MediaWiki\Logger\LoggerFactory::getInstance() static method.
MediaWiki\Logger\LoggerFactory expects a class implementing the
MediaWiki\Logger\Spi interface to act as a factory for new
Psr\Log\LoggerInterface instances.
The "Spi" in MediaWiki\Logger\Spi stands for "service provider interface". An
SPI is an API intended to be implemented or extended by a third party. This
software design pattern is intended to enable framework extension and
replaceable components. It is specifically used in the
MediaWiki\Logger\LoggerFactory service to allow alternate PSR-3 logging
implementations to be easily integrated with MediaWiki.
The service provider interface allows the backend logging library to be
implemented in multiple ways. The $wgMWLoggerDefaultSpi global provides the
classname of the default MediaWiki\Logger\Spi implementation to be loaded at
runtime. This can either be the name of a class implementing the
MediaWiki\Logger\Spi with a zero argument constructor or a callable that will
return an MediaWiki\Logger\Spi instance. Alternately the
MediaWiki\Logger\LoggerFactory::registerProvider() static method can be called
to inject an MediaWiki\Logger\Spi instance into the LoggerFactory and bypass
the use of the default configuration variable.
The MediaWiki\Logger\LegacySpi class implements a service provider to generate
MediaWiki\Logger\LegacyLogger instances. The MediaWiki\Logger\LegacyLogger
class implements the PSR-3 logger interface and provides output and
configuration equivalent to the historic logging output of wfDebug,
wfDebugLog, wfLogDBError and wfErrorLog. The MediaWiki\Logger\LegacySpi class
is the default service provider configured in DefaultSettings.php. It's usage
should be transparent for users who are not ready or do not wish to switch to
a alternate logging platform.
The MediaWiki\Logger\MonologSpi class implements a service provider to
generate Psr\Log\LoggerInterface instances that use the Monolog [1] logging
library. See the PHP docs (or source) for MediaWiki\Logger\MonologSpi for
details on the configuration of this provider. The default configuration
installs a null handler that will silently discard all logging events. The
documentation provided by the class describes a more feature rich logging
configuration.
== Classes ==
; MediaWiki\Logger\LoggerFactory
: Factory for Psr\Log\LoggerInterface loggers
; MediaWiki\Logger\Spi
: Service provider interface for MediaWiki\Logger\LoggerFactory
; MediaWiki\Logger\NullSpi
: MediaWiki\Logger\Spi for creating instances that discard all log events
; MediaWiki\Logger\LegacySpi
: Service provider for creating MediaWiki\Logger\LegacyLogger instances
; MediaWiki\Logger\LegacyLogger
: PSR-3 logger that mimics the historical output and configuration of wfDebug,
wfErrorLog and other global logging functions.
; MediaWiki\Logger\MonologSpi
: MediaWiki\Logger\Spi for creating instances backed by the monolog logging library
; MediaWiki\Logger\Monolog\LegacyHandler
: Monolog handler that replicates the udp2log and file logging
functionality of wfErrorLog()
; MediaWiki\Logger\Monolog\WikiProcessor
: Monolog log processer that adds host: wfHostname() and wiki: wfWikiID()
to all records
== Globals ==
; $wgMWLoggerDefaultSpi
: Specification for creating the default service provider interface to use
with MediaWiki\Logger\LoggerFactory
[0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
[1]: https://github.com/Seldaek/monolog

84
docs/magicword.md Normal file
View File

@ -0,0 +1,84 @@
Magic Words
====================================
Magic words are localizable keywords used in wikitext. They are used for many
small fragments of text, including:
* The names of parser functions e.g. `{{urlencode:...}}`
* The names of variables, e.g. `{{CURRENTDAY}}`
* Double-underscore behavior switches, e.g. `__NOTOC__`
* Image link parameter names
Magic words have a synonym list, with the canonical English word always present,
and a case sensitivity flag. The MagicWord class provides facilities for
matching a magic word by converting it to a regex.
A magic word has a unique ID. Often, the ID is the canonical English synonym in
lowercase.
To add a magic word in an extension, add a file to the **ExtensionMessagesFiles**
attribute in extension.json,
and in that file, set a variable called **$magicWords**. This array is associative
with the language code in the first dimension key and an ID in the second key. The
third level array is numerically indexed: the element with key 0 contains the case
sensitivity flag, with 0 for case-insensitive and 1 for case-sensitive. The
subsequent elements of the array are the synonyms in the relevant language.
To add a magic word in core, add it to $magicWords in MessagesEn.php, following the
comment there.
For example, to add a new parser function in an extension: create a file called
**ExtensionName.i18n.magic.php** with the following contents:
```php
<?php
$magicWords = [];
$magicWords['en'] = [
// Case insensitive.
'mag_custom' => [ 0, 'custom' ],
];
$magicWords['es'] = [
'mag_custom' => [ 0, 'aduanero' ],
];
```
Then in extension.json:
```json
{
"ExtensionMessagesFiles": {
"ExtensionNameMagic": "ExtensionName.i18n.magic.php"
},
"Hooks": {
"ParserFirstCallInit": "MyExtensionHooks::onParserFirstCallInit"
}
}
```
It is important that the key "ExtensionNameMagic" is unique. It must not be used
by another extension.
And in the class file:
```php
<?php
class MyExtensionHooks {
public static function onParserFirstCallInit( $parser ) {
$parser->setFunctionHook( 'mag_custom', [ self::class, 'expandCustom' ] );
return true;
}
public static function expandCustom( $parser, $var1, $var2 ) {
return "custom: var1 is $var1, var2 is $var2";
}
}
```
- Online documentation (contains more informations):
- Magic words: <https://www.mediawiki.org/wiki/Manual:Magic_words>
- Variables: <https://www.mediawiki.org/wiki/Manual:Variable>
- Parser functions: <https://www.mediawiki.org/wiki/Manual:Parser_functions>

View File

@ -1,95 +0,0 @@
magicword.txt
Magic Words are some phrases used in the wikitext. They are used for two things:
* Variables (like {{PAGENAME}}, {{SERVER}}, ...): part of wikitext, that looks
like templates but that don't accept any parameter.
* Parser functions (like {{fullurl:...}}, {{#special:...}}): behaves like
functions and accepts parameters.
The localized arrays keys are the internal name, and the values are an array,
whose include their case-sensitivity and their alias forms. The first form
defined is used by the program, for example, when moving a page and its old name
should include #REDIRECT.
They can be added in several arrays:
* By adding a file to $wgExtensionMessagesFiles and defining there $magicWords.
This array is associative with the language code in the first dimension key
and then a "normal" array of magic words.
* Localized arrays (languages/messages/LanguageXX.php) include their different
names to be used by the users.
To add a new variable, you should use the "MagicWordwgVariableIDs" hook to add
the internal name to the $magicWords array. You'll need to define the value of
the variable with the "ParserGetVariableValueSwitch" hook.
For example to add a new variable:
Create a file called ExtensionName.i18n.magic.php with the following contents:
----
<?php
$magicWords = [];
$magicWords['en'] = [
// Case sensitive.
'mag_custom' => [ 1, 'CUSTOM' ],
];
$magicWords['es'] = [
'mag_custom' => [ 1, 'ADUANERO' ],
];
----
$wgExtensionMessagesFiles['ExtensionNameMagic'] = __DIR__ . '/ExtensionName.i18n.magic.php';
$wgHooks['MagicWordwgVariableIDs'][] = 'wfAddCustomMagicWordID';
$wgHooks['ParserGetVariableValueSwitch'][] = 'wfGetCustomMagicWordValue';
function wfAddCustomMagicWordID( &$magicWords ) {
$magicWords[] = 'mag_custom';
return true;
}
function wfGetCustomMagicWordValue( &$parser, &$varCache, &$index, &$ret ){
if( $index == 'mag_custom' ){
$ret = $varCache['mag_custom'] = "Custom value";
}
return true;
}
And to add a new parser function:
Create a file called ExtensionName.i18n.magic.php with the following contents:
----
<?php
$magicWords = [];
$magicWords['en'] = [
// Case insensitive.
'mag_custom' => [ 0, 'custom' ],
];
$magicWords['es'] = [
'mag_custom' => [ 0, 'aduanero' ],
];
----
$wgExtensionMessagesFiles['ExtensionNameMagic'] = __DIR__ . '/ExtensionName.i18n.magic.php';
$wgHooks['ParserFirstCallInit'][] = 'wfRegisterCustomMagicWord';
function wfRegisterCustomMagicWord( &$parser ){
$parser->setFunctionHook( 'mag_custom', 'wfGetCustomMagicWordValue' );
return true;
}
function wfGetCustomMagicWordValue( &$parser, $var1, $var2 ){
return "custom: var1 is $var1, var2 is $var2";
}
Note: the 'ParserFirstCallInit' hook is only available since 1.12. To work with
an older version, you'll need to use an extension function.
Online documentation (contains more informations):
Magic words: https://www.mediawiki.org/wiki/Manual:Magic_words
Variables: https://www.mediawiki.org/wiki/Manual:Variable
Parser functions: https://www.mediawiki.org/wiki/Manual:Parser_functions

255
docs/memcached.md Normal file
View File

@ -0,0 +1,255 @@
Memcached
====================================
MediaWiki has optional support for memcached, a "high-performance,
distributed memory object caching system". For general information
on it, see: <http://www.danga.com/memcached/>
Memcached is likely more trouble than a small site will need, but
for a larger site with heavy load, like Wikipedia, it should help
lighten the load on the database servers by caching data and objects
in memory.
Installation
--------------------------------
Packages are available for Fedora, Debian, Ubuntu and probably other
Linux distributions. If there's no package available for your
distribution, you can compile it from source.
Compilation
--------------------------------
* PHP must be compiled with --enable-sockets
* libevent: <http://www.monkey.org/~provos/libevent/>
(as of 2003-08-11, 0.7a is current)
* optionally, epoll-rt patch for Linux kernel:
<http://www.xmailserver.org/linux-patches/nio-improve.html>
* memcached: <http://www.danga.com/memcached/download.bml>
(as of this writing, 1.1.9 is current)
Memcached and libevent are under BSD-style licenses.
The server should run on Linux and other Unix-like systems... you
can run multiple servers on one machine or on multiple machines on
a network; storage can be distributed across multiple servers, and
multiple web servers can use the same cache cluster.
**W A R N I N G ! ! ! ! !**
Memcached has no security or authentication. Please ensure that your
server is appropriately firewalled, and that the port(s) used for
memcached servers are not publicly accessible. Otherwise, anyone on
the internet can put data into and read data from your cache.
An attacker familiar with MediaWiki internals could use this to steal
passwords and email addresses, or to make themselves a sysop and
install malicious javascript on the site. There may be other types
of vulnerability, no audit has been done -- so be safe and keep it
behind a firewall.
**W A R N I N G ! ! ! ! !**
Setup
--------------------------------
If you installed memcached using a distro, the daemon should be started
automatically using
/etc/init.d/memcached
To start the daemon manually, use something like:
memcached -d -l 127.0.0.1 -p 11211 -m 64
(to run in daemon mode, accessible only via loopback interface,
on port 11211, using up to 64MB of memory)
In your LocalSettings.php file, set:
```php
$wgMainCacheType = CACHE_MEMCACHED;
$wgMemCachedServers = [ "127.0.0.1:11211" ];
```
The wiki should then use memcached to cache various data. To use
multiple servers (physically separate boxes or multiple caches
on one machine on a large-memory x86 box), just add more items
to the array. To increase the weight of a server (say, because
it has twice the memory of the others and you want to spread
usage evenly), make its entry a subarray:
```php
$wgMemCachedServers = [
"127.0.0.1:11211", # one gig on this box
[ "192.168.0.1:11211", 2 ] # two gigs on the other box
];
```
PHP client for memcached
--------------------------------
MediaWiki uses a fork of Ryan T. Dean's pure-PHP memcached client.
It also supports the PECL PHP extension for memcached.
MediaWiki uses the ObjectCache class to retrieve instances of
BagOStuff by purpose, controlled by the following variables:
* $wgMainCacheType
* $wgParserCacheType
* $wgMessageCacheType
If you set one of these to CACHE_NONE, MediaWiki still creates a
BagOStuff object, but calls it to it are no-ops. If the cache daemon
can't be contacted, it should also disable itself fairly smoothly.
Keys used
--------------------------------
(incomplete, out of date)
Date Formatter:
key: $wgDBname:dateformatter
ex: wikidb:dateformatter
stores: a single instance of the DateFormatter class
cleared by: nothing
expiry: one hour
Difference Engine:
key: $wgDBname:diff:version:{MW_DIFF_VERSION}:oldid:$old:newid:$new
ex: wikidb:diff:version:1.11a:oldid:1:newid:2
stores: body of a difference
cleared by: nothing
expiry: one week
Interwiki:
key: $wgDBname:interwiki:$prefix
ex: wikidb:interwiki:w
stores: object from the interwiki table of the database
expiry: $wgInterwikiExpiry
cleared by: nothing
Lag time of the databases:
key: $wgDBname:lag_times
ex: wikidb:lag_times
stores: array mapping the database id to its lag time
expiry: 5 secondes
cleared by: nothing
Localisation:
key: $wgDBname:localisation:$lang
ex: wikidb:localisation:de
stores: array of localisation settings
set in: Language::loadLocalisation()
expiry: none
cleared by: Language::loadLocalisation()
Message Cache:
See MessageCache.php.
Newtalk:
key: $wgDBname:newtalk:ip:$ip
ex: wikidb:newtalk:ip:123.45.67.89
stores: integer, 0 or 1
set in: User::loadFromDatabase()
cleared by: User::saveSettings() # ?
expiry: 30 minutes
Parser Cache:
access: ParserCache
backend: $wgParserCacheType
key: $wgDBname:pcache:idhash:$pageid-$renderkey!$hash
$pageid: id of the page
$renderkey: 1 if action=render, 0 otherwise
$hash: hash of user options applied to the page, see ParserOptions::optionsHash()
ex: wikidb:pcache:idhash:1-0!1!0!!en!2
stores: ParserOutput object
modified by: WikiPage::doEditUpdates() or PoolWorkArticleView::doWork()
expiry: $wgParserCacheExpireTime or less if it contains short lived functions
key: $wgDBname:pcache:idoptions:$pageid
stores: CacheTime object with an additional list of used options for the hash,
serves as ParserCache pointer.
modified by: ParserCache::save()
expiry: The same as the ParserCache entry it points to.
Ping limiter:
controlled by: $wgRateLimits
key: $wgDBname:limiter:action:$action:ip:$ip,
$wgDBname:limiter:action:$action:user:$id,
mediawiki:limiter:action:$action:ip:$ip and
mediawiki:limiter:action:$action:subnet:$sub
ex: wikidb:limiter:action:edit:ip:123.45.67.89,
wikidb:limiter:action:edit:user:1012
mediawiki:limiter:action:edit:ip:123.45.67.89 and
mediawiki:limiter:action:$action:subnet:123.45.67
stores: number of action made by user/ip/subnet
cleared by: nothing
expiry: expiry set for the action and group in $wgRateLimits
Proxy Check: (deprecated)
key: $wgDBname:proxy:ip:$ip
ex: wikidb:proxy:ip:123.45.67.89
stores: 1 if the ip is a proxy
cleared by: nothing
expiry: $wgProxyMemcExpiry
Revision text:
key: $wgDBname:revisiontext:textid:$id
ex: wikidb:revisiontext:textid:1012
stores: text of a revision
cleared by: nothing
expiry: $wgRevisionCacheExpiry
Sessions:
controlled by: $wgSessionsInObjectCache
key: $wgBDname:session:$id
ex: wikidb:session:38d7c5b8d3bfc51egf40c69bc40f8be3
stores: $SESSION, useful when using a multi-sever wiki
expiry: one hour
cleared by: session_destroy()
Sidebar:
access: WANObjectCache
controlled by: $wgEnableSidebarCache
key: $wgDBname:sidebar
ex: wikidb:sidebar
stores: the html output of the sidebar
expiry: $wgSidebarCacheExpiry
cleared by: MessageCache::replace()
Special:Allpages:
key: $wgDBname:allpages:ns:$ns
ex: wikidb:allpages:ns:0
stores: array of pages in a namespace
expiry: one hour
cleared by: nothing
Special:Recentchanges (feed):
backend: $wgMessageCacheType
key: $wgDBname:rcfeed:$format:$limit:$hideminor:$target and
rcfeed:$format:timestamp
ex: wikidb:rcfeed:rss:50:: and rcfeed:rss:timestamp
stores: xml output of feed
expiry: one day
clear by: maintenance/rebuildrecentchanges.php script, or
calling Special:Recentchanges?action=purge&feed=rss,
Special:Recentchanges?action=purge&feed=atom,
but note need $wgGroupPermissions[...]['purge'] permission.
... more to come ...

View File

@ -1,227 +0,0 @@
MediaWiki has optional support for memcached, a "high-performance,
distributed memory object caching system". For general information
on it, see: http://www.danga.com/memcached/
Memcached is likely more trouble than a small site will need, but
for a larger site with heavy load, like Wikipedia, it should help
lighten the load on the database servers by caching data and objects
in memory.
== Installation ==
Packages are available for Fedora, Debian, Ubuntu and probably other
Linux distributions. If there's no package available for your
distribution, you can compile it from source.
== Compilation ==
* PHP must be compiled with --enable-sockets
* libevent: http://www.monkey.org/~provos/libevent/
(as of 2003-08-11, 0.7a is current)
* optionally, epoll-rt patch for Linux kernel:
http://www.xmailserver.org/linux-patches/nio-improve.html
* memcached: http://www.danga.com/memcached/download.bml
(as of this writing, 1.1.9 is current)
Memcached and libevent are under BSD-style licenses.
The server should run on Linux and other Unix-like systems... you
can run multiple servers on one machine or on multiple machines on
a network; storage can be distributed across multiple servers, and
multiple web servers can use the same cache cluster.
********************* W A R N I N G ! ! ! ! ! ***********************
Memcached has no security or authentication. Please ensure that your
server is appropriately firewalled, and that the port(s) used for
memcached servers are not publicly accessible. Otherwise, anyone on
the internet can put data into and read data from your cache.
An attacker familiar with MediaWiki internals could use this to steal
passwords and email addresses, or to make themselves a sysop and
install malicious javascript on the site. There may be other types
of vulnerability, no audit has been done -- so be safe and keep it
behind a firewall.
********************* W A R N I N G ! ! ! ! ! ***********************
== Setup ==
If you installed memcached using a distro, the daemon should be started
automatically using /etc/init.d/memcached.
To start the daemon manually, use something like:
memcached -d -l 127.0.0.1 -p 11211 -m 64
(to run in daemon mode, accessible only via loopback interface,
on port 11211, using up to 64MB of memory)
In your LocalSettings.php file, set:
$wgMainCacheType = CACHE_MEMCACHED;
$wgMemCachedServers = [ "127.0.0.1:11211" ];
The wiki should then use memcached to cache various data. To use
multiple servers (physically separate boxes or multiple caches
on one machine on a large-memory x86 box), just add more items
to the array. To increase the weight of a server (say, because
it has twice the memory of the others and you want to spread
usage evenly), make its entry a subarray:
$wgMemCachedServers = [
"127.0.0.1:11211", # one gig on this box
[ "192.168.0.1:11211", 2 ] # two gigs on the other box
];
== PHP client for memcached ==
MediaWiki uses a fork of Ryan T. Dean's pure-PHP memcached client.
It also supports the PECL PHP extension for memcached.
MediaWiki uses the ObjectCache class to retrieve instances of
BagOStuff by purpose, controlled by the following variables:
* $wgMainCacheType
* $wgParserCacheType
* $wgMessageCacheType
If you set one of these to CACHE_NONE, MediaWiki still creates a
BagOStuff object, but calls it to it are no-ops. If the cache daemon
can't be contacted, it should also disable itself fairly smoothly.
== Keys used ==
(incomplete, out of date)
Date Formatter:
key: $wgDBname:dateformatter
ex: wikidb:dateformatter
stores: a single instance of the DateFormatter class
cleared by: nothing
expiry: one hour
Difference Engine:
key: $wgDBname:diff:version:{MW_DIFF_VERSION}:oldid:$old:newid:$new
ex: wikidb:diff:version:1.11a:oldid:1:newid:2
stores: body of a difference
cleared by: nothing
expiry: one week
Interwiki:
key: $wgDBname:interwiki:$prefix
ex: wikidb:interwiki:w
stores: object from the interwiki table of the database
expiry: $wgInterwikiExpiry
cleared by: nothing
Lag time of the databases:
key: $wgDBname:lag_times
ex: wikidb:lag_times
stores: array mapping the database id to its lag time
expiry: 5 secondes
cleared by: nothing
Localisation:
key: $wgDBname:localisation:$lang
ex: wikidb:localisation:de
stores: array of localisation settings
set in: Language::loadLocalisation()
expiry: none
cleared by: Language::loadLocalisation()
Message Cache:
See MessageCache.php.
Newtalk:
key: $wgDBname:newtalk:ip:$ip
ex: wikidb:newtalk:ip:123.45.67.89
stores: integer, 0 or 1
set in: User::loadFromDatabase()
cleared by: User::saveSettings() # ?
expiry: 30 minutes
Parser Cache:
access: ParserCache
backend: $wgParserCacheType
key: $wgDBname:pcache:idhash:$pageid-$renderkey!$hash
$pageid: id of the page
$renderkey: 1 if action=render, 0 otherwise
$hash: hash of user options applied to the page, see ParserOptions::optionsHash()
ex: wikidb:pcache:idhash:1-0!1!0!!en!2
stores: ParserOutput object
modified by: WikiPage::doEditUpdates() or PoolWorkArticleView::doWork()
expiry: $wgParserCacheExpireTime or less if it contains short lived functions
key: $wgDBname:pcache:idoptions:$pageid
stores: CacheTime object with an additional list of used options for the hash,
serves as ParserCache pointer.
modified by: ParserCache::save()
expiry: The same as the ParserCache entry it points to.
Ping limiter:
controlled by: $wgRateLimits
key: $wgDBname:limiter:action:$action:ip:$ip,
$wgDBname:limiter:action:$action:user:$id,
mediawiki:limiter:action:$action:ip:$ip and
mediawiki:limiter:action:$action:subnet:$sub
ex: wikidb:limiter:action:edit:ip:123.45.67.89,
wikidb:limiter:action:edit:user:1012
mediawiki:limiter:action:edit:ip:123.45.67.89 and
mediawiki:limiter:action:$action:subnet:123.45.67
stores: number of action made by user/ip/subnet
cleared by: nothing
expiry: expiry set for the action and group in $wgRateLimits
Proxy Check: (deprecated)
key: $wgDBname:proxy:ip:$ip
ex: wikidb:proxy:ip:123.45.67.89
stores: 1 if the ip is a proxy
cleared by: nothing
expiry: $wgProxyMemcExpiry
Revision text:
key: $wgDBname:revisiontext:textid:$id
ex: wikidb:revisiontext:textid:1012
stores: text of a revision
cleared by: nothing
expiry: $wgRevisionCacheExpiry
Sessions:
controlled by: $wgSessionsInObjectCache
key: $wgBDname:session:$id
ex: wikidb:session:38d7c5b8d3bfc51egf40c69bc40f8be3
stores: $SESSION, useful when using a multi-sever wiki
expiry: one hour
cleared by: session_destroy()
Sidebar:
access: WANObjectCache
controlled by: $wgEnableSidebarCache
key: $wgDBname:sidebar
ex: wikidb:sidebar
stores: the html output of the sidebar
expiry: $wgSidebarCacheExpiry
cleared by: MessageCache::replace()
Special:Allpages:
key: $wgDBname:allpages:ns:$ns
ex: wikidb:allpages:ns:0
stores: array of pages in a namespace
expiry: one hour
cleared by: nothing
Special:Recentchanges (feed):
backend: $wgMessageCacheType
key: $wgDBname:rcfeed:$format:$limit:$hideminor:$target and
rcfeed:$format:timestamp
ex: wikidb:rcfeed:rss:50:: and rcfeed:rss:timestamp
stores: xml output of feed
expiry: one day
clear by: maintenance/rebuildrecentchanges.php script, or
calling Special:Recentchanges?action=purge&feed=rss,
Special:Recentchanges?action=purge&feed=atom,
but note need $wgGroupPermissions[...]['purge'] permission.
... more to come ...

135
docs/pageupdater.md Normal file
View File

@ -0,0 +1,135 @@
PageUpdater
===========
This document provides an overview of the usage of PageUpdater and DerivedPageDataUpdater.
## `PageUpdater`
`PageUpdater` is the canonical way to create page revisions, that is, to perform edits.
`PageUpdater` is a stateful, handle-like object that allows new revisions to be created on a given wiki page using the `saveRevision()` method. `PageUpdater` provides setters for defining the new revision's content as well as meta-data such as change tags. `saveRevision()` stores the new revision's primary content and metadata, and triggers the necessary updates to derived secondary data and cached artifacts e.g. in the `ParserCache` and the CDN layer, using a `DerivedPageDataUpdater`.
`PageUpdater` instances follow the below life cycle, defined by a number of methods:
+----------------------------+
| |
| new |
| |
+------|--------------|------+
| |
grabParentRevision()-| |
or hasEditConflict()-| |
| |
+--------v-------+ |
| | |
| parent known | |
| | |
Enables---------------+--------|-------+ |
safe operations based on | |-saveRevision()
the parent revision, e.g. | |
section replacement or | |
edit conflict resolution. | |
| |
saveRevision()-| |
| |
+------v--------------v------+
| |
| creation committed |
| |
Enables-----------------+----------------------------+
wasSuccess()
isUnchanged()
isNew()
getState()
getNewRevision()
etc.
The stateful nature of `PageUpdater` allows it to be used to safely perform transformations that depend on the new revision's parent revision, such as replacing sections or applying 3-way conflict resolution, while protecting against race conditions using a compare-and-swap (CAS) mechanism: after calling code used the `grabParentRevision()` method to access the edit's logical parent, `PageUpdater` remembers that revision, and ensure that that revision is still the page's current revision when performing the atomic database update for the revision's primary meta-data when `saveRevision()` is called. If another revision was created concurrently, `saveRevision()` will fail, indicating the problem with the "edit-conflict" code in the status object.
Typical usage for programmatic revision creation (with `$page` being a WikiPage as of 1.32, to be replaced by a repository service later):
```php
$updater = $page->newPageUpdater( $user );
$updater->setContent( SlotRecord::MAIN, $content );
$updater->setRcPatrolStatus( RecentChange::PRC_PATROLLED );
$newRev = $updater->saveRevision( $comment );
```
Usage with content depending on the parent revision
```php
$updater = $page->newPageUpdater( $user );
$parent = $updater->grabParentRevision();
$content = $parent->getContent( SlotRecord::MAIN )->replaceSection( $section, $sectionContent );
$updater->setContent( SlotRecord::MAIN, $content );
$newRev = $updater->saveRevision( $comment, EDIT_UPDATE );
```
In both cases, all secondary updates will be triggered automatically.
# `DerivedPageDataUpdater`
`DerivedPageDataUpdater` is a stateful, handle-like object that caches derived data representing a revision, and can trigger updates of cached copies of that data, e.g. in the links tables, `page_props`, the `ParserCache`, and the CDN layer.
`DerivedPageDataUpdater` is used by `PageUpdater` when creating new revisions, but can also be used independently when performing meta data updates during undeletion, import, or when puring a page. It's a stepping stone on the way to a more complete refactoring of WikiPage.
**NOTE**: Avoid direct usage of `DerivedPageDataUpdater`. In the future, we want to define interfaces for the different use cases of `DerivedPageDataUpdater`, particularly providing access to post-PST content and `ParserOutput` to callbacks during revision creation, which currently use `WikiPage::prepareContentForEdit`, and allowing updates to be triggered on purge, import, and undeletion, which currently use `WikiPage::doEditUpdates()` and `Content::getSecondaryDataUpdates()`.
The primary reason for `DerivedPageDataUpdater` to be stateful is internal caching of state that avoids the re-generation of `ParserOutput` and re-application of pre-save-transformations (PST).
`DerivedPageDataUpdater` instances follow the below life cycle, defined by a number of methods:
+---------------------------------------------------------------------+
| |
| new |
| |
+---------------|------------------|------------------|---------------+
| | |
grabCurrentRevision()-| | |
| | |
+-----------v----------+ | |
| | |-prepareContent() |
| knows current | | |
| | | |
Enables------------------+-----|-----|----------+ | |
pageExisted() | | | |
wasRedirect() | |-prepareContent() | |-prepareUpdate()
| | | |
| | +-------------v------------+ |
| | | | |
| +----> has content | |
| | | |
Enables------------------------|----------+--------------------------+ |
isChange() | | |
isCreation() |-prepareUpdate() | |
getSlots() | prepareUpdate()-| |
getTouchedSlotRoles() | | |
getCanonicalParserOutput() | +-----------v------------v-----------------+
| | |
+------------------> has revision |
| |
Enables-------------------------------------------+------------------------|-----------------+
updateParserCache() |
runSecondaryDataUpdates() |-doUpdates()
|
+-----------v---------+
| |
| updates done |
| |
+---------------------+
- `grabCurrentRevision()` returns the logical parent revision of the target revision. It is guaranteed to always return the same revision for a given `DerivedPageDataUpdater` instance. If called before `prepareUpdate()`, this fixates the logical parent to be the page's current revision. If called for the first time after `prepareUpdate()`, it returns the revision passed as the 'oldrevision' option to `prepareUpdate()`, or, if that wasn't given, the parent of $revision parameter passed to `prepareUpdate()`.
- `prepareContent()` is called before the new revision is created, to apply pre-save-transformation (PST) and allow subsequent access to the canonical `ParserOutput` of the revision. `getSlots()` and `getCanonicalParserOutput()` as well as `getSecondaryDataUpdates()` may be used after `prepareContent()` was called. Calling `prepareContent()` with the same parameters again has no effect. Calling it again with mismatching parameters, or calling it after `prepareUpdate()` was called, triggers a `LogicException`.
- `prepareUpdate()` is called after the new revision has been created. This may happen right after the revision was created, on the same instance on which `prepareContent()` was called, or later (possibly much later), on a fresh instance in a different process, due to deferred or asynchronous updates, or during import, undeletion, purging, etc. `prepareUpdate()` is required before a call to `doUpdates()`, and it also enables calls to `getSlots()` and `getCanonicalParserOutput()` as well as `getSecondaryDataUpdates()`. Calling `prepareUpdate()` with the same parameters again has no effect. Calling it again with mismatching parameters, or calling it with parameters mismatching the ones `prepareContent()` was called with, triggers a `LogicException`.
- `getSecondaryDataUpdates()` returns `DataUpdates` that represent derived data for the revision. These may be used to update such data, e.g. in `ApiPurge`, `RefreshLinksJob`, and the `refreshLinks` script.
- `doUpdates()` triggers the updates defined by `getSecondaryDataUpdates()`, and also causes updates to cached artifacts in the `ParserCache`, the CDN layer, etc. This is primarily used by PageUpdater, but also by `PageArchive` during undeletion, and when importing revisions from XML. `doUpdates()` can only be called after `prepareUpdate()` was used to initialize the `DerivedPageDataUpdater` instance for a specific revision. Calling it before `prepareUpdate()` is called raises a `LogicException`.
A `DerivedPageDataUpdater` instance is intended to be re-used during different stages of complex update operations that often involve callbacks to extension code via
MediaWiki's hook mechanism, or deferred or even asynchronous execution of Jobs and `DeferredUpdates`. Since these mechanisms typically do not provide a way to pass a
`DerivedPageDataUpdater` directly, `WikiPage::getDerivedPageDataUpdater()` has to be used to obtain a `DerivedPageDataUpdater` for the update currently in progress - re-using the same `DerivedPageDataUpdater` if possible avoids re-generation of `ParserOutput` objects
and other expensively derived artifacts.
This mechanism for re-using a `DerivedPageDataUpdater` instance without passing it directly requires a way to ensure that a given `DerivedPageDataUpdater` instance can actually be used in the calling code's context. For this purpose, `WikiPage::getDerivedPageDataUpdater()` calls the `isReusableFor()` method on `DerivedPageDataUpdater`, which ensures that the given instance is applicable to the given parameters. In other words, `isReusableFor()` predicts whether calling `prepareContent()` or `prepareUpdate()` with a given set of parameters will trigger a `LogicException.` In that case, `WikiPage::getDerivedPageDataUpdater()` creates a fresh `DerivedPageDataUpdater` instance.

View File

@ -1,191 +0,0 @@
This document provides an overview of the usage of PageUpdater and DerivedPageDataUpdater.
== PageUpdater ==
PageUpdater is the canonical way to create page revisions, that is, to perform edits.
PageUpdater is a stateful, handle-like object that allows new revisions to be created
on a given wiki page using the saveRevision() method. PageUpdater provides setters for
defining the new revision's content as well as meta-data such as change tags. saveRevision()
stores the new revision's primary content and metadata, and triggers the necessary
updates to derived secondary data and cached artifacts e.g. in the ParserCache and the
CDN layer, using a DerivedPageDataUpdater.
PageUpdater instances follow the below life cycle, defined by a number of
methods:
+----------------------------+
| |
| new |
| |
+------|--------------|------+
| |
grabParentRevision()-| |
or hasEditConflict()-| |
| |
+--------v-------+ |
| | |
| parent known | |
| | |
Enables---------------+--------|-------+ |
safe operations based on | |-saveRevision()
the parent revision, e.g. | |
section replacement or | |
edit conflict resolution. | |
| |
saveRevision()-| |
| |
+------v--------------v------+
| |
| creation committed |
| |
Enables-----------------+----------------------------+
wasSuccess()
isUnchanged()
isNew()
getState()
getNewRevision()
etc.
The stateful nature of PageUpdater allows it to be used to safely perform
transformations that depend on the new revision's parent revision, such as replacing
sections or applying 3-way conflict resolution, while protecting against race
conditions using a compare-and-swap (CAS) mechanism: after calling code used the
grabParentRevision() method to access the edit's logical parent, PageUpdater
remembers that revision, and ensure that that revision is still the page's current
revision when performing the atomic database update for the revision's primary
meta-data when saveRevision() is called. If another revision was created concurrently,
saveRevision() will fail, indicating the problem with the "edit-conflict" code in the status
object.
Typical usage for programmatic revision creation (with $page being a WikiPage as of 1.32, to be
replaced by a repository service later):
$updater = $page->newPageUpdater( $user );
$updater->setContent( SlotRecord::MAIN, $content );
$updater->setRcPatrolStatus( RecentChange::PRC_PATROLLED );
$newRev = $updater->saveRevision( $comment );
Usage with content depending on the parent revision
$updater = $page->newPageUpdater( $user );
$parent = $updater->grabParentRevision();
$content = $parent->getContent( SlotRecord::MAIN )->replaceSection( $section, $sectionContent );
$updater->setContent( SlotRecord::MAIN, $content );
$newRev = $updater->saveRevision( $comment, EDIT_UPDATE );
In both cases, all secondary updates will be triggered automatically.
== DerivedPageDataUpdater ==
DerivedPageDataUpdater is a stateful, handle-like object that caches derived data representing
a revision, and can trigger updates of cached copies of that data, e.g. in the links tables,
page_props, the ParserCache, and the CDN layer.
DerivedPageDataUpdater is used by PageUpdater when creating new revisions, but can also
be used independently when performing meta data updates during undeletion, import, or
when puring a page. It's a stepping stone on the way to a more complete refactoring of WikiPage.
NOTE: Avoid direct usage of DerivedPageDataUpdater. In the future, we want to define interfaces
for the different use cases of DerivedPageDataUpdater, particularly providing access to post-PST
content and ParserOutput to callbacks during revision creation, which currently use
WikiPage::prepareContentForEdit, and allowing updates to be triggered on purge, import, and
undeletion, which currently use WikiPage::doEditUpdates() and Content::getSecondaryDataUpdates().
The primary reason for DerivedPageDataUpdater to be stateful is internal caching of state
that avoids the re-generation of ParserOutput and re-application of pre-save-
transformations (PST).
DerivedPageDataUpdater instances follow the below life cycle, defined by a number of
methods:
+---------------------------------------------------------------------+
| |
| new |
| |
+---------------|------------------|------------------|---------------+
| | |
grabCurrentRevision()-| | |
| | |
+-----------v----------+ | |
| | |-prepareContent() |
| knows current | | |
| | | |
Enables------------------+-----|-----|----------+ | |
pageExisted() | | | |
wasRedirect() | |-prepareContent() | |-prepareUpdate()
| | | |
| | +-------------v------------+ |
| | | | |
| +----> has content | |
| | | |
Enables------------------------|----------+--------------------------+ |
isChange() | | |
isCreation() |-prepareUpdate() | |
getSlots() | prepareUpdate()-| |
getTouchedSlotRoles() | | |
getCanonicalParserOutput() | +-----------v------------v-----------------+
| | |
+------------------> has revision |
| |
Enables-------------------------------------------+------------------------|-----------------+
updateParserCache() |
runSecondaryDataUpdates() |-doUpdates()
|
+-----------v---------+
| |
| updates done |
| |
+---------------------+
- grabCurrentRevision() returns the logical parent revision of the target revision. It is
guaranteed to always return the same revision for a given DerivedPageDataUpdater instance.
If called before prepareUpdate(), this fixates the logical parent to be the page's current
revision. If called for the first time after prepareUpdate(), it returns the revision
passed as the 'oldrevision' option to prepareUpdate(), or, if that wasn't given, the
parent of $revision parameter passed to prepareUpdate().
- prepareContent() is called before the new revision is created, to apply pre-save-
transformation (PST) and allow subsequent access to the canonical ParserOutput of the
revision. getSlots() and getCanonicalParserOutput() as well as getSecondaryDataUpdates()
may be used after prepareContent() was called. Calling prepareContent() with the same
parameters again has no effect. Calling it again with mismatching parameters, or calling
it after prepareUpdate() was called, triggers a LogicException.
- prepareUpdate() is called after the new revision has been created. This may happen
right after the revision was created, on the same instance on which prepareContent() was
called, or later (possibly much later), on a fresh instance in a different process,
due to deferred or asynchronous updates, or during import, undeletion, purging, etc.
prepareUpdate() is required before a call to doUpdates(), and it also enables calls to
getSlots() and getCanonicalParserOutput() as well as getSecondaryDataUpdates().
Calling prepareUpdate() with the same parameters again has no effect.
Calling it again with mismatching parameters, or calling it with parameters mismatching
the ones prepareContent() was called with, triggers a LogicException.
- getSecondaryDataUpdates() returns DataUpdates that represent derived data for the revision.
These may be used to update such data, e.g. in ApiPurge, RefreshLinksJob, and the refreshLinks
script.
- doUpdates() triggers the updates defined by getSecondaryDataUpdates(), and also causes
updates to cached artifacts in the ParserCache, the CDN layer, etc. This is primarily
used by PageUpdater, but also by PageArchive during undeletion, and when importing
revisions from XML. doUpdates() can only be called after prepareUpdate() was used to
initialize the DerivedPageDataUpdater instance for a specific revision. Calling it before
prepareUpdate() is called raises a LogicException.
A DerivedPageDataUpdater instance is intended to be re-used during different stages
of complex update operations that often involve callbacks to extension code via
MediaWiki's hook mechanism, or deferred or even asynchronous execution of Jobs and
DeferredUpdates. Since these mechanisms typically do not provide a way to pass a
DerivedPageDataUpdater directly, WikiPage::getDerivedPageDataUpdater() has to be used to
obtain a DerivedPageDataUpdater for the update currently in progress - re-using the
same DerivedPageDataUpdater if possible avoids re-generation of ParserOutput objects
and other expensively derived artifacts.
This mechanism for re-using a DerivedPageDataUpdater instance without passing it directly
requires a way to ensure that a given DerivedPageDataUpdater instance can actually be used
in the calling code's context. For this purpose, WikiPage::getDerivedPageDataUpdater()
calls the isReusableFor() method on DerivedPageDataUpdater, which ensures that the given
instance is applicable to the given parameters. In other words, isReusableFor() predicts
whether calling prepareContent() or prepareUpdate() with a given set of parameters will
trigger a LogicException. In that case, WikiPage::getDerivedPageDataUpdater() creates a
fresh DerivedPageDataUpdater instance.

View File

@ -1,28 +0,0 @@
09 Oct 2003:
1455 UTC:
Released version 0.1.2
Fixed bug in get_multi; when debugging was enabled but no keys were fetched,
script execution would halt (uninitialized $val)
08 Oct 2003:
1848 UTC:
Released version 0.1.1
1825 UTC:
Fixed bug in memcached::memcached; was attempting to initialize
memcached::_dead_sock (function) instead of memcached::_dead_hosts
(oops!)
1812 UTC:
Fixed memcached::enable_compression;
thanks to Justin Matlock <jmat@shutdown.net> for pointing it out
07 Oct 2003:
1635 UTC:
Fixed call to memcached::_dead_sock in memcached::delete
Added documentation for class variable $_buckets
06 Oct 2003:
2039 UTC:
Initial release of memcached-client-php; version 0.1

View File

@ -1,258 +0,0 @@
Ryan Gilfether <hotrodder@rocketmail.com>
http://www.gilfether.com
This module is Copyright (c) 2003 Ryan Gilfether.
All rights reserved.
You may distribute under the terms of the GNU General Public License
This is free software. IT COMES WITHOUT WARRANTY OF ANY KIND.
See the memcached website: http://www.danga.com/memcached/
// Takes one parameter, a array of options. The most important key is
// options["servers"], but that can also be set later with the set_servers()
// method. The servers must be an array of hosts, each of which is
// either a scalar of the form <10.0.0.10:11211> or an array of the
// former and an integer weight value. (the default weight if
// unspecified is 1.) It's recommended that weight values be kept as low
// as possible, as this module currently allocates memory for bucket
// distribution proportional to the total host weights.
// $options["debug"] turns the debugging on if set to true
MemCachedClient::MemCachedClient($options);
// sets up the list of servers and the ports to connect to
// takes an array of servers in the same format as in the constructor
MemCachedClient::set_servers($servers);
// Retrieves a key from the memcache. Returns the value (automatically
// unserialized, if necessary) or FALSE if it fails.
// The $key can optionally be an array, with the first element being the
// hash value, if you want to avoid making this module calculate a hash
// value. You may prefer, for example, to keep all of a given user's
// objects on the same memcache server, so you could use the user's
// unique id as the hash value.
// Possible errors set are:
// MC_ERR_GET
MemCachedClient::get($key);
// just like get(), but takes an array of keys, returns FALSE on error
// Possible errors set are:
// MC_ERR_NOT_ACTIVE
MemCachedClient::get_multi($keys)
// Unconditionally sets a key to a given value in the memcache. Returns true
// if it was stored successfully.
// The $key can optionally be an arrayref, with the first element being the
// hash value, as described above.
// returns TRUE on success else FALSE
// Possible errors set are:
// MC_ERR_NOT_ACTIVE
// MC_ERR_GET_SOCK
// MC_ERR_SOCKET_WRITE
// MC_ERR_SOCKET_READ
// MC_ERR_SET
MemCachedClient::set($key, $value, $exptime);
// Like set(), but only stores in memcache if the key doesn't already exist.
// returns TRUE on success else FALSE
// Possible errors set are:
// MC_ERR_NOT_ACTIVE
// MC_ERR_GET_SOCK
// MC_ERR_SOCKET_WRITE
// MC_ERR_SOCKET_READ
// MC_ERR_SET
MemCachedClient::add($key, $value, $exptime);
// Like set(), but only stores in memcache if the key already exists.
// returns TRUE on success else FALSE
// Possible errors set are:
// MC_ERR_NOT_ACTIVE
// MC_ERR_GET_SOCK
// MC_ERR_SOCKET_WRITE
// MC_ERR_SOCKET_READ
// MC_ERR_SET
MemCachedClient::replace($key, $value, $exptime);
// removes the key from the MemCache
// $time is the amount of time in seconds (or Unix time) until which
// the client wishes the server to refuse "add" and "replace" commands
// with this key. For this amount of item, the item is put into a
// delete queue, which means that it won't possible to retrieve it by
// the "get" command, but "add" and "replace" command with this key
// will also fail (the "set" command will succeed, however). After the
// time passes, the item is finally deleted from server memory.
// The parameter $time is optional, and, if absent, defaults to 0
// (which means that the item will be deleted immediately and further
// storage commands with this key will succeed).
// returns TRUE on success else returns FALSE
// Possible errors set are:
// MC_ERR_NOT_ACTIVE
// MC_ERR_GET_SOCK
// MC_ERR_SOCKET_WRITE
// MC_ERR_SOCKET_READ
// MC_ERR_DELETE
MemCachedClient::delete($key, $time = 0);
// Sends a command to the server to atomically increment the value for
// $key by $value, or by 1 if $value is undefined. Returns FALSE if $key
// doesn't exist on server, otherwise it returns the new value after
// incrementing. Value should be zero or greater. Overflow on server
// is not checked. Be aware of values approaching 2**32. See decr.
// Possible errors set are:
// MC_ERR_NOT_ACTIVE
// MC_ERR_GET_SOCK
// MC_ERR_SOCKET_WRITE
// MC_ERR_SOCKET_READ
// returns new value on success, else returns FALSE
// ONLY WORKS WITH NUMERIC VALUES
MemCachedClient::incr($key[, $value]);
// Like incr, but decrements. Unlike incr, underflow is checked and new
// values are capped at 0. If server value is 1, a decrement of 2
// returns 0, not -1.
// Possible errors set are:
// MC_ERR_NOT_ACTIVE
// MC_ERR_GET_SOCK
// MC_ERR_SOCKET_WRITE
// MC_ERR_SOCKET_READ
// returns new value on success, else returns FALSE
// ONLY WORKS WITH NUMERIC VALUES
MemCachedClient::decr($key[, $value]);
// disconnects from all servers
MemCachedClient::disconnect_all();
// if $do_debug is set to true, will print out
// debugging info, else debug is turned off
MemCachedClient::set_debug($do_debug);
// remove all cached hosts that are no longer good
MemCachedClient::forget_dead_hosts();
// When a function returns FALSE, an error code is set.
// This function will return the error code.
// See error_string()
// returns last error code set
MemCachedClient::error()
// Returns a string describing the error set in error()
// See error()
// returns a string describing the error code given
MemCachedClient::error_string()
// Resets the error number and error string
MemCachedClient::error_clear()
Error codes are as follows:
MC_ERR_NOT_ACTIVE // no active servers
MC_ERR_SOCKET_WRITE // socket_write() failed
MC_ERR_SOCKET_READ // socket_read() failed
MC_ERR_SOCKET_CONNECT // failed to connect to host
MC_ERR_DELETE // delete() did not recieve DELETED command
MC_ERR_HOST_FORMAT // sock_to_host() invalid host format
MC_ERR_HOST_DEAD // sock_to_host() host is dead
MC_ERR_GET_SOCK // get_sock() failed to find a valid socket
MC_ERR_SET // _set() failed to receive the STORED response
MC_ERR_LOADITEM_HEADER // _load_items failed to receive valid data header
MC_ERR_LOADITEM_END // _load_items failed to receive END response
MC_ERR_LOADITEM_BYTES // _load_items bytes read larger than bytes available
MC_ERR_GET // failed to get value associated with key
// Turns compression on or off; 0=off, 1=on
MemCacheClient::set_compression($setting)
EXAMPLE:
<?php
require 'MemCachedClient.inc.php';
// set the servers, with the last one having an integer weight value of 3
$options["servers"] = ["10.0.0.15:11000","10.0.0.16:11001",["10.0.0.17:11002", 3]];
$options["debug"] = false;
$memc = new MemCachedClient($options);
/***********************
* STORE AN ARRAY
***********************/
$myarr = ["one","two", 3];
$memc->set("key_one", $myarr);
$val = $memc->get("key_one");
print $val[0]."\n"; // prints 'one'
print $val[1]."\n"; // prints 'two'
print $val[2]."\n"; // prints 3
print "\n";
/***********************
* STORE A CLASS
***********************/
class tester
{
var $one;
var $two;
var $three;
}
$t = new tester;
$t->one = "one";
$t->two = "two";
$t->three = 3;
$memc->set("key_two", $t);
$val = $memc->get("key_two");
print $val->one."\n";
print $val->two."\n";
print $val->three."\n";
print "\n";
/***********************
* STORE A STRING
***********************/
$memc->set("key_three", "my string");
$val = $memc->get("key_three");
print $val; // prints 'my string'
$memc->delete("key_one");
$memc->delete("key_two");
$memc->delete("key_three");
$memc->disconnect_all();
print "\n";
/***********************
* STORE A BINARY FILE
***********************/
// first read the file and save it in memcache
$fp = fopen( "./image.jpg", "rb" ) ;
if ( !$fp )
{
print "Could not open ./file.dat!\n" ;
exit ;
}
$data = fread( $fp, filesize( "./image.jpg" ) ) ;
fclose( $fp ) ;
print "Data length is " . strlen( $data ) . "\n" ;
$memc->set( "key", $data ) ;
// now open a file for writing and write the data
// retrieved from memcache
$fp = fopen("./test.jpg","wb");
$data = $memc->get( "key" ) ;
print "Data length is " . strlen( $data ) . "\n" ;
fwrite($fp,$data,strlen( $data ));
fclose($fp);
?>

View File

@ -1 +0,0 @@
HTML documentation is under http://phpca.cytherianage.net/memcached/doc/

12
docs/schema.md Normal file
View File

@ -0,0 +1,12 @@
Schema
======
The most up-to-date schema for the tables in the database
will always be `tables.sql` in the maintenance directory,
which is called from the installation script.
That file has been commented with details of the usage for
each table and field.
Historical information and some other notes are available at
<https://www.mediawiki.org/wiki/Manual:Database_layout>.

View File

@ -1,9 +0,0 @@
The most up-to-date schema for the tables in the database
will always be "tables.sql" in the maintenance directory,
which is called from the installation script.
That file has been commented with details of the usage for
each table and field.
Historical information and some other notes are available at
https://www.mediawiki.org/wiki/Manual:Database_layout

View File

@ -1,38 +0,0 @@
scripts.txt
MediaWiki primary scripts are in the root directory of the software. Users
should only use these scripts to access the wiki. There are also some .php that
aren't primary scripts but helper files and won't work if they are accessed
directly by the web.
Primary scripts:
index.php
Main access point. It handles the most of requests.
See https://www.mediawiki.org/wiki/Manual:Index.php
api.php
Script to provide an API for bots to fetch content and informations about
the site and also modify it. See https://www.mediawiki.org/wiki/API
for more information.
img_auth.php
Script that only serve images to logged in users. To configure the wiki
to use that script, see https://www.mediawiki.org/wiki/Manual:Image_Authorisation.
load.php
Used by ResourceLoader to serve minified, concatenated and gzipped CSS and JS.
opensearch_desc.php
Returns a OpenSearch description document (see http://www.opensearch.org/)
that points to the search engines of the wiki.
profileinfo.php
Simple interface for displaying request profiles that were stored in the
database. For more information, see the documentation in that file, and at
https://www.mediawiki.org/wiki/Manual:Profiling.
thumb.php
Script used to resize images if it is configured to be done when the web
browser requests the image and not when generating the page. This script can
be used as a 404 handler to generate image thumbs when they don't exist.

45
docs/sitelist.md Normal file
View File

@ -0,0 +1,45 @@
Sitelist
========
This document describes the XML format used to represent information about external sites known to a MediaWiki installation. This information about external sites is used to allow "inter-wiki" links, cross-language navigation, as well as close integration via direct access to the other site's web API or even directly to their database.
Lists of external sites can be imported and exported using the *importSites.php* and *exportSites.php* scripts. In the database, external sites are described by the `sites` and `site_ids` tables.
The formal specification of the format used by *importSites.php* and *exportSites.php* can be found in the *sitelist-1.0.xsd* file. Below is an example and a brief description of what the individual XML elements and attributes mean:
```xml
<sites version="1.0">
<site>
<globalid>acme.com</globalid>
<localid type="interwiki">acme</localid>
<group>Vendor</group>
<path type="link">http://acme.com/</path>
<source>meta.wikimedia.org</source>
</site>
<site type="mediawiki">
<globalid>de.wikidik.example</globalid>
<localid type="equivalent">de</localid>
<group>Dictionary</group>
<forward/>
<path type="page_path">http://acme.com/</path>
</site>
</sites>
```
The XML elements are used as follows:
- `sites`: The root element, containing a set of site tags. May have a `version` attribute with the value `1.0`.
- `site`: A site entry, representing an external website. May have a `type` attribute with one of the following values:
+ `unknown`: (default) any website
+ `mediawiki`: A MediaWiki site
- `globalid`: A unique identifier for the site. For a given site, the same unique global ID must be used across all wikis in a wiki farm (aka wiki family).
- `localid`: An identifier for the site, for use on the local wiki. Multiple local IDs may be assigned to a given site. The same local ID can be used to refer to different sites by different wikis on the same farm/family. The `localid` element may have a type attribute with one of the following values:
+ `interwiki`: Used as an "interwiki" link prefix, for creating cross-wiki links.
+ `equivalent`: Used as a "language" link prefix, for cross-linking equivalent content in different languages.
- `group`: The site group (e.g. wiki family) the site belongs to.
- `path`: A URL template for accessing resources on the site. Several paths may be defined for a given site, for accessing different kinds of resources, identified by the `type` attribute, using one of the following values:
+ `link`: Generic URL template, often the document root.
+ `page_path`: (for `mediawiki` sites) URL template for wiki pages (corresponds to the target wiki's `$wgArticlePath` setting)
+ `file_path`: (for `mediawiki` sites) URL pattern for application entry points and resources (corresponds to the target wiki's `$wgScriptPath` setting).
- `forward`: Whether using a prefix defined by a `localid` tag in the URL will cause the request to be redirected to the corresponding page on the target wiki (currently unused). E.g. whether <http://wiki.acme.com/wiki/foo:Buzz> should be forwarded to <http://wiki.foo.com/read/Buzz>. (CAVEAT: not yet implement, can be specified but has no effect)

View File

@ -1,47 +0,0 @@
This document describes the XML format used to represent information about external sites known
to a MediaWiki installation. This information about external sites is used to allow "inter-wiki"
links, cross-language navigation, as well as close integration via direct access to the other
site's web API or even directly to their database.
Lists of external sites can be imported and exported using the importSites.php and exportSites.php
scripts. In the database, external sites are described by the sites and site_ids tables.
The formal specification of the format used by importSites.php and exportSites.php can be found in
the sitelist-1.0.xsd file. Below is an example and a brief description of what the individual XML
elements and attributes mean:
<sites version="1.0">
<site>
<globalid>acme.com</globalid>
<localid type="interwiki">acme</localid>
<group>Vendor</group>
<path type="link">http://acme.com/</path>
<source>meta.wikimedia.org</source>
</site>
<site type="mediawiki">
<globalid>de.wikidik.example</globalid>
<localid type="equivalent">de</localid>
<group>Dictionary</group>
<forward/>
<path type="page_path">http://acme.com/</path>
</site>
</sites>
The XML elements are used as follows:
* sites: The root element, containing a set of site tags. May have a version attribute with the value 1.0.
* site: A site entry, representing an external website. May have a type attribute with one of the following values:
** ''unknown'': (default) any website
** ''mediawiki'': A MediaWiki site
* globalid: A unique identifier for the site. For a given site, the same unique global ID must be used across all wikis in a wiki farm (aka wiki family).
* localid: An identifier for the site, for use on the local wiki. Multiple local IDs may be assigned to a given site. The same local ID can be used to refer to different sites by different wikis on the same farm/family. The localid element may have a type attribute with one of the following values:
** interwiki: Used as an "interwiki" link prefix, for creating cross-wiki links.
** equivalent: Used as a "language" link prefix, for cross-linking equivalent content in different languages.
* group: The site group (e.g. wiki family) the site belongs to.
* path: A URL template for accessing resources on the site. Several paths may be defined for a given site, for accessing different kinds of resources, identified by the type attribute, using one of the following values:
** link: Generic URL template, often the document root.
** page_path: (for mediawiki sites) URL template for wiki pages (corresponds to the target wiki's $wgArticlePath setting)
** file_path: (for mediawiki sites) URL pattern for application entry points and resources (corresponds to the target wiki's $wgScriptPath setting).
* forward: Whether using a prefix defined by a localid tag in the URL will cause the request to be redirected to the corresponding page on the target wiki (currently unused). E.g. whether http://wiki.acme.com/wiki/foo:Buzz should be forwarded to http://wiki.foo.com/read/Buzz. (CAVEAT: not yet implement, can be specified but has no effect)

View File

@ -1,82 +0,0 @@
skin.txt
MediaWiki includes four core skins:
* Vector: The default skin. Introduced in the 1.16 release (2010), it has been
set as the default in MediaWiki since the 1.17 release (2011), replacing
Monobook.
* Monobook: Named after the black-and-white photo of a book in the page
background. Introduced in the 2004 release of 1.3, it had been the
default skin since then, before being replaced by Vector.
* Modern: An attractive blue/grey theme with sidebar and top bar. Derived from
Monobook.
* Cologne Blue: A lightweight skin with minimal formatting. The oldest of the
currently bundled skins, largely rewritten in 2012 while keeping its
appearance.
Several legacy skins were removed in the 1.22 release, as the burden of
supporting them became too heavy to bear. Those were:
* Standard (a.k.a. Classic): The old default skin written by Lee Crocker during
the phase 3 rewrite, in 2002.
* Nostalgia: A skin which looks like Wikipedia did in its first year (2001).
This skin is now used for the old Wikipedia snapshot at
https://nostalgia.wikipedia.org/
* Chick: A lightweight Monobook skin with no sidebar. The sidebar links were
given at the bottom of the page instead.
* Simple: A lightweight skin with a simple white-background sidebar and no top
bar.
* MySkin: Essentially Monobook without the CSS. The idea was that it could be
customised using user-specific or site-wide CSS (see below).
== Custom CSS/JS ==
It is possible to customise the site CSS and JavaScript without editing any
server-side source files. This is done by editing some pages on the wiki:
* [[MediaWiki:Common.css]] -- for skin-independent CSS
* [[MediaWiki:Common.js]] -- for skin-independent JavaScript
* [[MediaWiki:Vector.css]], [[MediaWiki:Monobook.css]], etc. -- for
skin-dependent CSS
* [[MediaWiki:Vector.js]], [[MediaWiki:Monobook.js]], etc. -- for
skin-dependent JavaScript
These can also be customised on a per-user basis, by editing
[[User:<name>/vector.css]], [[User:<name>/vector.js]], etc.
== Custom skins ==
Several custom skins are available as of 2014.
https://www.mediawiki.org/wiki/Special:MyLanguage/Category:All_skins
Installing a skin requires adding its files in a subdirectory under skins/ and
adding an appropriate require_once line to LocalSettings.php, similarly to how
extensions are installed.
You can then make that skin the default by adding:
$wgDefaultSkin = '<name>';
Or disable it entirely by removing the require_once line. (User settings will
not be lost if it's reenabled later.)
See https://www.mediawiki.org/wiki/Manual:Skinning for more information on
writing new skins.
Until MediaWiki 1.25 it used to be possible to just put a <name>.php file in
MediaWiki's skins/ directory, which would be loaded and expected to contain the
Skin<name> class. This way has always been discouraged because of its limitations
(inability to add localisation messages, ResourceLoader modules, etc.) and
awkwardness in managing such skins. For information on migrating skins using
this old method, see <https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery>.

View File

@ -1,67 +0,0 @@
title.txt
The MediaWiki software's "Title" class represents article titles, which are used
for many purposes: as the human-readable text title of the article, in the URL
used to access the article, the wikitext link to the article, the key into the
article database, and so on. The class in instantiated from one of these forms
and can be queried for the others, and for other attributes of the title. This
is intended to be an immutable "value" class, so there are no mutator functions.
To get a new instance, call Title::newFromText(). Once instantiated, the
non-static accessor methods can be used, such as getText(), getDBkey(),
getNamespace(), etc. Note that Title::newFromText() may return false if the text
is illegal according to the rules below.
The prefix rules: a title consists of an optional interwiki prefix (such as "m:"
for meta or "de:" for German), followed by an optional namespace, followed by
the remainder of the title. Both interwiki prefixes and namespace prefixes have
the same rules: they contain only letters, digits, space, and underscore, must
start with a letter, are case insensitive, and spaces and underscores are
interchangeable. Prefixes end with a ":". A prefix is only recognized if it is
one of those specifically allowed by the software. For example, "de:name" is a
link to the article "name" in the German Wikipedia, because "de" is recognized
as one of the allowable interwikis. The title "talk:name" is a link to the
article "name" in the "talk" namespace of the current wiki, because "talk" is a
recognized namespace. Both may be present, and if so, the interwiki must
come first, for example, "m:talk:name". If a title begins with a colon as its
first character, no prefixes are scanned for, and the colon is just removed.
Note that because of these rules, it is possible to have articles with colons in
their names. "E. Coli 0157:H7" is a valid title, as is "2001: A Space Odyssey",
because "E. Coli 0157" and "2001" are not valid interwikis or namespaces.
It is not possible to have an article whose bare name includes a namespace or
interwiki prefix.
An initial colon in a title listed in wiki text may however suppress special
handling for interlanguage links, image links, and category links. It is also
used to indicate the main namespace in template inclusions.
Once prefixes have been stripped, the rest of the title processed this way:
* Spaces and underscores are treated as equivalent and each is converted to the
other in the appropriate context (underscore in URL and database keys, spaces
in plain text).
* Multiple consecutive spaces are converted to a single space.
* Leading or trailing space is removed.
* If $wgCapitalLinks is enabled (the default), the first letter is capitalised,
using the capitalisation function of the content language object.
* The unicode characters LRM (U+200E) and RLM (U+200F) are silently stripped.
* Invalid UTF-8 sequences or instances of the replacement character (U+FFFD) are
considered illegal.
* A percent sign followed by two hexadecimal characters is illegal
* Anything that looks like an XML/HTML character reference is illegal
* Any character not matched by the $wgLegalTitleChars regex is illegal
* Zero-length titles (after whitespace stripping) are illegal
All titles except special pages must be less than 255 bytes when encoded with
UTF-8, because that is the size of the database field. Special page titles may
be up to 512 bytes.
Note that Unicode Normal Form C (NFC) is enforced by MediaWiki's user interface
input functions, and so titles will typically be in this form.
getArticleID() needs some explanation: for "internal" articles, it should return
the "page_id" field if the article exists, else it returns 0. For all external
articles it returns 0. All of the IDs for all instances of Title created during
a request are cached, so they can be looked up quickly while rendering wiki text
with lots of internal links. See linkcache.txt.

View File

@ -144,4 +144,3 @@
</style>
</body>
</html>

View File

@ -1,141 +0,0 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="../../resources/src/mediawiki.diff.styles/diff.css">
<link rel="stylesheet" media="print" href="../../resources/src/mediawiki.diff.styles/print.css">
</head>
<body>
<p>This show various styles for our diff action. Style sheet: <code><a href="../../resources/src/mediawiki/mediawiki.diff.styles.css">resources/src/mediawiki/mediawiki.diff.styles.css</a></code>.</p>
<p>This file might help us fix our diff colors which have been a recurring issues among the community for a loooong time.</p>
<p>Try it out in print mode, too. Style sheet: <code><a href="../../resources/src/mediawiki/mediawiki.diff.styles.print.css">resources/src/mediawiki/mediawiki.diff.styles.print.css</a></code>.</p>
<p>Practical example copied from MediaWiki's HTML output:</p>
<table class="diff diff-contentalign-left">
<colgroup><col class="diff-marker">
<col class="diff-content">
<col class="diff-marker">
<col class="diff-content">
</colgroup>
<tbody>
<tr>
<td class="diff-marker"></td>
<td class="diff-deletedline"><div>Lorem ipsum dolor sit amet<del class="diffchange diffchange-inline">, consectetur adipisicing elit</del>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div></td>
<td class="diff-marker">+</td>
<td class="diff-addedline"><div>Lorem ipsum dolor sit amet, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td class="diff-deletedline"></td>
<td colspan="2" class="diff-empty">&nbsp;</td>
</tr>
<tr>
<td class="diff-marker"></td>
<td class="diff-deletedline"><div>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div></td>
<td colspan="2" class="diff-empty">&nbsp;</td>
</tr>
<tr>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"></td>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"></td>
</tr>
<tr>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"><div>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div></td>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"><div>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div></td>
</tr>
<tr>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"></td>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"></td>
</tr>
<tr>
<td class="diff-marker"></td>
<td class="diff-deletedline"><div>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim<del class="diffchange diffchange-inline"> id est laborum</del>.</div></td>
<td class="diff-marker">+</td>
<td class="diff-addedline"><div>Excepteur sint occaecat cupidatat non proident, sunt<ins class="diffchange diffchange-inline"> reprehenderit in voluptate</ins> in culpa qui officia deserunt mollit anim.</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty">&nbsp;</td>
<td class="diff-marker">+</td>
<td class="diff-addedline"></td>
</tr>
<tr>
<td colspan="2" class="diff-empty">&nbsp;</td>
<td class="diff-marker">+</td>
<td class="diff-addedline"><div>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div></td>
</tr>
</tbody></table>
<p>Below are some basic lines being applied one or two classes. Mainly for debugging purposes.</p>
<table class="diff">
<tr><th>Diff</th></tr>
<tr><td class="diff-addedline"><code>diff-addedline</code>: added line</td></tr>
<tr><td class="diff-deletedline"><code>diff-deletedline</code>: deleted line</td></tr>
<tr><td class="diff-context"><code>diff-context</code>: context</td></tr>
<tr><th>Same as above with a <code>&lt;ins&gt;</code> or <code>&lt;del&gt;</code> child element having the <code>diffchange</code> class:</th></tr>
<tr><td class="diffchange">Diffchange</td></tr>
<tr><td class="diff-addedline"><ins class="diffchange">Added line + diffchange</ins></td></tr>
<tr><td class="diff-deletedline"><del class="diffchange">Deleted line + diffchange</del></td></tr>
</table>
<p>Here an example for the diff output when a whole paragraph was moved:</p>
<table class="diff diff-contentalign-left">
<colgroup><col class="diff-marker">
<col class="diff-content">
<col class="diff-marker">
<col class="diff-content">
</colgroup><tbody>
<tr>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"></td>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"></td>
</tr>
<tr>
<td class="diff-marker"><a class="mw-diff-movedpara-left" href="#movedpara_3_1_rhs"></a></td>
<td class="diff-deletedline"><div><a name="movedpara_1_1_lhs"></a>Lorem ipsum alias non veritatis porro quidem harum ut et at ab sit atque soluta deleniti architecto ut pariatur? Non consequat. Aut minus occaecat quas lorem impedit, earum praesentium enim reprehenderit, anim consequat. Et maiores consequatur incidunt, nostrud non consectetur, ut eiusmod mollit anim eum vitae qui obcaecati molestiae nostrud dolore hic aperiam commodo nihil omnis aliquam irure expedita minima ut fugiat, error odi.</div></td>
<td colspan="2" class="diff-empty">&nbsp;</td>
</tr>
<tr>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"></td>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"></td>
</tr>
<tr>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"><div>Lorem ipsum sunt ducimus, quos aut quia a nulla molestiae doloremque dolorem inventore vel officia temporibus at ut iste totam officiis impedit, quaerat voluptate fugiat esse est sit, assumenda quis quaerat provident, laborum molestiae esse, quam qui cillum velit, mollit veniam, consequuntur esse, dolorem do amet, maiores ad dolores dolor duis aut amet, adipisicing est.</div></td>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"><div>Lorem ipsum sunt ducimus, quos aut quia a nulla molestiae doloremque dolorem inventore vel officia temporibus at ut iste totam officiis impedit, quaerat voluptate fugiat esse est sit, assumenda quis quaerat provident, laborum molestiae esse, quam qui cillum velit, mollit veniam, consequuntur esse, dolorem do amet, maiores ad dolores dolor duis aut amet, adipisicing est.</div></td>
</tr>
<tr>
<td colspan="2" class="diff-empty">&nbsp;</td>
<td class="diff-marker">+</td>
<td class="diff-addedline"></td>
</tr>
<tr>
<td colspan="2" class="diff-empty">&nbsp;</td>
<td class="diff-marker"><a class="mw-diff-movedpara-right" href="#movedpara_1_1_lhs"></a></td>
<td class="diff-addedline"><div><a name="movedpara_3_1_rhs"></a>Lorem ipsum alias non veritatis porro quidem harum ut et at ab sit atque soluta deleniti architecto ut pariatur? Non consequat. Aut minus occaecat quas lorem impedit, earum praesentium enim reprehenderit, anim consequat. Et maiores consequatur incidunt, nostrud non consectetur, ut eiusmod mollit anim eum vitae qui obcaecati molestiae nostrud dolore hic aperiam commodo nihil omnis aliquam irure expedita minima ut fugiat, error odi.</div></td>
</tr>
<tr>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"></td>
<td class="diff-marker">&nbsp;</td>
<td class="diff-context"></td>
</tr>
</tbody></table>
</body>
</html>

View File

@ -0,0 +1,12 @@
{
"root": true,
"extends": "wikimedia",
"env": {
"browser": true,
"commonjs": true
},
"globals": {
"mw": false,
"$": false
}
}

View File

@ -0,0 +1,5 @@
[gerrit]
host=gerrit.wikimedia.org
port=29418
project=mediawiki/extensions/CategoryTree.git
track=1

View File

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<ruleset>
<rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki" />
<file>.</file>
<arg name="extensions" value="php,php5,inc" />
<arg name="encoding" value="UTF-8" />
</ruleset>

View File

@ -0,0 +1,7 @@
{
"extends": "stylelint-config-wikimedia",
"rules": {
"selector-max-id": null,
"no-descending-specificity": null
}
}

View File

@ -16,7 +16,6 @@ module.exports = function ( grunt ) {
banana: conf.MessagesDirs,
eslint: {
options: {
reportUnusedDisableDirectives: true,
extensions: [ '.js', '.json' ],
cache: true
},

View File

@ -1,15 +1,15 @@
{
"require-dev": {
"jakub-onderka/php-parallel-lint": "1.0.0",
"jakub-onderka/php-console-highlighter": "0.3.2",
"mediawiki/mediawiki-codesniffer": "26.0.0",
"mediawiki/minus-x": "0.3.1",
"mediawiki/mediawiki-phan-config": "0.6.1"
"jakub-onderka/php-console-highlighter": "0.4.0",
"mediawiki/mediawiki-codesniffer": "30.0.0",
"mediawiki/minus-x": "1.0.0",
"mediawiki/mediawiki-phan-config": "0.9.1"
},
"scripts": {
"fix": [
"phpcbf",
"minus-x fix ."
"minus-x fix .",
"phpcbf"
],
"test": [
"parallel-lint . --exclude vendor --exclude node_modules",

View File

@ -6,7 +6,7 @@
"license-name": "GPL-2.0-or-later",
"type": "parserhook",
"requires": {
"MediaWiki": ">= 1.33.0"
"MediaWiki": ">= 1.35.0"
},
"ConfigRegistry": {
"categorytree": "GlobalVarConfig::newInstance"
@ -104,7 +104,8 @@
"CategoryTreeMaxDepth": {
"10": 1,
"20": 1,
"0": 2
"0": 2,
"_merge_strategy": "array_plus"
},
"CategoryTreeForceHeaders": false,
"CategoryTreeSidebarRoot": null,
@ -116,7 +117,8 @@
"mode": null,
"hideprefix": null,
"showcount": false,
"namespaces": false
"namespaces": false,
"notranslations": false
},
"CategoryTreeCategoryPageMode": 0,
"CategoryTreeCategoryPageOptions": {

View File

@ -1,10 +1,10 @@
{
"@metadata": {
"authors": [
"Amire80",
"Bedynokue.nart",
"Highlander45temp",
"SamGamgee",
"Amire80"
"SamGamgee"
]
},
"categorytree-expand": "зэхэщ",

View File

@ -2,9 +2,9 @@
"@metadata": {
"authors": [
"Arnobarnard",
"Fwolff",
"Naudefj",
"SPQRobin",
"Fwolff"
"SPQRobin"
]
},
"categorytree": "Kategorieboom",

View File

@ -3,12 +3,13 @@
"authors": [
"Fryed-peach",
"Otokoume",
"Shirayuki",
"Yusuke1109"
]
},
"apihelp-categorytree-description": "カテゴリツリー拡張機能の内部モジュール。",
"apihelp-categorytree-summary": "カテゴリツリー拡張機能の内部モジュール。",
"apihelp-categorytree-param-category": "カテゴリ名前空間におけるページ名、接頭辞は指定しても無視される。",
"apihelp-categorytree-param-options": "JSONオブジェクトとしてのCategoryTreeコンストラクタのオプション。<var>深さ</var>オプションのデフォルトは<kbd>1</kbd>です。",
"apihelp-categorytree-param-options": "CategoryTreeコンストラクターのオプションをJSONオブジェクトとして指定。<var>depth</var>オプションの既定値は<kbd>1</kbd>です。",
"apierror-categorytree-invalidjson": "オプションは有効なJSONオブジェクトでなければなりません。"
}

View File

@ -2,9 +2,9 @@
"@metadata": {
"authors": [
"Chrumps",
"Rail",
"Railfail536",
"Woytecr",
"Rail"
"Woytecr"
]
},
"apihelp-categorytree-description": "Wewnętrzny moduł rozszerzenia CategoryTree.",

View File

@ -9,6 +9,8 @@
"Malafaya",
"McDutchie",
"Meno25",
"Nemo bis",
"Purodha",
"Raimond Spekking",
"Raymond",
"Shirayuki",
@ -17,9 +19,7 @@
"Umherirrender",
"Yekrats",
"Александр Сигачёв",
"פוילישער",
"Purodha",
"Nemo bis"
"פוילישער"
]
},
"apihelp-categorytree-description": "{{doc-apihelp-description|categorytree}}",

View File

@ -1,12 +1,13 @@
{
"@metadata": {
"authors": [
"BaRaN6161 TURK",
"Hedda"
]
},
"apihelp-categorytree-description": "CategoryTree uzantısı için iç modül.",
"apihelp-categorytree-summary": "CategoryTree uzantısı için iç modül.",
"apihelp-categorytree-param-category": "Kategori ad alanındaki başlık, verilen varsa önek dikkate alınmaz.",
"apihelp-categorytree-param-options": "JSON nesnesi olarak CategoryTree yapıcısı için seçenekler. <var>Derinlik</var> seçeneği varsayılan <kbd>1</kbd>",
"apierror-categorytree-invalidjson": "Seçenekler bir JSON nesnesi için geçerli olmalıdır."
"apihelp-categorytree-param-options": "JSON nesnesi olarak CategoryTree yapıcısı için seçenekler. <var>depth</var> seçeneği varsayılan <kbd>1</kbd>",
"apierror-categorytree-invalidjson": "Seçenekler geçerli bir JSON nesnesi olmalıdır."
}

View File

@ -1,14 +1,14 @@
{
"@metadata": {
"authors": [
"Abanima",
"AwamerT",
"Maroen1990",
"Meno25",
"Mido",
"Moud hosny",
"OsamaK",
"زكريا",
"Abanima",
"Maroen1990",
"Moud hosny"
"زكريا"
]
},
"categorytree": "شجرة تصنيفات",

View File

@ -1,8 +1,15 @@
{
"@metadata": {
"authors": [
"Reda Benkhadra"
"Reda Benkhadra",
"SADI9I",
"SADIQUI"
]
},
"categorytree-expand": "وسع"
"categorytree-expand": "وسع",
"categorytree-member-counts": "كيحتاوي على {{PLURAL:$1|تصنيف فرعي واحد|$1 تصنيفات فرعية}}، {{PLURAL:$2|صفحة وحدة|$2 صفحات}}، و{{PLURAL:$3|ملف واحد|$3 ملفات}}",
"categorytree-num-categories": "$1 ت",
"categorytree-num-pages": " $1 ص",
"categorytree-num-files": " $1 م",
"categorytree-num-empty": "خاوي"
}

Some files were not shown because too many files have changed in this diff Show More