function do_post_savepage($formatter, $options) { global $DBInfo; if ($_SERVER['REQUEST_METHOD'] != 'POST' || !$DBInfo->security->writable($options)) { $options['title'] = _("Page is not writable"); $options['button_preview'] = 1; // force preview } if (isset($_FILES['upfile']) and is_array($_FILES) or isset($options['MYFILES']) and is_array($options['MYFILES'])) { $retstr = false; $options['retval'] =& $retstr; include_once 'plugin/UploadFile.php'; do_uploadfile($formatter, $options); } $savetext = $options['savetext']; $datestamp = $options['datestamp']; $hash = $options['hash']; $button_preview = !empty($options['button_preview']) ? 1 : 0; if ($button_preview) { $formatter->preview = 1; } $button_merge = !empty($options['button_merge']) ? 1 : 0; $button_merge = !empty($options['manual_merge']) ? 2 : $button_merge; $button_merge = !empty($options['force_merge']) ? 3 : $button_merge; $button_diff = !empty($options['button_changes']) ? 1 : 0; if ($button_diff) { $button_preview = 1; } $savetext = preg_replace("/\r\n|\r/", "\n", $savetext); $savetext = _stripslashes($savetext); $comment = _stripslashes($options['comment']); $comment = trim($comment); $section_savetext = ''; if (isset($options['section'])) { if ($formatter->page->exists()) { $sections = _get_sections($formatter->page->get_raw_body()); if ($sections[$options['section']]) { if (substr($savetext, -1) != "\n") { $savetext .= "\n"; } $sections[$options['section']] = $savetext; } $section_savetext = $savetext; $savetext = implode('', $sections); } } if ($savetext and $savetext[strlen($savetext) - 1] != "\n") { $savetext .= "\n"; } $new = md5($savetext); $menu = $formatter->link_to("#editor", _("Goto Editor"), ' class="preview-anchor"'); $diff = ''; if ($formatter->page->exists()) { # check difference $body = $formatter->page->get_raw_body(); $body = preg_replace("/\r\n|\r/", "\n", $body); $orig = md5($body); if ($orig == $new) { // same text. just update datestamp unset($options['datestamp']); $datestamp = $formatter->page->mtime(); } # check datestamp if ($formatter->page->mtime() > $datestamp) { $options['msg'] = sprintf(_("Someone else saved the page while you edited %s"), $formatter->link_tag($formatter->page->urlname, "", _html_escape($options['page']))); $options['preview'] = 1; $options['conflict'] = 1; if ($button_merge) { $options['msg'] = sprintf(_("%s is merged with latest contents."), $formatter->link_tag($formatter->page->urlname, "", _html_escape($options['page']))); $options['title'] = sprintf(_("%s is merged successfully"), _html_escape($options['page'])); $merge = $formatter->get_merge($savetext); if (preg_grep('/^<<<<<<<$/', explode("\n", $merge))) { $options['conflict'] = 2; $options['title'] = sprintf(_("Merge conflicts are detected for %s !"), _html_escape($options['page'])); $options['msg'] = sprintf(_("Merge cancelled on %s."), $formatter->link_tag($formatter->page->urlname, "", _html_escape($options['page']))); $merge = preg_replace('/^>>>>>>>$/m', "=== /!\\ >>>>>>> " . _("NEW") . ' ===', $merge); $merge = preg_replace('/^<<<<<<<$/m', "=== /!\\ <<<<<<< " . _("OLD") . ' ===', $merge); $merge = preg_replace('/^=======$/m', "=== ======= ===", $merge); if ($button_merge > 1) { unset($options['datestamp']); unset($options['section']); unset($section_savetext); $datestamp = $formatter->page->mtime(); $options['conflict'] = 0; if ($button_merge == 2) { $options['title'] = sprintf(_("Get merge conflicts for %s"), _html_escape($options['page'])); $options['msg'] = sprintf(_("Please resolve conflicts manually.")); if ($merge) { $savetext = $merge; } } else { $options['title'] = sprintf(_("Force merging for %s !"), _html_escape($options['page'])); $options['msg'] = sprintf(_("Please be careful, you could damage useful information.")); } } } else { $options['conflict'] = 0; if ($merge) { // successfully merged. reset datestamp $savetext = $merge; unset($options['datestamp']); $datestamp = $formatter->page->mtime(); } } $button_preview = 1; } else { $options['title'] = _("Conflict error!"); $button_preview = 1; } if ($options['conflict'] and !empty($merge)) { $diff = $formatter->get_diff($merge); } else { $diff = $formatter->get_diff($savetext); } // get diff } else { if ($datestamp > time()) { $options['msg'] = sprintf(_("Go back or return to %s"), $formatter->link_tag($formatter->page->urlname, "", _html_escape($options['page']))); $formatter->send_header("", $options); $formatter->send_title(_("Invalid access"), "", $options); $formatter->send_footer(); return; } else { if (!empty($DBInfo->use_savepage_hash)) { // check hash $ticket = getTicket($datestamp . $DBInfo->user->id, $_SERVER['REMOTE_ADDR']); if ($hash != md5($ticket)) { $formatter->send_header("", $options); $formatter->send_title(_("Invalid access"), "", $options); $formatter->send_footer(); return; } } } } } if (empty($button_preview) && !empty($orig) && $orig == $new) { $options['msg'] = sprintf(_("Go back or return to %s"), $formatter->link_tag($formatter->page->urlname, "", _html_escape($options['page']))); $formatter->send_header("", $options); $formatter->send_title(_("No difference found"), "", $options); $formatter->send_footer(); return; } if ($comment && (function_exists('mb_strlen') and mb_strlen($comment, $DBInfo->charset) > 256) or strlen($comment) > 256) { //$options['msg']=sprintf(_("Go back or return to %s"),$formatter->link_tag($formatter->page->urlname,"",_html_escape($options['page']))); $options['title'] = _("Too long Comment"); $button_preview = 1; } // XXX captcha $use_any = 0; if (!empty($DBInfo->use_textbrowsers)) { if (is_string($DBInfo->use_textbrowsers)) { $use_any = preg_match('/' . $DBInfo->use_textbrowsers . '/', $_SERVER['HTTP_USER_AGENT']) ? 1 : 0; } else { $use_any = preg_match('/Lynx|w3m|links/', $_SERVER['HTTP_USER_AGENT']) ? 1 : 0; } } $ok_ticket = 0; if (!$button_preview and !$use_any and !empty($DBInfo->use_ticket) and $options['id'] == 'Anonymous') { if ($options['__seed'] and $options['check']) { $mycheck = getTicket($options['__seed'], $_SERVER['REMOTE_ADDR'], 4); if ($mycheck == $options['check']) { $ok_ticket = 1; } else { $options['msg'] = _("Invalid ticket !"); $button_preview = 1; } } else { if (!$button_preview) { $options['msg'] = _("You need a ticket !"); } $button_preview = 1; } } else { $ok_ticket = 1; } // XXX if (!$button_preview and $DBInfo->spam_filter) { $text = $savetext; $fts = preg_split('/(\\||,)/', $DBInfo->spam_filter); foreach ($fts as $ft) { $text = $formatter->filter_repl($ft, $text, $options); } if ($text != $savetext) { $button_preview = 1; $options['msg'] = _("Sorry, can not save page because some messages are blocked in this wiki."); } else { if ($options['id'] == 'Anonymous' and !empty($comment) and !empty($DBInfo->spam_comment_filter)) { // comment filter for anonymous users $cmt = $comment; $fts = preg_split('/(\\||,)/', $DBInfo->spam_comment_filter); // bad comments file $options['.badcontents'] = !empty($DBInfo->comments_badcontents) ? $DBInfo->comments_badcontents : null; foreach ($fts as $ft) { $cmt = $formatter->filter_repl($ft, $cmt, $options); } if ($cmt != $comment) { $button_preview = 1; $options['msg'] = _("Sorry, can not save page because some messages are blocked in this wiki."); } } } } $formatter->page->set_raw_body($savetext); // check license agreement $ok_agreement = true; if (!empty($DBInfo->use_agreement)) { if ($options['id'] != 'Anonymous') { $ok_agreement = !empty($DBInfo->user->info['join_agreement']) && $DBInfo->user->info['join_agreement'] == 'agree'; if ($ok_agreement && !empty($DBInfo->agreement_version)) { $ok_agreement = $DBInfo->user->info['join_agreement_version'] == $DBInfo->agreement_version; } } else { $ok_agreement = false; } } if (empty($button_preview) && !$ok_agreement && empty($options['license_agree'])) { $button_preview = 1; if ($options['id'] == 'Anonymous') { $options['msg'] = _("Anonymous user have to agree the contribution agreement for this wiki."); } else { $options['msg'] = _("Sorry, you have to agree the contribution agreement or the join agreement of this wiki."); } } // check full permission to edit $full_permission = true; if (!empty($DBInfo->no_full_edit_permission) or $options['id'] == 'Anonymous' && !empty($DBInfo->anonymous_no_full_edit_permission)) { $full_permission = false; } // members always have full permission to edit if (in_array($options['id'], $DBInfo->members)) { $full_permission = true; } $minorfix = false; $options['editinfo'] = array(); if (!$full_permission || !empty($DBInfo->use_abusefilter)) { // get diff if (!isset($diff[0])) { $diff = $formatter->get_diff($savetext); } // get total line numbers // test \n or \r or \r\n $crlf = "\n"; if (preg_match("/(\r|\r\n|\n)\$/", $body, $match)) { $crlf = $match[1]; } // count crlf $nline = substr_count($body, $crlf); // count diff lines, chars $changes = diffcount_lines($diff, $DBInfo->charset); // set return values $added = $changes[0]; $deleted = $changes[1]; $added_chars = $changes[2]; $deleted_chars = $changes[3]; // check minorfix $minorfix = $changes[4]; $editinfo = array('add_lines' => $added, 'del_lines' => $deleted, 'add_chars' => $added_chars, 'del_chars' => $deleted_chars); $options['editinfo'] = $editinfo; if (!$button_diff) { $diff = ''; } } if (!$full_permission) { $restricted = false; $delete_lines_restricted_ratio = !empty($DBInfo->allowed_max_lines_delete_ratio) ? $DBInfo->allowed_max_lines_delete_ratio : 0.5; if ($deleted > 0 && $deleted / $nline > $delete_lines_restricted_ratio) { $restricted = true; } // check the maximum number of characters allowed to add/delete $max_chars_add = !empty($DBInfo->allowed_max_chars_add) ? $DBInfo->allowed_max_chars_add : 300; $max_chars_del = !empty($DBInfo->allowed_max_chars_delete) ? $DBInfo->allowed_max_chars_delete : 180; if (!$restricted && ($added_chars > $max_chars_add || $deleted_chars > $max_chars_del)) { $restricted = true; } if ($restricted) { $options['title'] = _("You do not have full permission to edit this page on this wiki."); if ($options['id'] == 'Anonymous') { $options['msg'] = _("Anonymous user is restricted to delete a lot amount of page on this wiki."); } else { $options['msg'] = _("You are restricted to delete a lot amount of page on this wiki."); } $button_preview = true; } } if ($button_preview) { if (empty($options['title'])) { $options['title'] = sprintf(_("Preview of %s"), _html_escape($options['page'])); } // http://stackoverflow.com/questions/1547884 $header = ''; if (!empty($DBInfo->preview_no_xss_protection)) { $header = 'X-XSS-Protection: 0'; } $formatter->send_header($header, $options); $formatter->send_title("", "", $options); $options['preview'] = 1; $options['datestamp'] = $datestamp; $savetext = $section_savetext ? $section_savetext : $savetext; $options['savetext'] = $savetext; $formatter->preview = 1; $has_form = false; $options['has_form'] =& $has_form; $options['.minorfix'] = $minorfix; print '<div id="editor_area_wrap">' . macro_EditText($formatter, '', $options); echo $formatter->get_javascripts(); if ($has_form and !empty($DBInfo->use_jsbuttons)) { $msg = _("Save"); $onclick = ' onclick="submit_all_forms()"'; $onclick1 = ' onclick="check_uploadform(this)"'; echo "<div id='save-buttons'>\n"; echo "<button type='button'{$onclick} tabindex='10'><span>{$msg}</span></button>\n"; echo "<button type='button'{$onclick1} tabindex='11' name='button_preview' value='1'><span>" . _("Preview") . '</span></button>'; if ($formatter->page->exists()) { echo "\n<button type='button'{$onclick1} tabindex='12' name='button_changes' value='1'><span>" . _("Show changes") . '</span></button>'; } if ($button_preview) { echo ' ' . $formatter->link_to('#preview', _("Skip to preview"), ' class="preview-anchor"'); } echo "</div>\n"; } print '</div>'; # XXX print $DBInfo->hr; print $menu; if ($button_diff and !isset($diff[0])) { $diff = $formatter->get_diff($options['section'] ? implode('', $sections) : $savetext); // get diff // strip diff header if (($p = strpos($diff, '@@')) !== false) { $diff = substr($diff, $p); } } if (isset($diff[0])) { echo "<div id='wikiDiffPreview'>\n"; echo $formatter->processor_repl('diff', $diff, $options); //echo $formatter->macro_repl('Diff','',array('text'=>$diff,'type'=>'fancy')); echo "</div>\n"; } print "<div id='wikiPreview'>\n"; #$formatter->preview=1; $formatter->send_page($savetext); $formatter->preview = 0; print $DBInfo->hr; print "</div>\n"; print $menu; } else { // check minorfix $options['.minorfix'] = $minorfix; if (empty($DBInfo->use_autodetect_minoredit)) { unset($options['.minorfix']); } if (!empty($options['category'])) { $savetext .= "----\n[[" . $options['category'] . "]]\n"; } $options['minor'] = !empty($DBInfo->use_minoredit) ? $options['minor'] : 0; if ($options['minor']) { $user = $DBInfo->user; # get from COOKIE VARS if ($DBInfo->owners and in_array($user->id, $DBInfo->owners)) { $options['minor'] = 1; } else { $options['minor'] = 0; } } $formatter->page->write($savetext); $retval = array(); $options['retval'] =& $retval; $ret = $DBInfo->savePage($formatter->page, $comment, $options); if ($ret != -1 and $DBInfo->notify and $options['minor'] != 1) { $options['noaction'] = 1; if (!function_exists('mail')) { $options['msg'] = sprintf(_("mail does not supported by default.")) . "<br />"; } else { $ret2 = wiki_notify($formatter, $options); if ($ret2) { $options['msg'] = sprintf(_("Sent notification mail.")) . "<br />"; } else { $options['msg'] = sprintf(_("No subscribers found.")) . "<br />"; } } } if ($ret == -1) { if (!empty($options['retval']['msg'])) { $msg = $options['retval']['msg']; } else { $msg = sprintf(_("%s is not editable"), $formatter->link_tag($formatter->page->urlname, "", _html_escape($options['page']))); } $options['title'] = $msg; } else { $options['title'] = sprintf(_("%s is saved"), $formatter->link_tag($formatter->page->urlname, "?action=show", _html_escape($options['page']))); } $myrefresh = ''; if (!empty($DBInfo->use_save_refresh)) { $lnk = $formatter->link_url($formatter->page->urlname, "?action=show"); if (!empty($options['section'])) { $lnk .= '#sect-' . $options['section']; } if ($DBInfo->use_save_refresh > 0 || $ret == -1) { $sec = $DBInfo->use_save_refresh - 1; if ($sec < 0) { $sec = 3; } $myrefresh = 'Refresh: ' . $sec . '; url=' . qualifiedURL($lnk); } else { $myrefresh = array('Status: 302', 'Location: ' . qualifiedURL($lnk)); } } $formatter->send_header($myrefresh, $options); if (is_array($myrefresh)) { return; } $formatter->send_title("", "", $options); $opt['pagelinks'] = 1; $opt['refresh'] = 1; $formatter->page->pi = null; // call get_instruction() again # re-generates pagelinks print "<div id='wikiContent'>\n"; $formatter->send_page("", $opt); print "</div>\n"; } $args['editable'] = 0; $formatter->send_footer($args, $options); }
function _savePage($pagename, $body, $options = array()) { $keyname = $this->_getPageKey($pagename); $filename = $this->text_dir . '/' . $keyname; $dir = dirname($filename); if (!is_dir($dir)) { $om = umask(~$this->umask); _mkdir_p($dir, 0777); umask($om); } $is_new = false; if (!file_exists($filename)) { $is_new = true; } $fp = @fopen($filename, "a+b"); if (!is_resource($fp)) { return -1; } flock($fp, LOCK_EX); // XXX ftruncate($fp, 0); fwrite($fp, $body); flock($fp, LOCK_UN); fclose($fp); $ret = 0; if (!empty($this->version_class)) { $om = umask(~$this->umask); $ver = $this->lazyLoad('version', $this); // get diff if (!$is_new) { $diff = $ver->diff($pagename); // count diff lines, chars $changes = diffcount_lines($diff, $this->charset); // set return values $retval =& $options['retval']; $retval['add'] = $changes[0]; $retval['del'] = $changes[1]; $retval['add_chars'] = $changes[2]; $retval['del_chars'] = $changes[3]; } else { // new file. // set return values $retval =& $options['retval']; $retval['add'] = get_file_lines($filename); $retval['del'] = 0; $retval['add_chars'] = mb_strlen($body, $this->charset); $retval['del_chars'] = 0; } $force = $is_new || $options['.force']; // FIXME fix for revert+create cases for clear if ($is_new && preg_match('@;;{REVERT}@', $options['log'])) { $tmp = preg_replace('@;;{REVERT}:@', ';;{CREATE}{REVERT}:', $options['log']); if ($tmp !== null) { $options['log'] = $tmp; } } $ret = $ver->_ci($filename, $options['log'], $force); if ($ret == -1) { $options['retval']['msg'] = _("Fail to save version information"); } chmod($filename, 0666 & $this->umask); umask($om); } return $ret; }