== Globals ==
; $wgMWLoggerDefaultSpi
-: Default service provider interface to use with MWLogger
-; $wgMWLoggerMonologSpiConfig
-: Configuration for MWLoggerMonologSpi describing how to configure the
- Monolog logger instances.
+: Specification for creating the default service provider interface to use
+ with MWLogger
[0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
[1]: https://github.com/Seldaek/monolog
'MWHookException' => 'includes/Hooks.php',
'MWHttpRequest' => 'includes/HttpFunctions.php',
'MWNamespace' => 'includes/MWNamespace.php',
+ 'ObjectFactory' => 'includes/libs/ObjectFactory.php',
'OutputPage' => 'includes/OutputPage.php',
'PathRouter' => 'includes/PathRouter.php',
'PathRouterPatternReplacer' => 'includes/PathRouter.php',
/**
* Default service provider for creating MWLogger instances.
*
- * This can either be the name of a class implementing the MWLoggerSpi
- * interface with a zero argument constructor or a callable that will return
- * an MWLoggerSpi instance. Alternately the MWLogger::registerProvider method
- * can be called to inject an MWLoggerSpi instance into MWLogger and bypass
- * the use of this configuration variable.
- *
- * @since 1.25
- * @var $wgMWLoggerDefaultSpi string|callable
- * @see MwLogger
- */
-$wgMWLoggerDefaultSpi = 'MWLoggerNullSpi';
-
-/**
- * Configuration for MWLoggerMonologSpi logger factory.
+ * The value should be an array suitable for use with
+ * ObjectFactory::getObjectFromSpec(). The created object is expected to
+ * implement the MWLoggerSpi interface. See ObjectFactory for additional
+ * details.
*
- * Default configuration installs a null handler that will silently discard
- * all logging events.
+ * Alternately the MWLogger::registerProvider method can be called to inject
+ * an MWLoggerSpi instance into MWLogger and bypass the use of this
+ * configuration variable entirely.
*
* @since 1.25
- * @see MWLoggerMonologSpi
+ * @var array $wgMWLoggerDefaultSpi
+ * @see MwLogger
*/
-$wgMWLoggerMonologSpiConfig = array(
- 'loggers' => array(
- '@default' => array(
- 'handlers' => array( 'null' ),
- ),
- ),
- 'handlers' => array(
- 'null' => array(
- 'class' => '\\Monolog\\Logger\\NullHandler',
- ),
- ),
+$wgMWLoggerDefaultSpi = array(
+ 'class' => 'MWLoggerNullSpi',
);
/**
# If we don't know whether the page exists, let's find out.
wfProfileIn( __METHOD__ . '-checkPageExistence' );
- if ( !in_array( 'known', $options ) and !in_array( 'broken', $options ) ) {
+ if ( !in_array( 'known', $options ) && !in_array( 'broken', $options ) ) {
if ( $target->isKnown() ) {
$options[] = 'known';
} else {
$this->logFeatureUsage( 'action=expandtemplates&generatexml' );
}
- $wgParser->startExternalParse( $title_obj, $options, OT_PREPROCESS );
+ $wgParser->startExternalParse( $title_obj, $options, Parser::OT_PREPROCESS );
$dom = $wgParser->preprocessToDom( $params['text'] );
if ( is_callable( array( $dom, 'saveXML' ) ) ) {
$xml = $dom->saveXML();
// if they didn't want any output except (probably) the parse tree,
// then don't bother actually fully expanding it
if ( $prop || $params['prop'] === null ) {
- $wgParser->startExternalParse( $title_obj, $options, OT_PREPROCESS );
+ $wgParser->startExternalParse( $title_obj, $options, Parser::OT_PREPROCESS );
$frame = $wgParser->getPreprocessor()->newFrame();
$wikitext = $wgParser->preprocess( $params['text'], $title_obj, $options, null, $frame );
if ( $params['prop'] === null ) {
$this->dieUsage( "generatexml is only supported for wikitext content", "notwikitext" );
}
- $wgParser->startExternalParse( $titleObj, $popts, OT_PREPROCESS );
+ $wgParser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
$dom = $wgParser->preprocessToDom( $this->content->getNativeData() );
if ( is_callable( array( $dom, 'saveXML' ) ) ) {
$xml = $dom->saveXML();
$this->run( $resultPageSet );
}
+ /**
+ * @param string $hexSortkey
+ * @return bool
+ */
+ private function validateHexSortkey( $hexSortkey ) {
+ // A hex sortkey has an unbound number of 2 letter pairs
+ return preg_match( '/^(?:[a-fA-F0-9]{2})*$/', $hexSortkey );
+ }
+
/**
* @param ApiPageSet $resultPageSet
* @return void
$queryTypes = array_slice( $queryTypes, $contTypeIndex );
// Add a WHERE clause for sortkey and from
+ $this->dieContinueUsageIf( !$this->validateHexSortkey( $cont[1] ) );
// pack( "H*", $foo ) is used to convert hex back to binary
$escSortkey = $this->getDB()->addQuotes( pack( 'H*', $cont[1] ) );
$from = intval( $cont[2] );
if ( $params['startsortkeyprefix'] !== null ) {
$startsortkey = Collation::singleton()->getSortkey( $params['startsortkeyprefix'] );
} elseif ( $params['starthexsortkey'] !== null ) {
+ if ( !$this->validateHexSortkey( $params['starthexsortkey'] ) ) {
+ $this->dieUsage( 'The starthexsortkey provided is not valid', 'bad_starthexsortkey' );
+ }
$startsortkey = pack( 'H*', $params['starthexsortkey'] );
} else {
$this->logFeatureUsage( 'list=categorymembers&cmstartsortkey' );
if ( $params['endsortkeyprefix'] !== null ) {
$endsortkey = Collation::singleton()->getSortkey( $params['endsortkeyprefix'] );
} elseif ( $params['endhexsortkey'] !== null ) {
+ if ( !$this->validateHexSortkey( $params['endhexsortkey'] ) ) {
+ $this->dieUsage( 'The endhexsortkey provided is not valid', 'bad_endhexsortkey' );
+ }
$endsortkey = pack( 'H*', $params['endhexsortkey'] );
} else {
$this->logFeatureUsage( 'list=categorymembers&cmendsortkey' );
$wgParser->startExternalParse(
$title,
ParserOptions::newFromContext( $this->getContext() ),
- OT_PREPROCESS
+ Parser::OT_PREPROCESS
);
$dom = $wgParser->preprocessToDom( $t );
if ( is_callable( array( $dom, 'saveXML' ) ) ) {
"apihelp-query+allfileusages-param-to": "The title of the file to stop enumerating at.",
"apihelp-query+allfileusages-param-prefix": "Search for all file titles that begin with this value.",
"apihelp-query+allfileusages-param-unique": "Only show distinct file titles. Cannot be used with $1prop=ids.\nWhen used as a generator, yields target pages instead of source pages.",
- "apihelp-query+allfileusages-param-prop": "Which pieces of information to include:\n;ids:Adds the pageid of the using page (cannot be used with $1unique).\n;title:Adds the title of the file.",
+ "apihelp-query+allfileusages-param-prop": "Which pieces of information to include:\n;ids:Adds the page ID of the using page (cannot be used with $1unique).\n;title:Adds the title of the file.",
"apihelp-query+allfileusages-param-limit": "How many total items to return.",
"apihelp-query+allfileusages-param-dir": "The direction in which to list.",
- "apihelp-query+allfileusages-example-B": "List file titles, including missing ones, with page ids they are from, starting at B",
+ "apihelp-query+allfileusages-example-B": "List file titles, including missing ones, with page IDs they are from, starting at B",
"apihelp-query+allfileusages-example-unique": "List unique file titles",
"apihelp-query+allfileusages-example-unique-generator": "Gets all file titles, marking the missing ones",
"apihelp-query+allfileusages-example-generator": "Gets pages containing the files",
"apihelp-query+alllinks-param-to": "The title of the link to stop enumerating at.",
"apihelp-query+alllinks-param-prefix": "Search for all linked titles that begin with this value.",
"apihelp-query+alllinks-param-unique": "Only show distinct linked titles. Cannot be used with $1prop=ids.\nWhen used as a generator, yields target pages instead of source pages.",
- "apihelp-query+alllinks-param-prop": "Which pieces of information to include:\n;ids:Adds the pageid of the linking page (cannot be used with $1unique).\n;title:Adds the title of the link.",
+ "apihelp-query+alllinks-param-prop": "Which pieces of information to include:\n;ids:Adds the page ID of the linking page (cannot be used with $1unique).\n;title:Adds the title of the link.",
"apihelp-query+alllinks-param-namespace": "The namespace to enumerate.",
"apihelp-query+alllinks-param-limit": "How many total items to return.",
"apihelp-query+alllinks-param-dir": "The direction in which to list.",
- "apihelp-query+alllinks-example-B": "List linked titles, including missing ones, with page ids they are from, starting at B",
+ "apihelp-query+alllinks-example-B": "List linked titles, including missing ones, with page IDs they are from, starting at B",
"apihelp-query+alllinks-example-unique": "List unique linked titles",
"apihelp-query+alllinks-example-unique-generator": "Gets all linked titles, marking the missing ones",
"apihelp-query+alllinks-example-generator": "Gets pages containing the links",
"apihelp-query+allredirects-param-to": "The title of the redirect to stop enumerating at.",
"apihelp-query+allredirects-param-prefix": "Search for all target pages that begin with this value.",
"apihelp-query+allredirects-param-unique": "Only show distinct target pages. Cannot be used with $1prop=ids|fragment|interwiki.\nWhen used as a generator, yields target pages instead of source pages.",
- "apihelp-query+allredirects-param-prop": "Which pieces of information to include:\n;ids:Adds the pageid of the redirecting page (cannot be used with $1unique).\n;title:Adds the title of the redirect.\n;fragment:Adds the fragment from the redirect, if any (cannot be used with $1unique).\n;interwiki:Adds the interwiki prefix from the redirect, if any (cannot be used with $1unique).",
+ "apihelp-query+allredirects-param-prop": "Which pieces of information to include:\n;ids:Adds the page ID of the redirecting page (cannot be used with $1unique).\n;title:Adds the title of the redirect.\n;fragment:Adds the fragment from the redirect, if any (cannot be used with $1unique).\n;interwiki:Adds the interwiki prefix from the redirect, if any (cannot be used with $1unique).",
"apihelp-query+allredirects-param-namespace": "The namespace to enumerate.",
"apihelp-query+allredirects-param-limit": "How many total items to return.",
"apihelp-query+allredirects-param-dir": "The direction in which to list.",
- "apihelp-query+allredirects-example-B": "List target pages, including missing ones, with page ids they are from, starting at B",
+ "apihelp-query+allredirects-example-B": "List target pages, including missing ones, with page IDs they are from, starting at B",
"apihelp-query+allredirects-example-unique": "List unique target pages",
"apihelp-query+allredirects-example-unique-generator": "Gets all target pages, marking the missing ones",
"apihelp-query+allredirects-example-generator": "Gets pages containing the redirects",
"apihelp-query+alltransclusions-param-to": "The title of the transclusion to stop enumerating at.",
"apihelp-query+alltransclusions-param-prefix": "Search for all transcluded titles that begin with this value.",
"apihelp-query+alltransclusions-param-unique": "Only show distinct transcluded titles. Cannot be used with $1prop=ids.\nWhen used as a generator, yields target pages instead of source pages.",
- "apihelp-query+alltransclusions-param-prop": "Which pieces of information to include:\n;ids:Adds the pageid of the transcluding page (cannot be used with $1unique).\n;title:Adds the title of the transclusion.",
+ "apihelp-query+alltransclusions-param-prop": "Which pieces of information to include:\n;ids:Adds the page ID of the transcluding page (cannot be used with $1unique).\n;title:Adds the title of the transclusion.",
"apihelp-query+alltransclusions-param-namespace": "The namespace to enumerate.",
"apihelp-query+alltransclusions-param-limit": "How many total items to return.",
"apihelp-query+alltransclusions-param-dir": "The direction in which to list.",
- "apihelp-query+alltransclusions-example-B": "List transcluded titles, including missing ones, with page ids they are from, starting at B",
+ "apihelp-query+alltransclusions-example-B": "List transcluded titles, including missing ones, with page IDs they are from, starting at B",
"apihelp-query+alltransclusions-example-unique": "List unique transcluded titles",
"apihelp-query+alltransclusions-example-unique-generator": "Gets all transcluded titles, marking the missing ones",
"apihelp-query+alltransclusions-example-generator": "Gets pages containing the transclusions",
"apihelp-query+backlinks-description": "Find all pages that link to the given page.",
"apihelp-query+backlinks-param-title": "Title to search. Cannot be used together with $1pageid.",
- "apihelp-query+backlinks-param-pageid": "Pageid to search. Cannot be used together with $1title.",
+ "apihelp-query+backlinks-param-pageid": "Page ID to search. Cannot be used together with $1title.",
"apihelp-query+backlinks-param-namespace": "The namespace to enumerate.",
"apihelp-query+backlinks-param-dir": "The direction in which to list.",
"apihelp-query+backlinks-param-filterredir": "How to filter for redirects. If set to nonredirects when $1redirect is enabled, this is only applied to the second level.",
"apihelp-query+embeddedin-description": "Find all pages that embed (transclude) the given title.",
"apihelp-query+embeddedin-param-title": "Title to search. Cannot be used together with $1pageid.",
- "apihelp-query+embeddedin-param-pageid": "Pageid to search. Cannot be used together with $1title.",
+ "apihelp-query+embeddedin-param-pageid": "Page ID to search. Cannot be used together with $1title.",
"apihelp-query+embeddedin-param-namespace": "The namespace to enumerate.",
"apihelp-query+embeddedin-param-dir": "The direction in which to list.",
"apihelp-query+embeddedin-param-filterredir": "How to filter for redirects.",
"apihelp-query+filerepoinfo-example-simple": "Get information about file repositories",
"apihelp-query+fileusage-description": "Find all pages that use the given files.",
- "apihelp-query+fileusage-param-prop": "Which properties to get:\n;pageid:Page id of each page.\n;title:Title of each page.\n;redirect:Flag if the page is a redirect.",
+ "apihelp-query+fileusage-param-prop": "Which properties to get:\n;pageid:Page ID of each page.\n;title:Title of each page.\n;redirect:Flag if the page is a redirect.",
"apihelp-query+fileusage-param-namespace": "Only include pages in these namespaces.",
"apihelp-query+fileusage-param-limit": "How many to return.",
"apihelp-query+fileusage-param-show": "Show only items that meet these criteria:\n;redirect:Only show redirects.\n;!redirects:Only show non-redirects.",
"apihelp-query+imageusage-description": "Find all pages that use the given image title.",
"apihelp-query+imageusage-param-title": "Title to search. Cannot be used together with $1pageid.",
- "apihelp-query+imageusage-param-pageid": "Pageid to search. Cannot be used together with $1title.",
+ "apihelp-query+imageusage-param-pageid": "Page ID to search. Cannot be used together with $1title.",
"apihelp-query+imageusage-param-namespace": "The namespace to enumerate.",
"apihelp-query+imageusage-param-dir": "The direction in which to list.",
"apihelp-query+imageusage-param-filterredir": "How to filter for redirects. If set to nonredirects when $1redirect is enabled, this is only applied to the second level.",
"apihelp-query+links-example-namespaces": "Get links from the [[Main Page]] in the User and Template namespaces",
"apihelp-query+linkshere-description": "Find all pages that link to the given pages.",
- "apihelp-query+linkshere-param-prop": "Which properties to get:\n;pageid:Page id of each page.\n;title:Title of each page.\n;redirect:Flag if the page is a redirect.",
+ "apihelp-query+linkshere-param-prop": "Which properties to get:\n;pageid:Page ID of each page.\n;title:Title of each page.\n;redirect:Flag if the page is a redirect.",
"apihelp-query+linkshere-param-namespace": "Only include pages in these namespaces.",
"apihelp-query+linkshere-param-limit": "How many to return.",
"apihelp-query+linkshere-param-show": "Show only items that meet these criteria:\n;redirect:Only show redirects.\n;!redirects:Only show non-redirects.",
"apihelp-query+protectedtitles-param-limit": "How many total pages to return.",
"apihelp-query+protectedtitles-param-start": "Start listing at this protection timestamp.",
"apihelp-query+protectedtitles-param-end": "Stop listing at this protection timestamp.",
- "apihelp-query+protectedtitles-param-prop": "Which properties to get:\n;timestamp:Adds the timestamp of when protection was added.\n;user:Adds the user that added the protection.\n;userid:Adds the user id that added the protection.\n;comment:Adds the comment for the protection.\n;parsedcomment:Adds the parsed comment for the protection.\n;expiry:Adds the timestamp of when the protection will be lifted.\n;level:Adds the protection level.",
+ "apihelp-query+protectedtitles-param-prop": "Which properties to get:\n;timestamp:Adds the timestamp of when protection was added.\n;user:Adds the user that added the protection.\n;userid:Adds the user ID that added the protection.\n;comment:Adds the comment for the protection.\n;parsedcomment:Adds the parsed comment for the protection.\n;expiry:Adds the timestamp of when the protection will be lifted.\n;level:Adds the protection level.",
"apihelp-query+protectedtitles-example-simple": "List protected titles",
"apihelp-query+protectedtitles-example-generator": "Find links to protected titles in the main namespace",
"apihelp-query+recentchanges-param-user": "Only list changes by this user.",
"apihelp-query+recentchanges-param-excludeuser": "Don't list changes by this user.",
"apihelp-query+recentchanges-param-tag": "Only list changes tagged with this tag.",
- "apihelp-query+recentchanges-param-prop": "Include additional pieces of information:\n;user:Adds the user responsible for the edit and tags if they are an IP.\n;userid:Adds the user id responsible for the edit.\n;comment:Adds the comment for the edit.\n;parsedcomment:Adds the parsed comment for the edit.\n;flags:Adds flags for the edit.\n;timestamp:Adds timestamp of the edit.\n;title:Adds the page title of the edit.\n;ids:Adds the page ID, recent changes ID and the new and old revision ID.\n;sizes:Adds the new and old page length in bytes.\n;redirect:Tags edit if page is a redirect.\n;patrolled:Tags patrollable edits as being patrolled or unpatrolled.\n;loginfo:Adds log information (logid, logtype, etc) to log entries.\n;tags:Lists tags for the entry.\n;sha1:Adds the content checksum for entries associated with a revision.",
+ "apihelp-query+recentchanges-param-prop": "Include additional pieces of information:\n;user:Adds the user responsible for the edit and tags if they are an IP.\n;userid:Adds the user ID responsible for the edit.\n;comment:Adds the comment for the edit.\n;parsedcomment:Adds the parsed comment for the edit.\n;flags:Adds flags for the edit.\n;timestamp:Adds timestamp of the edit.\n;title:Adds the page title of the edit.\n;ids:Adds the page ID, recent changes ID and the new and old revision ID.\n;sizes:Adds the new and old page length in bytes.\n;redirect:Tags edit if page is a redirect.\n;patrolled:Tags patrollable edits as being patrolled or unpatrolled.\n;loginfo:Adds log information (log ID, log type, etc) to log entries.\n;tags:Lists tags for the entry.\n;sha1:Adds the content checksum for entries associated with a revision.",
"apihelp-query+recentchanges-param-token": "Use [[Special:ApiHelp/query+tokens|action=query&meta=tokens]] instead.",
"apihelp-query+recentchanges-param-show": "Show only items that meet these criteria. For example, to see only minor edits done by logged-in users, set $1show=minor|!anon.",
"apihelp-query+recentchanges-param-limit": "How many total changes to return.",
"apihelp-query+recentchanges-example-generator": "Get page info about recent unpatrolled changes",
"apihelp-query+redirects-description": "Returns all redirects to the given pages.",
- "apihelp-query+redirects-param-prop": "Which properties to get:\n;pageid:Page id of each redirect.\n;title:Title of each redirect.\n;fragment:Fragment of each redirect, if any.",
+ "apihelp-query+redirects-param-prop": "Which properties to get:\n;pageid:Page ID of each redirect.\n;title:Title of each redirect.\n;fragment:Fragment of each redirect, if any.",
"apihelp-query+redirects-param-namespace": "Only include pages in these namespaces.",
"apihelp-query+redirects-param-limit": "How many redirects to return.",
"apihelp-query+redirects-param-show": "Show only items that meet these criteria:\n;fragment:Only show redirects with a fragment.\n;!fragment:Only show redirects without a fragment.",
"apihelp-query+revisions-description": "Get revision information.\n\nMay be used in several ways:\n# Get data about a set of pages (last revision), by setting titles or pageids.\n# Get revisions for one given page, by using titles or pageids with start, end, or limit.\n# Get data about a set of revisions by setting their IDs with revids.",
"apihelp-query+revisions-paraminfo-singlepageonly": "May only be used with a single page (mode #2).",
- "apihelp-query+revisions-param-prop": "Which properties to get for each revision:\n;ids:The ID of the revision.\n;flags:Revision flags (minor).\n;timestamp:The timestamp of the revision.\n;user:User that made the revision.\n;userid:User id of revision creator.\n;size:Length (bytes) of the revision.\n;sha1:SHA-1 (base 16) of the revision.\n;contentmodel:Content model id.\n;comment:Comment by the user for revision.\n;parsedcomment:Parsed comment by the user for the revision.\n;content:Text of the revision.\n;tags:Tags for the revision.",
+ "apihelp-query+revisions-param-prop": "Which properties to get for each revision:\n;ids:The ID of the revision.\n;flags:Revision flags (minor).\n;timestamp:The timestamp of the revision.\n;user:User that made the revision.\n;userid:User ID of revision creator.\n;size:Length (bytes) of the revision.\n;sha1:SHA-1 (base 16) of the revision.\n;contentmodel:Content model ID.\n;comment:Comment by the user for revision.\n;parsedcomment:Parsed comment by the user for the revision.\n;content:Text of the revision.\n;tags:Tags for the revision.",
"apihelp-query+revisions-param-limit": "Limit how many revisions will be returned.",
- "apihelp-query+revisions-param-startid": "From which revision id to start enumeration.",
- "apihelp-query+revisions-param-endid": "Stop revision enumeration on this revid.",
+ "apihelp-query+revisions-param-startid": "From which revision ID to start enumeration.",
+ "apihelp-query+revisions-param-endid": "Stop revision enumeration on this revision ID.",
"apihelp-query+revisions-param-start": "From which revision timestamp to start enumeration.",
"apihelp-query+revisions-param-end": "Enumerate up to this timestamp.",
"apihelp-query+revisions-param-user": "Only include revisions made by user.",
"apihelp-query+tokens-example-types": "Retrieve a watch token and a patrol token",
"apihelp-query+transcludedin-description": "Find all pages that transclude the given pages.",
- "apihelp-query+transcludedin-param-prop": "Which properties to get:\n;pageid:Page id of each page.\n;title:Title of each page.\n;redirect:Flag if the page is a redirect.",
+ "apihelp-query+transcludedin-param-prop": "Which properties to get:\n;pageid:Page ID of each page.\n;title:Title of each page.\n;redirect:Flag if the page is a redirect.",
"apihelp-query+transcludedin-param-namespace": "Only include pages in these namespaces.",
"apihelp-query+transcludedin-param-limit": "How many to return.",
"apihelp-query+transcludedin-param-show": "Show only items that meet these criteria:\n;redirect:Only show redirects.\n;!redirects:Only show non-redirects.",
"apihelp-query+watchlist-param-user": "Only list changes by this user.",
"apihelp-query+watchlist-param-excludeuser": "Don't list changes by this user.",
"apihelp-query+watchlist-param-limit": "How many total results to return per request.",
- "apihelp-query+watchlist-param-prop": "Which additional items to get:\n;ids:Adds revision ids and page ids.\n;title:Adds title of the page.\n;flags:Adds flags for the edit.\n;user:Adds the user who made the edit.\n;userid:Adds user id of whom made the edit.\n;comment:Adds comment of the edit.\n;parsedcomment:Adds parsed comment of the edit.\n;timestamp:Adds timestamp of the edit.\n;patrol:Tags edits that are patrolled.\n;sizes:Adds the old and new lengths of the page.\n;notificationtimestamp:Adds timestamp of when the user was last notified about the edit.\n;loginfo:Adds log information where appropriate.",
+ "apihelp-query+watchlist-param-prop": "Which additional items to get:\n;ids:Adds revision IDs and page IDs.\n;title:Adds title of the page.\n;flags:Adds flags for the edit.\n;user:Adds the user who made the edit.\n;userid:Adds user ID of whom made the edit.\n;comment:Adds comment of the edit.\n;parsedcomment:Adds parsed comment of the edit.\n;timestamp:Adds timestamp of the edit.\n;patrol:Tags edits that are patrolled.\n;sizes:Adds the old and new lengths of the page.\n;notificationtimestamp:Adds timestamp of when the user was last notified about the edit.\n;loginfo:Adds log information where appropriate.",
"apihelp-query+watchlist-param-show": "Show only items that meet these criteria. For example, to see only minor edits done by logged-in users, set $1show=minor|!anon.",
"apihelp-query+watchlist-param-type": "Which types of changes to show:\n;edit:Regular page edits.\n;external:External changes.\n;new:Page creations.\n;log:Log entries.",
"apihelp-query+watchlist-param-owner": "Used along with $1token to access a different user's watchlist.",
"apihelp-unblock-example-id": "Unblock block ID #105",
"apihelp-unblock-example-user": "Unblock user Bob with reason \"Sorry Bob\"",
- "apihelp-undelete-description": "Restore revisions of a deleted page.\n\nA list of deleted revisions (including timestamps) can be retrieved through [[Special:ApiHelp/query+deletedrevs|list=deletedrevs]], and a list of deleted file ids can be retrieved through [[Special:ApiHelp/query+filearchive|list=filearchive]].",
+ "apihelp-undelete-description": "Restore revisions of a deleted page.\n\nA list of deleted revisions (including timestamps) can be retrieved through [[Special:ApiHelp/query+deletedrevs|list=deletedrevs]], and a list of deleted file IDs can be retrieved through [[Special:ApiHelp/query+filearchive|list=filearchive]].",
"apihelp-undelete-param-title": "Title of the page to restore.",
"apihelp-undelete-param-reason": "Reason for restoring.",
"apihelp-undelete-param-timestamps": "Timestamps of the revisions to restore. If both $1timestamps and $1fileids are empty, all will be restored.",
"apihelp-userrights-description": "Change a user's group membership.",
"apihelp-userrights-param-user": "User name.",
- "apihelp-userrights-param-userid": "User id.",
+ "apihelp-userrights-param-userid": "User ID.",
"apihelp-userrights-param-add": "Add the user to these groups.",
"apihelp-userrights-param-remove": "Remove the user from these groups.",
"apihelp-userrights-param-reason": "Reason for the change.",
"apihelp-userrights-example-user": "Add user FooBot to group \"bot\", and remove from groups \"sysop\" and \"bureaucrat\"",
- "apihelp-userrights-example-userid": "Add the user with id 123 to group \"bot\", and remove from groups \"sysop\" and \"bureaucrat\"",
+ "apihelp-userrights-example-userid": "Add the user with ID 123 to group \"bot\", and remove from groups \"sysop\" and \"bureaucrat\"",
"apihelp-watch-description": "Add or remove pages from the current user's watchlist.",
"apihelp-watch-param-title": "The page to (un)watch. Use $1titles instead.",
// Matches: LIMIT {[offset,] row_count | row_count OFFSET offset}
$pattern = '/\bLIMIT\s+((([0-9]+)\s*,\s*)?([0-9]+)(\s+OFFSET\s+([0-9]+))?)/i';
if ( preg_match( $pattern, $sql, $matches ) ) {
- // row_count = $matches[4]
$row_count = $matches[4];
- // offset = $matches[3] OR $matches[6]
- $offset = $matches[3] or
- $offset = $matches[6] or
- $offset = false;
+ $offset = $matches[3] ?: $matches[6] ?: false;
// strip the matching LIMIT clause out
$sql = str_replace( $matches[0], '', $sql );
public static function getInstance( $channel ) {
if ( self::$spi === null ) {
global $wgMWLoggerDefaultSpi;
- if ( is_callable( $wgMWLoggerDefaultSpi ) ) {
- $provider = $wgMWLoggerDefaultSpi();
- } else {
- $provider = new $wgMWLoggerDefaultSpi();
- }
+ $provider = ObjectFactory::getObjectFromSpec(
+ $wgMWLoggerDefaultSpi
+ );
self::registerProvider( $provider );
}
* MWLogger service provider that creates \Psr\Log\NullLogger instances.
* A NullLogger silently discards all log events sent to it.
*
+ * Usage:
+ * @code
+ * $wgMWLoggerDefaultSpi = array(
+ * 'class' => 'MWLoggerNullSpi',
+ * );
+ * @endcode
+ *
* @see MWLogger
* @since 1.25
* @author Bryan Davis <bd808@wikimedia.org>
* for any channel that isn't explicitly named in the 'loggers' configuration
* section.
*
- * Configuration can be specified using the $wgMWLoggerMonologSpiConfig global
- * variable.
- *
- * Example:
+ * Configuration will most typically be provided in the $wgMWLoggerDefaultSpi
+ * global configuration variable used by MWLogger to construct its default SPI
+ * provider:
* @code
- * $wgMWLoggerMonologSpiConfig = array(
- * 'loggers' => array(
- * '@default' => array(
- * 'processors' => array( 'wiki', 'psr', 'pid', 'uid', 'web' ),
- * 'handlers' => array( 'stream' ),
- * ),
- * 'runJobs' => array(
- * 'processors' => array( 'wiki', 'psr', 'pid' ),
- * 'handlers' => array( 'stream' ),
- * )
- * ),
- * 'processors' => array(
- * 'wiki' => array(
- * 'class' => 'MWLoggerMonologProcessor',
- * ),
- * 'psr' => array(
- * 'class' => '\\Monolog\\Processor\\PsrLogMessageProcessor',
- * ),
- * 'pid' => array(
- * 'class' => '\\Monolog\\Processor\\ProcessIdProcessor',
- * ),
- * 'uid' => array(
- * 'class' => '\\Monolog\\Processor\\UidProcessor',
- * ),
- * 'web' => array(
- * 'class' => '\\Monolog\\Processor\\WebProcessor',
- * ),
- * ),
- * 'handlers' => array(
- * 'stream' => array(
- * 'class' => '\\Monolog\\Handler\\StreamHandler',
- * 'args' => array( 'path/to/your.log' ),
- * 'formatter' => 'line',
- * ),
- * 'redis' => array(
- * 'class' => '\\Monolog\\Handler\\RedisHandler',
- * 'args' => array( function() {
- * $redis = new Redis();
- * $redis->connect( '127.0.0.1', 6379 );
- * return $redis;
- * },
- * 'logstash'
- * ),
- * 'formatter' => 'logstash',
- * ),
- * 'udp2log' => array(
- * 'class' => 'MWLoggerMonologHandler',
- * 'args' => array(
- * 'udp://127.0.0.1:8420/mediawiki
- * ),
- * 'formatter' => 'line',
- * ),
- * ),
- * 'formatters' => array(
- * 'line' => array(
- * 'class' => '\\Monolog\\Formatter\\LineFormatter',
- * ),
- * 'logstash' => array(
- * 'class' => '\\Monolog\\Formatter\\LogstashFormatter',
- * 'args' => array( 'mediawiki', php_uname( 'n' ), null, '', 1 ),
- * ),
- * ),
+ * $wgMWLoggerDefaultSpi = array(
+ * 'class' => 'MWLoggerMonologSpi',
+ * 'args' => array( array(
+ * 'loggers' => array(
+ * '@default' => array(
+ * 'processors' => array( 'wiki', 'psr', 'pid', 'uid', 'web' ),
+ * 'handlers' => array( 'stream' ),
+ * ),
+ * 'runJobs' => array(
+ * 'processors' => array( 'wiki', 'psr', 'pid' ),
+ * 'handlers' => array( 'stream' ),
+ * )
+ * ),
+ * 'processors' => array(
+ * 'wiki' => array(
+ * 'class' => 'MWLoggerMonologProcessor',
+ * ),
+ * 'psr' => array(
+ * 'class' => '\\Monolog\\Processor\\PsrLogMessageProcessor',
+ * ),
+ * 'pid' => array(
+ * 'class' => '\\Monolog\\Processor\\ProcessIdProcessor',
+ * ),
+ * 'uid' => array(
+ * 'class' => '\\Monolog\\Processor\\UidProcessor',
+ * ),
+ * 'web' => array(
+ * 'class' => '\\Monolog\\Processor\\WebProcessor',
+ * ),
+ * ),
+ * 'handlers' => array(
+ * 'stream' => array(
+ * 'class' => '\\Monolog\\Handler\\StreamHandler',
+ * 'args' => array( 'path/to/your.log' ),
+ * 'formatter' => 'line',
+ * ),
+ * 'redis' => array(
+ * 'class' => '\\Monolog\\Handler\\RedisHandler',
+ * 'args' => array( function() {
+ * $redis = new Redis();
+ * $redis->connect( '127.0.0.1', 6379 );
+ * return $redis;
+ * },
+ * 'logstash'
+ * ),
+ * 'formatter' => 'logstash',
+ * ),
+ * 'udp2log' => array(
+ * 'class' => 'MWLoggerMonologHandler',
+ * 'args' => array(
+ * 'udp://127.0.0.1:8420/mediawiki
+ * ),
+ * 'formatter' => 'line',
+ * ),
+ * ),
+ * 'formatters' => array(
+ * 'line' => array(
+ * 'class' => '\\Monolog\\Formatter\\LineFormatter',
+ * ),
+ * 'logstash' => array(
+ * 'class' => '\\Monolog\\Formatter\\LogstashFormatter',
+ * 'args' => array( 'mediawiki', php_uname( 'n' ), null, '', 1 ),
+ * ),
+ * ),
+ * ) ),
* );
* @endcode
*
/**
- * @param array $config Configuration data. Defaults to global
- * $wgMWLoggerMonologSpiConfig
+ * @param array $config Configuration data.
*/
- public function __construct( $config = null ) {
- if ( $config === null ) {
- global $wgMWLoggerMonologSpiConfig;
- $config = $wgMWLoggerMonologSpiConfig;
- }
+ public function __construct( array $config ) {
$this->config = $config;
$this->reset();
}
$this->config['loggers'][$channel] :
$this->config['loggers']['@default'];
- $monolog = $this->createLogger( $channel, $spec );
- $this->singletons['loggers'][$channel] = new MWLogger( $monolog );
+ $monolog = $this->createLogger( $channel, $spec );
+ $this->singletons['loggers'][$channel] = new MWLogger( $monolog );
}
return $this->singletons['loggers'][$channel];
protected function getProcessor( $name ) {
if ( !isset( $this->singletons['processors'][$name] ) ) {
$spec = $this->config['processors'][$name];
- $this->singletons['processors'][$name] = $this->instantiate( $spec );
+ $processor = ObjectFactory::getObjectFromSpec( $spec );
+ $this->singletons['processors'][$name] = $processor;
}
return $this->singletons['processors'][$name];
}
protected function getHandler( $name ) {
if ( !isset( $this->singletons['handlers'][$name] ) ) {
$spec = $this->config['handlers'][$name];
- $handler = $this->instantiate( $spec );
+ $handler = ObjectFactory::getObjectFromSpec( $spec );
$handler->setFormatter( $this->getFormatter( $spec['formatter'] ) );
$this->singletons['handlers'][$name] = $handler;
}
protected function getFormatter( $name ) {
if ( !isset( $this->singletons['formatters'][$name] ) ) {
$spec = $this->config['formatters'][$name];
- $this->singletons['formatters'][$name] = $this->instantiate( $spec );
+ $formatter = ObjectFactory::getObjectFromSpec( $spec );
+ $this->singletons['formatters'][$name] = $formatter;
}
return $this->singletons['formatters'][$name];
}
-
-
- /**
- * Instantiate the requested object.
- *
- * The specification array must contain a 'class' key with string value that
- * specifies the class name to instantiate. It can optionally contain an
- * 'args' key that provides constructor arguments.
- *
- * @param array $spec Object specification
- * @return object
- */
- protected function instantiate( $spec ) {
- $clazz = $spec['class'];
- $args = isset( $spec['args'] ) ? $spec['args'] : array();
- // If an argument is a callable, call it.
- // This allows passing things such as a database connection to a logger.
- $args = array_map( function ( $value ) {
- if ( is_callable( $value ) ) {
- return $value();
- } else {
- return $value;
- }
- }, $args );
-
- if ( empty( $args ) ) {
- $obj = new $clazz();
-
- } else {
- $ref = new ReflectionClass( $clazz );
- $obj = $ref->newInstanceArgs( $args );
- }
-
- return $obj;
- }
-
}
public function __construct( array $config ) {
$this->domain = isset( $config['domain'] ) ? $config['domain'] : wfWikiID();
if ( isset( $config['lockTTL'] ) ) {
- $this->lockTTL = max( 1, $config['lockTTL'] );
+ $this->lockTTL = max( 5, $config['lockTTL'] );
} elseif ( PHP_SAPI === 'cli' ) {
- $this->lockTTL = 2 * 3600;
+ $this->lockTTL = 3600;
} else {
$met = ini_get( 'max_execution_time' ); // this is 0 in CLI mode
$this->lockTTL = max( 5 * 60, 2 * (int)$met );
"config-env-good": "Prostredie bolo skontrolované.\nMôžete nainštalovať MediaWiki.",
"config-env-bad": "Prostredie bolo skontrolované.\nNemôžete nainštalovať MediaWiki.",
"config-env-php": "PHP $1 je nainštalované.",
- "config-env-php-toolow": "PHP $1 je nainštalované. Avšak, MediaWiki vyžaduje PHP $2 alebo vyššie.",
+ "config-env-hhvm": "HHVM $1 je nainštalované.",
"config-db-type": "Typ databázy:",
"config-db-host": "Databázový server:",
"config-db-host-oracle": "Databázové TNS:",
"config-missing-db-name": "Musíte zadať hodnotu pre \"{{int:config-db-name}}\".",
"config-missing-db-host": "Musíte zadať hodnotu pre \"{{int:config-db-host}}\".",
"config-missing-db-server-oracle": "Musíte zadať hodnotu pre \"{{int:config-db-host-oracle}}\".",
+ "config-admin-box": "Účet správcu",
"config-admin-name": "Vaše používateľské meno:",
"config-admin-password": "Heslo:",
- "config-admin-password-confirm": "Zopakuj heslo:",
+ "config-admin-password-confirm": "Zopakujte heslo:",
"config-admin-name-blank": "Zadajte používateľské meno správcu.",
"config-admin-name-invalid": "Zadané používateľské meno \"<nowiki>$1</nowiki>\" je neplatné. \nZadajte iné meno.",
"config-admin-password-blank": "Zadajte heslo ku správcovskému účtu.",
--- /dev/null
+<?php
+/**
+ * @section LICENSE
+ * 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
+ *
+ * @file
+ */
+
+/**
+ * Construct objects from configuration instructions.
+ *
+ * @author Bryan Davis <bd808@wikimedia.org>
+ * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
+ */
+class ObjectFactory {
+
+ /**
+ * Instantiate an object based on a specification array.
+ *
+ * The specification array must contain a 'class' key with string value
+ * that specifies the class name to instantiate or a 'factory' key with
+ * a callable (is_callable() === true). It can optionally contain
+ * an 'args' key that provides arguments to pass to the
+ * constructor/callable.
+ *
+ * Object construction using a specification having both 'class' and
+ * 'args' members will call the constructor of the class using
+ * ReflectionClass::newInstanceArgs. The use of ReflectionClass carries
+ * a performance penalty and should not be used to create large numbers of
+ * objects. If this is needed, consider introducing a factory method that
+ * can be called via call_user_func_array() instead.
+ *
+ * Values in the arguments collection which are Closure instances will be
+ * expanded by invoking them with no arguments before passing the
+ * resulting value on to the constructor/callable. This can be used to
+ * pass DatabaseBase instances or other live objects to the
+ * constructor/callable.
+ *
+ * @param array $spec Object specification
+ * @return object
+ * @throws InvalidArgumentException when object specification does not
+ * contain 'class' or 'factory' keys
+ * @throws ReflectionException when 'args' are supplied and 'class'
+ * constructor is non-public or non-existant
+ */
+ public static function getObjectFromSpec( $spec ) {
+ $args = isset( $spec['args'] ) ? $spec['args'] : array();
+
+ $args = array_map( function ( $value ) {
+ if ( is_object( $value ) && $value instanceof Closure ) {
+ // If an argument is a Closure, call it.
+ return $value();
+ } else {
+ return $value;
+ }
+ }, $args );
+
+ if ( isset( $spec['class'] ) ) {
+ $clazz = $spec['class'];
+ if ( !$args ) {
+ $obj = new $clazz();
+ } else {
+ $ref = new ReflectionClass( $clazz );
+ $obj = $ref->newInstanceArgs( $args );
+ }
+ } elseif ( isset( $spec['factory'] ) ) {
+ $obj = call_user_func_array( $spec['factory'], $args );
+ } else {
+ throw new InvalidArgumentException(
+ 'Provided specification lacks both factory and class parameters.'
+ );
+ }
+
+ return $obj;
+ }
+}
if ( $exptime == 0 ) {
$encExpiry = $this->getMaxDateTime( $db );
} else {
- if ( $exptime < 3.16e8 ) { # ~10 years
- $exptime += time();
- }
+ $exptime = $this->convertExpiry( $exptime );
$encExpiry = $db->timestamp( $exptime );
}
foreach ( $serverKeys as $tableName => $tableKeys ) {
if ( $exptime == 0 ) {
$encExpiry = $this->getMaxDateTime( $db );
} else {
- if ( $exptime < 3.16e8 ) { # ~10 years
- $exptime += time();
- }
-
+ $exptime = $this->convertExpiry( $exptime );
$encExpiry = $db->timestamp( $exptime );
}
// (bug 24425) use a replace if the db supports it instead of
if ( $exptime == 0 ) {
$encExpiry = $this->getMaxDateTime( $db );
} else {
- if ( $exptime < 3.16e8 ) { # ~10 years
- $exptime += time();
- }
+ $exptime = $this->convertExpiry( $exptime );
$encExpiry = $db->timestamp( $exptime );
}
// (bug 24425) use a replace if the db supports it instead of
$options->setMaxIncludeSize( self::MAX_INCLUDE_SIZE );
if ( $this->generateXML ) {
- $wgParser->startExternalParse( $title, $options, OT_PREPROCESS );
+ $wgParser->startExternalParse( $title, $options, Parser::OT_PREPROCESS );
$dom = $wgParser->preprocessToDom( $input );
if ( method_exists( $dom, 'saveXML' ) ) {
"toolbox": "Strumèint",
"userpage": "Guêrda la pàgina utèint",
"projectpage": "Guêrda la pàgina dal prugèt",
- "imagepage": "Guêrda la pàgina dal 'file'",
+ "imagepage": "Guêrda la pàgina dal file",
"mediawikipage": "Guêrda al mesâg",
"templatepage": "Guêrda 'l mudèl",
"viewhelppage": "Guêrda la pàgina 'd ajót",
"nstab-media": "File multimediêl",
"nstab-special": "Pàgina specêla",
"nstab-project": "Pàgina 'd servési",
- "nstab-image": "'File'",
+ "nstab-image": "File",
"nstab-mediawiki": "Mesâg",
"nstab-template": "Mudèl",
"nstab-help": "Pàgina 'd ajót",
"nowiki_sample": "Mèt dèinter ché al tèst mìa furmatê",
"nowiki_tip": "An badêr mìa la furmatasiòun wiki",
"image_tip": "Mèt dèinter al file",
- "media_tip": "Colegamèint al 'file'",
+ "media_tip": "Colegamèint al file",
"sig_tip": "Fîrma cun la dâta e l'ōra",
"hr_tip": "Rîga spiâna (drōva cun giudési)",
"summary": "Ogèt:",
"searchprofile-everything": "Tót",
"searchprofile-advanced": "Specêla",
"searchprofile-articles-tooltip": "Sèirca in $1",
- "searchprofile-images-tooltip": "Sèirca 'file'",
+ "searchprofile-images-tooltip": "Sèirca file",
"searchprofile-everything-tooltip": "Sērca dapertót (ânch int al pàgini 'd discusuòun).",
"searchprofile-advanced-tooltip": "Sērca int i spâsi di nòm fât só mzûra.",
"search-result-size": "$1 ({{PLURAL:$2|'na parôla|$2 parôli}})",
"action-edit": "Mudifichêr cla pàgina ché",
"action-createpage": "inventêr pàgini",
"action-move": "spustêr cla pàgina ché",
- "action-movefile": "spustêr cól 'file' ché",
- "action-upload": "carghêr cól 'file' ché",
+ "action-movefile": "spustêr cól file ché",
+ "action-upload": "carghêr cól file ché",
"action-delete": "scanşlêr cla pàgina ché",
"nchanges": "$1\n{{PLURAL:$1|mudéfica|mudéfichi}}",
"recentchanges": "Ûltmi mudéfichi",
"recentchangeslinked-summary": "Cla pàgina specêla ché la fà vèder al j ûltmi mudéfichi al pàgini coleghêdi da còla sgnêda (o dèinter int la categoréia sgnêda). Al pàgini dèint a la tó lésta 'd j [[Special:Watchlist|tgnû sòt ôc specêl]] în sgnêdi in '''grasèt'''.",
"recentchangeslinked-page": "Nòm ' d la pàgina.",
"recentchangeslinked-to": "Fà vèder sōl al mudéfichi fâti al pàgini coleghêdi a còla sgnêda.",
- "upload": "Cârga un 'file'",
+ "upload": "Cârga un file",
"uploadlogpage": "Fil carghê",
"filedesc": "Particulêr.",
"license": "Licèinsa:",
"listfiles_date": "Dâta",
"listfiles_name": "Nòm",
"listfiles_user": "Utèint",
- "file-anchor-link": "'File'",
+ "file-anchor-link": "File",
"filehist": "Stòria 'd la pàgina",
"filehist-help": "Fà cléch insém a 'n gróp dâta/ōra per vèder al file cm'é l'ēra int al mumèint e-sgnê",
"filehist-revert": "armèt",
"filehist-user": "Utèint",
"filehist-dimensions": "Amzûri",
"filehist-comment": "Cumèint",
- "imagelinks": "Ûş dal 'file'",
+ "imagelinks": "Ûş dal file",
"linkstoimage": "{{PLURAL:$1|Int la pàgina seguèint a gh'é|Int al seguèinti $1 pàgini a gh'é}} colegamèint al file:",
"nolinkstoimage": "Nisóna pàgina la gh'à colegamèint al file",
"sharedupload-desc-here": "Cól file ché al deşvîn da $1 e al pōl èser druvê da êter prugèt. Ed sègvit a vîn fât vèder la spiegasiòun che gh'é int la [$2 pàgina de spiegasiòun dal file].",
"nolinkshere": "Nisóna pàgina la gh'à dèinter colegamèint che pûnten a '''[[:$1]]'''.",
"isredirect": "Pàgina redirect",
"istemplate": "uniòun",
- "isimage": "Colegamèint vêrs al 'file'",
+ "isimage": "Colegamèint vêrs al file",
"whatlinkshere-prev": "{{PLURAL:$1|còl préma|quî préma $1}}",
"whatlinkshere-next": "{{PLURAL:$1|còl dôp|quî dôp $1}}",
"whatlinkshere-links": "← colegamèint",
"allmessages-filter-submit": "Và",
"thumbnail-more": "Ingrandés",
"thumbnail_error": "Erōr mèinter ét fêv la miniadûra:$1",
- "import-upload-filename": "Nòm dal 'file':",
+ "import-upload-filename": "Nòm dal file:",
"import-comment": "Argumèint:",
"import-upload": "Cârga infurmasiòun XML",
"tooltip-pt-userpage": "La tó pàgina utèint",
"tooltip-feed-atom": "Feed Atom per cla pàgina ché.",
"tooltip-t-contributions": "Lèsta di lavōr fât da cl'utèint ché.",
"tooltip-t-emailuser": "Mânda un mesâg cun la pòsta eletrônica a cl'utèint ché",
- "tooltip-t-upload": "Cârga un 'file'",
+ "tooltip-t-upload": "Cârga un file",
"tooltip-t-specialpages": "Elèinch ed tót al pàgini specêli",
"tooltip-t-print": "Per stampêr cla pàgina ché.",
"tooltip-t-permalink": "Colegamèint fés a cla versiòun ché 'd la pàgina.",
"tooltip-ca-nstab-user": "Guêrda la pàgina utèint",
"tooltip-ca-nstab-special": "Còsta ché l'é 'na pàgina specêlal l'an pōl mìa èser mudifichêda",
"tooltip-ca-nstab-project": "Guêrda la pàgina dal prugèt",
- "tooltip-ca-nstab-image": "Guêrda la pàgina dal 'file'",
+ "tooltip-ca-nstab-image": "Guêrda la pàgina dal file",
"tooltip-ca-nstab-template": "Guêrda 'l mudèl",
"tooltip-ca-nstab-help": "Guêrda la pàgina d'ajót",
"tooltip-ca-nstab-category": "Guêrda la pàgina 'd la categoréia",
"ilsubmit": "Sērca",
"bydate": "per dâta",
"ago": "$1 fa",
- "bad_image_list": "La manēra l'é còsta:\n\na vînen cunsidrê sōl j elèinch puntê (ríghi che cumîncen cun al carâter *). Al prém colegamèint só ògni rîga al dēv èser un colegamèint a un 'file' mìa vrû. I colegamèint che vînen dôp, int l'istèsa rîga, în cunsidrê cme un chêş (oséia, pàgini in dó al 'file' al pōl èser arciamê normalmèint).",
+ "bad_image_list": "La manēra l'é còsta:\n\na vînen cunsidrê sōl j elèinch puntê (ríghi che cumîncen cun al carâter *). Al prém colegamèint só ògni rîga al dēv èser un colegamèint a un file mìa vrû. I colegamèint che vînen dôp, int l'istèsa rîga, în cunsidrê cme un chêş (oséia, pàgini in dó al file al pōl èser arciamê normalmèint).",
"metadata": "Metadati",
"metadata-help": "In cól file ché agh'é dal j infurmasiòun zuntêdi, prubabilmèint zuntêdi da la mâchina fotogrâfica o dal scàner druvê per fotografêrel o per fêrel dvintêr digitêl. Se al file l'é stê mudfifichê, soquânt particulêr a prén cumbinêr mìa cun la realtê.",
"metadata-fields": "I câmp relatîv a i metadati ed la figûra, in lésta in cól mesâg ché, a gnirân més int la pàgina ed la figûra quând la tabèla di metadati l'é mustrêda int la fōrma cûrta. Per impustasiòun pre-stabilîda, chiêter câmp a gnirân lughê. \n* make \n* model \n* datetimeoriginal \n* exposuretime \n* fnumber \n* isospeedratings \n* focallength \n* artist \n* copyright \n* imagedescription \n* gpslatitude \n* gpslongitude \n* gpsaltitude",
"version-version": "($1)",
"version-license": "Licèinsa Media Wiki",
"version-poweredby-others": "êter",
- "fileduplicatesearch-filename": "Nòm dal 'file':",
+ "fileduplicatesearch-filename": "Nòm dal file:",
"fileduplicatesearch-submit": "Sērca",
"specialpages": "Pàgini specêli",
"external_image_whitelist": "#Lasêr cla pàgina ché acsé cme l'é<pre>\n#Mèter dèinter i pès dal j espresiòun regolêri (sōl la pêrta cla va fra //) ed sègvit\n#Còsti gnirân més a cunfrûnt cun j indirés URL dal figûri d'ed fōra (hotlinked) \n#Al cunbinasiòun asrân fât vèder cme figûri, se no a gnirà fât vèder sōl al colegamèint\n#Al rîghi che cumîncen cun # în cunsidrêdi di cumèint\n#La diferèinsa tr' al lètri grândi e al lètri céchi an gh'à mìa impurtânsa\n\n#Mèter sōver cla rîga ché tót i pès di regex. Lasêr cla rîga ché acsé cme l'é</pre>",
"search-result-category-size": "{{PLURAL:$1|1 μέλος|$1 μέλη}} ({{PLURAL:$2|1 υποκατηγορία|$2 υποκατηγορίες}}, {{PLURAL:$3|1 αρχείο|$3 αρχεία}})",
"search-redirect": "(ανακατεύθυνση $1)",
"search-section": "(ενότητα $1)",
+ "search-category": "(κατηγορία $1)",
"search-file-match": "(ταιριάζει με το περιεχόμενο του αρχείου)",
"search-suggest": "Μήπως εννοούσατε: $1",
"search-interwiki-caption": "Αδελφικά εγχειρήματα",
"view-pool-error": "Valitettavasti palvelimet ovat ylikuormittuneet tällä hetkellä.\nLiian monta käyttäjää yrittää tarkastella tätä sivua.\nOdota hetki ennen kuin yrität uudelleen.\n\n$1",
"generic-pool-error": "Valitettavasti palvelimet ovat ylikuormittuneet tällä hetkellä.\nLiian monta käyttäjää yrittää tarkastella tätä sivua.\nOdota hetki ennen kuin yrität uudelleen.",
"pool-timeout": "Lukon aikakatkaisu.",
- "pool-queuefull": "Lukkojono on täysi.",
+ "pool-queuefull": "Prosessijoukon jono on täynnä",
"pool-errorunknown": "Tuntematon virhe.",
"pool-servererror": "Pool counter -palvelu ei ole käytettävissä ($1).",
"aboutsite": "Tietoja {{GRAMMAR:elative|{{SITENAME}}}}",
"search-result-category-size": "{{PLURAL:$1|1 jäsen|$1 jäsentä}} ({{PLURAL:$2|1 alaluokka|$2 alaluokkaa}}, {{PLURAL:$3|1 tiedosto|$3 tiedostoa}})",
"search-redirect": "(ohjaus $1)",
"search-section": "(osio $1)",
+ "search-category": "(luokka $1)",
"search-file-match": "(vastaa tiedoston sisältöä)",
"search-suggest": "Tarkoititko: $1",
"search-interwiki-caption": "Sisarprojektit",
"powersearch-remember": "Muista valinta tulevia hakuja varten",
"search-external": "Ulkoinen haku",
"searchdisabled": "Tekstihaku on poistettu toistaiseksi käytöstä suuren kuorman vuoksi. Voit käyttää alla olevaa Googlen hakukenttää sivujen etsimiseen, kunnes haku tulee taas käyttöön. <small>Huomaa, että ulkopuoliset kopiot {{GRAMMAR:genitive|{{SITENAME}}}} sisällöstä eivät välttämättä ole ajan tasalla.</small>",
- "search-error": "Virhe ilmaantui haettaessa: $1",
+ "search-error": "Hakutoiminnossa on havaittu virhe: $1",
"preferences": "Asetukset",
"mypreferences": "Asetukset",
"prefs-edits": "Muokkauksia",
"unblockiptext": "Tällä lomakkeella voit poistaa käyttäjän tai IP-osoitteen muokkauseston.",
"ipusubmit": "Poista tämä esto",
"unblocked": "Käyttäjän [[User:$1|$1]] esto on poistettu",
- "unblocked-range": "$1 ei ole enää estettynä",
+ "unblocked-range": "Osoitealueen $1 muokkausesto on poistettu.",
"unblocked-id": "Esto $1 on poistettu",
"unblocked-ip": "Käyttäjän [[Special:Contributions/$1|$1]] esto on poistettu.",
"blocklist": "Estetyt käyttäjät",
"search-result-category-size": "$1 membre{{PLURAL:$1||s}} ($2 sous-catégorie{{PLURAL:$2||s}}, $3 fichier{{PLURAL:$3||s}})",
"search-redirect": "(redirection depuis $1)",
"search-section": "(section $1)",
+ "search-category": "(catégorie $1)",
"search-file-match": "(correspond au contenu du fichier)",
"search-suggest": "Essayez avec cette orthographe : $1",
"search-interwiki-caption": "Projets frères",
"content-model-text": "testo normale",
"content-model-javascript": "JavaScript",
"content-model-css": "CSS",
- "duplicate-args-category": "Pagine che usano argomenti duplicati in chiamate a template",
+ "duplicate-args-category": "Pagine contenenti chiamate a template con parametri duplicati",
"duplicate-args-category-desc": "La pagina contiene chiamate a template che utilizzano argomenti duplicati, come ad esempio <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> o <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
"expensive-parserfunction-warning": "'''Attenzione:''' Questa pagina contiene troppe chiamate alle parser functions.\n\nDovrebbe averne meno di $2, al momento ce {{PLURAL:$1|n'è $1|ne sono $1}}.",
"expensive-parserfunction-category": "Pagine con troppe chiamate alle funzioni parser",
"search-result-category-size": "{{PLURAL:$1|1 utente|$1 utenti}} ({{PLURAL:$2|1 sottocategoria|$2 sottocategorie}}, {{PLURAL:$3|1 file|$3 files}})",
"search-redirect": "(redirect $1)",
"search-section": "(sezione $1)",
+ "search-category": "(categoria $1)",
"search-file-match": "(corrispondenza nel contenuto del file)",
"search-suggest": "Forse cercavi: $1",
"search-interwiki-caption": "Progetti fratelli",
"아라",
"Rxy",
"Mfuji",
- "Takot"
+ "Takot",
+ "SkyDaisy9"
]
},
"tog-underline": "リンクの下線:",
"revdelete-uname-unhid": "利用者名の可視化",
"revdelete-restricted": "管理者に対する制限の適用",
"revdelete-unrestricted": "管理者に対する制限の除去",
+ "logentry-merge-merge": "$1 {{GENDER:$2|統合元}} と$3 を $4 に統合(改訂版を$5に掲載)",
"logentry-move-move": "$1 がページ「$3」を「$4」に{{GENDER:$2|移動しました}}",
"logentry-move-move-noredirect": "$1 がページ「$3」を「$4」に、リダイレクトを残さずに{{GENDER:$2|移動しました}}",
"logentry-move-move_redir": "$1 がページ「$3」をリダイレクトの「$4」に{{GENDER:$2|移動しました}}",
"prefs-diffs": "Verschillen",
"prefs-help-prefershttps": "Deze voorkeur wordt toegepast bij de volgende keer aanmelden.",
"prefswarning-warning": "U heeft deze wijzigingen gemaakt in uw voorkeuren die nog niet opgeslagen zijn. Wanneer u de pagina verlaat zonder op \"$1\" te klikken zullen uw voorkeuren niet geüpdated worden.",
- "prefs-tabs-navigation-hint": "Tip: U kunt de pijltjestoetsen naar links en naar rechts gebruiken om te navigeren tussen de tabbladen in de lijst.",
+ "prefs-tabs-navigation-hint": "Tip: u kunt de pijltjestoetsen naar links en naar rechts gebruiken om te navigeren tussen de tabbladen in de lijst.",
"email-address-validity-valid": "Het e-mailadres lijkt geldig",
"email-address-validity-invalid": "Geef een geldig e-mailadres op",
"userrights": "Gebruikersrechtenbeheer",
"default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (abilità)",
"default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''disabilità''')",
"mediastatistics": "Statìstiche an sij mojen",
- "mediastatistics-summary": "Statìstiche an sle sòrt d'archivi carià. A ancludo mach la version pi recent ëd n'archivi. Le version veje o dëscancelà dj'archivi a son escludùe."
+ "mediastatistics-summary": "Statìstiche an sle sòrt d'archivi carià. A ancludo mach la version pi recent ëd n'archivi. Le version veje o dëscancelà dj'archivi a son escludùe.",
+ "mediastatistics-nbytes": "{{PLURAL:$1|$1 otet}} ($2 ; $3%)",
+ "mediastatistics-table-mimetype": "Sòrt MIME",
+ "mediastatistics-table-extensions": "Estension possìbij",
+ "mediastatistics-table-count": "Nùmer d'archivi",
+ "mediastatistics-table-totalbytes": "Taja combinà",
+ "mediastatistics-header-unknown": "Nen conossù",
+ "mediastatistics-header-bitmap": "Plance bitmap"
}
"@metadata": {
"authors": [
"Aursani",
- "아라"
+ "아라",
+ "Fayazburiro"
]
},
- "tog-showtoolbar": "سنوارپ اوزار دٻي ڏيکاريو (جاوا اسڪرپٽ)",
- "tog-watchcreations": "منهنجا سرجيل صفحا منهنجي ٽيٽ فهرست ۾ رکو",
- "tog-watchdefault": "منهنجا ترميميل صفحا منهنجي ٽيٽ فهرست تي رکو",
+ "tog-underline": "هيٺان ڏنل لڪير واري لنڪ",
+ "tog-hideminor": "تازيون ننڍيون تبدليون لڪايو",
+ "tog-hidepatrolled": "تازيون گھميل تبديليون لڪايو",
+ "tog-newpageshidepatrolled": "نئين صفحن تان تازي گھميل صفحي جي لسٽ لڪايو",
+ "tog-numberheadings": "خودڪار نمبرن واري هيڊنگ",
+ "tog-showtoolbar": "ايڊٽ بار ڏيکاريو",
+ "tog-editondblclick": "ٻٽي ڪلڪ تي صفحا ايڊت ڪيو",
+ "tog-watchcreations": "منهنجا سرجيل صفحا منهنجي نهار فهرست ۾ رکو",
+ "tog-watchdefault": "منهنجا ترميميل صفحا منهنجي نهار فهرست تي رکو",
"tog-watchdeletion": "آئون جيڪي صفحا ڊاهيان، سي منهنجي ٽيٽ فهرست تي رکو",
+ "tog-watchrollback": "انهن صفحن کي منهنجي ٽيٽ فهرست تي رکو، جن ۾ تبديلين کي مون واپس ورايو آهي.",
"tog-previewontop": "ترميمي باڪس مٿان پيش نگاهه ڏيکاريو",
"tog-previewonfirst": "پهرين ترميم تي پيش نگاهه ڏيکاريو",
"tog-enotifusertalkpages": "منهنجي مباحثي صفحي ۾ تبديليءَ جي صورت ۾ مون کي برق ٽپال اماڻيو",
- "tog-enotifminoredits": "صفحن ۾ معمولي ترميمن جي صورت ۾ به مون کي برق ٽپال ڪريو",
+ "tog-enotifminoredits": "صفحن ۾ معمولي ترميمن جي صورت ۾ بہ مون کي برق ٽپال ڪريو",
"tog-shownumberswatching": "ٽيٽيندڙ يوزرس جو تعداد ڏيکاريو",
+ "tog-oldsig": "موجوده دستخط",
+ "tog-watchlisthideliu": "لاگ اِن ٿيل يوزرس جون ڪيل ترميمون ٽيٽ فهرست ۾ نہ ڏيکاريو",
"tog-ccmeonemails": "ٻين يوزرس ڏانهن منهنجي موڪليل برق ٽپال جو پرت مون کي اماڻيو",
"tog-diffonly": "تفاوت هيٺان صفحي جو مواد نه ڏيکاريو",
"tog-showhiddencats": "لڪل زمرا ڏيکاريو",
"oct": "آڪٽوبر",
"nov": "نومبر",
"dec": "ڊسمبر",
+ "january-date": "جنوري $1",
+ "february-date": "فيبروري $1",
+ "march-date": "مارچ $1",
+ "april-date": "اپريل $1",
+ "may-date": "مَي $1",
+ "june-date": "جُون $1",
+ "july-date": "جُولاءِ $1",
+ "august-date": "آگسٽ $1",
+ "september-date": "سيپٽمبر $1",
+ "october-date": "آڪٽوبر $1",
+ "november-date": "نَوِمبر $1",
+ "december-date": "ڊسمبر $1",
"category_header": "\"$1\" زمري جا صفحا",
"subcategories": "ذيلي زمرا",
"category-media-header": " \"$1\" زمري اندر ذريعات",
"cancel": "رد",
"moredotdotdot": "اڃا...",
"mypage": "منهنجو صفحو",
- "mytalk": "مون سان ڳالهه",
+ "mytalk": "ڳاله ٻوله",
"and": " ۽",
"qbfind": "ڳوليو",
"qbbrowse": "جھانگيو",
"printableversion": "ڇپائتو پرت",
"permalink": "مسقتل ڳنڍڻو",
"print": "ڇاپيو",
+ "view": "نگاهہ",
"edit": "سنواريو",
+ "edit-local": "مقامي وضاحت کي ترميميو",
"create": "سرجيو",
"editthispage": "هيءُ صفحو سنواريو",
"create-this-page": "اهو صفحو نئين سر جوڙيو",
"delete": "ڊاھيو",
"deletethispage": "هيءُ صفحو ڊاهيو",
+ "undeletethispage": "هيءُ صفحو اڻ ڊاهيو",
"undelete_short": "اڻڊاهيو {{PLURAL:$1|هڪ ترميم|$1 ترميمون}}",
"protect": "تحفظيو",
+ "protect_change": "تبديل ڪريو",
"protectthispage": "هيءُ صفحو تحفظيو",
- "unprotect": "اڻتØÙ\81ظيو",
- "unprotectthispage": "Ù\87Ù\8aØ¡Ù\8f صÙ\81ØÙ\88 اڻتØÙ\81ظيو",
+ "unprotect": "ØÙ\81اظت Ù\85Ù½يو",
+ "unprotectthispage": "Ù\87Ù\86 صÙ\81ØÙ\8a جÙ\8a ØÙ\81اظت Ù\85Ù½يو",
"newpage": "نئون صفحو",
"talkpage": "هن صفحي تي بحث ڪريو",
"talkpagelinktext": "بحث",
"articlepage": "مسودو ڏسو",
"talk": "بحث",
"views": "ڏيٺون",
- "toolbox": "اوزاردٻي",
+ "toolbox": "ٽولَ",
"userpage": "يوزر صفحو ڏسو",
"projectpage": "رٿائي صفحو ڏسو",
"imagepage": "ذريعاتي صفحو ڏسو",
"otherlanguages": "ٻين ٻولين ۾",
"redirectedfrom": "($1 کان چوريل)",
"redirectpagesub": "چوريل صفحو",
+ "redirectto": "منتقل ڪيو",
"lastmodifiedat": "هيءُ صفحو آخري ڀيرو $2، $1ع تي ترميميو ويو هو.",
"viewcount": "هيءُ صفحو {{PLURAL:$1|دفعو|$1 دفعا}} ڏسجي چڪو آهي.",
"protectedpage": "تحفظيل صفحو",
+ "jumpto": "ڏانهن ٽپ ڏيو",
+ "jumptonavigation": "رهنمائي",
"jumptosearch": "ڳولا",
+ "generic-pool-error": "معذرت سان سرور هاڻي تمام گھڻو سُڪ آهي.\nتمام گھڻا يوزر هتي موجود آهن.\nمهرباني ڪري ٿورو ترسي پوءِ ڪوشش ڪريو.",
+ "pool-errorunknown": "اڻ ڄاتل چُڪَ",
"aboutsite": "{{SITENAME}} بابت",
"aboutpage": "Project:بابت",
"copyright": "سمورو مواد $1 تحت ميسر ڪجي ٿو",
"portal-url": "Project:نياتي باب",
"privacy": "ذاتيات پاليسي",
"privacypage": "Project:ذاتيات پاليسي",
+ "badaccess": "اجازتنامہ چُڪَ",
"ok": "ٺيڪ",
"retrievedfrom": "\"$1\" تان ورتل",
"youhavenewmessages": "توهان لاءِ $1 ($2) آهن.",
+ "youhavenewmessagesmulti": "$1 تي توهان لاءِ نوان نياپا آهن",
"editsection": "سنواريو",
"editold": "سنواريو",
"viewsourceold": "ڪوڊ ڏسو",
"toc": "فهرست",
"showtoc": "ڏيکاريو",
"hidetoc": "لڪايو",
+ "confirmable-yes": "ها",
+ "confirmable-no": "نه",
"viewdeleted": "$1 ڏسندا؟",
"feedlinks": "روان رسد:",
"site-rss-feed": "$1 آر ايس ايس روان رسد",
"search-result-category-size": "$1 trang thành viên ($2 thể loại con, $3 tập tin)",
"search-redirect": "(đổi hướng $1)",
"search-section": "(đề mục $1)",
+ "search-category": "(thể loại $1)",
"search-file-match": "(khớp nội dung tập tin)",
"search-suggest": "Có phải bạn muốn tìm: $1",
"search-interwiki-caption": "Các dự án liên quan",
--- /dev/null
+<?php
+/**
+ * Cleans up user blocks with user names not matching the 'user' table
+ *
+ * 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
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Maintenance script to clean up user blocks with user names not matching the
+ * 'user' table.
+ *
+ * @ingroup Maintenance
+ */
+class CleanupBlocks extends Maintenance {
+
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Cleanup user blocks with user names not matching the 'user' table";
+ $this->setBatchSize( 1000 );
+ }
+
+ public function execute() {
+ $db = wfGetDB( DB_MASTER );
+
+ $max = $db->selectField( 'ipblocks', 'MAX(ipb_user)' );
+
+ // Step 1: Clean up any duplicate user blocks
+ for ( $from = 1; $from <= $max; $from += $this->mBatchSize ) {
+ $to = min( $max, $from + $this->mBatchSize - 1 );
+ $this->output( "Cleaning up duplicate ipb_user ($from-$to of $max)\n" );
+
+ $delete = array();
+
+ $res = $db->select(
+ 'ipblocks',
+ array( 'ipb_user' ),
+ array(
+ "ipb_user >= $from",
+ "ipb_user <= $to",
+ ),
+ __METHOD__,
+ array(
+ 'GROUP BY' => 'ipb_user',
+ 'HAVING' => 'COUNT(*) > 1',
+ )
+ );
+ foreach ( $res as $row ) {
+ $bestBlock = null;
+ $res2 = $db->select(
+ 'ipblocks',
+ '*',
+ array(
+ 'ipb_user' => $row->ipb_user,
+ )
+ );
+ foreach ( $res2 as $row2 ) {
+ $block = Block::newFromRow( $row2 );
+ if ( !$bestBlock ) {
+ $bestBlock = $block;
+ continue;
+ }
+
+ // Find the most-restrictive block. Can't use
+ // Block::chooseBlock because that's for IP blocks, not
+ // user blocks.
+ $keep = null;
+ if ( $keep === null && $block->getExpiry() !== $bestBlock->getExpiry() ) {
+ // This works for infinite blocks because 'infinity' > '20141024234513'
+ $keep = $block->getExpiry() > $bestBlock->getExpiry();
+ }
+ if ( $keep === null ) {
+ foreach ( array( 'createaccount', 'sendemail', 'editownusertalk' ) as $action ) {
+ if ( $block->prevents( $action ) xor $bestBlock->prevents( $action ) ) {
+ $keep = $block->prevents( $action );
+ break;
+ }
+ }
+ }
+
+ if ( $keep ) {
+ $delete[] = $bestBlock->getId();
+ $bestBlock = $block;
+ } else {
+ $delete[] = $block->getId();
+ }
+ }
+ }
+
+ if ( $delete ) {
+ $db->delete(
+ 'ipblocks',
+ array( 'ipb_id' => $delete ),
+ __METHOD__
+ );
+ }
+ }
+
+ // Step 2: Update the user name in any blocks where it doesn't match
+ for ( $from = 1; $from <= $max; $from += $this->mBatchSize ) {
+ $to = min( $max, $from + $this->mBatchSize - 1 );
+ $this->output( "Cleaning up mismatched user name ($from-$to of $max)\n" );
+
+ $res = $db->select(
+ array( 'ipblocks', 'user' ),
+ array( 'ipb_id', 'user_name' ),
+ array(
+ 'ipb_user = user_id',
+ "ipb_user >= $from",
+ "ipb_user <= $to",
+ 'ipb_address != user_name',
+ ),
+ __METHOD__
+ );
+ foreach ( $res as $row ) {
+ $db->update(
+ 'ipblocks',
+ array( 'ipb_address' => $row->user_name ),
+ array( 'ipb_id' => $row->ipb_id ),
+ __METHOD__
+ );
+ }
+ }
+
+ $this->output( "Done!\n" );
+ }
+}
+
+$maintClass = "CleanupBlocks";
+require_once RUN_MAINTENANCE_IF_MAIN;
$this->setNamespacePriorities();
$this->url_limit = 50000;
$this->size_limit = pow( 2, 20 ) * 10;
- $this->fspath = self::init_path( $this->getOption( 'fspath', getcwd() ) );
+
+ # Create directory if needed
+ $fspath = $this->getOption( 'fspath', getcwd() );
+ if ( !wfMkdirParents( $fspath, null, __METHOD__ ) ) {
+ $this->error( "Can not create directory $fspath.", 1 );
+ }
+
+ $this->fspath = realpath( $fspath ) . DIRECTORY_SEPARATOR;
$this->urlpath = $this->getOption( 'urlpath', "" );
if ( $this->urlpath !== "" && substr( $this->urlpath, -1 ) !== '/' ) {
$this->urlpath .= '/';
}
}
- /**
- * Create directory if it does not exist and return pathname with a trailing slash
- * @param string $fspath
- * @return null|string
- */
- private static function init_path( $fspath ) {
- # Create directory if needed
- if ( $fspath && !is_dir( $fspath ) ) {
- wfMkdirParents( $fspath, null, __METHOD__ ) or die( "Can not create directory $fspath.\n" );
- }
-
- return realpath( $fspath ) . DIRECTORY_SEPARATOR;
- }
-
/**
* Generate a one-dimensional array of existing namespaces
*/