X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2FEditPage.php;h=bd58c81292c6d0e1f7c9ab4e7906d9361f69369b;hp=12966e53099610fb9b4e7eb45270995db8e99789;hb=a154a28c7a4442a7d08689036dc54688b0867a64;hpb=ecefa8f1082196cf27281bf9700b29798ad4364a diff --git a/includes/EditPage.php b/includes/EditPage.php index 12966e5309..bd58c81292 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -40,6 +40,11 @@ use Wikimedia\ScopedCallback; * headaches, which may be fatal. */ class EditPage { + /** + * Used for Unicode support checks + */ + const UNICODE_CHECK = 'ℳ𝒲♥𝓊𝓃𝒾𝒸ℴ𝒹ℯ'; + /** * Status: Article successfully updated */ @@ -177,6 +182,11 @@ class EditPage { */ const AS_CANNOT_USE_CUSTOM_MODEL = 241; + /** + * Status: edit rejected because browser doesn't support Unicode. + */ + const AS_UNICODE_NOT_SUPPORTED = 242; + /** * HTML id and name for the beginning of the edit form. */ @@ -203,12 +213,18 @@ class EditPage { */ const POST_EDIT_COOKIE_DURATION = 1200; - /** @var Article */ + /** + * @deprecated for public usage since 1.30 use EditPage::getArticle() + * @var Article + */ public $mArticle; /** @var WikiPage */ private $page; - /** @var Title */ + /** + * @deprecated for public usage since 1.30 use EditPage::getTitle() + * @var Title + */ public $mTitle; /** @var null|Title */ @@ -220,16 +236,28 @@ class EditPage { /** @var bool */ public $isConflict = false; - /** @var bool */ + /** + * @deprecated since 1.30 use Title::isCssJsSubpage() + * @var bool + */ public $isCssJsSubpage = false; - /** @var bool */ + /** + * @deprecated since 1.30 use Title::isCssSubpage() + * @var bool + */ public $isCssSubpage = false; - /** @var bool */ + /** + * @deprecated since 1.30 use Title::isJsSubpage() + * @var bool + */ public $isJsSubpage = false; - /** @var bool */ + /** + * @deprecated since 1.30 + * @var bool + */ public $isWrongCaseCssJsPage = false; /** @var bool New page or new section */ @@ -413,6 +441,11 @@ class EditPage { */ private $isOldRev = false; + /** + * @var string|null What the user submitted in the 'wpUnicodeCheck' field + */ + private $unicodeCheck; + /** * @param Article $article */ @@ -469,6 +502,10 @@ class EditPage { */ public function getContextTitle() { if ( is_null( $this->mContextTitle ) ) { + wfDebugLog( + 'GlobalTitleFail', + __METHOD__ . ' called by ' . wfGetAllCallers( 5 ) . ' with no title set.' + ); global $wgTitle; return $wgTitle; } else { @@ -527,7 +564,6 @@ class EditPage { * the newly-edited page. */ public function edit() { - global $wgRequest; // Allow extensions to modify/prevent this form or submission if ( !Hooks::run( 'AlternateEdit', [ $this ] ) ) { return; @@ -535,13 +571,14 @@ class EditPage { wfDebug( __METHOD__ . ": enter\n" ); + $request = $this->context->getRequest(); // If they used redlink=1 and the page exists, redirect to the main article - if ( $wgRequest->getBool( 'redlink' ) && $this->mTitle->exists() ) { + if ( $request->getBool( 'redlink' ) && $this->mTitle->exists() ) { $this->context->getOutput()->redirect( $this->mTitle->getFullURL() ); return; } - $this->importFormData( $wgRequest ); + $this->importFormData( $request ); $this->firsttime = false; if ( wfReadOnly() && $this->save ) { @@ -608,10 +645,11 @@ class EditPage { $this->isConflict = false; // css / js subpages of user pages get a special treatment + // The following member variables are deprecated since 1.30, + // the functions should be used instead. $this->isCssJsSubpage = $this->mTitle->isCssJsSubpage(); $this->isCssSubpage = $this->mTitle->isCssSubpage(); $this->isJsSubpage = $this->mTitle->isJsSubpage(); - // @todo FIXME: Silly assignment. $this->isWrongCaseCssJsPage = $this->isWrongCaseCssJsPage(); # Show applicable editing introductions @@ -700,10 +738,8 @@ class EditPage { * @throws PermissionsError */ protected function displayPermissionsError( array $permErrors ) { - global $wgRequest; - $out = $this->context->getOutput(); - if ( $wgRequest->getBool( 'redlink' ) ) { + if ( $this->context->getRequest()->getBool( 'redlink' ) ) { // The edit page was reached via a red link. // Redirect to the article page and let them click the edit tab if // they really want a permission error. @@ -785,17 +821,18 @@ class EditPage { * @return bool */ protected function previewOnOpen() { - global $wgRequest, $wgPreviewOnOpenNamespaces; - if ( $wgRequest->getVal( 'preview' ) == 'yes' ) { + global $wgPreviewOnOpenNamespaces; + $request = $this->context->getRequest(); + if ( $request->getVal( 'preview' ) == 'yes' ) { // Explicit override from request return true; - } elseif ( $wgRequest->getVal( 'preview' ) == 'no' ) { + } elseif ( $request->getVal( 'preview' ) == 'no' ) { // Explicit override from request return false; } elseif ( $this->section == 'new' ) { // Nothing *to* preview for new sections return false; - } elseif ( ( $wgRequest->getVal( 'preload' ) !== null || $this->mTitle->exists() ) + } elseif ( ( $request->getVal( 'preload' ) !== null || $this->mTitle->exists() ) && $this->context->getUser()->getOption( 'previewonfirst' ) ) { // Standard preference behavior @@ -862,7 +899,7 @@ class EditPage { # These fields need to be checked for encoding. # Also remove trailing whitespace, but don't remove _initial_ # whitespace from the text boxes. This may be significant formatting. - $this->textbox1 = $this->safeUnicodeInput( $request, 'wpTextbox1' ); + $this->textbox1 = rtrim( $request->getText( 'wpTextbox1' ) ); if ( !$request->getCheck( 'wpTextbox2' ) ) { // Skip this if wpTextbox2 has input, it indicates that we came // from a conflict page with raw page text, not a custom form @@ -873,6 +910,8 @@ class EditPage { } } + $this->unicodeCheck = $request->getText( 'wpUnicodeCheck' ); + $this->summary = $request->getText( 'wpSummary' ); # If the summary consists of a heading, e.g. '==Foobar==', extract the title from the @@ -1120,11 +1159,12 @@ class EditPage { * @since 1.21 */ protected function getContentObject( $def_content = null ) { - global $wgRequest, $wgContLang; + global $wgContLang; $content = false; $user = $this->context->getUser(); + $request = $this->context->getRequest(); // For message page not locally set, use the i18n message. // For other non-existent articles, use preload text if any. if ( !$this->mTitle->exists() || $this->section == 'new' ) { @@ -1136,10 +1176,10 @@ class EditPage { } if ( $content === false ) { # If requested, preload some text. - $preload = $wgRequest->getVal( 'preload', + $preload = $request->getVal( 'preload', // Custom preload text for new sections $this->section === 'new' ? 'MediaWiki:addsection-preload' : '' ); - $params = $wgRequest->getArray( 'preloadparams', [] ); + $params = $request->getArray( 'preloadparams', [] ); $content = $this->getPreloadedContent( $preload, $params ); } @@ -1154,8 +1194,8 @@ class EditPage { $content = $def_content; } } else { - $undoafter = $wgRequest->getInt( 'undoafter' ); - $undo = $wgRequest->getInt( 'undo' ); + $undoafter = $request->getInt( 'undoafter' ); + $undo = $request->getInt( 'undo' ); if ( $undo > 0 && $undoafter > 0 ) { $undorev = Revision::newFromId( $undo ); @@ -1482,9 +1522,7 @@ class EditPage { * Log when a page was successfully saved after the edit conflict view */ private function incrementResolvedConflicts() { - global $wgRequest; - - if ( $wgRequest->getText( 'mode' ) !== 'conflict' ) { + if ( $this->context->getRequest()->getText( 'mode' ) !== 'conflict' ) { return; } @@ -1542,6 +1580,7 @@ class EditPage { case self::AS_CANNOT_USE_CUSTOM_MODEL: case self::AS_PARSE_ERROR: + case self::AS_UNICODE_NOT_SUPPORTED: $out->addWikiText( '
' . "\n" . $status->getWikiText() . '
' ); return true; @@ -1730,7 +1769,7 @@ class EditPage { * time. */ public function internalAttemptSave( &$result, $bot = false ) { - global $wgRequest, $wgMaxArticleSize; + global $wgMaxArticleSize; global $wgContentHandlerUseDB; $status = Status::newGood(); @@ -1743,7 +1782,14 @@ class EditPage { return $status; } - $spam = $wgRequest->getText( 'wpAntispam' ); + if ( $this->unicodeCheck !== self::UNICODE_CHECK ) { + $status->fatal( 'unicode-support-fail' ); + $status->value = self::AS_UNICODE_NOT_SUPPORTED; + return $status; + } + + $request = $this->context->getRequest(); + $spam = $request->getText( 'wpAntispam' ); if ( $spam !== '' ) { wfDebugLog( 'SimpleAntiSpam', @@ -1803,7 +1849,7 @@ class EditPage { } if ( $match !== false ) { $result['spam'] = $match; - $ip = $wgRequest->getIP(); + $ip = $request->getIP(); $pdbk = $this->mTitle->getPrefixedDBkey(); $match = str_replace( "\n", '', $match ); wfDebugLog( 'SpamRegex', "$ip spam regex hit [[$pdbk]]: \"$match\"" ); @@ -2670,6 +2716,9 @@ class EditPage { call_user_func_array( $formCallback, [ &$out ] ); } + // Add a check for Unicode support + $out->addHTML( Html::hidden( 'wpUnicodeCheck', self::UNICODE_CHECK ) ); + // Add an empty field to trip up spambots $out->addHTML( Xml::openElement( 'div', [ 'id' => 'antispam-container', 'style' => 'display: none;' ] ) @@ -2765,7 +2814,7 @@ class EditPage { $out->addHTML( $this->editFormTextBeforeContent ); - if ( !$this->isCssJsSubpage && $showToolbar && $user->getOption( 'showtoolbar' ) ) { + if ( !$this->mTitle->isCssJsSubpage() && $showToolbar && $user->getOption( 'showtoolbar' ) ) { $out->addHTML( self::getEditToolbar( $this->mTitle ) ); } @@ -2944,10 +2993,6 @@ class EditPage { $out->addWikiText( $this->hookError ); } - if ( !$this->checkUnicodeCompliantBrowser() ) { - $out->addWikiMsg( 'nonunicodebrowser' ); - } - if ( $this->section != 'new' ) { $revision = $this->mArticle->getRevisionFetched(); if ( $revision ) { @@ -3005,27 +3050,28 @@ class EditPage { ); } } else { - if ( $this->isCssJsSubpage ) { + if ( $this->mTitle->isCssJsSubpage() ) { # Check the skin exists - if ( $this->isWrongCaseCssJsPage ) { + if ( $this->isWrongCaseCssJsPage() ) { $out->wrapWikiMsg( "
\n$1\n
", [ 'userinvalidcssjstitle', $this->mTitle->getSkinFromCssJsSubpage() ] ); } if ( $this->getTitle()->isSubpageOf( $user->getUserPage() ) ) { + $isCssSubpage = $this->mTitle->isCssSubpage(); $out->wrapWikiMsg( '
$1
', - $this->isCssSubpage ? 'usercssispublic' : 'userjsispublic' + $isCssSubpage ? 'usercssispublic' : 'userjsispublic' ); if ( $this->formtype !== 'preview' ) { - if ( $this->isCssSubpage && $wgAllowUserCss ) { + if ( $isCssSubpage && $wgAllowUserCss ) { $out->wrapWikiMsg( "
\n$1\n
", [ 'usercssyoucanpreview' ] ); } - if ( $this->isJsSubpage && $wgAllowUserJs ) { + if ( $this->mTitle->isJsSubpage() && $wgAllowUserJs ) { $out->wrapWikiMsg( "
\n$1\n
", [ 'userjsyoucanpreview' ] @@ -3218,10 +3264,6 @@ class EditPage { $out->addHTML( Html::hidden( 'wpEdittime', $this->edittime ) ); $out->addHTML( Html::hidden( 'editRevId', $this->editRevId ) ); $out->addHTML( Html::hidden( 'wpScrolltop', $this->scrolltop, [ 'id' => 'wpScrolltop' ] ) ); - - if ( !$this->checkUnicodeCompliantBrowser() ) { - $out->addHTML( Html::hidden( 'safemode', '1' ) ); - } } protected function showFormAfterText() { @@ -3315,8 +3357,7 @@ class EditPage { } protected function showTextbox( $text, $name, $customAttribs = [] ) { - $wikitext = $this->safeUnicodeOutput( $text ); - $wikitext = $this->addNewLineAtEnd( $wikitext ); + $wikitext = $this->addNewLineAtEnd( $text ); $attribs = $this->buildTextboxAttribs( $name, $customAttribs, $this->context->getUser() ); @@ -4185,8 +4226,6 @@ class EditPage { * @return array */ public function getCheckboxes( &$tabindex, $checked ) { - global $wgUseMediaWikiUIEverywhere; - $checkboxes = []; $checkboxesDef = $this->getCheckboxesDefinition( $checked ); @@ -4221,10 +4260,6 @@ class EditPage { ' ' . Xml::tags( 'label', $labelAttribs, $label ); - if ( $wgUseMediaWikiUIEverywhere ) { - $checkboxHtml = Html::rawElement( 'div', [ 'class' => 'mw-ui-checkbox' ], $checkboxHtml ); - } - $checkboxes[ $legacyName ] = $checkboxHtml; } @@ -4464,138 +4499,31 @@ class EditPage { $out->addReturnTo( $this->getContextTitle(), [ 'action' => 'edit' ] ); } - /** - * Check if the browser is on a blacklist of user-agents known to - * mangle UTF-8 data on form submission. Returns true if Unicode - * should make it through, false if it's known to be a problem. - * @return bool - */ - private function checkUnicodeCompliantBrowser() { - global $wgBrowserBlackList, $wgRequest; - - $currentbrowser = $wgRequest->getHeader( 'User-Agent' ); - if ( $currentbrowser === false ) { - // No User-Agent header sent? Trust it by default... - return true; - } - - foreach ( $wgBrowserBlackList as $browser ) { - if ( preg_match( $browser, $currentbrowser ) ) { - return false; - } - } - return true; - } - /** * Filter an input field through a Unicode de-armoring process if it * came from an old browser with known broken Unicode editing issues. * + * @deprecated since 1.30, does nothing + * * @param WebRequest $request * @param string $field * @return string */ protected function safeUnicodeInput( $request, $field ) { - $text = rtrim( $request->getText( $field ) ); - return $request->getBool( 'safemode' ) - ? $this->unmakeSafe( $text ) - : $text; + return rtrim( $request->getText( $field ) ); } /** * Filter an output field through a Unicode armoring process if it is * going to an old browser with known broken Unicode editing issues. * + * @deprecated since 1.30, does nothing + * * @param string $text * @return string */ protected function safeUnicodeOutput( $text ) { - return $this->checkUnicodeCompliantBrowser() - ? $text - : $this->makeSafe( $text ); - } - - /** - * A number of web browsers are known to corrupt non-ASCII characters - * in a UTF-8 text editing environment. To protect against this, - * detected browsers will be served an armored version of the text, - * with non-ASCII chars converted to numeric HTML character references. - * - * Preexisting such character references will have a 0 added to them - * to ensure that round-trips do not alter the original data. - * - * @param string $invalue - * @return string - */ - private function makeSafe( $invalue ) { - // Armor existing references for reversibility. - $invalue = strtr( $invalue, [ "&#x" => "�" ] ); - - $bytesleft = 0; - $result = ""; - $working = 0; - $valueLength = strlen( $invalue ); - for ( $i = 0; $i < $valueLength; $i++ ) { - $bytevalue = ord( $invalue[$i] ); - if ( $bytevalue <= 0x7F ) { // 0xxx xxxx - $result .= chr( $bytevalue ); - $bytesleft = 0; - } elseif ( $bytevalue <= 0xBF ) { // 10xx xxxx - $working = $working << 6; - $working += ( $bytevalue & 0x3F ); - $bytesleft--; - if ( $bytesleft <= 0 ) { - $result .= "&#x" . strtoupper( dechex( $working ) ) . ";"; - } - } elseif ( $bytevalue <= 0xDF ) { // 110x xxxx - $working = $bytevalue & 0x1F; - $bytesleft = 1; - } elseif ( $bytevalue <= 0xEF ) { // 1110 xxxx - $working = $bytevalue & 0x0F; - $bytesleft = 2; - } else { // 1111 0xxx - $working = $bytevalue & 0x07; - $bytesleft = 3; - } - } - return $result; - } - - /** - * Reverse the previously applied transliteration of non-ASCII characters - * back to UTF-8. Used to protect data from corruption by broken web browsers - * as listed in $wgBrowserBlackList. - * - * @param string $invalue - * @return string - */ - private function unmakeSafe( $invalue ) { - $result = ""; - $valueLength = strlen( $invalue ); - for ( $i = 0; $i < $valueLength; $i++ ) { - if ( ( substr( $invalue, $i, 3 ) == "&#x" ) && ( $invalue[$i + 3] != '0' ) ) { - $i += 3; - $hexstring = ""; - do { - $hexstring .= $invalue[$i]; - $i++; - } while ( ctype_xdigit( $invalue[$i] ) && ( $i < strlen( $invalue ) ) ); - - // Do some sanity checks. These aren't needed for reversibility, - // but should help keep the breakage down if the editor - // breaks one of the entities whilst editing. - if ( ( substr( $invalue, $i, 1 ) == ";" ) && ( strlen( $hexstring ) <= 6 ) ) { - $codepoint = hexdec( $hexstring ); - $result .= UtfNormal\Utils::codepointToUtf8( $codepoint ); - } else { - $result .= "&#x" . $hexstring . substr( $invalue, $i, 1 ); - } - } else { - $result .= substr( $invalue, $i, 1 ); - } - } - // reverse the transform that we made for reversibility reasons. - return strtr( $result, [ "�" => "&#x" ] ); + return $text; } /**