diff options
Diffstat (limited to 'includes/api/ApiParse.php')
-rw-r--r-- | includes/api/ApiParse.php | 445 |
1 files changed, 336 insertions, 109 deletions
diff --git a/includes/api/ApiParse.php b/includes/api/ApiParse.php index db389bdb..2d12c233 100644 --- a/includes/api/ApiParse.php +++ b/includes/api/ApiParse.php @@ -1,11 +1,10 @@ <?php - -/* - * Created on Dec 01, 2007 - * +/** * API for MediaWiki 1.8+ * - * Copyright (C) 2007 Yuri Astrakhan <Firstname><Lastname>@gmail.com + * Created on Dec 01, 2007 + * + * Copyright © 2007 Yuri Astrakhan <Firstname><Lastname>@gmail.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,13 +18,15 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html + * + * @file */ if ( !defined( 'MEDIAWIKI' ) ) { // Eclipse helper - will be ignored in production - require_once ( "ApiBase.php" ); + require_once( "ApiBase.php" ); } /** @@ -33,8 +34,10 @@ if ( !defined( 'MEDIAWIKI' ) ) { */ class ApiParse extends ApiBase { + private $section, $text, $pstText = null; + public function __construct( $main, $action ) { - parent :: __construct( $main, $action ); + parent::__construct( $main, $action ); } public function execute() { @@ -46,141 +49,238 @@ class ApiParse extends ApiBase { $text = $params['text']; $title = $params['title']; $page = $params['page']; + $pageid = $params['pageid']; $oldid = $params['oldid']; - if ( !is_null( $page ) && ( !is_null( $text ) || $title != "API" ) ) - $this->dieUsage( "The page parameter cannot be used together with the text and title parameters", 'params' ); + + if ( !is_null( $page ) && ( !is_null( $text ) || $title != 'API' ) ) { + $this->dieUsage( 'The page parameter cannot be used together with the text and title parameters', 'params' ); + } $prop = array_flip( $params['prop'] ); - $revid = false; + + if ( isset( $params['section'] ) ) { + $this->section = $params['section']; + } else { + $this->section = false; + } // The parser needs $wgTitle to be set, apparently the // $title parameter in Parser::parse isn't enough *sigh* - global $wgParser, $wgUser, $wgTitle, $wgEnableParserCache; + global $wgParser, $wgUser, $wgTitle, $wgLang; + + // Currently unnecessary, code to act as a safeguard against any change in current behaviour of uselang breaks + $oldLang = null; + if ( isset( $params['uselang'] ) && $params['uselang'] != $wgLang->getCode() ) { + $oldLang = $wgLang; // Backup wgLang + $wgLang = Language::factory( $params['uselang'] ); + } + $popts = new ParserOptions(); $popts->setTidy( true ); - $popts->enableLimitReport(); + $popts->enableLimitReport( !$params['disablepp'] ); + $redirValues = null; - if ( !is_null( $oldid ) || !is_null( $page ) ) - { - if ( !is_null( $oldid ) ) - { + + if ( !is_null( $oldid ) || !is_null( $pageid ) || !is_null( $page ) ) { + + if ( !is_null( $oldid ) ) { // Don't use the parser cache $rev = Revision::newFromID( $oldid ); - if ( !$rev ) + if ( !$rev ) { $this->dieUsage( "There is no revision ID $oldid", 'missingrev' ); - if ( !$rev->userCan( Revision::DELETED_TEXT ) ) + } + if ( !$rev->userCan( Revision::DELETED_TEXT ) ) { $this->dieUsage( "You don't have permission to view deleted revisions", 'permissiondenied' ); + } - $text = $rev->getText( Revision::FOR_THIS_USER ); $titleObj = $rev->getTitle(); + $wgTitle = $titleObj; - $p_result = $wgParser->parse( $text, $titleObj, $popts ); - } - else - { - if ( $params['redirects'] ) - { - $req = new FauxRequest( array( - 'action' => 'query', - 'redirects' => '', - 'titles' => $page - ) ); - $main = new ApiMain( $req ); - $main->execute(); - $data = $main->getResultData(); - $redirValues = @$data['query']['redirects']; - $to = $page; - foreach ( (array)$redirValues as $r ) - $to = $r['to']; + + //If for some reason the "oldid" is actually the current revision, it may be cached + if ( $titleObj->getLatestRevID() === $oldid ) { + $articleObj = new Article( $titleObj, 0 ); + + $p_result = $this->getParsedSectionOrText( $articleObj, $titleObj, $popts, $pageid, + isset( $prop['wikitext'] ) ) ; + + } else { // This is an old revision, so get the text differently + $this->text = $rev->getText( Revision::FOR_THIS_USER ); + + $wgTitle = $titleObj; + + if ( $this->section !== false ) { + $this->text = $this->getSectionText( $this->text, 'r' . $rev->getId() ); + } + + $p_result = $wgParser->parse( $this->text, $titleObj, $popts ); } - else - $to = $page; - $titleObj = Title::newFromText( $to ); - if ( !$titleObj ) - $this->dieUsage( "The page you specified doesn't exist", 'missingtitle' ); - - $articleObj = new Article( $titleObj ); - if ( isset( $prop['revid'] ) ) + + } else { // Not $oldid + + if ( !is_null ( $pageid ) ) { + $titleObj = Title::newFromID( $pageid ); + + if ( !$titleObj ) { + $this->dieUsageMsg( array( 'nosuchpageid', $pageid ) ); + } + } else { // $page + + if ( $params['redirects'] ) { + $req = new FauxRequest( array( + 'action' => 'query', + 'redirects' => '', + 'titles' => $page + ) ); + $main = new ApiMain( $req ); + $main->execute(); + $data = $main->getResultData(); + $redirValues = @$data['query']['redirects']; + $to = $page; + foreach ( (array)$redirValues as $r ) { + $to = $r['to']; + } + } else { + $to = $page; + } + $titleObj = Title::newFromText( $to ); + if ( !$titleObj || !$titleObj->exists() ) { + $this->dieUsage( "The page you specified doesn't exist", 'missingtitle' ); + } + } + $wgTitle = $titleObj; + + $articleObj = new Article( $titleObj, 0 ); + if ( isset( $prop['revid'] ) ) { $oldid = $articleObj->getRevIdFetched(); - // Try the parser cache first - $p_result = false; - $pcache = ParserCache::singleton(); - if ( $wgEnableParserCache ) - $p_result = $pcache->get( $articleObj, $wgUser ); - if ( !$p_result ) - { - $p_result = $wgParser->parse( $articleObj->getContent(), $titleObj, $popts ); - - if ( $wgEnableParserCache ) - $pcache->save( $p_result, $articleObj, $popts ); } + + $p_result = $this->getParsedSectionOrText( $articleObj, $titleObj, $popts, $pageid, + isset( $prop['wikitext'] ) ) ; } - } - else - { + + } else { // Not $oldid, $pageid, $page. Hence based on $text + + $this->text = $text; $titleObj = Title::newFromText( $title ); - if ( !$titleObj ) - $titleObj = Title::newFromText( "API" ); + if ( !$titleObj ) { + $titleObj = Title::newFromText( 'API' ); + } $wgTitle = $titleObj; - if ( $params['pst'] || $params['onlypst'] ) - $text = $wgParser->preSaveTransform( $text, $titleObj, $wgUser, $popts ); - if ( $params['onlypst'] ) - { + + if ( $this->section !== false ) { + $this->text = $this->getSectionText( $this->text, $titleObj->getText() ); + } + + if ( $params['pst'] || $params['onlypst'] ) { + $this->pstText = $wgParser->preSaveTransform( $this->text, $titleObj, $wgUser, $popts ); + } + if ( $params['onlypst'] ) { // Build a result and bail out $result_array['text'] = array(); - $this->getResult()->setContent( $result_array['text'], $text ); + $this->getResult()->setContent( $result_array['text'], $this->pstText ); + if ( isset( $prop['wikitext'] ) ) { + $result_array['wikitext'] = array(); + $this->getResult()->setContent( $result_array['wikitext'], $this->text ); + } $this->getResult()->addValue( null, $this->getModuleName(), $result_array ); return; } - $p_result = $wgParser->parse( $text, $titleObj, $popts ); + $p_result = $wgParser->parse( $params['pst'] ? $this->pstText : $this->text, $titleObj, $popts ); } // Return result $result = $this->getResult(); $result_array = array(); - if ( $params['redirects'] && !is_null( $redirValues ) ) + if ( $params['redirects'] && !is_null( $redirValues ) ) { $result_array['redirects'] = $redirValues; - + } + if ( isset( $prop['text'] ) ) { $result_array['text'] = array(); $result->setContent( $result_array['text'], $p_result->getText() ); } - + if ( !is_null( $params['summary'] ) ) { $result_array['parsedsummary'] = array(); $result->setContent( $result_array['parsedsummary'], $wgUser->getSkin()->formatComment( $params['summary'], $titleObj ) ); } - - if ( isset( $prop['langlinks'] ) ) + + if ( isset( $prop['langlinks'] ) ) { $result_array['langlinks'] = $this->formatLangLinks( $p_result->getLanguageLinks() ); - if ( isset( $prop['categories'] ) ) + } + if ( isset( $prop['languageshtml'] ) ) { + $languagesHtml = $this->languagesHtml( $p_result->getLanguageLinks() ); + $result_array['languageshtml'] = array(); + $result->setContent( $result_array['languageshtml'], $languagesHtml ); + } + if ( isset( $prop['categories'] ) ) { $result_array['categories'] = $this->formatCategoryLinks( $p_result->getCategories() ); - if ( isset( $prop['links'] ) ) + } + if ( isset( $prop['categorieshtml'] ) ) { + $categoriesHtml = $this->categoriesHtml( $p_result->getCategories() ); + $result_array['categorieshtml'] = array(); + $result->setContent( $result_array['categorieshtml'], $categoriesHtml ); + } + if ( isset( $prop['links'] ) ) { $result_array['links'] = $this->formatLinks( $p_result->getLinks() ); - if ( isset( $prop['templates'] ) ) + } + if ( isset( $prop['templates'] ) ) { $result_array['templates'] = $this->formatLinks( $p_result->getTemplates() ); - if ( isset( $prop['images'] ) ) + } + if ( isset( $prop['images'] ) ) { $result_array['images'] = array_keys( $p_result->getImages() ); - if ( isset( $prop['externallinks'] ) ) + } + if ( isset( $prop['externallinks'] ) ) { $result_array['externallinks'] = array_keys( $p_result->getExternalLinks() ); - if ( isset( $prop['sections'] ) ) + } + if ( isset( $prop['sections'] ) ) { $result_array['sections'] = $p_result->getSections(); - if ( isset( $prop['displaytitle'] ) ) + } + + if ( isset( $prop['displaytitle'] ) ) { $result_array['displaytitle'] = $p_result->getDisplayTitle() ? $p_result->getDisplayTitle() : $titleObj->getPrefixedText(); - - if ( isset( $prop['headitems'] ) ) - $result_array['headitems'] = $this->formatHeadItems( $p_result->getHeadItems() ); - - if ( isset( $prop['headhtml'] ) ) { + } + + if ( isset( $prop['headitems'] ) || isset( $prop['headhtml'] ) ) { $out = new OutputPage; $out->addParserOutputNoText( $p_result ); + $userSkin = $wgUser->getSkin(); + } + + if ( isset( $prop['headitems'] ) ) { + $headItems = $this->formatHeadItems( $p_result->getHeadItems() ); + + $userSkin->setupUserCss( $out ); + $css = $this->formatCss( $out->buildCssLinksArray() ); + + $scripts = array( $out->getHeadScripts( $userSkin ) ); + + $result_array['headitems'] = array_merge( $headItems, $css, $scripts ); + } + + if ( isset( $prop['headhtml'] ) ) { $result_array['headhtml'] = array(); - $result->setContent( $result_array['headhtml'], $out->headElement( $wgUser->getSkin() ) ); + $result->setContent( $result_array['headhtml'], $out->headElement( $userSkin ) ); + } + + if ( isset( $prop['iwlinks'] ) ) { + $result_array['iwlinks'] = $this->formatIWLinks( $p_result->getInterwikiLinks() ); } - if ( !is_null( $oldid ) ) + if ( isset( $prop['wikitext'] ) ) { + $result_array['wikitext'] = array(); + $result->setContent( $result_array['wikitext'], $this->text ); + if ( !is_null( $this->pstText ) ) { + $result_array['psttext'] = array(); + $result->setContent( $result_array['psttext'], $this->pstText ); + } + } + + if ( !is_null( $oldid ) ) { $result_array['revid'] = intval( $oldid ); + } $result_mapping = array( 'redirects' => 'r', @@ -190,11 +290,54 @@ class ApiParse extends ApiBase { 'templates' => 'tl', 'images' => 'img', 'externallinks' => 'el', + 'iwlinks' => 'iw', 'sections' => 's', - 'headitems' => 'hi' + 'headitems' => 'hi', ); $this->setIndexedTagNames( $result_array, $result_mapping ); $result->addValue( null, $this->getModuleName(), $result_array ); + + if ( !is_null( $oldLang ) ) { + $wgLang = $oldLang; // Reset $wgLang to $oldLang + } + } + + /** + * @param $articleObj Article + * @param $titleObj Title + * @param $popts ParserOptions + * @param $pageId Int + * @param $getWikitext Bool + * @return ParserOutput + */ + private function getParsedSectionOrText( $articleObj, $titleObj, $popts, $pageId = null, $getWikitext = false ) { + if ( $this->section !== false ) { + global $wgParser; + + $this->text = $this->getSectionText( $articleObj->getRawText(), !is_null ( $pageId ) + ? 'page id ' . $pageId : $titleObj->getText() ); + + return $wgParser->parse( $this->text, $titleObj, $popts ); + } else { + // Try the parser cache first + $pout = $articleObj->getParserOutput(); + if ( $getWikitext ) { + $rev = Revision::newFromTitle( $titleObj ); + if ( $rev ) { + $this->text = $rev->getText(); + } + } + return $pout; + } + } + + private function getSectionText( $text, $what ) { + global $wgParser; + $text = $wgParser->getSection( $text, $this->section, false ); + if ( $text === false ) { + $this->dieUsage( "There is no section {$this->section} in " . $what, 'nosuchsection' ); + } + return $text; } private function formatLangLinks( $links ) { @@ -202,7 +345,12 @@ class ApiParse extends ApiBase { foreach ( $links as $link ) { $entry = array(); $bits = explode( ':', $link, 2 ); + $title = Title::newFromText( $link ); + $entry['lang'] = $bits[0]; + if ( $title ) { + $entry['url'] = $title->getFullURL(); + } $this->getResult()->setContent( $entry, $bits[1] ); $result[] = $entry; } @@ -220,6 +368,20 @@ class ApiParse extends ApiBase { return $result; } + private function categoriesHtml( $categories ) { + global $wgOut, $wgUser; + $wgOut->addCategoryLinks( $categories ); + $sk = $wgUser->getSkin(); + return $sk->getCategories(); + } + + private function languagesHtml( $languages ) { + global $wgOut, $wgUser; + $wgOut->setLanguageLinks( $languages ); + $sk = $wgUser->getSkin(); + return $sk->otherLanguages(); + } + private function formatLinks( $links ) { $result = array(); foreach ( $links as $ns => $nslinks ) { @@ -227,8 +389,28 @@ class ApiParse extends ApiBase { $entry = array(); $entry['ns'] = $ns; $this->getResult()->setContent( $entry, Title::makeTitle( $ns, $title )->getFullText() ); - if ( $id != 0 ) + if ( $id != 0 ) { $entry['exists'] = ''; + } + $result[] = $entry; + } + } + return $result; + } + + private function formatIWLinks( $iw ) { + $result = array(); + foreach ( $iw as $prefix => $titles ) { + foreach ( array_keys( $titles ) as $title ) { + $entry = array(); + $entry['prefix'] = $prefix; + + $title = Title::newFromText( "{$prefix}:{$title}" ); + if ( $title ) { + $entry['url'] = $title->getFullURL(); + } + + $this->getResult()->setContent( $entry, $title->getFullText() ); $result[] = $entry; } } @@ -246,30 +428,45 @@ class ApiParse extends ApiBase { return $result; } + private function formatCss( $css ) { + $result = array(); + foreach ( $css as $file => $link ) { + $entry = array(); + $entry['file'] = $file; + $this->getResult()->setContent( $entry, $link ); + $result[] = $entry; + } + return $result; + } + private function setIndexedTagNames( &$array, $mapping ) { foreach ( $mapping as $key => $name ) { - if ( isset( $array[$key] ) ) + if ( isset( $array[$key] ) ) { $this->getResult()->setIndexedTagName( $array[$key], $name ); + } } } public function getAllowedParams() { - return array ( + return array( 'title' => array( - ApiBase :: PARAM_DFLT => 'API', + ApiBase::PARAM_DFLT => 'API', ), 'text' => null, 'summary' => null, 'page' => null, + 'pageid' => null, 'redirects' => false, 'oldid' => null, 'prop' => array( - ApiBase :: PARAM_DFLT => 'text|langlinks|categories|links|templates|images|externallinks|sections|revid|displaytitle', - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array( + ApiBase::PARAM_DFLT => 'text|langlinks|categories|links|templates|images|externallinks|sections|revid|displaytitle', + ApiBase::PARAM_ISMULTI => true, + ApiBase::PARAM_TYPE => array( 'text', 'langlinks', + 'languageshtml', 'categories', + 'categorieshtml', 'links', 'templates', 'images', @@ -278,54 +475,84 @@ class ApiParse extends ApiBase { 'revid', 'displaytitle', 'headitems', - 'headhtml' + 'headhtml', + 'iwlinks', + 'wikitext', ) ), 'pst' => false, 'onlypst' => false, + 'uselang' => null, + 'section' => null, + 'disablepp' => false, ); } public function getParamDescription() { - return array ( + $p = $this->getModulePrefix(); + return array( 'text' => 'Wikitext to parse', 'summary' => 'Summary to parse', - 'redirects' => 'If the page parameter is set to a redirect, resolve it', + 'redirects' => "If the {$p}page parameter is set to a redirect, resolve it", 'title' => 'Title of page the text belongs to', - 'page' => 'Parse the content of this page. Cannot be used together with text and title', - 'oldid' => 'Parse the content of this revision. Overrides page', - 'prop' => array( 'Which pieces of information to get.', - 'NOTE: Section tree is only generated if there are more than 4 sections, or if the __TOC__ keyword is present' + 'page' => "Parse the content of this page. Cannot be used together with {$p}text and {$p}title", + 'pageid' => "Parse the content of this page. Overrides {$p}page", + 'oldid' => "Parse the content of this revision. Overrides {$p}page and {$p}pageid", + 'prop' => array( + 'Which pieces of information to get', + ' text - Gives the parsed text of the wikitext', + ' langlinks - Gives the langlinks the parsed wikitext', + ' categories - Gives the categories of the parsed wikitext', + ' categorieshtml - Gives the html version of the categories', + ' languageshtml - Gives the html version of the languagelinks', + ' links - Gives the internal links in the parsed wikitext', + ' templates - Gives the templates in the parsed wikitext', + ' images - Gives the images in the parsed wikitext', + ' externallinks - Gives the external links in the parsed wikitext', + ' sections - Gives the sections in the parsed wikitext', + ' revid - Adds the revision id of the parsed page', + ' displaytitle - Adds the title of the parsed wikitext', + ' headitems - Gives items to put in the <head> of the page', + ' headhtml - Gives parsed <head> of the page', + ' iwlinks - Gives interwiki links in the parsed wikitext', + ' wikitext - Gives the original wikitext that was parsed', ), - 'pst' => array( 'Do a pre-save transform on the input before parsing it.', - 'Ignored if page or oldid is used.' + 'pst' => array( + 'Do a pre-save transform on the input before parsing it', + 'Ignored if page, pageid or oldid is used' ), - 'onlypst' => array( 'Do a PST on the input, but don\'t parse it.', - 'Returns PSTed wikitext. Ignored if page or oldid is used.' + 'onlypst' => array( + 'Do a pre-save transform (PST) on the input, but don\'t parse it', + 'Returns the same wikitext, after a PST has been applied. Ignored if page, pageid or oldid is used' ), + 'uselang' => 'Which language to parse the request in', + 'section' => 'Only retrieve the content of this section number', + 'disablepp' => 'Disable the PP Report from the parser output', ); } public function getDescription() { return 'This module parses wikitext and returns parser output'; } - + public function getPossibleErrors() { return array_merge( parent::getPossibleErrors(), array( array( 'code' => 'params', 'info' => 'The page parameter cannot be used together with the text and title parameters' ), array( 'code' => 'missingrev', 'info' => 'There is no revision ID oldid' ), array( 'code' => 'permissiondenied', 'info' => 'You don\'t have permission to view deleted revisions' ), array( 'code' => 'missingtitle', 'info' => 'The page you specified doesn\'t exist' ), + array( 'code' => 'nosuchsection', 'info' => 'There is no section sectionnumber in page' ), + array( 'nosuchpageid' ), ) ); } protected function getExamples() { - return array ( + return array( 'api.php?action=parse&text={{Project:Sandbox}}' ); } public function getVersion() { - return __CLASS__ . ': $Id: ApiParse.php 69932 2010-07-26 08:03:21Z tstarling $'; + return __CLASS__ . ': $Id: ApiParse.php 89672 2011-06-07 18:45:20Z catrope $'; } } |