Index: trunk/phase3/RELEASE-NOTES =================================================================== --- trunk/phase3/RELEASE-NOTES (revision 14411) +++ trunk/phase3/RELEASE-NOTES (revision 14412) @@ -1,422 +1,426 @@ = MediaWiki release notes = Security reminder: MediaWiki does not require PHP's register_globals setting since version 1.2.0. If you have it on, turn it *off* if you can. == MediaWiki 1.7 == THIS IS NOT A RELEASE YET. MediaWiki is now using a "continuous integration" development model with quarterly snapshot releases. The latest development code is always kept "ready to run", and in fact runs our own sites on Wikipedia. Release branches will continue to receive security updates for about a year from first release, but nonessential bugfixes and feature development happen will be made on the development trunk and appear in the next quarterly release. Those wishing to use the latest code instead of a branch release can obtain it from source control: http://www.mediawiki.org/wiki/Download_from_SVN == Changes since 1.6 == * (bug 5458) Fix double-URL encoding in block log link in contribs and contribs link in block log * (bug 5462) Bogus missing patch warning in updater * (bug 5461) Use of deprecated "showhideminor" in Special:Recentchangeslinked * PHP warning when allow_call_time_pass_reference is off * Update to Finnish localization * (bug 5467) Link to page histories in watchlist edit mode * Further additions to Hebrew localisation * (bug 5476) Invalid xhtml in German localization * (bug 5479) Id translation for preferences tabs caption * (bug 5493) Id translation for special pages * Added skinname and style path parameters to CBT version of MonoBook * Include subversion revision number in Special:Version if available * (bug 5344) Fix regression that broke slashes in extension tag parameters * Improve Special:Log performance on big log sets * (bug 5507) Changed mediawiki:logouttext from plain to wikitext * (bug 4760) Prevent creation of entries in protection log when protection levels haven't changed * (bug 861) Show page protection/unprotection events in histories * (bug 5499) Don't clear the tag strip state when asked not to clear state. Fixes regression with use of in a template breaking etc. * Minor improvements to English language files * Display the anon talk page info message on anon talk pages again (moved outside the parser cache) * Optional {{DISPLAYTITLE|title with markup}} magic word Deactivated by default, set "$wgAllowDisplayTitle = true" in LocalSettings.php to activate * Cleaned SpecialContributions a bit * Added a table to track interlanguage links * (bug 5544) Fix redirect arrow in Special:Listredirects for right-to-left languages * Replace "doubleredirectsarrow" with a content language check that picks the appropriate arrow * (bug 5537) Add stub language file for Samogitian (bat-smg); inherits Lithuanian (lt) * Don't force edit summaries when a user is editing their own user/talk page * (bug 5510) Warning produced when using {{SUBPAGENAME}} in some namespaces * (bug 385) Installer support for PostgreSQL, fixes for PG compatibility * PersistentObject removed; it doesn't do anything and was broken besides. All extensions using it have been corrected. * Propagate ISBN number for Booksources in LanguageNo.php * (bug 5548) Improvements to Indonesian localisation [patch: Ivan Lanin] * Add TALKSPACE, SUBJECTSPACE, TALKPAGENAME, SUBJECTPAGENAME (and encoded forms for all) magic words * (bug 5403) Fix Special:Newpages RSS/Atom feeds * Reject malformed addresses in X-Forwarded-For entries * (bug 3359) Add hooks on completion of file upload * (bug 5559) Improve detection of ImageMagick [patch: Greg Turnquist] * (bug 5475) New pages feeds ignore "limit" argument * (bug 5184) CSS misapplied to elements in Special:Allmessages due to conflicting anchor identifiers * (bug 5519) Allow sidebar cache to be disabled; disable it by default. * Maintenance script to import the contents of a text file into a wiki page * Add $wgReservedUsernames configuration directive to block account creation/use * (bug 5576) Remove debugging hack in session check * (bug 5426) Lowercase treatment of titles in rights log leads to broken links on Special:Log * Minor improvements to French localisation files * (bug 5181) Update "nogomatch" for Slovak * (bug 5594) Id translation up to # Login and logout pages section * (bug 5536) Use content language for editing help link * Improvements to German localisation files * (bug 5570) Problems using /parameter link form for long titles * (bug 3884) Add $user parameter to AddNewUser hook, call it for by-email registrations as well as self-registrations. * (bug 4327) Report age of cached data sets in query pages * (bug 4662) Fix Safari check in wikibits.js * (bug 4663) Edit toolbar enabled in compatible versions of Safari * (bug 5572) Edit toolbar enabled in compatible versions of Konqueror (3.5+) * (bug 5235) Edit toolbar tooltips no longer show JavaScript junk in Opera * Edit toolbar now works in pure XHTML mode (application/xhtml+xml) * Add watchlist clear function to allow quick purging of all items * (bug 5625) Additional namespace translations for Welsh * Add meta tag and JavaScript variables to cached special pages which provides the timestamp of the last update, in YYYYMMDDHHMMSS format. * (bug 5628) More translations for MessagesHr.php * (bug 5595) Localisation for Bosnian language (bs) * (bug 2910) Default view preferences for watchlists * Add "hide bot edits from the watchlist" user preference * (bug 5250) Introduce Special:Unusedtemplates * Add user preference setting for an extended watchlist, showing all recent edits up to a certain edit, and not just the latest edit.. * Made MessageRo.php more general * (bug 5640) Indonesian localisation improvements * (bug 5592) Actions are logged with the default language for the wiki, not the language of the user performing the operation. * (bug 5644) Error in LanguageBs.php file * (bug 5646) Compare for identical types in wfElement() * (bug 5472) Language::userAdjust()->minDiff not initialized on else condition * (bug 5386) LanguageMk.php: updated namespaces translations * (bug 5422) Stub for Romani (rmy) language which extends ro * Fix linktrail for LanguageSr * (bug 5664) Fix Bosnian linktrail * (bug 3825) Namespace filtering on Special:Newpages * (bug 1922) When Special:Wantedpages is cached, mark links to pages which have since been created * (bug 5659) Change grammar hacks for Bosnian Wikimedia namespaces. This sort of special casing should be removed and fixed properly. * Remove useless whitespace from Special:Brokenredirects header * Treat "allmessagesnotsupporteddb" as wikitext when echoing; change default text * (bug 5497) Regression in HTML normalization in 1.6 (unclosed
  • ,
    ,
    ) * (bug 5709) Allow customisation of separator for categories * (bug 5684) Introduce Special:Randomredirect * (bug 5611) Add a name attribute to the text box containing source text in read-only pages * Indicate when a protected page is an interface message ("protectedinterface") * (bug 4259) Indicate when a protected page being edited is an interface message ("editinginterface") * (bug 4834) Fix XHTML output when using $wgMaxTocLevel * Pass login link to "whitelistedittext" containing 'returnto' parameter * (bug 5728): mVersion missing from User::__sleep() leading to constant cache miss * Updated maintenance/transstat.php so it can show duplicate messages * Improvements to update scripts; print out the version, check for superuser credentials before attempting a connection, and produce a friendlier error if the connection fails * (bug 5005) Fix XHTML output. * (bug 5315) "Expires: -1" HTTP header made strictly valid (using 1970 date). * (bug 4825) note in DefaultSettings.php about 'profiling' table creation * Remove unneeded extra whitespace at top of Special:Categories * (bug 5679) time units are now using local numerals * (bug 5751) Updates to Portuguese localisation files * (bug 5741) Introduce {{NUMBEROFUSERS}} magic word * (bug 93) tags and tildes in templates * The returnto parameter is now actually used by SpecialUserlogin.php * Parser can now know that it is parsing an interface message * (bug 4737) MediaWiki:Viewcount supports {{PLURAL}} now * Fix bug in wfMsgExt under PHP 5.1.2 * (bug 5761) Project talk namespace broken in Xal, Os, Udm and Cv * Rewrite reassignEdits script to be more efficient; support optional updates to recent changes table; add reporting and silent modes * Cleaned up formatNum usage in langfiles * (bug 5716) Warn when a user tries to upload a file which was previously deleted * (bug 5565) Add a class attribute to the table on Special:Allpages * "lang=xx" option for parser test cases to set content language * (bug 5764) Friulian translation updated * (bug 5757) Fix premature cutoff in LanguageConverter with extra end markers * (bug 5516) Show appropriate "return to" link on blocked page * (bug 5377) Do not auto-login when creating an account as another user * (bug 5284) Special redirect pages should remember parameters * Suppress 7za output on dumpBackup * (bug 5338) Reject extra initial colons in title * (bug 5487) Escape self-closed HTML pair tags * Add "raw suffix" magic word for some magic words, e.g. {{NUMBEROFUSERS|R}} will produce a count minus formatting * Fix Parser::cleanSig() to use Parser::startExternalParse() and choose an appropriate output format given the scope of the clean * (bug 5593) Change "bureaucrat log" to "rights log" * Show a boilerplate "(none)" in place of a blank within the log action text for user rights * (bug 137) Commented out translations for copyrightwarning which mention GNU FDL * (bug 5723) Don't count pages linked to from the MediaWiki namespace as "wanted" * (bug 5696) Add a third parameter, $3, to "rcnote", passing the current time formatted according to the current user's settings * (bug 5780) Thousands and decimal separators for Norwegian * Updated initStats maintenance script * (bug 5767) Fix date formats in Vietnamese locale * (bug 361) URL in URL, they were almost fixed. Now they are. * (bug 4876) Add __NEWSECTIONLINK__ magic word to force the "new section" link/tab to show up on specific pages on demand * Bidi-aid on list pages * (bug 5782) Allow entries in the bad image list to use canonical namespace names * (bug 5789) Treat "loginreqpagetext" as wikitext * Sanitizer: now handles nested
  • in
      or
        * (bug 5796) We require MySQL >=4.0.14 * Add 'EmailConfirmed' hook * New findhooks.php script to find undocumented hooks. * Silently ignore errors on profiling table update. * (bug 5801) Correct handling of underscores in Special:Listusers * Clean up Special:Listusers; add an "(all)" label to the group selection box * (bug 5812) Use appropriate link colour in Special:Mostlinked * (bug 5802) {{CURRENTMONTHNAME}} variable broken in Vietnamese locale * (bug 5817) Appropriate handling for Special:Recentchangeslinked where the target page doesn't exist * Special:Randompage now additionally accepts English namespace name as parameter * (bug 2981) Really fixed linktrail for Tamil (ta) * Disallow substituting Special pages when included into a page * (bug 5587) Clean up the languages from references to the Groups special page * Added new group-X and group-X-member messages * Rewritten removeUnusedAccounts to be more efficient, print names of inactive accounts * Redirect Special:Userlist to Special:Listusers * Introduce $wgAllowTitlesInSVG, which allows the attribute in uploaded files bearing the image/svg MIME type. Disabled by default due to the vast majority of web servers being hideously misconfigured. See DefaultSettings.php for more details. * Changed default LocalSettings.php to append the previous include path when setting it * (bug 5837) Use "members" for the value descriptor in Special:Categories, Special:Wantedcategories and Special:Mostlinkedcategories. * (bug 3309) Allow comments when undeleting pages * Clean up Special:Undelete a bit * (bug 5805) messages nbytes, ncategories can now use {{plural:}} * Clean up Special:Imagelist a bit * (bug 5838) Namespace names for Nds-NL * (bug 5749) Added Tyvan language files * (bug 5791) Fix SQL syntax in Special:BrokenRedirects, was causing incorrect data to show * (bug 5839) Prevent access to Special:Confirmemail for logged-out users * (bug 5853) Update for Portuguese messages (pt) * (bug 5851) Use Cyrillic for Kirghiz language name * (bug 5841) Allow the 'EditFilter' hook to return a non-fatal error message * (bug 5846) Link to individual group description pages in Special:Listusers * (bug 5857) Update for German localisation (de) * (bug 5858) Update for Russian language (ru) * (bug 5860) Update for Indonesian language (id) * (bug 1120) Update for Czech language (Cs) * Added many missing formatNum calls * Added grammar function to Belarusian (be) * (bug 5819) Add 'PersonalUrls' hook * (bug 5862) Update of Belarusian language (be) * (bug 5886) Update for Portuguese messages (pt) * (bug 5586) <gallery> treated text as links * (bug 5878) Update for Indonesian language (id) * (bug 5697) Update for Malay language (ms) * (bug 5890) Update for German language (de) * (bug 5889) Name for Sindhi language should appear as سنڌي * --force-normal parameter on dump scripts to force check for ICU extension * (bug 5895) Update for Dutch language (nl) * (bug 5891) Linktrail for Polish language (pl) * User::isBureaucrat , User::isDeveloper , User::isSysop deprecated in v1.6 now die with a backtrace. They will be removed in v1.8 * dumpTextPass now skips goes to database for entries that were blank in the previous dump, as this may indicate a broken dump. * dumpTextPass progress includes percentage of items prefetched * dumpTextPass can now use 7zip files for prefetch * (bug 5915) Update to Indonesian localisation (id) * (bug 5913) Update for German localisation (de) * (bug 5905) Plural support for Bosnian localisation (bs) * Groups which won't hit the rate limiter now configurable with $wgRateLimitsExcludedGroups * (bug 5806) {{plural:}} support instead of "twin" MediaWiki messages * (bug 5931) Update for Polish language (pl) * Ignore the user and user talk namespaces on Special:Wantedpages * Introduce NUMBEROFPAGES magic word * (bug 5833) Introduce CURRENTVERSION magic word * (bug 5370) Allow throttling of password reminder requests with the rate limiter * (bug 5683) Respect parser output marked as uncacheable when saving * (bug 5918) Links autonumbering now work for all defined protocols * (bug 5935) Improvement to German localisation (de) * (bug 5937) Register links from gallery captions with the parent parser output object so that link tables receive those updates too * (bug 5845) Introduce BASEPAGENAME and BASEPAGENAMEE magic words * (bug 5941) Use content language when getting the administrator page title for Special:Statistics * (bug 5949) Update to Indonesian localisation (id) * (bug 5862) Update of Belarusian translation (be) * (bug 5950) Improvements to French localisation * (bug 5805) {{plural:}} support for counters in some special pages * (bug 5952) Improvement to German localisation (de) * Rename conflicting metadata help message to "metadata_help" (was "metadata") and treat it as wiki text * Improve preferences input filtering * Maintenance script to import multiple files into the wiki * (bug 5957) Update for Hebrew language (he) * (bug 5962) Update for Italian language (it) * (bug 5961) Update for Portuguese localisation (pt) * (bug 5849) Remove some hard-coded references to "Wikipedia" in messages * (bug 5967) Improvement to German localisation (de) * (bug 5962) Update for Italian language (it) * Suppress images in galleries which appear on the bad image list (when rendering for a wiki page; galleries in special pages and categories are unaffected) * Maintenance script to remove orphaned revisions from the database * (bug 5991) Update for Russian language (ru) * (bug 6001) PAGENAMEE and FULLPAGENAMEE don't work in FULLURL and LOCALURL magic words * (bug 5958) Switch Uzbek language name to use latin script * (bug 839) Add URLENCODE magic word * (bug 6004) Update for Polish language (pl) * (bug 5971) Improvement to German localisation (de) * (bug 4873) Don't overwrite the subtitle navigation when viewing a redirect page that isn't current * (bug 2203) Namespace updates for Thai * Fix breakage in parser test suite which caused incorrect reporting of the failure of {{NUMBEROFFILES}}. Now initialises the site_stats table with some dumb data. Updated the expected output for {{NUMBEROFARTICLES}} to reflect this. * (bug 6009) Use {{ns:project}} in messages where appropriate * (bug 6012) Update to Indonesian localisation (id) * (bug 6017) Update list of bookstores in German localisation files * (bug 5187) Allow programmatically bypassing username validation, for scripts * (bug 6025) SpecialImport: wrong message when no file selected * (bug 6015) EditPage: add spacing in the boxes "edit is minor" and "watch this" * (bug 6018) Userrights: new message when no user specified ('nouserspecified') * (bug 2015) Add "\sim" to ~ conversion for HTML rendering * (bug 6029) Improvement to German localisation (de) * (bug 5015) Update be: magic words * (bug 3974) Add parameter for site URL to "passwordremindertext" * (bug 6039) Update for Portuguese localisation (pt) * (bug 764) Add CREATE TEMPORARY TABLES to default database permissions * Big update to Swedish localisation (sv) * Use appropriate HTML functions to create the tool links on image pages, so they don't look garbled when tidy isn't on * (bug 5511) Fix URL-encoding of usernames in links on Special:Ipblocklist * (bug 6046) Update to Indonesian localisation (id) #15 * (bug 5523) $wgNoFollowNsExceptions to allow disabling rel="nofollow" in specially-selected namespaces. * (bug 6055) Fix for HTML/JS injection bug in variable handler (found by Nick Jenkins) * Reordered wiki table handling and __TOC__ extraction in the parser to better handle some overlapping tag cases. * Only the first __TOC__ is now turned into a TOC * (bug 4610) Indicate patrolled status on watchlists and allow users to mark changes as patrolled using the diff links there * Add 'DiffViewHeader' hook called before diff page output * (bug 6051) Improvement to German localisation (de) * (bug 6054) Update to Indonesian localisation (id) #16 * Add {{CURRENTTIMESTAMP}} magic word * (bug 6061) Improper escaping in some html forms * (bug 6065) Remove underscore when using NAMESPACE and TALKSPACE magics. * (bug 6074) Correct squid purging of offsite upload URLs * To simplify the lives of extension developers, the logging type arrays can now be appended to directly by an extension setup function. It is no longer necessary to write four separate functions just to add a custom log type. * (bug 6057) Count "licenses" as a message (and show it in Special:Allmessages) * Added $wgGrammarForms global * Fixed hardcoded 'done.' when removing watchlist entries. * (bug 5962) Update for Italian language (it) * (bug 6086) Remove vestigial attempt to call Article::validate() * wfHostname() function for consistent server hostname use in debug messages * Send thumbnailing error messages to 'thumbnail' log group * wfShellexec() now accepts an optional parameter to receive the exit code * Failed, but not zero-length, thumbnail renderings are now removed. Should help clean up when rsvg fails in weird ways. * (bug 6081) Change description for Turkmen language * Increase robustness of parser placeholders; fixes some glitches when adjacent to identifier-ish constructs such as URLs. * Shut up the parser test whining about files in a temp directory. * (bug 6098) Add Aragonese language support (an) * (bug 6101) Update for Russian language (ru) +* Add $wgIgnoreImageErrors to suppress error messages for thumbnail rendering + problems. If errors are transitory, this should reduce annoying messages + making it into cached display. + == Compatibility == MediaWiki 1.7 requires PHP 5 (5.1 recommended). PHP 4 is no longer supported. MySQL 3.23.x is no longer supported; some older hosts may need to upgrade. At this time we still recommend 4.0, but 4.1/5.0 will work fine in most cases. == Upgrading == Several changes to the database have been made from 1.5; these are relatively minor but do require that the update process be run before the new code will work properly: * A new "templatelinks" table tracks template inclusions. * A new "externallinks" table tracks URL links; this can be used by a mass spam-cleanup tool in the SpamBlacklist extension. * A new "jobs" table stores a queue of pages to update in the background; this is used to update links in including pages when templates are edited. To ensure that these tables are filled with data, run refreshLinks.php after the upgrade. If you are upgrading from MediaWiki 1.4.x or earlier, some major database changes are made, and there is a slightly higher chance that things could break. Don't forget to always back up your database before upgrading! See the file UPGRADE for more detailed upgrade instructions. === Caveats === Some output, particularly involving user-supplied inline HTML, may not produce 100% valid or well-formed XHTML output. Testers are welcome to set $wgMimeType = "application/xhtml+xml"; to test for remaining problem cases, but this is not recommended on live sites. (This must be set for MathML to display properly in Mozilla.) For notes on 1.5.x and older releases, see HISTORY. === Online documentation === Documentation for both end-users and site administrators is currently being built up on Meta-Wikipedia, and is covered under the GNU Free Documentation License: http://www.mediawiki.org/wiki/Documentation === Mailing list === A MediaWiki-l mailing list has been set up distinct from the Wikipedia wikitech-l list: http://mail.wikimedia.org/mailman/listinfo/mediawiki-l A low-traffic announcements-only list is also available: http://mail.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 Index: trunk/phase3/includes/DefaultSettings.php =================================================================== --- trunk/phase3/includes/DefaultSettings.php (revision 14411) +++ trunk/phase3/includes/DefaultSettings.php (revision 14412) @@ -1,2044 +1,2056 @@ <?php /** * * NEVER EDIT THIS FILE * * * To customize your installation, edit "LocalSettings.php". If you make * changes here, they will be lost on next upgrade of MediaWiki! * * Note that since all these string interpolations are expanded * before LocalSettings is included, if you localize something * like $wgScriptPath, you must also localize everything that * depends on it. * * Documentation is in the source and on: * http://www.mediawiki.org/wiki/Help:Configuration_settings * * @package MediaWiki */ # This is not a valid entry point, perform no further processing unless MEDIAWIKI is defined if( !defined( 'MEDIAWIKI' ) ) { echo "This file is part of MediaWiki and is not a valid entry point\n"; die( -1 ); } /** * Create a site configuration object * Not used for much in a default install */ require_once( 'includes/SiteConfiguration.php' ); $wgConf = new SiteConfiguration; /** MediaWiki version number */ $wgVersion = '1.7alpha'; /** Name of the site. It must be changed in LocalSettings.php */ $wgSitename = 'MediaWiki'; /** Will be same as you set @see $wgSitename */ $wgMetaNamespace = FALSE; /** URL of the server. It will be automatically built including https mode */ $wgServer = ''; if( isset( $_SERVER['SERVER_NAME'] ) ) { $wgServerName = $_SERVER['SERVER_NAME']; } elseif( isset( $_SERVER['HOSTNAME'] ) ) { $wgServerName = $_SERVER['HOSTNAME']; } elseif( isset( $_SERVER['HTTP_HOST'] ) ) { $wgServerName = $_SERVER['HTTP_HOST']; } elseif( isset( $_SERVER['SERVER_ADDR'] ) ) { $wgServerName = $_SERVER['SERVER_ADDR']; } else { $wgServerName = 'localhost'; } # check if server use https: $wgProto = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; $wgServer = $wgProto.'://' . $wgServerName; # If the port is a non-standard one, add it to the URL if( isset( $_SERVER['SERVER_PORT'] ) && ( ( $wgProto == 'http' && $_SERVER['SERVER_PORT'] != 80 ) || ( $wgProto == 'https' && $_SERVER['SERVER_PORT'] != 443 ) ) ) { $wgServer .= ":" . $_SERVER['SERVER_PORT']; } /** * The path we should point to. * It might be a virtual path in case with use apache mod_rewrite for example */ $wgScriptPath = '/wiki'; /** * Whether to support URLs like index.php/Page_title * @global bool $wgUsePathInfo */ $wgUsePathInfo = ( strpos( php_sapi_name(), 'cgi' ) === false ); /**#@+ * Script users will request to get articles * ATTN: Old installations used wiki.phtml and redirect.phtml - * make sure that LocalSettings.php is correctly set! * @deprecated */ /** * @global string $wgScript */ $wgScript = "{$wgScriptPath}/index.php"; /** * @global string $wgRedirectScript */ $wgRedirectScript = "{$wgScriptPath}/redirect.php"; /**#@-*/ /**#@+ * @global string */ /** * style path as seen by users * @global string $wgStylePath */ $wgStylePath = "{$wgScriptPath}/skins"; /** * filesystem stylesheets directory * @global string $wgStyleDirectory */ $wgStyleDirectory = "{$IP}/skins"; $wgStyleSheetPath = &$wgStylePath; $wgArticlePath = "{$wgScript}?title=$1"; $wgUploadPath = "{$wgScriptPath}/upload"; $wgUploadDirectory = "{$IP}/upload"; $wgHashedUploadDirectory = true; $wgLogo = "{$wgUploadPath}/wiki.png"; $wgFavicon = '/favicon.ico'; $wgMathPath = "{$wgUploadPath}/math"; $wgMathDirectory = "{$wgUploadDirectory}/math"; $wgTmpDirectory = "{$wgUploadDirectory}/tmp"; $wgUploadBaseUrl = ""; /**#@-*/ /** * Allowed title characters -- regex character class * Don't change this unless you know what you're doing * * Problematic punctuation: * []{}|# Are needed for link syntax, never enable these * % Enabled by default, minor problems with path to query rewrite rules, see below * + Doesn't work with path to query rewrite rules, corrupted by apache * ? Enabled by default, but doesn't work with path to PATH_INFO rewrites * * All three of these punctuation problems can be avoided by using an alias, instead of a * rewrite rule of either variety. * * The problem with % is that when using a path to query rewrite rule, URLs are * double-unescaped: once by Apache's path conversion code, and again by PHP. So * %253F, for example, becomes "?". Our code does not double-escape to compensate * for this, indeed double escaping would break if the double-escaped title was * passed in the query string rather than the path. This is a minor security issue * because articles can be created such that they are hard to view or edit. * * Theoretically 0x80-0x9F of ISO 8859-1 should be disallowed, but * this breaks interlanguage links */ $wgLegalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF"; /** * The external URL protocols */ $wgUrlProtocols = array( 'http://', 'https://', 'ftp://', 'irc://', 'gopher://', 'telnet://', // Well if we're going to support the above.. -ævar 'nntp://', // @bug 3808 RFC 1738 'worldwind://', 'mailto:', 'news:' ); /** internal name of virus scanner. This servers as a key to the $wgAntivirusSetup array. * Set this to NULL to disable virus scanning. If not null, every file uploaded will be scanned for viruses. * @global string $wgAntivirus */ $wgAntivirus= NULL; /** Configuration for different virus scanners. This an associative array of associative arrays: * it contains on setup array per known scanner type. The entry is selected by $wgAntivirus, i.e. * valid values for $wgAntivirus are the keys defined in this array. * * The configuration array for each scanner contains the following keys: "command", "codemap", "messagepattern"; * * "command" is the full command to call the virus scanner - %f will be replaced with the name of the * file to scan. If not present, the filename will be appended to the command. Note that this must be * overwritten if the scanner is not in the system path; in that case, plase set * $wgAntivirusSetup[$wgAntivirus]['command'] to the desired command with full path. * * "codemap" is a mapping of exit code to return codes of the detectVirus function in SpecialUpload. * An exit code mapped to AV_SCAN_FAILED causes the function to consider the scan to be failed. This will pass * the file if $wgAntivirusRequired is not set. * An exit code mapped to AV_SCAN_ABORTED causes the function to consider the file to have an usupported format, * which is probably imune to virusses. This causes the file to pass. * An exit code mapped to AV_NO_VIRUS will cause the file to pass, meaning no virus was found. * All other codes (like AV_VIRUS_FOUND) will cause the function to report a virus. * You may use "*" as a key in the array to catch all exit codes not mapped otherwise. * * "messagepattern" is a perl regular expression to extract the meaningful part of the scanners * output. The relevant part should be matched as group one (\1). * If not defined or the pattern does not match, the full message is shown to the user. * * @global array $wgAntivirusSetup */ $wgAntivirusSetup= array( #setup for clamav 'clamav' => array ( 'command' => "clamscan --no-summary ", 'codemap'=> array ( "0"=> AV_NO_VIRUS, #no virus "1"=> AV_VIRUS_FOUND, #virus found "52"=> AV_SCAN_ABORTED, #unsupported file format (probably imune) "*"=> AV_SCAN_FAILED, #else scan failed ), 'messagepattern'=> '/.*?:(.*)/sim', ), #setup for f-prot 'f-prot' => array ( 'command' => "f-prot ", 'codemap'=> array ( "0"=> AV_NO_VIRUS, #no virus "3"=> AV_VIRUS_FOUND, #virus found "6"=> AV_VIRUS_FOUND, #virus found "*"=> AV_SCAN_FAILED, #else scan failed ), 'messagepattern'=> '/.*?Infection:(.*)$/m', ), ); /** Determines if a failed virus scan (AV_SCAN_FAILED) will cause the file to be rejected. * @global boolean $wgAntivirusRequired */ $wgAntivirusRequired= true; /** Determines if the mime type of uploaded files should be checked * @global boolean $wgVerifyMimeType */ $wgVerifyMimeType= true; /** Sets the mime type definition file to use by MimeMagic.php. * @global string $wgMimeTypeFile */ #$wgMimeTypeFile= "/etc/mime.types"; $wgMimeTypeFile= "includes/mime.types"; #$wgMimeTypeFile= NULL; #use built-in defaults only. /** Sets the mime type info file to use by MimeMagic.php. * @global string $wgMimeInfoFile */ $wgMimeInfoFile= "includes/mime.info"; #$wgMimeInfoFile= NULL; #use built-in defaults only. /** Switch for loading the FileInfo extension by PECL at runtime. * This should be used only if fileinfo is installed as a shared object / dynamic libary * @global string $wgLoadFileinfoExtension */ $wgLoadFileinfoExtension= false; /** Sets an external mime detector program. The command must print only the mime type to standard output. * the name of the file to process will be appended to the command given here. * If not set or NULL, mime_content_type will be used if available. */ $wgMimeDetectorCommand= NULL; # use internal mime_content_type function, available since php 4.3.0 #$wgMimeDetectorCommand= "file -bi"; #use external mime detector (Linux) /** Switch for trivial mime detection. Used by thumb.php to disable all fance things, * because only a few types of images are needed and file extensions can be trusted. */ $wgTrivialMimeDetection= false; /** * To set 'pretty' URL paths for actions other than * plain page views, add to this array. For instance: * 'edit' => "$wgScriptPath/edit/$1" * * There must be an appropriate script or rewrite rule * in place to handle these URLs. */ $wgActionPaths = array(); /** * If you operate multiple wikis, you can define a shared upload path here. * Uploads to this wiki will NOT be put there - they will be put into * $wgUploadDirectory. * If $wgUseSharedUploads is set, the wiki will look in the shared repository if * no file of the given name is found in the local repository (for [[Image:..]], * [[Media:..]] links). Thumbnails will also be looked for and generated in this * directory. */ $wgUseSharedUploads = false; /** Full path on the web server where shared uploads can be found */ $wgSharedUploadPath = "http://commons.wikimedia.org/shared/images"; /** Fetch commons image description pages and display them on the local wiki? */ $wgFetchCommonsDescriptions = false; /** Path on the file system where shared uploads can be found. */ $wgSharedUploadDirectory = "/var/www/wiki3/images"; /** DB name with metadata about shared directory. Set this to false if the uploads do not come from a wiki. */ $wgSharedUploadDBname = false; /** Optional table prefix used in database. */ $wgSharedUploadDBprefix = ''; /** Cache shared metadata in memcached. Don't do this if the commons wiki is in a different memcached domain */ $wgCacheSharedUploads = true; /** * Point the upload navigation link to an external URL * Useful if you want to use a shared repository by default * without disabling local uploads (use $wgEnableUploads = false for that) * e.g. $wgUploadNavigationUrl = 'http://commons.wikimedia.org/wiki/Special:Upload'; */ $wgUploadNavigationUrl = false; /** * Give a path here to use thumb.php for thumbnail generation on client request, instead of * generating them on render and outputting a static URL. This is necessary if some of your * apache servers don't have read/write access to the thumbnail path. * * Example: * $wgThumbnailScriptPath = "{$wgScriptPath}/thumb.php"; */ $wgThumbnailScriptPath = false; $wgSharedThumbnailScriptPath = false; /** * Set the following to false especially if you have a set of files that need to * be accessible by all wikis, and you do not want to use the hash (path/a/aa/) * directory layout. */ $wgHashedSharedUploadDirectory = true; /** * Base URL for a repository wiki. Leave this blank if uploads are just stored * in a shared directory and not meant to be accessible through a separate wiki. * Otherwise the image description pages on the local wiki will link to the * image description page on this wiki. * * Please specify the namespace, as in the example below. */ $wgRepositoryBaseUrl="http://commons.wikimedia.org/wiki/Image:"; # # Email settings # /** * Site admin email address * Default to wikiadmin@SERVER_NAME * @global string $wgEmergencyContact */ $wgEmergencyContact = 'wikiadmin@' . $wgServerName; /** * Password reminder email address * The address we should use as sender when a user is requesting his password * Default to apache@SERVER_NAME * @global string $wgPasswordSender */ $wgPasswordSender = 'MediaWiki Mail <apache@' . $wgServerName . '>'; /** * dummy address which should be accepted during mail send action * It might be necessay to adapt the address or to set it equal * to the $wgEmergencyContact address */ #$wgNoReplyAddress = $wgEmergencyContact; $wgNoReplyAddress = 'reply@not.possible'; /** * Set to true to enable the e-mail basic features: * Password reminders, etc. If sending e-mail on your * server doesn't work, you might want to disable this. * @global bool $wgEnableEmail */ $wgEnableEmail = true; /** * Set to true to enable user-to-user e-mail. * This can potentially be abused, as it's hard to track. * @global bool $wgEnableUserEmail */ $wgEnableUserEmail = true; /** * SMTP Mode * For using a direct (authenticated) SMTP server connection. * Default to false or fill an array : * <code> * "host" => 'SMTP domain', * "IDHost" => 'domain for MessageID', * "port" => "25", * "auth" => true/false, * "username" => user, * "password" => password * </code> * * @global mixed $wgSMTP */ $wgSMTP = false; /**#@+ * Database settings */ /** database host name or ip address */ $wgDBserver = 'localhost'; /** name of the database */ $wgDBname = 'wikidb'; /** */ $wgDBconnection = ''; /** Database username */ $wgDBuser = 'wikiuser'; /** Database type * "mysql" for working code and "PostgreSQL" for development/broken code */ $wgDBtype = "mysql"; /** Search type * Leave as null to select the default search engine for the * selected database type (eg SearchMySQL4), or set to a class * name to override to a custom search engine. */ $wgSearchType = null; /** Table name prefix */ $wgDBprefix = ''; /** Database schema * on some databases this allows separate * logical namespace for application data */ $wgDBschema = 'mediawiki'; /**#@-*/ /** Live high performance sites should disable this - some checks acquire giant mysql locks */ $wgCheckDBSchema = true; /** * Shared database for multiple wikis. Presently used for storing a user table * for single sign-on. The server for this database must be the same as for the * main database. * EXPERIMENTAL */ $wgSharedDB = null; # Database load balancer # This is a two-dimensional array, an array of server info structures # Fields are: # host: Host name # dbname: Default database name # user: DB user # password: DB password # type: "mysql" or "pgsql" # load: ratio of DB_SLAVE load, must be >=0, the sum of all loads must be >0 # groupLoads: array of load ratios, the key is the query group name. A query may belong # to several groups, the most specific group defined here is used. # # flags: bit field # DBO_DEFAULT -- turns on DBO_TRX only if !$wgCommandLineMode (recommended) # DBO_DEBUG -- equivalent of $wgDebugDumpSql # DBO_TRX -- wrap entire request in a transaction # DBO_IGNORE -- ignore errors (not useful in LocalSettings.php) # DBO_NOBUFFER -- turn off buffering (not useful in LocalSettings.php) # # max lag: (optional) Maximum replication lag before a slave will taken out of rotation # max threads: (optional) Maximum number of running threads # # These and any other user-defined properties will be assigned to the mLBInfo member # variable of the Database object. # # Leave at false to use the single-server variables above $wgDBservers = false; /** How long to wait for a slave to catch up to the master */ $wgMasterWaitTimeout = 10; /** File to log MySQL errors to */ $wgDBerrorLog = false; /** When to give an error message */ $wgDBClusterTimeout = 10; /** * wgDBminWordLen : * MySQL 3.x : used to discard words that MySQL will not return any results for * shorter values configure mysql directly. * MySQL 4.x : ignore it and configure mySQL * See: http://dev.mysql.com/doc/mysql/en/Fulltext_Fine-tuning.html */ $wgDBminWordLen = 4; /** Set to true if using InnoDB tables */ $wgDBtransactions = false; /** Set to true for compatibility with extensions that might be checking. * MySQL 3.23.x is no longer supported. */ $wgDBmysql4 = true; /** * Set to true to engage MySQL 4.1/5.0 charset-related features; * for now will just cause sending of 'SET NAMES=utf8' on connect. * * WARNING: THIS IS EXPERIMENTAL! * * May break if you're not using the table defs from mysql5/tables.sql. * May break if you're upgrading an existing wiki if set differently. * Broken symptoms likely to include incorrect behavior with page titles, * usernames, comments etc containing non-ASCII characters. * Might also cause failures on the object cache and other things. * * Even correct usage may cause failures with Unicode supplementary * characters (those not in the Basic Multilingual Plane) unless MySQL * has enhanced their Unicode support. */ $wgDBmysql5 = false; /** * Other wikis on this site, can be administered from a single developer * account. * Array numeric key => database name */ $wgLocalDatabases = array(); /** * Object cache settings * See Defines.php for types */ $wgMainCacheType = CACHE_NONE; $wgMessageCacheType = CACHE_ANYTHING; $wgParserCacheType = CACHE_ANYTHING; $wgParserCacheExpireTime = 86400; $wgSessionsInMemcached = false; $wgLinkCacheMemcached = false; # Not fully tested /** * Memcached-specific settings * See docs/memcached.txt */ $wgUseMemCached = false; $wgMemCachedDebug = false; # Will be set to false in Setup.php, if the server isn't working $wgMemCachedServers = array( '127.0.0.1:11000' ); $wgMemCachedDebug = false; $wgMemCachedPersistent = false; /** * Directory for local copy of message cache, for use in addition to memcached */ $wgLocalMessageCache = false; /** * Directory for compiled constant message array databases * WARNING: turning anything on will just break things, aaaaaah!!!! */ $wgCachedMessageArrays = false; # Language settings # /** Site language code, should be one of ./languages/Language(.*).php */ $wgLanguageCode = 'en'; /** * Some languages need different word forms, usually for different cases. * Used in Language::convertGrammar(). */ $wgGrammarForms = array(); #$wgGrammarForms['en']['genitive']['car'] = 'car\'s'; /** Treat language links as magic connectors, not inline links */ $wgInterwikiMagic = true; /** Hide interlanguage links from the sidebar */ $wgHideInterlanguageLinks = false; /** We speak UTF-8 all the time now, unless some oddities happen */ $wgInputEncoding = 'UTF-8'; $wgOutputEncoding = 'UTF-8'; $wgEditEncoding = ''; # Set this to eg 'ISO-8859-1' to perform character set # conversion when loading old revisions not marked with # "utf-8" flag. Use this when converting wiki to UTF-8 # without the burdensome mass conversion of old text data. # # NOTE! This DOES NOT touch any fields other than old_text. # Titles, comments, user names, etc still must be converted # en masse in the database before continuing as a UTF-8 wiki. $wgLegacyEncoding = false; /** * If set to true, the MediaWiki 1.4 to 1.5 schema conversion will * create stub reference rows in the text table instead of copying * the full text of all current entries from 'cur' to 'text'. * * This will speed up the conversion step for large sites, but * requires that the cur table be kept around for those revisions * to remain viewable. * * maintenance/migrateCurStubs.php can be used to complete the * migration in the background once the wiki is back online. * * This option affects the updaters *only*. Any present cur stub * revisions will be readable at runtime regardless of this setting. */ $wgLegacySchemaConversion = false; $wgMimeType = 'text/html'; $wgJsMimeType = 'text/javascript'; $wgDocType = '-//W3C//DTD XHTML 1.0 Transitional//EN'; $wgDTD = 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'; /** Enable to allow rewriting dates in page text. * DOES NOT FORMAT CORRECTLY FOR MOST LANGUAGES */ $wgUseDynamicDates = false; /** Enable dates like 'May 12' instead of '12 May', this only takes effect if * the interface is set to English */ $wgAmericanDates = false; /** * For Hindi and Arabic use local numerals instead of Western style (0-9) * numerals in interface. */ $wgTranslateNumerals = true; # Translation using MediaWiki: namespace # This will increase load times by 25-60% unless memcached is installed # Interface messages will be loaded from the database. $wgUseDatabaseMessages = true; $wgMsgCacheExpiry = 86400; # Whether to enable language variant conversion. $wgDisableLangConversion = false; # Whether to use zhdaemon to perform Chinese text processing # zhdaemon is under developement, so normally you don't want to # use it unless for testing $wgUseZhdaemon = false; $wgZhdaemonHost="localhost"; $wgZhdaemonPort=2004; /** Normally you can ignore this and it will be something like $wgMetaNamespace . "_talk". In some languages, you may want to set this manually for grammatical reasons. It is currently only respected by those languages where it might be relevant and where no automatic grammar converter exists. */ $wgMetaNamespaceTalk = false; # Miscellaneous configuration settings # $wgLocalInterwiki = 'w'; $wgInterwikiExpiry = 10800; # Expiry time for cache of interwiki table /** Interwiki caching settings. $wgInterwikiCache specifies path to constant database file This cdb database is generated by dumpInterwiki from maintenance and has such key formats: dbname:key - a simple key (e.g. enwiki:meta) _sitename:key - site-scope key (e.g. wiktionary:meta) __global:key - global-scope key (e.g. __global:meta) __sites:dbname - site mapping (e.g. __sites:enwiki) Sites mapping just specifies site name, other keys provide "local url" data layout. $wgInterwikiScopes specify number of domains to check for messages: 1 - Just wiki(db)-level 2 - wiki and global levels 3 - site levels $wgInterwikiFallbackSite - if unable to resolve from cache */ $wgInterwikiCache = false; $wgInterwikiScopes = 3; $wgInterwikiFallbackSite = 'wiki'; /** * If local interwikis are set up which allow redirects, * set this regexp to restrict URLs which will be displayed * as 'redirected from' links. * * It might look something like this: * $wgRedirectSources = '!^https?://[a-z-]+\.wikipedia\.org/!'; * * Leave at false to avoid displaying any incoming redirect markers. * This does not affect intra-wiki redirects, which don't change * the URL. */ $wgRedirectSources = false; $wgShowIPinHeader = true; # For non-logged in users $wgMaxNameChars = 255; # Maximum number of bytes in username $wgMaxArticleSize = 2048; # Maximum article size in kilobytes $wgExtraSubtitle = ''; $wgSiteSupportPage = ''; # A page where you users can receive donations $wgReadOnlyFile = "{$wgUploadDirectory}/lock_yBgMBwiR"; /** * The debug log file should be not be publicly accessible if it is used, as it * may contain private data. */ $wgDebugLogFile = ''; /**#@+ * @global bool */ $wgDebugRedirects = false; $wgDebugRawPage = false; # Avoid overlapping debug entries by leaving out CSS $wgDebugComments = false; $wgReadOnly = null; $wgLogQueries = false; /** * Write SQL queries to the debug log */ $wgDebugDumpSql = false; /** * Set to an array of log group keys to filenames. * If set, wfDebugLog() output for that group will go to that file instead * of the regular $wgDebugLogFile. Useful for enabling selective logging * in production. */ $wgDebugLogGroups = array(); /** * Whether to show "we're sorry, but there has been a database error" pages. * Displaying errors aids in debugging, but may display information useful * to an attacker. */ $wgShowSQLErrors = false; /** * If true, some error messages will be colorized when running scripts on the * command line; this can aid picking important things out when debugging. * Ignored when running on Windows or when output is redirected to a file. */ $wgColorErrors = true; /** * disable experimental dmoz-like category browsing. Output things like: * Encyclopedia > Music > Style of Music > Jazz */ $wgUseCategoryBrowser = false; /** * Keep parsed pages in a cache (objectcache table, turck, or memcached) * to speed up output of the same page viewed by another user with the * same options. * * This can provide a significant speedup for medium to large pages, * so you probably want to keep it on. */ $wgEnableParserCache = true; /** * If on, the sidebar navigation links are cached for users with the * current language set. This can save a touch of load on a busy site * by shaving off extra message lookups. * * However it is also fragile: changing the site configuration, or * having a variable $wgArticlePath, can produce broken links that * don't update as expected. */ $wgEnableSidebarCache = false; /** * Under which condition should a page in the main namespace be counted * as a valid article? If $wgUseCommaCount is set to true, it will be * counted if it contains at least one comma. If it is set to false * (default), it will only be counted if it contains at least one [[wiki * link]]. See http://meta.wikimedia.org/wiki/Help:Article_count * * Retroactively changing this variable will not affect * the existing count (cf. maintenance/recount.sql). */ $wgUseCommaCount = false; /**#@-*/ /** * wgHitcounterUpdateFreq sets how often page counters should be updated, higher * values are easier on the database. A value of 1 causes the counters to be * updated on every hit, any higher value n cause them to update *on average* * every n hits. Should be set to either 1 or something largish, eg 1000, for * maximum efficiency. */ $wgHitcounterUpdateFreq = 1; # Basic user rights and block settings $wgSysopUserBans = true; # Allow sysops to ban logged-in users $wgSysopRangeBans = true; # Allow sysops to ban IP ranges $wgAutoblockExpiry = 86400; # Number of seconds before autoblock entries expire $wgBlockAllowsUTEdit = false; # Blocks allow users to edit their own user talk page # Pages anonymous user may see as an array, e.g.: # array ( "Main Page", "Special:Userlogin", "Wikipedia:Help"); # NOTE: This will only work if $wgGroupPermissions['*']['read'] # is false -- see below. Otherwise, ALL pages are accessible, # regardless of this setting. # Also note that this will only protect _pages in the wiki_. # Uploaded files will remain readable. Make your upload # directory name unguessable, or use .htaccess to protect it. $wgWhitelistRead = false; /** * Should editors be required to have a validated e-mail * address before being allowed to edit? */ $wgEmailConfirmToEdit=false; /** * Permission keys given to users in each group. * All users are implicitly in the '*' group including anonymous visitors; * logged-in users are all implicitly in the 'user' group. These will be * combined with the permissions of all groups that a given user is listed * in in the user_groups table. * * Functionality to make pages inaccessible has not been extensively tested * for security. Use at your own risk! * * This replaces wgWhitelistAccount and wgWhitelistEdit */ $wgGroupPermissions = array(); // Implicit group for all visitors $wgGroupPermissions['*' ]['createaccount'] = true; $wgGroupPermissions['*' ]['read'] = true; $wgGroupPermissions['*' ]['edit'] = true; $wgGroupPermissions['*' ]['createpage'] = true; $wgGroupPermissions['*' ]['createtalk'] = true; // Implicit group for all logged-in accounts $wgGroupPermissions['user' ]['move'] = true; $wgGroupPermissions['user' ]['read'] = true; $wgGroupPermissions['user' ]['edit'] = true; $wgGroupPermissions['user' ]['createpage'] = true; $wgGroupPermissions['user' ]['createtalk'] = true; $wgGroupPermissions['user' ]['upload'] = true; $wgGroupPermissions['user' ]['reupload'] = true; $wgGroupPermissions['user' ]['reupload-shared'] = true; $wgGroupPermissions['user' ]['minoredit'] = true; // Implicit group for accounts that pass $wgAutoConfirmAge $wgGroupPermissions['autoconfirmed']['autoconfirmed'] = true; // Users with bot privilege can have their edits hidden // from various log pages by default $wgGroupPermissions['bot' ]['bot'] = true; $wgGroupPermissions['bot' ]['autoconfirmed'] = true; // Most extra permission abilities go to this group $wgGroupPermissions['sysop']['block'] = true; $wgGroupPermissions['sysop']['createaccount'] = true; $wgGroupPermissions['sysop']['delete'] = true; $wgGroupPermissions['sysop']['deletedhistory'] = true; // can view deleted history entries, but not see or restore the text $wgGroupPermissions['sysop']['editinterface'] = true; $wgGroupPermissions['sysop']['import'] = true; $wgGroupPermissions['sysop']['importupload'] = true; $wgGroupPermissions['sysop']['move'] = true; $wgGroupPermissions['sysop']['patrol'] = true; $wgGroupPermissions['sysop']['protect'] = true; $wgGroupPermissions['sysop']['proxyunbannable'] = true; $wgGroupPermissions['sysop']['rollback'] = true; $wgGroupPermissions['sysop']['trackback'] = true; $wgGroupPermissions['sysop']['upload'] = true; $wgGroupPermissions['sysop']['reupload'] = true; $wgGroupPermissions['sysop']['reupload-shared'] = true; $wgGroupPermissions['sysop']['unwatchedpages'] = true; $wgGroupPermissions['sysop']['autoconfirmed'] = true; // Permission to change users' group assignments $wgGroupPermissions['bureaucrat']['userrights'] = true; // Experimental permissions, not ready for production use //$wgGroupPermissions['sysop']['deleterevision'] = true; //$wgGroupPermissions['bureaucrat']['hiderevision'] = true; /** * The developer group is deprecated, but can be activated if need be * to use the 'lockdb' and 'unlockdb' special pages. Those require * that a lock file be defined and creatable/removable by the web * server. */ # $wgGroupPermissions['developer']['siteadmin'] = true; /** * Set of available actions that can be restricted via Special:Protect * You probably shouldn't change this. * Translated trough restriction-* messages. */ $wgRestrictionTypes = array( 'edit', 'move' ); /** * Set of permission keys that can be selected via Special:Protect. * 'autoconfirm' allows all registerd users if $wgAutoConfirmAge is 0. */ $wgRestrictionLevels = array( '', 'autoconfirmed', 'sysop' ); /** * Number of seconds an account is required to age before * it's given the implicit 'autoconfirm' group membership. * This can be used to limit privileges of new accounts. * * Accounts created by earlier versions of the software * may not have a recorded creation date, and will always * be considered to pass the age test. * * When left at 0, all registered accounts will pass. */ $wgAutoConfirmAge = 0; //$wgAutoConfirmAge = 600; // ten minutes //$wgAutoConfirmAge = 3600*24; // one day # Proxy scanner settings # /** * If you enable this, every editor's IP address will be scanned for open HTTP * proxies. * * Don't enable this. Many sysops will report "hostile TCP port scans" to your * ISP and ask for your server to be shut down. * * You have been warned. */ $wgBlockOpenProxies = false; /** Port we want to scan for a proxy */ $wgProxyPorts = array( 80, 81, 1080, 3128, 6588, 8000, 8080, 8888, 65506 ); /** Script used to scan */ $wgProxyScriptPath = "$IP/proxy_check.php"; /** */ $wgProxyMemcExpiry = 86400; /** This should always be customised in LocalSettings.php */ $wgSecretKey = false; /** big list of banned IP addresses, in the keys not the values */ $wgProxyList = array(); /** deprecated */ $wgProxyKey = false; /** Number of accounts each IP address may create, 0 to disable. * Requires memcached */ $wgAccountCreationThrottle = 0; # Client-side caching: /** Allow client-side caching of pages */ $wgCachePages = true; /** * Set this to current time to invalidate all prior cached pages. Affects both * client- and server-side caching. * You can get the current date on your server by using the command: * date +%Y%m%d%H%M%S */ $wgCacheEpoch = '20030516000000'; # Server-side caching: /** * This will cache static pages for non-logged-in users to reduce * database traffic on public sites. * Must set $wgShowIPinHeader = false */ $wgUseFileCache = false; /** Directory where the cached page will be saved */ $wgFileCacheDirectory = "{$wgUploadDirectory}/cache"; /** * When using the file cache, we can store the cached HTML gzipped to save disk * space. Pages will then also be served compressed to clients that support it. * THIS IS NOT COMPATIBLE with ob_gzhandler which is now enabled if supported in * the default LocalSettings.php! If you enable this, remove that setting first. * * Requires zlib support enabled in PHP. */ $wgUseGzip = false; # Email notification settings # /** For email notification on page changes */ $wgPasswordSender = $wgEmergencyContact; # true: from page editor if s/he opted-in # false: Enotif mails appear to come from $wgEmergencyContact $wgEnotifFromEditor = false; // TODO move UPO to preferences probably ? # If set to true, users get a corresponding option in their preferences and can choose to enable or disable at their discretion # If set to false, the corresponding input form on the user preference page is suppressed # It call this to be a "user-preferences-option (UPO)" $wgEmailAuthentication = true; # UPO (if this is set to false, texts referring to authentication are suppressed) $wgEnotifWatchlist = false; # UPO $wgEnotifUserTalk = false; # UPO $wgEnotifRevealEditorAddress = false; # UPO; reply-to address may be filled with page editor's address (if user allowed this in the preferences) $wgEnotifMinorEdits = true; # UPO; false: "minor edits" on pages do not trigger notification mails. # # Attention: _every_ change on a user_talk page trigger a notification mail (if the user is not yet notified) /** Show watching users in recent changes, watchlist and page history views */ $wgRCShowWatchingUsers = false; # UPO /** Show watching users in Page views */ $wgPageShowWatchingUsers = false; /** * Show "Updated (since my last visit)" marker in RC view, watchlist and history * view for watched pages with new changes */ $wgShowUpdatedMarker = true; $wgCookieExpiration = 2592000; /** Clock skew or the one-second resolution of time() can occasionally cause cache * problems when the user requests two pages within a short period of time. This * variable adds a given number of seconds to vulnerable timestamps, thereby giving * a grace period. */ $wgClockSkewFudge = 5; # Squid-related settings # /** Enable/disable Squid */ $wgUseSquid = false; /** If you run Squid3 with ESI support, enable this (default:false): */ $wgUseESI = false; /** Internal server name as known to Squid, if different */ # $wgInternalServer = 'http://yourinternal.tld:8000'; $wgInternalServer = $wgServer; /** * Cache timeout for the squid, will be sent as s-maxage (without ESI) or * Surrogate-Control (with ESI). Without ESI, you should strip out s-maxage in * the Squid config. 18000 seconds = 5 hours, more cache hits with 2678400 = 31 * days */ $wgSquidMaxage = 18000; /** * A list of proxy servers (ips if possible) to purge on changes don't specify * ports here (80 is default) */ # $wgSquidServers = array('127.0.0.1'); $wgSquidServers = array(); $wgSquidServersNoPurge = array(); /** Maximum number of titles to purge in any one client operation */ $wgMaxSquidPurgeTitles = 400; /** HTCP multicast purging */ $wgHTCPPort = 4827; $wgHTCPMulticastTTL = 1; # $wgHTCPMulticastAddress = "224.0.0.85"; # Cookie settings: # /** * Set to set an explicit domain on the login cookies eg, "justthis.domain. org" * or ".any.subdomain.net" */ $wgCookieDomain = ''; $wgCookiePath = '/'; $wgCookieSecure = ($wgProto == 'https'); $wgDisableCookieCheck = false; /** Whether to allow inline image pointing to other websites */ $wgAllowExternalImages = true; /** If the above is false, you can specify an exception here. Image URLs * that start with this string are then rendered, while all others are not. * You can use this to set up a trusted, simple repository of images. * * Example: * $wgAllowExternalImagesFrom = 'http://127.0.0.1/'; */ $wgAllowExternalImagesFrom = ''; /** Disable database-intensive features */ $wgMiserMode = false; /** Disable all query pages if miser mode is on, not just some */ $wgDisableQueryPages = false; /** Generate a watchlist once every hour or so */ $wgUseWatchlistCache = false; /** The hour or so mentioned above */ $wgWLCacheTimeout = 3600; /** Number of links to a page required before it is deemed "wanted" */ $wgWantedPagesThreshold = 1; /** * To use inline TeX, you need to compile 'texvc' (in the 'math' subdirectory of * the MediaWiki package and have latex, dvips, gs (ghostscript), andconvert * (ImageMagick) installed and available in the PATH. * Please see math/README for more information. */ $wgUseTeX = false; /** Location of the texvc binary */ $wgTexvc = './math/texvc'; # # Profiling / debugging # # You have to create a 'profiling' table in your database before using # profiling see maintenance/archives/patch-profiling.sql . /** Enable for more detailed by-function times in debug log */ $wgProfiling = false; /** Only record profiling info for pages that took longer than this */ $wgProfileLimit = 0.0; /** Don't put non-profiling info into log file */ $wgProfileOnly = false; /** Log sums from profiling into "profiling" table in db. */ $wgProfileToDatabase = false; /** Only profile every n requests when profiling is turned on */ $wgProfileSampleRate = 1; /** If true, print a raw call tree instead of per-function report */ $wgProfileCallTree = false; /** If not empty, specifies profiler type to load */ $wgProfilerType = ''; /** Settings for UDP profiler */ $wgUDPProfilerHost = '127.0.0.1'; $wgUDPProfilerPort = '3811'; /** Detects non-matching wfProfileIn/wfProfileOut calls */ $wgDebugProfiling = false; /** Output debug message on every wfProfileIn/wfProfileOut */ $wgDebugFunctionEntry = 0; /** Lots of debugging output from SquidUpdate.php */ $wgDebugSquid = false; $wgDisableCounters = false; $wgDisableTextSearch = false; $wgDisableSearchContext = false; /** * If you've disabled search semi-permanently, this also disables updates to the * table. If you ever re-enable, be sure to rebuild the search table. */ $wgDisableSearchUpdate = false; /** Uploads have to be specially set up to be secure */ $wgEnableUploads = false; /** * Show EXIF data, on by default if available. * Requires PHP's EXIF extension: http://www.php.net/manual/en/ref.exif.php */ $wgShowEXIF = function_exists( 'exif_read_data' ); /** * Set to true to enable the upload _link_ while local uploads are disabled. * Assumes that the special page link will be bounced to another server where * uploads do work. */ $wgRemoteUploads = false; $wgDisableAnonTalk = false; /** * Do DELETE/INSERT for link updates instead of incremental */ $wgUseDumbLinkUpdate = false; /** * Anti-lock flags - bitfield * ALF_PRELOAD_LINKS * Preload links during link update for save * ALF_PRELOAD_EXISTENCE * Preload cur_id during replaceLinkHolders * ALF_NO_LINK_LOCK * Don't use locking reads when updating the link table. This is * necessary for wikis with a high edit rate for performance * reasons, but may cause link table inconsistency * ALF_NO_BLOCK_LOCK * As for ALF_LINK_LOCK, this flag is a necessity for high-traffic * wikis. */ $wgAntiLockFlags = 0; /** * Path to the GNU diff3 utility. If the file doesn't exist, edit conflicts will * fall back to the old behaviour (no merging). */ $wgDiff3 = '/usr/bin/diff3'; /** * We can also compress text in the old revisions table. If this is set on, old * revisions will be compressed on page save if zlib support is available. Any * compressed revisions will be decompressed on load regardless of this setting * *but will not be readable at all* if zlib support is not available. */ $wgCompressRevisions = false; /** * This is the list of preferred extensions for uploading files. Uploading files * with extensions not in this list will trigger a warning. */ $wgFileExtensions = array( 'png', 'gif', 'jpg', 'jpeg' ); /** Files with these extensions will never be allowed as uploads. */ $wgFileBlacklist = array( # HTML may contain cookie-stealing JavaScript and web bugs 'html', 'htm', 'js', 'jsb', # PHP scripts may execute arbitrary code on the server 'php', 'phtml', 'php3', 'php4', 'phps', # Other types that may be interpreted by some servers 'shtml', 'jhtml', 'pl', 'py', 'cgi', # May contain harmful executables for Windows victims 'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl' ); /** Files with these mime types will never be allowed as uploads * if $wgVerifyMimeType is enabled. */ $wgMimeTypeBlacklist= array( # HTML may contain cookie-stealing JavaScript and web bugs 'text/html', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', # PHP scripts may execute arbitrary code on the server 'application/x-php', 'text/x-php', # Other types that may be interpreted by some servers 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', # Windows metafile, client-side vulnerability on some systems 'application/x-msmetafile' ); /** This is a flag to determine whether or not to check file extensions on upload. */ $wgCheckFileExtensions = true; /** * If this is turned off, users may override the warning for files not covered * by $wgFileExtensions. */ $wgStrictFileExtensions = true; /** Warn if uploaded files are larger than this */ $wgUploadSizeWarning = 150 * 1024; /** For compatibility with old installations set to false */ $wgPasswordSalt = true; /** Which namespaces should support subpages? * See Language.php for a list of namespaces. */ $wgNamespacesWithSubpages = array( NS_TALK => true, NS_USER => true, NS_USER_TALK => true, NS_PROJECT_TALK => true, NS_IMAGE_TALK => true, NS_MEDIAWIKI_TALK => true, NS_TEMPLATE_TALK => true, NS_HELP_TALK => true, NS_CATEGORY_TALK => true ); $wgNamespacesToBeSearchedDefault = array( NS_MAIN => true, ); /** If set, a bold ugly notice will show up at the top of every page. */ $wgSiteNotice = ''; # # Images settings # /** dynamic server side image resizing ("Thumbnails") */ $wgUseImageResize = false; /** * Resizing can be done using PHP's internal image libraries or using * ImageMagick or another third-party converter, e.g. GraphicMagick. * These support more file formats than PHP, which only supports PNG, * GIF, JPG, XBM and WBMP. * * Use Image Magick instead of PHP builtin functions. */ $wgUseImageMagick = false; /** The convert command shipped with ImageMagick */ $wgImageMagickConvertCommand = '/usr/bin/convert'; /** * Use another resizing converter, e.g. GraphicMagick * %s will be replaced with the source path, %d with the destination * %w and %h will be replaced with the width and height * * An example is provided for GraphicMagick * Leave as false to skip this */ #$wgCustomConvertCommand = "gm convert %s -resize %wx%h %d" $wgCustomConvertCommand = false; # Scalable Vector Graphics (SVG) may be uploaded as images. # Since SVG support is not yet standard in browsers, it is # necessary to rasterize SVGs to PNG as a fallback format. # # An external program is required to perform this conversion: $wgSVGConverters = array( 'ImageMagick' => '$path/convert -background white -geometry $width $input $output', 'sodipodi' => '$path/sodipodi -z -w $width -f $input -e $output', 'inkscape' => '$path/inkscape -z -w $width -f $input -e $output', 'batik' => 'java -Djava.awt.headless=true -jar $path/batik-rasterizer.jar -w $width -d $output $input', 'rsvg' => '$path/rsvg -w$width -h$height $input $output', ); /** Pick one of the above */ $wgSVGConverter = 'ImageMagick'; /** If not in the executable PATH, specify */ $wgSVGConverterPath = ''; /** Don't scale a SVG larger than this */ $wgSVGMaxSize = 1024; /** * Don't thumbnail an image if it will use too much working memory * Default is 50 MB if decompressed to RGBA form, which corresponds to * 12.5 million pixels or 3500x3500 */ $wgMaxImageArea = 1.25e7; /** * If rendered thumbnail files are older than this timestamp, they * will be rerendered on demand as if the file didn't already exist. * Update if there is some need to force thumbs and SVG rasterizations * to rerender, such as fixes to rendering bugs. */ $wgThumbnailEpoch = '20030516000000'; +/** + * If set, inline scaled images will still produce <img> tags ready for + * output instead of showing an error message. + * + * This may be useful if errors are transitory, especially if the site + * is configured to automatically render thumbnails on request. + * + * On the other hand, it may obscure error conditions from debugging. + * Enable the debug log or the 'thumbnail' log group to make sure errors + * are logged to a file for review. + */ +$wgIgnoreImageErrors = false; /** Set $wgCommandLineMode if it's not set already, to avoid notices */ if( !isset( $wgCommandLineMode ) ) { $wgCommandLineMode = false; } # # Recent changes settings # /** Log IP addresses in the recentchanges table */ $wgPutIPinRC = true; /** * Recentchanges items are periodically purged; entries older than this many * seconds will go. * For one week : 7 * 24 * 3600 */ $wgRCMaxAge = 7 * 24 * 3600; # Send RC updates via UDP $wgRC2UDPAddress = false; $wgRC2UDPPort = false; $wgRC2UDPPrefix = ''; # # Copyright and credits settings # /** RDF metadata toggles */ $wgEnableDublinCoreRdf = false; $wgEnableCreativeCommonsRdf = false; /** Override for copyright metadata. * TODO: these options need documentation */ $wgRightsPage = NULL; $wgRightsUrl = NULL; $wgRightsText = NULL; $wgRightsIcon = NULL; /** Set this to some HTML to override the rights icon with an arbitrary logo */ $wgCopyrightIcon = NULL; /** Set this to true if you want detailed copyright information forms on Upload. */ $wgUseCopyrightUpload = false; /** Set this to false if you want to disable checking that detailed copyright * information values are not empty. */ $wgCheckCopyrightUpload = true; /** * Set this to the number of authors that you want to be credited below an * article text. Set it to zero to hide the attribution block, and a negative * number (like -1) to show all authors. Note that this will require 2-3 extra * database hits, which can have a not insignificant impact on performance for * large wikis. */ $wgMaxCredits = 0; /** If there are more than $wgMaxCredits authors, show $wgMaxCredits of them. * Otherwise, link to a separate credits page. */ $wgShowCreditsIfMax = true; /** * Set this to false to avoid forcing the first letter of links to capitals. * WARNING: may break links! This makes links COMPLETELY case-sensitive. Links * appearing with a capital at the beginning of a sentence will *not* go to the * same place as links in the middle of a sentence using a lowercase initial. */ $wgCapitalLinks = true; /** * List of interwiki prefixes for wikis we'll accept as sources for * Special:Import (for sysops). Since complete page history can be imported, * these should be 'trusted'. * * If a user has the 'import' permission but not the 'importupload' permission, * they will only be able to run imports through this transwiki interface. */ $wgImportSources = array(); /** * If set to false, disables the full-history option on Special:Export. * This is currently poorly optimized for long edit histories, so is * disabled on Wikimedia's sites. */ $wgExportAllowHistory = true; $wgExportAllowListContributors = false ; /** Text matching this regular expression will be recognised as spam * See http://en.wikipedia.org/wiki/Regular_expression */ $wgSpamRegex = false; /** Similarly if this function returns true */ $wgFilterCallback = false; /** Go button goes straight to the edit screen if the article doesn't exist. */ $wgGoToEdit = false; /** Allow limited user-specified HTML in wiki pages? * It will be run through a whitelist for security. Set this to false if you * want wiki pages to consist only of wiki markup. Note that replacements do not * yet exist for all HTML constructs.*/ $wgUserHtml = true; /** Allow raw, unchecked HTML in <html>...</html> sections. * THIS IS VERY DANGEROUS on a publically editable site, so USE wgGroupPermissions * TO RESTRICT EDITING to only those that you trust */ $wgRawHtml = false; /** * $wgUseTidy: use tidy to make sure HTML output is sane. * This should only be enabled if $wgUserHtml is true. * tidy is a free tool that fixes broken HTML. * See http://www.w3.org/People/Raggett/tidy/ * $wgTidyBin should be set to the path of the binary and * $wgTidyConf to the path of the configuration file. * $wgTidyOpts can include any number of parameters. * * $wgTidyInternal controls the use of the PECL extension to use an in- * process tidy library instead of spawning a separate program. * Normally you shouldn't need to override the setting except for * debugging. To install, use 'pear install tidy' and add a line * 'extension=tidy.so' to php.ini. */ $wgUseTidy = false; $wgAlwaysUseTidy = false; $wgTidyBin = 'tidy'; $wgTidyConf = $IP.'/extensions/tidy/tidy.conf'; $wgTidyOpts = ''; $wgTidyInternal = function_exists( 'tidy_load_config' ); /** See list of skins and their symbolic names in languages/Language.php */ $wgDefaultSkin = 'monobook'; /** * Settings added to this array will override the language globals for the user * preferences used by anonymous visitors and newly created accounts. (See names * and sample values in languages/Language.php) * For instance, to disable section editing links: * $wgDefaultUserOptions ['editsection'] = 0; * */ $wgDefaultUserOptions = array(); /** Whether or not to allow and use real name fields. Defaults to true. */ $wgAllowRealName = true; /** Use XML parser? */ $wgUseXMLparser = false ; /** Extensions */ $wgSkinExtensionFunctions = array(); $wgExtensionFunctions = array(); /** * An array of extension types and inside that their names, versions, authors * and urls, note that the version and url key can be omitted. * * <code> * $wgExtensionCredits[$type][] = array( * 'name' => 'Example extension', * 'version' => 1.9, * 'author' => 'Foo Barstein', * 'url' => 'http://wwww.example.com/Example%20Extension/', * ); * </code> * * Where $type is 'specialpage', 'parserhook', or 'other'. */ $wgExtensionCredits = array(); /** * Allow user Javascript page? * This enables a lot of neat customizations, but may * increase security risk to users and server load. */ $wgAllowUserJs = false; /** * Allow user Cascading Style Sheets (CSS)? * This enables a lot of neat customizations, but may * increase security risk to users and server load. */ $wgAllowUserCss = false; /** Use the site's Javascript page? */ $wgUseSiteJs = true; /** Use the site's Cascading Style Sheets (CSS)? */ $wgUseSiteCss = true; /** Filter for Special:Randompage. Part of a WHERE clause */ $wgExtraRandompageSQL = false; /** Allow the "info" action, very inefficient at the moment */ $wgAllowPageInfo = false; /** Maximum indent level of toc. */ $wgMaxTocLevel = 999; /** Name of the external diff engine to use */ $wgExternalDiffEngine = false; /** Use RC Patrolling to check for vandalism */ $wgUseRCPatrol = true; /** Set maximum number of results to return in syndication feeds (RSS, Atom) for * eg Recentchanges, Newpages. */ $wgFeedLimit = 50; /** _Minimum_ timeout for cached Recentchanges feed, in seconds. * A cached version will continue to be served out even if changes * are made, until this many seconds runs out since the last render. * * If set to 0, feed caching is disabled. Use this for debugging only; * feed generation can be pretty slow with diffs. */ $wgFeedCacheTimeout = 60; /** When generating Recentchanges RSS/Atom feed, diffs will not be generated for * pages larger than this size. */ $wgFeedDiffCutoff = 32768; /** * Additional namespaces. If the namespaces defined in Language.php and * Namespace.php are insufficient, you can create new ones here, for example, * to import Help files in other languages. * PLEASE NOTE: Once you delete a namespace, the pages in that namespace will * no longer be accessible. If you rename it, then you can access them through * the new namespace name. * * Custom namespaces should start at 100 to avoid conflicting with standard * namespaces, and should always follow the even/odd main/talk pattern. */ #$wgExtraNamespaces = # array(100 => "Hilfe", # 101 => "Hilfe_Diskussion", # 102 => "Aide", # 103 => "Discussion_Aide" # ); $wgExtraNamespaces = NULL; /** * Limit images on image description pages to a user-selectable limit. In order * to reduce disk usage, limits can only be selected from a list. This is the * list of settings the user can choose from: */ $wgImageLimits = array ( array(320,240), array(640,480), array(800,600), array(1024,768), array(1280,1024), array(10000,10000) ); /** * Adjust thumbnails on image pages according to a user setting. In order to * reduce disk usage, the values can only be selected from a list. This is the * list of settings the user can choose from: */ $wgThumbLimits = array( 120, 150, 180, 200, 250, 300 ); /** * On category pages, show thumbnail gallery for images belonging to that * category instead of listing them as articles. */ $wgCategoryMagicGallery = true; /** * Paging limit for categories */ $wgCategoryPagingLimit = 200; /** * Browser Blacklist for unicode non compliant browsers * Contains a list of regexps : "/regexp/" matching problematic browsers */ $wgBrowserBlackList = array( /** * Netscape 2-4 detection * The minor version may contain strings such as "Gold" or "SGoldC-SGI" * Lots of non-netscape user agents have "compatible", so it's useful to check for that * with a negative assertion. The [UIN] identifier specifies the level of security * in a Netscape/Mozilla browser, checking for it rules out a number of fakers. * The language string is unreliable, it is missing on NS4 Mac. * * Reference: http://www.psychedelix.com/agents/index.shtml */ '/^Mozilla\/2\.[^ ]+ .*?\((?!compatible).*; [UIN]/', '/^Mozilla\/3\.[^ ]+ .*?\((?!compatible).*; [UIN]/', '/^Mozilla\/4\.[^ ]+ .*?\((?!compatible).*; [UIN]/', /** * MSIE on Mac OS 9 is teh sux0r, converts þ to <thorn>, ð to <eth>, Þ to <THORN> and Ð to <ETH> * * Known useragents: * - Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC) * - Mozilla/4.0 (compatible; MSIE 5.15; Mac_PowerPC) * - Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC) * - [...] * * @link http://en.wikipedia.org/w/index.php?title=User%3A%C6var_Arnfj%F6r%F0_Bjarmason%2Ftestme&diff=12356041&oldid=12355864 * @link http://en.wikipedia.org/wiki/Template%3AOS9 */ '/^Mozilla\/4\.0 \(compatible; MSIE \d+\.\d+; Mac_PowerPC\)/' ); /** * Fake out the timezone that the server thinks it's in. This will be used for * date display and not for what's stored in the DB. Leave to null to retain * your server's OS-based timezone value. This is the same as the timezone. * * This variable is currently used ONLY for signature formatting, not for * anything else. */ # $wgLocaltimezone = 'GMT'; # $wgLocaltimezone = 'PST8PDT'; # $wgLocaltimezone = 'Europe/Sweden'; # $wgLocaltimezone = 'CET'; $wgLocaltimezone = null; /** * Set an offset from UTC in minutes to use for the default timezone setting * for anonymous users and new user accounts. * * This setting is used for most date/time displays in the software, and is * overrideable in user preferences. It is *not* used for signature timestamps. * * You can set it to match the configured server timezone like this: * $wgLocalTZoffset = date("Z") / 60; * * If your server is not configured for the timezone you want, you can set * this in conjunction with the signature timezone and override the TZ * environment variable like so: * $wgLocaltimezone="Europe/Berlin"; * putenv("TZ=$wgLocaltimezone"); * $wgLocalTZoffset = date("Z") / 60; * * Leave at NULL to show times in universal time (UTC/GMT). */ $wgLocalTZoffset = null; /** * When translating messages with wfMsg(), it is not always clear what should be * considered UI messages and what shoud be content messages. * * For example, for regular wikipedia site like en, there should be only one * 'mainpage', therefore when getting the link of 'mainpage', we should treate * it as content of the site and call wfMsgForContent(), while for rendering the * text of the link, we call wfMsg(). The code in default behaves this way. * However, sites like common do offer different versions of 'mainpage' and the * like for different languages. This array provides a way to override the * default behavior. For example, to allow language specific mainpage and * community portal, set * * $wgForceUIMsgAsContentMsg = array( 'mainpage', 'portal-url' ); */ $wgForceUIMsgAsContentMsg = array(); /** * Authentication plugin. */ $wgAuth = null; /** * Global list of hooks. * Add a hook by doing: * $wgHooks['event_name'][] = $function; * or: * $wgHooks['event_name'][] = array($function, $data); * or: * $wgHooks['event_name'][] = array($object, 'method'); */ $wgHooks = array(); /** * The logging system has two levels: an event type, which describes the * general category and can be viewed as a named subset of all logs; and * an action, which is a specific kind of event that can exist in that * log type. */ $wgLogTypes = array( '', 'block', 'protect', 'rights', 'delete', 'upload', 'move' ); /** * Lists the message key string for each log type. The localized messages * will be listed in the user interface. * * Extensions with custom log types may add to this array. */ $wgLogNames = array( '' => 'log', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage' ); /** * Lists the message key string for descriptive text to be shown at the * top of each log type. * * Extensions with custom log types may add to this array. */ $wgLogHeaders = array( '' => 'alllogstext', 'block' => 'blocklogtext', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'delete' => 'dellogpagetext', 'upload' => 'uploadlogpagetext', 'move' => 'movelogpagetext' ); /** * Lists the message key string for formatting individual events of each * type and action when listed in the logs. * * Extensions with custom log types may add to this array. */ $wgLogActions = array( 'block/block' => 'blocklogentry', 'block/unblock' => 'unblocklogentry', 'protect/protect' => 'protectedarticle', 'protect/unprotect' => 'unprotectedarticle', // TODO: This whole section should be moved to extensions/Makesysop/SpecialMakesysop.php 'rights/rights' => 'rightslogentry', 'rights/addgroup' => 'addgrouplogentry', 'rights/rngroup' => 'renamegrouplogentry', 'rights/chgroup' => 'changegrouplogentry', 'delete/delete' => 'deletedarticle', 'delete/restore' => 'undeletedarticle', 'delete/revision' => 'revdelete-logentry', 'upload/upload' => 'uploadedimage', 'upload/revert' => 'uploadedimage', 'move/move' => '1movedto2', 'move/move_redir' => '1movedto2_redir' ); /** * Experimental preview feature to fetch rendered text * over an XMLHttpRequest from JavaScript instead of * forcing a submit and reload of the whole page. * Leave disabled unless you're testing it. */ $wgLivePreview = false; /** * Disable the internal MySQL-based search, to allow it to be * implemented by an extension instead. */ $wgDisableInternalSearch = false; /** * Set this to a URL to forward search requests to some external location. * If the URL includes '$1', this will be replaced with the URL-encoded * search term. * * For example, to forward to Google you'd have something like: * $wgSearchForwardUrl = 'http://www.google.com/search?q=$1' . * '&domains=http://example.com' . * '&sitesearch=http://example.com' . * '&ie=utf-8&oe=utf-8'; */ $wgSearchForwardUrl = null; /** * If true, external URL links in wiki text will be given the * rel="nofollow" attribute as a hint to search engines that * they should not be followed for ranking purposes as they * are user-supplied and thus subject to spamming. */ $wgNoFollowLinks = true; /** * Namespaces in which $wgNoFollowLinks doesn't apply. * See Language.php for a list of namespaces. */ $wgNoFollowNsExceptions = array(); /** * Specifies the minimal length of a user password. If set to * 0, empty passwords are allowed. */ $wgMinimalPasswordLength = 0; /** * Activate external editor interface for files and pages * See http://meta.wikimedia.org/wiki/Help:External_editors */ $wgUseExternalEditor = true; /** Whether or not to sort special pages in Special:Specialpages */ $wgSortSpecialPages = true; /** * Specify the name of a skin that should not be presented in the * list of available skins. * Use for blacklisting a skin which you do not want to remove * from the .../skins/ directory */ $wgSkipSkin = ''; $wgSkipSkins = array(); # More of the same /** * Array of disabled article actions, e.g. view, edit, dublincore, delete, etc. */ $wgDisabledActions = array(); /** * Disable redirects to special pages and interwiki redirects, which use a 302 and have no "redirected from" link */ $wgDisableHardRedirects = false; /** * Use http.dnsbl.sorbs.net to check for open proxies */ $wgEnableSorbs = false; /** * Proxy whitelist, list of addresses that are assumed to be non-proxy despite what the other * methods might say */ $wgProxyWhitelist = array(); /** * Simple rate limiter options to brake edit floods. * Maximum number actions allowed in the given number of seconds; * after that the violating client receives HTTP 500 error pages * until the period elapses. * * array( 4, 60 ) for a maximum of 4 hits in 60 seconds. * * This option set is experimental and likely to change. * Requires memcached. */ $wgRateLimits = array( 'edit' => array( 'anon' => null, // for any and all anonymous edits (aggregate) 'user' => null, // for each logged-in user 'newbie' => null, // for each recent account; overrides 'user' 'ip' => null, // for each anon and recent account 'subnet' => null, // ... with final octet removed ), 'move' => array( 'user' => null, 'newbie' => null, 'ip' => null, 'subnet' => null, ), 'mailpassword' => array( 'anon' => NULL, ), ); /** * Set to a filename to log rate limiter hits. */ $wgRateLimitLog = null; /** * Array of groups which should never trigger the rate limiter */ $wgRateLimitsExcludedGroups = array( 'sysop', 'bureaucrat' ); /** * On Special:Unusedimages, consider images "used", if they are put * into a category. Default (false) is not to count those as used. */ $wgCountCategorizedImagesAsUsed = false; /** * External stores allow including content * from non database sources following URL links * * Short names of ExternalStore classes may be specified in an array here: * $wgExternalStores = array("http","file","custom")... * * CAUTION: Access to database might lead to code execution */ $wgExternalStores = false; /** * An array of external mysql servers, e.g. * $wgExternalServers = array( 'cluster1' => array( 'srv28', 'srv29', 'srv30' ) ); */ $wgExternalServers = array(); /** * The place to put new revisions, false to put them in the local text table. * Part of a URL, e.g. DB://cluster1 * * Can be an array instead of a single string, to enable data distribution. Keys * must be consecutive integers, starting at zero. Example: * * $wgDefaultExternalStore = array( 'DB://cluster1', 'DB://cluster2' ); * */ $wgDefaultExternalStore = false; /** * list of trusted media-types and mime types. * Use the MEDIATYPE_xxx constants to represent media types. * This list is used by Image::isSafeFile * * Types not listed here will have a warning about unsafe content * displayed on the images description page. It would also be possible * to use this for further restrictions, like disabling direct * [[media:...]] links for non-trusted formats. */ $wgTrustedMediaFormats= array( MEDIATYPE_BITMAP, //all bitmap formats MEDIATYPE_AUDIO, //all audio formats MEDIATYPE_VIDEO, //all plain video formats "image/svg", //svg (only needed if inline rendering of svg is not supported) "application/pdf", //PDF files #"application/x-shockwafe-flash", //flash/shockwave movie ); /** * Allow special page inclusions such as {{Special:Allpages}} */ $wgAllowSpecialInclusion = true; /** * Timeout for HTTP requests done via CURL */ $wgHTTPTimeout = 3; /** * Proxy to use for CURL requests. */ $wgHTTPProxy = false; /** * Enable interwiki transcluding. Only when iw_trans=1. */ $wgEnableScaryTranscluding = false; /** * Expiry time for interwiki transclusion */ $wgTranscludeCacheExpiry = 3600; /** * Support blog-style "trackbacks" for articles. See * http://www.sixapart.com/pronet/docs/trackback_spec for details. */ $wgUseTrackbacks = false; /** * Enable filtering of categories in Recentchanges */ $wgAllowCategorizedRecentChanges = false ; /** * Number of jobs to perform per request. May be less than one in which case * jobs are performed probabalistically. If this is zero, jobs will not be done * during ordinary apache requests. In this case, maintenance/doJobs.php should * be run periodically. */ $wgJobRunRate = 1; /** * Log file for job execution */ $wgJobLogFile = false; /** * Enable use of AJAX features, currently auto suggestion for the search bar */ $wgUseAjax = false; /** * List of Ajax-callable functions */ $wgAjaxExportList = array( 'wfSajaxSearch' ); /** * Allow DISPLAYTITLE to change title display */ $wgAllowDisplayTitle = false ; /** * Array of usernames which may not be registered or logged in from * Maintenance scripts can still use these */ $wgReservedUsernames = array( 'MediaWiki default', 'Conversion script' ); /** * MediaWiki will reject HTMLesque tags in uploaded files due to idiotic browsers which can't * perform basic stuff like MIME detection and which are vulnerable to further idiots uploading * crap files as images. When this directive is on, <title> will be allowed in files with * an "image/svg" MIME type. You should leave this disabled if your web server is misconfigured * and doesn't send appropriate MIME types for SVG images. */ $wgAllowTitlesInSVG = false; ?> Index: trunk/phase3/includes/Image.php =================================================================== --- trunk/phase3/includes/Image.php (revision 14411) +++ trunk/phase3/includes/Image.php (revision 14412) @@ -1,1967 +1,1971 @@ <?php /** * @package MediaWiki */ /** * NOTE FOR WINDOWS USERS: * To enable EXIF functions, add the folloing lines to the * "Windows extensions" section of php.ini: * * extension=extensions/php_mbstring.dll * extension=extensions/php_exif.dll */ if ($wgShowEXIF) require_once('Exif.php'); /** * Bump this number when serialized cache records may be incompatible. */ define( 'MW_IMAGE_VERSION', 1 ); /** * Class to represent an image * * Provides methods to retrieve paths (physical, logical, URL), * to generate thumbnails or for uploading. * @package MediaWiki */ class Image { /**#@+ * @private */ var $name, # name of the image (constructor) $imagePath, # Path of the image (loadFromXxx) $url, # Image URL (accessor) $title, # Title object for this image (constructor) $fileExists, # does the image file exist on disk? (loadFromXxx) $fromSharedDirectory, # load this image from $wgSharedUploadDirectory (loadFromXxx) $historyLine, # Number of line to return by nextHistoryLine() (constructor) $historyRes, # result of the query for the image's history (nextHistoryLine) $width, # \ $height, # | $bits, # --- returned by getimagesize (loadFromXxx) $attr, # / $type, # MEDIATYPE_xxx (bitmap, drawing, audio...) $mime, # MIME type, determined by MimeMagic::guessMimeType $size, # Size in bytes (loadFromXxx) $metadata, # Metadata $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx) $lastError; # Error string associated with a thumbnail display error /**#@-*/ /** * Create an Image object from an image name * * @param string $name name of the image, used to create a title object using Title::makeTitleSafe * @public */ function newFromName( $name ) { $title = Title::makeTitleSafe( NS_IMAGE, $name ); if ( is_object( $title ) ) { return new Image( $title ); } else { return NULL; } } /** * Obsolete factory function, use constructor */ function newFromTitle( $title ) { return new Image( $title ); } function Image( $title ) { if( !is_object( $title ) ) { wfDebugDieBacktrace( 'Image constructor given bogus title.' ); } $this->title =& $title; $this->name = $title->getDBkey(); $this->metadata = serialize ( array() ) ; $n = strrpos( $this->name, '.' ); $this->extension = strtolower( $n ? substr( $this->name, $n + 1 ) : '' ); $this->historyLine = 0; $this->dataLoaded = false; } /** * Get the memcached keys * Returns an array, first element is the local cache key, second is the shared cache key, if there is one */ function getCacheKeys( ) { global $wgDBname, $wgUseSharedUploads, $wgSharedUploadDBname, $wgCacheSharedUploads; $hashedName = md5($this->name); $keys = array( "$wgDBname:Image:$hashedName" ); if ( $wgUseSharedUploads && $wgSharedUploadDBname && $wgCacheSharedUploads ) { $keys[] = "$wgSharedUploadDBname:Image:$hashedName"; } return $keys; } /** * Try to load image metadata from memcached. Returns true on success. */ function loadFromCache() { global $wgUseSharedUploads, $wgMemc; $fname = 'Image::loadFromMemcached'; wfProfileIn( $fname ); $this->dataLoaded = false; $keys = $this->getCacheKeys(); $cachedValues = $wgMemc->get( $keys[0] ); // Check if the key existed and belongs to this version of MediaWiki if (!empty($cachedValues) && is_array($cachedValues) && isset($cachedValues['version']) && ( $cachedValues['version'] == MW_IMAGE_VERSION ) && $cachedValues['fileExists'] && isset( $cachedValues['mime'] ) && isset( $cachedValues['metadata'] ) ) { if ( $wgUseSharedUploads && $cachedValues['fromShared']) { # if this is shared file, we need to check if image # in shared repository has not changed if ( isset( $keys[1] ) ) { $commonsCachedValues = $wgMemc->get( $keys[1] ); if (!empty($commonsCachedValues) && is_array($commonsCachedValues) && isset($commonsCachedValues['version']) && ( $commonsCachedValues['version'] == MW_IMAGE_VERSION ) && isset($commonsCachedValues['mime'])) { wfDebug( "Pulling image metadata from shared repository cache\n" ); $this->name = $commonsCachedValues['name']; $this->imagePath = $commonsCachedValues['imagePath']; $this->fileExists = $commonsCachedValues['fileExists']; $this->width = $commonsCachedValues['width']; $this->height = $commonsCachedValues['height']; $this->bits = $commonsCachedValues['bits']; $this->type = $commonsCachedValues['type']; $this->mime = $commonsCachedValues['mime']; $this->metadata = $commonsCachedValues['metadata']; $this->size = $commonsCachedValues['size']; $this->fromSharedDirectory = true; $this->dataLoaded = true; $this->imagePath = $this->getFullPath(true); } } } else { wfDebug( "Pulling image metadata from local cache\n" ); $this->name = $cachedValues['name']; $this->imagePath = $cachedValues['imagePath']; $this->fileExists = $cachedValues['fileExists']; $this->width = $cachedValues['width']; $this->height = $cachedValues['height']; $this->bits = $cachedValues['bits']; $this->type = $cachedValues['type']; $this->mime = $cachedValues['mime']; $this->metadata = $cachedValues['metadata']; $this->size = $cachedValues['size']; $this->fromSharedDirectory = false; $this->dataLoaded = true; $this->imagePath = $this->getFullPath(); } } if ( $this->dataLoaded ) { wfIncrStats( 'image_cache_hit' ); } else { wfIncrStats( 'image_cache_miss' ); } wfProfileOut( $fname ); return $this->dataLoaded; } /** * Save the image metadata to memcached */ function saveToCache() { global $wgMemc; $this->load(); $keys = $this->getCacheKeys(); if ( $this->fileExists ) { // We can't cache negative metadata for non-existent files, // because if the file later appears in commons, the local // keys won't be purged. $cachedValues = array( 'version' => MW_IMAGE_VERSION, 'name' => $this->name, 'imagePath' => $this->imagePath, 'fileExists' => $this->fileExists, 'fromShared' => $this->fromSharedDirectory, 'width' => $this->width, 'height' => $this->height, 'bits' => $this->bits, 'type' => $this->type, 'mime' => $this->mime, 'metadata' => $this->metadata, 'size' => $this->size ); $wgMemc->set( $keys[0], $cachedValues, 60 * 60 * 24 * 7 ); // A week } else { // However we should clear them, so they aren't leftover // if we've deleted the file. $wgMemc->delete( $keys[0] ); } } /** * Load metadata from the file itself */ function loadFromFile() { global $wgUseSharedUploads, $wgSharedUploadDirectory, $wgContLang, $wgShowEXIF; $fname = 'Image::loadFromFile'; wfProfileIn( $fname ); $this->imagePath = $this->getFullPath(); $this->fileExists = file_exists( $this->imagePath ); $this->fromSharedDirectory = false; $gis = array(); if (!$this->fileExists) wfDebug("$fname: ".$this->imagePath." not found locally!\n"); # If the file is not found, and a shared upload directory is used, look for it there. if (!$this->fileExists && $wgUseSharedUploads && $wgSharedUploadDirectory) { # In case we're on a wgCapitalLinks=false wiki, we # capitalize the first letter of the filename before # looking it up in the shared repository. $sharedImage = Image::newFromName( $wgContLang->ucfirst($this->name) ); $this->fileExists = $sharedImage && file_exists( $sharedImage->getFullPath(true) ); if ( $this->fileExists ) { $this->name = $sharedImage->name; $this->imagePath = $this->getFullPath(true); $this->fromSharedDirectory = true; } } if ( $this->fileExists ) { $magic=& wfGetMimeMagic(); $this->mime = $magic->guessMimeType($this->imagePath,true); $this->type = $magic->getMediaType($this->imagePath,$this->mime); # Get size in bytes $this->size = filesize( $this->imagePath ); $magic=& wfGetMimeMagic(); # Height and width if( $this->mime == 'image/svg' ) { wfSuppressWarnings(); $gis = wfGetSVGsize( $this->imagePath ); wfRestoreWarnings(); } elseif ( !$magic->isPHPImageType( $this->mime ) ) { # Don't try to get the width and height of sound and video files, that's bad for performance $gis[0]= 0; //width $gis[1]= 0; //height $gis[2]= 0; //unknown $gis[3]= ""; //width height string } else { wfSuppressWarnings(); $gis = getimagesize( $this->imagePath ); wfRestoreWarnings(); } wfDebug("$fname: ".$this->imagePath." loaded, ".$this->size." bytes, ".$this->mime.".\n"); } else { $gis[0]= 0; //width $gis[1]= 0; //height $gis[2]= 0; //unknown $gis[3]= ""; //width height string $this->mime = NULL; $this->type = MEDIATYPE_UNKNOWN; wfDebug("$fname: ".$this->imagePath." NOT FOUND!\n"); } $this->width = $gis[0]; $this->height = $gis[1]; #NOTE: $gis[2] contains a code for the image type. This is no longer used. #NOTE: we have to set this flag early to avoid load() to be called # be some of the functions below. This may lead to recursion or other bad things! # as ther's only one thread of execution, this should be safe anyway. $this->dataLoaded = true; if ($this->fileExists && $wgShowEXIF) $this->metadata = serialize ( $this->retrieveExifData() ) ; else $this->metadata = serialize ( array() ) ; if ( isset( $gis['bits'] ) ) $this->bits = $gis['bits']; else $this->bits = 0; wfProfileOut( $fname ); } /** * Load image metadata from the DB */ function loadFromDB() { global $wgUseSharedUploads, $wgSharedUploadDBname, $wgSharedUploadDBprefix, $wgContLang; $fname = 'Image::loadFromDB'; wfProfileIn( $fname ); $dbr =& wfGetDB( DB_SLAVE ); $this->checkDBSchema($dbr); $row = $dbr->selectRow( 'image', array( 'img_size', 'img_width', 'img_height', 'img_bits', 'img_media_type', 'img_major_mime', 'img_minor_mime', 'img_metadata' ), array( 'img_name' => $this->name ), $fname ); if ( $row ) { $this->fromSharedDirectory = false; $this->fileExists = true; $this->loadFromRow( $row ); $this->imagePath = $this->getFullPath(); // Check for rows from a previous schema, quietly upgrade them if ( is_null($this->type) ) { $this->upgradeRow(); } } elseif ( $wgUseSharedUploads && $wgSharedUploadDBname ) { # In case we're on a wgCapitalLinks=false wiki, we # capitalize the first letter of the filename before # looking it up in the shared repository. $name = $wgContLang->ucfirst($this->name); $dbc =& wfGetDB( DB_SLAVE, 'commons' ); $row = $dbc->selectRow( "`$wgSharedUploadDBname`.{$wgSharedUploadDBprefix}image", array( 'img_size', 'img_width', 'img_height', 'img_bits', 'img_media_type', 'img_major_mime', 'img_minor_mime', 'img_metadata' ), array( 'img_name' => $name ), $fname ); if ( $row ) { $this->fromSharedDirectory = true; $this->fileExists = true; $this->imagePath = $this->getFullPath(true); $this->name = $name; $this->loadFromRow( $row ); // Check for rows from a previous schema, quietly upgrade them if ( is_null($this->type) ) { $this->upgradeRow(); } } } if ( !$row ) { $this->size = 0; $this->width = 0; $this->height = 0; $this->bits = 0; $this->type = 0; $this->fileExists = false; $this->fromSharedDirectory = false; $this->metadata = serialize ( array() ) ; } # Unconditionally set loaded=true, we don't want the accessors constantly rechecking $this->dataLoaded = true; wfProfileOut( $fname ); } /* * Load image metadata from a DB result row */ function loadFromRow( &$row ) { $this->size = $row->img_size; $this->width = $row->img_width; $this->height = $row->img_height; $this->bits = $row->img_bits; $this->type = $row->img_media_type; $major= $row->img_major_mime; $minor= $row->img_minor_mime; if (!$major) $this->mime = "unknown/unknown"; else { if (!$minor) $minor= "unknown"; $this->mime = $major.'/'.$minor; } $this->metadata = $row->img_metadata; if ( $this->metadata == "" ) $this->metadata = serialize ( array() ) ; $this->dataLoaded = true; } /** * Load image metadata from cache or DB, unless already loaded */ function load() { global $wgSharedUploadDBname, $wgUseSharedUploads; if ( !$this->dataLoaded ) { if ( !$this->loadFromCache() ) { $this->loadFromDB(); if ( !$wgSharedUploadDBname && $wgUseSharedUploads ) { $this->loadFromFile(); } elseif ( $this->fileExists ) { $this->saveToCache(); } } $this->dataLoaded = true; } } /** * Metadata was loaded from the database, but the row had a marker indicating it needs to be * upgraded from the 1.4 schema, which had no width, height, bits or type. Upgrade the row. */ function upgradeRow() { global $wgDBname, $wgSharedUploadDBname; $fname = 'Image::upgradeRow'; wfProfileIn( $fname ); $this->loadFromFile(); if ( $this->fromSharedDirectory ) { if ( !$wgSharedUploadDBname ) { wfProfileOut( $fname ); return; } // Write to the other DB using selectDB, not database selectors // This avoids breaking replication in MySQL $dbw =& wfGetDB( DB_MASTER, 'commons' ); $dbw->selectDB( $wgSharedUploadDBname ); } else { $dbw =& wfGetDB( DB_MASTER ); } $this->checkDBSchema($dbw); if (strpos($this->mime,'/')!==false) { list($major,$minor)= explode('/',$this->mime,2); } else { $major= $this->mime; $minor= "unknown"; } wfDebug("$fname: upgrading ".$this->name." to 1.5 schema\n"); $dbw->update( 'image', array( 'img_width' => $this->width, 'img_height' => $this->height, 'img_bits' => $this->bits, 'img_media_type' => $this->type, 'img_major_mime' => $major, 'img_minor_mime' => $minor, 'img_metadata' => $this->metadata, ), array( 'img_name' => $this->name ), $fname ); if ( $this->fromSharedDirectory ) { $dbw->selectDB( $wgDBname ); } wfProfileOut( $fname ); } /** * Return the name of this image * @public */ function getName() { return $this->name; } /** * Return the associated title object * @public */ function getTitle() { return $this->title; } /** * Return the URL of the image file * @public */ function getURL() { if ( !$this->url ) { $this->load(); if($this->fileExists) { $this->url = Image::imageUrl( $this->name, $this->fromSharedDirectory ); } else { $this->url = ''; } } return $this->url; } function getViewURL() { if( $this->mustRender()) { if( $this->canRender() ) { return $this->createThumb( $this->getWidth() ); } else { wfDebug('Image::getViewURL(): supposed to render '.$this->name.' ('.$this->mime."), but can't!\n"); return $this->getURL(); #hm... return NULL? } } else { return $this->getURL(); } } /** * Return the image path of the image in the * local file system as an absolute path * @public */ function getImagePath() { $this->load(); return $this->imagePath; } /** * Return the width of the image * * Returns -1 if the file specified is not a known image type * @public */ function getWidth() { $this->load(); return $this->width; } /** * Return the height of the image * * Returns -1 if the file specified is not a known image type * @public */ function getHeight() { $this->load(); return $this->height; } /** * Return the size of the image file, in bytes * @public */ function getSize() { $this->load(); return $this->size; } /** * Returns the mime type of the file. */ function getMimeType() { $this->load(); return $this->mime; } /** * Return the type of the media in the file. * Use the value returned by this function with the MEDIATYPE_xxx constants. */ function getMediaType() { $this->load(); return $this->type; } /** * Checks if the file can be presented to the browser as a bitmap. * * Currently, this checks if the file is an image format * that can be converted to a format * supported by all browsers (namely GIF, PNG and JPEG), * or if it is an SVG image and SVG conversion is enabled. * * @todo remember the result of this check. */ function canRender() { global $wgUseImageMagick; if( $this->getWidth()<=0 || $this->getHeight()<=0 ) return false; $mime= $this->getMimeType(); if (!$mime || $mime==='unknown' || $mime==='unknown/unknown') return false; #if it's SVG, check if there's a converter enabled if ($mime === 'image/svg') { global $wgSVGConverters, $wgSVGConverter; if ($wgSVGConverter && isset( $wgSVGConverters[$wgSVGConverter])) { wfDebug( "Image::canRender: SVG is ready!\n" ); return true; } else { wfDebug( "Image::canRender: SVG renderer missing\n" ); } } #image formats available on ALL browsers if ( $mime === 'image/gif' || $mime === 'image/png' || $mime === 'image/jpeg' ) return true; #image formats that can be converted to the above formats if ($wgUseImageMagick) { #convertable by ImageMagick (there are more...) if ( $mime === 'image/vnd.wap.wbmp' || $mime === 'image/x-xbitmap' || $mime === 'image/x-xpixmap' #|| $mime === 'image/x-icon' #file may be split into multiple parts || $mime === 'image/x-portable-anymap' || $mime === 'image/x-portable-bitmap' || $mime === 'image/x-portable-graymap' || $mime === 'image/x-portable-pixmap' #|| $mime === 'image/x-photoshop' #this takes a lot of CPU and RAM! || $mime === 'image/x-rgb' || $mime === 'image/x-bmp' || $mime === 'image/tiff' ) return true; } else { #convertable by the PHP GD image lib if ( $mime === 'image/vnd.wap.wbmp' || $mime === 'image/x-xbitmap' ) return true; } return false; } /** * Return true if the file is of a type that can't be directly * rendered by typical browsers and needs to be re-rasterized. * * This returns true for everything but the bitmap types * supported by all browsers, i.e. JPEG; GIF and PNG. It will * also return true for any non-image formats. * * @return bool */ function mustRender() { $mime= $this->getMimeType(); if ( $mime === "image/gif" || $mime === "image/png" || $mime === "image/jpeg" ) return false; return true; } /** * Determines if this media file may be shown inline on a page. * * This is currently synonymous to canRender(), but this could be * extended to also allow inline display of other media, * like flash animations or videos. If you do so, please keep in mind that * that could be a security risk. */ function allowInlineDisplay() { return $this->canRender(); } /** * Determines if this media file is in a format that is unlikely to * contain viruses or malicious content. It uses the global * $wgTrustedMediaFormats list to determine if the file is safe. * * This is used to show a warning on the description page of non-safe files. * It may also be used to disallow direct [[media:...]] links to such files. * * Note that this function will always return true if allowInlineDisplay() * or isTrustedFile() is true for this file. */ function isSafeFile() { if ($this->allowInlineDisplay()) return true; if ($this->isTrustedFile()) return true; global $wgTrustedMediaFormats; $type= $this->getMediaType(); $mime= $this->getMimeType(); #wfDebug("Image::isSafeFile: type= $type, mime= $mime\n"); if (!$type || $type===MEDIATYPE_UNKNOWN) return false; #unknown type, not trusted if ( in_array( $type, $wgTrustedMediaFormats) ) return true; if ($mime==="unknown/unknown") return false; #unknown type, not trusted if ( in_array( $mime, $wgTrustedMediaFormats) ) return true; return false; } /** Returns true if the file is flagged as trusted. Files flagged that way * can be linked to directly, even if that is not allowed for this type of * file normally. * * This is a dummy function right now and always returns false. It could be * implemented to extract a flag from the database. The trusted flag could be * set on upload, if the user has sufficient privileges, to bypass script- * and html-filters. It may even be coupled with cryptographics signatures * or such. */ function isTrustedFile() { #this could be implemented to check a flag in the databas, #look for signatures, etc return false; } /** * Return the escapeLocalURL of this image * @public */ function getEscapeLocalURL() { $this->getTitle(); return $this->title->escapeLocalURL(); } /** * Return the escapeFullURL of this image * @public */ function getEscapeFullURL() { $this->getTitle(); return $this->title->escapeFullURL(); } /** * Return the URL of an image, provided its name. * * @param string $name Name of the image, without the leading "Image:" * @param boolean $fromSharedDirectory Should this be in $wgSharedUploadPath? * @return string URL of $name image * @public * @static */ function imageUrl( $name, $fromSharedDirectory = false ) { global $wgUploadPath,$wgUploadBaseUrl,$wgSharedUploadPath; if($fromSharedDirectory) { $base = ''; $path = $wgSharedUploadPath; } else { $base = $wgUploadBaseUrl; $path = $wgUploadPath; } $url = "{$base}{$path}" . wfGetHashPath($name, $fromSharedDirectory) . "{$name}"; return wfUrlencode( $url ); } /** * Returns true if the image file exists on disk. * @return boolean Whether image file exist on disk. * @public */ function exists() { $this->load(); return $this->fileExists; } /** * @todo document * @private */ function thumbUrl( $width, $subdir='thumb') { global $wgUploadPath, $wgUploadBaseUrl, $wgSharedUploadPath; global $wgSharedThumbnailScriptPath, $wgThumbnailScriptPath; // Generate thumb.php URL if possible $script = false; $url = false; if ( $this->fromSharedDirectory ) { if ( $wgSharedThumbnailScriptPath ) { $script = $wgSharedThumbnailScriptPath; } } else { if ( $wgThumbnailScriptPath ) { $script = $wgThumbnailScriptPath; } } if ( $script ) { $url = $script . '?f=' . urlencode( $this->name ) . '&w=' . urlencode( $width ); if( $this->mustRender() ) { $url.= '&r=1'; } } else { $name = $this->thumbName( $width ); if($this->fromSharedDirectory) { $base = ''; $path = $wgSharedUploadPath; } else { $base = $wgUploadBaseUrl; $path = $wgUploadPath; } if ( Image::isHashed( $this->fromSharedDirectory ) ) { $url = "{$base}{$path}/{$subdir}" . wfGetHashPath($this->name, $this->fromSharedDirectory) . $this->name.'/'.$name; $url = wfUrlencode( $url ); } else { $url = "{$base}{$path}/{$subdir}/{$name}"; } } return array( $script !== false, $url ); } /** * Return the file name of a thumbnail of the specified width * * @param integer $width Width of the thumbnail image * @param boolean $shared Does the thumbnail come from the shared repository? * @private */ function thumbName( $width ) { $thumb = $width."px-".$this->name; if( $this->mustRender() ) { if( $this->canRender() ) { # Rasterize to PNG (for SVG vector images, etc) $thumb .= '.png'; } else { #should we use iconThumb here to get a symbolic thumbnail? #or should we fail with an internal error? return NULL; //can't make bitmap } } return $thumb; } /** * Create a thumbnail of the image having the specified width/height. * The thumbnail will not be created if the width is larger than the * image's width. Let the browser do the scaling in this case. * The thumbnail is stored on disk and is only computed if the thumbnail * file does not exist OR if it is older than the image. * Returns the URL. * * Keeps aspect ratio of original image. If both width and height are * specified, the generated image will be no bigger than width x height, * and will also have correct aspect ratio. * * @param integer $width maximum width of the generated thumbnail * @param integer $height maximum height of the image (optional) * @public */ function createThumb( $width, $height=-1 ) { $thumb = $this->getThumbnail( $width, $height ); if( is_null( $thumb ) ) return ''; return $thumb->getUrl(); } /** * As createThumb, but returns a ThumbnailImage object. This can * provide access to the actual file, the real size of the thumb, * and can produce a convenient <img> tag for you. * * @param integer $width maximum width of the generated thumbnail * @param integer $height maximum height of the image (optional) * @return ThumbnailImage * @public */ function getThumbnail( $width, $height=-1 ) { if ( $height <= 0 ) { return $this->renderThumb( $width ); } $this->load(); if ($this->canRender()) { if ( $width > $this->width * $height / $this->height ) $width = wfFitBoxWidth( $this->width, $this->height, $height ); $thumb = $this->renderThumb( $width ); } else $thumb= NULL; #not a bitmap or renderable image, don't try. if( is_null( $thumb ) ) { $thumb = $this->iconThumb(); } return $thumb; } /** * @return ThumbnailImage */ function iconThumb() { global $wgStylePath, $wgStyleDirectory; $try = array( 'fileicon-' . $this->extension . '.png', 'fileicon.png' ); foreach( $try as $icon ) { $path = '/common/images/icons/' . $icon; $filepath = $wgStyleDirectory . $path; if( file_exists( $filepath ) ) { return new ThumbnailImage( $wgStylePath . $path, 120, 120 ); } } return null; } /** * Create a thumbnail of the image having the specified width. * The thumbnail will not be created if the width is larger than the * image's width. Let the browser do the scaling in this case. * The thumbnail is stored on disk and is only computed if the thumbnail * file does not exist OR if it is older than the image. * Returns an object which can return the pathname, URL, and physical * pixel size of the thumbnail -- or null on failure. * * @return ThumbnailImage * @private */ function renderThumb( $width, $useScript = true ) { global $wgUseSquid; global $wgSVGMaxSize, $wgMaxImageArea, $wgThumbnailEpoch; $fname = 'Image::renderThumb'; wfProfileIn( $fname ); $width = intval( $width ); $this->load(); if ( ! $this->exists() ) { # If there is no image, there will be no thumbnail wfProfileOut( $fname ); return null; } # Sanity check $width if( $width <= 0 || $this->width <= 0) { # BZZZT wfProfileOut( $fname ); return null; } # Don't thumbnail an image so big that it will fill hard drives and send servers into swap # JPEG has the handy property of allowing thumbnailing without full decompression, so we make # an exception for it. if ( $this->getMediaType() == MEDIATYPE_BITMAP && $this->getMimeType() !== 'image/jpeg' && $this->width * $this->height > $wgMaxImageArea ) { wfProfileOut( $fname ); return null; } # Don't make an image bigger than the source, or wgMaxSVGSize for SVGs if ( $this->mustRender() ) { $width = min( $width, $wgSVGMaxSize ); } elseif ( $width > $this->width - 1 ) { $thumb = new ThumbnailImage( $this->getURL(), $this->getWidth(), $this->getHeight() ); wfProfileOut( $fname ); return $thumb; } $height = round( $this->height * $width / $this->width ); list( $isScriptUrl, $url ) = $this->thumbUrl( $width ); if ( $isScriptUrl && $useScript ) { // Use thumb.php to render the image $thumb = new ThumbnailImage( $url, $width, $height ); wfProfileOut( $fname ); return $thumb; } $thumbName = $this->thumbName( $width, $this->fromSharedDirectory ); $thumbPath = wfImageThumbDir( $this->name, $this->fromSharedDirectory ).'/'.$thumbName; if ( is_dir( $thumbPath ) ) { // Directory where file should be // This happened occasionally due to broken migration code in 1.5 // Rename to broken-* global $wgUploadDirectory; for ( $i = 0; $i < 100 ; $i++ ) { $broken = "$wgUploadDirectory/broken-$i-$thumbName"; if ( !file_exists( $broken ) ) { rename( $thumbPath, $broken ); break; } } // Code below will ask if it exists, and the answer is now no clearstatcache(); } $done = true; if ( !file_exists( $thumbPath ) || filemtime( $thumbPath ) < wfTimestamp( TS_UNIX, $wgThumbnailEpoch ) ) { $oldThumbPath = wfDeprecatedThumbDir( $thumbName, 'thumb', $this->fromSharedDirectory ). '/'.$thumbName; $done = false; // Migration from old directory structure if ( is_file( $oldThumbPath ) ) { if ( filemtime($oldThumbPath) >= filemtime($this->imagePath) ) { if ( file_exists( $thumbPath ) ) { if ( !is_dir( $thumbPath ) ) { // Old image in the way of rename unlink( $thumbPath ); } else { // This should have been dealt with already wfDebugDieBacktrace( "Directory where image should be: $thumbPath" ); } } // Rename the old image into the new location rename( $oldThumbPath, $thumbPath ); $done = true; } else { unlink( $oldThumbPath ); } } if ( !$done ) { $this->lastError = $this->reallyRenderThumb( $thumbPath, $width, $height ); if ( $this->lastError === true ) { $done = true; + } elseif( $GLOBALS['wgIgnoreImageErrors'] ) { + // Log the error but output anyway. + // With luck it's a transitory error... + $done = true; } # Purge squid # This has to be done after the image is updated and present for all machines on NFS, # or else the old version might be stored into the squid again if ( $wgUseSquid ) { $urlArr = array( $url ); wfPurgeSquidServers($urlArr); } } } if ( $done ) { $thumb = new ThumbnailImage( $url, $width, $height, $thumbPath ); } else { $thumb = null; } wfProfileOut( $fname ); return $thumb; } // END OF function renderThumb /** * Really render a thumbnail * Call this only for images for which canRender() returns true. * * @param string $thumbPath Path to thumbnail * @param int $width Desired width in pixels * @param int $height Desired height in pixels * @return bool True on error, false or error string on failure. * @private */ function reallyRenderThumb( $thumbPath, $width, $height ) { global $wgSVGConverters, $wgSVGConverter; global $wgUseImageMagick, $wgImageMagickConvertCommand; global $wgCustomConvertCommand; $this->load(); $err = false; $cmd = ""; $retval = 0; if( $this->mime === "image/svg" ) { #Right now we have only SVG global $wgSVGConverters, $wgSVGConverter; if( isset( $wgSVGConverters[$wgSVGConverter] ) ) { global $wgSVGConverterPath; $cmd = str_replace( array( '$path/', '$width', '$height', '$input', '$output' ), array( $wgSVGConverterPath ? "$wgSVGConverterPath/" : "", intval( $width ), intval( $height ), wfEscapeShellArg( $this->imagePath ), wfEscapeShellArg( $thumbPath ) ), $wgSVGConverters[$wgSVGConverter] ); wfProfileIn( 'rsvg' ); wfDebug( "reallyRenderThumb SVG: $cmd\n" ); $err = wfShellExec( $cmd, $retval ); wfProfileOut( 'rsvg' ); } } elseif ( $wgUseImageMagick ) { # use ImageMagick if ( $this->mime == 'image/jpeg' ) { $quality = "-quality 80"; // 80% } elseif ( $this->mime == 'image/png' ) { $quality = "-quality 95"; // zlib 9, adaptive filtering } else { $quality = ''; // default } # Specify white background color, will be used for transparent images # in Internet Explorer/Windows instead of default black. # Note, we specify "-size {$width}" and NOT "-size {$width}x{$height}". # It seems that ImageMagick has a bug wherein it produces thumbnails of # the wrong size in the second case. $cmd = wfEscapeShellArg($wgImageMagickConvertCommand) . " {$quality} -background white -size {$width} ". wfEscapeShellArg($this->imagePath) . // For the -resize option a "!" is needed to force exact size, // or ImageMagick may decide your ratio is wrong and slice off // a pixel. " -resize " . wfEscapeShellArg( "{$width}x{$height}!" ) . " -depth 8 " . wfEscapeShellArg($thumbPath) . " 2>&1"; wfDebug("reallyRenderThumb: running ImageMagick: $cmd\n"); wfProfileIn( 'convert' ); $err = wfShellExec( $cmd, $retval ); wfProfileOut( 'convert' ); } elseif( $wgCustomConvertCommand ) { # Use a custom convert command # Variables: %s %d %w %h $src = wfEscapeShellArg( $this->imagePath ); $dst = wfEscapeShellArg( $thumbPath ); $cmd = $wgCustomConvertCommand; $cmd = str_replace( '%s', $src, str_replace( '%d', $dst, $cmd ) ); # Filenames $cmd = str_replace( '%h', $height, str_replace( '%w', $width, $cmd ) ); # Size wfDebug( "reallyRenderThumb: Running custom convert command $cmd\n" ); wfProfileIn( 'convert' ); $err = wfShellExec( $cmd, $retval ); wfProfileOut( 'convert' ); } else { # Use PHP's builtin GD library functions. # # First find out what kind of file this is, and select the correct # input routine for this. $typemap = array( 'image/gif' => array( 'imagecreatefromgif', 'palette', 'imagegif' ), 'image/jpeg' => array( 'imagecreatefromjpeg', 'truecolor', array( &$this, 'imageJpegWrapper' ) ), 'image/png' => array( 'imagecreatefrompng', 'bits', 'imagepng' ), 'image/vnd.wap.wmbp' => array( 'imagecreatefromwbmp', 'palette', 'imagewbmp' ), 'image/xbm' => array( 'imagecreatefromxbm', 'palette', 'imagexbm' ), ); if( !isset( $typemap[$this->mime] ) ) { $err = 'Image type not supported'; wfDebug( "$err\n" ); return $err; } list( $loader, $colorStyle, $saveType ) = $typemap[$this->mime]; if( !function_exists( $loader ) ) { $err = "Incomplete GD library configuration: missing function $loader"; wfDebug( "$err\n" ); return $err; } if( $colorStyle == 'palette' ) { $truecolor = false; } elseif( $colorStyle == 'truecolor' ) { $truecolor = true; } elseif( $colorStyle == 'bits' ) { $truecolor = ( $this->bits > 8 ); } $src_image = call_user_func( $loader, $this->imagePath ); if ( $truecolor ) { $dst_image = imagecreatetruecolor( $width, $height ); } else { $dst_image = imagecreate( $width, $height ); } imagecopyresampled( $dst_image, $src_image, 0,0,0,0, $width, $height, $this->width, $this->height ); call_user_func( $saveType, $dst_image, $thumbPath ); imagedestroy( $dst_image ); imagedestroy( $src_image ); } # # Check for zero-sized thumbnails. Those can be generated when # no disk space is available or some other error occurs # if( file_exists( $thumbPath ) ) { $thumbstat = stat( $thumbPath ); if( $thumbstat['size'] == 0 || $retval != 0 ) { wfDebugLog( 'thumbnail', sprintf( 'Removing bad %d-byte thumbnail "%s"', $thumbstat['size'], $thumbPath ) ); unlink( $thumbPath ); } } if ( $retval != 0 ) { wfDebugLog( 'thumbnail', sprintf( 'thumbnail failed on %s: error %d "%s" from "%s"', wfHostname(), $retval, trim($err), $cmd ) ); return wfMsg( 'thumbnail_error', $err ); } else { return true; } } function getLastError() { return $this->lastError; } function imageJpegWrapper( $dst_image, $thumbPath ) { imageinterlace( $dst_image ); imagejpeg( $dst_image, $thumbPath, 95 ); } /** * Get all thumbnail names previously generated for this image */ function getThumbnails( $shared = false ) { if ( Image::isHashed( $shared ) ) { $this->load(); $files = array(); $dir = wfImageThumbDir( $this->name, $shared ); // This generates an error on failure, hence the @ $handle = @opendir( $dir ); if ( $handle ) { while ( false !== ( $file = readdir($handle) ) ) { if ( $file{0} != '.' ) { $files[] = $file; } } closedir( $handle ); } } else { $files = array(); } return $files; } /** * Refresh metadata in memcached, but don't touch thumbnails or squid */ function purgeMetadataCache() { clearstatcache(); $this->loadFromFile(); $this->saveToCache(); } /** * Delete all previously generated thumbnails, refresh metadata in memcached and purge the squid */ function purgeCache( $archiveFiles = array(), $shared = false ) { global $wgUseSquid; // Refresh metadata cache $this->purgeMetadataCache(); // Delete thumbnails $files = $this->getThumbnails( $shared ); $dir = wfImageThumbDir( $this->name, $shared ); $urls = array(); foreach ( $files as $file ) { if ( preg_match( '/^(\d+)px/', $file, $m ) ) { $urls[] = $this->thumbUrl( $m[1], $this->fromSharedDirectory ); @unlink( "$dir/$file" ); } } // Purge the squid if ( $wgUseSquid ) { $urls[] = $this->getViewURL(); foreach ( $archiveFiles as $file ) { $urls[] = wfImageArchiveUrl( $file ); } wfPurgeSquidServers( $urls ); } } function checkDBSchema(&$db) { global $wgCheckDBSchema; if (!$wgCheckDBSchema) { return; } # img_name must be unique if ( !$db->indexUnique( 'image', 'img_name' ) && !$db->indexExists('image','PRIMARY') ) { wfDebugDieBacktrace( 'Database schema not up to date, please run maintenance/archives/patch-image_name_unique.sql' ); } #new fields must exist if ( !$db->fieldExists( 'image', 'img_media_type' ) || !$db->fieldExists( 'image', 'img_metadata' ) || !$db->fieldExists( 'image', 'img_width' ) ) { wfDebugDieBacktrace( 'Database schema not up to date, please run maintenance/update.php' ); } } /** * Return the image history of this image, line by line. * starts with current version, then old versions. * uses $this->historyLine to check which line to return: * 0 return line for current version * 1 query for old versions, return first one * 2, ... return next old version from above query * * @public */ function nextHistoryLine() { $fname = 'Image::nextHistoryLine()'; $dbr =& wfGetDB( DB_SLAVE ); $this->checkDBSchema($dbr); if ( $this->historyLine == 0 ) {// called for the first time, return line from cur $this->historyRes = $dbr->select( 'image', array( 'img_size', 'img_description', 'img_user','img_user_text', 'img_timestamp', 'img_width', 'img_height', "'' AS oi_archive_name" ), array( 'img_name' => $this->title->getDBkey() ), $fname ); if ( 0 == wfNumRows( $this->historyRes ) ) { return FALSE; } } else if ( $this->historyLine == 1 ) { $this->historyRes = $dbr->select( 'oldimage', array( 'oi_size AS img_size', 'oi_description AS img_description', 'oi_user AS img_user', 'oi_user_text AS img_user_text', 'oi_timestamp AS img_timestamp', 'oi_width as img_width', 'oi_height as img_height', 'oi_archive_name' ), array( 'oi_name' => $this->title->getDBkey() ), $fname, array( 'ORDER BY' => 'oi_timestamp DESC' ) ); } $this->historyLine ++; return $dbr->fetchObject( $this->historyRes ); } /** * Reset the history pointer to the first element of the history * @public */ function resetHistory() { $this->historyLine = 0; } /** * Return the full filesystem path to the file. Note that this does * not mean that a file actually exists under that location. * * This path depends on whether directory hashing is active or not, * i.e. whether the images are all found in the same directory, * or in hashed paths like /images/3/3c. * * @public * @param boolean $fromSharedDirectory Return the path to the file * in a shared repository (see $wgUseSharedRepository and related * options in DefaultSettings.php) instead of a local one. * */ function getFullPath( $fromSharedRepository = false ) { global $wgUploadDirectory, $wgSharedUploadDirectory; $dir = $fromSharedRepository ? $wgSharedUploadDirectory : $wgUploadDirectory; // $wgSharedUploadDirectory may be false, if thumb.php is used if ( $dir ) { $fullpath = $dir . wfGetHashPath($this->name, $fromSharedRepository) . $this->name; } else { $fullpath = false; } return $fullpath; } /** * @return bool * @static */ function isHashed( $shared ) { global $wgHashedUploadDirectory, $wgHashedSharedUploadDirectory; return $shared ? $wgHashedSharedUploadDirectory : $wgHashedUploadDirectory; } /** * Record an image upload in the upload log and the image table */ function recordUpload( $oldver, $desc, $license = '', $copyStatus = '', $source = '', $watch = false ) { global $wgUser, $wgUseCopyrightUpload, $wgUseSquid, $wgPostCommitUpdateList; $fname = 'Image::recordUpload'; $dbw =& wfGetDB( DB_MASTER ); $this->checkDBSchema($dbw); // Delete thumbnails and refresh the metadata cache $this->purgeCache(); // Fail now if the image isn't there if ( !$this->fileExists || $this->fromSharedDirectory ) { wfDebug( "Image::recordUpload: File ".$this->imagePath." went missing!\n" ); return false; } if ( $wgUseCopyrightUpload ) { if ( $license != '' ) { $licensetxt = '== ' . wfMsgForContent( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n"; } $textdesc = '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $desc . "\n" . '== ' . wfMsgForContent ( 'filestatus' ) . " ==\n" . $copyStatus . "\n" . "$licensetxt" . '== ' . wfMsgForContent ( 'filesource' ) . " ==\n" . $source ; } else { if ( $license != '' ) { $filedesc = $desc == '' ? '' : '== ' . wfMsg ( 'filedesc' ) . " ==\n" . $desc . "\n"; $textdesc = $filedesc . '== ' . wfMsgForContent ( 'license' ) . " ==\n" . '{{' . $license . '}}' . "\n"; } else { $textdesc = $desc; } } $now = $dbw->timestamp(); #split mime type if (strpos($this->mime,'/')!==false) { list($major,$minor)= explode('/',$this->mime,2); } else { $major= $this->mime; $minor= "unknown"; } # Test to see if the row exists using INSERT IGNORE # This avoids race conditions by locking the row until the commit, and also # doesn't deadlock. SELECT FOR UPDATE causes a deadlock for every race condition. $dbw->insert( 'image', array( 'img_name' => $this->name, 'img_size'=> $this->size, 'img_width' => intval( $this->width ), 'img_height' => intval( $this->height ), 'img_bits' => $this->bits, 'img_media_type' => $this->type, 'img_major_mime' => $major, 'img_minor_mime' => $minor, 'img_timestamp' => $now, 'img_description' => $desc, 'img_user' => $wgUser->getID(), 'img_user_text' => $wgUser->getName(), 'img_metadata' => $this->metadata, ), $fname, 'IGNORE' ); $descTitle = $this->getTitle(); $purgeURLs = array(); if( $dbw->affectedRows() == 0 ) { # Collision, this is an update of an image # Insert previous contents into oldimage $dbw->insertSelect( 'oldimage', 'image', array( 'oi_name' => 'img_name', 'oi_archive_name' => $dbw->addQuotes( $oldver ), 'oi_size' => 'img_size', 'oi_width' => 'img_width', 'oi_height' => 'img_height', 'oi_bits' => 'img_bits', 'oi_timestamp' => 'img_timestamp', 'oi_description' => 'img_description', 'oi_user' => 'img_user', 'oi_user_text' => 'img_user_text', ), array( 'img_name' => $this->name ), $fname ); # Update the current image row $dbw->update( 'image', array( /* SET */ 'img_size' => $this->size, 'img_width' => intval( $this->width ), 'img_height' => intval( $this->height ), 'img_bits' => $this->bits, 'img_media_type' => $this->type, 'img_major_mime' => $major, 'img_minor_mime' => $minor, 'img_timestamp' => $now, 'img_description' => $desc, 'img_user' => $wgUser->getID(), 'img_user_text' => $wgUser->getName(), 'img_metadata' => $this->metadata, ), array( /* WHERE */ 'img_name' => $this->name ), $fname ); } else { # This is a new image # Update the image count $site_stats = $dbw->tableName( 'site_stats' ); $dbw->query( "UPDATE $site_stats SET ss_images=ss_images+1", $fname ); } $article = new Article( $descTitle ); $minor = false; $watch = $watch || $wgUser->isWatched( $descTitle ); $suppressRC = true; // There's already a log entry, so don't double the RC load if( $descTitle->exists() ) { // TODO: insert a null revision into the page history for this update. if( $watch ) { $wgUser->addWatch( $descTitle ); } # Invalidate the cache for the description page $descTitle->invalidateCache(); $purgeURLs[] = $descTitle->getInternalURL(); } else { // New image; create the description page. $article->insertNewArticle( $textdesc, $desc, $minor, $watch, $suppressRC ); } # Invalidate cache for all pages using this image $linksTo = $this->getLinksTo(); if ( $wgUseSquid ) { $u = SquidUpdate::newFromTitles( $linksTo, $purgeURLs ); array_push( $wgPostCommitUpdateList, $u ); } Title::touchArray( $linksTo ); $log = new LogPage( 'upload' ); $log->addEntry( 'upload', $descTitle, $desc ); return true; } /** * Get an array of Title objects which are articles which use this image * Also adds their IDs to the link cache * * This is mostly copied from Title::getLinksTo() */ function getLinksTo( $options = '' ) { $fname = 'Image::getLinksTo'; wfProfileIn( $fname ); if ( $options ) { $db =& wfGetDB( DB_MASTER ); } else { $db =& wfGetDB( DB_SLAVE ); } $linkCache =& LinkCache::singleton(); extract( $db->tableNames( 'page', 'imagelinks' ) ); $encName = $db->addQuotes( $this->name ); $sql = "SELECT page_namespace,page_title,page_id FROM $page,$imagelinks WHERE page_id=il_from AND il_to=$encName $options"; $res = $db->query( $sql, $fname ); $retVal = array(); if ( $db->numRows( $res ) ) { while ( $row = $db->fetchObject( $res ) ) { if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) { $linkCache->addGoodLinkObj( $row->page_id, $titleObj ); $retVal[] = $titleObj; } } } $db->freeResult( $res ); wfProfileOut( $fname ); return $retVal; } /** * Retrive Exif data from the database * * Retrive Exif data from the database and prune unrecognized tags * and/or tags with invalid contents * * @return array */ function retrieveExifData() { if ( $this->getMimeType() !== "image/jpeg" ) return array(); $exif = new Exif( $this->imagePath ); return $exif->getFilteredData(); } function getExifData() { global $wgRequest; if ( $this->metadata === '0' ) return array(); $purge = $wgRequest->getVal( 'action' ) == 'purge'; $ret = unserialize( $this->metadata ); $oldver = isset( $ret['MEDIAWIKI_EXIF_VERSION'] ) ? $ret['MEDIAWIKI_EXIF_VERSION'] : 0; $newver = Exif::version(); if ( !count( $ret ) || $purge || $oldver != $newver ) { $this->purgeMetadataCache(); $this->updateExifData( $newver ); } if ( isset( $ret['MEDIAWIKI_EXIF_VERSION'] ) ) unset( $ret['MEDIAWIKI_EXIF_VERSION'] ); $format = new FormatExif( $ret ); return $format->getFormattedData(); } function updateExifData( $version ) { $fname = 'Image:updateExifData'; if ( $this->getImagePath() === false ) # Not a local image return; # Get EXIF data from image $exif = $this->retrieveExifData(); if ( count( $exif ) ) { $exif['MEDIAWIKI_EXIF_VERSION'] = $version; $this->metadata = serialize( $exif ); } else { $this->metadata = '0'; } # Update EXIF data in database $dbw =& wfGetDB( DB_MASTER ); $this->checkDBSchema($dbw); $dbw->update( 'image', array( 'img_metadata' => $this->metadata ), array( 'img_name' => $this->name ), $fname ); } /** * Returns true if the image does not come from the shared * image repository. * * @return bool */ function isLocal() { return !$this->fromSharedDirectory; } /** * Was this image ever deleted from the wiki? * * @return bool */ function wasDeleted() { $dbw =& wfGetDB( DB_MASTER ); $del = $dbw->selectField( 'archive', 'COUNT(*) AS count', array( 'ar_namespace' => NS_IMAGE, 'ar_title' => $this->title->getDBkey() ), 'Image::wasDeleted' ); return $del > 0; } } //class /** * Returns the image directory of an image * If the directory does not exist, it is created. * The result is an absolute path. * * This function is called from thumb.php before Setup.php is included * * @param $fname String: file name of the image file. * @public */ function wfImageDir( $fname ) { global $wgUploadDirectory, $wgHashedUploadDirectory; if (!$wgHashedUploadDirectory) { return $wgUploadDirectory; } $hash = md5( $fname ); $oldumask = umask(0); $dest = $wgUploadDirectory . '/' . $hash{0}; if ( ! is_dir( $dest ) ) { mkdir( $dest, 0777 ); } $dest .= '/' . substr( $hash, 0, 2 ); if ( ! is_dir( $dest ) ) { mkdir( $dest, 0777 ); } umask( $oldumask ); return $dest; } /** * Returns the image directory of an image's thubnail * If the directory does not exist, it is created. * The result is an absolute path. * * This function is called from thumb.php before Setup.php is included * * @param $fname String: file name of the original image file * @param $shared Boolean: (optional) use the shared upload directory (default: 'false'). * @public */ function wfImageThumbDir( $fname, $shared = false ) { $base = wfImageArchiveDir( $fname, 'thumb', $shared ); if ( Image::isHashed( $shared ) ) { $dir = "$base/$fname"; if ( !is_dir( $base ) ) { $oldumask = umask(0); @mkdir( $base, 0777 ); umask( $oldumask ); } if ( ! is_dir( $dir ) ) { if ( is_file( $dir ) ) { // Old thumbnail in the way of directory creation, kill it unlink( $dir ); } $oldumask = umask(0); @mkdir( $dir, 0777 ); umask( $oldumask ); } } else { $dir = $base; } return $dir; } /** * Old thumbnail directory, kept for conversion */ function wfDeprecatedThumbDir( $thumbName , $subdir='thumb', $shared=false) { return wfImageArchiveDir( $thumbName, $subdir, $shared ); } /** * Returns the image directory of an image's old version * If the directory does not exist, it is created. * The result is an absolute path. * * This function is called from thumb.php before Setup.php is included * * @param $fname String: file name of the thumbnail file, including file size prefix. * @param $subdir String: subdirectory of the image upload directory that should be used for storing the old version. Default is 'archive'. * @param $shared Boolean use the shared upload directory (only relevant for other functions which call this one). Default is 'false'. * @public */ function wfImageArchiveDir( $fname , $subdir='archive', $shared=false ) { global $wgUploadDirectory, $wgHashedUploadDirectory; global $wgSharedUploadDirectory, $wgHashedSharedUploadDirectory; $dir = $shared ? $wgSharedUploadDirectory : $wgUploadDirectory; $hashdir = $shared ? $wgHashedSharedUploadDirectory : $wgHashedUploadDirectory; if (!$hashdir) { return $dir.'/'.$subdir; } $hash = md5( $fname ); $oldumask = umask(0); # Suppress warning messages here; if the file itself can't # be written we'll worry about it then. wfSuppressWarnings(); $archive = $dir.'/'.$subdir; if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); } $archive .= '/' . $hash{0}; if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); } $archive .= '/' . substr( $hash, 0, 2 ); if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); } wfRestoreWarnings(); umask( $oldumask ); return $archive; } /* * Return the hash path component of an image path (URL or filesystem), * e.g. "/3/3c/", or just "/" if hashing is not used. * * @param $dbkey The filesystem / database name of the file * @param $fromSharedDirectory Use the shared file repository? It may * use different hash settings from the local one. */ function wfGetHashPath ( $dbkey, $fromSharedDirectory = false ) { if( Image::isHashed( $fromSharedDirectory ) ) { $hash = md5($dbkey); return '/' . $hash{0} . '/' . substr( $hash, 0, 2 ) . '/'; } else { return '/'; } } /** * Returns the image URL of an image's old version * * @param $name String: file name of the image file * @param $subdir String: (optional) subdirectory of the image upload directory that is used by the old version. Default is 'archive' * @public */ function wfImageArchiveUrl( $name, $subdir='archive' ) { global $wgUploadPath, $wgHashedUploadDirectory; if ($wgHashedUploadDirectory) { $hash = md5( substr( $name, 15) ); $url = $wgUploadPath.'/'.$subdir.'/' . $hash{0} . '/' . substr( $hash, 0, 2 ) . '/'.$name; } else { $url = $wgUploadPath.'/'.$subdir.'/'.$name; } return wfUrlencode($url); } /** * Return a rounded pixel equivalent for a labeled CSS/SVG length. * http://www.w3.org/TR/SVG11/coords.html#UnitIdentifiers * * @param $length String: CSS/SVG length. * @return Integer: length in pixels */ function wfScaleSVGUnit( $length ) { static $unitLength = array( 'px' => 1.0, 'pt' => 1.25, 'pc' => 15.0, 'mm' => 3.543307, 'cm' => 35.43307, 'in' => 90.0, '' => 1.0, // "User units" pixels by default '%' => 2.0, // Fake it! ); if( preg_match( '/^(\d+(?:\.\d+)?)(em|ex|px|pt|pc|cm|mm|in|%|)$/', $length, $matches ) ) { $length = floatval( $matches[1] ); $unit = $matches[2]; return round( $length * $unitLength[$unit] ); } else { // Assume pixels return round( floatval( $length ) ); } } /** * Compatible with PHP getimagesize() * @todo support gzipped SVGZ * @todo check XML more carefully * @todo sensible defaults * * @param $filename String: full name of the file (passed to php fopen()). * @return array */ function wfGetSVGsize( $filename ) { $width = 256; $height = 256; // Read a chunk of the file $f = fopen( $filename, "rt" ); if( !$f ) return false; $chunk = fread( $f, 4096 ); fclose( $f ); // Uber-crappy hack! Run through a real XML parser. if( !preg_match( '/<svg\s*([^>]*)\s*>/s', $chunk, $matches ) ) { return false; } $tag = $matches[1]; if( preg_match( '/\bwidth\s*=\s*("[^"]+"|\'[^\']+\')/s', $tag, $matches ) ) { $width = wfScaleSVGUnit( trim( substr( $matches[1], 1, -1 ) ) ); } if( preg_match( '/\bheight\s*=\s*("[^"]+"|\'[^\']+\')/s', $tag, $matches ) ) { $height = wfScaleSVGUnit( trim( substr( $matches[1], 1, -1 ) ) ); } return array( $width, $height, 'SVG', "width=\"$width\" height=\"$height\"" ); } /** * Determine if an image exists on the 'bad image list'. * * @param $name String: the image name to check * @return bool */ function wfIsBadImage( $name ) { static $titleList = false; if( !$titleList ) { # Build the list now $titleList = array(); $lines = explode( "\n", wfMsgForContent( 'bad_image_list' ) ); foreach( $lines as $line ) { if( preg_match( '/^\*\s*\[\[:?(.*?)\]\]/i', $line, $matches ) ) { $title = Title::newFromText( $matches[1] ); if( is_object( $title ) && $title->getNamespace() == NS_IMAGE ) $titleList[ $title->getDBkey() ] = true; } } } return array_key_exists( $name, $titleList ); } /** * Wrapper class for thumbnail images * @package MediaWiki */ class ThumbnailImage { /** * @param string $path Filesystem path to the thumb * @param string $url URL path to the thumb * @private */ function ThumbnailImage( $url, $width, $height, $path = false ) { $this->url = $url; $this->width = round( $width ); $this->height = round( $height ); # These should be integers when they get here. # If not, there's a bug somewhere. But let's at # least produce valid HTML code regardless. $this->path = $path; } /** * @return string The thumbnail URL */ function getUrl() { return $this->url; } /** * Return HTML <img ... /> tag for the thumbnail, will include * width and height attributes and a blank alt text (as required). * * You can set or override additional attributes by passing an * associative array of name => data pairs. The data will be escaped * for HTML output, so should be in plaintext. * * @param array $attribs * @return string * @public */ function toHtml( $attribs = array() ) { $attribs['src'] = $this->url; $attribs['width'] = $this->width; $attribs['height'] = $this->height; if( !isset( $attribs['alt'] ) ) $attribs['alt'] = ''; $html = '<img '; foreach( $attribs as $name => $data ) { $html .= $name . '="' . htmlspecialchars( $data ) . '" '; } $html .= '/>'; return $html; } } /** * Calculate the largest thumbnail width for a given original file size * such that the thumbnail's height is at most $maxHeight. * @param $boxWidth Integer Width of the thumbnail box. * @param $boxHeight Integer Height of the thumbnail box. * @param $maxHeight Integer Maximum height expected for the thumbnail. * @return Integer. */ function wfFitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) { $idealWidth = $boxWidth * $maxHeight / $boxHeight; $roundedUp = ceil( $idealWidth ); if( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight ) return floor( $idealWidth ); else return $roundedUp; } ?>