Extension:ProtectText/ProtectText.php

From MediaWiki.org
Jump to navigation Jump to search
<?php
# 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
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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.
# http://www.gnu.org/copyleft/gpl.html

/**
 * This is an extension that let you protect some part of a text. You just
 * have to be a member of a group with the 'protecttext' user right or
 * you have to be the sole contributor of the complete text.
 *
 * To protect a text, enclose it in a <protect> </protect> block.
 *
 * @addtogroup Extensions
 *
 * @author ThomasV <thomasv1@gmx.de>, John Erling Blad <john.erling.blad@jeb.no>
 * @copyright Copyright © 2006, ThomasV, John Erling Blad
 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 */

if( !defined( 'MEDIAWIKI' ) ) {
    echo( "This file is an extension to the MediaWiki software and cannot be used standalone.\n" );
    die( 1 );
}

$wgExtensionCredits['other'][] = array(
	'name' => 'ProtectText',
	'version'=> '0.4',
	'author' => 'ThomasV, John Erling Blad',
	'description' => 'Allows authorised users, and sole contributors, to protect parts of a text',
	'url' => 'http://www.mediawiki.org/wiki/Extension:ProtectText'
);

$dir = dirname(__FILE__) . '/';
$wgExtensionMessagesFiles['ProtectText'] = $dir . 'ProtectText.i18n.php';

// Two new permissions
$wgGroupPermissions['*']['protectsolecontributor']  = true;
$wgGroupPermissions['sysop']['protecttext']         = true;
$wgGroupPermissions['bureaucrat']['protecttext']    = true;
$wgAvailableRights[] = 'protecttext';
 
$wgExtensionFunctions[] = 'wfProtectTextSetup';

// Register hooks
$wgHooks['ParserBeforeStrip'][] = 'wfStripProtectTags' ;
$wgHooks['EditFilter'][] = 'wfCheckProtectText' ;

/**
 * TODO: use some arrays in ./languages/ for proper l10n
 */
function wfProtectTextSetup() {
    wfLoadExtensionMessages( 'ProtectText' );
}

/**
 * @param &$parser The parser object
 * @param &$text The text being parsed
 * @param &$x Something not used
 */
function wfStripProtectTags ( &$parser , &$text, &$x ) { 

	$text = preg_replace(
		array('/<protect>(.*?)<\/protect>/si', '/(\n;?:*;?)§(.*?)\n/si', '/(\n;?:*;?)§(.*?)$/si', '/\{§(.*?)§\}/si'),
		array("$1", "$1$2\n", "$1$2", "$1"),
		$text);
	return true;
}


/**
 * @todo Document
 * @param $editpage
 * @param $textbox1
 * @param $section
 * @param $error
 */
function wfCheckProtectText ( $editpage, $textbox1, $section, $error )  {

	global $wgUser, $wgTitle, $wgOut, $wgVersion;
	$modifyProtect = false; 

	if ( !$wgUser->isAllowed( 'protecttext' ) ) {
		$text1 = $editpage->mArticle->getContent(true);
		$text2 = $textbox1 ;

		preg_match_all( "/<protect>(.*?)<\/protect>|\n;?:*;?§(.*?)\n|\{§(.*?)§\}/si", $text1, $list1, PREG_SET_ORDER );
		preg_match_all( "/<protect>(.*?)<\/protect>|\n;?:*;?§(.*?)\n|\{§(.*?)§\}/si", $text2, $list2, PREG_SET_ORDER );
		if( count($list1) < count($list2)) { 
			$error = '<p class="error">' . wfMsg( 'protecttext_remove') . '</p>'; 
			$modifyProtect = true; 
		}
		if( count($list1) > count($list2)) { 
			$error = '<p class="error">' . wfMsg( 'protecttext_add') . '</p>'; 
			$modifyProtect = true; 
		}
		else for ( $i=0 ; $i < count( $list1 ); $i++ ) {
			if( $list1[$i][0] != $list2[$i][0]) { 
				$error = '<p class="error">' . wfMsg( 'protecttext_modify' ) . '</p>';
				$modifyProtect = true; 
				break;
			}
		}

		if ( $modifyProtect && $wgUser->isAllowed( 'protectsolecontributor' ) ) {
			$conds['rev_page'] = $wgTitle->getArticleID();
			if( version_compare( $wgVersion, '1.11alpha', '>=' ) )
				$conds[] = 'rev_deleted & ' . Revision::DELETED_USER . ' = 0';
			$contributors = array();
			$dbr = wfGetDB( DB_SLAVE );
			$res = $dbr->select(
				'revision',
				array(
					'COUNT(*) AS count',
					'rev_user',
					'rev_user_text',
				),
				$conds,
				__METHOD__,
				array(
					'GROUP BY' => 'rev_user_text',
					'ORDER BY' => 'count DESC',
				)
			);
			if( $res && $dbr->numRows( $res ) > 0 )
				while( $row = $dbr->fetchObject( $res ) )
					$contributors[ $row->rev_user_text ] = array( $row->rev_user );
			$total = 0;
			foreach( $contributors as $username => $info ) {
				list( $id ) = $info;
				if ($wgUser->getID() != $id) {
					$total++;
					break;
				}
			}
			if (!$total)
				$error = null;
		}
	}
	return true;
}

