public function ProcessShortcodeBBAction($parent) { global $bb_dir, $bb_pref_lang, $bb_revision_num, $bb_writeperms; $info = $this->GetInfo($parent->GetSID()); if ($_REQUEST["sc_action"] == "bb_image_upload_ajaxupload") { BB_RunPluginAction("pre_bb_content_shortcode_bb_image_upload_ajaxupload"); $msg = BB_ValidateAJAXUpload(); if ($msg != "") { echo htmlspecialchars(BB_Translate($msg)); exit; } // Use official magic numbers for each format to determine the real content type. $data = file_get_contents($_FILES["Filedata"]["tmp_name"]); $type = BB_GetImageType($data); if ($type != "gif" && $type != "jpg" && $type != "png") { echo htmlspecialchars(BB_Translate("Uploaded file is not a valid web image. Must be PNG, JPG, or GIF.")); exit; } if (!is_dir($bb_dir . "/images")) { mkdir($bb_dir . "/images", 0777, true); } $dirfile = preg_replace('/\\.+/', ".", preg_replace('/[^A-Za-z0-9_.\\-]/', "_", $bb_pref_lang . "_" . ($bb_revision_num > -1 ? $bb_revision_num . "_" : "") . trim($_FILES["Filedata"]["name"]))); if ($dirfile == ".") { $dirfile = ""; } if ($dirfile == "") { echo htmlspecialchars(BB_Translate("A filename was not specified.")); exit; } $pos = strrpos($dirfile, "."); if ($pos === false || substr($dirfile, $pos + 1) != $type) { $dirfile .= "." . $type; } if (!@move_uploaded_file($_FILES["Filedata"]["tmp_name"], $bb_dir . "/images/" . $dirfile)) { echo htmlspecialchars(BB_Translate("Unable to move temporary file to final location. Check the permissions of the target directory and destination file.")); exit; } @chmod($bb_dir . "/images/" . $dirfile, 0444 | $bb_writeperms); $info["src"] = "images/" . $dirfile; if (!$parent->SaveShortcode($info)) { echo htmlspecialchars(BB_Translate("Unable to save the shortcode.")); exit; } echo "OK"; BB_RunPluginAction("post_bb_content_shortcode_bb_image_upload_ajaxupload"); } else { if ($_REQUEST["sc_action"] == "bb_image_upload_submit") { BB_RunPluginAction("pre_bb_content_shortcode_bb_image_upload_submit"); $imginfo = BB_IsValidHTMLImage($_REQUEST["url"], array("protocol" => "http")); if (!$imginfo["success"]) { BB_PropertyFormError($imginfo["error"]); } $dirfile = preg_replace('/\\.+/', ".", preg_replace('/[^A-Za-z0-9_.\\-]/', "_", $_REQUEST["destfile"])); if ($dirfile == ".") { $dirfile = ""; } // Automatically calculate the new filename based on the URL. if ($dirfile == "") { $dirfile = $bb_pref_lang . "_" . ($bb_revision_num > -1 ? $bb_revision_num . "_" : "") . BB_MakeFilenameFromURL($imginfo["url"], $imginfo["type"]); } if (!is_dir($bb_dir . "/images")) { mkdir($bb_dir . "/images", 0777, true); } if (BB_WriteFile($bb_dir . "/images/" . $dirfile, $imginfo["data"]) === false) { BB_PropertyFormError("Unable to save the image."); } $info["src"] = "images/" . $dirfile; if (!$parent->SaveShortcode($info)) { BB_PropertyFormError("Unable to save the shortcode."); } ?> <div class="success"><?php echo htmlspecialchars(BB_Translate("Image transferred.")); ?> </div> <script type="text/javascript"> LoadProperties(<?php echo $parent->CreateShortcodePropertiesJS(""); ?> ); ReloadIFrame(); </script> <?php BB_RunPluginAction("post_bb_content_shortcode_bb_image_upload_submit"); } else { if ($_REQUEST["sc_action"] == "bb_image_upload") { $parent->CreateShortcodeUploader("", array(), "Configure Image", "Image", "image", "*.png;*.jpg;*.gif", "Web Image Files"); } else { if ($_REQUEST["sc_action"] == "bb_image_configure_submit") { BB_RunPluginAction("pre_bb_content_shortcode_bb_image_configure_submit"); $src = trim($_REQUEST["src"]); if ($info["src"] != $src) { if ($src != "") { $imginfo = BB_IsValidHTMLImage($src, array("protocol" => "http")); if (!$imginfo["success"] && function_exists("fsockopen")) { BB_PropertyFormError("'Image URL' field does not point to a valid image file."); } } $info["src"] = $src; } $info["alt"] = $_REQUEST["alt"]; $info["opt-caption"] = $_REQUEST["opt-caption"] == "enable"; $info["opt-caption-width"] = (int) $_REQUEST["opt-caption-width"]; if ($info["opt-caption-width"] < 0) { $info["opt-caption-width"] = 0; } if (!$parent->SaveShortcode($info)) { BB_PropertyFormError("Unable to save the shortcode."); } ?> <div class="success"><?php echo htmlspecialchars(BB_Translate("Options saved.")); ?> </div> <script type="text/javascript"> CloseProperties(); ReloadIFrame(); </script> <?php BB_RunPluginAction("post_bb_content_shortcode_bb_image_configure_submit"); } else { if ($_REQUEST["sc_action"] == "bb_image_configure") { BB_RunPluginAction("pre_bb_content_shortcode_bb_image_configure"); $desc = "<br />"; $desc .= $parent->CreateShortcodePropertiesLink(BB_Translate("Upload/Transfer Image"), "bb_image_upload"); $options = array("title" => "Configure Image", "desc" => "Configure the image or upload/transfer a new image.", "htmldesc" => $desc, "bb_action" => $_REQUEST["bb_action"], "hidden" => array("sid" => $parent->GetSID(), "sc_action" => "bb_image_configure_submit"), "fields" => array(array("title" => "Image URL", "type" => "text", "name" => "src", "value" => $info["src"], "desc" => "The URL of this image."), array("title" => "Alternate Text", "type" => "text", "name" => "alt", "value" => $info["alt"], "desc" => "The alternate text to display if images are not able to be seen (e.g. visually impaired visitors)."), array("title" => "Display Caption", "type" => "select", "name" => "opt-caption", "options" => array("enable" => "Enable", "disable" => "Disable"), "select" => $info["opt-caption"] ? "enable" : "disable", "desc" => "Display the alternate text as a caption below the image."), array("title" => "Caption Width", "type" => "text", "name" => "opt-caption-width", "value" => $info["opt-caption-width"], "desc" => "The width in pixels to constrain the caption to. Typically the width of the image.")), "submit" => "Save", "focus" => true); BB_RunPluginActionInfo("bb_content_shortcode_bb_image_configure_options", $options); BB_PropertyForm($options); BB_RunPluginAction("post_bb_content_shortcode_bb_image_configure"); } } } } } }
function BB_HTMLPurifyForWYMEditor($data, $options) { if (isset($options["shortcodes"]) && (!$options["shortcodes"] || !isset($options["shortcode_placeholder"]) || !isset($options["shortcode_ids"]))) { unset($options["shortcodes"]); } if (isset($options["validate_img"]) && !$options["validate_img"]) { unset($options["validate_img"]); } // Let HTML Purifier do the heavy-lifting (removes XSS, etc). // If the 'p' tag ever accepts more than 'class', the 'class' extraction code while generating pretty HTML will need rewriting. $config = array("Attr.EnableID" => isset($options["shortcodes"]), "HTML.Allowed" => "p[class],strong,em,sup,sub,a[title|href],ul[class],ol[class],li[class],h1[class],h2[class],h3[class],h4[class],h5[class],h6[class],pre[class],blockquote[class],img[" . (isset($options["shortcodes"]) ? "id|class|" : "") . "src|alt]"); if (isset($options["allowed_classes"]) && is_array($options["allowed_classes"])) { $config["Attr.AllowedClasses"] = $options["allowed_classes"]; } $data = BB_HTMLPurify($data, $config); // Replace newlines outside of 'pre' tags with spaces. $data2 = ""; $lastpos = 0; $pos = strpos($data, "<pre"); $pos2 = strpos($data, "</pre>"); $pos3 = strpos($data, ">", $pos); while ($pos !== false && $pos2 !== false && $pos3 !== false && $pos3 < $pos2) { $data2 .= Str::ReplaceNewlines(" ", substr($data, $lastpos, $pos3 + 1 - $lastpos)); $data2 .= Str::ReplaceNewlines("\n", substr($data, $pos3 + 1, $pos2 - $pos3 - 1)); $data2 .= "</pre>"; $lastpos = $pos2 + 6; $pos = strpos($data, "<pre", $lastpos); $pos2 = strpos($data, "</pre>", $lastpos); $pos3 = strpos($data, ">", $pos); } $data = $data2 . Str::ReplaceNewlines(" ", substr($data, $lastpos)); // Process the DOM to create consistent input and output. require_once ROOT_PATH . "/" . SUPPORT_PATH . "/simple_html_dom.php"; $html = new simple_html_dom(); $html2 = new simple_html_dom(); // Make sure all elements and text are inside a top-level tag. $html->load("<body>" . $data . "</body>"); $bodytags = array("p" => true, "ul" => true, "ol" => true, "h1" => true, "h2" => true, "h3" => true, "h4" => true, "h5" => true, "h6" => true, "pre" => true, "blockquote" => true); $rows = $html->find("body text"); foreach ($rows as $row) { $row2 = $row; while ($row2->parent()->tag != "body") { $row2 = $row2->parent(); } if (!isset($bodytags[$row2->tag])) { $row2->outertext = "<p>" . $row2->outertext . "</p>"; } } $html->load($html->save()); $body = $html->find("body", 0); $rows = $body->children(); foreach ($rows as $row) { if (!isset($bodytags[$row->tag])) { $row->outertext = "<p>" . $row->outertext . "</p>"; } } $html->load($html->save()); $rows = $html->find("blockquote text"); foreach ($rows as $row) { $row2 = $row; while ($row2->parent()->tag != "blockquote") { $row2 = $row2->parent(); } if (!isset($bodytags[$row2->tag])) { $row2->outertext = "<p>" . $row2->outertext . "</p>"; } } $html->load($html->save()); // Clean up 'li' elements. WYMEditor only allows a limited number of tags (a good thing). $rows = $html->find("li"); foreach ($rows as $row) { $row->innertext = strip_tags($row->innertext, "<strong><em><sup><sub><a><img><ul><ol><li>"); } // Replace with spaces. $data = $html->save(); $data = str_replace(array(" ", " ", "Â "), array(" ", " ", " "), $data); $html->load($data); // Process shortcodes or images. if (isset($options["shortcodes"])) { // Remove invalid 'img' tags. $rows = $html->find("img"); foreach ($rows as $row) { if (!isset($row->class) || $row->class != $options["shortcode_placeholder"] || !isset($row->id) || !isset($options["shortcode_ids"][$row->id])) { $row->outertext = ""; } else { $row->src = $options["shortcode_ids"][$row->id]; } } $html->load($html->save()); // Move text inside the special 'p.wrap-shortcode' class to separate 'p' tags. $rows = $html->find("p.wrap-shortcode img"); foreach ($rows as $row) { $str = $row->parent()->innertext; $pos = strpos($str, "<img "); $pos2 = strpos($str, "/>", $pos); $str2 = substr($str, 0, $pos); $str3 = substr($str, $pos2 + 2); $str = substr($str, $pos, $pos2 + 2 - $pos); if ($str2 != "" || $str3 != "") { $row->parent()->outertext = ($str2 == "" ? "" : "<p>" . $str2 . "</p>") . "<p class=\"" . $row->parent()->class . "\">" . $str . "</p>" . ($str3 == "" ? "" : "<p>" . $str3 . "</p>"); } } $html->load($html->save()); } else { if (isset($options["validate_img"])) { // Download each 'img' 'src' and check them for valid web output (only allow JPEG, PNG, and GIF). $imgopts = array("protocol" => isset($options["validate_img_protocol"]) ? $options["validate_img_protocol"] : "", "allow_gif" => isset($options["validate_img_allow_gif"]) ? $options["validate_img_allow_gif"] : true, "allow_jpg" => isset($options["validate_img_allow_jpg"]) ? $options["validate_img_allow_jpg"] : true, "allow_png" => isset($options["validate_img_allow_png"]) ? $options["validate_img_allow_png"] : true); $rows = $html->find("img"); foreach ($rows as $row) { if (!isset($row->src)) { $row->outertext = ""; } else { $imginfo = BB_IsValidHTMLImage($row->src, $imgopts); if (!$imginfo["success"]) { $row->outertext = ""; } } } $html->load($html->save()); } } // Remove special classes that are improperly used. $specials = array("wrap-start" => "p", "wrap-end" => "p", "table-row" => "p", "table-cell" => "p", "table-end" => "p"); if (isset($options["shortcodes"])) { $specials["wrap-shortcode"] = array("p", "img"); } if (isset($options["additional_specials"])) { $specials = array_merge($specials, $options["additional_specials"]); } foreach ($specials as $class => $tags) { $rows = $html->find("." . $class); foreach ($rows as $row) { if (is_string($tags)) { $valid = true; } else { $html2->load($row->innertext); $row2 = $html2->find($tags[1], 0); $valid = $row2 ? true : false; } $valid = $valid && (is_string($tags) && $row->tag == $tags || is_array($tags) && $row->tag == $tags[0]); if (!$valid) { $row->class = BB_HTMLRemoveClass($row->class, $class); } if ($row->class == "") { unset($row->class); } } $html->load($html->save()); } // Remove empty elements without a class attribute. do { $found = false; $stack = array(); $body = $html->find("body", 0); $stack[] = array("rows" => $body->children(), "pos" => 0); while (count($stack)) { $pos = count($stack) - 1; if ($stack[$pos]["pos"] >= count($stack[$pos]["rows"])) { $stack = array_slice($stack, 0, -1); if (count($stack)) { $pos = count($stack) - 1; $row = $stack[$pos]["rows"][$stack[$pos]["pos"]]; if (!$found && trim($row->innertext) !== $row->innertext) { $row->innertext = trim($row->innertext); $found = true; } $stack[$pos]["pos"]++; } } else { $row = $stack[$pos]["rows"][$stack[$pos]["pos"]]; $rows = $row->children(); if (count($rows)) { $stack[] = array("rows" => $rows, "pos" => 0); } else { if (!isset($row->class) && trim($row->innertext) == "") { $row->outertext = ""; $found = true; } else { if (trim($row->innertext) !== $row->innertext) { $row->innertext = trim($row->innertext); $found = true; } } $stack[$pos]["pos"]++; } } } $html->load($html->save()); } while ($found); $body = $html->find("body", 0); $data = $body->innertext; // Finalize 'li' tag cleanup. $data = preg_replace('/<\\/li>\\s+/', "</li>", $data); return $data; }