465 lines
18 KiB
PHP
465 lines
18 KiB
PHP
<?php
|
|
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../../').'/');
|
|
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
|
|
if(!defined('DOKU_MEDIA')) define('DOKU_MEDIA',DOKU_INC.'data/media/');
|
|
define ('BROKEN_IMAGE', DOKU_BASE . 'lib/plugins/ckgedit/fckeditor/userfiles/blink.jpg?nolink&33x34');
|
|
require_once(DOKU_PLUGIN.'action.php');
|
|
if(!defined('FCK_ACTION_SUBDIR')) define('FCK_ACTION_SUBDIR', realpath(dirname(__FILE__)) . '/');
|
|
/**
|
|
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
|
*/
|
|
|
|
class action_plugin_ckgedit_save extends DokuWiki_Action_Plugin {
|
|
var $helper = false;
|
|
function register(Doku_Event_Handler $controller) {
|
|
|
|
$controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'ckgedit_save_preprocess');
|
|
}
|
|
|
|
function ckgedit_save_preprocess(Doku_Event $event){
|
|
global $ACT,$INPUT;
|
|
$this->helper = $this->loadhelper('ckgedit');
|
|
if (!isset($_REQUEST['ckgedit']) || ! is_array($ACT) || !(isset($ACT['save']) || isset($ACT['preview']))) return;
|
|
if (isset($_REQUEST["fontdel"]) ) {
|
|
msg($this->getLang("fontdel"),1);
|
|
}
|
|
if (isset($_REQUEST["formatdel"]) ) {
|
|
msg($this->getLang("formatdel"),1);
|
|
}
|
|
|
|
$img_size = $INPUT->int('broken_image');
|
|
if($img_size) msg($this->getLang('broken_image') . $img_size/1000000 . 'M' );
|
|
|
|
|
|
global $TEXT, $conf;
|
|
|
|
if (!$TEXT) return;
|
|
$preserve_enc = $this->getConf('preserve_enc');
|
|
$deaccent = $conf['deaccent'] == 0 ? false : true;
|
|
$TEXT = $_REQUEST['fck_wikitext'];
|
|
|
|
if(!preg_match('/^\s+(\-|\*)/',$TEXT)) {
|
|
$TEXT = trim($TEXT);
|
|
}
|
|
|
|
|
|
$TEXT = preg_replace_callback(
|
|
'|\{\{data:(.*?);base64|ms',
|
|
create_function(
|
|
'$matches',
|
|
'if(!preg_match("/image/",$matches[1])) {
|
|
return "{{data:image/jpeg;base64";
|
|
}
|
|
return $matches[0];'
|
|
),$TEXT);
|
|
|
|
if(strpos($TEXT,'data:image') !== false) {
|
|
$TEXT = preg_replace_callback(
|
|
'|\{\{(\s*)data:image\/(\w+;base64,\s*)(.*?)\?nolink&(\s*)\}\}|ms',
|
|
create_function(
|
|
'$matches',
|
|
'list($ext,$base) = explode(";",$matches[2]);
|
|
if($ext == "jpeg" || $ext == "tiff") $ext = "jpg";
|
|
if(function_exists("imagecreatefromstring") && !imagecreatefromstring (base64_decode($matches[3]))) {
|
|
msg("Clipboard paste: invalid $ext image format");
|
|
return "{{" . BROKEN_IMAGE . "}}";
|
|
}
|
|
global $INFO,$conf;
|
|
$ns = getNS($INFO["id"]);
|
|
$ns = trim($ns);
|
|
if(!empty($ns)) {
|
|
$ns = ":$ns:";
|
|
$dir = str_replace(":","/",$ns);
|
|
}
|
|
else { // root namespace
|
|
$dir = "/";
|
|
$ns = ":";
|
|
}
|
|
$fn = md5($matches[3]) . ".$ext";
|
|
$path = $conf["mediadir"] . $dir . $fn;
|
|
@io_makeFileDir($path);
|
|
if(!file_exists($path)) {
|
|
@file_put_contents($path, base64_decode($matches[3]));
|
|
global $lang;
|
|
$id = $dir . $fn;
|
|
$id = str_replace("/",":",$id);
|
|
addMediaLogEntry(time(), $id, DOKU_CHANGE_TYPE_CREATE, $lang["created"],"", null, strlen(base64_decode($matches[3])));
|
|
}
|
|
else {
|
|
msg("file for this image previousely saved",2);
|
|
}
|
|
$left = "{{";
|
|
$right = "}}";
|
|
if($matches[1]) $left .= $matches[1];
|
|
if($matches[4]) $right = $matches[4] . $right;
|
|
|
|
$retv = "$left" . $ns. $fn . "$right";
|
|
return $retv;'
|
|
),
|
|
$TEXT
|
|
);
|
|
}
|
|
$TEXT = str_replace('%%', "FCKGPERCENTESC", $TEXT);
|
|
|
|
if($deaccent || $preserve_enc) {
|
|
$TEXT = preg_replace_callback('/^(.*?)(\[\[.*?\]\])*(.*?)$/ms',
|
|
create_function(
|
|
'$matches',
|
|
'$matches[1] = preg_replace("/%([A-F0-9]{1,3})/i", "URLENC_PERCENT$1", $matches[1]);
|
|
$matches[2] = preg_replace("/%([A-F0-9]{1,3})/i", "URLENC_PERCENT$1", $matches[2]);
|
|
$matches[3] = preg_replace("/%([A-F0-9]{1,3})/i", "URLENC_PERCENT$1", $matches[3]);
|
|
return $matches[1].$matches[2].$matches[3];'
|
|
),
|
|
$TEXT
|
|
);
|
|
}
|
|
|
|
$TEXT = rawurldecode($TEXT);
|
|
$TEXT = preg_replace('/NOWIKI_%_NOWIKI_%_/', '%%',$TEXT);
|
|
$TEXT = preg_replace('/URLENC_PERCENT/', '%',$TEXT);
|
|
$TEXT = preg_replace('/NOWIKI_(.)_/', '$1',$TEXT);
|
|
|
|
/* preserve newlines in code blocks */
|
|
$TEXT = preg_replace_callback(
|
|
'/(<code>|<file>)(.*?)(<\/code>|<\/file>)/ms',
|
|
create_function(
|
|
'$matches',
|
|
'return str_replace("\n", "__code_NL__",$matches[0]);'
|
|
),
|
|
$TEXT
|
|
);
|
|
|
|
$TEXT = preg_replace('/^\s*[\r\n]$/ms',"__n__", $TEXT);
|
|
$TEXT = preg_replace('/oIWIKIo|cIWIKIc/ms',"", $TEXT);
|
|
$TEXT = preg_replace('/\r/ms',"", $TEXT);
|
|
$TEXT = preg_replace('/^\s+(?=\^|\|)/ms',"", $TEXT);
|
|
$TEXT = preg_replace('/__n__/',"\n", $TEXT);
|
|
$TEXT = str_replace("__code_NL__","\n", $TEXT);
|
|
$TEXT = str_replace("FCKGPERCENTESC", '%%', $TEXT);
|
|
if($this->getConf('complex_tables')) {
|
|
$TEXT = str_replace('~~COMPLEX_TABLES~~','',$TEXT);
|
|
}
|
|
$TEXT .= "\n";
|
|
// Removes relics of markup characters left over after acronym markup has been removed
|
|
//$TEXT = preg_replace('/([\*\/_]{2})\s+\\1\s*([A-Z]+)\s*\\1+/ms',"$2",$TEXT);
|
|
|
|
$pos = strpos($TEXT, 'MULTI_PLUGIN_OPEN');
|
|
if($pos !== false) {
|
|
$TEXT = preg_replace_callback(
|
|
'|MULTI_PLUGIN_OPEN.*?MULTI_PLUGIN_CLOSE|ms',
|
|
create_function(
|
|
'$matches',
|
|
'return preg_replace("/\\\\\\\\/ms","\n",$matches[0]);'
|
|
),
|
|
$TEXT
|
|
);
|
|
|
|
$TEXT = preg_replace_callback(
|
|
'|MULTI_PLUGIN_OPEN.*?MULTI_PLUGIN_CLOSE|ms',
|
|
create_function(
|
|
'$matches',
|
|
'return preg_replace("/^\s+/ms","",$matches[0]);'
|
|
),
|
|
$TEXT
|
|
);
|
|
$TEXT = str_replace("~~MULTI_PLUGIN_OPEN~~","~~MULTI_PLUGIN_OPEN~~\n",$TEXT);
|
|
}
|
|
|
|
if(strpos($TEXT,'L_PARgr') !== false) {
|
|
$TEXT = preg_replace_callback(
|
|
'|\(\((.*?)\)\)|ms',
|
|
create_function(
|
|
'$matches',
|
|
'return "((" . trim($matches[1]) . "))"; '
|
|
),
|
|
$TEXT
|
|
);
|
|
$TEXT = str_replace('L_PARgr', '(',$TEXT);
|
|
$TEXT = str_replace('R_PARgr', ')',$TEXT);
|
|
}
|
|
/*
|
|
Restructure numbered syntax highlighting 13/09/2019
|
|
*/
|
|
$TEXT = preg_replace_callback("#<code\s+(\w+)>.*?(\[enable_line_numbers.*?\])\s*\*\/#ms",
|
|
function($matches) {
|
|
return '<code ' . $matches[1] .' ' . $matches[2] .'>';
|
|
}, $TEXT
|
|
) ;
|
|
|
|
$this->replace_entities();
|
|
/*Remove urls from linkonly images inserted after second and additional saves, resulting in multiple urls corrupting HTML output */
|
|
$TEXT = preg_replace("/\{\{http:\/\/.*?fetch.php\?media=(.*?linkonly.*?)\}\}/",'{{' . "$1" .'}}',$TEXT);
|
|
$TEXT = str_replace('< nowiki >', '%%<nowiki>%%',$TEXT);
|
|
|
|
|
|
$TEXT = preg_replace_callback(
|
|
'#\[\[(.*?)\]\]#ms',
|
|
function($matches){
|
|
if($this->helper->has_plugin('button') && strpos($matches[0], '[[{') === 0) {
|
|
return $matches[0];
|
|
}
|
|
if(preg_match('/[\w\.]+\s*>/',$matches[0])) {
|
|
return $matches[0];
|
|
}
|
|
if(preg_match('/([\w\.\-]+@[\w\.\-]+\.\w{2,3})\?.*?\|\1/i',$matches[0])) {
|
|
return $matches[0];
|
|
}
|
|
global $ID, $conf;
|
|
$qs = "";
|
|
if(preg_match("/\[\[http/",$matches[0])) return $matches[0]; //not an internal link
|
|
if(preg_match("#\[\[.*?\|\{\{.*?\}\}\]\]#", $matches[0],$matches_1)) { // media file
|
|
if(!$this->getConf('rel_links')) {
|
|
return $matches[0];
|
|
}
|
|
$link = explode('?',$matches[1]);
|
|
list($link_id,$linktext) = explode('|', $link[0]);
|
|
$current_id = $this->abs2rel($link_id,$ID);
|
|
return preg_replace("#$link_id#",$current_id, $matches[0]);
|
|
}
|
|
|
|
$link = explode('?',$matches[1]);
|
|
if($link[1]) {
|
|
$link_id = $link[0];
|
|
list($qs,$linktext) = explode('|', $link[1]);
|
|
}
|
|
else list($link_id,$linktext) = explode('|', $link[0]);
|
|
if($this->getConf('rel_links'))
|
|
$current_id = $this->abs2rel($link_id,$ID);
|
|
else $current_id = $link_id;
|
|
if($qs) $current_id .= "?$qs";
|
|
|
|
//as in _getLinkTitle in xhtml.php
|
|
if(useHeading('content')) {
|
|
$tmp_linktext = p_get_first_heading($link_id);
|
|
if(trim($linktext) == trim($tmp_linktext)) {
|
|
$linktext = "";
|
|
}
|
|
}
|
|
$tmp_ar = explode(':',$link_id);
|
|
$tmp_id = array_pop($tmp_ar);
|
|
if(!useHeading('content') && (trim($linktext,'.: ' ) == trim($tmp_id,'.: ')))
|
|
$linktext = "";
|
|
|
|
$current_id = $current_id.'|'.$linktext;
|
|
return '[[' . $current_id .']]';
|
|
},
|
|
$TEXT
|
|
);
|
|
|
|
if($this->getConf('rel_links')) {
|
|
$TEXT = preg_replace_callback(
|
|
'#\{\{(\s*)(.*?)(\s*)\}\}#ms',
|
|
function($matches) {
|
|
global $ID;
|
|
$link = explode('?',$matches[2]);
|
|
list($link_id,$linktext) = explode('|', $link[0]);
|
|
$rel = $this->abs2rel($link_id,$ID);
|
|
if(!empty($link[1])) $rel .= '?' . $link[1];
|
|
if(!empty($linktext)) $rel = $rel.'|'.$linktext;
|
|
return '{{' .$matches[1] . $rel . $matches[3] .'}}';
|
|
},
|
|
$TEXT
|
|
);
|
|
}
|
|
|
|
/* 11 Dec 2013 see comment below
|
|
Remove discarded font syntax
|
|
*/
|
|
$TEXT = preg_replace_callback(
|
|
'|_REMOVE_FONTS_START_(.*?)_REMOVE_FONTS_END_|ms',
|
|
create_function(
|
|
'$matches',
|
|
'$matches[1] = preg_replace("/<font.*?>/ms","",$matches[1]);
|
|
return preg_replace("/<\/font>/ms","",$matches[1]);'
|
|
),
|
|
$TEXT
|
|
);
|
|
|
|
/*
|
|
6 April 2013
|
|
Removed newlines and spaces from beginnings and ends of text enclosed by font tags. Too subtle for javascript.
|
|
*/
|
|
$TEXT = preg_replace_callback(
|
|
'|(<font.*?>)(.*?)(?=</font>)|ms',
|
|
create_function(
|
|
'$matches',
|
|
'$matches[2]=preg_replace("/^\s+/ms","",$matches[2]);
|
|
$matches[2]=preg_replace("/\s+$/ms","",$matches[2]);
|
|
return $matches[1]. $matches[2];'
|
|
),
|
|
$TEXT
|
|
);
|
|
/* insure space before and after ckgedit font oprning and closing tags*/
|
|
$TEXT = preg_replace("/<font.*?>\s+<\/font>/","", $TEXT);
|
|
$TEXT = preg_replace("/<font/ms"," <font", $TEXT); // add space
|
|
$TEXT = preg_replace("/<\/font>/ms","</font> ", $TEXT);
|
|
$TEXT = preg_replace('/\s{2,}<font/ms',' <font',$TEXT); // remove duplicate spaces
|
|
$TEXT = preg_replace('/font>{2,}/ms',' font> ',$TEXT);
|
|
|
|
$TEXT = preg_replace('/__QUOTE__/ms',">",$TEXT);
|
|
$TEXT = preg_replace('/[\t\x20]+$/ms',"",$TEXT);
|
|
$TEXT = preg_replace('/\n{4,}/ms',"\n\n",$TEXT);
|
|
$TEXT = preg_replace('/\n{3,}/ms',"\n\n",$TEXT);
|
|
|
|
/*first pass for blockquotes*/
|
|
$TEXT = preg_replace_callback(
|
|
"#^>+(.*?)\\\\\\\\#ms",
|
|
function($matches) {
|
|
return str_replace('\\',"",$matches[0]);
|
|
},
|
|
$TEXT
|
|
);
|
|
|
|
/* remove extra line-feeds following in-table code blocks
|
|
make sure cell-ending pipe not mistaken for a following link divider
|
|
*/
|
|
$TEXT = preg_replace_callback(
|
|
'#(/code|/file)\>.*?\n\|#ms',
|
|
function($matches) {
|
|
$matches[0] = preg_replace("/([\S\s\w\:])\\\\\\\\(\w)/ms","$1@#@$2",$matches[0]); //retain backslashes inside code blocks
|
|
$matches[0] = preg_replace("/(\w+)\\\\\\\\(\w)/ms","$1@#@",$matches[0]);
|
|
$matches[0] = preg_replace("/\\\\(\w+)/ms","@!@$1",$matches[0]);
|
|
$matches[0] = preg_replace("/(\w+)\\\\/ms","@!@$1",$matches[0]);
|
|
$matches[0] = str_replace("\\", "",$matches[0]);
|
|
$matches[0] = str_replace("@!@",'\\',$matches[0]);
|
|
return str_replace("@#@", "\\\\",$matches[0]);
|
|
},
|
|
$TEXT
|
|
);
|
|
/* reformat table cell after removing extra line-feeds, above */
|
|
$TEXT = preg_replace_callback(
|
|
'#\|[\s\n]+(\<file.*?\>)(.*?)(\<\/file>\s*.*?)\n?\|#ms',
|
|
function($matches) {
|
|
//$ret = '</' . $matches[1] . '>' . str_replace('\\',"",$matches[2]) . '|';
|
|
$matches[3] = preg_replace('/\n+/',"",$matches[3] );
|
|
$matches[3] = preg_replace('/\s+$/',"",$matches[3] ) . '|';
|
|
return '|' . $matches[1] . $matches[2] . str_replace("\\ ","",$matches[3]);
|
|
},
|
|
$TEXT
|
|
);
|
|
|
|
|
|
/* Feb 23 2019
|
|
remove spaces and line feeds between beginning of table cell and start of code block
|
|
*/
|
|
$TEXT = preg_replace_callback(
|
|
'#\|(.*?)[\s\n]+\<(code|file)\>#ms',
|
|
function($matches) {
|
|
return '|' . $matches[1] ."\n<". $matches[2] .'>' . "\n";
|
|
},$TEXT
|
|
);
|
|
/*remove line feeds following block */
|
|
$TEXT = preg_replace_callback(
|
|
'#\<\/(code|file)\>([^\w\|]+)#ms',
|
|
function($matches) {
|
|
$matches[2] = str_replace(':\\', '~~WIN__DIR~~',$matches[2]);
|
|
$matches[2] = preg_replace('#([\w;.:=\:])\\\\#ms', "$1_bSL_",$matches[2]); //protect backslashes in Windows paths
|
|
$ret = '</' . $matches[1] . '>' . str_replace("\\","",$matches[2]);
|
|
$ret = str_replace( '_bSL_', '\\',$ret);
|
|
$ret = str_replace( '~~WIN__DIR~~', ':\\',$ret);
|
|
return "\n" .$ret;
|
|
},$TEXT
|
|
);
|
|
$TEXT = str_replace('CBL__Bksl','\\',$TEXT);
|
|
$TEXT = preg_replace("/<code\s+file/ms",'<code ',$TEXT);
|
|
|
|
$TEXT = preg_replace('#((\\\\){2}\s*)$#', "",$TEXT);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
function replace_entities() {
|
|
global $TEXT;
|
|
global $ents;
|
|
$serialized = FCK_ACTION_SUBDIR . 'ent.ser';
|
|
$ents = unserialize(file_get_contents($serialized));
|
|
|
|
$TEXT = preg_replace_callback(
|
|
'|(&(\w+);)|',
|
|
create_function(
|
|
'$matches',
|
|
'global $ents; return $ents[$matches[2]];'
|
|
),
|
|
$TEXT
|
|
);
|
|
|
|
}
|
|
|
|
|
|
function write_debug($data) {
|
|
return;
|
|
if (!$handle = fopen('save.txt', 'a')) {
|
|
return;
|
|
}
|
|
|
|
// Write $somecontent to our opened file.
|
|
fwrite($handle, "save.php: $data\n");
|
|
fclose($handle);
|
|
|
|
}
|
|
/* @auth Sergey Kotov */
|
|
//linkPath is the link in the page
|
|
//pagePath is absolute path of the page (ns1:ns2:....:page or :ns1:ns2:....:page)
|
|
function abs2rel($linkPath,$pagePath){
|
|
if ($linkPath[0]==='.'){
|
|
// It's already relative
|
|
return $linkPath;
|
|
}
|
|
$aLink=explode(':',$linkPath);
|
|
$nLink=count($aLink);
|
|
if ($nLink<2){
|
|
return $linkPath;
|
|
}
|
|
$aPage=explode(':',$pagePath);
|
|
if(empty($aLink[0])) {
|
|
// If linkPath is started by ':'
|
|
// Make canonical absolute path ns1:ns2:.....:pageLink (strip leading :)
|
|
array_shift($aLink);
|
|
if (--$nLink<2) {
|
|
return $linkPath;
|
|
}
|
|
}
|
|
|
|
if(empty($aPage[0])) {
|
|
// If pagePath is started by ':'
|
|
// Make canonical absolute path ns1:ns2:.....:page (strip leading :)
|
|
array_shift($aPage);
|
|
}
|
|
$nPage=count($aPage);
|
|
$nslEqual=0; // count of equal namespaces from left to right
|
|
// Minimal length of these two arrays, page name is not included
|
|
$nMin=($nLink<$nPage ? $nLink : $nPage)-1 ;
|
|
for ($i=0;$i<$nMin;++$i){
|
|
if ($aLink[$i]===$aPage[$i]){
|
|
++$nslEqual;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
if ($nslEqual==0){
|
|
// Link and page from different root namespaces
|
|
return $linkPath;
|
|
}
|
|
// Truncate equal lef namespaces
|
|
$aPageDiff=array_slice($aPage,$nslEqual);
|
|
$nPageDiff=count($aPageDiff);
|
|
$aLinkDiff=array_slice($aLink,$nslEqual);
|
|
|
|
// Now we have to go up to nPageDiff-1 levels
|
|
$aResult=array();
|
|
if ($nPageDiff>1){
|
|
$aResult=array_fill(0,$nPageDiff-1,'..');
|
|
}
|
|
else if($nPageDiff == 1) {
|
|
$aResult[] = '.';
|
|
}
|
|
$aResult=array_merge($aResult,$aLinkDiff);
|
|
return implode(':', $aResult);
|
|
}
|
|
|
|
|
|
} //end of action class
|
|
?>
|