Alternative PHP module[edit]

The original above ProtectText php module has several issue's

  • Not functional for MediaWiki 1.25.5
  • Only suitable when editing the full page , otherwise when editing an section you always get an error

As no-one updates this extension , i took the freedom to update this extension for MediaWiki 1.25.5 and

removed the section edit error

NOTE: the file names and tag are changed, to assure that no installation error could happen

Source of new ProtectABC.php[edit]

This new file should be allocated in /extensions/ProtectABCText/ProtectABCText.php

<?php
/******************
 *  variable Extension - this extension is an QBox extention
 *  Copyright (C) 2016 qbox4u.com <qbox4u@gmail.com>
 *
 *  This program is not free software therefore you can-not redistribute 
 *  it and/or modify it under the terms of the GNU General Public License 
 *  as published by the Free Software Foundation; either version 2 of the 
 *  License, or (at your option) any later version.
 *
 *  Please consult and/or request the administrator of QBox4u 
 *  to use the information and samples
 *  To copy the data an written autorisation of the developer as stated in 
 *  the $wgExtensionCredits is required 
 * 
 *  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.
 *  http://www.gnu.org/copyleft/gpl.html
 *
 *  1  <protectABC> text block to be protected </protectABC>
 *  2  {§fragment of text to be protected§}
 *
 *  To activate this extension, add the following into your LocalSettings.php file:
 *  require_once( "$IP/extensions/ProtectABCText/ProtectABCText.php");
 *
 *  @ingroup Extensions
 *  @author Jan boer <qbox4u@gmail.com>
 *  @version 1.0
 *  @link http://QBox4u.com
 *
 */ 
 
 /******************
 * Include all the required library's 
 * This line must be present before any global variable is referenced.
 */

if( !defined( 'MEDIAWIKI' ) )  {
	echo( "This is an extension to the MediaWiki package and cannot be run standalone.<br>\n" );
	echo( "Use this php file only locally on the QNAP TS-459 proII server  <br>\n" );
	echo( "****************************   WARNING  WARNING  WARNING ******************************<br>\n" );
	echo( "This is an restricted application only tested for application purposes inside QBox4u.com<br>\n" ); 
	echo( "This application wil malfunction if illegal and/or unautorised access has been detected \n" );
	die( -1 );
}

$wgExtensionCredits['other'][] = array(
    'path'           	=> __FILE__,
	'name'				=> 'Protect ABC Text',
	'version'			=> '1.0.1',
	'author' 			=>  array( 'https://www.linkedin.com/in/jan-boer-a24640113','qbox4u@gmail.com', 'note:modified from the first base source of ThomasV and John Erling Blad'),
	'description' 		=> 'Allow authorised users to protect parts of a Page text by the tag <code>&lt;protectABC&gt;</code>',
	'license-name' 		=> 'Licence',
	'url' 				=> 'https://www.mediawiki.org/wiki/Extension_talk:ProtectText'
);


// Keep i18n globals so mergeMessageFileList.php doesn't break
$wgMessagesDirs['ProtectABC'] 	= __DIR__ . '/i18n';
$wgmodifyProtect 				= false;
$wgOriginal_ABC_Page 			= '';


// Two new permissions
$wgAvailableRights[] = 'protectABC';
$wgAvailableRights[] = 'protectsolecontributor';

// Set the appropiate rights
$wgGroupPermissions['*']['protectABC']         				= false;
$wgGroupPermissions['*']['protectsolecontributor']  		= false;
$wgGroupPermissions['sysop']['protectABC']         			= true;
$wgGroupPermissions['sysop']['protectsolecontributor']  	= true;
$wgGroupPermissions['bureaucrat']['protectABC']    			= true;
$wgGroupPermissions['bureaucrat']['protectsolecontributor']	= true;

