24 use Psr\Log\LoggerAwareInterface;
25 use Psr\Log\LoggerInterface;
26 use Psr\Log\NullLogger;
118 const NS_RDF =
'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
119 const NS_XML =
'http://www.w3.org/XML/1998/namespace';
139 if ( !function_exists(
'xml_parser_create_ns' ) ) {
141 throw new RuntimeException(
'XMP support requires XML Parser' );
166 if ( $this->xmlParser ) {
167 xml_parser_free( $this->xmlParser );
168 $this->xmlParser = null;
180 $this->xmlParser = xml_parser_create_ns(
'UTF-8',
' ' );
181 xml_parser_set_option( $this->xmlParser, XML_OPTION_CASE_FOLDING, 0 );
182 xml_parser_set_option( $this->xmlParser, XML_OPTION_SKIP_WHITE, 1 );
184 xml_set_element_handler( $this->xmlParser,
185 [ $this,
'startElement' ],
186 [ $this,
'endElement' ] );
188 xml_set_character_data_handler( $this->xmlParser, [ $this,
'char' ] );
190 $this->parsable = self::PARSABLE_UNKNOWN;
191 $this->xmlParsableBuffer =
'';
198 return function_exists(
'xml_parser_create_ns' ) && class_exists(
'XMLReader' );
218 if ( isset( $data[
'xmp-special'][
'AuthorsPosition'] )
219 && is_string( $data[
'xmp-special'][
'AuthorsPosition'] )
220 && isset( $data[
'xmp-general'][
'Artist'][0] )
227 $data[
'xmp-general'][
'Artist'][0] =
228 $data[
'xmp-special'][
'AuthorsPosition'] .
', '
229 . $data[
'xmp-general'][
'Artist'][0];
236 if ( isset( $data[
'xmp-special'][
'LocationShown'][0] )
237 && is_array( $data[
'xmp-special'][
'LocationShown'][0] )
241 foreach ( $data[
'xmp-special'][
'LocationShown']
as $loc ) {
242 if ( !is_array( $loc ) ) {
246 foreach ( $loc
as $field => $val ) {
247 $data[
'xmp-general'][$field .
'Dest'][] = $val;
251 if ( isset( $data[
'xmp-special'][
'LocationCreated'][0] )
252 && is_array( $data[
'xmp-special'][
'LocationCreated'][0] )
256 foreach ( $data[
'xmp-special'][
'LocationCreated']
as $loc ) {
257 if ( !is_array( $loc ) ) {
261 foreach ( $loc
as $field => $val ) {
262 $data[
'xmp-general'][$field .
'Created'][] = $val;
269 unset( $data[
'xmp-special'] );
272 if ( isset( $data[
'xmp-exif'][
'GPSAltitudeRef'] )
273 && isset( $data[
'xmp-exif'][
'GPSAltitude'] )
278 list( $nom, $denom ) = explode(
'/', $data[
'xmp-exif'][
'GPSAltitude'] );
279 $data[
'xmp-exif'][
'GPSAltitude'] = $nom / $denom;
281 if ( $data[
'xmp-exif'][
'GPSAltitudeRef'] ==
'1' ) {
282 $data[
'xmp-exif'][
'GPSAltitude'] *= -1;
284 unset( $data[
'xmp-exif'][
'GPSAltitudeRef'] );
303 if ( !$this->xmlParser ) {
310 if ( !$this->charset ) {
312 if ( preg_match(
'/\xEF\xBB\xBF|\xFE\xFF|\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\xFF\xFE/',
317 $this->charset =
'UTF-16BE';
320 $this->charset =
'UTF-16LE';
322 case "\x00\x00\xFE\xFF":
323 $this->charset =
'UTF-32BE';
325 case "\xFF\xFE\x00\x00":
326 $this->charset =
'UTF-32LE';
329 $this->charset =
'UTF-8';
333 throw new RuntimeException(
"Invalid BOM" );
337 $this->charset =
'UTF-8';
340 if ( $this->charset !==
'UTF-8' ) {
342 MediaWiki\suppressWarnings();
344 MediaWiki\restoreWarnings();
349 if ( $this->parsable !== self::PARSABLE_OK ) {
350 if ( $this->parsable === self::PARSABLE_NO ) {
351 throw new RuntimeException(
'Unsafe doctype declaration in XML.' );
356 if ( !$allOfIt && $this->parsable !== self::PARSABLE_NO ) {
361 $msg = ( $this->parsable === self::PARSABLE_NO ) ?
362 'Unsafe doctype declaration in XML.' :
363 'No root element found in XML.';
364 throw new RuntimeException( $msg );
368 $ok = xml_parse( $this->xmlParser,
$content, $allOfIt );
370 $code = xml_get_error_code( $this->xmlParser );
371 $error = xml_error_string(
$code );
372 $line = xml_get_current_line_number( $this->xmlParser );
373 $col = xml_get_current_column_number( $this->xmlParser );
374 $offset = xml_get_current_byte_index( $this->xmlParser );
376 $this->logger->warning(
377 '{method} : Error reading XMP content: {error} ' .
378 '(line: {line} column: {column} byte offset: {offset})',
380 'method' => __METHOD__,
381 'error_code' =>
$code,
392 }
catch ( Exception
$e ) {
393 $this->logger->warning(
394 '{method} Exception caught while parsing: ' . $e->getMessage(),
396 'method' => __METHOD__,
422 if ( !isset( $this->results[
'xmp-special'][
'HasExtendedXMP'] )
423 || $this->results[
'xmp-special'][
'HasExtendedXMP'] !== $guid
425 $this->logger->info( __METHOD__ .
426 " Ignoring XMPExtended block due to wrong guid (guid= '$guid')" );
430 $len = unpack(
'Nlength/Noffset', substr(
$content, 32, 8 ) );
433 $len[
'length'] < 4 ||
434 $len[
'offset'] < 0 ||
435 $len[
'offset'] > $len[
'length']
438 __METHOD__ .
'Error reading extended XMP block, invalid length or offset.'
454 if ( $len[
'offset'] !== $this->extendedXMPOffset ) {
455 $this->logger->info( __METHOD__ .
'Ignoring XMPExtended block due to wrong order. (Offset was '
456 . $len[
'offset'] .
' but expected ' . $this->extendedXMPOffset .
')' );
461 if ( $len[
'offset'] === 0 ) {
467 $this->extendedXMPOffset += $len[
'length'];
469 $actualContent = substr(
$content, 40 );
471 if ( $this->extendedXMPOffset === strlen( $actualContent ) ) {
477 $this->logger->debug( __METHOD__ .
'Parsing a XMPExtended block' );
479 return $this->
parse( $actualContent, $atEnd );
500 $data = trim( $data );
501 if ( trim( $data ) ===
"" ) {
505 if ( !isset( $this->mode[0] ) ) {
506 throw new RuntimeException(
'Unexpected character data before first rdf:Description element' );
509 if ( $this->mode[0] === self::MODE_IGNORE ) {
513 if ( $this->mode[0] !== self::MODE_SIMPLE
514 && $this->mode[0] !== self::MODE_QDESC
516 throw new RuntimeException(
'character data where not expected. (mode ' . $this->mode[0] .
')' );
520 if ( $this->charContent ===
false ) {
521 $this->charContent = $data;
523 $this->charContent .= $data;
536 $reader =
new XMLReader();
542 'data://text/plain,' . urlencode(
$content ),
544 LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_NONET
547 $oldDisable = libxml_disable_entity_loader(
true );
550 'libxml_disable_entity_loader',
553 $reader->setParserProperty( XMLReader::SUBST_ENTITIES,
false );
557 MediaWiki\suppressWarnings();
558 while ( $reader->read() ) {
559 if ( $reader->nodeType === XMLReader::ELEMENT ) {
561 $this->parsable = self::PARSABLE_OK;
565 if ( $reader->nodeType === XMLReader::DOC_TYPE ) {
566 $this->parsable = self::PARSABLE_NO;
571 MediaWiki\restoreWarnings();
579 $this->parsable = self::PARSABLE_BUFFERING;
580 $this->xmlParsableBuffer =
$content;
591 if ( $this->curItem[0] === $elm ) {
592 array_shift( $this->curItem );
593 array_shift( $this->mode );
613 if ( $this->charContent !==
false ) {
614 if ( $this->processingArray ) {
617 list( $ns,
$tag ) = explode(
' ', $this->curItem[0], 2 );
619 list( $ns,
$tag ) = explode(
' ', $elm, 2 );
623 $this->charContent =
false;
625 array_shift( $this->curItem );
626 array_shift( $this->mode );
651 if ( $this->curItem[0] !== $elm
652 && !( $elm === self::NS_RDF .
' Description'
653 && $this->mode[0] === self::MODE_STRUCT )
655 throw new RuntimeException(
"nesting mismatch. got a </$elm> but expected a </" .
656 $this->curItem[0] .
'>' );
660 list( $ns,
$tag ) = explode(
' ', $elm, 2 );
661 if ( isset( $this->items[$ns][
$tag][
'validate'] ) ) {
662 $info =& $this->items[$ns][
$tag];
663 $finalName = isset( $info[
'map_name'] )
664 ? $info[
'map_name'] :
$tag;
666 if ( is_array( $info[
'validate'] ) ) {
667 $validate = $info[
'validate'];
670 $validate = [ $validator, $info[
'validate'] ];
673 if ( !isset( $this->results[
'xmp-' . $info[
'map_group']][$finalName] ) ) {
675 $this->logger->debug( __METHOD__ .
" <$ns:$tag> has no valid members." );
676 } elseif ( is_callable( $validate ) ) {
677 $val =& $this->results[
'xmp-' . $info[
'map_group']][$finalName];
678 call_user_func_array( $validate, [ $info, &$val,
false ] );
679 if ( is_null( $val ) ) {
682 $this->logger->info( __METHOD__ .
" <$ns:$tag> failed validation." );
683 unset( $this->results[
'xmp-' . $info[
'map_group']][$finalName] );
686 $this->logger->warning( __METHOD__ .
" Validation function for $finalName ("
687 . $validate[0] .
'::' . $validate[1] .
'()) is not callable.' );
691 array_shift( $this->curItem );
692 array_shift( $this->mode );
693 $this->ancestorStruct =
false;
694 $this->processingArray =
false;
695 $this->itemLang =
false;
718 list( $ns,
$tag ) = explode(
' ', $this->curItem[0], 2 );
719 $info = $this->items[$ns][
$tag];
720 $finalName = isset( $info[
'map_name'] )
721 ? $info[
'map_name'] :
$tag;
723 array_shift( $this->mode );
725 if ( !isset( $this->results[
'xmp-' . $info[
'map_group']][$finalName] ) ) {
726 $this->logger->debug( __METHOD__ .
" Empty compund element $finalName." );
731 if ( $elm === self::NS_RDF .
' Seq' ) {
732 $this->results[
'xmp-' . $info[
'map_group']][$finalName][
'_type'] =
'ol';
733 } elseif ( $elm === self::NS_RDF .
' Bag' ) {
734 $this->results[
'xmp-' . $info[
'map_group']][$finalName][
'_type'] =
'ul';
735 } elseif ( $elm === self::NS_RDF .
' Alt' ) {
737 if ( $info[
'mode'] === self::MODE_LANG ) {
738 $this->results[
'xmp-' . $info[
'map_group']][$finalName][
'_type'] =
'lang';
741 throw new RuntimeException(
742 __METHOD__ .
" expected </rdf:seq> or </rdf:bag> but instead got $elm."
759 if ( $elm === self::NS_RDF .
' value' ) {
760 list( $ns,
$tag ) = explode(
' ', $this->curItem[0], 2 );
765 array_shift( $this->mode );
766 array_shift( $this->curItem );
784 if ( $elm === ( self::NS_RDF .
' RDF' )
785 || $elm ===
'adobe:ns:meta/ xmpmeta'
786 || $elm ===
'adobe:ns:meta/ xapmeta'
792 if ( $elm === self::NS_RDF .
' type' ) {
795 $this->logger->info( __METHOD__ .
' encountered <rdf:type>' );
798 if ( strpos( $elm,
' ' ) ===
false ) {
803 $this->logger->info( __METHOD__ .
" Encountered </$elm> which has no namespace. Skipping." );
808 if ( count( $this->mode[0] ) === 0 ) {
811 throw new RuntimeException(
'Encountered end element with no mode' );
814 if ( count( $this->curItem ) == 0 && $this->mode[0] !== self::MODE_INITIAL ) {
817 throw new RuntimeException(
"Hit end element </$elm> but no curItem" );
820 switch ( $this->mode[0] ) {
821 case self::MODE_IGNORE:
824 case self::MODE_SIMPLE:
827 case self::MODE_STRUCT:
830 case self::MODE_LANG:
831 case self::MODE_BAGSTRUCT:
834 case self::MODE_INITIAL:
835 if ( $elm === self::NS_RDF .
' Description' ) {
836 array_shift( $this->mode );
838 throw new RuntimeException(
'Element ended unexpectedly while in MODE_INITIAL' );
842 case self::MODE_LI_LANG:
845 case self::MODE_QDESC:
849 $this->logger->warning( __METHOD__ .
" no mode (elm = $elm)" );
866 if ( $elm === $this->curItem[0] ) {
867 array_unshift( $this->curItem, $elm );
868 array_unshift( $this->mode, self::MODE_IGNORE );
880 if ( $elm === self::NS_RDF .
' Bag' ) {
881 array_unshift( $this->mode, self::MODE_LI );
883 throw new RuntimeException(
"Expected <rdf:Bag> but got $elm." );
895 if ( $elm === self::NS_RDF .
' Seq' ) {
896 array_unshift( $this->mode, self::MODE_LI );
897 } elseif ( $elm === self::NS_RDF .
' Bag' ) {
899 $this->logger->info( __METHOD__ .
' Expected an rdf:Seq, but got an rdf:Bag. Pretending'
900 .
' it is a Seq, since some buggy software is known to screw this up.' );
901 array_unshift( $this->mode, self::MODE_LI );
903 throw new RuntimeException(
"Expected <rdf:Seq> but got $elm." );
922 if ( $elm === self::NS_RDF .
' Alt' ) {
923 array_unshift( $this->mode, self::MODE_LI_LANG );
925 throw new RuntimeException(
"Expected <rdf:Seq> but got $elm." );
948 if ( $elm === self::NS_RDF .
' Description' ) {
950 array_unshift( $this->mode, self::MODE_QDESC );
951 array_unshift( $this->curItem, $this->curItem[0] );
953 if ( isset(
$attribs[self::NS_RDF .
' value'] ) ) {
954 list( $ns,
$tag ) = explode(
' ', $this->curItem[0], 2 );
957 } elseif ( $elm === self::NS_RDF .
' value' ) {
959 throw new RuntimeException( __METHOD__ .
' Encountered <rdf:value> where it was unexpected.' );
962 $this->logger->info( __METHOD__ .
963 " Encountered element <$elm> where only expecting character data as value of " .
965 array_unshift( $this->mode, self::MODE_IGNORE );
966 array_unshift( $this->curItem, $elm );
985 if ( $elm === self::NS_RDF .
' value' ) {
989 array_unshift( $this->mode, self::MODE_IGNORE );
990 array_unshift( $this->curItem, $elm );
1007 if ( $ns !== self::NS_RDF ) {
1009 if ( isset( $this->items[$ns][
$tag] ) ) {
1010 if ( isset( $this->items[$ns][$tag][
'structPart'] ) ) {
1016 $this->logger->warning(
"Encountered <$ns:$tag> outside"
1017 .
" of its expected parent. Ignoring." );
1019 array_unshift( $this->mode, self::MODE_IGNORE );
1020 array_unshift( $this->curItem, $ns .
' ' . $tag );
1024 $mode = $this->items[$ns][
$tag][
'mode'];
1025 array_unshift( $this->mode,
$mode );
1026 array_unshift( $this->curItem, $ns .
' ' . $tag );
1027 if (
$mode === self::MODE_STRUCT ) {
1028 $this->ancestorStruct = isset( $this->items[$ns][$tag][
'map_name'] )
1029 ? $this->items[$ns][
$tag][
'map_name'] :
$tag;
1031 if ( $this->charContent !==
false ) {
1034 throw new RuntimeException(
'tag nested in non-whitespace characters.' );
1038 $this->logger->debug( __METHOD__ .
" Ignoring unrecognized element <$ns:$tag>." );
1039 array_unshift( $this->mode, self::MODE_IGNORE );
1040 array_unshift( $this->curItem, $ns .
' ' . $tag );
1069 if ( $ns !== self::NS_RDF ) {
1071 if ( isset( $this->items[$ns][
$tag] ) ) {
1072 if ( isset( $this->items[$ns][$this->ancestorStruct][
'children'] )
1073 && !isset( $this->items[$ns][$this->ancestorStruct][
'children'][$tag] )
1077 throw new RuntimeException(
" <$tag> appeared nested in <" . $this->ancestorStruct
1078 .
"> where it is not allowed." );
1080 array_unshift( $this->mode, $this->items[$ns][$tag][
'mode'] );
1081 array_unshift( $this->curItem, $ns .
' ' . $tag );
1082 if ( $this->charContent !==
false ) {
1085 throw new RuntimeException(
"tag <$tag> nested in non-whitespace characters (" .
1086 $this->charContent .
")." );
1089 array_unshift( $this->mode, self::MODE_IGNORE );
1090 array_unshift( $this->curItem, $elm );
1096 if ( $ns === self::NS_RDF &&
$tag ===
'Description' ) {
1098 array_unshift( $this->mode, self::MODE_STRUCT );
1099 array_unshift( $this->curItem, $this->curItem[0] );
1117 if ( ( $elm ) !== self::NS_RDF .
' li' ) {
1118 throw new RuntimeException(
"<rdf:li> expected but got $elm." );
1121 if ( !isset( $this->mode[1] ) ) {
1124 throw new RuntimeException(
'In mode Li, but no 2xPrevious mode!' );
1127 if ( $this->mode[1] === self::MODE_BAGSTRUCT ) {
1129 array_unshift( $this->mode, self::MODE_STRUCT );
1130 array_unshift( $this->curItem, $elm );
1131 $this->processingArray =
true;
1133 if ( !isset( $this->curItem[1] ) ) {
1135 throw new RuntimeException(
'Can not find parent of BAGSTRUCT.' );
1137 list( $curNS, $curTag ) = explode(
' ', $this->curItem[1] );
1138 $this->ancestorStruct = isset( $this->items[$curNS][$curTag][
'map_name'] )
1139 ? $this->items[$curNS][$curTag][
'map_name'] : $curTag;
1144 array_unshift( $this->mode, self::MODE_SIMPLE );
1147 array_unshift( $this->curItem, $this->curItem[0] );
1148 $this->processingArray =
true;
1167 if ( $elm !== self::NS_RDF .
' li' ) {
1168 throw new RuntimeException( __METHOD__ .
" <rdf:li> expected but got $elm." );
1170 if ( !isset(
$attribs[self::NS_XML .
' lang'] )
1171 || !preg_match(
'/^[-A-Za-z0-9]{2,}$/D',
$attribs[self::NS_XML .
' lang'] )
1173 throw new RuntimeException( __METHOD__
1174 .
" <rdf:li> did not contain, or has invalid xml:lang attribute in lang alternative" );
1178 $this->itemLang = strtolower(
$attribs[self::NS_XML .
' lang'] );
1182 array_unshift( $this->curItem, $this->curItem[0] );
1183 array_unshift( $this->mode, self::MODE_SIMPLE );
1184 $this->processingArray =
true;
1199 if ( $elm === self::NS_RDF .
' RDF'
1200 || $elm ===
'adobe:ns:meta/ xmpmeta'
1201 || $elm ===
'adobe:ns:meta/ xapmeta'
1205 } elseif ( $elm === self::NS_RDF .
' Description' ) {
1206 if ( count( $this->mode ) === 0 ) {
1208 array_unshift( $this->mode, self::MODE_INITIAL );
1210 } elseif ( $elm === self::NS_RDF .
' type' ) {
1217 $this->logger->info( __METHOD__ .
' Encountered <rdf:type> which isn\'t currently supported' );
1220 if ( strpos( $elm,
' ' ) ===
false ) {
1222 $this->logger->info( __METHOD__ .
" Encountered <$elm> which has no namespace. Skipping." );
1227 list( $ns,
$tag ) = explode(
' ', $elm, 2 );
1229 if ( count( $this->mode ) === 0 ) {
1231 throw new RuntimeException(
'Error extracting XMP, '
1232 .
"encountered <$elm> with no mode" );
1235 switch ( $this->mode[0] ) {
1236 case self::MODE_IGNORE:
1239 case self::MODE_SIMPLE:
1242 case self::MODE_INITIAL:
1245 case self::MODE_STRUCT:
1248 case self::MODE_BAG:
1249 case self::MODE_BAGSTRUCT:
1252 case self::MODE_SEQ:
1255 case self::MODE_LANG:
1258 case self::MODE_LI_LANG:
1264 case self::MODE_QDESC:
1268 throw new RuntimeException(
'StartElement in unknown mode: ' . $this->mode[0] );
1293 if ( isset(
$attribs[self::NS_RDF .
' parseType'] )
1294 &&
$attribs[self::NS_RDF .
' parseType'] ===
'Resource'
1295 && $this->mode[0] === self::MODE_SIMPLE
1298 $this->mode[0] = self::MODE_QDESC;
1301 if ( strpos(
$name,
' ' ) ===
false ) {
1304 $this->logger->info( __METHOD__ .
' Encountered non-namespaced attribute: '
1305 .
" $name=\"$val\". Skipping. " );
1309 if ( $ns === self::NS_RDF ) {
1310 if (
$tag ===
'value' ||
$tag ===
'resource' ) {
1313 $this->
char( $this->xmlParser, $val );
1315 } elseif ( isset( $this->items[$ns][
$tag] ) ) {
1316 if ( $this->mode[0] === self::MODE_SIMPLE ) {
1317 throw new RuntimeException( __METHOD__
1318 .
" $ns:$tag found as attribute where not allowed" );
1322 $this->logger->debug( __METHOD__ .
" Ignoring unrecognized element <$ns:$tag>." );
1340 $info =& $this->items[$ns][
$tag];
1341 $finalName = isset( $info[
'map_name'] )
1342 ? $info[
'map_name'] :
$tag;
1343 if ( isset( $info[
'validate'] ) ) {
1344 if ( is_array( $info[
'validate'] ) ) {
1345 $validate = $info[
'validate'];
1348 $validate = [ $validator, $info[
'validate'] ];
1351 if ( is_callable( $validate ) ) {
1352 call_user_func_array( $validate, [ $info, &$val,
true ] );
1355 if ( is_null( $val ) ) {
1356 $this->logger->info( __METHOD__ .
" <$ns:$tag> failed validation." );
1361 $this->logger->warning( __METHOD__ .
" Validation function for $finalName ("
1362 . $validate[0] .
'::' . $validate[1] .
'()) is not callable.' );
1366 if ( $this->ancestorStruct && $this->processingArray ) {
1369 } elseif ( $this->ancestorStruct ) {
1371 } elseif ( $this->processingArray ) {
1372 if ( $this->itemLang ===
false ) {
1374 $this->results[
'xmp-' . $info[
'map_group']][$finalName][] = $val;
1377 $this->results[
'xmp-' . $info[
'map_group']][$finalName][
$this->itemLang] = $val;
1380 $this->results[
'xmp-' . $info[
'map_group']][$finalName] = $val;
doAttribs($attribs)
Process attributes.
startElementModeLi($elm, $attribs)
opening element in MODE_LI process elements of arrays.
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
startElement($parser, $elm, $attribs)
Hits an opening element.
checkParseSafety($content)
Check if a block of XML is safe to pass to xml_parse, i.e.
const MODE_INITIAL
These are various mode constants.
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException'returning false will NOT prevent logging $e
destroyXMLParser()
free the XML parser.
string $xmlParsableBuffer
Buffer of XML to parse.
parseExtended($content)
Entry point for XMPExtended blocks in jpeg files.
getResults()
Get the result array.
int $parsable
Flag determining if the XMP is safe to parse.
endElement($parser, $elm)
Handler for hitting a closing element.
char($parser, $data)
Character data handler Called whenever character data is found in the xmp document.
bool string $itemLang
Used for lang alts only.
bool string $ancestorStruct
The structure name when processing nested structures.
static getItems()
Get the items array.
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message.Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item.Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page.Return false to stop further processing of the tag $reader:XMLReader object &$pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision.Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag.Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload.Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports.&$fullInterwikiPrefix:Interwiki prefix, may contain colons.&$pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable.Can be used to lazy-load the import sources list.&$importSources:The value of $wgImportSources.Modify as necessary.See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page.$context:IContextSource object &$pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect.&$title:Title object for the current page &$request:WebRequest &$ignoreRedirect:boolean to skip redirect check &$target:Title/string of redirect target &$article:Article object 'InternalParseBeforeLinks':during Parser's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings.&$parser:Parser object &$text:string containing partially parsed text &$stripState:Parser's internal StripState object 'InternalParseBeforeSanitize':during Parser's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings.Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments.&$parser:Parser object &$text:string containing partially parsed text &$stripState:Parser's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not.Return true without providing an interwiki to continue interwiki search.$prefix:interwiki prefix we are looking for.&$iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user's email has been invalidated successfully.$user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification.Callee may modify $url and $query, URL will be constructed as $url.$query &$url:URL to index.php &$query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) &$article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() &$ip:IP being check &$result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from &$allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn't match your organization.$addr:The e-mail address entered by the user &$result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user &$result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we're looking for a messages file for &$file:The messages file path, you can override this to change the location. 'LanguageGetMagic':DEPRECATED!Use $magicWords in a file listed in $wgExtensionMessagesFiles instead.Use this to define synonyms of magic words depending of the language &$magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces.Do not use this hook to add namespaces.Use CanonicalNamespaces for that.&$namespaces:Array of namespaces indexed by their numbers 'LanguageGetSpecialPageAliases':DEPRECATED!Use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead.Use to define aliases of special pages names depending of the language &$specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names.&$names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page's language links.This is called in various places to allow extensions to define the effective language links for a page.$title:The page's Title.&$links:Associative array mapping language codes to prefixed links of the form"language:title".&$linkFlags:Associative array mapping prefixed links to arrays of flags.Currently unused, but planned to provide support for marking individual language links in the UI, e.g.for featured articles. 'LanguageSelector':Hook to change the language selector available on a page.$out:The output page.$cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED!Use HtmlPageLinkRendererBegin instead.Used when generating internal and interwiki links in Linker::link(), before processing starts.Return false to skip default processing and return $ret.See documentation for Linker::link() for details on the expected meanings of parameters.$skin:the Skin object $target:the Title that the link is pointing to &$html:the contents that the< a > tag should have(raw HTML) $result
endElementNested($elm)
Hit a closing element in MODE_STRUCT, MODE_SEQ, MODE_BAG generally means we've finished processing a ...
Class for asserting that a callback happens when an dummy object leaves scope.
array $results
Array to hold results.
static isSupported()
Check if this instance supports using this class.
endElementModeIgnore($elm)
When we hit a closing element in MODE_IGNORE Check to see if this is the element we started to ignore...
startElementModeBag($elm)
Start element in MODE_BAG (unordered array) this should always be <rdf:Bag>
startElementModeSeq($elm)
Start element in MODE_SEQ (ordered array) this should always be <rdf:Seq>
saveValue($ns, $tag, $val)
Given an extracted value, save it to results array.
bool string $charContent
Temporary holder for character data that appears in xmp doc.
startElementModeQDesc($elm)
Start an element when in MODE_QDESC.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books $tag
This contains some static methods for validating XMP properties.
endElementModeLi($elm)
Hit a closing element in MODE_LI (either rdf:Seq, or rdf:Bag ) Add information about what type of ele...
startElementModeLiLang($elm, $attribs)
Opening element in MODE_LI_LANG.
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Class for reading xmp data containing properties relevant to images, and spitting out an array that F...
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 modifiable & $code
array $curItem
Array to hold the current element (and previous element, and so on)
startElementModeIgnore($elm)
Hit an opening element while in MODE_IGNORE.
parse($content, $allOfIt=true)
Main function to call to parse XMP.
resetXMLParser()
Main use is if a single item has multiple xmp documents describing it.
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
bool string $charset
Character set like 'UTF-8'.
startElementModeInitial($ns, $tag, $attribs)
Starting an element when in MODE_INITIAL This usually happens when we hit an element inside the outer...
resource $xmlParser
A resource handle for the XML parser.
endElementModeSimple($elm)
Hit a closing element when in MODE_SIMPLE.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content $content
startElementModeStruct($ns, $tag, $attribs)
Hit an opening element when in a Struct (MODE_STRUCT) This is generally for fields of a compound prop...
setLogger(LoggerInterface $logger)
array $items
XMP item configuration array.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing & $attribs
startElementModeLang($elm)
Start element in MODE_LANG (language alternative) this should always be <rdf:Alt> ...
array $mode
Stores the state the xmpreader is in (see MODE_FOO constants)
__construct(LoggerInterface $logger=null)
Constructor.
endElementModeQDesc($elm)
End element while in MODE_QDESC mostly when ending an element when we have a simple value that has qu...
startElementModeSimple($elm, $attribs)
Handle an opening element when in MODE_SIMPLE.
bool $processingArray
If we're doing a seq or bag.
Allows to change the fields on the form that will be generated $name