Source for file edit.php
Documentation is available at edit.php
* Copyright( c ) 2004 bitweaver.org
* Copyright( c ) 2003 tikwiki.org
* Copyright( c ) 2002-2003, Luis Argerich, Garland Foster, Eduardo Polidor, et. al.
* All Rights Reserved. See below for details and a complete list of authors.
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See http://www.gnu.org/copyleft/lesser.html for details
require_once( '../kernel/setup_inc.php' );
include_once( WIKI_PKG_PATH. 'BitBook.php' );
$gBitSystem->verifyPackage( 'wiki' );
// bypass lookup_content_inc.php as we can't prevent it parsing faulty pages
unset ($_REQUEST['content_id']);
// Disable parsing data if not asking to preview page
$_REQUEST["parse"] = false;
include( WIKI_PKG_PATH. 'lookup_page_inc.php' );
if( $gContent->isValid() ) {
$gContent->verifyUpdatePermission();
$gContent->verifyCreatePermission();
//make comment count for this page available for templates
if( $gBitSystem->isFeatureActive( 'wiki_comments' ) && !empty( $_REQUEST['page_id'] ) ) {
require_once( LIBERTY_PKG_PATH. 'LibertyComment.php' );
$numComments = $gComment->getNumComments($gContent->mContentId);
$gBitSmarty->assign('comments_count', $numComments);
if( !isset ( $_REQUEST['title'] ) && isset ( $gContent->mInfo['title'] ) ) {
$_REQUEST['title'] = $gContent->mInfo['title'];
$gBitSystem->fatalError( 'Cannot edit page because it is locked' );
$gContent->invokeServices( 'content_edit_function' );
if( !empty( $gContent->mInfo ) ) {
$formInfo = $gContent->mInfo;
$data_to_edit = !empty( $gContent->mInfo['data'] ) ? $gContent->mInfo['data'] : '';
if (!empty($_REQUEST['section'])) {
$section = $_REQUEST['section'];
$formInfo['data'] = $data_to_edit;
$formInfo['edit_section'] = 1;
$formInfo['section'] = $_REQUEST['section'];
$formInfo['edit'] = $data_to_edit;
$formInfo['edit_comment'] = '';
$gBitSmarty->assign( 'footnote', '' );
$gBitSmarty->assign( 'has_footnote', 'n' );
if( $gBitUser->mUserId ) {
$footnote = $gContent->getFootnote( $gBitUser->mUserId );
$gBitSmarty->assign( 'footnote', $footnote );
$gBitSmarty->assign( 'has_footnote', 'y' );
$gBitSmarty->assign( 'parsed_footnote', $gContent->parseData( $footnote ) );
if( isset ( $_REQUEST['footnote'] ) ) {
$gBitSmarty->assign( 'parsed_footnote', $gContent->parseData( $_REQUEST['footnote'] ) );
$gBitSmarty->assign( 'footnote', $_REQUEST['footnote'] );
$gBitSmarty->assign( 'has_footnote', 'y' );
if( empty( $_REQUEST['footnote'] ) ) {
$gContent->expungeFootnote( $gBitUser->mUserId );
$gContent->storeFootnote( $gBitUser->mUserId, $_REQUEST['footnote'] );
if( isset ( $_REQUEST["edit"] ) ) {
$formInfo['edit'] = $_REQUEST["edit"];
if(isset ($_REQUEST["section"])) {
$formInfo['section'] = $_REQUEST["section"];
$formInfo['edit_section'] = 1;
if( isset ( $_REQUEST['title'] ) ) {
$formInfo['title'] = $_REQUEST['title'];
} elseif( isset ( $_REQUEST['page'] ) ) {
$formInfo['title'] = $_REQUEST['page'];
if( isset ( $_REQUEST["description"] ) ) {
$formInfo['description'] = $_REQUEST["description"];
if( isset ( $_REQUEST["edit_comment"] ) ) {
$formInfo['edit_comment'] = $_REQUEST["edit_comment"];
$formInfo['edit_comment'] = '';
$cat_obj_type = BITPAGE_CONTENT_TYPE_GUID;
if( isset ( $_REQUEST['copyrightTitle'] ) ) {
$gBitSmarty->assign( 'copyrightTitle', $_REQUEST["copyrightTitle"] );
if( isset ( $_REQUEST['copyrightYear'] ) ) {
$gBitSmarty->assign( 'copyrightYear', $_REQUEST["copyrightYear"] );
if( isset ( $_REQUEST['copyrightAuthors'] ) ) {
$gBitSmarty->assign( 'copyrightAuthors', $_REQUEST["copyrightAuthors"] );
// Check if the page has changed
if( isset ( $_REQUEST["fCancel"] ) ) {
if( @BitBase::verifyId( $gContent->mContentId ) ) {
header( "Location: ". WIKI_PKG_URL );
} elseif( isset ( $_REQUEST["fSavePage"] ) ) {
// Check if all Request values are delivered, and if not, set them
// to avoid error messages. This can happen if some features are
// add permisions here otherwise return error!
&& isset ( $_REQUEST['copyrightAuthors'] )
&& !empty( $_REQUEST['copyrightYear'] )
&& !empty( $_REQUEST['copyrightTitle'] )
require_once( WIKI_PKG_PATH. 'copyrights_lib.php' );
$copyrightYear = $_REQUEST['copyrightYear'];
$copyrightTitle = $_REQUEST['copyrightTitle'];
$copyrightAuthors = $_REQUEST['copyrightAuthors'];
$copyrightslib->add_copyright( $gContent->mPageId, $copyrightTitle, $copyrightYear, $copyrightAuthors, $gBitUser->mUserId );
// Parse $edit and eliminate image references to external URIs( make them internal )
if( $gBitSystem->isPackageActive( 'imagegals' ) ) {
include_once( IMAGEGALS_PKG_PATH. 'imagegal_lib.php' );
$edit = $imagegallib->capture_images( $edit );
{ if( isset ( $_REQUEST['isminor'] ) && $_REQUEST['isminor']== 'on' ) {
$_REQUEST['minor']= false;
// $links = $gContent->get_links( $edit );
// $wikilib->cache_links( $links );
// $gContent->storeLinks( $links );
// $links = $gContent->get_links( $_REQUEST["edit"] );
// $notcachedlinks = $gContent->get_links_nocache( $_REQUEST["edit"] );
// $cachedlinks = array_diff( $links, $notcachedlinks );
// $gContent->cache_links( $cachedlinks );
// $gContent->storeLinks( $cachedlinks );
$data_to_parse = $formInfo['edit'];
if (!empty($formInfo['section']) && !empty($gContent->mInfo['data']) ) {
$full_page_data = $gContent->mInfo['data'];
$data_to_parse = replace_section($full_page_data,$formInfo['section'],$formInfo['edit']);
$_REQUEST["edit"] = $data_to_parse;
if( $gContent->store( $_REQUEST ) ) {
$gBitUser->storeWatch( "wiki_page_changed", $gContent->mPageId, $gContent->mContentTypeGuid, $_REQUEST['title'], $gContent->getDisplayUrl() );
$formInfo['data'] = &$_REQUEST['edit'];
} elseif( !empty( $_REQUEST['edit'] ) ) {
// perhaps we have a javascript non-saving form submit
$formInfo['data'] = &$_REQUEST['edit'];
if( isset ( $_REQUEST['format_guid'] ) && !isset ( $gContent->mInfo['format_guid'] ) ) {
$formInfo['format_guid'] = $gContent->mInfo['format_guid'] = $_REQUEST['format_guid'];
if( isset ( $_REQUEST["preview"] ) ) {
$gBitSmarty->assign( 'preview',1 );
$gBitSmarty->assign( 'title',!empty( $_REQUEST["title"] ) ? $_REQUEST["title"]: $gContent->mPageName );
if (!empty($formInfo['section'])) {
$formInfo['edit_section'] = 1;
$data_to_parse = $formInfo['edit'];
if( !empty( $formInfo['section'] ) && !empty( $gContent->mInfo['data'] )) {
$full_page_data = $gContent->mInfo['data'];
$formInfo['parsed_data'] = $gContent->parseData(
( !empty( $_REQUEST['format_guid'] ) ? $_REQUEST['format_guid'] : ( isset ( $gContent->mInfo['format_guid'] ) ? $gContent->mInfo['format_guid'] : 'tikiwiki' ))
$gContent->invokeServices( 'content_preview_function' );
$gBitSmarty->assign( 'showstructs', $gContent->getStructures() );
// Flag for 'page bar' that currently 'Edit' mode active
// so no need to show comments & attachments, but need
// to show 'wiki quick help'
$gBitSmarty->assign( 'edit_page', 'y' );
// formInfo might be set due to a error on submit
if( empty( $formInfo ) ) {
$formInfo = &$gContent->mInfo;
// make original page title available for template
$formInfo['original_title'] = ( !empty( $gContent->mInfo['title'] ) ) ? $gContent->mInfo['title'] : "" ;
$gBitSmarty->assign_by_ref( 'pageInfo', $formInfo );
$gBitSmarty->assign_by_ref( 'errors', $gContent->mErrors );
if( $gBitSystem->isPackageActive( 'ckeditor' ) ) {
$gBitSystem->display( 'bitpackage:wiki/edit_page.tpl', 'Edit: '. $gContent->getTitle() , array( 'display_mode' => 'edit' ));
//******************* WIKI Edit Functions
$string = preg_replace( "/&#([0-9]+);/me", "chr('\\1')", $string );
if( !empty( $obj->parts ) ) {
for( $i= 0; $i< count( $obj->parts ); $i++ ) {
$ctype = $obj->ctype_primary. '/'. $obj->ctype_secondary;
case 'application/x-tikiwiki':
$aux["body"] = $obj->body;
$ccc= $obj->headers["content-type"];
$items = split( ';',$ccc );
foreach( $items as $item ) {
$portions = split( '=',$item );
if( isset ( $portions[0] ) &&isset ( $portions[1] ) ) {
$aux[trim( $portions[0] )]= trim( $portions[1] );
global $gContent, $gBitSystem;
$section_data = preg_split( "/\n(". ( str_repeat( "!", $gBitSystem->getConfig( "wiki_section_edit" ) ) ). "[^!])/", "\n$data", - 1, PREG_SPLIT_DELIM_CAPTURE );
$a = 1 + ($section - 1) * 2;
return $section_data[$a] . $section_data[$b];
global $gContent, $gBitSystem;
$section_data = preg_split("/(\n". ( str_repeat( "!", $gBitSystem->getConfig( "wiki_section_edit" ) ) ). "[^!])/", "\n$data" ,- 1,PREG_SPLIT_DELIM_CAPTURE);
$a = 1 + ($section - 1) * 2;
$section_data[$a] = "\n";
$section_data[$b] = $new_section_data;
return $a1["version"] - $a2["version"];
* \brief Parsed HTML tree walker( used by HTML sucker )
* This is initial implementation( stupid... w/o any intellegence( almost : ) )
* It is rapidly designed version... just for test: 'can this feature be useful'.
* Later it should be replaced by well designed one :) don't bash me now : )
* \param &$c array -- parsed HTML
* \param &$src string -- output string
* \param &$p array -- ['stack'] = closing strings stack,
['listack'] = stack of list types currently opened
['first_td'] = flag: 'is <tr> was just before this <td>'
for( $i= 0; $i <= $c["contentpos"]; $i++ ) {
// If content type 'text' output it to destination...
if( $c[$i]["type"] == "text" ) {
} elseif( $c[$i]["type"] == "tag" ) {
if( $c[$i]["data"]["type"] == "open" ) {
switch( $c[$i]["data"]["name"] ) {
case "br": $src .= "\n"; break;
case "title": $src .= "\n!"; $p['stack'][] = array( 'tag' => 'title', 'string' => "\n" ); break;
case "p": $src .= "\n"; $p['stack'][] = array( 'tag' => 'p', 'string' => "\n" ); break;
case "b": $src .= '__'; $p['stack'][] = array( 'tag' => 'b', 'string' => '__' ); break;
case "i": $src .= "''"; $p['stack'][] = array( 'tag' => 'i', 'string' => "''" ); break;
case "u": $src .= "=="; $p['stack'][] = array( 'tag' => 'u', 'string' => "==" ); break;
case "center": $src .= '::'; $p['stack'][] = array( 'tag' => 'center', 'string' => '::' ); break;
case "code": $src .= '-+'; $p['stack'][] = array( 'tag' => 'code', 'string' => '+-' ); break;
// headers detection looks like real suxx code...
// but possible it run faster :) I don't know where is profiler in PHP...
case "h1": $src .= "\n!"; $p['stack'][] = array( 'tag' => 'h1', 'string' => "\n" ); break;
case "h2": $src .= "\n!!"; $p['stack'][] = array( 'tag' => 'h2', 'string' => "\n" ); break;
case "h3": $src .= "\n!!!"; $p['stack'][] = array( 'tag' => 'h3', 'string' => "\n" ); break;
case "h4": $src .= "\n!!!!"; $p['stack'][] = array( 'tag' => 'h4', 'string' => "\n" ); break;
case "h5": $src .= "\n!!!!!"; $p['stack'][] = array( 'tag' => 'h5', 'string' => "\n" ); break;
case "h6": $src .= "\n!!!!!!"; $p['stack'][] = array( 'tag' => 'h6', 'string' => "\n" ); break;
case "pre": $src .= '~pp~'; $p['stack'][] = array( 'tag' => 'pre', 'string' => '~/pp~' ); break;
case "table": $src .= '||'; $p['stack'][] = array( 'tag' => 'table', 'string' => '||' ); break;
case "tr": $p['first_td'] = true; break;
case "td": $src .= $p['first_td'] ? '' : '|'; $p['first_td'] = false; break;
case "ul": $p['listack'][] = '*'; break;
case "ol": $p['listack'][] = '#'; break;
// Generate wiki list item according to current list depth.
//( ensure '*/#' starts from begining of line )
for( $l = ''; strlen( $l ) < count( $p['listack'] ); $l .= end( $p['listack'] ) );
// If color attribute present in <font> tag
if( isset ( $c[$i]["pars"]["color"]["value"] ) ) {
$src .= '~~'. $c[$i]["pars"]["color"]["value"]. ':';
$p['stack'][] = array( 'tag' => 'font', 'string' => '~~' );
// If src attribute present in <img> tag
if( isset ( $c[$i]["pars"]["src"]["value"] ) ) {
// Note what it produce( img ) not {img}! Will fix this below...
$src .= '( img src='. $c[$i]["pars"]["src"]["value"]. ' )';
// If href attribute present in <a> tag
if( isset ( $c[$i]["pars"]["href"]["value"] ) ) {
$src .= '['. $c[$i]["pars"]["href"]["value"]. '|';
$p['stack'][] = array( 'tag' => 'a', 'string' => ']' );
// This is close tag type. Is that smth we r waiting for?
switch( $c[$i]["data"]["name"] ) {
if( end( $p['listack'] ) == '*' ) array_pop( $p['listack'] );
if( end( $p['listack'] ) == '#' ) array_pop( $p['listack'] );
if( $c[$i]["data"]["name"] == $e['tag'] ) {
// Recursive call on tags with content...
if( isset ( $c[$i]["content"] ) ) {
// if( substr( $src, -1 )!= " " )$src .= " ";
if( isset ( $_REQUEST["suck_url"] ) ) {
$gBitSystem->fatalError( tra( "Importing remote URLs is disabled" ));
// Suck another page and append to the end of current
require_once( UTIL_PKG_PATH. 'htmlparser/html_parser_inc.php' );
$suck_url = isset ( $_REQUEST["suck_url"] ) ? $_REQUEST["suck_url"] : '';
$parsehtml = isset ( $_REQUEST["parsehtml"] ) ? ( $_REQUEST["parsehtml"] == 'on' ? 'y' : 'n' ): 'n';
if( isset ( $_REQUEST['do_suck'] ) && strlen( $suck_url ) > 0 ) {
// This is ugly implementation of wiki HTML import.
// I think it should be plugable import/export converters with ability
// to choose from edit form what converter to use for operation.
// In case of import converter, it can try to guess what source
// file is( using mime type from remote server response ).
// Of couse converters may have itsown configuration panel what should be
// pluged into wiki page edit form too...( like HTML importer may have
// flags 'strip HTML tags' and 'try to convert HTML to wiki' : )
// At least one export filter for wiki already coded : ) -- PDF exporter...
//Disallow urls without schema (usually relative urls), or http(s)
if(!isset ($parsed_url['scheme']) || ($parsed_url['scheme']!= 'http' && $parsed_url['scheme']!= 'https')){
$gBitSystem->fatalError( tra( "Invalid URL; not absolute or not HTTP" ));
//Make sure the passed host isn't local
if(!isset ($parsed_url['host']) || ($parsed_url['host']== 'localhost') || strncmp($parsed_url['host'],"127.",4)== 0){
$gBitSystem->fatalError( tra( "The host specified is either empty or local." ));
if( isset ( $php_errormsg ) && strlen( $php_errormsg ) ) {
$gBitSystem->fatalError( tra( "Can't import remote HTML page" ));
if( $parsehtml == 'y' ) {
// Read compiled( serialized ) grammar
if( !$fp = @fopen( $grammarfile,'r' ) ) {
$gBitSystem->fatalError( tra( "Can't parse remote HTML page" ));
// create parser object, insert html code and parse it
$htmlparser = new HtmlParser( $sdta, $grammar, '', 0 );
// Should I try to convert HTML to wiki?
$p = array( 'stack' => array(), 'listack' => array(), 'first_td' => false );
// Is some tags still opened?( It can be if HTML not valid, but this is not reason
// to produce invalid wiki : )
while( count( $p['stack'] ) ) {
// Unclosed lists r ignored... wiki have no special start/end lists syntax....
// OK. Things remains to do:
$parseddata = preg_replace( ',\[(.*)\|\( img src=(.*)\)\],mU','{img src=$2 link=$1}', $parseddata );
// 2 ) fix remains images( not in links )
$parseddata = preg_replace( ',\( img src=(.*)\),mU','{img src=$1}', $parseddata );
// 3 ) remove empty lines
$parseddata = preg_replace( ",[\n]+,mU","\n", $parseddata );
// Reassign previous data
$_REQUEST['edit'] .= $sdta;
//***************************************
|