// Register hooks
$wgHooks['ParserBeforeStrip'][] = 'wfStripProtectTags' ;
$wgHooks['EditFilter'][] 		= 'wfAllocateOriginalText' ;
$wgHooks['PageContentSave'][] 	= 'wfCheckProtectText' ;

function wfCheckProtectText ( &$wikiPage, &$user, &$content, &$summary, $isMinor, $isWatch, $section, &$flags, &$status) { 
global $wgUser, $wgTitle, $wgVersion, $wgOriginal_ABC_Page;

		if ( !$wgUser->isAllowed( 'protectABC' ) ) {
			$Submitted_page_text = $content->getNativeData();
			// Retrieve all the area's with protected text
			// the original text 
			preg_match_all( "/<protectABC>(.*?)<\/protectABC>|\n;?:*;?§(.*?)\n|\{§(.*?)§\}/si", $wgOriginal_ABC_Page, $list1, PREG_SET_ORDER );
			// the text as the user want to save
			preg_match_all( "/<protectABC>(.*?)<\/protectABC>|\n;?:*;?§(.*?)\n|\{§(.*?)§\}/si", $Submitted_page_text, $list2, PREG_SET_ORDER );		
	
			if( count($list1) < count($list2)) {
				# indeed an addition  of an tag, we will have to protect the text				
				$wgmodifyProtect = true;
				// create an error status, than the page is not saved
				$message = '<p class="error">'.wfMessage( 'protecttext_add' )->parse().'</p>'; }
				
			if( count($list1) > count($list2)) {
				# indeed an removal of the tag, we will have to protect the text				
				$wgmodifyProtect = true;
				// create an error status, than the page is not saved								
				$message = '<p class="error">'.wfMessage( 'protecttext_remove' )->parse().'</p>';	}
				
			else for ( $i=0 ; $i < count( $list1 ); $i++ ) {	
				// compair the content of an enclosed protected text 
				if( $list1[$i][0] != $list2[$i][0]) {
				// create an error status if the encosed data differs ,than the page is not saved	
					$wgmodifyProtect = true;				
					$message = '<p class="error">' . wfMessage( 'protecttext_modify' )->parse() . '</p>';
					break;
				}
			}
			
			//************** Check on protectsolecontributor ************
			//* Whenever we have an protection breach, but the user is an allowed contributer
			//***********************************************************			
			if ( $wgmodifyProtect && $wgUser->isAllowed( 'protectsolecontributor' ) ) {
				$conds['rev_page'] = $wgTitle->getArticleID();
				if( version_compare( $wgVersion, '1.11alpha', '>=' ) )
					$conds[] = 'rev_deleted & ' . Revision::DELETED_USER . ' = 0';
				$contributors = array();
				$dbr = wfGetDB( DB_SLAVE );
				$res = $dbr->select(
					'revision',
					array(
						'COUNT(*) AS count',
						'rev_user',
						'rev_user_text',
					),
				$conds,
				__METHOD__,
				array(
					'GROUP BY' => 'rev_user_text',
					'ORDER BY' => 'count DESC',
					)
				);
				if( $res && $dbr->numRows( $res ) > 0 )
					while( $row = $dbr->fetchObject( $res ) )
						$contributors[ $row->rev_user_text ] = array( $row->rev_user );
				$total = 0;
			
				foreach( $contributors as $username => $info ) {
					list( $id ) = $info;
					if ($wgUser->getID() != $id) {
						$total++;
						break;
					}
				}
				// if we have the same page owner and not an different contributer, and they are aowed to contributer
				// than cancel the protection of the previous part
				if (!$total){ $wgmodifyProtect = false; }
			}

			// If we have an protection breach, terminate the save and show an fatal error
			if($wgmodifyProtect){ $status->fatal(new RawMessage("$message")); }
		}

	
	return;
}

/**
 * @param &$parser The parser object
 * @param &$text The text being parsed
 * @param &$x Something not used
 */
function wfStripProtectTags ( &$parser , &$text, &$x ) { 

		$text = preg_replace(
			array('/<protectABC>(.*?)<\/protectABC>/si', '/(\n;?:*;?)§(.*?)\n/si', '/(\n;?:*;?)§(.*?)$/si', '/\{§(.*?)§\}/si'),
			array("$1", "$1$2\n", "$1$2", "$1"),
			$text);
	return true;
}

/**
 * @param $editor 
 * @param $text
 * @param $section
 * @param &$error
 * @param $summary
 */

function wfAllocateOriginalText ( $editor, $text, $section, &$error, $summary )  {
global $wgOriginal_ABC_Page;

		$wgOriginal_ABC_Page = $editor->mArticle->getContent(true);
	return true;
}

?>