execute_query("SELECT img, mime FROM queue WHERE id = ?", array($id))) { $row = $getimg->fetch_assoc(); $img = $row['img']; $mime = $row['mime']; $getimg->close(); } else { db_fail(); } } else { $image_file = save_uploaded_file(); if ($image_file) { $img = fread(fopen($image_file, "r"), filesize($image_file)); $mime = get_mimetype($image_file); } } // Column => value; the values are bound as query parameters $fields = array( 'title' => $title, 'author' => $author, 'email' => $email, 'editor' => $editor, ); if ($is_admin && isset($comments)) { $fields['comments'] = $comments; } $fields['hidden'] = $hidden ? 1 : 0; if ($remove_img && $story) { $fields['story'] = $story; $fields['mime'] = NULL; $fields['img'] = NULL; } else if (isset($img)) { $fields['mime'] = $mime; $fields['img'] = $img; $fields['story'] = ''; } else { $fields['story'] = $story; } if (!is_numeric($id) || $move) $fields['date'] = $date; $set = implode(', ', array_map(function ($column) { return "`$column` = ?"; }, array_keys($fields))); $params = array_values($fields); if (is_numeric($id) && !$move) { $query = "UPDATE $table SET $set WHERE `id` = ? LIMIT 1"; $params[] = $id; } else { $query = "INSERT INTO $table SET $set"; } //echo $query; $result = $db->execute_query($query, $params) or db_fail(); if (is_numeric($id) && $move) { $queue_id = $id; } // Get the (new) ID if we don't already have it. if (!is_numeric($id) || $move) { $query = "SELECT LAST_INSERT_ID();"; $getid = $db->query($query) or db_fail(); $row = $getid->fetch_row(); $id = $row[0]; } // Delete the article in the queue if pushing live if ($move && $queue_id) { delete_story($queue_id, $move); $queue = FALSE; } // Allow unprivileged user to view image on queue if (!$is_admin && $action == 'submit') $_SESSION['allow_queue_image'] = $id; // A visitor's next story needs a new captcha if (!$is_admin) captcha_used(); // Prune filesystem if ($image_file) prune_images(); // email admin if added to the queue if ($action == 'submit') send_email($title, $author, $story); return $id; } function delete_story($id, $move = FALSE) { global $db, $is_admin, $queue; // Only editors can delete stories if (!$is_admin) return ''; $queue = get_queue(); $table = which_table($move, 'delete'); $query = "DELETE FROM $table WHERE `id` = ? LIMIT 1"; //echo $query; $result = $db->execute_query($query, array((int)$id)) or db_fail(); $message = ''; if (!$move) $message = 'Article has been deleted.'; return $message; } function get_mimetype($image_file) { $upload = getimagesize($image_file); $mimetype = $upload ? $upload['mime'] : NULL; return $mimetype; } function save_uploaded_file() { // A new upload in this request: PHP removes the file after the request $upload_tmp = $_FILES['upload']['tmp_name'] ?? ''; if (!is_string($upload_tmp)) return FALSE; if (is_uploaded_file($upload_tmp)) { return $upload_tmp; } // An image uploaded at the preview step; the session knows which one if (($_POST['uploaded'] ?? '') === 'pending') { return pending_upload(); } return FALSE; } // After a save: remove this session's upload, and any abandoned uploads function prune_images() { remove_pending_upload(); prune_uploads(); } /* * Validate data * * Updates the global $validate array, with the key as the element name, and the value set to the error message. * */ $validate = array(); function validate_data() { global $validate, $is_admin; // extract POST variables $result = get_post_data(TRUE); // assign their keys and values to the symbol table extract($result[0], EXTR_OVERWRITE); $upload_error = $_FILES['upload']['error'] ?? UPLOAD_ERR_NO_FILE; $upload_tmp = $_FILES['upload']['tmp_name'] ?? ''; $upload_name = $_FILES['upload']['name'] ?? ''; // Visitors must solve the captcha before a preview or a save if (!$is_admin && !captcha_check()) { $validate['captcha'] = 'Please complete the captcha.'; } if (!$author) { $validate['author'] = "You have not submitted an author."; } if (!$title) { $validate['title'] = "You have not submitted a title."; } if (story_too_long($story)) { $validate['story'] = 'The story is too long. Please shorten it.'; } if ($remove_img && !$story) { $validate['story'] = "You've tried to remove an image without replacing it with text."; } if (!is_array($_FILES['upload'] ?? array()) || !is_int($upload_error) || !is_string($upload_tmp) || !is_string($upload_name)) { $validate['upload'] = 'The upload is invalid. Please choose the image again.'; return TRUE; } if ($upload_error === UPLOAD_ERR_NO_FILE) return TRUE; $upload_max = upload_max_bytes(); $too_large = htmlspecialchars($upload_name) . ($upload_max === NULL ? ' is larger than the server accepts.' : ' is larger than '.upload_max_mb().' MB.') . ' Please choose a smaller image.'; // 0 == no error; 4 == no file; all others are errors. if ($upload_error === UPLOAD_ERR_INI_SIZE || $upload_error === UPLOAD_ERR_FORM_SIZE) { $validate['upload'] = $too_large; } else if ($upload_error !== UPLOAD_ERR_OK) { $validate['upload'] = 'There was an error uploading the file ('.$upload_error.')'; } else if ($upload_tmp === '' || !is_file($upload_tmp) || !is_readable($upload_tmp)) { $validate['upload'] = 'The uploaded file is unavailable. Please choose the image again.'; } else if ($upload_max !== NULL && (int)@filesize($upload_tmp) > $upload_max) { $validate['upload'] = $too_large; } else { // The file can disappear after the check above, or contain incomplete image data. $upload = @getimagesize($upload_tmp); if (!$upload) $validate['upload'] = htmlspecialchars($upload_name) . " wasn't an image file. Please go back."; } return TRUE; } function sanitise($story) { if ($story) { // No Javascript please! $story = preg_replace("#]*?>.*?#si", "", $story); // No comments please! $story = preg_replace("##si", "", $story); // Replace number ranges with n-dashes, in the text only (not in tags, // where the digits can be part of a link or an attribute) $parts = preg_split("#(<[^>]*>)#", $story, -1, PREG_SPLIT_DELIM_CAPTURE); for ($i = 0; $i < count($parts); $i += 2) $parts[$i] = preg_replace("#(\d)-+(?=\d)#", "$1–", $parts[$i]); $story = implode('', $parts); // Replace " -- " and "--" with m-dashes $story = preg_replace("#(\s?)--(\s?)#si", "$1—$2", $story); // Replace ellipses $story = preg_replace("#(\w|\p{P}|>)\. ?\. ?\.(\s|\p{P})#si", "$1…$2", $story); // External processing include_once('../lib/smartypants.inc.php'); $story = SmartyPants($story); #include_once('../lib/convert_entities.inc.php'); #$story = html_entity_decode_full($story); // Convert named entities to numeric entities // Remove any unsafe markup; this must stay the last step $story = purify_story($story); } return $story; } function send_email($title, $author, $story) { include_once('../lib/convert_entities.inc.php'); $to = site_email('editor'); $subject = "New submission: $title"; $headers = 'From: x.x.x Queue <'.site_email('editor').'>'."\r\n"; $message = "Please review the queue. $author has sent the following new submission:\n\n"; if ($story) { // Turn line and paragraph breaks into new lines before the tags are removed, // and decode the entities last, so that a decoded "<" is not taken for a tag $text = preg_replace(array("##i", "#

#i"), array("\n", "\n\n"), $story); $text = html_entity_decode_full(strip_tags($text)); $text = preg_replace("#\n{3,}#", "\n\n", trim($text)); $message .= wordwrap($text); } else $message .= ""; $message .= "\n\n" . site_url() . "/publish/edit"; mb_send_mail($to, $subject, $message, $headers); }