Rev 1372 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php////////////////////////////////////////////////////////////////////////////////// //// Copyright (C) 2006 Phorum Development Team //// http://www.phorum.org //// //// This program is free software. You can redistribute it and/or modify //// it under the terms of either the current Phorum License (viewable at //// phorum.org) or the Phorum License that was distributed with this file //// //// 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. //// //// You should have received a copy of the Phorum License //// along with this program. //////////////////////////////////////////////////////////////////////////////////// This script can initially be called in multiple ways to indicate what// type of posting mode will be used. The parameters are://// 1) The forum id.//// 2) The mode to use. Possibilities are://// - post Post a new message (default if no mode is issued)// - edit User edit of an already posted message// - moderation Moderator edit of an already posted message// - reply Reply to a message// - quote Reply to a message, with quoting of the original message//// 3) If edit, moderation or reply is used: the message id.//// Examples:// http://yoursite/phorum/posting.php?10,quote,15// http://yoursite/phorum/posting.php?10,edit,20// http://yoursite/phorum/posting.php?10,post//// This script can also be included in another page (for putting the editor// screen inline in a page), by setting up the $PHORUM["postingargs"] before// including://// $PHORUM["postingargs"]["as_include"] any true value, to flag included state// $PHORUM["postingargs"][0] the forum id// $PHORUM["postingargs"][1] the mode to use (post,reply,quote,edit,moderation)// $PHORUM["postingargs"][2] the message id to work with (omit for "post")//// ----------------------------------------------------------------------// Basic setup and checks// ----------------------------------------------------------------------if (! defined('phorum_page')) {define('phorum_page', 'post');}include_once("./common.php");include_once("include/format_functions.php");// Check if the Phorum is in read-only mode.if(isset($PHORUM["status"]) && $PHORUM["status"]=="read-only"){phorum_build_common_urls();$PHORUM["DATA"]["MESSAGE"] = $PHORUM["DATA"]["LANG"]["ReadOnlyMessage"];// Only show header and footer when not included in another page.if (phorum_page == "post") {include phorum_get_template("header");phorum_hook("after_header");}include phorum_get_template("message");if (phorum_page == "post") {phorum_hook("before_footer");include phorum_get_template("footer");}return;}// No forum id was set. Take the user back to the index.if(empty($PHORUM["forum_id"])){$dest_url = phorum_get_url(PHORUM_INDEX_URL);phorum_redirect_by_url($dest_url);exit();}// Somehow we got to a folder in posting.php. Take the// user back to the folder.if($PHORUM["folder_flag"]){$dest_url = phorum_get_url(PHORUM_INDEX_URL, $PHORUM["forum_id"]);phorum_redirect_by_url($dest_url);exit();}// ----------------------------------------------------------------------// Definitions// ----------------------------------------------------------------------// A list of valid posting modes.$valid_modes = array("post", // Post a new message"reply", // Post a reply to a message"quote", // Post a reply with quoting of the message replied to"edit", // Edit a message"moderation", // Edit a message in moderator modus);// Configuration that we use for fields that we use in the editor form.// Format for the array elements:// [0] The type of field (string, integer, boolean, array).// [1] Whether the value must be included as a hidden form field// if the field is read-write flagged. So this is used for// identifying values which are always implemented as a// hidden form fields.// [2] Whether the field is read-only or not. Within the editing process,// this parameter can be changed to make the field writable.// (for example if a moderator is editing a message).// [3] A default value to initialize the form field with.//$PHORUM["post_fields"] = array("message_id" => array("integer", true, true, 0),"user_id" => array("integer", true, true, 0),"datestamp" => array("string", true, true, ''),"status" => array("integer", false, true, 0),"author" => array("string", false, true, ''),"email" => array("string", false, true, ''),"subject" => array("string", false, false, ''),"body" => array("string", false, false, ''),"forum_id" => array("integer", true, true, $PHORUM["forum_id"]),"thread" => array("integer", true, true, 0),"parent_id" => array("integer", true, true, 0),"allow_reply" => array("boolean", false, true, 1),"special" => array("string", false, true, ''),"email_notify" => array("boolean", false, false, 0),"show_signature" => array("boolean", false, false, 0),"attachments" => array("array", true, true, array()),"meta" => array("array", true, true, array()),"thread_count" => array("integer", true, true, 0),"mode" => array("string", true, true, ''),);// Indices for referencing the fields in $post_fields.define("pf_TYPE", 0);define("pf_HIDDEN", 1);define("pf_READONLY", 2);define("pf_INIT", 3);// Definitions for a clear $apply_readonly parameter in// the function phorum_posting_merge_db2form().define("ALLFIELDS", false);define("READONLYFIELDS", true);// ----------------------------------------------------------------------// Gather information about the editor state and start processing// ----------------------------------------------------------------------// Is this an initial request?$initial = ! isset($_POST["message_id"]);// Is finish, cancel of preview clicked?$finish = (! $initial && isset($_POST["finish"]));$cancel = (! $initial && isset($_POST["cancel"]));$preview = (! $initial && isset($_POST["preview"]));// Do we already have postingargs or do we use the global args?if (! isset($PHORUM["postingargs"])) {$PHORUM["postingargs"] = $PHORUM["args"];}// Find out what editing mode we're running in.if ($initial) {$mode = isset($PHORUM["postingargs"][1]) ? $PHORUM["postingargs"][1] : "post";// Quote may also be passed as a phorum parameter (quote=1).if ($mode == "reply" && isset($PHORUM["postingargs"]["quote"]) && $PHORUM["postingargs"]["quote"]) {$mode = "quote";}} else {if (! isset($_POST["mode"])) {die("Missing parameter \"mode\" in request");}$mode = $_POST["mode"];}if (! in_array($mode, $valid_modes)) {die("Illegal mode issued: $mode");}// Find out if we are attaching or detaching something.// For detaching $do_detach will be set to the attachment's file_id.$do_detach = false;$do_attach = false;foreach ($_POST as $var => $val) {if (substr($var, 0, 7) == "detach:") {$do_detach = substr($var, 7);} elseif ($var == "attach") {$do_attach = true;}}// In case users click on post or preview, without uploading// their attachment first, we fake an upload action.if (count($_FILES)) {list($name, $data) = each($_FILES);if ($data["size"]) $do_attach = true;reset($_FILES);}// Set all our URL'sphorum_build_common_urls();$PHORUM["DATA"]["URL"]["ACTION"] = phorum_get_url(PHORUM_POSTING_URL);// Keep track of errors.$error_flag = false;$PHORUM["DATA"]["MESSAGE"] = null;$PHORUM["DATA"]["ERROR"] = null;// Do things that are specific for first time or followup requests.if ($initial) {include("./include/posting/request_first.php");} else {include("./include/posting/request_followup.php");}// Store the posting mode in the form parameters, so we can remember// the mode throughout the editing cycle (for example to be able to// create page titles which match the editing mode).$PHORUM["DATA"]["MODE"] = $mode;// ----------------------------------------------------------------------// Permission and ability handling// ----------------------------------------------------------------------// Make a descision on what posting mode we're really handling, based on// the data that we have. The posting modes "reply" and "quote" will// both be called "reply" from here. Modes "edit" and "moderation" will// be called "edit" from here. The exact editor behaviour for editing is// based on the user's permissions, not on posting mode.$mode = "post";if ($message["message_id"]) {$mode = "edit";} elseif ($message["parent_id"]) {$mode = "reply";}// Do ban list checks. Only check the bans on entering and// on finishing up. No checking is needed on intermediate requests.if (! $error_flag && ($initial || $finish || $preview)) {include("./include/posting/check_banlist.php");}// Determine the abilities that the current user has.if (! $error_flag){// Is the forum running in a moderated state?$PHORUM["DATA"]["MODERATED"] =$PHORUM["moderation"] == PHORUM_MODERATE_ON &&!phorum_user_access_allowed(PHORUM_USER_ALLOW_MODERATE_MESSAGES);// Does the user have administrator permissions?$PHORUM["DATA"]["ADMINISTRATOR"] = $PHORUM["user"]["admin"];// Does the user have moderator permissions?$PHORUM["DATA"]["MODERATOR"] =phorum_user_access_allowed(PHORUM_USER_ALLOW_MODERATE_MESSAGES);// Ability: Do we allow attachments?$PHORUM["DATA"]["ATTACHMENTS"] = $PHORUM["max_attachments"] > 0 && phorum_user_access_allowed(PHORUM_USER_ALLOW_ATTACH);$PHORUM["DATA"]["EMAILNOTIFY"] =(isset($PHORUM['allow_email_notify']) && !empty($PHORUM['allow_email_notify']))? 1 : 0;// What special options can this user set for a message?$PHORUM["DATA"]["OPTION_ALLOWED"] = array("sticky" => false, // Sticky flag for message sorting"announcement" => false, // Announcement flag for message sorting"allow_reply" => false, // Wheter replies are allowed in the thread);// For moderators and administrators.if (($PHORUM["DATA"]["MODERATOR"] || $PHORUM["DATA"]["ADMINISTRATOR"]) && $message["parent_id"] == 0) {$PHORUM["DATA"]["OPTION_ALLOWED"]["sticky"] = true;$PHORUM["DATA"]["OPTION_ALLOWED"]["allow_reply"] = true;}// For administrators only.if ($PHORUM["DATA"]["ADMINISTRATOR"]) {$PHORUM["DATA"]["OPTION_ALLOWED"]["announcement"] = true;}}if (! $error_flag){// A hook to allow modules to change the abilities from above.phorum_hook("posting_permission");// Show special sort options in the editor? These only are// honoured for the thread starter messages, so we check the// parent_id for that.$PHORUM["DATA"]["SHOW_SPECIALOPTIONS"] =$message["parent_id"] == 0 &&($PHORUM["DATA"]["OPTION_ALLOWED"]["announcement"] ||$PHORUM["DATA"]["OPTION_ALLOWED"]["sticky"]);// Show special sort options or allow_reply in the editor?$PHORUM["DATA"]["SHOW_THREADOPTIONS"] =$PHORUM["DATA"]["SHOW_SPECIALOPTIONS"] ||$PHORUM["DATA"]["OPTION_ALLOWED"]["allow_reply"];}// Set extra writeable fields, based on the user's abilities.if (isset($PHORUM["DATA"]["ATTACHMENTS"]) && $PHORUM["DATA"]["ATTACHMENTS"]) {// Keep it as a hidden field.$PHORUM["post_fields"]["attachments"][pf_READONLY] = false;}if (isset($PHORUM["DATA"]["MODERATOR"]) && $PHORUM["DATA"]["MODERATOR"]) {if (! $message["user_id"]) {$PHORUM["post_fields"]["author"][pf_READONLY] = false;$PHORUM["post_fields"]["email"][pf_READONLY] = false;}}if (isset($PHORUM["DATA"]["SHOW_SPECIALOPTIONS"]) && $PHORUM["DATA"]["SHOW_SPECIALOPTIONS"]) {$PHORUM["post_fields"]["special"][pf_READONLY] = false;}if (isset($PHORUM["DATA"]["OPTION_ALLOWED"]["allow_reply"]) && $PHORUM["DATA"]["OPTION_ALLOWED"]["allow_reply"]) {$PHORUM["post_fields"]["allow_reply"][pf_READONLY] = false;}// Check permissions and apply read-only data.// Only do this on entering and on finishing up.// No checking is needed on intermediate requests.if (! $error_flag && ($initial || $finish)) {include("./include/posting/check_permissions.php");}// Do permission checks for attachment management.if (! $error_flag && ($do_attach || $do_detach)) {if (! $PHORUM["DATA"]["ATTACHMENTS"]) {$PHORUM["DATA"]["MESSAGE"] =$PHORUM["DATA"]["LANG"]["AttachNotAllowed"];$error_flag = true;}}// ----------------------------------------------------------------------// Perform actions// ----------------------------------------------------------------------// Only check the integrity of the data on finishing up. During the// editing process, the user may produce garbage as much as he likes.if (! $error_flag && $finish) {include("./include/posting/check_integrity.php");}// Handle cancel request.if (! $error_flag && $cancel) {include("./include/posting/action_cancel.php");}// Count the number and total size of active attachments// that we currently have.$attach_count = 0;$attach_totalsize = 0;foreach ($message["attachments"] as $attachment) {if ($attachment["keep"]) {$attach_count ++;$attach_totalsize += $attachment["size"];}}// Attachment management. This will update the// $attach_count and $attach_totalsize variables.if (! $error_flag && ($do_attach || $do_detach)) {include("./include/posting/action_attachments.php");}// Handle finishing actions.if (! $error_flag && $finish){// Posting modeif ($mode == "post" || $mode == "reply") {include("./include/posting/action_post.php");}// Editing mode.elseif ($mode == "edit") {include("./include/posting/action_edit.php");}// A little safety net.else {die("Internal error: finish action for \"$mode\" not available");}}// ----------------------------------------------------------------------// Display the page// ----------------------------------------------------------------------// Make up the text which must be used on the posting form's submit button.$button_txtid = $mode == "edit" ? "SaveChanges" : "Post";$message["submitbutton_text"] = $PHORUM["DATA"]["LANG"][$button_txtid];// Attachment configif($PHORUM["max_attachments"]){$php_limit = ini_get('upload_max_filesize')*1024;$max_packetsize = phorum_db_maxpacketsize();if ($max_packetsize == NULL) {$db_limit = $php_limit;} else {$db_limit = $max_packetsize/1024*.6;}if($PHORUM["max_attachment_size"]==0) $PHORUM["max_attachment_size"]=$php_limit;$PHORUM["max_attachment_size"] = min($PHORUM["max_attachment_size"], $php_limit, $db_limit);if ($PHORUM["max_totalattachment_size"]) {if ($PHORUM["max_totalattachment_size"] < $PHORUM["max_attachment_size"]) {$PHORUM["max_attachment_size"] = $PHORUM["max_totalattachment_size"];}}// Data for attachment explanation.if ($PHORUM["allow_attachment_types"]) {$PHORUM["DATA"]["ATTACH_FILE_TYPES"] = str_replace(";", ", ", $PHORUM["allow_attachment_types"]);$PHORUM["DATA"]["EXPLAIN_ATTACH_FILE_TYPES"] = str_replace("%types%", $PHORUM["DATA"]["ATTACH_FILE_TYPES"], $PHORUM["DATA"]["LANG"]["AttachFileTypes"]);}if ($PHORUM["max_attachment_size"]) {$PHORUM["DATA"]["ATTACH_FILE_SIZE"] = $PHORUM["max_attachment_size"];$PHORUM["DATA"]["ATTACH_FORMATTED_FILE_SIZE"] = phorum_filesize($PHORUM["max_attachment_size"] * 1024);$PHORUM["DATA"]["EXPLAIN_ATTACH_FILE_SIZE"] = str_replace("%size%", $PHORUM["DATA"]["ATTACH_FORMATTED_FILE_SIZE"], $PHORUM["DATA"]["LANG"]["AttachFileSize"]);}if ($PHORUM["max_totalattachment_size"] && $PHORUM["max_attachments"]>1) {$PHORUM["DATA"]["ATTACH_TOTALFILE_SIZE"] = $PHORUM["max_totalattachment_size"];$PHORUM["DATA"]["ATTACH_FORMATTED_TOTALFILE_SIZE"] = phorum_filesize($PHORUM["max_totalattachment_size"] * 1024);$PHORUM["DATA"]["EXPLAIN_ATTACH_TOTALFILE_SIZE"] = str_replace("%size%", $PHORUM["DATA"]["ATTACH_FORMATTED_TOTALFILE_SIZE"], $PHORUM["DATA"]["LANG"]["AttachTotalFileSize"]);}if ($PHORUM["max_attachments"] && $PHORUM["max_attachments"]>1) {$PHORUM["DATA"]["ATTACH_MAX_ATTACHMENTS"] = $PHORUM["max_attachments"];$PHORUM["DATA"]["ATTACH_REMAINING_ATTACHMENTS"] = $PHORUM["max_attachments"] - $attach_count;$PHORUM["DATA"]["EXPLAIN_ATTACH_MAX_ATTACHMENTS"] = str_replace("%count%", $PHORUM["DATA"]["ATTACH_REMAINING_ATTACHMENTS"], $PHORUM["DATA"]["LANG"]["AttachMaxAttachments"]);}// A flag for the template building to be able to see if the// attachment storage space is full.$PHORUM["DATA"]["ATTACHMENTS_FULL"] =$attach_count >= $PHORUM["max_attachments"] ||($PHORUM["max_totalattachment_size"] &&$attach_totalsize >= $PHORUM["max_totalattachment_size"]*1024);}// Let the templates know if we're running as an include.$PHORUM["DATA"]["EDITOR_AS_INCLUDE"] =isset($PHORUM["postingargs"]["as_include"]) && $PHORUM["postingargs"]["as_include"];// Process data for previewing.if ($preview) {include("./include/posting/action_preview.php");}// Always put the current mode in the message, so hook// writers can use this for identifying what we're doing.$message["mode"] = $mode;// Create hidden form field code. Fields which are read-only are// all added as a hidden form fields in the form. Also the fields// for which the pf_HIDDEN flag is set will be added to the// hidden fields.$hidden = "";foreach ($PHORUM["post_fields"] as $var => $spec){if ($var == "mode") {$val = $mode;} elseif ($spec[pf_TYPE] == "array") {$val = htmlspecialchars(serialize($message[$var]));} else {$val = htmlentities($message[$var], ENT_COMPAT, $PHORUM["DATA"]["CHARSET"]);}if ($spec[pf_READONLY] || $spec[pf_HIDDEN]) {$hidden .= '<input type="hidden" name="' . $var . '" ' .'value="' . $val . "\" />\n";}}$PHORUM["DATA"]["POST_VARS"] .= $hidden;// Process data for XSS prevention.foreach ($message as $var => $val){// The meta information should not be used in templates, because// nothing is escaped here. But we might want to use the data in// mods which are run after this code. We continue here, so the// data won't be stripped from the message data later on.if ($var == "meta") continue;if ($var == "attachments") {if (is_array($val)) {foreach ($val as $nr => $data){// Do not show attachments which are not kept.if (! $data["keep"]) {unset($message["attachments"][$nr]);continue;}$message[$var][$nr]["name"] = htmlspecialchars($data["name"]);$message[$var][$nr]["size"] = phorum_filesize(round($data["size"]));}}} else {if (is_scalar($val)) {$message[$var] = htmlspecialchars($val);} else {// Not used in the template, unless proven otherwise.$message[$var] = '[removed from template data]';}}}// A cancel button is not needed if the editor is included in a page.// This can also be used by the before_editor hook to disable the// cancel button in all pages.$PHORUM["DATA"]["SHOW_CANCEL_BUTTON"] = (isset($PHORUM["postingargs"]["as_include"]) ? false : true);// A hook to give modules a last chance to update the message data.$message = phorum_hook("before_editor", $message);// Make the message data available to the template engine.$PHORUM["DATA"]["POST"] = $message;// Set the field to focus.$focus = "phorum_subject";if (!empty($message["subject"])) $focus = "phorum_textarea";$PHORUM["DATA"]["FOCUS_TO_ID"] = $focus;// Load page header.if (! isset($PHORUM["postingargs"]["as_include"])) {include phorum_get_template("header");phorum_hook("after_header");}// Load page content.if (isset($PHORUM["DATA"]["MESSAGE"])) {include phorum_get_template("message");} else {include phorum_get_template("posting");}// Load page footer.if (! isset($PHORUM["postingargs"]["as_include"])) {phorum_hook("before_footer");include phorum_get_template("footer");}// ----------------------------------------------------------------------// Functions// ----------------------------------------------------------------------// Merge data from a database message record into the form fields// that we use. If $apply_readonly is set to a true value, then// only the fields which are flagged as read-only will be copied.function phorum_posting_merge_db2form($form, $db, $apply_readonly = false){$PHORUM = $GLOBALS['PHORUM'];// If we have a user linked to the current message, then get the// user data from the database, if it has to be applied as// read-only data.if ($PHORUM["post_fields"]["email"][pf_READONLY] || $PHORUM["post_fields"]["author"][pf_READONLY]) {if ($db["user_id"]) {$user_info = phorum_user_get($db["user_id"], false);$user_info["author"] = $user_info["username"];}}foreach ($PHORUM["post_fields"] as $key => $info){// Skip writeable fields if we only have to apply read-only ones.if ($apply_readonly && ! $info[pf_READONLY]) continue;switch ($key) {case "show_signature": {$form[$key] = !empty($db["meta"]["show_signature"]);break;}case "allow_reply": {$form[$key] = ! $db["closed"];break;}case "email_notify": {$form[$key] = phorum_db_get_if_subscribed($db["forum_id"], $db["thread"], $db["user_id"]);break;}case "forum_id": {$form["forum_id"] = $db["forum_id"] ? $db["forum_id"] : $PHORUM["forum_id"];break;}case "attachments": {$form[$key] = array();if (isset($db["meta"]["attachments"])) {foreach ($db["meta"]["attachments"] as $data) {$data["keep"] = true;$data["linked"] = true;$form["attachments"][] = $data;}}break;}case "author":case "email": {if ($db["user_id"]) {$form[$key] = $user_info[$key];} else {$form[$key] = $db[$key];}break;}case "special": {if ($db["sort"] == PHORUM_SORT_ANNOUNCEMENT) {$form["special"] = "announcement";} elseif ($db["sort"] == PHORUM_SORT_STICKY) {$form["special"] = "sticky";} else {$form["special"] = "";}break;}case "mode": {// NOOPbreak;}default:$form[$key] = $db[$key];}}return $form;}?>