From 22f8c4ce37f97e60191e7bc9f6d9668ade6c907a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 4 Apr 2004 21:58:05 +0000 Subject: [PATCH] Added code to implement Dublin Core and Creative Commons RDF metadata. If these features are turned on (with global flags), a metadata link tag is provided to the appropriate action ('dublincore' or 'creativecommons'). When the wiki script receives these actions, it creates RDF files on the fly. Also includes two valuable general functions: one to show an HTTP error (used when the flags are turned off), and one to do content negotiation (used to determine the MIME type for RDF files). A helper function is also added to page output to display metadata links. --- includes/DefaultSettings.php | 14 +++++- includes/GlobalFunctions.php | 97 ++++++++++++++++++++++++++++++++++++ includes/OutputPage.php | 6 +++ includes/Skin.php | 19 ++++++- index.php | 16 ++++++ languages/Language.php | 9 ++++ 6 files changed, 158 insertions(+), 3 deletions(-) diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index c0cc8a42c6..d731b011c2 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -292,5 +292,17 @@ if( !isset( $wgCommandLineMode ) ) { } # Show seconds in Recent Changes -$wgRCSeconds = false +$wgRCSeconds = false; + + +# RDF metadata toggles + +$wgEnableDublinCoreRdf = false; +$wgEnableCreativeCommonsRdf = false; + +# Override for copyright metadata. + +$wgRightsPage = NULL; +$wgRightsUrl = NULL; +$wgRightsText = NULL; ?> diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 81739bafef..e6a05527b4 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -845,4 +845,101 @@ function wfVarDump( $var ) } } +/* Provide a simple HTTP error. */ + +function wfHttpError($code, $label, $desc) { + + global $wgOut; + $wgOut->disable(); + header("HTTP/1.0 $code $label"); + header("Status: $code $label"); + $wgOut->sendCacheControl(); + + /* Don't send content if it's a HEAD request. */ + + if (strcmp($HTTP_SERVER_VARS['REQUEST_METHOD'],'HEAD') != 0) { + header("Content-type: text/plain"); + print "$desc\n"; + } +} + +# Converts an Accept-* header into an array mapping string values to quality factors + +function wfAcceptToPrefs($accept, $def = "*/*") { + # No arg means accept anything (per HTTP spec) + if (!$accept) { + return array($def => 1); + } + + $prefs = array(); + + $parts = explode(",", $accept); + + foreach ($parts as $part) { + #FIXME: doesn't deal with params like 'text/html; level=1' + list($value, $qpart) = explode(";", $part); + if (!isset($qpart)) { + $prefs[$value] = 1; + } else if (preg_match('/q\s*=\s*(\d*\.\d+)/', $qpart, $match)) { + $prefs[$value] = $match[1]; + } + } + + return $prefs; +} + +/* private */ function mimeTypeMatch($type, $avail) { + if (array_key_exists($type, $avail)) { + return $type; + } else { + $parts = explode('/', $type); + if (array_key_exists($parts[0] . '/*', $avail)) { + return $parts[0] . '/*'; + } else if (array_key_exists('*/*', $avail)) { + return '*/*'; + } else { + return NULL; + } + } +} + +#FIXME: doesn't handle params like 'text/plain; charset=UTF-8' +#XXX: generalize to negotiate other stuff + +function wfNegotiateType($cprefs, $sprefs) { + $combine = array(); + + foreach (array_keys($sprefs) as $type) { + $parts = explode('/', $type); + if ($parts[1] != '*') { + $ckey = mimeTypeMatch($type, $cprefs); + if ($ckey) { + $combine[$type] = $sprefs[$type] * $cprefs[$ckey]; + } + } + } + + foreach (array_keys($cprefs) as $type) { + $parts = explode('/', $type); + if ($parts[1] != '*' && !array_key_exists($type, $sprefs)) { + $skey = mimeTypeMatch($type, $sprefs); + if ($skey) { + $combine[$type] = $sprefs[$skey] * $cprefs[$type]; + } + } + } + + $bestq = 0; + $besttype = NULL; + + foreach (array_keys($combine) as $type) { + if ($combine[$type] > $bestq) { + $besttype = $type; + $bestq = $combine[$type]; + } + } + + return $besttype; +} + ?> diff --git a/includes/OutputPage.php b/includes/OutputPage.php index e4f79a1703..908205ae63 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -46,6 +46,12 @@ class OutputPage { function addKeyword( $text ) { array_push( $this->mKeywords, $text ); } function addLink( $rel, $rev, $target, $type="", $media="" ) { array_push( $this->mLinktags, array( $rel, $rev, $target, $type, $media ) ); } + function addMetadataLink( $type, $target ) { + static $haveMeta = false; + $this->addLink(($haveMeta) ? "alternate meta" : "meta", "", $target, $type); + $haveMeta = true; + } + # checkLastModified tells the client to use the client-cached page if # possible. If sucessful, the OutputPage is disabled so that # any future call to OutputPage->output() have no effect. The method diff --git a/includes/Skin.php b/includes/Skin.php index 6a416c864c..1002e41c5f 100644 --- a/includes/Skin.php +++ b/includes/Skin.php @@ -95,15 +95,30 @@ class Skin { function initPage( &$out ) { - global $wgStyleSheetPath; $fname = "Skin::initPage"; wfProfileIn( $fname ); $out->addLink( "shortcut icon", "", "/favicon.ico" ); - + + $this->addMetadataLinks($out); + wfProfileOut( $fname ); } + function addMetadataLinks( &$out ) { + global $wgTitle, $wgEnableDublinCoreRdf, $wgEnableCreativeCommonsRdf, $wgRdfMimeType, $action; + + if ($action == 'view') { + # note: buggy CC software only reads first "meta" link + if ($wgEnableCreativeCommonsRdf) { + $out->addMetadataLink('application/rdf+xml', wfLocalUrl($wgTitle->getPrefixedURL(), "action=creativecommons")); + } + if ($wgEnableDublinCoreRdf) { + $out->addMetadataLink('application/rdf+xml', wfLocalUrl($wgTitle->getPrefixedURL(), "action=dublincore")); + } + } + } + function outputPage( &$out ) { global $wgDebugComments; diff --git a/index.php b/index.php index a2f178267c..6906028279 100644 --- a/index.php +++ b/index.php @@ -108,6 +108,22 @@ if ( $search = $wgRequest->getText( 'search' ) ) { case "print": $wgArticle->view(); break; + case "dublincore": + if (!$wgEnableDublinCoreRdf) { + wfHttpError(403, "Forbidden", wfMsg("nodublincore")); + } else { + include_once("Metadata.php"); + wfDublinCoreRdf($wgArticle); + } + break; + case "creativecommons": + if (!$wgEnableCreativeCommonsRdf) { + wfHttpError(403, "Forbidden", wfMsg("nocreativecommons")); + } else { + include_once("Metadata.php"); + wfCreativeCommonsRdf($wgArticle); + } + break; case "edit": case "submit": if( !$wgCommandLineMode && !$wgRequest->checkSessionCookie() ) { diff --git a/languages/Language.php b/languages/Language.php index 52c812e328..69e8fbe88f 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -1548,6 +1548,15 @@ amusement.", 'tooltip-specialpages' => 'List of all special pages', 'tooltip-upload' => 'Upload images or media files [alt-u]', 'tooltip-specialpage' => 'This is a special page, you can\'t edit the page itself.', + +# Metadata +"nodublincore" => "Dublin Core RDF metadata disabled for this server.", +"nocreativecommons" => "Creative Commons RDF metadata disabled for this server.", +"notacceptable" => "The wiki server can't provide data in a format your client can read.", + +# Attribution + +"anonymous" => "Anonymous user(s) of $wgSitename" ); #-------------------------------------------------------------------------- -- 2.20.1