28use Wikimedia\Timestamp\TimestampException;
66 $this->singleLang = $val;
88 return $obj->makeFormattedData( $tags );
103 $resolutionunit = !isset( $tags[
'ResolutionUnit'] ) || $tags[
'ResolutionUnit'] == 2 ? 2 : 3;
104 unset( $tags[
'ResolutionUnit'] );
106 foreach ( $tags as $tag => &$vals ) {
109 if ( !is_array( $tags[$tag] ) ) {
114 if ( isset( $tags[$tag][
'_type'] ) ) {
115 $type = $tags[$tag][
'_type'];
116 unset( $vals[
'_type'] );
122 if ( $tag ==
'GPSTimeStamp' && count( $vals ) === 3 ) {
125 $h = explode(
'/', $vals[0] );
126 $m = explode(
'/', $vals[1] );
127 $s = explode(
'/', $vals[2] );
142 $tags[$tag] = str_pad( intval( $h[0] / $h[1] ), 2,
'0', STR_PAD_LEFT )
143 .
':' . str_pad( intval( $m[0] / $m[1] ), 2,
'0', STR_PAD_LEFT )
144 .
':' . str_pad( intval(
$s[0] /
$s[1] ), 2,
'0', STR_PAD_LEFT );
152 }
catch ( TimestampException
$e ) {
163 if ( $tag ===
'Contact' ) {
168 foreach ( $vals as &$val ) {
183 $val = $this->
exifMsg( $tag, $val );
191 case 'PhotometricInterpretation':
205 $val = $this->
exifMsg( $tag, $val );
223 $val = $this->
exifMsg( $tag, $val );
231 case 'PlanarConfiguration':
235 $val = $this->
exifMsg( $tag, $val );
244 case 'YCbCrPositioning':
248 $val = $this->
exifMsg( $tag, $val );
258 switch ( $resolutionunit ) {
273 case 'FlashpixVersion':
274 $val = (int)$val / 100;
281 $val = $this->
exifMsg( $tag, $val );
289 case 'ComponentsConfiguration':
298 $val = $this->
exifMsg( $tag, $val );
307 case 'DateTimeOriginal':
308 case 'DateTimeDigitized':
309 case 'DateTimeReleased':
310 case 'DateTimeExpires':
313 case 'DateTimeMetadata':
314 if ( $val ==
'0000:00:00 00:00:00' || $val ==
' : : : : ' ) {
315 $val = $this->
msg(
'exif-unknowndate' )->text();
316 } elseif ( preg_match(
317 '/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d):(?:\d\d)$/D',
325 } elseif ( preg_match(
'/^(?:\d{4}):(?:\d\d):(?:\d\d) (?:\d\d):(?:\d\d)$/D', $val ) ) {
333 } elseif ( preg_match(
'/^(?:\d{4}):(?:\d\d):(?:\d\d)$/D', $val ) ) {
336 . substr( $val, 5, 2 )
337 . substr( $val, 8, 2 )
346 case 'ExposureProgram':
357 $val = $this->
exifMsg( $tag, $val );
365 case 'SubjectDistance':
380 $val = $this->
exifMsg( $tag, $val );
411 $val = $this->
exifMsg( $tag, $val );
421 'fired' => $val & 0b00000001,
422 'return' => ( $val & 0b00000110 ) >> 1,
423 'mode' => ( $val & 0b00011000 ) >> 3,
424 'function' => ( $val & 0b00100000 ) >> 5,
425 'redeye' => ( $val & 0b01000000 ) >> 6,
429 # We do not need to handle unknown values since all are used.
430 foreach ( $flashDecode as $subTag => $subValue ) {
431 # We do not need any message for zeroed values.
432 if ( $subTag !=
'fired' && $subValue == 0 ) {
435 $fullTag = $tag .
'-' . $subTag;
436 $flashMsgs[] = $this->
exifMsg( $fullTag, $subValue );
438 $val = $this->
getLanguage()->commaList( $flashMsgs );
441 case 'FocalPlaneResolutionUnit':
444 $val = $this->
exifMsg( $tag, $val );
452 case 'SensingMethod':
461 $val = $this->
exifMsg( $tag, $val );
472 $val = $this->
exifMsg( $tag, $val );
483 $val = $this->
exifMsg( $tag, $val );
491 case 'CustomRendered':
495 $val = $this->
exifMsg( $tag, $val );
508 $val = $this->
exifMsg( $tag, $val );
520 $val = $this->
exifMsg( $tag, $val );
528 case 'SceneCaptureType':
534 $val = $this->
exifMsg( $tag, $val );
549 $val = $this->
exifMsg( $tag, $val );
562 $val = $this->
exifMsg( $tag, $val );
575 $val = $this->
exifMsg( $tag, $val );
588 $val = $this->
exifMsg( $tag, $val );
596 case 'SubjectDistanceRange':
602 $val = $this->
exifMsg( $tag, $val );
611 case 'GPSLatitudeRef':
612 case 'GPSDestLatitudeRef':
616 $val = $this->
exifMsg(
'GPSLatitude', $val );
624 case 'GPSLongitudeRef':
625 case 'GPSDestLongitudeRef':
629 $val = $this->
exifMsg(
'GPSLongitude', $val );
639 $val = $this->
exifMsg(
'GPSAltitude',
'below-sealevel', $this->
formatNum( -$val, 3 ) );
641 $val = $this->
exifMsg(
'GPSAltitude',
'above-sealevel', $this->
formatNum( $val, 3 ) );
649 $val = $this->
exifMsg( $tag, $val );
657 case 'GPSMeasureMode':
661 $val = $this->
exifMsg( $tag, $val );
670 case 'GPSImgDirectionRef':
671 case 'GPSDestBearingRef':
675 $val = $this->
exifMsg(
'GPSDirection', $val );
684 case 'GPSDestLatitude':
688 case 'GPSDestLongitude':
697 $val = $this->
exifMsg(
'GPSSpeed', $val );
705 case 'GPSDestDistanceRef':
710 $val = $this->
exifMsg(
'GPSDestDistance', $val );
722 } elseif ( $val <= 5 ) {
724 } elseif ( $val <= 10 ) {
726 } elseif ( $val <= 20 ) {
738 $val = $this->
exifMsg( $tag,
'', $val );
742 if ( is_array( $val ) ) {
743 if ( count( $val ) > 1 ) {
745 $val = $this->
msg(
'exif-software-version-value', $val[0], $val[1] )->text();
748 $val = $this->
exifMsg( $tag,
'', $val[0] );
751 $val = $this->
exifMsg( $tag,
'', $val );
757 $val = $this->
msg(
'exif-exposuretime-format',
760 case 'ISOSpeedRatings':
764 if ( $val ==
'65535' ) {
765 $val = $this->
exifMsg( $tag,
'overflow' );
771 $val = $this->
msg(
'exif-fnumber-format',
776 case 'FocalLengthIn35mmFilm':
777 $val = $this->
msg(
'exif-focallength-format',
781 case 'MaxApertureValue':
782 if ( strpos( $val,
'/' ) !==
false ) {
784 list( $n, $d ) = explode(
'/', $val );
785 if ( is_numeric( $n ) && is_numeric( $d ) ) {
789 if ( is_numeric( $val ) ) {
790 $fNumber = 2 ** ( $val / 2 );
791 if ( $fNumber !==
false ) {
792 $val = $this->
msg(
'exif-maxaperturevalue-value',
801 switch ( strtolower( $val ) ) {
827 case 'SubjectNewsCode':
839 if ( $val == 0 || $val == 9 ) {
841 } elseif ( $val < 5 && $val > 1 ) {
843 } elseif ( $val == 5 ) {
845 } elseif ( $val <= 8 && $val > 5 ) {
849 if ( $urgency !==
'' ) {
850 $val = $this->
exifMsg(
'urgency',
857 case 'OriginalImageHeight':
858 case 'OriginalImageWidth':
859 case 'PixelXDimension':
860 case 'PixelYDimension':
863 $val = $this->
formatNum( $val ) .
' ' . $this->
msg(
'unit-pixel' )->text();
873 case 'ImageDescription':
877 case 'RelatedSoundFile':
878 case 'ImageUniqueID':
879 case 'SpectralSensitivity':
880 case 'GPSSatellites':
884 case 'WorldRegionDest':
886 case 'CountryCodeDest':
887 case 'ProvinceOrStateDest':
889 case 'SublocationDest':
890 case 'WorldRegionCreated':
891 case 'CountryCreated':
892 case 'CountryCodeCreated':
893 case 'ProvinceOrStateCreated':
895 case 'SublocationCreated':
897 case 'SpecialInstructions':
902 case 'FixtureIdentifier':
904 case 'LocationDestCode':
906 case 'JPEGFileComment':
907 case 'iimSupplementalCategory':
908 case 'OriginalTransmissionRef':
910 case 'dc-contributor':
919 case 'CameraOwnerName':
922 case 'RightsCertificate':
923 case 'CopyrightOwner':
926 case 'OriginalDocumentID':
928 case 'MorePermissionsUrl':
929 case 'AttributionUrl':
930 case 'PreferredAttributionName':
931 case 'PNGFileComment':
933 case 'ContentWarning':
934 case 'GIFFileComment':
936 case 'IntellectualGenre':
938 case 'OrginisationInImage':
939 case 'PersonInImage':
941 $val = htmlspecialchars( $val );
949 $val = $this->
exifMsg( $tag, $val );
952 $val = htmlspecialchars( $val );
960 $val = $this->
exifMsg( $tag, $val );
965 if ( $val ==
'-1' ) {
966 $val = $this->
exifMsg( $tag,
'rejected' );
973 $lang = Language::fetchLanguageName( strtolower( $val ), $this->
getLanguage()->getCode() );
974 $val = htmlspecialchars(
$lang ?: $val );
1011 $context->setLanguage( MediaWikiServices::getInstance()->getContentLanguage() );
1014 return $obj->flattenArrayReal( $vals,
$type, $noHtml );
1034 if ( !is_array( $vals ) ) {
1038 if ( isset( $vals[
'_type'] ) ) {
1039 $type = $vals[
'_type'];
1040 unset( $vals[
'_type'] );
1043 if ( !is_array( $vals ) ) {
1045 } elseif ( count( $vals ) === 1 &&
$type !==
'lang' && isset( $vals[0] ) ) {
1047 } elseif ( count( $vals ) === 0 ) {
1048 wfDebug( __METHOD__ .
" metadata array with 0 elements!\n" );
1067 $defaultItem =
false;
1068 $defaultLang =
false;
1077 if ( isset( $vals[
'x-default'] ) ) {
1078 $defaultItem = $vals[
'x-default'];
1079 unset( $vals[
'x-default'] );
1081 foreach ( $priorityLanguages as $pLang ) {
1082 if ( isset( $vals[$pLang] ) ) {
1084 if ( $vals[$pLang] === $defaultItem ) {
1085 $defaultItem =
false;
1089 $vals[$pLang], $pLang,
1090 $isDefault, $noHtml );
1092 unset( $vals[$pLang] );
1094 if ( $this->singleLang ) {
1095 return Html::rawElement(
'span',
1096 [
'lang' => $pLang ], $vals[$pLang] );
1102 foreach ( $vals as
$lang => $item ) {
1103 if ( $item === $defaultItem ) {
1104 $defaultLang =
$lang;
1108 $lang,
false, $noHtml );
1109 if ( $this->singleLang ) {
1110 return Html::rawElement(
'span',
1111 [
'lang' =>
$lang ], $item );
1114 if ( $defaultItem !==
false ) {
1116 $defaultLang,
true, $noHtml ) .
1118 if ( $this->singleLang ) {
1119 return $defaultItem;
1126 return '<ul class="metadata-langlist">' .
1131 return "\n#" . implode(
"\n#", $vals );
1134 return "<ol><li>" . implode(
"</li>\n<li>", $vals ) .
'</li></ol>';
1138 return "\n*" . implode(
"\n*", $vals );
1141 return "<ul><li>" . implode(
"</li>\n<li>", $vals ) .
'</li></ul>';
1157 if (
$lang ===
false && $default ===
false ) {
1158 throw new MWException(
'$lang and $default cannot both '
1165 $wrappedValue =
'<span class="mw-metadata-lang-value">'
1169 if (
$lang ===
false ) {
1170 $msg = $this->
msg(
'metadata-langitem-default', $wrappedValue );
1172 return $msg->text() .
"\n\n";
1175 return '<li class="mw-metadata-lang-default">'
1180 $lowLang = strtolower(
$lang );
1181 $langName = Language::fetchLanguageName( $lowLang );
1182 if ( $langName ===
'' ) {
1184 list( $langPrefix ) = explode(
'-', $lowLang, 2 );
1185 $langName = Language::fetchLanguageName( $langPrefix );
1186 if ( $langName ===
'' ) {
1193 $msg = $this->
msg(
'metadata-langitem', $wrappedValue, $langName,
$lang );
1195 return '*' . $msg->text();
1198 $item =
'<li class="mw-metadata-lang-code-'
1201 $item .=
' mw-metadata-lang-default';
1203 $item .=
'" lang="' .
$lang .
'">';
1204 $item .= $msg->text();
1219 private function exifMsg( $tag, $val, $arg =
null, $arg2 =
null ) {
1220 if ( $val ===
'' ) {
1225 MediaWikiServices::getInstance()->getContentLanguage()->lc(
"exif-$tag-$val" ),
1241 if ( is_array( $num ) ) {
1243 foreach ( $num as $number ) {
1249 if ( preg_match(
'/^(-?\d+)\/(\d+)$/', $num, $m ) ) {
1251 $newNum = $m[1] / $m[2];
1252 if ( $round !==
false ) {
1253 $newNum = round( $newNum, $round );
1259 return $this->
getLanguage()->formatNum( $newNum );
1261 if ( is_numeric( $num ) && $round !==
false ) {
1262 $num = round( $num, $round );
1277 if ( preg_match(
'/^(-?\d+)\/(\d+)$/', $num, $m ) ) {
1278 $numerator = intval( $m[1] );
1279 $denominator = intval( $m[2] );
1280 $gcd = $this->
gcd( abs( $numerator ), $denominator );
1283 return $this->
formatNum( $numerator / $gcd ) .
'/' . $this->
formatNum( $denominator / $gcd );
1297 private function gcd( $a, $b ) {
1307 $remainder = $a % $b;
1330 if ( !preg_match(
'/^\d{8}$/D', $val ) ) {
1335 switch ( substr( $val, 0, 2 ) ) {
1388 if ( $cat !==
'' ) {
1389 $catMsg = $this->
exifMsg(
'iimcategory', $cat );
1390 $val = $this->
exifMsg(
'subjectnewscode',
'', $val, $catMsg );
1405 if ( !is_numeric( $coord ) ) {
1406 wfDebugLog(
'exif', __METHOD__ .
": \"$coord\" is not a number" );
1407 return (
string)$coord;
1413 if (
$type ===
'latitude' ) {
1415 } elseif (
$type ===
'longitude' ) {
1419 $nCoord = (float)$coord;
1420 if (
$type ===
'latitude' ) {
1422 } elseif (
$type ===
'longitude' ) {
1427 $deg = floor( $nCoord );
1428 $min = floor( ( $nCoord - $deg ) * 60 );
1429 $sec = round( ( ( $nCoord - $deg ) * 60 - $min ) * 60, 2 );
1436 return $this->
msg(
'exif-coordinate-format', $deg, $min, $sec, $ref, $coord )->text();
1454 if ( !( isset( $vals[
'CiAdrExtadr'] )
1455 || isset( $vals[
'CiAdrCity'] )
1456 || isset( $vals[
'CiAdrCtry'] )
1457 || isset( $vals[
'CiEmailWork'] )
1458 || isset( $vals[
'CiTelWork'] )
1459 || isset( $vals[
'CiAdrPcode'] )
1460 || isset( $vals[
'CiAdrRegion'] )
1461 || isset( $vals[
'CiUrlWork'] )
1472 foreach ( $vals as &$val ) {
1473 $val = htmlspecialchars( $val );
1481 $url = $tel = $street = $city = $country =
'';
1482 $email = $postal = $region =
'';
1491 if ( isset( $vals[
'CiAdrExtadr'] ) ) {
1494 $street =
'<span class="extended-address">'
1496 $vals[
'CiAdrExtadr'] )
1499 if ( isset( $vals[
'CiAdrCity'] ) ) {
1500 $city =
'<span class="locality">'
1501 . htmlspecialchars( $vals[
'CiAdrCity'] )
1504 if ( isset( $vals[
'CiAdrCtry'] ) ) {
1505 $country =
'<span class="country-name">'
1506 . htmlspecialchars( $vals[
'CiAdrCtry'] )
1509 if ( isset( $vals[
'CiEmailWork'] ) ) {
1512 $splitEmails = explode(
"\n", $vals[
'CiEmailWork'] );
1513 foreach ( $splitEmails as $e1 ) {
1515 foreach ( explode(
',', $e1 ) as $e2 ) {
1516 $finalEmail = trim( $e2 );
1517 if ( $finalEmail ==
',' || $finalEmail ==
'' ) {
1520 if ( strpos( $finalEmail,
'<' ) !==
false ) {
1523 $emails[] = $finalEmail;
1525 $emails[] =
'[mailto:'
1527 .
' <span class="email">'
1533 $email = implode(
', ', $emails );
1535 if ( isset( $vals[
'CiTelWork'] ) ) {
1536 $tel =
'<span class="tel">'
1537 . htmlspecialchars( $vals[
'CiTelWork'] )
1540 if ( isset( $vals[
'CiAdrPcode'] ) ) {
1541 $postal =
'<span class="postal-code">'
1543 $vals[
'CiAdrPcode'] )
1546 if ( isset( $vals[
'CiAdrRegion'] ) ) {
1548 $region =
'<span class="region">'
1550 $vals[
'CiAdrRegion'] )
1553 if ( isset( $vals[
'CiUrlWork'] ) ) {
1554 $url =
'<span class="url">'
1555 . htmlspecialchars( $vals[
'CiUrlWork'] )
1559 return $this->
msg(
'exif-contact-value', $email, $url,
1560 $street, $city, $region, $postal, $country,
1576 if ( preg_match(
'/^\\*\s*(.*?)\s*$/',
$line,
$matches ) ) {
1580 $fields = array_map(
'strtolower', $fields );
1593 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1600 $cacheKey =
$cache->makeKey(
1601 'getExtendedMetadata',
1603 (
int)$this->singleLang,
1607 $cachedValue =
$cache->get( $cacheKey );
1610 && Hooks::run(
'ValidateExtendedMetadataCache', [ $cachedValue[
'timestamp'], $file ] )
1612 $extendedMetadata = $cachedValue[
'data'];
1614 $maxCacheTime = ( $file instanceof
ForeignAPIFile ) ? 60 * 60 * 12 : 60 * 60 * 24 * 30;
1617 if ( $this->singleLang ) {
1626 $valueToCache = [
'data' => $extendedMetadata,
'timestamp' =>
wfTimestampNow() ];
1627 $cache->set( $cacheKey, $valueToCache, $maxCacheTime );
1630 return $extendedMetadata;
1648 return $file->getExtendedMetadata() ?: [];
1651 $uploadDate =
wfTimestamp( TS_ISO_8601, $file->getTimestamp() );
1656 'value' => $uploadDate,
1657 'source' =>
'mediawiki-metadata',
1661 $title = $file->getTitle();
1663 $text = $title->getText();
1664 $pos = strrpos( $text,
'.' );
1667 $name = substr( $text, 0, $pos );
1672 $fileMetadata[
'ObjectName'] = [
1674 'source' =>
'mediawiki-metadata',
1678 return $fileMetadata;
1694 Hooks::run(
'GetExtendedMetadata', [
1702 $visible = array_flip( self::getVisibleFields() );
1703 foreach ( $extendedMetadata as $key =>
$value ) {
1704 if ( !isset( $visible[strtolower( $key )] ) ) {
1705 $extendedMetadata[$key][
'hidden'] =
'';
1709 return $extendedMetadata;
1723 || !isset(
$value[
'_type'] )
1724 ||
$value[
'_type'] !=
'lang'
1731 foreach ( $priorityLanguages as
$lang ) {
1738 if ( isset(
$value[
'x-default'] ) ) {
1739 return $value[
'x-default'];
1743 unset(
$value[
'_type'] );
1744 if ( !empty(
$value ) ) {
1762 if ( !is_array(
$value ) ) {
1764 } elseif ( isset(
$value[
'_type'] ) &&
$value[
'_type'] ===
'lang' ) {
1767 foreach (
$value as $k => $v ) {
1787 if ( !is_array( $metadata ) ) {
1790 foreach ( $metadata as &$field ) {
1791 if ( isset( $field[
'value'] ) ) {
1804 if ( !is_array( $metadata ) ) {
1807 foreach ( $metadata as $key => &$field ) {
1808 if ( $key ===
'Software' || $key ===
'Contact' ) {
1813 if ( isset( $field[
'value'] ) ) {
1824 if ( !is_array( $arr ) ) {
1829 foreach ( $arr as $key => &
$value ) {
1831 if ( $sanitizedKey !== $key ) {
1832 if ( isset( $arr[$sanitizedKey] ) ) {
1837 $sanitizedKey .= $counter;
1840 $arr[$sanitizedKey] = $arr[$key];
1841 unset( $arr[$key] );
1843 if ( is_array(
$value ) ) {
1849 $keys = array_filter( array_keys( $arr ),
'ApiResult::isMetadataKey' );
1865 $key = preg_replace(
'/[^a-zA-z0-9_:.\-]/',
'', $key );
1867 $key = preg_replace(
'/^[\d\-.]+/',
'', $key );
1874 if ( $key ==
'_element' ) {
1888 $priorityLanguages =
1889 Language::getFallbacksIncludingSiteLanguage( $this->
getLanguage()->getCode() );
1890 $priorityLanguages = array_merge(
1892 $priorityLanguages[0],
1893 $priorityLanguages[1]
1896 return $priorityLanguages;
This list may contain false positives That usually means there is additional text with links below the first Each row contains links to the first and second as well as the first line of the second redirect text
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
static setPreserveKeysList(array &$arr, $names)
Preserve specified keys.
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
msg( $key)
Get a Message object with context set Parameters are the same as wfMessage()
getContext()
Get the base IContextSource object.
setContext(IContextSource $context)
An IContextSource implementation which will inherit context from another source but allow individual ...
Implements some public methods and some protected utility functions which are required by multiple ch...
Foreign file accessible through api.php requests.
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
see documentation in includes Linker php for Linker::makeImageLink & $time
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message key
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "<div ...>$1</div>"). - flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException':Called before an exception(or PHP error) is logged. This is meant for integration with external error aggregation services
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Allows to change the fields on the form that will be generated $name
returning false will NOT prevent logging $e
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
if(!isset( $args[0])) $lang